This is an automated email from the ASF dual-hosted git repository.
ivandika3 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 d1eee36a502 HDDS-15618. Fix ListObjects to include single
whitespace-only S3 object keys (#10589)
d1eee36a502 is described below
commit d1eee36a502793f0fa095668ab47e01e8b7c7c52
Author: Gargi Jaiswal <[email protected]>
AuthorDate: Mon Jun 29 14:58:22 2026 +0530
HDDS-15618. Fix ListObjects to include single whitespace-only S3 object
keys (#10589)
---
.../hadoop/ozone/s3/awssdk/S3SDKTestUtils.java | 9 ++++++++
.../ozone/s3/awssdk/v1/AbstractS3SDKV1Tests.java | 22 +++++++++++++++++++
.../ozone/s3/awssdk/v2/AbstractS3SDKV2Tests.java | 22 +++++++++++++++++++
.../hadoop/ozone/om/OmMetadataManagerImpl.java | 2 +-
.../hadoop/ozone/om/TestOmMetadataManager.java | 25 ++++++++++++++++++++++
5 files changed, 79 insertions(+), 1 deletion(-)
diff --git
a/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/S3SDKTestUtils.java
b/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/S3SDKTestUtils.java
index ec42a0d7b4f..ec3793c68d1 100644
---
a/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/S3SDKTestUtils.java
+++
b/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/S3SDKTestUtils.java
@@ -25,6 +25,8 @@
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
@@ -38,6 +40,13 @@
*/
public final class S3SDKTestUtils {
+ /**
+ * Key names from ceph s3-tests {@code test_bucket_create_special_key_names}.
+ */
+ public static final List<String> S3_SPECIAL_KEY_NAMES =
Collections.unmodifiableList(
+ Arrays.asList(" ", "\"",
+ "$", "%", "&", "'", "<", ">", "_", "_ ", "_ _", "__"));
+
public static final Pattern UPLOAD_ID_PATTERN =
Pattern.compile("<UploadId>(.+?)</UploadId>");
private S3SDKTestUtils() {
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 5de874b51d0..e810a8786b9 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
@@ -1316,6 +1316,28 @@ public void testListObjectsManyV2() throws Exception {
testListObjectsMany(true);
}
+ @Test
+ public void testListObjectsSpecialKeyNames() throws Exception {
+ final String bucketName = getBucketName("special-keys");
+ final String content = "x";
+ s3Client.createBucket(bucketName);
+
+ for (String keyName : S3SDKTestUtils.S3_SPECIAL_KEY_NAMES) {
+ InputStream is = new
ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8));
+ s3Client.putObject(bucketName, keyName, is, new ObjectMetadata());
+ try (S3Object object = s3Client.getObject(bucketName, keyName)) {
+ assertEquals(content, IOUtils.toString(object.getObjectContent(),
StandardCharsets.UTF_8));
+ }
+ }
+
+ ObjectListing listObjectsResponse = s3Client.listObjects(
+ new ListObjectsRequest().withBucketName(bucketName));
+ List<String> listedKeys = listObjectsResponse.getObjectSummaries().stream()
+ .map(S3ObjectSummary::getKey)
+ .collect(Collectors.toList());
+ assertEquals(S3SDKTestUtils.S3_SPECIAL_KEY_NAMES, listedKeys);
+ }
+
private void testListObjectsMany(boolean isListV2) throws Exception {
final String bucketName = getBucketName();
s3Client.createBucket(bucketName);
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 ff46b739d9f..d807be57483 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
@@ -993,6 +993,28 @@ public void testListObjectsManyV2() throws Exception {
testListObjectsMany(true);
}
+ @Test
+ public void testListObjectsSpecialKeyNamesV2() throws Exception {
+ final String bucketName = getBucketName("special-keys");
+ final String content = "x";
+ s3Client.createBucket(b -> b.bucket(bucketName));
+
+ for (String keyName : S3SDKTestUtils.S3_SPECIAL_KEY_NAMES) {
+ s3Client.putObject(b -> b.bucket(bucketName).key(keyName),
+ RequestBody.fromString(content));
+ ResponseBytes<GetObjectResponse> objectBytes = s3Client.getObjectAsBytes(
+ b -> b.bucket(bucketName).key(keyName));
+ assertEquals(content, objectBytes.asUtf8String());
+ }
+
+ ListObjectsV2Response listObjectsResponse = s3Client.listObjectsV2(
+ ListObjectsV2Request.builder().bucket(bucketName).build());
+ List<String> listedKeys = listObjectsResponse.contents().stream()
+ .map(S3Object::key)
+ .collect(Collectors.toList());
+ assertEquals(S3SDKTestUtils.S3_SPECIAL_KEY_NAMES, listedKeys);
+ }
+
private void testListObjectsMany(boolean isListV2) throws Exception {
final String bucketName = getBucketName();
s3Client.createBucket(b -> b.bucket(bucketName));
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataManagerImpl.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataManagerImpl.java
index b76e5aa5262..69b1ef67bfe 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataManagerImpl.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataManagerImpl.java
@@ -640,7 +640,7 @@ public String getOzoneKey(String volume, String bucket,
String key) {
StringBuilder builder = new StringBuilder()
.append(OM_KEY_PREFIX).append(volume)
.append(OM_KEY_PREFIX).append(bucket); // TODO : Throw if the Bucket
is null?
- if (StringUtils.isNotBlank(key)) {
+ if (StringUtils.isNotEmpty(key)) {
builder.append(OM_KEY_PREFIX);
if (!key.equals(OM_KEY_PREFIX)) {
builder.append(key);
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOmMetadataManager.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOmMetadataManager.java
index fc2a9ca78b0..17131e0c7db 100644
---
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOmMetadataManager.java
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOmMetadataManager.java
@@ -1294,4 +1294,29 @@ public void testGetMultipartUploadKeys() throws
Exception {
assertEquals(25, noPagination.size());
}
+
+ @Test
+ public void testListKeysSpecialKeyNames() throws Exception {
+ List<String> keyNames = Arrays.asList(" ", "\"",
+ "$", "%", "&", "'", "<", ">", "_", "_ ", "_ _", "__");
+
+ String volumeName = "volumeA";
+ String bucketName = "bucketA";
+ OMRequestTestUtils.addVolumeToDB(volumeName, omMetadataManager);
+ addBucketsToCache(volumeName, bucketName);
+
+ assertEquals("/volumeA/bucketA/ ",
+ omMetadataManager.getOzoneKey(volumeName, bucketName, " "));
+
+ for (int i = 0; i < keyNames.size(); i++) {
+ addKeysToOM(volumeName, bucketName, keyNames.get(i), i);
+ }
+
+ List<String> listedKeys = omMetadataManager.listKeys(volumeName,
bucketName,
+ null, null, 100).getKeys().stream()
+ .map(OmKeyInfo::getKeyName)
+ .collect(Collectors.toList());
+
+ assertEquals(keyNames, listedKeys);
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]