Skip to content

Commit a5a0405

Browse files
Quanzzzzdagnir
authored andcommitted
Add S3 Object Lambda customizations
1 parent 12d3094 commit a5a0405

24 files changed

+1955
-15
lines changed

core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/handler/AwsClientHandlerUtils.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import software.amazon.awssdk.core.RequestOverrideConfiguration;
3535
import software.amazon.awssdk.core.SdkRequest;
3636
import software.amazon.awssdk.core.SdkResponse;
37+
import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption;
3738
import software.amazon.awssdk.core.client.config.SdkClientConfiguration;
3839
import software.amazon.awssdk.core.client.config.SdkClientOption;
3940
import software.amazon.awssdk.core.client.handler.ClientExecutionParams;
@@ -95,7 +96,9 @@ static <InputT extends SdkRequest, OutputT extends SdkResponse> ExecutionContext
9596
.putAttribute(SdkExecutionAttribute.SERVICE_NAME, clientConfig.option(SdkClientOption.SERVICE_NAME))
9697
.putAttribute(SdkExecutionAttribute.OPERATION_NAME, executionParams.getOperationName())
9798
.putAttribute(SdkExecutionAttribute.CLIENT_ENDPOINT, clientConfig.option(SdkClientOption.ENDPOINT))
98-
.putAttribute(SdkExecutionAttribute.ENDPOINT_OVERRIDDEN, clientConfig.option(SdkClientOption.ENDPOINT_OVERRIDDEN));
99+
.putAttribute(SdkExecutionAttribute.ENDPOINT_OVERRIDDEN, clientConfig.option(SdkClientOption.ENDPOINT_OVERRIDDEN))
100+
.putAttribute(SdkInternalExecutionAttribute.DISABLE_HOST_PREFIX_INJECTION,
101+
clientConfig.option(SdkAdvancedClientOption.DISABLE_HOST_PREFIX_INJECTION));
99102

100103
ExecutionInterceptorChain executionInterceptorChain =
101104
new ExecutionInterceptorChain(clientConfig.option(SdkClientOption.EXECUTION_INTERCEPTORS));

core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/SdkInternalExecutionAttribute.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ public final class SdkInternalExecutionAttribute extends SdkExecutionAttribute {
3333
public static final ExecutionAttribute<HttpChecksumRequired> HTTP_CHECKSUM_REQUIRED =
3434
new ExecutionAttribute<>("HttpChecksumRequired");
3535

36+
/**
37+
* Whether host prefix injection has been disbabled on the client.
38+
* See {@link software.amazon.awssdk.core.client.config.SdkAdvancedClientOption#DISABLE_HOST_PREFIX_INJECTION}
39+
*/
40+
public static final ExecutionAttribute<Boolean> DISABLE_HOST_PREFIX_INJECTION =
41+
new ExecutionAttribute<>("DisableHostPrefixInjection");
42+
3643
private SdkInternalExecutionAttribute() {
3744
}
3845
}

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import software.amazon.awssdk.regions.Region;
3939
import software.amazon.awssdk.services.s3.internal.endpoints.S3EndpointResolverContext;
4040
import software.amazon.awssdk.services.s3.internal.endpoints.S3EndpointResolverFactory;
41+
import software.amazon.awssdk.services.s3.internal.endpoints.S3EndpointResolverFactoryContext;
4142
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
4243
import software.amazon.awssdk.services.s3.model.GetUrlRequest;
4344
import software.amazon.awssdk.utils.Validate;
@@ -168,7 +169,12 @@ public URL getUrl(GetUrlRequest getUrlRequest) {
168169
.serviceConfiguration(s3Configuration)
169170
.build();
170171

171-
SdkHttpRequest httpRequest = S3EndpointResolverFactory.getEndpointResolver(getObjectRequest.bucket())
172+
S3EndpointResolverFactoryContext resolverFactoryContext = S3EndpointResolverFactoryContext.builder()
173+
.bucketName(getObjectRequest.bucket())
174+
.originalRequest(getObjectRequest)
175+
.build();
176+
177+
SdkHttpRequest httpRequest = S3EndpointResolverFactory.getEndpointResolver(resolverFactoryContext)
172178
.applyEndpointConfiguration(resolverContext)
173179
.sdkHttpRequest();
174180

services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/endpoints/S3AccessPointEndpointResolver.java

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import static software.amazon.awssdk.services.s3.internal.endpoints.S3EndpointUtils.removeFipsIfNeeded;
2525

2626
import java.net.URI;
27+
import java.util.Optional;
2728
import software.amazon.awssdk.annotations.SdkInternalApi;
2829
import software.amazon.awssdk.arns.Arn;
2930
import software.amazon.awssdk.http.SdkHttpRequest;
@@ -34,6 +35,8 @@
3435
import software.amazon.awssdk.services.s3.internal.resource.S3AccessPointBuilder;
3536
import software.amazon.awssdk.services.s3.internal.resource.S3AccessPointResource;
3637
import software.amazon.awssdk.services.s3.internal.resource.S3ArnConverter;
38+
import software.amazon.awssdk.services.s3.internal.resource.S3ObjectLambdaEndpointBuilder;
39+
import software.amazon.awssdk.services.s3.internal.resource.S3ObjectLambdaResource;
3740
import software.amazon.awssdk.services.s3.internal.resource.S3OutpostAccessPointBuilder;
3841
import software.amazon.awssdk.services.s3.internal.resource.S3OutpostResource;
3942
import software.amazon.awssdk.services.s3.internal.resource.S3Resource;
@@ -48,6 +51,7 @@
4851
public final class S3AccessPointEndpointResolver implements S3EndpointResolver {
4952

5053
private static final String S3_OUTPOSTS_NAME = "s3-outposts";
54+
private static final String S3_OBJECT_LAMBDA_NAME = "s3-object-lambda";
5155

5256
private S3AccessPointEndpointResolver() {
5357
}
@@ -85,8 +89,7 @@ public ConfiguredS3SdkHttpRequest applyEndpointConfiguration(S3EndpointResolverC
8589
.build();
8690

8791
String signingServiceModification = s3EndpointResource.parentS3Resource()
88-
.filter(r -> r instanceof S3OutpostResource)
89-
.map(ignore -> S3_OUTPOSTS_NAME)
92+
.flatMap(S3AccessPointEndpointResolver::resolveSigningService)
9093
.orElse(null);
9194

9295
return ConfiguredS3SdkHttpRequest.builder()
@@ -175,6 +178,8 @@ private URI getUriForAccessPointResource(S3EndpointResolverContext context, Stri
175178

176179
if (isOutpostAccessPoint(s3EndpointResource)) {
177180
return getOutpostAccessPointUri(context, arnRegion, clientPartitionMetadata, s3EndpointResource);
181+
} else if (isObjectLambdaAccessPoint(s3EndpointResource)) {
182+
return getObjectLambdaAccessPointUri(context, arnRegion, clientPartitionMetadata, s3EndpointResource);
178183
}
179184

180185
boolean dualstackEnabled = isDualstackEnabled(context.serviceConfiguration());
@@ -196,6 +201,10 @@ private boolean isOutpostAccessPoint(S3AccessPointResource s3EndpointResource) {
196201
return s3EndpointResource.parentS3Resource().filter(r -> r instanceof S3OutpostResource).isPresent();
197202
}
198203

204+
private boolean isObjectLambdaAccessPoint(S3AccessPointResource s3EndpointResource) {
205+
return s3EndpointResource.parentS3Resource().filter(r -> r instanceof S3ObjectLambdaResource).isPresent();
206+
}
207+
199208
private URI getOutpostAccessPointUri(S3EndpointResolverContext context, String arnRegion,
200209
PartitionMetadata clientPartitionMetadata, S3AccessPointResource s3EndpointResource) {
201210
if (isDualstackEnabled(context.serviceConfiguration())) {
@@ -221,4 +230,35 @@ private URI getOutpostAccessPointUri(S3EndpointResolverContext context, String a
221230
.toUri();
222231
}
223232

233+
private URI getObjectLambdaAccessPointUri(S3EndpointResolverContext context, String arnRegion,
234+
PartitionMetadata clientPartitionMetadata,
235+
S3AccessPointResource s3EndpointResource) {
236+
if (isDualstackEnabled(context.serviceConfiguration())) {
237+
throw new IllegalArgumentException("An Object Lambda Access Point ARN cannot be passed as a bucket parameter to "
238+
+ "an S3 operation if the S3 client has been configured with dualstack.");
239+
}
240+
241+
return S3ObjectLambdaEndpointBuilder.create()
242+
.endpointOverride(context.endpointOverride())
243+
.accountId(s3EndpointResource.accountId().get())
244+
.region(arnRegion)
245+
.accessPointName(s3EndpointResource.accessPointName())
246+
.protocol(context.request().protocol())
247+
.fipsEnabled(isFipsRegion(context.region().toString()))
248+
.dualstackEnabled(isDualstackEnabled(context.serviceConfiguration()))
249+
.domain(clientPartitionMetadata.dnsSuffix())
250+
.toUri();
251+
}
252+
253+
private static Optional<String> resolveSigningService(S3Resource resource) {
254+
if (resource instanceof S3OutpostResource) {
255+
return Optional.of(S3_OUTPOSTS_NAME);
256+
}
257+
258+
if (resource instanceof S3ObjectLambdaResource) {
259+
return Optional.of(S3_OBJECT_LAMBDA_NAME);
260+
}
261+
262+
return Optional.empty();
263+
}
224264
}

services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/endpoints/S3EndpointResolverContext.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,15 @@ public final class S3EndpointResolverContext {
3333
private final Region region;
3434
private final S3Configuration serviceConfiguration;
3535
private final URI endpointOverride;
36+
private final boolean disableHostPrefixInjection;
3637

3738
private S3EndpointResolverContext(Builder builder) {
3839
this.request = builder.request;
3940
this.originalRequest = builder.originalRequest;
4041
this.region = builder.region;
4142
this.serviceConfiguration = builder.serviceConfiguration;
4243
this.endpointOverride = builder.endpointOverride;
44+
this.disableHostPrefixInjection = builder.disableHostPrefixInjection;
4345
}
4446

4547
public static Builder builder() {
@@ -66,6 +68,9 @@ public URI endpointOverride() {
6668
return endpointOverride;
6769
}
6870

71+
public boolean isDisableHostPrefixInjection() {
72+
return disableHostPrefixInjection;
73+
}
6974

7075
@Override
7176
public boolean equals(Object o) {
@@ -80,7 +85,8 @@ public boolean equals(Object o) {
8085
Objects.equals(request, that.request) &&
8186
Objects.equals(originalRequest, that.originalRequest) &&
8287
Objects.equals(region, that.region) &&
83-
Objects.equals(serviceConfiguration, that.serviceConfiguration);
88+
Objects.equals(serviceConfiguration, that.serviceConfiguration) &&
89+
Objects.equals(disableHostPrefixInjection, that.disableHostPrefixInjection);
8490
}
8591

8692
@Override
@@ -91,6 +97,7 @@ public int hashCode() {
9197
hashCode = 31 * hashCode + Objects.hashCode(region());
9298
hashCode = 31 * hashCode + Objects.hashCode(serviceConfiguration());
9399
hashCode = 31 * hashCode + Objects.hashCode(endpointOverride());
100+
hashCode = 31 * hashCode + Objects.hashCode(isDisableHostPrefixInjection());
94101
return hashCode;
95102
}
96103

@@ -108,6 +115,7 @@ public static final class Builder {
108115
private Region region;
109116
private S3Configuration serviceConfiguration;
110117
private URI endpointOverride;
118+
private boolean disableHostPrefixInjection;
111119

112120
private Builder() {
113121
}
@@ -137,6 +145,11 @@ public Builder endpointOverride(URI endpointOverride) {
137145
return this;
138146
}
139147

148+
public Builder disableHostPrefixInjection(boolean disableHostPrefixInjection) {
149+
this.disableHostPrefixInjection = disableHostPrefixInjection;
150+
return this;
151+
}
152+
140153
public S3EndpointResolverContext build() {
141154
return new S3EndpointResolverContext(this);
142155
}

services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/endpoints/S3EndpointResolverFactory.java

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

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

18+
import java.util.Optional;
1819
import software.amazon.awssdk.annotations.SdkInternalApi;
20+
import software.amazon.awssdk.services.s3.model.S3Request;
21+
import software.amazon.awssdk.services.s3.model.WriteGetObjectResponseRequest;
1922

2023
/**
2124
* Get endpoint resolver.
@@ -25,14 +28,25 @@ public final class S3EndpointResolverFactory {
2528

2629
private static final S3EndpointResolver ACCESS_POINT_ENDPOINT_RESOLVER = S3AccessPointEndpointResolver.create();
2730
private static final S3EndpointResolver BUCKET_ENDPOINT_RESOLVER = S3BucketEndpointResolver.create();
31+
private static final S3EndpointResolver OBJECT_LAMBDA_OPERATION_RESOLVER = S3ObjectLambdaOperationEndpointResolver.create();
2832

2933
private S3EndpointResolverFactory() {
3034
}
3135

32-
public static S3EndpointResolver getEndpointResolver(String bucketName) {
33-
if (bucketName != null && S3EndpointUtils.isArn(bucketName)) {
36+
public static S3EndpointResolver getEndpointResolver(S3EndpointResolverFactoryContext context) {
37+
Optional<String> bucketName = context.bucketName();
38+
if (bucketName.isPresent() && S3EndpointUtils.isArn(bucketName.get())) {
3439
return ACCESS_POINT_ENDPOINT_RESOLVER;
3540
}
41+
42+
if (isObjectLambdaRequest(context.originalRequest())) {
43+
return OBJECT_LAMBDA_OPERATION_RESOLVER;
44+
}
45+
3646
return BUCKET_ENDPOINT_RESOLVER;
3747
}
48+
49+
private static boolean isObjectLambdaRequest(S3Request request) {
50+
return request instanceof WriteGetObjectResponseRequest;
51+
}
3852
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
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.endpoints;
17+
18+
import java.util.Optional;
19+
import software.amazon.awssdk.annotations.SdkInternalApi;
20+
import software.amazon.awssdk.services.s3.model.S3Request;
21+
22+
@SdkInternalApi
23+
public final class S3EndpointResolverFactoryContext {
24+
private final String bucketName;
25+
private final S3Request originalRequest;
26+
27+
private S3EndpointResolverFactoryContext(DefaultBuilder builder) {
28+
this.bucketName = builder.bucketName;
29+
this.originalRequest = builder.originalRequest;
30+
}
31+
32+
public Optional<String> bucketName() {
33+
return Optional.ofNullable(bucketName);
34+
}
35+
36+
public S3Request originalRequest() {
37+
return originalRequest;
38+
}
39+
40+
public static Builder builder() {
41+
return new DefaultBuilder();
42+
}
43+
44+
public interface Builder {
45+
Builder bucketName(String bucketName);
46+
47+
Builder originalRequest(S3Request originalRequest);
48+
49+
S3EndpointResolverFactoryContext build();
50+
}
51+
52+
private static final class DefaultBuilder implements Builder {
53+
private String bucketName;
54+
private S3Request originalRequest;
55+
56+
@Override
57+
public Builder bucketName(String bucketName) {
58+
this.bucketName = bucketName;
59+
return this;
60+
}
61+
62+
@Override
63+
public Builder originalRequest(S3Request originalRequest) {
64+
this.originalRequest = originalRequest;
65+
return this;
66+
}
67+
68+
@Override
69+
public S3EndpointResolverFactoryContext build() {
70+
return new S3EndpointResolverFactoryContext(this);
71+
}
72+
}
73+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
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.endpoints;
17+
18+
import java.net.URI;
19+
import software.amazon.awssdk.annotations.SdkInternalApi;
20+
import software.amazon.awssdk.utils.Validate;
21+
22+
/**
23+
* Endpoint builder for operations specific to S3 Object Lambda.
24+
*/
25+
@SdkInternalApi
26+
public class S3ObjectLambdaOperationEndpointBuilder {
27+
private String region;
28+
private String protocol;
29+
private String domain;
30+
31+
private S3ObjectLambdaOperationEndpointBuilder() {
32+
}
33+
34+
/**
35+
* Create a new instance of this builder class.
36+
*/
37+
public static S3ObjectLambdaOperationEndpointBuilder create() {
38+
return new S3ObjectLambdaOperationEndpointBuilder();
39+
}
40+
41+
42+
public S3ObjectLambdaOperationEndpointBuilder region(String region) {
43+
this.region = region;
44+
return this;
45+
}
46+
47+
public S3ObjectLambdaOperationEndpointBuilder protocol(String protocol) {
48+
this.protocol = protocol;
49+
return this;
50+
}
51+
52+
public S3ObjectLambdaOperationEndpointBuilder domain(String domain) {
53+
this.domain = domain;
54+
return this;
55+
}
56+
57+
/**
58+
* Generate an endpoint URI with no path that maps to the Object Lambdas Access Point information stored in this builder.
59+
*/
60+
public URI toUri() {
61+
Validate.paramNotBlank(protocol, "protocol");
62+
Validate.paramNotBlank(domain, "domain");
63+
Validate.paramNotBlank(region, "region");
64+
65+
String servicePrefix = "s3-object-lambda";
66+
67+
String uriString = String.format("%s://%s.%s.%s",
68+
protocol,
69+
servicePrefix,
70+
region,
71+
domain);
72+
73+
return URI.create(uriString);
74+
}
75+
}

0 commit comments

Comments
 (0)