Skip to content

Commit d27b8e3

Browse files
committed
Support ClientContextParams for S3CrtAsyncClient
1 parent b11e9b4 commit d27b8e3

File tree

4 files changed

+131
-9
lines changed

4 files changed

+131
-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 - Disabling multi region accesspoints\n - Using pathstyle addressing\n - Enabling using the region in an accesspoint ARN"
6+
}

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

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

179+
// S3 client context params, copied from S3BaseClientBuilder.
180+
/**
181+
* Enables this client to use S3 Transfer Acceleration endpoints.
182+
*/
183+
S3CrtAsyncClientBuilder accelerate(Boolean accelerate);
184+
185+
/**
186+
* Disables this client's usage of Multi-Region Access Points.
187+
*/
188+
S3CrtAsyncClientBuilder disableMultiRegionAccessPoints(Boolean disableMultiRegionAccessPoints);
189+
190+
/**
191+
* Forces this client to use path-style addressing for buckets.
192+
*/
193+
S3CrtAsyncClientBuilder forcePathStyle(Boolean forcePathStyle);
194+
195+
/**
196+
* Enables this client to use an ARN's region when constructing an endpoint instead of the client's configured
197+
* region.
198+
*/
199+
S3CrtAsyncClientBuilder useArnRegion(Boolean useArnRegion);
179200

180201
@Override
181202
S3AsyncClient build();

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

Lines changed: 63 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,33 @@ 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+
.disableMultiRegionAccessPoints(builder.disableMultiRegionAccessPoints)
101+
.forcePathStyle(builder.forcePathStyle)
102+
.useArnRegion(builder.useArnRegion)
88103
.httpClientBuilder(initializeS3CrtAsyncHttpClient(builder))
89104
.build();
90105
}
@@ -123,6 +138,12 @@ public static final class DefaultS3CrtClientBuilder implements S3CrtAsyncClientB
123138
private URI endpointOverride;
124139
private Boolean checksumValidationEnabled;
125140
private S3CrtHttpConfiguration httpConfiguration;
141+
private Boolean accelerate;
142+
private Boolean disableMultiRegionAccessPoints;
143+
private Boolean forcePathStyle;
144+
private Boolean useArnRegion;
145+
146+
private List<ExecutionInterceptor> executionInterceptors;
126147

127148
public AwsCredentialsProvider credentialsProvider() {
128149
return credentialsProvider;
@@ -206,6 +227,39 @@ public S3CrtAsyncClientBuilder httpConfiguration(S3CrtHttpConfiguration configur
206227
return this;
207228
}
208229

230+
@Override
231+
public S3CrtAsyncClientBuilder accelerate(Boolean accelerate) {
232+
this.accelerate = accelerate;
233+
return this;
234+
}
235+
236+
@Override
237+
public S3CrtAsyncClientBuilder disableMultiRegionAccessPoints(Boolean disableMultiRegionAccessPoints) {
238+
this.disableMultiRegionAccessPoints = disableMultiRegionAccessPoints;
239+
return this;
240+
}
241+
242+
@Override
243+
public S3CrtAsyncClientBuilder forcePathStyle(Boolean forcePathStyle) {
244+
this.forcePathStyle = forcePathStyle;
245+
return this;
246+
}
247+
248+
@Override
249+
public S3CrtAsyncClientBuilder useArnRegion(Boolean useArnRegion) {
250+
this.useArnRegion = useArnRegion;
251+
return this;
252+
}
253+
254+
@SdkTestInternalApi
255+
S3CrtAsyncClientBuilder addExecutionInterceptor(ExecutionInterceptor executionInterceptor) {
256+
if (executionInterceptors == null) {
257+
this.executionInterceptors = new ArrayList<>();
258+
}
259+
executionInterceptors.add(executionInterceptor);
260+
return this;
261+
}
262+
209263
@Override
210264
public S3CrtAsyncClient build() {
211265
return new DefaultS3CrtAsyncClient(this);

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

Lines changed: 41 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,39 @@ 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+
.disableMultiRegionAccessPoints(true)
70+
.forcePathStyle(true)
71+
.useArnRegion(true)
72+
.build()) {
73+
74+
assertThatThrownBy(s3AsyncClient.listBuckets()::join).hasMessageContaining("BOOM");
75+
AttributeMap attributeMap = clientContexParams.get();
76+
77+
assertThat(attributeMap.get(S3ClientContextParams.ACCELERATE)).isFalse();
78+
assertThat(attributeMap.get(S3ClientContextParams.DISABLE_MULTI_REGION_ACCESS_POINTS)).isTrue();
79+
assertThat(attributeMap.get(S3ClientContextParams.FORCE_PATH_STYLE)).isTrue();
80+
assertThat(attributeMap.get(S3ClientContextParams.USE_ARN_REGION)).isTrue();
81+
}
82+
}
83+
4384
@ParameterizedTest
4485
@ValueSource(longs = {0, -1L})
4586
void invalidConfig_shouldThrowException(long value) {

0 commit comments

Comments
 (0)