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

chungen0126 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 9ff43fef43f HDDS-16004. Return NotImplemented for GetObjectTorrent 
instead of GetObject body (#10899)
9ff43fef43f is described below

commit 9ff43fef43f6d65ac56d1afe82c8746a64ff6fa6
Author: Mark Tsai <[email protected]>
AuthorDate: Thu Aug 6 10:49:24 2026 +0800

    HDDS-16004. Return NotImplemented for GetObjectTorrent instead of GetObject 
body (#10899)
---
 .../ozone/s3/awssdk/v1/AbstractS3SDKV1Tests.java   | 30 ++++++++++++
 .../ozone/s3/awssdk/v2/AbstractS3SDKV2Tests.java   | 20 ++++++++
 .../org/apache/hadoop/ozone/audit/S3GAction.java   |  1 +
 .../hadoop/ozone/s3/endpoint/ObjectEndpoint.java   |  1 +
 .../ozone/s3/endpoint/ObjectGetTorrentHandler.java | 48 +++++++++++++++++++
 .../org/apache/hadoop/ozone/s3/util/S3Consts.java  |  2 +
 .../ozone/s3/endpoint/TestObjectGetTorrent.java    | 54 ++++++++++++++++++++++
 7 files changed, 156 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 8ef4bdcd83a..f95d7de9bb9 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
@@ -2454,6 +2454,36 @@ public void testPresignedUrlGet() throws IOException {
       }
     }
 
+    @Test
+    public void testPresignedUrlGetObjectTorrentNotImplemented() throws 
Exception {
+      final String keyName = getKeyName();
+
+      InputStream is = new 
ByteArrayInputStream(CONTENT.getBytes(StandardCharsets.UTF_8));
+      s3Client.putObject(BUCKET_NAME, keyName, is, new ObjectMetadata());
+
+      // AmazonS3 (SDK v1) has no getObjectTorrent API, so exercise the same 
HTTP behavior
+      // via a presigned URL with the torrent query parameter, as with other 
request shapes
+      // the typed v1 API doesn't expose.
+      GeneratePresignedUrlRequest generatePresignedUrlRequest =
+          new GeneratePresignedUrlRequest(BUCKET_NAME, 
keyName).withMethod(HttpMethod.GET).withExpiration(expiration);
+      generatePresignedUrlRequest.addRequestParameter("torrent", "");
+      URL presignedUrl = 
s3Client.generatePresignedUrl(generatePresignedUrlRequest);
+
+      HttpURLConnection connection = null;
+      try {
+        connection = S3SDKTestUtils.openHttpURLConnection(presignedUrl, "GET", 
null, null);
+        assertEquals(HttpURLConnection.HTTP_NOT_IMPLEMENTED, 
connection.getResponseCode());
+      } finally {
+        if (connection != null) {
+          connection.disconnect();
+        }
+      }
+
+      // object must be untouched
+      ObjectMetadata metadata = s3Client.getObjectMetadata(BUCKET_NAME, 
keyName);
+      assertEquals(CONTENT.length(), metadata.getContentLength());
+    }
+
     @Test
     public void testPresignedUrlHead() throws IOException {
       final String keyName = getKeyName();
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 096c154bf66..dfe570d23c4 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
@@ -640,6 +640,26 @@ public void testGetObjectUnreadableKey() {
     assertEquals(S3ErrorTable.INVALID_URI.getErrorMessage(), 
exception.awsErrorDetails().errorMessage());
   }
 
+  @Test
+  public void testGetObjectTorrentNotImplemented() {
+    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));
+
+    S3Exception exception = assertThrows(S3Exception.class,
+        () -> s3Client.getObjectTorrent(b -> 
b.bucket(bucketName).key(keyName)));
+
+    assertEquals(501, exception.statusCode());
+    assertEquals(S3ErrorTable.NOT_IMPLEMENTED.getCode(), 
exception.awsErrorDetails().errorCode());
+    assertEquals(S3ErrorTable.NOT_IMPLEMENTED.getErrorMessage(), 
exception.awsErrorDetails().errorMessage());
+
+    // object must be untouched
+    HeadObjectResponse headObjectResponse = s3Client.headObject(b -> 
b.bucket(bucketName).key(keyName));
+    assertEquals(content.length(), headObjectResponse.contentLength());
+  }
+
   @Test
   public void testHeadObjectIfMatch() {
     final String bucketName = getBucketName();
diff --git 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/audit/S3GAction.java
 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/audit/S3GAction.java
index e46f4d53f9f..11efd4e9064 100644
--- 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/audit/S3GAction.java
+++ 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/audit/S3GAction.java
@@ -55,6 +55,7 @@ public enum S3GAction implements AuditAction {
   CREATE_DIRECTORY,
   GENERATE_SECRET,
   REVOKE_SECRET,
+  GET_OBJECT_TORRENT,
   GET_OBJECT_TAGGING,
   PUT_OBJECT_TAGGING,
   DELETE_OBJECT_TAGGING,
diff --git 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectEndpoint.java
 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectEndpoint.java
index ad798e36989..0fa629764e5 100644
--- 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectEndpoint.java
+++ 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectEndpoint.java
@@ -149,6 +149,7 @@ public ObjectEndpoint() {
   protected void init() {
     super.init();
     ObjectOperationHandler chain = ObjectOperationHandlerChain.newBuilder(this)
+        .add(new ObjectGetTorrentHandler())
         .add(new ObjectAclHandler())
         .add(new ObjectTaggingHandler())
         .add(new MultipartKeyHandler())
diff --git 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectGetTorrentHandler.java
 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectGetTorrentHandler.java
new file mode 100644
index 00000000000..312d323d803
--- /dev/null
+++ 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectGetTorrentHandler.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.ozone.s3.endpoint;
+
+import static 
org.apache.hadoop.ozone.s3.exception.S3ErrorTable.NOT_IMPLEMENTED;
+import static org.apache.hadoop.ozone.s3.exception.S3ErrorTable.newError;
+
+import java.io.IOException;
+import javax.ws.rs.core.Response;
+import org.apache.hadoop.ozone.audit.S3GAction;
+import org.apache.hadoop.ozone.s3.endpoint.ObjectEndpoint.ObjectRequestContext;
+import org.apache.hadoop.ozone.s3.exception.OS3Exception;
+import org.apache.hadoop.ozone.s3.util.S3Consts.QueryParams;
+
+/**
+ * Handles GET object {@code ?torrent} ({@code GetObjectTorrent}).
+ * <p>
+ * This operation is not implemented; previously the request incorrectly fell
+ * through to GetObject and returned the raw object body.
+ */
+class ObjectGetTorrentHandler extends ObjectOperationHandler {
+
+  @Override
+  Response handleGetRequest(ObjectRequestContext context, String keyName)
+      throws IOException, OS3Exception {
+    if (queryParams().get(QueryParams.TORRENT) == null) {
+      return null;
+    }
+
+    context.setAction(S3GAction.GET_OBJECT_TORRENT);
+    throw newError(NOT_IMPLEMENTED, "GetObjectTorrent");
+  }
+}
diff --git 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/util/S3Consts.java
 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/util/S3Consts.java
index 0d2122d999a..c8a2f7f4809 100644
--- 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/util/S3Consts.java
+++ 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/util/S3Consts.java
@@ -164,6 +164,8 @@ public static final class QueryParams {
     public static final String PREFIX = "prefix";
     public static final String START_AFTER = "start-after";
     public static final String TAGGING = "tagging";
+    // GetObjectTorrent is not implemented
+    public static final String TORRENT = "torrent";
     public static final String UPLOAD_ID = "uploadId";
     public static final String UPLOAD_ID_MARKER = "upload-id-marker";
     public static final String UPLOADS = "uploads";
diff --git 
a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestObjectGetTorrent.java
 
b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestObjectGetTorrent.java
new file mode 100644
index 00000000000..4791d7cf006
--- /dev/null
+++ 
b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestObjectGetTorrent.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.ozone.s3.endpoint;
+
+import static 
org.apache.hadoop.ozone.s3.endpoint.EndpointTestUtils.assertErrorResponse;
+import static org.apache.hadoop.ozone.s3.endpoint.EndpointTestUtils.get;
+
+import java.io.IOException;
+import org.apache.hadoop.ozone.client.OzoneClient;
+import org.apache.hadoop.ozone.client.OzoneClientStub;
+import org.apache.hadoop.ozone.s3.exception.S3ErrorTable;
+import org.apache.hadoop.ozone.s3.util.S3Consts.QueryParams;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/** Tests for {@code GET /{bucket}/{key}?torrent} ({@code GetObjectTorrent}). 
*/
+public class TestObjectGetTorrent {
+
+  private static final String BUCKET_NAME = "b1";
+  private static final String KEY_NAME = "key1";
+  private ObjectEndpoint objectEndpoint;
+
+  @BeforeEach
+  public void setup() throws IOException {
+    final OzoneClient clientStub = new OzoneClientStub();
+    clientStub.getObjectStore().createS3Bucket(BUCKET_NAME);
+
+    objectEndpoint = EndpointBuilder.newObjectEndpointBuilder()
+        .setClient(clientStub)
+        .build();
+  }
+
+  @Test
+  public void getObjectTorrentIsNotImplemented() {
+    objectEndpoint.queryParamsForTest().set(QueryParams.TORRENT, "");
+
+    assertErrorResponse(S3ErrorTable.NOT_IMPLEMENTED, () -> 
get(objectEndpoint, BUCKET_NAME, KEY_NAME));
+  }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to