Skip to content

Commit f7e4188

Browse files
authored
Add User Agent Api name for Cross region API calls (#4105)
* Add User Agent Api name for Cross region API calls * Added test case for default client not to have user agent related to cross region
1 parent 578cc0d commit f7e4188

File tree

5 files changed

+88
-4
lines changed

5 files changed

+88
-4
lines changed

services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crossregion/S3CrossRegionAsyncClient.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

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

18+
import static software.amazon.awssdk.services.s3.internal.crossregion.utils.CrossRegionUtils.updateUserAgentInConfig;
19+
1820
import java.util.Optional;
1921
import java.util.concurrent.CompletableFuture;
2022
import java.util.function.Function;
@@ -39,11 +41,14 @@ public S3CrossRegionAsyncClient(S3AsyncClient s3Client) {
3941

4042
Optional<String> bucket = request.getValueForField("Bucket", String.class);
4143

44+
AwsRequestOverrideConfiguration overrideConfiguration = updateUserAgentInConfig(request);
45+
T userAgentUpdatedRequest = (T) request.toBuilder().overrideConfiguration(overrideConfiguration).build();
46+
4247
if (!bucket.isPresent()) {
43-
return operation.apply(request);
48+
return operation.apply(userAgentUpdatedRequest);
4449
}
4550

46-
return operation.apply(requestWithDecoratedEndpointProvider(request, bucket.get()))
51+
return operation.apply(requestWithDecoratedEndpointProvider(userAgentUpdatedRequest, bucket.get()))
4752
.whenComplete((r, t) -> handleOperationFailure(t, bucket.get()));
4853
}
4954

services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crossregion/S3CrossRegionSyncClient.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

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

18+
import static software.amazon.awssdk.services.s3.internal.crossregion.utils.CrossRegionUtils.updateUserAgentInConfig;
19+
1820
import java.util.Optional;
1921
import java.util.concurrent.CompletableFuture;
2022
import java.util.function.Function;
@@ -38,15 +40,18 @@ protected <T extends S3Request, ReturnT> ReturnT invokeOperation(T request, Func
3840

3941
Optional<String> bucket = request.getValueForField("Bucket", String.class);
4042

43+
AwsRequestOverrideConfiguration overrideConfiguration = updateUserAgentInConfig(request);
44+
T userAgentUpdatedRequest = (T) request.toBuilder().overrideConfiguration(overrideConfiguration).build();
45+
4146
if (bucket.isPresent()) {
4247
try {
43-
return operation.apply(requestWithDecoratedEndpointProvider(request, bucket.get()));
48+
return operation.apply(requestWithDecoratedEndpointProvider(userAgentUpdatedRequest, bucket.get()));
4449
} catch (Exception e) {
4550
handleOperationFailure(e, bucket.get());
4651
}
4752
}
4853

49-
return operation.apply(request);
54+
return operation.apply(userAgentUpdatedRequest);
5055
}
5156

5257
private void handleOperationFailure(Throwable t, String bucket) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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.crossregion.utils;
17+
18+
19+
import java.util.function.Consumer;
20+
import software.amazon.awssdk.annotations.SdkInternalApi;
21+
import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration;
22+
import software.amazon.awssdk.core.ApiName;
23+
import software.amazon.awssdk.services.s3.model.S3Request;
24+
25+
@SdkInternalApi
26+
public final class CrossRegionUtils {
27+
private static final ApiName API_NAME = ApiName.builder().version("cross-region").name("hll").build();
28+
private static final Consumer<AwsRequestOverrideConfiguration.Builder> USER_AGENT_APPLIER = b -> b.addApiName(API_NAME);
29+
30+
private CrossRegionUtils() {
31+
}
32+
33+
public static <T extends S3Request> AwsRequestOverrideConfiguration updateUserAgentInConfig(T request) {
34+
AwsRequestOverrideConfiguration overrideConfiguration =
35+
request.overrideConfiguration().map(c -> c.toBuilder()
36+
.applyMutation(USER_AGENT_APPLIER)
37+
.build())
38+
.orElse(AwsRequestOverrideConfiguration.builder()
39+
.applyMutation(USER_AGENT_APPLIER)
40+
.build());
41+
return overrideConfiguration;
42+
}
43+
}

services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/crossregion/S3CrossRegionAsyncClientTest.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,20 @@ void crossRegionClient_createdWithWrapping_SuccessfullyIntercepts() {
9898
assertThat(captureInterceptor.endpointProvider).isInstanceOf(S3CrossRegionAsyncClient.BucketEndpointProvider.class);
9999
}
100100

101+
@Test
102+
void standardOp_crossRegionClient_containUserAgent() {
103+
S3AsyncClient crossRegionClient = clientBuilder().serviceConfiguration(c -> c.crossRegionAccessEnabled(true)).build();
104+
crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY), AsyncResponseTransformer.toBytes()).join();
105+
assertThat(mockAsyncHttpClient.getLastRequest().firstMatchingHeader("User-Agent").get()).contains("hll/cross-region");
106+
}
107+
108+
@Test
109+
void standardOp_simpleClient_doesNotContainCrossRegionUserAgent() {
110+
S3AsyncClient crossRegionClient = clientBuilder().serviceConfiguration(c -> c.crossRegionAccessEnabled(false)).build();
111+
crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY), AsyncResponseTransformer.toBytes()).join();
112+
assertThat(mockAsyncHttpClient.getLastRequest().firstMatchingHeader("User-Agent").get()).doesNotContain("hll/cross-region");
113+
}
114+
101115
private S3AsyncClientBuilder clientBuilder() {
102116
return S3AsyncClient.builder()
103117
.httpClient(mockAsyncHttpClient)

services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/crossregion/S3CrossRegionSyncClientTest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.net.URI;
2121
import org.junit.jupiter.api.BeforeEach;
2222
import org.junit.jupiter.api.Test;
23+
import software.amazon.awssdk.core.async.AsyncResponseTransformer;
2324
import software.amazon.awssdk.core.interceptor.Context;
2425
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
2526
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
@@ -28,6 +29,7 @@
2829
import software.amazon.awssdk.http.AbortableInputStream;
2930
import software.amazon.awssdk.http.HttpExecuteResponse;
3031
import software.amazon.awssdk.http.SdkHttpResponse;
32+
import software.amazon.awssdk.services.s3.S3AsyncClient;
3133
import software.amazon.awssdk.services.s3.S3Client;
3234
import software.amazon.awssdk.services.s3.S3ClientBuilder;
3335
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
@@ -95,6 +97,21 @@ void crossRegionClient_createdWithWrapping_SuccessfullyIntercepts() {
9597
assertThat(captureInterceptor.endpointProvider).isInstanceOf(S3CrossRegionSyncClient.BucketEndpointProvider.class);
9698
}
9799

100+
@Test
101+
void standardOp_crossRegionClient_containUserAgent() {
102+
S3Client crossRegionClient = clientBuilder().serviceConfiguration(c -> c.crossRegionAccessEnabled(true)).build();
103+
crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY));
104+
assertThat(mockSyncHttpClient.getLastRequest().firstMatchingHeader("User-Agent").get()).contains("hll/cross-region");
105+
}
106+
107+
@Test
108+
void standardOp_simpleClient_doesNotContainCrossRegionUserAgent() {
109+
S3Client crossRegionClient = clientBuilder().serviceConfiguration(c -> c.crossRegionAccessEnabled(false)).build();
110+
crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY));
111+
assertThat(mockSyncHttpClient.getLastRequest().firstMatchingHeader("User-Agent").get())
112+
.doesNotContain("hll/cross-region");
113+
}
114+
98115
private S3ClientBuilder clientBuilder() {
99116
return S3Client.builder()
100117
.httpClient(mockSyncHttpClient)

0 commit comments

Comments
 (0)