Skip to content

Commit f11ba79

Browse files
committed
Check the header for responses when the header is not returned by the service. Fixes #1209.
1 parent ab7e5df commit f11ba79

File tree

4 files changed

+75
-1
lines changed

4 files changed

+75
-1
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"type": "bugfix",
3+
"category": "Amazon S3",
4+
"description": "Check the `x-amz-content-range` header for `GetObject` responses when the `Content-Range` header is not returned by the service. Fixes [#1209](https://github.com/aws/aws-sdk-java-v2/issues/1209)."
5+
}

services/s3/src/it/java/software/amazon/awssdk/services/s3/GetObjectIntegrationTest.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ public void toInputStream() throws Exception {
7474
}
7575
}
7676

77-
7877
@Test
7978
public void toInputStream_loadFromProperties() throws IOException {
8079
s3.putObject(b -> b.bucket(BUCKET).key(PROPERTY_KEY), RequestBody.fromString("test: test"));
@@ -117,6 +116,13 @@ public void customResponseHandler_InterceptorRecievesResponsePojo() throws Excep
117116
}
118117
}
119118

119+
@Test
120+
public void contentRangeIsReturnedForRangeRequests() {
121+
ResponseInputStream<GetObjectResponse> stream = s3.getObject(getObjectRequest.copy(r -> r.range("bytes=0-1")));
122+
stream.abort();
123+
assertThat(stream.response().contentRange()).isEqualTo("bytes 0-1/10000");
124+
}
125+
120126
private S3Client createClientWithInterceptor(ExecutionInterceptor interceptor) {
121127
return s3ClientBuilder().overrideConfiguration(ClientOverrideConfiguration.builder()
122128
.addExecutionInterceptor(interceptor)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.services.s3.internal.handlers;
17+
18+
import java.util.Optional;
19+
import software.amazon.awssdk.annotations.SdkInternalApi;
20+
import software.amazon.awssdk.core.SdkResponse;
21+
import software.amazon.awssdk.core.interceptor.Context;
22+
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
23+
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
24+
import software.amazon.awssdk.http.SdkHttpResponse;
25+
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
26+
import software.amazon.awssdk.services.s3.model.GetObjectResponse;
27+
28+
/**
29+
* Interceptor for {@link GetObjectRequest} messages.
30+
*/
31+
@SdkInternalApi
32+
public class GetObjectInterceptor implements ExecutionInterceptor {
33+
@Override
34+
public SdkResponse modifyResponse(Context.ModifyResponse context, ExecutionAttributes executionAttributes) {
35+
SdkResponse response = context.response();
36+
if (!(response instanceof GetObjectResponse)) {
37+
return response;
38+
}
39+
40+
return fixContentRange(response, context.httpResponse());
41+
}
42+
43+
/**
44+
* S3 currently returns content-range in two possible headers: Content-Range or x-amz-content-range based on the x-amz-te
45+
* in the request. This will check the x-amz-content-range if the modeled header (Content-Range) wasn't populated.
46+
*/
47+
private SdkResponse fixContentRange(SdkResponse sdkResponse, SdkHttpResponse httpResponse) {
48+
// Use the modeled content range header, if the service returned it.
49+
GetObjectResponse getObjectResponse = (GetObjectResponse) sdkResponse;
50+
if (getObjectResponse.contentRange() != null) {
51+
return getObjectResponse;
52+
}
53+
54+
// If the service didn't use the modeled content range header, check the x-amz-content-range header.
55+
Optional<String> xAmzContentRange = httpResponse.firstMatchingHeader("x-amz-content-range");
56+
if (!xAmzContentRange.isPresent()) {
57+
return getObjectResponse;
58+
}
59+
60+
return getObjectResponse.copy(r -> r.contentRange(xAmzContentRange.get()));
61+
}
62+
}

services/s3/src/main/resources/software/amazon/awssdk/services/s3/execution.interceptors

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ software.amazon.awssdk.services.s3.internal.handlers.AsyncChecksumValidationInte
1111
software.amazon.awssdk.services.s3.internal.handlers.SyncChecksumValidationInterceptor
1212
software.amazon.awssdk.services.s3.internal.handlers.EnableTrailingChecksumInterceptor
1313
software.amazon.awssdk.services.s3.internal.handlers.ExceptionTranslationInterceptor
14+
software.amazon.awssdk.services.s3.internal.handlers.GetObjectInterceptor

0 commit comments

Comments
 (0)