This is an automated email from the ASF dual-hosted git repository.
peterxcli 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 b8a63126881 HDDS-15304. DeleteObjects should enforce the request key
limit (#10309)
b8a63126881 is described below
commit b8a631268816056b3378d8f8a987b199a18a66f9
Author: sreejasahithi <[email protected]>
AuthorDate: Wed Jun 17 22:12:47 2026 +0530
HDDS-15304. DeleteObjects should enforce the request key limit (#10309)
Co-authored-by: Peter Lee <[email protected]>
---
.../hadoop/ozone/s3/endpoint/BucketEndpoint.java | 6 ++++
.../org/apache/hadoop/ozone/s3/util/S3Consts.java | 3 ++
.../ozone/s3/endpoint/TestObjectMultiDelete.java | 39 ++++++++++++++++++++++
3 files changed, 48 insertions(+)
diff --git
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketEndpoint.java
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketEndpoint.java
index 9301c235f40..d35da257cd0 100644
---
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketEndpoint.java
+++
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketEndpoint.java
@@ -62,6 +62,7 @@
import org.apache.hadoop.ozone.s3.exception.OS3Exception;
import org.apache.hadoop.ozone.s3.exception.S3ErrorTable;
import org.apache.hadoop.ozone.s3.util.ContinueToken;
+import org.apache.hadoop.ozone.s3.util.S3Consts;
import org.apache.hadoop.ozone.s3.util.S3Consts.QueryParams;
import org.apache.hadoop.ozone.s3.util.S3StorageType;
import org.apache.hadoop.util.Time;
@@ -337,6 +338,11 @@ public MultiDeleteResponse multiDelete(
) throws OS3Exception, IOException {
S3GAction s3GAction = S3GAction.MULTI_DELETE;
+ if (request.getObjects() != null
+ && request.getObjects().size() > S3Consts.S3_DELETE_OBJECTS_MAX_KEYS) {
+ throw newError(S3ErrorTable.MALFORMED_XML, bucketName);
+ }
+
OzoneBucket bucket = getVolume().getBucket(bucketName);
MultiDeleteResponse result = new MultiDeleteResponse();
List<String> deleteKeys = new ArrayList<>();
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 c898ea78e4a..abc654f916e 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
@@ -95,6 +95,9 @@ public final class S3Consts {
public static final Pattern TAG_REGEX_PATTERN =
Pattern.compile("^([\\p{L}\\p{Z}\\p{N}_.:/=+\\-]*)$");
public static final String MP_PARTS_COUNT = "x-amz-mp-parts-count";
+ /** AWS S3 maximum number of keys per DeleteObjects request. */
+ public static final int S3_DELETE_OBJECTS_MAX_KEYS = 1000;
+
// Bucket owner condition headers
// See
https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-owner-condition.html
public static final String EXPECTED_BUCKET_OWNER_HEADER =
"x-amz-expected-bucket-owner";
diff --git
a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestObjectMultiDelete.java
b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestObjectMultiDelete.java
index 8b6c869b5d9..1d657460346 100644
---
a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestObjectMultiDelete.java
+++
b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestObjectMultiDelete.java
@@ -18,6 +18,8 @@
package org.apache.hadoop.ozone.s3.endpoint;
import static java.util.Collections.singleton;
+import static
org.apache.hadoop.ozone.s3.endpoint.EndpointTestUtils.assertErrorResponse;
+import static org.apache.hadoop.ozone.s3.exception.S3ErrorTable.MALFORMED_XML;
import static org.junit.jupiter.api.Assertions.assertEquals;
import com.google.common.collect.Sets;
@@ -32,6 +34,7 @@
import org.apache.hadoop.ozone.client.OzoneKey;
import org.apache.hadoop.ozone.s3.endpoint.MultiDeleteRequest.DeleteObject;
import org.apache.hadoop.ozone.s3.exception.OS3Exception;
+import org.apache.hadoop.ozone.s3.util.S3Consts;
import org.junit.jupiter.api.Test;
/**
@@ -101,6 +104,42 @@ public void deleteQuiet() throws IOException,
OS3Exception, JAXBException {
assertEquals(0, response.getErrors().size());
}
+ @Test
+ public void multiDeleteRejectsMoreThanMaxKeysPerRequest() throws Exception {
+ OzoneClient client = new OzoneClientStub();
+ BucketEndpoint rest = EndpointBuilder.newBucketEndpointBuilder()
+ .setClient(client)
+ .build();
+
+ MultiDeleteRequest mdr = new MultiDeleteRequest();
+ for (int i = 0; i < S3Consts.S3_DELETE_OBJECTS_MAX_KEYS + 1; i++) {
+ mdr.getObjects().add(new DeleteObject("key-" + i));
+ }
+
+ assertErrorResponse(MALFORMED_XML, () -> rest.multiDelete("b1", "", mdr));
+ }
+
+ @Test
+ public void multiDeleteAllowsMaxKeysPerRequest() throws Exception {
+ OzoneClient client = new OzoneClientStub();
+ OzoneBucket bucket = initTestData(client);
+ BucketEndpoint rest = EndpointBuilder.newBucketEndpointBuilder()
+ .setClient(client)
+ .build();
+
+ MultiDeleteRequest mdr = new MultiDeleteRequest();
+ mdr.setQuiet(true);
+ for (int i = 0; i < S3Consts.S3_DELETE_OBJECTS_MAX_KEYS; i++) {
+ mdr.getObjects().add(new DeleteObject("missing-" + i));
+ }
+
+ MultiDeleteResponse response = rest.multiDelete("b1", "", mdr);
+ assertEquals(0, response.getDeletedObjects().size());
+ assertEquals(0, response.getErrors().size());
+
+ assertEquals(3, Sets.newHashSet(bucket.listKeys("")).size());
+ }
+
private OzoneBucket initTestData(OzoneClient client) throws IOException {
client.getObjectStore().createS3Bucket("b1");
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]