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