This is an automated email from the ASF dual-hosted git repository.
adoroszlai 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 0a558c15e0 HDDS-12758. Error in OmUtils.normalizeKey for key name
starting with `//` (#8225)
0a558c15e0 is described below
commit 0a558c15e039c8db65f03024e829009fa4365567
Author: XiChen <[email protected]>
AuthorDate: Sat Apr 5 13:53:12 2025 +0800
HDDS-12758. Error in OmUtils.normalizeKey for key name starting with `//`
(#8225)
---
.../java/org/apache/hadoop/ozone/OzoneConsts.java | 1 +
.../main/java/org/apache/hadoop/ozone/OmUtils.java | 17 ++++++++++-
.../ozone/s3/awssdk/v1/AbstractS3SDKV1Tests.java | 29 ++++++++++++++++++
.../fs/ozone/TestOzoneFSWithObjectStoreCreate.java | 35 ++++++++++++++++++++++
.../ozone/om/request/TestNormalizePaths.java | 3 ++
5 files changed, 84 insertions(+), 1 deletion(-)
diff --git
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConsts.java
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConsts.java
index d03cc2a22f..11065a27ec 100644
--- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConsts.java
+++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConsts.java
@@ -170,6 +170,7 @@ public final class OzoneConsts {
*/
public static final String OM_KEY_PREFIX = "/";
+ public static final String DOUBLE_SLASH_OM_KEY_PREFIX = "//";
public static final String OM_USER_PREFIX = "$";
public static final String OM_S3_PREFIX = "S3:";
public static final String OM_S3_CALLER_CONTEXT_PREFIX = "S3Auth:S3G|";
diff --git
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java
index 100ff74ed5..e71e5b912a 100644
--- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java
+++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java
@@ -20,6 +20,7 @@
import static org.apache.hadoop.hdds.HddsUtils.getHostName;
import static org.apache.hadoop.hdds.HddsUtils.getHostNameFromConfigKeys;
import static org.apache.hadoop.hdds.HddsUtils.getPortNumberFromConfigKeys;
+import static org.apache.hadoop.ozone.OzoneConsts.DOUBLE_SLASH_OM_KEY_PREFIX;
import static org.apache.hadoop.ozone.OzoneConsts.OM_KEY_PREFIX;
import static org.apache.hadoop.ozone.OzoneConsts.OM_SNAPSHOT_INDICATOR;
import static org.apache.hadoop.ozone.OzoneConsts.OZONE_URI_DELIMITER;
@@ -760,7 +761,7 @@ public static String normalizeKey(String keyName,
if (!StringUtils.isBlank(keyName)) {
String normalizedKeyName;
if (keyName.startsWith(OM_KEY_PREFIX)) {
- normalizedKeyName = new Path(keyName).toUri().getPath();
+ normalizedKeyName = new
Path(normalizeLeadingSlashes(keyName)).toUri().getPath();
} else {
normalizedKeyName = new Path(OM_KEY_PREFIX + keyName)
.toUri().getPath();
@@ -778,6 +779,20 @@ public static String normalizeKey(String keyName,
return keyName;
}
+ /**
+ * Normalizes paths by replacing multiple leading slashes with a single
slash.
+ */
+ private static String normalizeLeadingSlashes(String keyName) {
+ if (keyName.startsWith(DOUBLE_SLASH_OM_KEY_PREFIX)) {
+ int index = 0;
+ while (index < keyName.length() && keyName.charAt(index) ==
OM_KEY_PREFIX.charAt(0)) {
+ index++;
+ }
+ return OM_KEY_PREFIX + keyName.substring(index);
+ }
+ return keyName;
+ }
+
/**
* Normalizes a given path up to the bucket level.
*
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 a4eefb81db..c45b37eed9 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
@@ -101,6 +101,9 @@
import org.apache.hadoop.ozone.client.OzoneClientFactory;
import org.apache.hadoop.ozone.client.OzoneVolume;
import org.apache.hadoop.ozone.client.io.OzoneOutputStream;
+import org.apache.hadoop.ozone.om.helpers.BucketLayout;
+import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
+import org.apache.hadoop.ozone.om.protocol.OzoneManagerProtocol;
import org.apache.hadoop.ozone.s3.S3ClientFactory;
import org.apache.hadoop.ozone.s3.S3GatewayService;
import org.apache.ozone.test.OzoneTestBase;
@@ -365,6 +368,32 @@ public void testPutObject() {
assertEquals("37b51d194a7513e45b56f6524f2d51f2",
putObjectResult.getETag());
}
+ @Test
+ public void testPutDoubleSlashPrefixObject() throws IOException {
+ final String bucketName = getBucketName();
+ final String keyName = "//dir1";
+ final String content = "bar";
+ OzoneConfiguration conf = cluster.getConf();
+ // Create a FSO bucket for test
+ try (OzoneClient ozoneClient = OzoneClientFactory.getRpcClient(conf)) {
+ ObjectStore store = ozoneClient.getObjectStore();
+ OzoneVolume volume = store.getS3Volume();
+ OmBucketInfo.Builder bucketInfo = new OmBucketInfo.Builder()
+ .setVolumeName(volume.getName())
+ .setBucketName(bucketName)
+ .setBucketLayout(BucketLayout.FILE_SYSTEM_OPTIMIZED);
+ OzoneManagerProtocol ozoneManagerProtocol =
store.getClientProxy().getOzoneManagerClient();
+ ozoneManagerProtocol.createBucket(bucketInfo.build());
+ }
+
+ InputStream is = new
ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8));
+ PutObjectResult putObjectResult = s3Client.putObject(bucketName, keyName,
is, new ObjectMetadata());
+ assertEquals("37b51d194a7513e45b56f6524f2d51f2",
putObjectResult.getETag());
+
+ S3Object object = s3Client.getObject(bucketName, keyName);
+ assertEquals(content.length(),
object.getObjectMetadata().getContentLength());
+ }
+
@Test
public void testPutObjectEmpty() {
final String bucketName = getBucketName();
diff --git
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestOzoneFSWithObjectStoreCreate.java
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestOzoneFSWithObjectStoreCreate.java
index 0f5f24fd66..26f06f9abc 100644
---
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestOzoneFSWithObjectStoreCreate.java
+++
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestOzoneFSWithObjectStoreCreate.java
@@ -27,6 +27,7 @@
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -67,6 +68,8 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.Timeout;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
/**
* Class tests create with object store and getFileStatus.
@@ -386,6 +389,38 @@ public void testListKeysWithNotNormalizedPath() throws
Exception {
checkKeyList(ozoneKeyIterator, keys);
}
+ @ParameterizedTest
+ @ValueSource(ints = {2, 3, 4})
+ public void testDoubleSlashPrefixPathNormalization(int slashCount) throws
Exception {
+ OzoneVolume ozoneVolume = client.getObjectStore().getVolume(volumeName);
+ OzoneBucket ozoneBucket = ozoneVolume.getBucket(bucketName);
+ // Generate a path with the specified number of leading slashes
+ StringBuilder keyPrefix = new StringBuilder();
+ for (int i = 0; i < slashCount; i++) {
+ keyPrefix.append('/');
+ }
+ String dirPath = "dir" + slashCount + "/";
+ String keyName = "key" + slashCount;
+ String slashyKey = keyPrefix + dirPath + keyName;
+ String normalizedKey = dirPath + keyName;
+ byte[] data = new byte[10];
+ Arrays.fill(data, (byte)96);
+ ArrayList<String> expectedKeys = new ArrayList<>();
+ expectedKeys.add(dirPath);
+ expectedKeys.add(normalizedKey);
+ TestDataUtil.createKey(ozoneBucket, slashyKey, data);
+
+ try {
+ ozoneBucket.readKey(slashyKey).close();
+ ozoneBucket.readKey(normalizedKey).close();
+ } catch (Exception e) {
+ fail("Should be able to read key " + e.getMessage());
+ }
+
+ Iterator<? extends OzoneKey> it = ozoneBucket.listKeys(dirPath);
+ checkKeyList(it, expectedKeys);
+ }
+
private void checkKeyList(Iterator<? extends OzoneKey > ozoneKeyIterator,
List<String> keys) {
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/TestNormalizePaths.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/TestNormalizePaths.java
index c37cbfda59..0889a53272 100644
---
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/TestNormalizePaths.java
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/TestNormalizePaths.java
@@ -58,6 +58,9 @@ public void testNormalizePathsEnabled() throws Exception {
validateAndNormalizeKey(true, "a/b/c/d/"));
assertEquals("a/b/c/...../d",
validateAndNormalizeKey(true, "////a/b/////c/...../d/"));
+ assertEquals("a/b/c", validateAndNormalizeKey(true, "/a/b/c"));
+ assertEquals("a/b/c", validateAndNormalizeKey(true, "//a/b/c"));
+ assertEquals("a/b/c", validateAndNormalizeKey(true, "///a/b/c"));
}
@Test
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]