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

ivandika pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git


The following commit(s) were added to refs/heads/master by this push:
     new ae9c53cfba7 HDDS-13663. Validate Presigned DeleteObject (#9019)
ae9c53cfba7 is described below

commit ae9c53cfba7a449455e4c031b838d05e8689b969
Author: Hsu Han Wen <hevin...@gmail.com>
AuthorDate: Fri Sep 12 11:46:12 2025 +0800

    HDDS-13663. Validate Presigned DeleteObject (#9019)
---
 .../ozone/s3/awssdk/v1/AbstractS3SDKV1Tests.java   | 34 +++++++++
 .../ozone/s3/awssdk/v2/AbstractS3SDKV2Tests.java   | 87 ++++++++++++++++++++++
 2 files changed, 121 insertions(+)

diff --git 
a/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v1/AbstractS3SDKV1Tests.java
 
b/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v1/AbstractS3SDKV1Tests.java
index eed72db3c13..54bdddf6e1c 100644
--- 
a/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v1/AbstractS3SDKV1Tests.java
+++ 
b/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v1/AbstractS3SDKV1Tests.java
@@ -1378,6 +1378,40 @@ private GeneratePresignedUrlRequest 
createInitMPUPresignedUrlRequest(String buck
     return initMPUPresignUrlRequest;
   }
 
+  @Test
+  public void testPresignedUrlDelete() throws IOException {
+    final String bucketName = getBucketName();
+    final String keyName = getKeyName();
+    final String content = "bar";
+
+    s3Client.createBucket(bucketName);
+    try (InputStream is = new 
ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8))) {
+      s3Client.putObject(bucketName, keyName, is, new ObjectMetadata());
+    }
+
+    // Set the presigned URL to expire after one hour.
+    Date expiration = Date.from(Instant.now().plusMillis(1000 * 60 * 60));
+
+    // Generate the presigned URL for DELETE
+    GeneratePresignedUrlRequest generatePresignedUrlRequest =
+        new GeneratePresignedUrlRequest(bucketName, keyName)
+            .withMethod(HttpMethod.DELETE)
+            .withExpiration(expiration);
+    URL url = s3Client.generatePresignedUrl(generatePresignedUrlRequest);
+
+    // Execute the DELETE request using HttpUrlConnection
+    URL presignedUrl = new URL(url.toExternalForm());
+    HttpURLConnection connection = (HttpURLConnection) 
presignedUrl.openConnection();
+    connection.setRequestMethod("DELETE");
+    int responseCode = connection.getResponseCode();
+
+    // Verify the response code is 204 (No Content)
+    assertEquals(HttpURLConnection.HTTP_NO_CONTENT, responseCode);
+
+    // Verify the object is deleted
+    assertFalse(s3Client.doesObjectExist(bucketName, keyName));
+  }
+
   /**
    * Tests the functionality to create a snapshot of an Ozone bucket and then 
read files
    * from the snapshot directory using the S3 SDK.
diff --git 
a/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v2/AbstractS3SDKV2Tests.java
 
b/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v2/AbstractS3SDKV2Tests.java
index ff54190d3f3..31f58c6d9a2 100644
--- 
a/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v2/AbstractS3SDKV2Tests.java
+++ 
b/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v2/AbstractS3SDKV2Tests.java
@@ -103,6 +103,7 @@
 import software.amazon.awssdk.services.s3.model.CreateMultipartUploadResponse;
 import software.amazon.awssdk.services.s3.model.Delete;
 import software.amazon.awssdk.services.s3.model.DeleteBucketRequest;
+import software.amazon.awssdk.services.s3.model.DeleteObjectRequest;
 import software.amazon.awssdk.services.s3.model.DeleteObjectTaggingRequest;
 import software.amazon.awssdk.services.s3.model.DeleteObjectsRequest;
 import software.amazon.awssdk.services.s3.model.GetBucketAclRequest;
@@ -119,6 +120,7 @@
 import software.amazon.awssdk.services.s3.model.ListObjectsV2Request;
 import software.amazon.awssdk.services.s3.model.ListObjectsV2Response;
 import software.amazon.awssdk.services.s3.model.ListPartsRequest;
+import software.amazon.awssdk.services.s3.model.NoSuchKeyException;
 import software.amazon.awssdk.services.s3.model.ObjectIdentifier;
 import software.amazon.awssdk.services.s3.model.PutBucketAclRequest;
 import software.amazon.awssdk.services.s3.model.PutObjectRequest;
@@ -134,11 +136,13 @@
 import software.amazon.awssdk.services.s3.presigner.S3Presigner;
 import 
software.amazon.awssdk.services.s3.presigner.model.CompleteMultipartUploadPresignRequest;
 import 
software.amazon.awssdk.services.s3.presigner.model.CreateMultipartUploadPresignRequest;
+import 
software.amazon.awssdk.services.s3.presigner.model.DeleteObjectPresignRequest;
 import 
software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest;
 import 
software.amazon.awssdk.services.s3.presigner.model.HeadBucketPresignRequest;
 import 
software.amazon.awssdk.services.s3.presigner.model.HeadObjectPresignRequest;
 import 
software.amazon.awssdk.services.s3.presigner.model.PresignedCompleteMultipartUploadRequest;
 import 
software.amazon.awssdk.services.s3.presigner.model.PresignedCreateMultipartUploadRequest;
+import 
software.amazon.awssdk.services.s3.presigner.model.PresignedDeleteObjectRequest;
 import 
software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest;
 import 
software.amazon.awssdk.services.s3.presigner.model.PresignedHeadBucketRequest;
 import 
software.amazon.awssdk.services.s3.presigner.model.PresignedHeadObjectRequest;
@@ -1077,6 +1081,89 @@ private String 
buildCompleteMultipartUploadXml(List<CompletedPart> parts) {
     return xml.toString();
   }
 
+  @Test
+  public void testPresignedUrlDelete() throws Exception {
+    final String bucketName = getBucketName();
+    final String keyName = getKeyName();
+    final String content = "bar";
+    s3Client.createBucket(b -> b.bucket(bucketName));
+
+    s3Client.putObject(b -> b
+            .bucket(bucketName)
+            .key(keyName),
+        RequestBody.fromString(content));
+
+    try (S3Presigner presigner = createS3Presigner()) {
+
+      DeleteObjectRequest objectRequest = DeleteObjectRequest.builder()
+          .bucket(bucketName)
+          .key(keyName)
+          .build();
+
+      DeleteObjectPresignRequest presignRequest = 
DeleteObjectPresignRequest.builder()
+          .signatureDuration(Duration.ofMinutes(10))
+          .deleteObjectRequest(objectRequest)
+          .build();
+
+      PresignedDeleteObjectRequest presignedRequest = 
presigner.presignDeleteObject(presignRequest);
+
+      // use http url connection
+      HttpURLConnection connection = null;
+      try {
+        connection = (HttpURLConnection) 
presignedRequest.url().openConnection();
+        connection.setRequestMethod("DELETE");
+
+        int responseCode = connection.getResponseCode();
+        assertEquals(204, responseCode, "DeleteObject presigned URL should 
return 204 No Content");
+
+        //verify the object was deleted
+        assertThrows(NoSuchKeyException.class, () -> s3Client.getObject(b -> 
b.bucket(bucketName).key(keyName)));
+      } finally {
+        if (connection != null) {
+          connection.disconnect();
+        }
+      }
+    }
+
+    // use SdkHttpClient
+    s3Client.putObject(b -> b
+            .bucket(bucketName)
+            .key(keyName),
+        RequestBody.fromString(content));
+
+    try (S3Presigner presigner = createS3Presigner();
+         SdkHttpClient sdkHttpClient = ApacheHttpClient.create()) {
+
+      DeleteObjectRequest objectRequest = DeleteObjectRequest.builder()
+          .bucket(bucketName)
+          .key(keyName)
+          .build();
+
+      DeleteObjectPresignRequest presignRequest = 
DeleteObjectPresignRequest.builder()
+          .signatureDuration(Duration.ofMinutes(10))
+          .deleteObjectRequest(objectRequest)
+          .build();
+
+      PresignedDeleteObjectRequest presignedRequest = 
presigner.presignDeleteObject(presignRequest);
+
+      SdkHttpRequest request = SdkHttpRequest.builder()
+          .method(SdkHttpMethod.DELETE)
+          .uri(presignedRequest.url().toURI())
+          .build();
+
+      HttpExecuteRequest executeRequest = HttpExecuteRequest.builder()
+          .request(request)
+          .build();
+
+      HttpExecuteResponse response = 
sdkHttpClient.prepareRequest(executeRequest).call();
+      assertEquals(204, response.httpResponse().statusCode(),
+          "DeleteObject presigned URL should return 204 No Content via 
SdkHttpClient");
+
+      //verify the object was deleted
+      assertThrows(NoSuchKeyException.class, () -> s3Client.getObject(b -> 
b.bucket(bucketName).key(keyName)));
+    }
+  }
+
   private S3Presigner createS3Presigner() {
     return S3Presigner.builder()
         // TODO: Find a way to retrieve the path style configuration from 
S3Client instead


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@ozone.apache.org
For additional commands, e-mail: commits-h...@ozone.apache.org

Reply via email to