1 /*
2  * Copyright (c) 2016. 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.http.AmazonHttpClient;
18 import com.amazonaws.http.IdleConnectionReaper;
19 import com.amazonaws.http.apache.SdkProxyRoutePlanner;
20 import com.amazonaws.http.apache.utils.ApacheUtils;
21 import com.amazonaws.http.client.ConnectionManagerFactory;
22 import com.amazonaws.http.client.HttpClientFactory;
23 import com.amazonaws.http.conn.ClientConnectionManagerFactory;
24 import com.amazonaws.http.conn.SdkConnectionKeepAliveStrategy;
25 import com.amazonaws.http.protocol.SdkHttpRequestExecutor;
26 import com.amazonaws.http.settings.HttpClientSettings;
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29 import org.apache.http.HttpResponseInterceptor;
30 import org.apache.http.conn.ConnectionKeepAliveStrategy;
31 import org.apache.http.conn.HttpClientConnectionManager;
32 import org.apache.http.impl.client.HttpClientBuilder;
33 import org.apache.http.impl.client.HttpClients;
34
35 /**
36  * Factory class that builds the apache http client from the settings.
37  */

38 public class ApacheHttpClientFactory implements HttpClientFactory<ConnectionManagerAwareHttpClient> {
39
40     private static final Log LOG = LogFactory.getLog(AmazonHttpClient.class);
41     private final ConnectionManagerFactory<HttpClientConnectionManager>
42             cmFactory = new ApacheConnectionManagerFactory();
43
44     @Override
45     public ConnectionManagerAwareHttpClient create(HttpClientSettings settings) {
46         final HttpClientBuilder builder = HttpClients.custom();
47         // Note that it is important we register the original connection manager with the
48         // IdleConnectionReaper as it's required for the successful deregistration of managers
49         // from the reaper. See https://github.com/aws/aws-sdk-java/issues/722.
50         final HttpClientConnectionManager cm = cmFactory.create(settings);
51
52         builder.setRequestExecutor(new SdkHttpRequestExecutor())
53                 .setKeepAliveStrategy(buildKeepAliveStrategy(settings))
54                 .disableRedirectHandling()
55                 .disableAutomaticRetries()
56                 .setConnectionManager(ClientConnectionManagerFactory.wrap(cm));
57
58         // By default http client enables Gzip compression. So we disable it
59         // here.
60         // Apache HTTP client removes Content-Length, Content-Encoding and
61         // Content-MD5 headers when Gzip compression is enabled. Currently
62         // this doesn't affect S3 or Glacier which exposes these headers.
63         //
64         if (!(settings.useGzip())) {
65             builder.disableContentCompression();
66         }
67
68         HttpResponseInterceptor itcp = new CRC32ChecksumResponseInterceptor();
69         if (settings.calculateCRC32FromCompressedData()) {
70             builder.addInterceptorFirst(itcp);
71         } else {
72             builder.addInterceptorLast(itcp);
73         }
74
75         addProxyConfig(builder, settings);
76
77         final ConnectionManagerAwareHttpClient httpClient = new SdkHttpClient(builder.build(), cm);
78
79         if (settings.useReaper()) {
80             IdleConnectionReaper.registerConnectionManager(cm, settings.getMaxIdleConnectionTime());
81         }
82
83         return httpClient;
84     }
85
86     private void addProxyConfig(HttpClientBuilder builder,
87                                 HttpClientSettings settings) {
88         if (settings.isProxyEnabled()) {
89
90             LOG.info("Configuring Proxy. Proxy Host: " + settings.getProxyHost() + " " +
91                     "Proxy Port: " + settings.getProxyPort());
92
93             builder.setRoutePlanner(new SdkProxyRoutePlanner(
94                     settings.getProxyHost(), settings.getProxyPort(), settings.getProxyProtocol(), settings.getNonProxyHosts()));
95
96             if (settings.isAuthenticatedProxy()) {
97                 builder.setDefaultCredentialsProvider(ApacheUtils.newProxyCredentialsProvider(settings));
98             }
99         }
100     }
101
102     private ConnectionKeepAliveStrategy buildKeepAliveStrategy(HttpClientSettings settings) {
103         return settings.getMaxIdleConnectionTime() > 0
104                 ? new SdkConnectionKeepAliveStrategy(settings.getMaxIdleConnectionTime())
105                 : null;
106     }
107 }