@@ -40,11 +40,6 @@ static CoreErrors GuessBodylessErrorType(const Aws::Http::HttpResponseCode respo
4040 }
4141}
4242
43- JsonErrorMarshaller::JsonErrorMarshaller (bool queryCompatibilityMode)
44- : AWSErrorMarshaller(), m_queryCompatibilityMode{queryCompatibilityMode} {}
45-
46- bool JsonErrorMarshaller::isQueryCompatibleMode () const { return m_queryCompatibilityMode; }
47-
4843AWSError<CoreErrors> JsonErrorMarshaller::Marshall (const Aws::Http::HttpResponse& httpResponse) const {
4944 Aws::StringStream memoryStream;
5045 std::copy (std::istreambuf_iterator<char >(httpResponse.GetResponseBody ()), std::istreambuf_iterator<char >(),
@@ -70,46 +65,6 @@ AWSError<CoreErrors> JsonErrorMarshaller::Marshall(const Aws::Http::HttpResponse
7065 error.SetMessage (message);
7166 }
7267
73- if (isQueryCompatibleMode () && !error.GetExceptionName ().empty ()) {
74- /*
75- AWS Query-Compatible mode: This is a special setting that allows
76- certain AWS services to communicate using a specific "query"
77- format, which can send customized error codes. Users are divided
78- into different groups based on how they communicate with the
79- service: Group #1: Users using the AWS Query format, receiving
80- custom error codes. Group #2: Users using the regular AWS JSON
81- format without the trait, receiving standard error codes. Group #3:
82- Users using the AWS JSON format with the trait, receiving custom
83- error codes.
84-
85- The header "x-amzn-query-error" shouldn't be present if it's not
86- awsQueryCompatible, so added checks for it.
87- */
88-
89- if (httpResponse.HasHeader (QUERY_ERROR_HEADER)) {
90- auto errorCodeString = httpResponse.GetHeader (QUERY_ERROR_HEADER);
91- auto locationOfSemicolon = errorCodeString.find_first_of (' ;' );
92- Aws::String errorCode;
93-
94- if (locationOfSemicolon != Aws::String::npos) {
95- errorCode = errorCodeString.substr (0 , locationOfSemicolon);
96- } else {
97- errorCode = errorCodeString;
98- }
99-
100- error.SetExceptionName (errorCode);
101- }
102- // check for exception name from payload field 'type'
103- else if (payloadView.ValueExists (TYPE)) {
104- // handle missing header and parse code from message
105- const auto & typeStr = payloadView.GetString (TYPE);
106- auto locationOfPound = typeStr.find_first_of (' #' );
107- if (locationOfPound != Aws::String::npos) {
108- error.SetExceptionName (typeStr.substr (locationOfPound + 1 ));
109- }
110- }
111- }
112-
11368 } else {
11469 bool isRetryable = IsRetryableHttpResponseCode (httpResponse.GetResponseCode ());
11570 AWS_LOGSTREAM_ERROR (AWS_ERROR_MARSHALLER_LOG_TAG,
@@ -146,67 +101,60 @@ AWSError<CoreErrors> JsonErrorMarshaller::BuildAWSError(const std::shared_ptr<Ht
146101 return error;
147102}
148103
149- const JsonValue& JsonErrorMarshaller::GetJsonPayloadFromError (const AWSError<CoreErrors>& error) const
150- {
151- return error.GetJsonPayload ();
152- }
104+ const JsonValue& JsonErrorMarshaller::GetJsonPayloadFromError (const AWSError<CoreErrors>& error) const { return error.GetJsonPayload (); }
153105
154- AWSError<CoreErrors> XmlErrorMarshaller::Marshall (const Aws::Http::HttpResponse& httpResponse) const
155- {
156- XmlDocument doc = XmlDocument::CreateFromXmlStream (httpResponse.GetResponseBody ());
157- AWS_LOGSTREAM_TRACE (AWS_ERROR_MARSHALLER_LOG_TAG, " Error response is " << doc.ConvertToString ());
158- bool errorParsed = false ;
159- AWSError<CoreErrors> error;
160- if (doc.WasParseSuccessful ())
161- {
162- XmlNode errorNode = doc.GetRootElement ();
106+ AWSError<CoreErrors> XmlErrorMarshaller::Marshall (const Aws::Http::HttpResponse& httpResponse) const {
107+ XmlDocument doc = XmlDocument::CreateFromXmlStream (httpResponse.GetResponseBody ());
108+ AWS_LOGSTREAM_TRACE (AWS_ERROR_MARSHALLER_LOG_TAG, " Error response is " << doc.ConvertToString ());
109+ bool errorParsed = false ;
110+ AWSError<CoreErrors> error;
111+ if (doc.WasParseSuccessful ()) {
112+ XmlNode errorNode = doc.GetRootElement ();
163113
164- Aws::String requestId (!errorNode.FirstChild (" RequestId" ).IsNull () ? errorNode.FirstChild (" RequestId" ).GetText () :
165- !errorNode.FirstChild (" RequestID" ).IsNull () ? errorNode.FirstChild (" RequestID" ).GetText () : " " );
114+ Aws::String requestId (!errorNode.FirstChild (" RequestId" ).IsNull () ? errorNode.FirstChild (" RequestId" ).GetText ()
115+ : !errorNode.FirstChild (" RequestID" ).IsNull () ? errorNode.FirstChild (" RequestID" ).GetText ()
116+ : " " );
166117
167- if (errorNode.GetName () != " Error" )
168- {
169- errorNode = doc.GetRootElement ().FirstChild (" Error" );
170- }
171- if (errorNode.IsNull ())
172- {
173- errorNode = doc.GetRootElement ().FirstChild (" Errors" );
174- if (!errorNode.IsNull ())
175- {
176- errorNode = errorNode.FirstChild (" Error" );
177- }
178- }
118+ if (errorNode.GetName () != " Error" ) {
119+ errorNode = doc.GetRootElement ().FirstChild (" Error" );
120+ }
121+ if (errorNode.IsNull ()) {
122+ errorNode = doc.GetRootElement ().FirstChild (" Errors" );
123+ if (!errorNode.IsNull ()) {
124+ errorNode = errorNode.FirstChild (" Error" );
125+ }
126+ }
179127
180- if (!errorNode.IsNull ())
181- {
182- requestId = !requestId.empty () ? requestId : !errorNode.FirstChild (" RequestId" ).IsNull () ? errorNode.FirstChild (" RequestId" ).GetText () :
183- !errorNode.FirstChild (" RequestID" ).IsNull () ? errorNode.FirstChild (" RequestID" ).GetText () : " " ;
184-
185- XmlNode codeNode = errorNode.FirstChild (" Code" );
186- XmlNode messageNode = errorNode.FirstChild (" Message" );
187-
188- if (!codeNode.IsNull ())
189- {
190- error = Marshall (StringUtils::Trim (codeNode.GetText ().c_str ()),
191- StringUtils::Trim (messageNode.GetText ().c_str ()));
192- errorParsed = true ;
193- }
194- }
128+ if (!errorNode.IsNull ()) {
129+ requestId = !requestId.empty () ? requestId
130+ : !errorNode.FirstChild (" RequestId" ).IsNull () ? errorNode.FirstChild (" RequestId" ).GetText ()
131+ : !errorNode.FirstChild (" RequestID" ).IsNull () ? errorNode.FirstChild (" RequestID" ).GetText ()
132+ : " " ;
195133
196- error. SetRequestId (requestId );
197- }
134+ XmlNode codeNode = errorNode. FirstChild ( " Code " );
135+ XmlNode messageNode = errorNode. FirstChild ( " Message " );
198136
199- if (!errorParsed)
200- {
201- // An error occurred attempting to parse the httpResponse as an XML stream, so we're just
202- // going to dump the XML parsing error and the http response code as a string
203- AWS_LOGSTREAM_WARN (AWS_ERROR_MARSHALLER_LOG_TAG, " Unable to generate a proper httpResponse from the response "
204- " stream. Response code: " << static_cast < uint32_t >(httpResponse.GetResponseCode ()));
205- error = FindErrorByHttpResponseCode (httpResponse.GetResponseCode ());
137+ if (!codeNode.IsNull ()) {
138+ error = Marshall (StringUtils::Trim (codeNode.GetText ().c_str ()), StringUtils::Trim (messageNode.GetText ().c_str ()));
139+ errorParsed = true ;
140+ }
206141 }
207142
208- error.SetXmlPayload (std::move (doc));
209- return error;
143+ error.SetRequestId (requestId);
144+ }
145+
146+ if (!errorParsed) {
147+ // An error occurred attempting to parse the httpResponse as an XML stream, so we're just
148+ // going to dump the XML parsing error and the http response code as a string
149+ AWS_LOGSTREAM_WARN (AWS_ERROR_MARSHALLER_LOG_TAG,
150+ " Unable to generate a proper httpResponse from the response "
151+ " stream. Response code: "
152+ << static_cast <uint32_t >(httpResponse.GetResponseCode ()));
153+ error = FindErrorByHttpResponseCode (httpResponse.GetResponseCode ());
154+ }
155+
156+ error.SetXmlPayload (std::move (doc));
157+ return error;
210158}
211159
212160AWSError<CoreErrors> XmlErrorMarshaller::BuildAWSError (const std::shared_ptr<Http::HttpResponse>& httpResponse) const
@@ -300,3 +248,82 @@ AWSError<CoreErrors> AWSErrorMarshaller::FindErrorByHttpResponseCode(Aws::Http::
300248{
301249 return CoreErrorsMapper::GetErrorForHttpResponseCode (code);
302250}
251+
252+
253+ AWSError<CoreErrors> JsonErrorMarshallerQueryCompatible::Marshall (const Aws::Http::HttpResponse& httpResponse) const
254+ {
255+ Aws::StringStream memoryStream;
256+ std::copy (std::istreambuf_iterator<char >(httpResponse.GetResponseBody ()), std::istreambuf_iterator<char >(),
257+ std::ostreambuf_iterator<char >(memoryStream));
258+ Aws::String rawPayloadStr = memoryStream.str ();
259+
260+ JsonValue exceptionPayload (rawPayloadStr);
261+ JsonView payloadView (exceptionPayload);
262+ AWSError<CoreErrors> error;
263+ if (exceptionPayload.WasParseSuccessful ()) {
264+ AWS_LOGSTREAM_TRACE (AWS_ERROR_MARSHALLER_LOG_TAG, " Error response is " << payloadView.WriteReadable ());
265+
266+ Aws::String message (payloadView.ValueExists (MESSAGE_CAMEL_CASE) ? payloadView.GetString (MESSAGE_CAMEL_CASE)
267+ : payloadView.ValueExists (MESSAGE_LOWER_CASE) ? payloadView.GetString (MESSAGE_LOWER_CASE)
268+ : " " );
269+
270+ if (httpResponse.HasHeader (ERROR_TYPE_HEADER)) {
271+ error = Marshall (httpResponse.GetHeader (ERROR_TYPE_HEADER), message);
272+ } else if (payloadView.ValueExists (TYPE)) {
273+ error = Marshall (payloadView.GetString (TYPE), message);
274+ } else {
275+ error = FindErrorByHttpResponseCode (httpResponse.GetResponseCode ());
276+ error.SetMessage (message);
277+ }
278+
279+ if (!error.GetExceptionName ().empty ()) {
280+ /*
281+ AWS Query-Compatible mode: This is a special setting that allows
282+ certain AWS services to communicate using a specific "query"
283+ format, which can send customized error codes. Users are divided
284+ into different groups based on how they communicate with the
285+ service: Group #1: Users using the AWS Query format, receiving
286+ custom error codes. Group #2: Users using the regular AWS JSON
287+ format without the trait, receiving standard error codes. Group #3:
288+ Users using the AWS JSON format with the trait, receiving custom
289+ error codes.
290+
291+ The header "x-amzn-query-error" shouldn't be present if it's not
292+ awsQueryCompatible, so added checks for it.
293+ */
294+
295+ if (httpResponse.HasHeader (QUERY_ERROR_HEADER)) {
296+ auto errorCodeString = httpResponse.GetHeader (QUERY_ERROR_HEADER);
297+ auto locationOfSemicolon = errorCodeString.find_first_of (' ;' );
298+ Aws::String errorCode;
299+
300+ if (locationOfSemicolon != Aws::String::npos) {
301+ errorCode = errorCodeString.substr (0 , locationOfSemicolon);
302+ } else {
303+ errorCode = errorCodeString;
304+ }
305+
306+ error.SetExceptionName (errorCode);
307+ }
308+ // check for exception name from payload field 'type'
309+ else if (payloadView.ValueExists (TYPE)) {
310+ // handle missing header and parse code from message
311+ const auto & typeStr = payloadView.GetString (TYPE);
312+ auto locationOfPound = typeStr.find_first_of (' #' );
313+ if (locationOfPound != Aws::String::npos) {
314+ error.SetExceptionName (typeStr.substr (locationOfPound + 1 ));
315+ }
316+ }
317+ }
318+
319+ } else {
320+ bool isRetryable = IsRetryableHttpResponseCode (httpResponse.GetResponseCode ());
321+ AWS_LOGSTREAM_ERROR (AWS_ERROR_MARSHALLER_LOG_TAG,
322+ " Failed to parse error payload: " << httpResponse.GetResponseCode () << " : " << rawPayloadStr);
323+ error = AWSError<CoreErrors>(CoreErrors::UNKNOWN, " " , " Failed to parse error payload: " + rawPayloadStr, isRetryable);
324+ }
325+
326+ error.SetRequestId (httpResponse.HasHeader (REQUEST_ID_HEADER) ? httpResponse.GetHeader (REQUEST_ID_HEADER) : " " );
327+ error.SetJsonPayload (std::move (exceptionPayload));
328+ return error;
329+ }
0 commit comments