From 2182a44a8ff5ea8a77a23fddcff23574642eddbe Mon Sep 17 00:00:00 2001 From: Will Paul Date: Thu, 16 May 2024 13:37:55 -0400 Subject: [PATCH] Fix 4990, allow null values in S3 object metadata Change tests to check keys in any order instead of relying on keySets implicit ordering. --- .../next-release/bugfix-AmazonS3-d82f8b1.json | 6 ++++++ .../handlers/ObjectMetadataInterceptor.java | 4 ++-- .../ObjectMetadataInterceptorTest.java | 18 ++++++++++++------ 3 files changed, 20 insertions(+), 8 deletions(-) create mode 100644 .changes/next-release/bugfix-AmazonS3-d82f8b1.json diff --git a/.changes/next-release/bugfix-AmazonS3-d82f8b1.json b/.changes/next-release/bugfix-AmazonS3-d82f8b1.json new file mode 100644 index 000000000000..8d9b9a478c72 --- /dev/null +++ b/.changes/next-release/bugfix-AmazonS3-d82f8b1.json @@ -0,0 +1,6 @@ +{ + "type": "bugfix", + "category": "Amazon S3", + "contributor": "dropofwill", + "description": "Fixes issue 4990 allowing null values in S3 object metadata" +} diff --git a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/handlers/ObjectMetadataInterceptor.java b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/handlers/ObjectMetadataInterceptor.java index b5043a990374..7665b2be1aaa 100644 --- a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/handlers/ObjectMetadataInterceptor.java +++ b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/handlers/ObjectMetadataInterceptor.java @@ -15,8 +15,8 @@ package software.amazon.awssdk.services.s3.internal.handlers; +import java.util.HashMap; import java.util.Map; -import java.util.stream.Collectors; import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.core.SdkRequest; import software.amazon.awssdk.core.interceptor.Context; @@ -69,6 +69,6 @@ private CreateMultipartUploadRequest trimMetadataNames(CreateMultipartUploadRequ private Map trimKeys(Map map) { return map.entrySet().stream() - .collect(Collectors.toMap(e -> StringUtils.trim(e.getKey()), Map.Entry::getValue)); + .collect(HashMap::new, (hm, entry) -> hm.put(StringUtils.trim(entry.getKey()), entry.getValue()), HashMap::putAll); } } diff --git a/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/handlers/ObjectMetadataInterceptorTest.java b/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/handlers/ObjectMetadataInterceptorTest.java index a29fff164c8e..71b27446f1b6 100644 --- a/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/handlers/ObjectMetadataInterceptorTest.java +++ b/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/handlers/ObjectMetadataInterceptorTest.java @@ -20,6 +20,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -37,15 +38,20 @@ public class ObjectMetadataInterceptorTest { private static final ObjectMetadataInterceptor INTERCEPTOR = new ObjectMetadataInterceptor(); - - public static List testCases() { + List listWithNulls = new ArrayList<>(); + listWithNulls.add("\tc\r\n"); + listWithNulls.add(null); + + List listWithNullsTrimmed = new ArrayList<>(); + listWithNullsTrimmed.add("c"); + listWithNullsTrimmed.add(null); return asList( tc(asList("a", "b", "c"), asList("a", "b", "c")), tc(asList(" a ", "b", "c"), asList("a", "b", "c")), tc(asList(" a", "\tb", "\tc"), asList("a", "b", "c")), - tc(asList("a\n", "\tb", "\tc\r\n"), asList("a", "b", "c")) - + tc(asList("a\n", "\tb", "\tc\r\n"), asList("a", "b", "c")), + tc(listWithNulls, listWithNullsTrimmed) ); } @@ -68,7 +74,7 @@ public void modifyRequest_putObject_metadataKeysAreTrimmed(TestCase tc) { PutObjectRequest modified = (PutObjectRequest) INTERCEPTOR.modifyRequest(ctx, attrs); - assertThat(modified.metadata().keySet()).containsExactlyElementsOf(tc.expectedKeys); + assertThat(modified.metadata().keySet()).containsOnlyOnceElementsOf(tc.expectedKeys); } @ParameterizedTest @@ -90,7 +96,7 @@ public void modifyRequest_creatMultipartUpload_metadataKeysAreTrimmed(TestCase t CreateMultipartUploadRequest modified = (CreateMultipartUploadRequest) INTERCEPTOR.modifyRequest(ctx, attrs); - assertThat(modified.metadata().keySet()).containsExactlyElementsOf(tc.expectedKeys); + assertThat(modified.metadata().keySet()).containsOnlyOnceElementsOf(tc.expectedKeys); } @Test