diff --git a/.changes/next-release/bugfix-AWSSDKforJavav2-a6e2ed8.json b/.changes/next-release/bugfix-AWSSDKforJavav2-a6e2ed8.json new file mode 100644 index 000000000000..83206605963c --- /dev/null +++ b/.changes/next-release/bugfix-AWSSDKforJavav2-a6e2ed8.json @@ -0,0 +1,6 @@ +{ + "category": "AWS SDK for Java v2", + "contributor": "", + "type": "bugfix", + "description": "Fixes a bug in XML error unmarshalling where error responses with empty body won't populate the requestId field. Affects Amazon S3 API calls such as Head object" +} diff --git a/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/unmarshall/AwsXmlErrorUnmarshaller.java b/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/unmarshall/AwsXmlErrorUnmarshaller.java index b94d2e3ca48c..3827eb831d45 100644 --- a/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/unmarshall/AwsXmlErrorUnmarshaller.java +++ b/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/unmarshall/AwsXmlErrorUnmarshaller.java @@ -27,6 +27,7 @@ import software.amazon.awssdk.awscore.exception.AwsServiceException; import software.amazon.awssdk.core.SdkBytes; import software.amazon.awssdk.core.SdkPojo; +import software.amazon.awssdk.core.http.HttpResponseHandler; import software.amazon.awssdk.core.interceptor.ExecutionAttributes; import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute; import software.amazon.awssdk.http.SdkHttpFullResponse; @@ -39,7 +40,6 @@ */ @SdkInternalApi public final class AwsXmlErrorUnmarshaller { - private static final String X_AMZN_REQUEST_ID_HEADER = "x-amzn-RequestId"; private static final String X_AMZ_ID_2_HEADER = "x-amz-id-2"; private final List exceptions; @@ -175,7 +175,16 @@ private String getRequestId(SdkHttpFullResponse response, XmlElement document) { .orElse(document.getElementByName("RequestID")); return requestId != null ? requestId.textContent() : - response.firstMatchingHeader(X_AMZN_REQUEST_ID_HEADER).orElse(null); + matchRequestIdHeaders(response); + } + + private String matchRequestIdHeaders(SdkHttpFullResponse response) { + return HttpResponseHandler.X_AMZN_REQUEST_ID_HEADERS.stream() + .map(h -> response.firstMatchingHeader(h)) + .filter(Optional::isPresent) + .map(Optional::get) + .findFirst() + .orElse(null); } /** diff --git a/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/exception/QueryExceptionTests.java b/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/exception/QueryExceptionTests.java index 1470d492041c..b65247235eda 100644 --- a/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/exception/QueryExceptionTests.java +++ b/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/exception/QueryExceptionTests.java @@ -286,6 +286,19 @@ public void requestIdAndExtendedRequestIdInHeader_IsSetOnException() { } } + @Test + public void alternateRequestIdInHeader_IsSetOnException() { + stubFor(post(urlEqualTo(PATH)).willReturn( + aResponse() + .withStatus(404) + .withHeader("x-amz-request-id", "1234"))); + try { + client.allTypes(); + } catch (ProtocolQueryException e) { + assertThat(e.requestId()).isEqualTo("1234"); + } + } + private void callAllTypes() { client.allTypes(AllTypesRequest.builder().build()); } diff --git a/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/exception/RestXmlExceptionTests.java b/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/exception/RestXmlExceptionTests.java index 99dc7a2b97a9..6630c3a2b773 100644 --- a/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/exception/RestXmlExceptionTests.java +++ b/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/exception/RestXmlExceptionTests.java @@ -216,6 +216,19 @@ public void illegalArgumentException_emptyPathParam() { IllegalArgumentException.class); } + @Test + public void alternateRequestIdInHeader_IsSetOnException() { + stubFor(post(urlEqualTo(ALL_TYPES_PATH)).willReturn( + aResponse() + .withStatus(404) + .withHeader("x-amz-request-id", "1234"))); + try { + client.allTypes(); + } catch (ProtocolRestXmlException e) { + assertThat(e.requestId()).isEqualTo("1234"); + } + } + private void callAllTypes() { client.allTypes(AllTypesRequest.builder().build()); }