Skip to content

Commit

Permalink
Fix compilation error for older gcc (#3220)
Browse files Browse the repository at this point in the history
  • Loading branch information
sbera87 authored Dec 12, 2024
1 parent ddc4966 commit 1604dc7
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ namespace Aws
*/
virtual Aws::String ExtractEndpoint(const AWSError<CoreErrors>&) const { return {}; }
protected:
AWSError<CoreErrors> Marshall(const Aws::String& exceptionName, const Aws::String& message) const;
virtual AWSError<CoreErrors> Marshall(const Aws::String& exceptionName, const Aws::String& message) const;
virtual void MarshallError(AWSError<CoreErrors>&, const Http::HttpResponse&) const {};
};

class AWS_CORE_API JsonErrorMarshaller : public AWSErrorMarshaller
Expand All @@ -91,16 +92,12 @@ namespace Aws

protected:
const Aws::Utils::Json::JsonValue& GetJsonPayloadFromError(const AWSError<CoreErrors>&) const;
static Aws::Utils::Json::JsonValue GetJsonPayloadHttpResponse(const Http::HttpResponse& httpResponse);
};

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<CoreErrors> Marshall(const Aws::Http::HttpResponse& response) const override;
protected:
void MarshallError(AWSError<CoreErrors>&, const Http::HttpResponse&) const override;
};

class AWS_CORE_API XmlErrorMarshaller : public AWSErrorMarshaller {
Expand Down
123 changes: 48 additions & 75 deletions src/aws-cpp-sdk-core/source/client/AWSErrorMarshaller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,18 @@ static CoreErrors GuessBodylessErrorType(const Aws::Http::HttpResponseCode respo
}
}

AWSError<CoreErrors> JsonErrorMarshaller::Marshall(const Aws::Http::HttpResponse& httpResponse) const {
JsonValue JsonErrorMarshaller::GetJsonPayloadHttpResponse(const Http::HttpResponse& httpResponse) {
Aws::StringStream memoryStream;
std::copy(std::istreambuf_iterator<char>(httpResponse.GetResponseBody()), std::istreambuf_iterator<char>(),
std::ostreambuf_iterator<char>(memoryStream));
Aws::String rawPayloadStr = memoryStream.str();

JsonValue exceptionPayload(rawPayloadStr);
JsonView payloadView(exceptionPayload);
return JsonValue(rawPayloadStr);
}

AWSError<CoreErrors> JsonErrorMarshaller::Marshall(const Aws::Http::HttpResponse& httpResponse) const {
auto exceptionPayload = GetJsonPayloadHttpResponse(httpResponse);
auto payloadView = JsonView(exceptionPayload);
AWSError<CoreErrors> error;
if (exceptionPayload.WasParseSuccessful()) {
AWS_LOGSTREAM_TRACE(AWS_ERROR_MARSHALLER_LOG_TAG, "Error response is " << payloadView.WriteReadable());
Expand All @@ -68,10 +72,12 @@ AWSError<CoreErrors> JsonErrorMarshaller::Marshall(const Aws::Http::HttpResponse
} 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>(CoreErrors::UNKNOWN, "", "Failed to parse error payload: " + rawPayloadStr, isRetryable);
"Failed to parse error payload: " << httpResponse.GetResponseCode() << ": " << payloadView.AsString());
error = AWSError<CoreErrors>(CoreErrors::UNKNOWN, "", "Failed to parse error payload: " + payloadView.AsString(), isRetryable);
}

MarshallError(error, httpResponse);

error.SetRequestId(httpResponse.HasHeader(REQUEST_ID_HEADER) ? httpResponse.GetHeader(REQUEST_ID_HEADER) : "");
error.SetJsonPayload(std::move(exceptionPayload));
return error;
Expand Down Expand Up @@ -249,79 +255,46 @@ AWSError<CoreErrors> AWSErrorMarshaller::FindErrorByHttpResponseCode(Aws::Http::
return CoreErrorsMapper::GetErrorForHttpResponseCode(code);
}

AWSError<CoreErrors> JsonErrorMarshallerQueryCompatible::Marshall(const Aws::Http::HttpResponse& httpResponse) const {
Aws::StringStream memoryStream;
std::copy(std::istreambuf_iterator<char>(httpResponse.GetResponseBody()), std::istreambuf_iterator<char>(),
std::ostreambuf_iterator<char>(memoryStream));
Aws::String rawPayloadStr = memoryStream.str();

JsonValue exceptionPayload(rawPayloadStr);
JsonView payloadView(exceptionPayload);
AWSError<CoreErrors> 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)
: "");
void JsonErrorMarshallerQueryCompatible::MarshallError(AWSError<CoreErrors>& error, const Http::HttpResponse& httpResponse) const {
if (!error.GetExceptionName().empty()) {
auto exceptionPayload = GetJsonPayloadHttpResponse(httpResponse);
auto payloadView = JsonView(exceptionPayload);
/*
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;
}

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);
error.SetExceptionName(errorCode);
}

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));
}
// 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>(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;
}

0 comments on commit 1604dc7

Please sign in to comment.