Skip to content

Commit 0ddda42

Browse files
committed
adding headobject and headbucket functionality and test coverage
1 parent 6e4de06 commit 0ddda42

File tree

8 files changed

+683
-13
lines changed

8 files changed

+683
-13
lines changed

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

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@
5252
import software.amazon.awssdk.services.s3.presigner.model.PresignedCreateMultipartUploadRequest;
5353
import software.amazon.awssdk.services.s3.presigner.model.PresignedDeleteObjectRequest;
5454
import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest;
55+
import software.amazon.awssdk.services.s3.presigner.model.PresignedHeadBucketRequest;
56+
import software.amazon.awssdk.services.s3.presigner.model.PresignedHeadObjectRequest;
5557
import software.amazon.awssdk.services.s3.presigner.model.PresignedPutObjectRequest;
5658
import software.amazon.awssdk.services.s3.presigner.model.PresignedUploadPartRequest;
5759
import software.amazon.awssdk.services.s3.utils.S3TestUtils;
@@ -363,6 +365,50 @@ public void abortMultipartUpload_CanBePresigned() throws IOException {
363365
assertThat(getMultipartUpload(objectKey)).isNotPresent();
364366
}
365367

368+
@Test
369+
public void headObject_CanBePresigned() throws IOException {
370+
PresignedHeadObjectRequest presigned =
371+
presigner.presignHeadObject(r -> r.signatureDuration(Duration.ofMinutes(5))
372+
.headObjectRequest(hor -> hor.bucket(testBucket)
373+
.key(testGetObjectKey)));
374+
375+
assertThat(presigned.isBrowserExecutable()).isFalse();
376+
377+
SdkHttpClient httpClient = ApacheHttpClient.builder().build(); // or UrlConnectionHttpClient.builder().build()
378+
379+
HttpExecuteRequest request = HttpExecuteRequest.builder()
380+
.request(presigned.httpRequest())
381+
.build();
382+
383+
HttpExecuteResponse response = httpClient.prepareRequest(request).call();
384+
385+
assertThat(response.httpResponse().isSuccessful()).isTrue();
386+
assertThat(response.httpResponse().firstMatchingHeader("Content-Length")).isPresent();
387+
assertThat(response.httpResponse().firstMatchingHeader("ETag")).isPresent();
388+
assertThat(response.httpResponse().firstMatchingHeader("Last-Modified")).isPresent();
389+
390+
}
391+
392+
@Test
393+
public void headBucket_CanBePresigned() throws IOException {
394+
PresignedHeadBucketRequest presigned =
395+
presigner.presignHeadBucket(r -> r.signatureDuration(Duration.ofMinutes(5))
396+
.headBucketRequest(hbr -> hbr.bucket(testBucket)));
397+
398+
assertThat(presigned.isBrowserExecutable()).isFalse();
399+
400+
SdkHttpClient httpClient = ApacheHttpClient.builder().build(); // or UrlConnectionHttpClient.builder().build()
401+
402+
HttpExecuteRequest request = HttpExecuteRequest.builder()
403+
.request(presigned.httpRequest())
404+
.build();
405+
406+
HttpExecuteResponse response = httpClient.prepareRequest(request).call();
407+
408+
assertThat(response.httpResponse().isSuccessful()).isTrue();
409+
assertThat(response.httpResponse().firstMatchingHeader("x-amz-bucket-region")).isPresent();
410+
}
411+
366412
private Consumer<CreateMultipartUploadRequest.Builder> createMultipartUploadRequest(String objectKey) {
367413
return r -> r.bucket(testBucket).key(objectKey);
368414
}

services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/signing/DefaultS3Presigner.java

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@
9797
import software.amazon.awssdk.services.s3.model.CreateMultipartUploadRequest;
9898
import software.amazon.awssdk.services.s3.model.DeleteObjectRequest;
9999
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
100+
import software.amazon.awssdk.services.s3.model.HeadBucketRequest;
101+
import software.amazon.awssdk.services.s3.model.HeadObjectRequest;
100102
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
101103
import software.amazon.awssdk.services.s3.model.UploadPartRequest;
102104
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
@@ -105,11 +107,15 @@
105107
import software.amazon.awssdk.services.s3.presigner.model.CreateMultipartUploadPresignRequest;
106108
import software.amazon.awssdk.services.s3.presigner.model.DeleteObjectPresignRequest;
107109
import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest;
110+
import software.amazon.awssdk.services.s3.presigner.model.HeadBucketPresignRequest;
111+
import software.amazon.awssdk.services.s3.presigner.model.HeadObjectPresignRequest;
108112
import software.amazon.awssdk.services.s3.presigner.model.PresignedAbortMultipartUploadRequest;
109113
import software.amazon.awssdk.services.s3.presigner.model.PresignedCompleteMultipartUploadRequest;
110114
import software.amazon.awssdk.services.s3.presigner.model.PresignedCreateMultipartUploadRequest;
111115
import software.amazon.awssdk.services.s3.presigner.model.PresignedDeleteObjectRequest;
112116
import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest;
117+
import software.amazon.awssdk.services.s3.presigner.model.PresignedHeadBucketRequest;
118+
import software.amazon.awssdk.services.s3.presigner.model.PresignedHeadObjectRequest;
113119
import software.amazon.awssdk.services.s3.presigner.model.PresignedPutObjectRequest;
114120
import software.amazon.awssdk.services.s3.presigner.model.PresignedUploadPartRequest;
115121
import software.amazon.awssdk.services.s3.presigner.model.PutObjectPresignRequest;
@@ -120,6 +126,8 @@
120126
import software.amazon.awssdk.services.s3.transform.CreateMultipartUploadRequestMarshaller;
121127
import software.amazon.awssdk.services.s3.transform.DeleteObjectRequestMarshaller;
122128
import software.amazon.awssdk.services.s3.transform.GetObjectRequestMarshaller;
129+
import software.amazon.awssdk.services.s3.transform.HeadBucketRequestMarshaller;
130+
import software.amazon.awssdk.services.s3.transform.HeadObjectRequestMarshaller;
123131
import software.amazon.awssdk.services.s3.transform.PutObjectRequestMarshaller;
124132
import software.amazon.awssdk.services.s3.transform.UploadPartRequestMarshaller;
125133
import software.amazon.awssdk.utils.AttributeMap;
@@ -141,6 +149,8 @@ public final class DefaultS3Presigner extends DefaultSdkPresigner implements S3P
141149
private final S3Configuration serviceConfiguration;
142150
private final List<ExecutionInterceptor> clientInterceptors;
143151
private final GetObjectRequestMarshaller getObjectRequestMarshaller;
152+
private final HeadObjectRequestMarshaller headObjectRequestMarshaller;
153+
private final HeadBucketRequestMarshaller headBucketRequestMarshaller;
144154
private final PutObjectRequestMarshaller putObjectRequestMarshaller;
145155
private final CreateMultipartUploadRequestMarshaller createMultipartUploadRequestMarshaller;
146156
private final UploadPartRequestMarshaller uploadPartRequestMarshaller;
@@ -156,16 +166,16 @@ private DefaultS3Presigner(Builder b) {
156166
super(b);
157167

158168
S3Configuration serviceConfiguration = b.serviceConfiguration != null ? b.serviceConfiguration :
159-
S3Configuration.builder()
160-
.profileFile(profileFileSupplier())
161-
.profileName(profileName())
162-
.checksumValidationEnabled(false)
163-
.build();
169+
S3Configuration.builder()
170+
.profileFile(profileFileSupplier())
171+
.profileName(profileName())
172+
.checksumValidationEnabled(false)
173+
.build();
164174
S3Configuration.Builder serviceConfigBuilder = serviceConfiguration.toBuilder();
165175

166176
if (serviceConfiguration.checksumValidationEnabled()) {
167177
log.debug(() -> "The provided S3Configuration has ChecksumValidationEnabled set to true. Please note that "
168-
+ "the pre-signed request can't be executed using a web browser if checksum validation is enabled.");
178+
+ "the pre-signed request can't be executed using a web browser if checksum validation is enabled.");
169179
}
170180

171181
if (dualstackEnabled() != null && serviceConfigBuilder.dualstackEnabled() != null) {
@@ -193,6 +203,10 @@ private DefaultS3Presigner(Builder b) {
193203
// Copied from DefaultS3Client#getObject
194204
this.getObjectRequestMarshaller = new GetObjectRequestMarshaller(protocolFactory);
195205

206+
this.headObjectRequestMarshaller = new HeadObjectRequestMarshaller(protocolFactory);
207+
208+
this.headBucketRequestMarshaller = new HeadBucketRequestMarshaller(protocolFactory);
209+
196210
// Copied from DefaultS3Client#putObject
197211
this.putObjectRequestMarshaller = new PutObjectRequestMarshaller(protocolFactory);
198212

@@ -273,6 +287,28 @@ public PresignedGetObjectRequest presignGetObject(GetObjectPresignRequest reques
273287
.build();
274288
}
275289

290+
@Override
291+
public PresignedHeadObjectRequest presignHeadObject(HeadObjectPresignRequest request) {
292+
return presign(PresignedHeadObjectRequest.builder(),
293+
request,
294+
request.headObjectRequest(),
295+
HeadObjectRequest.class,
296+
headObjectRequestMarshaller::marshall,
297+
"HeadObject")
298+
.build();
299+
}
300+
301+
@Override
302+
public PresignedHeadBucketRequest presignHeadBucket(HeadBucketPresignRequest request) {
303+
return presign(PresignedHeadBucketRequest.builder(),
304+
request,
305+
request.headBucketRequest(),
306+
HeadBucketRequest.class,
307+
headBucketRequestMarshaller::marshall,
308+
"HeadBucket")
309+
.build();
310+
}
311+
276312
@Override
277313
public PresignedPutObjectRequest presignPutObject(PutObjectPresignRequest request) {
278314
return presign(PresignedPutObjectRequest.builder(),
@@ -573,7 +609,7 @@ private SdkHttpFullRequest presignRequest(ExecutionContext execCtx, SdkHttpFullR
573609
* Presign the provided HTTP request using SRA HttpSigner
574610
*/
575611
private SdkHttpFullRequest sraPresignRequest(ExecutionContext execCtx, SdkHttpFullRequest request,
576-
Clock signingClock, Duration expirationDuration) {
612+
Clock signingClock, Duration expirationDuration) {
577613
SelectedAuthScheme selectedAuthScheme = execCtx.executionAttributes().getAttribute(SELECTED_AUTH_SCHEME);
578614
return doSraPresign(request, selectedAuthScheme, signingClock, expirationDuration);
579615
}
@@ -657,7 +693,7 @@ private AttributeMap createClientContextParams(Boolean resolvedDisableS3ExpressS
657693

658694
params.put(S3ClientContextParams.USE_ARN_REGION, serviceConfiguration.useArnRegionEnabled());
659695
params.put(S3ClientContextParams.DISABLE_MULTI_REGION_ACCESS_POINTS,
660-
!serviceConfiguration.multiRegionEnabled());
696+
!serviceConfiguration.multiRegionEnabled());
661697
params.put(S3ClientContextParams.FORCE_PATH_STYLE, serviceConfiguration.pathStyleAccessEnabled());
662698
params.put(S3ClientContextParams.ACCELERATE, serviceConfiguration.accelerateModeEnabled());
663699
params.put(S3ClientContextParams.DISABLE_S3_EXPRESS_SESSION_AUTH, resolvedDisableS3ExpressSessionAuth);
@@ -670,10 +706,10 @@ private UseGlobalEndpointResolver createUseGlobalEndpointResolver() {
670706
.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT);
671707

672708
SdkClientConfiguration config = clientConfiguration.toBuilder()
673-
.option(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, legacyOption)
674-
.option(SdkClientOption.PROFILE_FILE_SUPPLIER, profileFileSupplier())
675-
.option(SdkClientOption.PROFILE_NAME, profileName())
676-
.build();
709+
.option(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, legacyOption)
710+
.option(SdkClientOption.PROFILE_FILE_SUPPLIER, profileFileSupplier())
711+
.option(SdkClientOption.PROFILE_NAME, profileName())
712+
.build();
677713

678714
return new UseGlobalEndpointResolver(config);
679715
}

services/s3/src/main/java/software/amazon/awssdk/services/s3/presigner/S3Presigner.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,15 @@
4747
import software.amazon.awssdk.services.s3.presigner.model.CreateMultipartUploadPresignRequest;
4848
import software.amazon.awssdk.services.s3.presigner.model.DeleteObjectPresignRequest;
4949
import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest;
50+
import software.amazon.awssdk.services.s3.presigner.model.HeadBucketPresignRequest;
51+
import software.amazon.awssdk.services.s3.presigner.model.HeadObjectPresignRequest;
5052
import software.amazon.awssdk.services.s3.presigner.model.PresignedAbortMultipartUploadRequest;
5153
import software.amazon.awssdk.services.s3.presigner.model.PresignedCompleteMultipartUploadRequest;
5254
import software.amazon.awssdk.services.s3.presigner.model.PresignedCreateMultipartUploadRequest;
5355
import software.amazon.awssdk.services.s3.presigner.model.PresignedDeleteObjectRequest;
5456
import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest;
57+
import software.amazon.awssdk.services.s3.presigner.model.PresignedHeadBucketRequest;
58+
import software.amazon.awssdk.services.s3.presigner.model.PresignedHeadObjectRequest;
5559
import software.amazon.awssdk.services.s3.presigner.model.PresignedPutObjectRequest;
5660
import software.amazon.awssdk.services.s3.presigner.model.PresignedUploadPartRequest;
5761
import software.amazon.awssdk.services.s3.presigner.model.PutObjectPresignRequest;
@@ -328,7 +332,7 @@ static Builder builder() {
328332
* <p />
329333
* This is a shorter method of invoking {@link #presignGetObject(GetObjectPresignRequest)} without needing
330334
* to call {@code GetObjectPresignRequest.builder()} or {@code .build()}.
331-
*
335+
*
332336
* @see #presignGetObject(GetObjectPresignRequest)
333337
*/
334338
default PresignedGetObjectRequest presignGetObject(Consumer<GetObjectPresignRequest.Builder> request) {
@@ -337,6 +341,23 @@ default PresignedGetObjectRequest presignGetObject(Consumer<GetObjectPresignRequ
337341
return presignGetObject(builder.build());
338342
}
339343

344+
PresignedHeadObjectRequest presignHeadObject(HeadObjectPresignRequest request);
345+
346+
default PresignedHeadObjectRequest presignHeadObject(Consumer<HeadObjectPresignRequest.Builder> request) {
347+
HeadObjectPresignRequest.Builder builder = HeadObjectPresignRequest.builder();
348+
request.accept(builder);
349+
return presignHeadObject(builder.build());
350+
}
351+
352+
353+
PresignedHeadBucketRequest presignHeadBucket(HeadBucketPresignRequest request);
354+
355+
default PresignedHeadBucketRequest presignHeadBucket(Consumer<HeadBucketPresignRequest.Builder> request) {
356+
HeadBucketPresignRequest.Builder builder = HeadBucketPresignRequest.builder();
357+
request.accept(builder);
358+
return presignHeadBucket(builder.build());
359+
}
360+
340361
/**
341362
* Presign a {@link PutObjectRequest} so that it can be executed at a later time without requiring additional
342363
* signing or authentication.

0 commit comments

Comments
 (0)