1 /* 2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"). 5 * You may not use this file except in compliance with the License. 6 * A copy of the License is located at 7 * 8 * http://aws.amazon.com/apache2.0 9 * 10 * or in the "license" file accompanying this file. This file is distributed 11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 * express or implied. See the License for the specific language governing 13 * permissions and limitations under the License. 14 */ 15 16 package software.amazon.awssdk.services.s3.internal.handlers; 17 18 import java.util.Map; 19 import java.util.stream.Collectors; 20 import software.amazon.awssdk.annotations.SdkInternalApi; 21 import software.amazon.awssdk.core.SdkRequest; 22 import software.amazon.awssdk.core.interceptor.Context; 23 import software.amazon.awssdk.core.interceptor.ExecutionAttributes; 24 import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; 25 import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute; 26 import software.amazon.awssdk.services.s3.model.CreateMultipartUploadRequest; 27 import software.amazon.awssdk.services.s3.model.PutObjectRequest; 28 import software.amazon.awssdk.utils.StringUtils; 29 30 /** 31 * Interceptor that trims object metadata keys of any leading or trailing whitespace for {@code PutObject} and {@code 32 * CreateMultipartUpload}. This behavior is intended to provide the same functionality as in 1.x. 33 */ 34 @SdkInternalApi 35 public final class ObjectMetadataInterceptor implements ExecutionInterceptor { 36 @Override modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes)37 public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) { 38 SdkRequest request = context.request(); 39 40 switch (executionAttributes.getAttribute(SdkExecutionAttribute.OPERATION_NAME)) { 41 case "PutObject": 42 return trimMetadataNames((PutObjectRequest) request); 43 case "CreateMultipartUpload": 44 return trimMetadataNames((CreateMultipartUploadRequest) request); 45 default: 46 return request; 47 } 48 } 49 trimMetadataNames(PutObjectRequest putObjectRequest)50 private PutObjectRequest trimMetadataNames(PutObjectRequest putObjectRequest) { 51 if (!putObjectRequest.hasMetadata()) { 52 return putObjectRequest; 53 } 54 55 return putObjectRequest.toBuilder() 56 .metadata(trimKeys(putObjectRequest.metadata())) 57 .build(); 58 } 59 trimMetadataNames(CreateMultipartUploadRequest createMultipartUploadRequest)60 private CreateMultipartUploadRequest trimMetadataNames(CreateMultipartUploadRequest createMultipartUploadRequest) { 61 if (!createMultipartUploadRequest.hasMetadata()) { 62 return createMultipartUploadRequest; 63 } 64 65 return createMultipartUploadRequest.toBuilder() 66 .metadata(trimKeys(createMultipartUploadRequest.metadata())) 67 .build(); 68 } 69 trimKeys(Map<String, String> map)70 private Map<String, String> trimKeys(Map<String, String> map) { 71 return map.entrySet().stream() 72 .collect(Collectors.toMap(e -> StringUtils.trim(e.getKey()), Map.Entry::getValue)); 73 } 74 } 75