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 static software.amazon.awssdk.services.s3.internal.checksums.ChecksumConstant.ENABLE_CHECKSUM_REQUEST_HEADER; 19 import static software.amazon.awssdk.services.s3.internal.checksums.ChecksumConstant.ENABLE_MD5_CHECKSUM_HEADER_VALUE; 20 import static software.amazon.awssdk.services.s3.internal.checksums.ChecksumConstant.S3_MD5_CHECKSUM_LENGTH; 21 import static software.amazon.awssdk.services.s3.internal.checksums.ChecksumsEnabledValidator.getObjectChecksumEnabledPerRequest; 22 import static software.amazon.awssdk.services.s3.internal.checksums.ChecksumsEnabledValidator.getObjectChecksumEnabledPerResponse; 23 24 import software.amazon.awssdk.annotations.SdkInternalApi; 25 import software.amazon.awssdk.core.SdkRequest; 26 import software.amazon.awssdk.core.SdkResponse; 27 import software.amazon.awssdk.core.interceptor.Context; 28 import software.amazon.awssdk.core.interceptor.ExecutionAttributes; 29 import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; 30 import software.amazon.awssdk.http.SdkHttpRequest; 31 import software.amazon.awssdk.http.SdkHttpResponse; 32 import software.amazon.awssdk.services.s3.internal.s3express.S3ExpressUtils; 33 import software.amazon.awssdk.services.s3.model.ChecksumMode; 34 import software.amazon.awssdk.services.s3.model.GetObjectRequest; 35 import software.amazon.awssdk.services.s3.model.GetObjectResponse; 36 import software.amazon.awssdk.utils.Validate; 37 38 @SdkInternalApi 39 public final class EnableTrailingChecksumInterceptor implements ExecutionInterceptor { 40 41 /** 42 * Enable {@link ChecksumMode} for {@link GetObjectRequest} if trailing checksum is enabled from config, 43 * {@link ChecksumMode} is disabled, and is S3Express. 44 * TODO (s3express) - refactor to migrate out s3express specific code 45 */ 46 @Override modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes)47 public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) { 48 49 SdkRequest request = context.request(); 50 if (getObjectChecksumEnabledPerRequest(request, executionAttributes) 51 && S3ExpressUtils.useS3Express(executionAttributes)) { 52 return ((GetObjectRequest) request).toBuilder().checksumMode(ChecksumMode.ENABLED).build(); 53 } 54 return request; 55 } 56 57 /** 58 * Append trailing checksum header for {@link GetObjectRequest} if trailing checksum is enabled from config, 59 * {@link ChecksumMode} is disabled, and is not S3Express. 60 */ 61 @Override modifyHttpRequest(Context.ModifyHttpRequest context, ExecutionAttributes executionAttributes)62 public SdkHttpRequest modifyHttpRequest(Context.ModifyHttpRequest context, 63 ExecutionAttributes executionAttributes) { 64 65 if (getObjectChecksumEnabledPerRequest(context.request(), executionAttributes) 66 && !S3ExpressUtils.useS3Express(executionAttributes)) { 67 return context.httpRequest() 68 .toBuilder() 69 .putHeader(ENABLE_CHECKSUM_REQUEST_HEADER, ENABLE_MD5_CHECKSUM_HEADER_VALUE) 70 .build(); 71 } 72 73 return context.httpRequest(); 74 } 75 76 /** 77 * Subtract the contentLength of {@link GetObjectResponse} if trailing checksums is enabled. 78 */ 79 @Override modifyResponse(Context.ModifyResponse context, ExecutionAttributes executionAttributes)80 public SdkResponse modifyResponse(Context.ModifyResponse context, ExecutionAttributes executionAttributes) { 81 SdkResponse response = context.response(); 82 SdkHttpResponse httpResponse = context.httpResponse(); 83 84 if (getObjectChecksumEnabledPerResponse(context.request(), httpResponse)) { 85 GetObjectResponse getResponse = (GetObjectResponse) response; 86 Long contentLength = getResponse.contentLength(); 87 Validate.notNull(contentLength, "Service returned null 'Content-Length'."); 88 return getResponse.toBuilder() 89 .contentLength(contentLength - S3_MD5_CHECKSUM_LENGTH) 90 .build(); 91 } 92 93 return response; 94 } 95 } 96