This is an automated email from the ASF dual-hosted git repository.

amoghj pushed a commit to branch wip-s3sign-body
in repository https://gitbox.apache.org/repos/asf/iceberg.git


The following commit(s) were added to refs/heads/wip-s3sign-body by this push:
     new b48b0fb13a AWS: Update S3V4RestSignerClient to send body for 
DeleteObjects requests
b48b0fb13a is described below

commit b48b0fb13abcbdab318ea91515a89338505ea549
Author: amogh-jahagirdar <[email protected]>
AuthorDate: Mon Aug 21 16:35:44 2023 -0700

    AWS: Update S3V4RestSignerClient to send body for DeleteObjects requests
---
 .../aws/s3/signer/S3V4RestSignerClient.java        | 34 ++++++++++++++++++++--
 .../iceberg/aws/s3/signer/TestS3RestSigner.java    | 22 ++++++++++++++
 2 files changed, 53 insertions(+), 3 deletions(-)

diff --git 
a/aws/src/main/java/org/apache/iceberg/aws/s3/signer/S3V4RestSignerClient.java 
b/aws/src/main/java/org/apache/iceberg/aws/s3/signer/S3V4RestSignerClient.java
index a334221a25..703bf9a829 100644
--- 
a/aws/src/main/java/org/apache/iceberg/aws/s3/signer/S3V4RestSignerClient.java
+++ 
b/aws/src/main/java/org/apache/iceberg/aws/s3/signer/S3V4RestSignerClient.java
@@ -21,6 +21,9 @@ package org.apache.iceberg.aws.s3.signer;
 import com.github.benmanes.caffeine.cache.Cache;
 import com.github.benmanes.caffeine.cache.Caffeine;
 import com.github.benmanes.caffeine.cache.RemovalListener;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
 import java.net.URI;
 import java.time.Duration;
 import java.util.Collections;
@@ -55,6 +58,8 @@ import 
software.amazon.awssdk.auth.signer.params.AwsS3V4SignerParams;
 import software.amazon.awssdk.core.checksums.SdkChecksum;
 import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
 import software.amazon.awssdk.http.SdkHttpFullRequest;
+import software.amazon.awssdk.http.SdkHttpMethod;
+import software.amazon.awssdk.utils.IoUtils;
 
 @Value.Immutable
 public abstract class S3V4RestSignerClient
@@ -279,15 +284,16 @@ public abstract class S3V4RestSignerClient
     AwsS3V4SignerParams signerParams =
         extractSignerParams(AwsS3V4SignerParams.builder(), 
executionAttributes).build();
 
-    S3SignRequest remoteSigningRequest =
+    ImmutableS3SignRequest.Builder remoteSigningRequestBuilder =
         ImmutableS3SignRequest.builder()
             .method(request.method().name())
             .region(signerParams.signingRegion().id())
             .uri(request.getUri())
             .headers(request.headers())
-            .properties(requestPropertiesSupplier().get())
-            .build();
+            .properties(requestPropertiesSupplier().get());
 
+    addBodyToRequestIfNeeded(request, remoteSigningRequestBuilder);
+    ImmutableS3SignRequest remoteSigningRequest = 
remoteSigningRequestBuilder.build();
     Key cacheKey = Key.from(remoteSigningRequest);
     SignedComponent cachedSignedComponent = 
SIGNED_COMPONENT_CACHE.getIfPresent(cacheKey);
     SignedComponent signedComponent;
@@ -328,6 +334,28 @@ public abstract class S3V4RestSignerClient
     return mutableRequest.build();
   }
 
+  private void addBodyToRequestIfNeeded(
+      SdkHttpFullRequest request, ImmutableS3SignRequest.Builder 
requestBuilder) {
+    if (request.contentStreamProvider().isPresent()) {
+      if (shouldAddBodyToRequest(request)) {
+        try (InputStream is = 
request.contentStreamProvider().get().newStream()) {
+          requestBuilder.body(IoUtils.toUtf8String(is));
+        } catch (IOException e) {
+          throw new UncheckedIOException("Failed to set body for S3 sign 
request", e);
+        }
+      }
+    }
+  }
+
+  /**
+   * Only add body for DeleteObjectsRequest. Refer to
+   * 
https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjects.html#API_DeleteObjects_RequestSyntax
+   */
+  private boolean shouldAddBodyToRequest(SdkHttpFullRequest request) {
+    return request.method() == SdkHttpMethod.POST
+        && request.rawQueryParameters().containsKey("delete");
+  }
+
   private void reconstructHeaders(
       Map<String, List<String>> signedAndUnsignedHeaders,
       SdkHttpFullRequest.Builder mutableRequest) {
diff --git 
a/aws/src/test/java/org/apache/iceberg/aws/s3/signer/TestS3RestSigner.java 
b/aws/src/test/java/org/apache/iceberg/aws/s3/signer/TestS3RestSigner.java
index 1e44e53318..7972826bea 100644
--- a/aws/src/test/java/org/apache/iceberg/aws/s3/signer/TestS3RestSigner.java
+++ b/aws/src/test/java/org/apache/iceberg/aws/s3/signer/TestS3RestSigner.java
@@ -56,8 +56,11 @@ import software.amazon.awssdk.regions.Region;
 import software.amazon.awssdk.services.s3.S3Client;
 import software.amazon.awssdk.services.s3.model.CreateBucketRequest;
 import software.amazon.awssdk.services.s3.model.CreateMultipartUploadRequest;
+import software.amazon.awssdk.services.s3.model.Delete;
+import software.amazon.awssdk.services.s3.model.DeleteObjectsRequest;
 import software.amazon.awssdk.services.s3.model.GetObjectRequest;
 import software.amazon.awssdk.services.s3.model.ListObjectsV2Request;
+import software.amazon.awssdk.services.s3.model.ObjectIdentifier;
 import software.amazon.awssdk.services.s3.model.PutObjectRequest;
 import software.amazon.awssdk.services.s3.model.UploadPartRequest;
 
@@ -177,6 +180,25 @@ public class TestS3RestSigner {
         PutObjectRequest.builder().bucket(BUCKET).key("some/key").build(), 
Paths.get("/etc/hosts"));
   }
 
+  @Test
+  public void validateDeleteObjects() {
+    s3.putObject(
+        PutObjectRequest.builder().bucket(BUCKET).key("some/key1").build(),
+        Paths.get("/etc/hosts"));
+    s3.putObject(
+        PutObjectRequest.builder().bucket(BUCKET).key("some/key2").build(),
+        Paths.get("/etc/hosts"));
+
+    Delete objectsToDelete =
+        Delete.builder()
+            .objects(
+                ObjectIdentifier.builder().key("some/key1").build(),
+                ObjectIdentifier.builder().key("some/key2").build())
+            .build();
+
+    
s3.deleteObjects(DeleteObjectsRequest.builder().bucket(BUCKET).delete(objectsToDelete).build());
+  }
+
   @Test
   public void validateListPrefix() {
     
s3.listObjectsV2(ListObjectsV2Request.builder().bucket(BUCKET).prefix("some/prefix/").build());

Reply via email to