← All changes
|
includes/sdk/s3/Aws/Api/ErrorParser/JsonParserTrait.php
+87
-5
1.1.1
→
1.4.2
View file →
| @@ -10,17 +10,99 @@ | ||
| 10 | 10 | */ |
| 11 | 11 | trait JsonParserTrait |
| 12 | 12 | { |
| 13 | 13 | use PayloadParserTrait; |
| 14 | - private function genericHandler(ResponseInterface $response) | |
| 14 | + private function genericHandler(ResponseInterface $response) : array | |
| 15 | 15 | { |
| 16 | 16 | $code = (string) $response->getStatusCode(); |
| 17 | - return ['request_id' => (string) $response->getHeaderLine('x-amzn-requestid'), 'code' => null, 'message' => null, 'type' => $code[0] == '4' ? 'client' : 'server', 'parsed' => $this->parseJson($response->getBody(), $response)]; | |
| 17 | + $error_code = null; | |
| 18 | + $error_type = null; | |
| 19 | + // Parse error code and type for query compatible services | |
| 20 | + if ($this->api && !\is_null($this->api->getMetadata('awsQueryCompatible')) && $response->hasHeader('x-amzn-query-error')) { | |
| 21 | + $awsQueryError = $this->parseAwsQueryCompatibleHeader($response); | |
| 22 | + if ($awsQueryError) { | |
| 23 | + $error_code = $awsQueryError['code']; | |
| 24 | + $error_type = $awsQueryError['type']; | |
| 25 | + } | |
| 26 | + } | |
| 27 | + // Parse error code from X-Amzn-Errortype header | |
| 28 | + if (!$error_code && $response->hasHeader('X-Amzn-Errortype')) { | |
| 29 | + $error_code = $this->extractErrorCode($response->getHeaderLine('X-Amzn-Errortype')); | |
| 30 | + } | |
| 31 | + $parsedBody = null; | |
| 32 | + $body = $response->getBody(); | |
| 33 | + if (!$body->isSeekable() || $body->getSize()) { | |
| 34 | + $parsedBody = $this->parseJson((string) $body, $response); | |
| 35 | + } | |
| 36 | + // Parse error code from response body | |
| 37 | + if (!$error_code && $parsedBody) { | |
| 38 | + $error_code = $this->parseErrorFromBody($parsedBody); | |
| 39 | + } | |
| 40 | + if (!isset($error_type)) { | |
| 41 | + $error_type = $code[0] == '4' ? 'client' : 'server'; | |
| 42 | + } | |
| 43 | + return ['request_id' => $response->getHeaderLine('x-amzn-requestid'), 'code' => $error_code ?? null, 'message' => null, 'type' => $error_type, 'parsed' => $parsedBody]; | |
| 18 | 44 | } |
| 45 | + /** | |
| 46 | + * Parse AWS Query Compatible error from header | |
| 47 | + * | |
| 48 | + * @param ResponseInterface $response | |
| 49 | + * @return array|null Returns ['code' => string, 'type' => string] or null | |
| 50 | + */ | |
| 51 | + private function parseAwsQueryCompatibleHeader(ResponseInterface $response) : ?array | |
| 52 | + { | |
| 53 | + $queryError = $response->getHeaderLine('x-amzn-query-error'); | |
| 54 | + $parts = \explode(';', $queryError); | |
| 55 | + if (\count($parts) === 2 && $parts[0] && $parts[1]) { | |
| 56 | + return ['code' => $parts[0], 'type' => $parts[1]]; | |
| 57 | + } | |
| 58 | + return null; | |
| 59 | + } | |
| 60 | + /** | |
| 61 | + * Parse error code from response body | |
| 62 | + * | |
| 63 | + * @param array|null $parsedBody | |
| 64 | + * @return string|null | |
| 65 | + */ | |
| 66 | + private function parseErrorFromBody(?array $parsedBody) : ?string | |
| 67 | + { | |
| 68 | + if (!$parsedBody || !isset($parsedBody['code']) && !isset($parsedBody['__type'])) { | |
| 69 | + return null; | |
| 70 | + } | |
| 71 | + $error_code = $parsedBody['code'] ?? $parsedBody['__type']; | |
| 72 | + return $this->extractErrorCode($error_code); | |
| 73 | + } | |
| 74 | + /** | |
| 75 | + * Extract error code from raw error string containing # and/or : delimiters | |
| 76 | + * | |
| 77 | + * @param string $rawErrorCode | |
| 78 | + * @return string | |
| 79 | + */ | |
| 80 | + private function extractErrorCode(string $rawErrorCode) : string | |
| 81 | + { | |
| 82 | + // Handle format with both # and uri (e.g., "namespace#http://foo-bar") | |
| 83 | + if (\str_contains($rawErrorCode, ':') && \str_contains($rawErrorCode, '#')) { | |
| 84 | + $start = \strpos($rawErrorCode, '#') + 1; | |
| 85 | + $end = \strpos($rawErrorCode, ':', $start); | |
| 86 | + return \substr($rawErrorCode, $start, $end - $start); | |
| 87 | + } | |
| 88 | + // Handle format with uri only : (e.g., "ErrorCode:http://foo-bar.com/baz") | |
| 89 | + if (\str_contains($rawErrorCode, ':')) { | |
| 90 | + return \substr($rawErrorCode, 0, \strpos($rawErrorCode, ':')); | |
| 91 | + } | |
| 92 | + // Handle format with only # (e.g., "namespace#ErrorCode") | |
| 93 | + if (\str_contains($rawErrorCode, '#')) { | |
| 94 | + return \substr($rawErrorCode, \strpos($rawErrorCode, '#') + 1); | |
| 95 | + } | |
| 96 | + return $rawErrorCode; | |
| 97 | + } | |
| 19 | 98 | protected function payload(ResponseInterface $response, StructureShape $member) |
| 20 | 99 | { |
| 21 | - $jsonBody = $this->parseJson($response->getBody(), $response); | |
| 22 | - if ($jsonBody) { | |
| 23 | - return $this->parser->parse($member, $jsonBody); | |
| 100 | + $body = $response->getBody(); | |
| 101 | + if (!$body->isSeekable() || $body->getSize()) { | |
| 102 | + $jsonBody = $this->parseJson($body, $response); | |
| 103 | + } else { | |
| 104 | + $jsonBody = (string) $body; | |
| 24 | 105 | } |
| 106 | + return $this->parser->parse($member, $jsonBody); | |
| 25 | 107 | } |
| 26 | 108 | } |