Skip to content

Commit 55f5348

Browse files
committed
Add cbor query compat error marshaling
1 parent 1803a43 commit 55f5348

File tree

2 files changed

+109
-0
lines changed

2 files changed

+109
-0
lines changed

src/aws-cpp-sdk-core/include/aws/core/client/AWSErrorMarshaller.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,5 +136,10 @@ namespace Aws
136136
static Aws::Utils::Cbor::CborValue GetCborPayloadHttpResponse(const Http::HttpResponse& httpResponse);
137137
};
138138

139+
class AWS_CORE_API RpcV2ErrorMarshallerQueryCompatible : public RpcV2ErrorMarshaller {
140+
protected:
141+
void MarshallError(AWSError<CoreErrors>&, const Http::HttpResponse&) const override;
142+
};
143+
139144
} // namespace Client
140145
} // namespace Aws

src/aws-cpp-sdk-core/source/client/AWSErrorMarshaller.cpp

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,110 @@ void JsonErrorMarshallerQueryCompatible::MarshallError(AWSError<CoreErrors>& err
301301
}
302302
}
303303

304+
void RpcV2ErrorMarshallerQueryCompatible::MarshallError(AWSError<CoreErrors>& error, const Http::HttpResponse& httpResponse) const {
305+
if (!error.GetExceptionName().empty()) {
306+
/*
307+
AWS Query-Compatible mode: This is a special setting that allows
308+
certain AWS services to communicate using a specific "query"
309+
format, which can send customized error codes. Users are divided
310+
into different groups based on how they communicate with the
311+
service: Group #1: Users using the AWS Query format, receiving
312+
custom error codes. Group #2: Users using the regular AWS Cbor
313+
format without the trait, receiving standard error codes. Group #3:
314+
Users using the AWS Cbor format with the trait, receiving custom
315+
error codes.
316+
317+
The header "x-amzn-query-error" shouldn't be present if it's not
318+
awsQueryCompatible, so added checks for it.
319+
*/
320+
321+
if (httpResponse.HasHeader(QUERY_ERROR_HEADER)) {
322+
auto errorCodeString = httpResponse.GetHeader(QUERY_ERROR_HEADER);
323+
auto locationOfSemicolon = errorCodeString.find_first_of(';');
324+
Aws::String errorCode;
325+
326+
if (locationOfSemicolon != Aws::String::npos) {
327+
errorCode = errorCodeString.substr(0, locationOfSemicolon);
328+
} else {
329+
errorCode = errorCodeString;
330+
}
331+
332+
error.SetExceptionName(errorCode);
333+
}
334+
// check for exception name from payload field 'type'
335+
else {
336+
// handle missing header and parse code from message
337+
auto exceptionPayload = GetCborPayloadHttpResponse(httpResponse);
338+
if (exceptionPayload.WasParseSuccessful()) {
339+
auto decoder = exceptionPayload.GetDecoder();
340+
Aws::String errorType;
341+
if (decoder != nullptr) {
342+
auto initialMapType = decoder->PeekType();
343+
if (initialMapType.has_value() && (initialMapType.value() == Aws::Crt::Cbor::CborType::MapStart ||
344+
initialMapType.value() == Aws::Crt::Cbor::CborType::IndefMapStart)) {
345+
if (initialMapType.value() == Aws::Crt::Cbor::CborType::MapStart) {
346+
auto mapSize = decoder->PopNextMapStart();
347+
if (mapSize.has_value()) {
348+
for (size_t i = 0; i < mapSize.value(); ++i) {
349+
auto key = decoder->PopNextTextVal();
350+
if (key.has_value()) {
351+
Aws::String keyStr(reinterpret_cast<const char*>(key.value().ptr), key.value().len);
352+
353+
if (keyStr == TYPE) {
354+
auto val = decoder->PopNextTextVal();
355+
if (val.has_value()) {
356+
errorType = Aws::String(reinterpret_cast<const char*>(val.value().ptr), val.value().len);
357+
}
358+
} else {
359+
decoder->ConsumeNextWholeDataItem();
360+
}
361+
}
362+
if (decoder->LastError() != AWS_ERROR_UNKNOWN) {
363+
break;
364+
}
365+
}
366+
}
367+
} else {
368+
decoder->ConsumeNextSingleElement();
369+
while (decoder->LastError() == AWS_ERROR_UNKNOWN) {
370+
auto nextType = decoder->PeekType();
371+
if (!nextType.has_value() || nextType.value() == Aws::Crt::Cbor::CborType::Break) {
372+
if (nextType.has_value()) {
373+
decoder->ConsumeNextSingleElement();
374+
}
375+
break;
376+
}
377+
378+
auto key = decoder->PopNextTextVal();
379+
if (key.has_value()) {
380+
const Aws::String keyStr(reinterpret_cast<const char*>(key.value().ptr), key.value().len);
381+
382+
if (keyStr == TYPE) {
383+
auto val = decoder->PopNextTextVal();
384+
if (val.has_value()) {
385+
errorType = Aws::String(reinterpret_cast<const char*>(val.value().ptr), val.value().len);
386+
}
387+
} else {
388+
decoder->ConsumeNextWholeDataItem();
389+
}
390+
}
391+
}
392+
}
393+
}
394+
}
395+
396+
if (errorType.empty()) {
397+
return;
398+
}
399+
auto locationOfPound = errorType.find_first_of('#');
400+
if (locationOfPound != Aws::String::npos) {
401+
error.SetExceptionName(errorType.substr(locationOfPound + 1));
402+
}
403+
}
404+
}
405+
}
406+
}
407+
304408
CborValue RpcV2ErrorMarshaller::GetCborPayloadHttpResponse(const Http::HttpResponse& httpResponse) {
305409
return CborValue(httpResponse.GetResponseBody());
306410
}

0 commit comments

Comments
 (0)