• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.core.internal.interceptor;
17 
18 import static software.amazon.awssdk.core.ClientType.ASYNC;
19 import static software.amazon.awssdk.core.ClientType.SYNC;
20 import static software.amazon.awssdk.core.internal.util.HttpChecksumUtils.getAlgorithmChecksumValuePair;
21 
22 import java.io.InputStream;
23 import java.nio.ByteBuffer;
24 import java.util.Optional;
25 import java.util.function.Predicate;
26 import org.reactivestreams.Publisher;
27 import software.amazon.awssdk.annotations.SdkInternalApi;
28 import software.amazon.awssdk.core.ClientType;
29 import software.amazon.awssdk.core.checksums.Algorithm;
30 import software.amazon.awssdk.core.checksums.ChecksumSpecs;
31 import software.amazon.awssdk.core.checksums.ChecksumValidation;
32 import software.amazon.awssdk.core.checksums.SdkChecksum;
33 import software.amazon.awssdk.core.interceptor.Context;
34 import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
35 import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
36 import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute;
37 import software.amazon.awssdk.core.internal.async.ChecksumValidatingPublisher;
38 import software.amazon.awssdk.core.internal.io.ChecksumValidatingInputStream;
39 import software.amazon.awssdk.core.internal.util.HttpChecksumResolver;
40 import software.amazon.awssdk.core.internal.util.HttpChecksumUtils;
41 import software.amazon.awssdk.utils.Pair;
42 
43 /**
44  * Interceptor to intercepts Sync and Async responses.
45  * The Http Checksum is computed and validated with the one that is passed in the header of the response.
46  */
47 @SdkInternalApi
48 public final class HttpChecksumValidationInterceptor implements ExecutionInterceptor {
49 
50     private static final Predicate<ExecutionAttributes> IS_FORCE_SKIPPED_VALIDATION =
51         ex -> ChecksumValidation.FORCE_SKIP.equals(
52             ex.getOptionalAttribute(SdkExecutionAttribute.HTTP_RESPONSE_CHECKSUM_VALIDATION).orElse(null));
53 
54     @Override
modifyHttpResponseContent(Context.ModifyHttpResponse context, ExecutionAttributes executionAttributes)55     public Optional<InputStream> modifyHttpResponseContent(Context.ModifyHttpResponse context,
56                                                            ExecutionAttributes executionAttributes) {
57 
58         ChecksumSpecs resolvedChecksumSpecs = HttpChecksumResolver.getResolvedChecksumSpecs(executionAttributes);
59         if (resolvedChecksumSpecs != null &&
60             isFlexibleChecksumValidationForResponse(executionAttributes, resolvedChecksumSpecs, SYNC)) {
61 
62             Pair<Algorithm, String> algorithmChecksumPair = getAlgorithmChecksumValuePair(
63                 context.httpResponse(), resolvedChecksumSpecs);
64             updateContextWithChecksumValidationStatus(executionAttributes, algorithmChecksumPair);
65 
66             if (algorithmChecksumPair != null && context.responseBody().isPresent()) {
67                 return Optional.of(new ChecksumValidatingInputStream(
68                     context.responseBody().get(), SdkChecksum.forAlgorithm(algorithmChecksumPair.left()),
69                     algorithmChecksumPair.right()));
70             }
71         }
72         return context.responseBody();
73     }
74 
75     @Override
modifyAsyncHttpResponseContent(Context.ModifyHttpResponse context, ExecutionAttributes executionAttributes)76     public Optional<Publisher<ByteBuffer>> modifyAsyncHttpResponseContent(Context.ModifyHttpResponse context,
77                                                                           ExecutionAttributes executionAttributes) {
78         ChecksumSpecs resolvedChecksumSpecs = HttpChecksumResolver.getResolvedChecksumSpecs(executionAttributes);
79         if (resolvedChecksumSpecs != null &&
80             isFlexibleChecksumValidationForResponse(executionAttributes, resolvedChecksumSpecs, ASYNC)) {
81             Pair<Algorithm, String> algorithmChecksumPair = getAlgorithmChecksumValuePair(context.httpResponse(),
82                                                                                           resolvedChecksumSpecs);
83             updateContextWithChecksumValidationStatus(executionAttributes, algorithmChecksumPair);
84             if (algorithmChecksumPair != null && context.responsePublisher().isPresent()) {
85                 return Optional.of(new ChecksumValidatingPublisher(context.responsePublisher().get(),
86                                                                    SdkChecksum.forAlgorithm(algorithmChecksumPair.left()),
87                                                                    algorithmChecksumPair.right()));
88             }
89         }
90         return context.responsePublisher();
91     }
92 
updateContextWithChecksumValidationStatus(ExecutionAttributes executionAttributes, Pair<Algorithm, String> algorithmChecksumPair)93     private void updateContextWithChecksumValidationStatus(ExecutionAttributes executionAttributes,
94                                                            Pair<Algorithm, String> algorithmChecksumPair) {
95         if (algorithmChecksumPair == null || algorithmChecksumPair.left() == null) {
96             executionAttributes.putAttribute(SdkExecutionAttribute.HTTP_RESPONSE_CHECKSUM_VALIDATION,
97                                              ChecksumValidation.CHECKSUM_ALGORITHM_NOT_FOUND);
98         } else {
99             executionAttributes.putAttribute(SdkExecutionAttribute.HTTP_RESPONSE_CHECKSUM_VALIDATION,
100                                              ChecksumValidation.VALIDATED);
101             executionAttributes.putAttribute(SdkExecutionAttribute.HTTP_CHECKSUM_VALIDATION_ALGORITHM,
102                                              algorithmChecksumPair.left());
103         }
104     }
105 
isFlexibleChecksumValidationForResponse(ExecutionAttributes executionAttributes, ChecksumSpecs checksumSpecs, ClientType clientType)106     private boolean isFlexibleChecksumValidationForResponse(ExecutionAttributes executionAttributes,
107                                                             ChecksumSpecs checksumSpecs,
108                                                             ClientType clientType) {
109 
110         return HttpChecksumUtils.isHttpChecksumValidationEnabled(checksumSpecs) &&
111                executionAttributes.getAttribute(SdkExecutionAttribute.CLIENT_TYPE).equals(clientType) &&
112                !IS_FORCE_SKIPPED_VALIDATION.test(executionAttributes);
113     }
114 }