Skip to content

Commit d126935

Browse files
authored
Support ClientContextParams for S3CrtAsyncClient (#3880)
Only support UseArnRegion and ForcePathStyle as they're the only ones we can support with the CRT client.
1 parent 11c5ef1 commit d126935

File tree

4 files changed

+103
-9
lines changed

4 files changed

+103
-9
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"type": "feature",
3+
"category": "Amazon S3",
4+
"contributor": "",
5+
"description": "Add support for the following in the CRT S3 client:\n\n - Enabling/disabling accelerate endpoints\n - Using pathstyle addressing"
6+
}

services/s3/src/main/java/software/amazon/awssdk/services/s3/S3CrtAsyncClientBuilder.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,17 @@ default S3CrtAsyncClientBuilder httpConfiguration(Consumer<S3CrtHttpConfiguratio
176176
.build());
177177
}
178178

179+
// S3 client context params, copied from S3BaseClientBuilder. Note we only have accelerate and path style because they're
180+
// the only ones we can support in the CRT client (does not affect signing).
181+
/**
182+
* Enables this client to use S3 Transfer Acceleration endpoints.
183+
*/
184+
S3CrtAsyncClientBuilder accelerate(Boolean accelerate);
185+
186+
/**
187+
* Forces this client to use path-style addressing for buckets.
188+
*/
189+
S3CrtAsyncClientBuilder forcePathStyle(Boolean forcePathStyle);
179190

180191
@Override
181192
S3AsyncClient build();

services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/DefaultS3CrtAsyncClient.java

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,17 @@
2121
import static software.amazon.awssdk.services.s3.internal.crt.S3NativeClientConfiguration.DEFAULT_PART_SIZE_IN_BYTES;
2222

2323
import java.net.URI;
24+
import java.util.ArrayList;
25+
import java.util.List;
2426
import java.util.concurrent.CompletableFuture;
2527
import software.amazon.awssdk.annotations.SdkInternalApi;
28+
import software.amazon.awssdk.annotations.SdkTestInternalApi;
2629
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
2730
import software.amazon.awssdk.awscore.AwsRequest;
2831
import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration;
2932
import software.amazon.awssdk.core.SdkRequest;
3033
import software.amazon.awssdk.core.checksums.ChecksumValidation;
34+
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
3135
import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption;
3236
import software.amazon.awssdk.core.interceptor.Context;
3337
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
@@ -69,22 +73,31 @@ public CompletableFuture<CopyObjectResponse> copyObject(CopyObjectRequest copyOb
6973
}
7074

7175
private static S3AsyncClient initializeS3AsyncClient(DefaultS3CrtClientBuilder builder) {
76+
ClientOverrideConfiguration.Builder overrideConfigurationBuilder =
77+
ClientOverrideConfiguration.builder()
78+
// Disable checksum, retry policy and signer because they are handled in crt
79+
.putAdvancedOption(SdkAdvancedClientOption.SIGNER, new NoOpSigner())
80+
.putExecutionAttribute(SdkExecutionAttribute.HTTP_RESPONSE_CHECKSUM_VALIDATION,
81+
ChecksumValidation.FORCE_SKIP)
82+
.retryPolicy(RetryPolicy.none())
83+
.addExecutionInterceptor(new ValidateRequestInterceptor())
84+
.addExecutionInterceptor(new AttachHttpAttributesExecutionInterceptor());
85+
86+
if (builder.executionInterceptors != null) {
87+
builder.executionInterceptors.forEach(overrideConfigurationBuilder::addExecutionInterceptor);
88+
}
89+
7290
return S3AsyncClient.builder()
73-
// Disable checksum, retry policy and signer because they are handled in crt
91+
// Disable checksum, it is handled in CRT
7492
.serviceConfiguration(S3Configuration.builder()
7593
.checksumValidationEnabled(false)
7694
.build())
7795
.region(builder.region)
7896
.endpointOverride(builder.endpointOverride)
7997
.credentialsProvider(builder.credentialsProvider)
80-
.overrideConfiguration(o -> o.putAdvancedOption(SdkAdvancedClientOption.SIGNER,
81-
new NoOpSigner())
82-
.putExecutionAttribute(
83-
SdkExecutionAttribute.HTTP_RESPONSE_CHECKSUM_VALIDATION,
84-
ChecksumValidation.FORCE_SKIP)
85-
.retryPolicy(RetryPolicy.none())
86-
.addExecutionInterceptor(new ValidateRequestInterceptor())
87-
.addExecutionInterceptor(new AttachHttpAttributesExecutionInterceptor()))
98+
.overrideConfiguration(overrideConfigurationBuilder.build())
99+
.accelerate(builder.accelerate)
100+
.forcePathStyle(builder.forcePathStyle)
88101
.httpClientBuilder(initializeS3CrtAsyncHttpClient(builder))
89102
.build();
90103
}
@@ -123,6 +136,10 @@ public static final class DefaultS3CrtClientBuilder implements S3CrtAsyncClientB
123136
private URI endpointOverride;
124137
private Boolean checksumValidationEnabled;
125138
private S3CrtHttpConfiguration httpConfiguration;
139+
private Boolean accelerate;
140+
private Boolean forcePathStyle;
141+
142+
private List<ExecutionInterceptor> executionInterceptors;
126143

127144
public AwsCredentialsProvider credentialsProvider() {
128145
return credentialsProvider;
@@ -206,6 +223,27 @@ public S3CrtAsyncClientBuilder httpConfiguration(S3CrtHttpConfiguration configur
206223
return this;
207224
}
208225

226+
@Override
227+
public S3CrtAsyncClientBuilder accelerate(Boolean accelerate) {
228+
this.accelerate = accelerate;
229+
return this;
230+
}
231+
232+
@Override
233+
public S3CrtAsyncClientBuilder forcePathStyle(Boolean forcePathStyle) {
234+
this.forcePathStyle = forcePathStyle;
235+
return this;
236+
}
237+
238+
@SdkTestInternalApi
239+
S3CrtAsyncClientBuilder addExecutionInterceptor(ExecutionInterceptor executionInterceptor) {
240+
if (executionInterceptors == null) {
241+
this.executionInterceptors = new ArrayList<>();
242+
}
243+
executionInterceptors.add(executionInterceptor);
244+
return this;
245+
}
246+
209247
@Override
210248
public S3CrtAsyncClient build() {
211249
return new DefaultS3CrtAsyncClient(this);

services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/crt/DefaultS3CrtAsyncClientTest.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,23 @@
1515

1616
package software.amazon.awssdk.services.s3.internal.crt;
1717

18+
import static org.assertj.core.api.Assertions.assertThat;
1819
import static org.assertj.core.api.Assertions.assertThatThrownBy;
1920

21+
import java.util.concurrent.atomic.AtomicReference;
2022
import org.junit.jupiter.api.Test;
2123
import org.junit.jupiter.params.ParameterizedTest;
2224
import org.junit.jupiter.params.provider.ValueSource;
2325
import software.amazon.awssdk.auth.signer.AwsS3V4Signer;
2426
import software.amazon.awssdk.core.async.AsyncRequestBody;
2527
import software.amazon.awssdk.core.async.AsyncResponseTransformer;
28+
import software.amazon.awssdk.core.interceptor.Context;
29+
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
30+
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
31+
import software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute;
2632
import software.amazon.awssdk.services.s3.S3AsyncClient;
33+
import software.amazon.awssdk.services.s3.endpoints.S3ClientContextParams;
34+
import software.amazon.awssdk.utils.AttributeMap;
2735

2836
class DefaultS3CrtAsyncClientTest {
2937

@@ -40,6 +48,37 @@ void requestSignerOverrideProvided_shouldThrowException() {
4048
}
4149
}
4250

51+
@Test
52+
void clientContextParamsSetOnBuilder_propagatedToInterceptors() {
53+
AtomicReference<AttributeMap> clientContexParams = new AtomicReference<>();
54+
55+
ExecutionInterceptor paramsCaptor = new ExecutionInterceptor() {
56+
@Override
57+
public void beforeExecution(Context.BeforeExecution context, ExecutionAttributes executionAttributes) {
58+
clientContexParams.set(executionAttributes.getAttribute(SdkInternalExecutionAttribute.CLIENT_CONTEXT_PARAMS));
59+
throw new RuntimeException("BOOM");
60+
}
61+
};
62+
63+
DefaultS3CrtAsyncClient.DefaultS3CrtClientBuilder builder =
64+
(DefaultS3CrtAsyncClient.DefaultS3CrtClientBuilder) S3CrtAsyncClient.builder();
65+
66+
builder.addExecutionInterceptor(paramsCaptor);
67+
68+
try (S3AsyncClient s3AsyncClient = builder.accelerate(false)
69+
.forcePathStyle(true)
70+
.build()) {
71+
72+
assertThatThrownBy(s3AsyncClient.listBuckets()::join).hasMessageContaining("BOOM");
73+
AttributeMap attributeMap = clientContexParams.get();
74+
75+
assertThat(attributeMap.get(S3ClientContextParams.ACCELERATE)).isFalse();
76+
assertThat(attributeMap.get(S3ClientContextParams.FORCE_PATH_STYLE)).isTrue();
77+
assertThat(attributeMap.get(S3ClientContextParams.USE_ARN_REGION)).isFalse();
78+
assertThat(attributeMap.get(S3ClientContextParams.DISABLE_MULTI_REGION_ACCESS_POINTS)).isFalse();
79+
}
80+
}
81+
4382
@ParameterizedTest
4483
@ValueSource(longs = {0, -1L})
4584
void invalidConfig_shouldThrowException(long value) {

0 commit comments

Comments
 (0)