From ceca736588260f3f0aaa36d57b1453a8baa5c4ff Mon Sep 17 00:00:00 2001 From: sbera87 Date: Tue, 26 Nov 2024 09:17:38 -0500 Subject: [PATCH] Support query compatible trait only for json protocol (#3204) --- .github/workflows/clang-format.yml | 4 +- .../include/aws/sqs/SQSErrorMarshaller.h | 2 +- .../include/aws/sqs/SQSRequest.h | 1 + .../include/aws/core/client/AWSError.h | 1 + .../aws/core/client/AWSErrorMarshaller.h | 49 +-- .../include/aws/core/http/HttpRequest.h | 1 + .../source/client/AWSClient.cpp | 2 +- .../source/client/AWSErrorMarshaller.cpp | 316 ++++++++++-------- .../source/http/HttpRequest.cpp | 2 +- .../aws/client/AWSErrorMashallerTest.cpp | 8 +- .../C2jModelToGeneratorModelTransformer.java | 9 +- .../cpp/AbstractServiceRequestHeader.vm | 3 + .../cpp/json/JsonErrorMarshallerHeader.vm | 4 + 13 files changed, 237 insertions(+), 165 deletions(-) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index 03c5af5f0f3..93b74d2c1fa 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -56,7 +56,7 @@ jobs: run: | clang-format --version if [ -s diff_output.patch ]; then - python3 clang-format-diff.py -p1 -style=file:.clang-format < diff_output.patch > formatted_differences.patch 2> error.log || true + python3 clang-format-diff.py -iregex '.*\.(cpp|cc|c\+\+|cxx|c|h|hh|hpp)' -p1 -style=file:.clang-format < diff_output.patch > formatted_differences.patch 2> error.log || true if [ -s error.log ]; then echo "Errors from clang-format-diff.py:" cat error.log @@ -77,4 +77,4 @@ jobs: cat formatted_differences.patch rm formatted_differences.patch exit 1 - fi \ No newline at end of file + fi diff --git a/generated/src/aws-cpp-sdk-sqs/include/aws/sqs/SQSErrorMarshaller.h b/generated/src/aws-cpp-sdk-sqs/include/aws/sqs/SQSErrorMarshaller.h index 382b3a01651..b6900b900c2 100644 --- a/generated/src/aws-cpp-sdk-sqs/include/aws/sqs/SQSErrorMarshaller.h +++ b/generated/src/aws-cpp-sdk-sqs/include/aws/sqs/SQSErrorMarshaller.h @@ -13,7 +13,7 @@ namespace Aws namespace Client { -class AWS_SQS_API SQSErrorMarshaller : public Aws::Client::JsonErrorMarshaller +class AWS_SQS_API SQSErrorMarshaller : public Aws::Client::JsonErrorMarshallerQueryCompatible { public: Aws::Client::AWSError FindErrorByName(const char* exceptionName) const override; diff --git a/generated/src/aws-cpp-sdk-sqs/include/aws/sqs/SQSRequest.h b/generated/src/aws-cpp-sdk-sqs/include/aws/sqs/SQSRequest.h index da967b302c2..5c275e56f85 100644 --- a/generated/src/aws-cpp-sdk-sqs/include/aws/sqs/SQSRequest.h +++ b/generated/src/aws-cpp-sdk-sqs/include/aws/sqs/SQSRequest.h @@ -31,6 +31,7 @@ namespace SQS if(headers.size() == 0 || (headers.size() > 0 && headers.count(Aws::Http::CONTENT_TYPE_HEADER) == 0)) { headers.emplace(Aws::Http::HeaderValuePair(Aws::Http::CONTENT_TYPE_HEADER, Aws::AMZN_JSON_CONTENT_TYPE_1_0 )); + headers.emplace(Aws::Http::HeaderValuePair(Aws::Http::X_AMZN_QUERY_MODE,"true")); } headers.emplace(Aws::Http::HeaderValuePair(Aws::Http::API_VERSION_HEADER, "2012-11-05")); return headers; diff --git a/src/aws-cpp-sdk-core/include/aws/core/client/AWSError.h b/src/aws-cpp-sdk-core/include/aws/core/client/AWSError.h index 52ebe3ca278..69653735839 100644 --- a/src/aws-cpp-sdk-core/include/aws/core/client/AWSError.h +++ b/src/aws-cpp-sdk-core/include/aws/core/client/AWSError.h @@ -43,6 +43,7 @@ namespace Aws // Allow ErrorMarshaller to set error payload. friend class XmlErrorMarshaller; friend class JsonErrorMarshaller; + friend class JsonErrorMarshallerQueryCompatible; template friend class AWSError; public: /** diff --git a/src/aws-cpp-sdk-core/include/aws/core/client/AWSErrorMarshaller.h b/src/aws-cpp-sdk-core/include/aws/core/client/AWSErrorMarshaller.h index d53c5748516..6b0bc2d03d9 100644 --- a/src/aws-cpp-sdk-core/include/aws/core/client/AWSErrorMarshaller.h +++ b/src/aws-cpp-sdk-core/include/aws/core/client/AWSErrorMarshaller.h @@ -80,32 +80,43 @@ namespace Aws { using AWSErrorMarshaller::Marshall; public: - /** - * Converts an exceptionName and message into an Error object, if it can be parsed. Otherwise, it returns - * and AWSError with CoreErrors::UNKNOWN as the error type. - */ - AWSError Marshall(const Aws::Http::HttpResponse& response) const override; + /** + * Converts an exceptionName and message into an Error object, if it + * can be parsed. Otherwise, it returns and AWSError with + * CoreErrors::UNKNOWN as the error type. + */ + virtual AWSError Marshall(const Aws::Http::HttpResponse& response) const override; - AWSError BuildAWSError(const std::shared_ptr& httpResponse) const override; + AWSError BuildAWSError(const std::shared_ptr& httpResponse) const override; protected: - const Aws::Utils::Json::JsonValue& GetJsonPayloadFromError(const AWSError&) const; + const Aws::Utils::Json::JsonValue& GetJsonPayloadFromError(const AWSError&) const; }; - class AWS_CORE_API XmlErrorMarshaller : public AWSErrorMarshaller - { - using AWSErrorMarshaller::Marshall; - public: - /** - * Converts an exceptionName and message into an Error object, if it can be parsed. Otherwise, it returns - * and AWSError with CoreErrors::UNKNOWN as the error type. - */ - AWSError Marshall(const Aws::Http::HttpResponse& response) const override; + class AWS_CORE_API JsonErrorMarshallerQueryCompatible : public JsonErrorMarshaller { + public: + /** + * Converts an exceptionName and message into an Error object, if it + * can be parsed. Otherwise, it returns and AWSError with + * CoreErrors::UNKNOWN as the error type. + */ + AWSError Marshall(const Aws::Http::HttpResponse& response) const override; + }; - AWSError BuildAWSError(const std::shared_ptr& httpResponse) const override; + class AWS_CORE_API XmlErrorMarshaller : public AWSErrorMarshaller { + using AWSErrorMarshaller::Marshall; - protected: - const Aws::Utils::Xml::XmlDocument& GetXmlPayloadFromError(const AWSError&) const; + public: + /** + * Converts an exceptionName and message into an Error object, if it can be parsed. Otherwise, it returns + * and AWSError with CoreErrors::UNKNOWN as the error type. + */ + AWSError Marshall(const Aws::Http::HttpResponse& response) const override; + + AWSError BuildAWSError(const std::shared_ptr& httpResponse) const override; + + protected: + const Aws::Utils::Xml::XmlDocument& GetXmlPayloadFromError(const AWSError&) const; }; } // namespace Client diff --git a/src/aws-cpp-sdk-core/include/aws/core/http/HttpRequest.h b/src/aws-cpp-sdk-core/include/aws/core/http/HttpRequest.h index 23b42af64c1..139f1ba33c2 100644 --- a/src/aws-cpp-sdk-core/include/aws/core/http/HttpRequest.h +++ b/src/aws-cpp-sdk-core/include/aws/core/http/HttpRequest.h @@ -63,6 +63,7 @@ namespace Aws extern AWS_CORE_API const char CHUNKED_VALUE[]; extern AWS_CORE_API const char AWS_CHUNKED_VALUE[]; extern AWS_CORE_API const char X_AMZN_ERROR_TYPE[]; + extern AWS_CORE_API const char X_AMZN_QUERY_MODE[]; class HttpRequest; class HttpResponse; diff --git a/src/aws-cpp-sdk-core/source/client/AWSClient.cpp b/src/aws-cpp-sdk-core/source/client/AWSClient.cpp index 7d33207e9de..0c33a43e8bf 100644 --- a/src/aws-cpp-sdk-core/source/client/AWSClient.cpp +++ b/src/aws-cpp-sdk-core/source/client/AWSClient.cpp @@ -1048,4 +1048,4 @@ void AWSClient::AppendRecursionDetectionHeader(std::shared_ptrSetHeaderValue(Aws::Http::X_AMZN_TRACE_ID_HEADER, xAmznTraceIdVal); -} +} \ No newline at end of file diff --git a/src/aws-cpp-sdk-core/source/client/AWSErrorMarshaller.cpp b/src/aws-cpp-sdk-core/source/client/AWSErrorMarshaller.cpp index 242db2d7978..418b2cf1e5a 100644 --- a/src/aws-cpp-sdk-core/source/client/AWSErrorMarshaller.cpp +++ b/src/aws-cpp-sdk-core/source/client/AWSErrorMarshaller.cpp @@ -40,158 +40,121 @@ static CoreErrors GuessBodylessErrorType(const Aws::Http::HttpResponseCode respo } } -AWSError JsonErrorMarshaller::Marshall(const Aws::Http::HttpResponse& httpResponse) const -{ - Aws::StringStream memoryStream; - std::copy(std::istreambuf_iterator(httpResponse.GetResponseBody()), std::istreambuf_iterator(), std::ostreambuf_iterator(memoryStream)); - Aws::String rawPayloadStr = memoryStream.str(); - - JsonValue exceptionPayload(rawPayloadStr); - JsonView payloadView(exceptionPayload); - AWSError error; - if (exceptionPayload.WasParseSuccessful()) - { - AWS_LOGSTREAM_TRACE(AWS_ERROR_MARSHALLER_LOG_TAG, "Error response is " << payloadView.WriteReadable()); - - Aws::String message(payloadView.ValueExists(MESSAGE_CAMEL_CASE) ? payloadView.GetString(MESSAGE_CAMEL_CASE) : - payloadView.ValueExists(MESSAGE_LOWER_CASE) ? payloadView.GetString(MESSAGE_LOWER_CASE) : ""); - - if (httpResponse.HasHeader(ERROR_TYPE_HEADER)) - { - error = Marshall(httpResponse.GetHeader(ERROR_TYPE_HEADER), message); - } - else if (payloadView.ValueExists(TYPE)) - { - error = Marshall(payloadView.GetString(TYPE), message); - } - else - { - error = FindErrorByHttpResponseCode(httpResponse.GetResponseCode()); - error.SetMessage(message); - } - - if (httpResponse.HasHeader(QUERY_ERROR_HEADER)) - { - auto errorCodeString = httpResponse.GetHeader(QUERY_ERROR_HEADER); - auto locationOfSemicolon = errorCodeString.find_first_of(';'); - Aws::String errorCode; - - if (locationOfSemicolon != Aws::String::npos) - { - errorCode = errorCodeString.substr(0, locationOfSemicolon); - } - else - { - errorCode = errorCodeString; - } - - error.SetExceptionName(errorCode); - } - } - else - { - bool isRetryable = IsRetryableHttpResponseCode(httpResponse.GetResponseCode()); - AWS_LOGSTREAM_ERROR(AWS_ERROR_MARSHALLER_LOG_TAG, "Failed to parse error payload: " << httpResponse.GetResponseCode() << ": " << rawPayloadStr); - error = AWSError(CoreErrors::UNKNOWN, "", "Failed to parse error payload: " + rawPayloadStr, isRetryable); +AWSError JsonErrorMarshaller::Marshall(const Aws::Http::HttpResponse& httpResponse) const { + Aws::StringStream memoryStream; + std::copy(std::istreambuf_iterator(httpResponse.GetResponseBody()), std::istreambuf_iterator(), + std::ostreambuf_iterator(memoryStream)); + Aws::String rawPayloadStr = memoryStream.str(); + + JsonValue exceptionPayload(rawPayloadStr); + JsonView payloadView(exceptionPayload); + AWSError error; + if (exceptionPayload.WasParseSuccessful()) { + AWS_LOGSTREAM_TRACE(AWS_ERROR_MARSHALLER_LOG_TAG, "Error response is " << payloadView.WriteReadable()); + + Aws::String message(payloadView.ValueExists(MESSAGE_CAMEL_CASE) ? payloadView.GetString(MESSAGE_CAMEL_CASE) + : payloadView.ValueExists(MESSAGE_LOWER_CASE) ? payloadView.GetString(MESSAGE_LOWER_CASE) + : ""); + + if (httpResponse.HasHeader(ERROR_TYPE_HEADER)) { + error = Marshall(httpResponse.GetHeader(ERROR_TYPE_HEADER), message); + } else if (payloadView.ValueExists(TYPE)) { + error = Marshall(payloadView.GetString(TYPE), message); + } else { + error = FindErrorByHttpResponseCode(httpResponse.GetResponseCode()); + error.SetMessage(message); } - error.SetRequestId(httpResponse.HasHeader(REQUEST_ID_HEADER) ? httpResponse.GetHeader(REQUEST_ID_HEADER) : ""); - error.SetJsonPayload(std::move(exceptionPayload)); - return error; -} - -AWSError JsonErrorMarshaller::BuildAWSError(const std::shared_ptr& httpResponse) const -{ - AWSError error; - if (httpResponse->HasClientError()) - { - bool retryable = httpResponse->GetClientErrorType() == CoreErrors::NETWORK_CONNECTION ? true : false; - error = AWSError(httpResponse->GetClientErrorType(), "", httpResponse->GetClientErrorMessage(), retryable); - } - else if (!httpResponse->GetResponseBody() || httpResponse->GetResponseBody().tellp() < 1) - { - auto responseCode = httpResponse->GetResponseCode(); - auto errorCode = GuessBodylessErrorType(responseCode); + } else { + bool isRetryable = IsRetryableHttpResponseCode(httpResponse.GetResponseCode()); + AWS_LOGSTREAM_ERROR(AWS_ERROR_MARSHALLER_LOG_TAG, + "Failed to parse error payload: " << httpResponse.GetResponseCode() << ": " << rawPayloadStr); + error = AWSError(CoreErrors::UNKNOWN, "", "Failed to parse error payload: " + rawPayloadStr, isRetryable); + } - Aws::StringStream ss; - ss << "No response body."; - error = AWSError(errorCode, "", ss.str(), - IsRetryableHttpResponseCode(responseCode)); - } - else - { - assert(httpResponse->GetResponseCode() != HttpResponseCode::OK); - error = Marshall(*httpResponse); - } - - error.SetResponseHeaders(httpResponse->GetHeaders()); - error.SetResponseCode(httpResponse->GetResponseCode()); - error.SetRemoteHostIpAddress(httpResponse->GetOriginatingRequest().GetResolvedRemoteHost()); - AWS_LOGSTREAM_ERROR(AWS_ERROR_MARSHALLER_LOG_TAG, error); - return error; + error.SetRequestId(httpResponse.HasHeader(REQUEST_ID_HEADER) ? httpResponse.GetHeader(REQUEST_ID_HEADER) : ""); + error.SetJsonPayload(std::move(exceptionPayload)); + return error; } -const JsonValue& JsonErrorMarshaller::GetJsonPayloadFromError(const AWSError& error) const -{ - return error.GetJsonPayload(); +AWSError JsonErrorMarshaller::BuildAWSError(const std::shared_ptr& httpResponse) const { + AWSError error; + if (httpResponse->HasClientError()) { + bool retryable = httpResponse->GetClientErrorType() == CoreErrors::NETWORK_CONNECTION ? true : false; + error = AWSError(httpResponse->GetClientErrorType(), "", httpResponse->GetClientErrorMessage(), retryable); + } else if (!httpResponse->GetResponseBody() || httpResponse->GetResponseBody().tellp() < 1) { + auto responseCode = httpResponse->GetResponseCode(); + auto errorCode = GuessBodylessErrorType(responseCode); + + Aws::StringStream ss; + ss << "No response body."; + error = AWSError(errorCode, "", ss.str(), IsRetryableHttpResponseCode(responseCode)); + } else { + assert(httpResponse->GetResponseCode() != HttpResponseCode::OK); + error = Marshall(*httpResponse); + } + + error.SetResponseHeaders(httpResponse->GetHeaders()); + error.SetResponseCode(httpResponse->GetResponseCode()); + error.SetRemoteHostIpAddress(httpResponse->GetOriginatingRequest().GetResolvedRemoteHost()); + AWS_LOGSTREAM_ERROR(AWS_ERROR_MARSHALLER_LOG_TAG, error); + return error; } -AWSError XmlErrorMarshaller::Marshall(const Aws::Http::HttpResponse& httpResponse) const -{ - XmlDocument doc = XmlDocument::CreateFromXmlStream(httpResponse.GetResponseBody()); - AWS_LOGSTREAM_TRACE(AWS_ERROR_MARSHALLER_LOG_TAG, "Error response is " << doc.ConvertToString()); - bool errorParsed = false; - AWSError error; - if (doc.WasParseSuccessful()) - { - XmlNode errorNode = doc.GetRootElement(); +const JsonValue& JsonErrorMarshaller::GetJsonPayloadFromError(const AWSError& error) const { return error.GetJsonPayload(); } - Aws::String requestId(!errorNode.FirstChild("RequestId").IsNull() ? errorNode.FirstChild("RequestId").GetText() : - !errorNode.FirstChild("RequestID").IsNull() ? errorNode.FirstChild("RequestID").GetText() : ""); +AWSError XmlErrorMarshaller::Marshall(const Aws::Http::HttpResponse& httpResponse) const { + XmlDocument doc = XmlDocument::CreateFromXmlStream(httpResponse.GetResponseBody()); + AWS_LOGSTREAM_TRACE(AWS_ERROR_MARSHALLER_LOG_TAG, "Error response is " << doc.ConvertToString()); + bool errorParsed = false; + AWSError error; + if (doc.WasParseSuccessful()) { + XmlNode errorNode = doc.GetRootElement(); - if (errorNode.GetName() != "Error") - { - errorNode = doc.GetRootElement().FirstChild("Error"); - } - if (errorNode.IsNull()) - { - errorNode = doc.GetRootElement().FirstChild("Errors"); - if(!errorNode.IsNull()) - { - errorNode = errorNode.FirstChild("Error"); - } - } + Aws::String requestId(!errorNode.FirstChild("RequestId").IsNull() ? errorNode.FirstChild("RequestId").GetText() + : !errorNode.FirstChild("RequestID").IsNull() ? errorNode.FirstChild("RequestID").GetText() + : ""); - if (!errorNode.IsNull()) - { - requestId = !requestId.empty() ? requestId : !errorNode.FirstChild("RequestId").IsNull() ? errorNode.FirstChild("RequestId").GetText() : - !errorNode.FirstChild("RequestID").IsNull() ? errorNode.FirstChild("RequestID").GetText() : ""; - - XmlNode codeNode = errorNode.FirstChild("Code"); - XmlNode messageNode = errorNode.FirstChild("Message"); - - if (!codeNode.IsNull()) - { - error = Marshall(StringUtils::Trim(codeNode.GetText().c_str()), - StringUtils::Trim(messageNode.GetText().c_str())); - errorParsed = true; - } - } - - error.SetRequestId(requestId); + if (errorNode.GetName() != "Error") { + errorNode = doc.GetRootElement().FirstChild("Error"); + } + if (errorNode.IsNull()) { + errorNode = doc.GetRootElement().FirstChild("Errors"); + if (!errorNode.IsNull()) { + errorNode = errorNode.FirstChild("Error"); + } } - if(!errorParsed) - { - // An error occurred attempting to parse the httpResponse as an XML stream, so we're just - // going to dump the XML parsing error and the http response code as a string - AWS_LOGSTREAM_WARN(AWS_ERROR_MARSHALLER_LOG_TAG, "Unable to generate a proper httpResponse from the response " - "stream. Response code: " << static_cast< uint32_t >(httpResponse.GetResponseCode())); - error = FindErrorByHttpResponseCode(httpResponse.GetResponseCode()); + if (!errorNode.IsNull()) { + requestId = !requestId.empty() ? requestId + : !errorNode.FirstChild("RequestId").IsNull() ? errorNode.FirstChild("RequestId").GetText() + : !errorNode.FirstChild("RequestID").IsNull() ? errorNode.FirstChild("RequestID").GetText() + : ""; + + XmlNode codeNode = errorNode.FirstChild("Code"); + XmlNode messageNode = errorNode.FirstChild("Message"); + + if (!codeNode.IsNull()) { + error = Marshall(StringUtils::Trim(codeNode.GetText().c_str()), StringUtils::Trim(messageNode.GetText().c_str())); + errorParsed = true; + } } - error.SetXmlPayload(std::move(doc)); - return error; + error.SetRequestId(requestId); + } + + if (!errorParsed) { + // An error occurred attempting to parse the httpResponse as an XML stream, so we're just + // going to dump the XML parsing error and the http response code as a string + AWS_LOGSTREAM_WARN(AWS_ERROR_MARSHALLER_LOG_TAG, + "Unable to generate a proper httpResponse from the response " + "stream. Response code: " + << static_cast(httpResponse.GetResponseCode())); + error = FindErrorByHttpResponseCode(httpResponse.GetResponseCode()); + } + + error.SetXmlPayload(std::move(doc)); + return error; } AWSError XmlErrorMarshaller::BuildAWSError(const std::shared_ptr& httpResponse) const @@ -285,3 +248,80 @@ AWSError AWSErrorMarshaller::FindErrorByHttpResponseCode(Aws::Http:: { return CoreErrorsMapper::GetErrorForHttpResponseCode(code); } + +AWSError JsonErrorMarshallerQueryCompatible::Marshall(const Aws::Http::HttpResponse& httpResponse) const { + Aws::StringStream memoryStream; + std::copy(std::istreambuf_iterator(httpResponse.GetResponseBody()), std::istreambuf_iterator(), + std::ostreambuf_iterator(memoryStream)); + Aws::String rawPayloadStr = memoryStream.str(); + + JsonValue exceptionPayload(rawPayloadStr); + JsonView payloadView(exceptionPayload); + AWSError error; + if (exceptionPayload.WasParseSuccessful()) { + AWS_LOGSTREAM_TRACE(AWS_ERROR_MARSHALLER_LOG_TAG, "Error response is " << payloadView.WriteReadable()); + + Aws::String message(payloadView.ValueExists(MESSAGE_CAMEL_CASE) ? payloadView.GetString(MESSAGE_CAMEL_CASE) + : payloadView.ValueExists(MESSAGE_LOWER_CASE) ? payloadView.GetString(MESSAGE_LOWER_CASE) + : ""); + + if (httpResponse.HasHeader(ERROR_TYPE_HEADER)) { + error = AWSErrorMarshaller::Marshall(httpResponse.GetHeader(ERROR_TYPE_HEADER), message); + } else if (payloadView.ValueExists(TYPE)) { + error = AWSErrorMarshaller::Marshall(payloadView.GetString(TYPE), message); + } else { + error = FindErrorByHttpResponseCode(httpResponse.GetResponseCode()); + error.SetMessage(message); + } + + if (!error.GetExceptionName().empty()) { + /* + AWS Query-Compatible mode: This is a special setting that allows + certain AWS services to communicate using a specific "query" + format, which can send customized error codes. Users are divided + into different groups based on how they communicate with the + service: Group #1: Users using the AWS Query format, receiving + custom error codes. Group #2: Users using the regular AWS JSON + format without the trait, receiving standard error codes. Group #3: + Users using the AWS JSON format with the trait, receiving custom + error codes. + + The header "x-amzn-query-error" shouldn't be present if it's not + awsQueryCompatible, so added checks for it. + */ + + if (httpResponse.HasHeader(QUERY_ERROR_HEADER)) { + auto errorCodeString = httpResponse.GetHeader(QUERY_ERROR_HEADER); + auto locationOfSemicolon = errorCodeString.find_first_of(';'); + Aws::String errorCode; + + if (locationOfSemicolon != Aws::String::npos) { + errorCode = errorCodeString.substr(0, locationOfSemicolon); + } else { + errorCode = errorCodeString; + } + + error.SetExceptionName(errorCode); + } + // check for exception name from payload field 'type' + else if (payloadView.ValueExists(TYPE)) { + // handle missing header and parse code from message + const auto& typeStr = payloadView.GetString(TYPE); + auto locationOfPound = typeStr.find_first_of('#'); + if (locationOfPound != Aws::String::npos) { + error.SetExceptionName(typeStr.substr(locationOfPound + 1)); + } + } + } + + } else { + bool isRetryable = IsRetryableHttpResponseCode(httpResponse.GetResponseCode()); + AWS_LOGSTREAM_ERROR(AWS_ERROR_MARSHALLER_LOG_TAG, + "Failed to parse error payload: " << httpResponse.GetResponseCode() << ": " << rawPayloadStr); + error = AWSError(CoreErrors::UNKNOWN, "", "Failed to parse error payload: " + rawPayloadStr, isRetryable); + } + + error.SetRequestId(httpResponse.HasHeader(REQUEST_ID_HEADER) ? httpResponse.GetHeader(REQUEST_ID_HEADER) : ""); + error.SetJsonPayload(std::move(exceptionPayload)); + return error; +} diff --git a/src/aws-cpp-sdk-core/source/http/HttpRequest.cpp b/src/aws-cpp-sdk-core/source/http/HttpRequest.cpp index ee23f0262d5..00a9bda9bfe 100644 --- a/src/aws-cpp-sdk-core/source/http/HttpRequest.cpp +++ b/src/aws-cpp-sdk-core/source/http/HttpRequest.cpp @@ -42,7 +42,7 @@ namespace Aws const char X_AMZN_TRACE_ID_HEADER[] = "X-Amzn-Trace-Id"; const char ALLOCATION_TAG[] = "HttpRequestConversion"; const char X_AMZN_ERROR_TYPE[] = "x-amzn-errortype"; - + const char X_AMZN_QUERY_MODE[] = "x-amzn-query-mode"; std::shared_ptr HttpRequest::ToCrtHttpRequest() { auto request = Aws::MakeShared(ALLOCATION_TAG); diff --git a/tests/aws-cpp-sdk-core-tests/aws/client/AWSErrorMashallerTest.cpp b/tests/aws-cpp-sdk-core-tests/aws/client/AWSErrorMashallerTest.cpp index f16404e0c74..6e25085c316 100644 --- a/tests/aws-cpp-sdk-core-tests/aws/client/AWSErrorMashallerTest.cpp +++ b/tests/aws-cpp-sdk-core-tests/aws/client/AWSErrorMashallerTest.cpp @@ -474,7 +474,9 @@ TEST_F(AWSErrorMarshallerTest, TestErrorsWithPrefixParse) ASSERT_EQ(requestId, error.GetRequestId()); ASSERT_FALSE(error.ShouldRetry()); - error = awsErrorMarshaller.Marshall(*BuildHttpResponse(exceptionPrefix + "AccessDeniedException", message, requestId, LowerCaseMessage, "AwsQueryErrorCode")); + JsonErrorMarshallerQueryCompatible awsErrorMarshaller2; + error = awsErrorMarshaller2.Marshall( + *BuildHttpResponse(exceptionPrefix + "AccessDeniedException", message, requestId, LowerCaseMessage, "AwsQueryErrorCode")); ASSERT_EQ(CoreErrors::ACCESS_DENIED, error.GetErrorType()); ASSERT_EQ("AwsQueryErrorCode", error.GetExceptionName()); ASSERT_EQ(message, error.GetMessage()); @@ -741,7 +743,9 @@ TEST_F(AWSErrorMarshallerTest, TestErrorsWithoutPrefixParse) ASSERT_EQ(requestId, error.GetRequestId()); ASSERT_FALSE(error.ShouldRetry()); - error = awsErrorMarshaller.Marshall(*BuildHttpResponse(exceptionPrefix + "AccessDeniedException", message, requestId, LowerCaseMessage, "AwsQueryErrorCode")); + JsonErrorMarshallerQueryCompatible awsErrorMarshaller2; + error = awsErrorMarshaller2.Marshall( + *BuildHttpResponse(exceptionPrefix + "AccessDeniedException", message, requestId, LowerCaseMessage, "AwsQueryErrorCode")); ASSERT_EQ(CoreErrors::ACCESS_DENIED, error.GetErrorType()); ASSERT_EQ("AwsQueryErrorCode", error.GetExceptionName()); ASSERT_EQ(message, error.GetMessage()); diff --git a/tools/code-generation/generator/src/main/java/com/amazonaws/util/awsclientgenerator/transform/C2jModelToGeneratorModelTransformer.java b/tools/code-generation/generator/src/main/java/com/amazonaws/util/awsclientgenerator/transform/C2jModelToGeneratorModelTransformer.java index d4dfa30db55..422e9eed7b3 100644 --- a/tools/code-generation/generator/src/main/java/com/amazonaws/util/awsclientgenerator/transform/C2jModelToGeneratorModelTransformer.java +++ b/tools/code-generation/generator/src/main/java/com/amazonaws/util/awsclientgenerator/transform/C2jModelToGeneratorModelTransformer.java @@ -168,7 +168,14 @@ public ServiceModel convert() { serviceModel.getMetadata().setHasEndpointDiscoveryTrait(hasEndpointDiscoveryTrait && !endpointOperationName.isEmpty()); serviceModel.getMetadata().setRequireEndpointDiscovery(requireEndpointDiscovery); serviceModel.getMetadata().setEndpointOperationName(endpointOperationName); - serviceModel.getMetadata().setAwsQueryCompatible(c2jServiceModel.getMetadata().getAwsQueryCompatible() != null); + + // add protocol check. only for json, query protocols + if (serviceModel.getMetadata().getProtocol().equals("json")) { + serviceModel.getMetadata().setAwsQueryCompatible( + c2jServiceModel.getMetadata().getAwsQueryCompatible() != null); + } else { + serviceModel.getMetadata().setAwsQueryCompatible(false); + } if (c2jServiceModel.getEndpointRules() != null) { ObjectMapper objectMapper = new ObjectMapper(); diff --git a/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/AbstractServiceRequestHeader.vm b/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/AbstractServiceRequestHeader.vm index faa9d51979f..a35a80c43f3 100644 --- a/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/AbstractServiceRequestHeader.vm +++ b/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/AbstractServiceRequestHeader.vm @@ -39,6 +39,9 @@ namespace ${serviceNamespace} headers.emplace(Aws::Http::HeaderValuePair(Aws::Http::CONTENT_TYPE_HEADER, ${CppViewHelper.computeRequestContentType($metadata)} )); #if($metadata.acceptHeader) headers.emplace(Aws::Http::HeaderValuePair(Aws::Http::ACCEPT_HEADER, "${metadata.acceptHeader}")); +#end +#if ($metadata.awsQueryCompatible) + headers.emplace(Aws::Http::HeaderValuePair(Aws::Http::X_AMZN_QUERY_MODE,"true")); #end } #if($metadata.apiVersion) diff --git a/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/json/JsonErrorMarshallerHeader.vm b/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/json/JsonErrorMarshallerHeader.vm index 00cd8e4257d..8451ac36580 100644 --- a/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/json/JsonErrorMarshallerHeader.vm +++ b/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/json/JsonErrorMarshallerHeader.vm @@ -18,7 +18,11 @@ namespace ${serviceNamespace} { #set($className = "${metadata.classNamePrefix}ErrorMarshaller") +#if ($metadata.awsQueryCompatible) +class ${CppViewHelper.computeExportValue($metadata.classNamePrefix)} $className : public Aws::Client::JsonErrorMarshallerQueryCompatible +#else class ${CppViewHelper.computeExportValue($metadata.classNamePrefix)} $className : public Aws::Client::JsonErrorMarshaller +#end { public: Aws::Client::AWSError FindErrorByName(const char* exceptionName) const override;