1 /*
2  * Copyright 2016-2020 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 package com.amazonaws.http.apache.client.impl;
16
17 import com.amazonaws.util.CRC32ChecksumCalculatingInputStream;
18 import com.amazonaws.util.IOUtils;
19
20 import org.apache.http.Header;
21 import org.apache.http.HttpEntity;
22 import org.apache.http.HttpException;
23 import org.apache.http.HttpResponse;
24 import org.apache.http.HttpResponseInterceptor;
25 import org.apache.http.entity.HttpEntityWrapper;
26 import org.apache.http.protocol.HttpContext;
27
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.io.OutputStream;
31
32 public class CRC32ChecksumResponseInterceptor implements HttpResponseInterceptor {
33
34     @Override
35     public void process(HttpResponse response, final HttpContext context)
36             throws HttpException, IOException {
37         final HttpEntity entity = response.getEntity();
38
39         // Only Json protocol has this header, we only wrap CRC32ChecksumCalculatingInputStream in json protocol clients.
40         Header[] headers = response.getHeaders("x-amz-crc32");
41         if (entity == null || headers == null || headers.length == 0) {
42             return;
43         }
44         HttpEntity crc32ResponseEntity = new HttpEntityWrapper(entity) {
45
46             private final InputStream content = new CRC32ChecksumCalculatingInputStream(
47                     wrappedEntity.getContent());
48
49             @Override
50             public InputStream getContent() throws IOException {
51                 return content;
52             }
53
54             /**
55              * It's important to override writeTo. Some versions of Apache HTTP
56              * client use writeTo for {@link org.apache.http.entity.BufferedHttpEntity}
57              * and the default implementation just delegates to the wrapped entity
58              * which completely bypasses our CRC32 calculating input stream. The
59              * {@link org.apache.http.entity.BufferedHttpEntity} is used for the
60              * request timeout and client execution timeout features.
61              *
62              * @see <a href="https://github.com/aws/aws-sdk-java/issues/526">Issue #526</a>
63              *
64              * @param outstream OutputStream to write contents to
65              */

66             @Override
67             public void writeTo(OutputStream outstream) throws IOException {
68                 try {
69                     IOUtils.copy(this.getContent(), outstream);
70                 } finally {
71                     this.getContent().close();
72                 }
73             }
74         };
75
76         response.setEntity(crc32ResponseEntity);
77         context.setAttribute(CRC32ChecksumCalculatingInputStream.class.getName(),
78                              crc32ResponseEntity.getContent());
79     }
80
81 }
82