View Javadoc

1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.http.impl.client;
29  
30  import java.io.Closeable;
31  import java.io.IOException;
32  import java.net.ProxySelector;
33  import java.util.ArrayList;
34  import java.util.Collection;
35  import java.util.Collections;
36  import java.util.LinkedList;
37  import java.util.List;
38  import java.util.Map;
39  import java.util.concurrent.TimeUnit;
40  
41  import javax.net.ssl.HostnameVerifier;
42  import javax.net.ssl.SSLContext;
43  import javax.net.ssl.SSLSocketFactory;
44  
45  import org.apache.http.ConnectionReuseStrategy;
46  import org.apache.http.Header;
47  import org.apache.http.HttpHost;
48  import org.apache.http.HttpRequestInterceptor;
49  import org.apache.http.HttpResponseInterceptor;
50  import org.apache.http.annotation.NotThreadSafe;
51  import org.apache.http.auth.AuthSchemeProvider;
52  import org.apache.http.client.AuthenticationStrategy;
53  import org.apache.http.client.BackoffManager;
54  import org.apache.http.client.ConnectionBackoffStrategy;
55  import org.apache.http.client.CookieStore;
56  import org.apache.http.client.CredentialsProvider;
57  import org.apache.http.client.HttpRequestRetryHandler;
58  import org.apache.http.client.RedirectStrategy;
59  import org.apache.http.client.ServiceUnavailableRetryStrategy;
60  import org.apache.http.client.UserTokenHandler;
61  import org.apache.http.client.config.AuthSchemes;
62  import org.apache.http.client.config.RequestConfig;
63  import org.apache.http.client.entity.InputStreamFactory;
64  import org.apache.http.client.protocol.RequestAcceptEncoding;
65  import org.apache.http.client.protocol.RequestAddCookies;
66  import org.apache.http.client.protocol.RequestAuthCache;
67  import org.apache.http.client.protocol.RequestClientConnControl;
68  import org.apache.http.client.protocol.RequestDefaultHeaders;
69  import org.apache.http.client.protocol.RequestExpectContinue;
70  import org.apache.http.client.protocol.ResponseContentEncoding;
71  import org.apache.http.client.protocol.ResponseProcessCookies;
72  import org.apache.http.config.ConnectionConfig;
73  import org.apache.http.config.Lookup;
74  import org.apache.http.config.RegistryBuilder;
75  import org.apache.http.config.SocketConfig;
76  import org.apache.http.conn.ConnectionKeepAliveStrategy;
77  import org.apache.http.conn.HttpClientConnectionManager;
78  import org.apache.http.conn.SchemePortResolver;
79  import org.apache.http.conn.routing.HttpRoutePlanner;
80  import org.apache.http.conn.socket.ConnectionSocketFactory;
81  import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
82  import org.apache.http.conn.socket.PlainConnectionSocketFactory;
83  import org.apache.http.conn.ssl.DefaultHostnameVerifier;
84  import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
85  import org.apache.http.conn.ssl.X509HostnameVerifier;
86  import org.apache.http.conn.util.PublicSuffixMatcher;
87  import org.apache.http.conn.util.PublicSuffixMatcherLoader;
88  import org.apache.http.cookie.CookieSpecProvider;
89  import org.apache.http.impl.DefaultConnectionReuseStrategy;
90  import org.apache.http.impl.NoConnectionReuseStrategy;
91  import org.apache.http.impl.auth.BasicSchemeFactory;
92  import org.apache.http.impl.auth.DigestSchemeFactory;
93  import org.apache.http.impl.auth.KerberosSchemeFactory;
94  import org.apache.http.impl.auth.NTLMSchemeFactory;
95  import org.apache.http.impl.auth.SPNegoSchemeFactory;
96  import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
97  import org.apache.http.impl.conn.DefaultRoutePlanner;
98  import org.apache.http.impl.conn.DefaultSchemePortResolver;
99  import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
100 import org.apache.http.impl.conn.SystemDefaultRoutePlanner;
101 import org.apache.http.impl.execchain.BackoffStrategyExec;
102 import org.apache.http.impl.execchain.ClientExecChain;
103 import org.apache.http.impl.execchain.MainClientExec;
104 import org.apache.http.impl.execchain.ProtocolExec;
105 import org.apache.http.impl.execchain.RedirectExec;
106 import org.apache.http.impl.execchain.RetryExec;
107 import org.apache.http.impl.execchain.ServiceUnavailableRetryExec;
108 import org.apache.http.protocol.HttpProcessor;
109 import org.apache.http.protocol.HttpProcessorBuilder;
110 import org.apache.http.protocol.HttpRequestExecutor;
111 import org.apache.http.protocol.ImmutableHttpProcessor;
112 import org.apache.http.protocol.RequestContent;
113 import org.apache.http.protocol.RequestTargetHost;
114 import org.apache.http.protocol.RequestUserAgent;
115 import org.apache.http.ssl.SSLContexts;
116 import org.apache.http.util.TextUtils;
117 import org.apache.http.util.VersionInfo;
118 
119 /**
120  * Builder for {@link CloseableHttpClient} instances.
121  * <p>
122  * When a particular component is not explicitly set this class will
123  * use its default implementation. System properties will be taken
124  * into account when configuring the default implementations when
125  * {@link #useSystemProperties()} method is called prior to calling
126  * {@link #build()}.
127  * </p>
128  * <ul>
129  *  <li>ssl.TrustManagerFactory.algorithm</li>
130  *  <li>javax.net.ssl.trustStoreType</li>
131  *  <li>javax.net.ssl.trustStore</li>
132  *  <li>javax.net.ssl.trustStoreProvider</li>
133  *  <li>javax.net.ssl.trustStorePassword</li>
134  *  <li>ssl.KeyManagerFactory.algorithm</li>
135  *  <li>javax.net.ssl.keyStoreType</li>
136  *  <li>javax.net.ssl.keyStore</li>
137  *  <li>javax.net.ssl.keyStoreProvider</li>
138  *  <li>javax.net.ssl.keyStorePassword</li>
139  *  <li>https.protocols</li>
140  *  <li>https.cipherSuites</li>
141  *  <li>http.proxyHost</li>
142  *  <li>http.proxyPort</li>
143  *  <li>http.nonProxyHosts</li>
144  *  <li>http.keepAlive</li>
145  *  <li>http.maxConnections</li>
146  *  <li>http.agent</li>
147  * </ul>
148  * <p>
149  * Please note that some settings used by this class can be mutually
150  * exclusive and may not apply when building {@link CloseableHttpClient}
151  * instances.
152  * </p>
153  *
154  * @since 4.3
155  */
156 @NotThreadSafe
157 public class HttpClientBuilder {
158 
159     private HttpRequestExecutor requestExec;
160     private HostnameVerifier hostnameVerifier;
161     private LayeredConnectionSocketFactory sslSocketFactory;
162     private SSLContext sslContext;
163     private HttpClientConnectionManager connManager;
164     private boolean connManagerShared;
165     private SchemePortResolver schemePortResolver;
166     private ConnectionReuseStrategy reuseStrategy;
167     private ConnectionKeepAliveStrategy keepAliveStrategy;
168     private AuthenticationStrategy targetAuthStrategy;
169     private AuthenticationStrategy proxyAuthStrategy;
170     private UserTokenHandler userTokenHandler;
171     private HttpProcessor httpprocessor;
172 
173     private LinkedList<HttpRequestInterceptor> requestFirst;
174     private LinkedList<HttpRequestInterceptor> requestLast;
175     private LinkedList<HttpResponseInterceptor> responseFirst;
176     private LinkedList<HttpResponseInterceptor> responseLast;
177 
178     private HttpRequestRetryHandler retryHandler;
179     private HttpRoutePlanner routePlanner;
180     private RedirectStrategy redirectStrategy;
181     private ConnectionBackoffStrategy connectionBackoffStrategy;
182     private BackoffManager backoffManager;
183     private ServiceUnavailableRetryStrategy serviceUnavailStrategy;
184     private Lookup<AuthSchemeProvider> authSchemeRegistry;
185     private Lookup<CookieSpecProvider> cookieSpecRegistry;
186     private Map<String, InputStreamFactory> contentDecoderMap;
187     private CookieStore cookieStore;
188     private CredentialsProvider credentialsProvider;
189     private String userAgent;
190     private HttpHost proxy;
191     private Collection<? extends Header> defaultHeaders;
192     private SocketConfig defaultSocketConfig;
193     private ConnectionConfig defaultConnectionConfig;
194     private RequestConfig defaultRequestConfig;
195     private boolean evictExpiredConnections;
196     private boolean evictIdleConnections;
197     private long maxIdleTime;
198     private TimeUnit maxIdleTimeUnit;
199 
200     private boolean systemProperties;
201     private boolean redirectHandlingDisabled;
202     private boolean automaticRetriesDisabled;
203     private boolean contentCompressionDisabled;
204     private boolean cookieManagementDisabled;
205     private boolean authCachingDisabled;
206     private boolean connectionStateDisabled;
207 
208     private int maxConnTotal = 0;
209     private int maxConnPerRoute = 0;
210 
211     private long connTimeToLive = -1;
212     private TimeUnit connTimeToLiveTimeUnit = TimeUnit.MILLISECONDS;
213 
214     private List<Closeable> closeables;
215 
216     private PublicSuffixMatcher publicSuffixMatcher;
217 
218     public static HttpClientBuilder create() {
219         return new HttpClientBuilder();
220     }
221 
222     protected HttpClientBuilder() {
223         super();
224     }
225 
226     /**
227      * Assigns {@link HttpRequestExecutor} instance.
228      */
229     public final HttpClientBuilder setRequestExecutor(final HttpRequestExecutor requestExec) {
230         this.requestExec = requestExec;
231         return this;
232     }
233 
234     /**
235      * Assigns {@link X509HostnameVerifier} instance.
236      * <p>
237      * Please note this value can be overridden by the {@link #setConnectionManager(
238      *   org.apache.http.conn.HttpClientConnectionManager)} and the {@link #setSSLSocketFactory(
239      *   org.apache.http.conn.socket.LayeredConnectionSocketFactory)} methods.
240      * </p>
241      *
242      *   @deprecated (4.4)
243      */
244     @Deprecated
245     public final HttpClientBuilder setHostnameVerifier(final X509HostnameVerifier hostnameVerifier) {
246         this.hostnameVerifier = hostnameVerifier;
247         return this;
248     }
249 
250     /**
251      * Assigns {@link javax.net.ssl.HostnameVerifier} instance.
252      * <p>
253      * Please note this value can be overridden by the {@link #setConnectionManager(
254      *   org.apache.http.conn.HttpClientConnectionManager)} and the {@link #setSSLSocketFactory(
255      *   org.apache.http.conn.socket.LayeredConnectionSocketFactory)} methods.
256      * </p>
257      *
258      *   @since 4.4
259      */
260     public final HttpClientBuilder setSSLHostnameVerifier(final HostnameVerifier hostnameVerifier) {
261         this.hostnameVerifier = hostnameVerifier;
262         return this;
263     }
264 
265     /**
266      * Assigns file containing public suffix matcher. Instances of this class can be created
267      * with {@link org.apache.http.conn.util.PublicSuffixMatcherLoader}.
268      *
269      * @see org.apache.http.conn.util.PublicSuffixMatcher
270      * @see org.apache.http.conn.util.PublicSuffixMatcherLoader
271      *
272      *   @since 4.4
273      */
274     public final HttpClientBuilder setPublicSuffixMatcher(final PublicSuffixMatcher publicSuffixMatcher) {
275         this.publicSuffixMatcher = publicSuffixMatcher;
276         return this;
277     }
278 
279     /**
280      * Assigns {@link SSLContext} instance.
281      * <p>
282      * Please note this value can be overridden by the {@link #setConnectionManager(
283      *   org.apache.http.conn.HttpClientConnectionManager)} and the {@link #setSSLSocketFactory(
284      *   org.apache.http.conn.socket.LayeredConnectionSocketFactory)} methods.
285      * </p>
286      *
287      * @deprecated (4.5) use {@link #setSSLContext(SSLContext)}
288      */
289     @Deprecated
290     public final HttpClientBuilder setSslcontext(final SSLContext sslcontext) {
291         return setSSLContext(sslcontext);
292     }
293 
294     /**
295      * Assigns {@link SSLContext} instance.
296      * <p>
297      * Please note this value can be overridden by the {@link #setConnectionManager(
298      *   org.apache.http.conn.HttpClientConnectionManager)} and the {@link #setSSLSocketFactory(
299      *   org.apache.http.conn.socket.LayeredConnectionSocketFactory)} methods.
300      * </p>
301      */
302     public final HttpClientBuilder setSSLContext(final SSLContext sslContext) {
303         this.sslContext = sslContext;
304         return this;
305     }
306 
307     /**
308      * Assigns {@link LayeredConnectionSocketFactory} instance.
309      * <p>
310      * Please note this value can be overridden by the {@link #setConnectionManager(
311      *   org.apache.http.conn.HttpClientConnectionManager)} method.
312      * </p>
313      */
314     public final HttpClientBuilder setSSLSocketFactory(
315             final LayeredConnectionSocketFactory sslSocketFactory) {
316         this.sslSocketFactory = sslSocketFactory;
317         return this;
318     }
319 
320     /**
321      * Assigns maximum total connection value.
322      * <p>
323      * Please note this value can be overridden by the {@link #setConnectionManager(
324      *   org.apache.http.conn.HttpClientConnectionManager)} method.
325      * </p>
326      */
327     public final HttpClientBuilder setMaxConnTotal(final int maxConnTotal) {
328         this.maxConnTotal = maxConnTotal;
329         return this;
330     }
331 
332     /**
333      * Assigns maximum connection per route value.
334      * <p>
335      * Please note this value can be overridden by the {@link #setConnectionManager(
336      *   org.apache.http.conn.HttpClientConnectionManager)} method.
337      * </p>
338      */
339     public final HttpClientBuilder setMaxConnPerRoute(final int maxConnPerRoute) {
340         this.maxConnPerRoute = maxConnPerRoute;
341         return this;
342     }
343 
344     /**
345      * Assigns default {@link SocketConfig}.
346      * <p>
347      * Please note this value can be overridden by the {@link #setConnectionManager(
348      *   org.apache.http.conn.HttpClientConnectionManager)} method.
349      * </p>
350      */
351     public final HttpClientBuilder setDefaultSocketConfig(final SocketConfig config) {
352         this.defaultSocketConfig = config;
353         return this;
354     }
355 
356     /**
357      * Assigns default {@link ConnectionConfig}.
358      * <p>
359      * Please note this value can be overridden by the {@link #setConnectionManager(
360      *   org.apache.http.conn.HttpClientConnectionManager)} method.
361      * </p>
362      */
363     public final HttpClientBuilder setDefaultConnectionConfig(final ConnectionConfig config) {
364         this.defaultConnectionConfig = config;
365         return this;
366     }
367 
368     /**
369      * Sets maximum time to live for persistent connections
370      * <p>
371      * Please note this value can be overridden by the {@link #setConnectionManager(
372      *   org.apache.http.conn.HttpClientConnectionManager)} method.
373      * </p>
374      *
375      * @since 4.4
376      */
377     public final HttpClientBuilder setConnectionTimeToLive(final long connTimeToLive, final TimeUnit connTimeToLiveTimeUnit) {
378         this.connTimeToLive = connTimeToLive;
379         this.connTimeToLiveTimeUnit = connTimeToLiveTimeUnit;
380         return this;
381     }
382 
383     /**
384      * Assigns {@link HttpClientConnectionManager} instance.
385      */
386     public final HttpClientBuilder setConnectionManager(
387             final HttpClientConnectionManager connManager) {
388         this.connManager = connManager;
389         return this;
390     }
391 
392     /**
393      * Defines the connection manager is to be shared by multiple
394      * client instances.
395      * <p>
396      * If the connection manager is shared its life-cycle is expected
397      * to be managed by the caller and it will not be shut down
398      * if the client is closed.
399      * </p>
400      *
401      * @param shared defines whether or not the connection manager can be shared
402      *  by multiple clients.
403      *
404      * @since 4.4
405      */
406     public final HttpClientBuilder setConnectionManagerShared(
407             final boolean shared) {
408         this.connManagerShared = shared;
409         return this;
410     }
411 
412     /**
413      * Assigns {@link ConnectionReuseStrategy} instance.
414      */
415     public final HttpClientBuilder setConnectionReuseStrategy(
416             final ConnectionReuseStrategy reuseStrategy) {
417         this.reuseStrategy = reuseStrategy;
418         return this;
419     }
420 
421     /**
422      * Assigns {@link ConnectionKeepAliveStrategy} instance.
423      */
424     public final HttpClientBuilder setKeepAliveStrategy(
425             final ConnectionKeepAliveStrategy keepAliveStrategy) {
426         this.keepAliveStrategy = keepAliveStrategy;
427         return this;
428     }
429 
430     /**
431      * Assigns {@link AuthenticationStrategy} instance for target
432      * host authentication.
433      */
434     public final HttpClientBuilder setTargetAuthenticationStrategy(
435             final AuthenticationStrategy targetAuthStrategy) {
436         this.targetAuthStrategy = targetAuthStrategy;
437         return this;
438     }
439 
440     /**
441      * Assigns {@link AuthenticationStrategy} instance for proxy
442      * authentication.
443      */
444     public final HttpClientBuilder setProxyAuthenticationStrategy(
445             final AuthenticationStrategy proxyAuthStrategy) {
446         this.proxyAuthStrategy = proxyAuthStrategy;
447         return this;
448     }
449 
450     /**
451      * Assigns {@link UserTokenHandler} instance.
452      * <p>
453      * Please note this value can be overridden by the {@link #disableConnectionState()}
454      * method.
455      * </p>
456      */
457     public final HttpClientBuilder setUserTokenHandler(final UserTokenHandler userTokenHandler) {
458         this.userTokenHandler = userTokenHandler;
459         return this;
460     }
461 
462     /**
463      * Disables connection state tracking.
464      */
465     public final HttpClientBuilder disableConnectionState() {
466         connectionStateDisabled = true;
467         return this;
468     }
469 
470     /**
471      * Assigns {@link SchemePortResolver} instance.
472      */
473     public final HttpClientBuilder setSchemePortResolver(
474             final SchemePortResolver schemePortResolver) {
475         this.schemePortResolver = schemePortResolver;
476         return this;
477     }
478 
479     /**
480      * Assigns {@code User-Agent} value.
481      * <p>
482      * Please note this value can be overridden by the {@link #setHttpProcessor(
483      * org.apache.http.protocol.HttpProcessor)} method.
484      * </p>
485      */
486     public final HttpClientBuilder setUserAgent(final String userAgent) {
487         this.userAgent = userAgent;
488         return this;
489     }
490 
491     /**
492      * Assigns default request header values.
493      * <p>
494      * Please note this value can be overridden by the {@link #setHttpProcessor(
495      * org.apache.http.protocol.HttpProcessor)} method.
496      * </p>
497      */
498     public final HttpClientBuilder setDefaultHeaders(final Collection<? extends Header> defaultHeaders) {
499         this.defaultHeaders = defaultHeaders;
500         return this;
501     }
502 
503     /**
504      * Adds this protocol interceptor to the head of the protocol processing list.
505      * <p>
506      * Please note this value can be overridden by the {@link #setHttpProcessor(
507      * org.apache.http.protocol.HttpProcessor)} method.
508      * </p>
509      */
510     public final HttpClientBuilder addInterceptorFirst(final HttpResponseInterceptor itcp) {
511         if (itcp == null) {
512             return this;
513         }
514         if (responseFirst == null) {
515             responseFirst = new LinkedList<HttpResponseInterceptor>();
516         }
517         responseFirst.addFirst(itcp);
518         return this;
519     }
520 
521     /**
522      * Adds this protocol interceptor to the tail of the protocol processing list.
523      * <p>
524      * Please note this value can be overridden by the {@link #setHttpProcessor(
525      * org.apache.http.protocol.HttpProcessor)} method.
526      * </p>
527      */
528     public final HttpClientBuilder addInterceptorLast(final HttpResponseInterceptor itcp) {
529         if (itcp == null) {
530             return this;
531         }
532         if (responseLast == null) {
533             responseLast = new LinkedList<HttpResponseInterceptor>();
534         }
535         responseLast.addLast(itcp);
536         return this;
537     }
538 
539     /**
540      * Adds this protocol interceptor to the head of the protocol processing list.
541      * <p>
542      * Please note this value can be overridden by the {@link #setHttpProcessor(
543      * org.apache.http.protocol.HttpProcessor)} method.
544      */
545     public final HttpClientBuilder addInterceptorFirst(final HttpRequestInterceptor itcp) {
546         if (itcp == null) {
547             return this;
548         }
549         if (requestFirst == null) {
550             requestFirst = new LinkedList<HttpRequestInterceptor>();
551         }
552         requestFirst.addFirst(itcp);
553         return this;
554     }
555 
556     /**
557      * Adds this protocol interceptor to the tail of the protocol processing list.
558      * <p>
559      * Please note this value can be overridden by the {@link #setHttpProcessor(
560      * org.apache.http.protocol.HttpProcessor)} method.
561      */
562     public final HttpClientBuilder addInterceptorLast(final HttpRequestInterceptor itcp) {
563         if (itcp == null) {
564             return this;
565         }
566         if (requestLast == null) {
567             requestLast = new LinkedList<HttpRequestInterceptor>();
568         }
569         requestLast.addLast(itcp);
570         return this;
571     }
572 
573     /**
574      * Disables state (cookie) management.
575      * <p>
576      * Please note this value can be overridden by the {@link #setHttpProcessor(
577      * org.apache.http.protocol.HttpProcessor)} method.
578      */
579     public final HttpClientBuilder disableCookieManagement() {
580         this.cookieManagementDisabled = true;
581         return this;
582     }
583 
584     /**
585      * Disables automatic content decompression.
586      * <p>
587      * Please note this value can be overridden by the {@link #setHttpProcessor(
588      * org.apache.http.protocol.HttpProcessor)} method.
589      */
590     public final HttpClientBuilder disableContentCompression() {
591         contentCompressionDisabled = true;
592         return this;
593     }
594 
595     /**
596      * Disables authentication scheme caching.
597      * <p>
598      * Please note this value can be overridden by the {@link #setHttpProcessor(
599      * org.apache.http.protocol.HttpProcessor)} method.
600      */
601     public final HttpClientBuilder disableAuthCaching() {
602         this.authCachingDisabled = true;
603         return this;
604     }
605 
606     /**
607      * Assigns {@link HttpProcessor} instance.
608      */
609     public final HttpClientBuilder setHttpProcessor(final HttpProcessor httpprocessor) {
610         this.httpprocessor = httpprocessor;
611         return this;
612     }
613 
614     /**
615      * Assigns {@link HttpRequestRetryHandler} instance.
616      * <p>
617      * Please note this value can be overridden by the {@link #disableAutomaticRetries()}
618      * method.
619      */
620     public final HttpClientBuilder setRetryHandler(final HttpRequestRetryHandler retryHandler) {
621         this.retryHandler = retryHandler;
622         return this;
623     }
624 
625     /**
626      * Disables automatic request recovery and re-execution.
627      */
628     public final HttpClientBuilder disableAutomaticRetries() {
629         automaticRetriesDisabled = true;
630         return this;
631     }
632 
633     /**
634      * Assigns default proxy value.
635      * <p>
636      * Please note this value can be overridden by the {@link #setRoutePlanner(
637      *   org.apache.http.conn.routing.HttpRoutePlanner)} method.
638      */
639     public final HttpClientBuilder setProxy(final HttpHost proxy) {
640         this.proxy = proxy;
641         return this;
642     }
643 
644     /**
645      * Assigns {@link HttpRoutePlanner} instance.
646      */
647     public final HttpClientBuilder setRoutePlanner(final HttpRoutePlanner routePlanner) {
648         this.routePlanner = routePlanner;
649         return this;
650     }
651 
652     /**
653      * Assigns {@link RedirectStrategy} instance.
654      * <p>
655      * Please note this value can be overridden by the {@link #disableRedirectHandling()}
656      * method.
657      * </p>
658 `     */
659     public final HttpClientBuilder setRedirectStrategy(final RedirectStrategy redirectStrategy) {
660         this.redirectStrategy = redirectStrategy;
661         return this;
662     }
663 
664     /**
665      * Disables automatic redirect handling.
666      */
667     public final HttpClientBuilder disableRedirectHandling() {
668         redirectHandlingDisabled = true;
669         return this;
670     }
671 
672     /**
673      * Assigns {@link ConnectionBackoffStrategy} instance.
674      */
675     public final HttpClientBuilder setConnectionBackoffStrategy(
676             final ConnectionBackoffStrategy connectionBackoffStrategy) {
677         this.connectionBackoffStrategy = connectionBackoffStrategy;
678         return this;
679     }
680 
681     /**
682      * Assigns {@link BackoffManager} instance.
683      */
684     public final HttpClientBuilder setBackoffManager(final BackoffManager backoffManager) {
685         this.backoffManager = backoffManager;
686         return this;
687     }
688 
689     /**
690      * Assigns {@link ServiceUnavailableRetryStrategy} instance.
691      */
692     public final HttpClientBuilder setServiceUnavailableRetryStrategy(
693             final ServiceUnavailableRetryStrategy serviceUnavailStrategy) {
694         this.serviceUnavailStrategy = serviceUnavailStrategy;
695         return this;
696     }
697 
698     /**
699      * Assigns default {@link CookieStore} instance which will be used for
700      * request execution if not explicitly set in the client execution context.
701      */
702     public final HttpClientBuilder setDefaultCookieStore(final CookieStore cookieStore) {
703         this.cookieStore = cookieStore;
704         return this;
705     }
706 
707     /**
708      * Assigns default {@link CredentialsProvider} instance which will be used
709      * for request execution if not explicitly set in the client execution
710      * context.
711      */
712     public final HttpClientBuilder setDefaultCredentialsProvider(
713             final CredentialsProvider credentialsProvider) {
714         this.credentialsProvider = credentialsProvider;
715         return this;
716     }
717 
718     /**
719      * Assigns default {@link org.apache.http.auth.AuthScheme} registry which will
720      * be used for request execution if not explicitly set in the client execution
721      * context.
722      */
723     public final HttpClientBuilder setDefaultAuthSchemeRegistry(
724             final Lookup<AuthSchemeProvider> authSchemeRegistry) {
725         this.authSchemeRegistry = authSchemeRegistry;
726         return this;
727     }
728 
729     /**
730      * Assigns default {@link org.apache.http.cookie.CookieSpec} registry which will
731      * be used for request execution if not explicitly set in the client execution
732      * context.
733      *
734      * @see org.apache.http.impl.client.CookieSpecRegistries
735      *
736      */
737     public final HttpClientBuilder setDefaultCookieSpecRegistry(
738             final Lookup<CookieSpecProvider> cookieSpecRegistry) {
739         this.cookieSpecRegistry = cookieSpecRegistry;
740         return this;
741     }
742 
743 
744     /**
745      * Assigns a map of {@link org.apache.http.client.entity.InputStreamFactory}s
746      * to be used for automatic content decompression.
747      */
748     public final HttpClientBuilder setContentDecoderRegistry(
749             final Map<String, InputStreamFactory> contentDecoderMap) {
750         this.contentDecoderMap = contentDecoderMap;
751         return this;
752     }
753 
754     /**
755      * Assigns default {@link RequestConfig} instance which will be used
756      * for request execution if not explicitly set in the client execution
757      * context.
758      */
759     public final HttpClientBuilder setDefaultRequestConfig(final RequestConfig config) {
760         this.defaultRequestConfig = config;
761         return this;
762     }
763 
764     /**
765      * Use system properties when creating and configuring default
766      * implementations.
767      */
768     public final HttpClientBuilder useSystemProperties() {
769         this.systemProperties = true;
770         return this;
771     }
772 
773     /**
774      * Makes this instance of HttpClient proactively evict expired connections from the
775      * connection pool using a background thread.
776      * <p>
777      * One MUST explicitly close HttpClient with {@link CloseableHttpClient#close()} in order
778      * to stop and release the background thread.
779      * <p>
780      * Please note this method has no effect if the instance of HttpClient is configuted to
781      * use a shared connection manager.
782      * <p>
783      * Please note this method may not be used when the instance of HttpClient is created
784      * inside an EJB container.
785      *
786      * @see #setConnectionManagerShared(boolean)
787      * @see org.apache.http.conn.HttpClientConnectionManager#closeExpiredConnections()
788      *
789      * @since 4.4
790      */
791     public final HttpClientBuilder evictExpiredConnections() {
792         evictExpiredConnections = true;
793         return this;
794     }
795 
796     /**
797      * Makes this instance of HttpClient proactively evict idle connections from the
798      * connection pool using a background thread.
799      * <p>
800      * One MUST explicitly close HttpClient with {@link CloseableHttpClient#close()} in order
801      * to stop and release the background thread.
802      * <p>
803      * Please note this method has no effect if the instance of HttpClient is configuted to
804      * use a shared connection manager.
805      * <p>
806      * Please note this method may not be used when the instance of HttpClient is created
807      * inside an EJB container.
808      *
809      * @see #setConnectionManagerShared(boolean)
810      * @see org.apache.http.conn.HttpClientConnectionManager#closeExpiredConnections()
811      *
812      * @param maxIdleTime maximum time persistent connections can stay idle while kept alive
813      * in the connection pool. Connections whose inactivity period exceeds this value will
814      * get closed and evicted from the pool.
815      * @param maxIdleTimeUnit time unit for the above parameter.
816      *
817      * @deprecated (4.5) use {@link #evictIdleConnections(long, TimeUnit)}
818      *
819      * @since 4.4
820      */
821     @Deprecated
822     public final HttpClientBuilder evictIdleConnections(final Long maxIdleTime, final TimeUnit maxIdleTimeUnit) {
823         return evictIdleConnections(maxIdleTime.longValue(), maxIdleTimeUnit);
824     }
825 
826     /**
827      * Makes this instance of HttpClient proactively evict idle connections from the
828      * connection pool using a background thread.
829      * <p>
830      * One MUST explicitly close HttpClient with {@link CloseableHttpClient#close()} in order
831      * to stop and release the background thread.
832      * <p>
833      * Please note this method has no effect if the instance of HttpClient is configuted to
834      * use a shared connection manager.
835      * <p>
836      * Please note this method may not be used when the instance of HttpClient is created
837      * inside an EJB container.
838      *
839      * @see #setConnectionManagerShared(boolean)
840      * @see org.apache.http.conn.HttpClientConnectionManager#closeExpiredConnections()
841      *
842      * @param maxIdleTime maximum time persistent connections can stay idle while kept alive
843      * in the connection pool. Connections whose inactivity period exceeds this value will
844      * get closed and evicted from the pool.
845      * @param maxIdleTimeUnit time unit for the above parameter.
846      *
847      * @since 4.4
848      */
849     public final HttpClientBuilder evictIdleConnections(final long maxIdleTime, final TimeUnit maxIdleTimeUnit) {
850         this.evictIdleConnections = true;
851         this.maxIdleTime = maxIdleTime;
852         this.maxIdleTimeUnit = maxIdleTimeUnit;
853         return this;
854     }
855 
856     /**
857      * Produces an instance of {@link ClientExecChain} to be used as a main exec.
858      * <p>
859      * Default implementation produces an instance of {@link MainClientExec}
860      * </p>
861      * <p>
862      * For internal use.
863      * </p>
864      *
865      * @since 4.4
866      */
867     protected ClientExecChain createMainExec(
868             final HttpRequestExecutor requestExec,
869             final HttpClientConnectionManager connManager,
870             final ConnectionReuseStrategy reuseStrategy,
871             final ConnectionKeepAliveStrategy keepAliveStrategy,
872             final HttpProcessor proxyHttpProcessor,
873             final AuthenticationStrategy targetAuthStrategy,
874             final AuthenticationStrategy proxyAuthStrategy,
875             final UserTokenHandler userTokenHandler)
876     {
877         return new MainClientExec(
878                 requestExec,
879                 connManager,
880                 reuseStrategy,
881                 keepAliveStrategy,
882                 proxyHttpProcessor,
883                 targetAuthStrategy,
884                 proxyAuthStrategy,
885                 userTokenHandler);
886     }
887 
888     /**
889      * For internal use.
890      */
891     protected ClientExecChain decorateMainExec(final ClientExecChain mainExec) {
892         return mainExec;
893     }
894 
895     /**
896      * For internal use.
897      */
898     protected ClientExecChain decorateProtocolExec(final ClientExecChain protocolExec) {
899         return protocolExec;
900     }
901 
902     /**
903      * For internal use.
904      */
905     protected void addCloseable(final Closeable closeable) {
906         if (closeable == null) {
907             return;
908         }
909         if (closeables == null) {
910             closeables = new ArrayList<Closeable>();
911         }
912         closeables.add(closeable);
913     }
914 
915     private static String[] split(final String s) {
916         if (TextUtils.isBlank(s)) {
917             return null;
918         }
919         return s.split(" *, *");
920     }
921 
922     public CloseableHttpClient build() {
923         // Create main request executor
924         // We copy the instance fields to avoid changing them, and rename to avoid accidental use of the wrong version
925         PublicSuffixMatcher publicSuffixMatcherCopy = this.publicSuffixMatcher;
926         if (publicSuffixMatcherCopy == null) {
927             publicSuffixMatcherCopy = PublicSuffixMatcherLoader.getDefault();
928         }
929 
930         HttpRequestExecutor requestExecCopy = this.requestExec;
931         if (requestExecCopy == null) {
932             requestExecCopy = new HttpRequestExecutor();
933         }
934         HttpClientConnectionManager connManagerCopy = this.connManager;
935         if (connManagerCopy == null) {
936             LayeredConnectionSocketFactory sslSocketFactoryCopy = this.sslSocketFactory;
937             if (sslSocketFactoryCopy == null) {
938                 final String[] supportedProtocols = systemProperties ? split(
939                         System.getProperty("https.protocols")) : null;
940                 final String[] supportedCipherSuites = systemProperties ? split(
941                         System.getProperty("https.cipherSuites")) : null;
942                 HostnameVerifier hostnameVerifierCopy = this.hostnameVerifier;
943                 if (hostnameVerifierCopy == null) {
944                     hostnameVerifierCopy = new DefaultHostnameVerifier(publicSuffixMatcherCopy);
945                 }
946                 if (sslContext != null) {
947                     sslSocketFactoryCopy = new SSLConnectionSocketFactory(
948                             sslContext, supportedProtocols, supportedCipherSuites, hostnameVerifierCopy);
949                 } else {
950                     if (systemProperties) {
951                         sslSocketFactoryCopy = new SSLConnectionSocketFactory(
952                                 (SSLSocketFactory) SSLSocketFactory.getDefault(),
953                                 supportedProtocols, supportedCipherSuites, hostnameVerifierCopy);
954                     } else {
955                         sslSocketFactoryCopy = new SSLConnectionSocketFactory(
956                                 SSLContexts.createDefault(),
957                                 hostnameVerifierCopy);
958                     }
959                 }
960             }
961             @SuppressWarnings("resource")
962             final PoolingHttpClientConnectionManager poolingmgr = new PoolingHttpClientConnectionManager(
963                     RegistryBuilder.<ConnectionSocketFactory>create()
964                         .register("http", PlainConnectionSocketFactory.getSocketFactory())
965                         .register("https", sslSocketFactoryCopy)
966                         .build(),
967                     null,
968                     null,
969                     null,
970                     connTimeToLive,
971                     connTimeToLiveTimeUnit != null ? connTimeToLiveTimeUnit : TimeUnit.MILLISECONDS);
972             if (defaultSocketConfig != null) {
973                 poolingmgr.setDefaultSocketConfig(defaultSocketConfig);
974             }
975             if (defaultConnectionConfig != null) {
976                 poolingmgr.setDefaultConnectionConfig(defaultConnectionConfig);
977             }
978             if (systemProperties) {
979                 String s = System.getProperty("http.keepAlive", "true");
980                 if ("true".equalsIgnoreCase(s)) {
981                     s = System.getProperty("http.maxConnections", "5");
982                     final int max = Integer.parseInt(s);
983                     poolingmgr.setDefaultMaxPerRoute(max);
984                     poolingmgr.setMaxTotal(2 * max);
985                 }
986             }
987             if (maxConnTotal > 0) {
988                 poolingmgr.setMaxTotal(maxConnTotal);
989             }
990             if (maxConnPerRoute > 0) {
991                 poolingmgr.setDefaultMaxPerRoute(maxConnPerRoute);
992             }
993             connManagerCopy = poolingmgr;
994         }
995         ConnectionReuseStrategy reuseStrategyCopy = this.reuseStrategy;
996         if (reuseStrategyCopy == null) {
997             if (systemProperties) {
998                 final String s = System.getProperty("http.keepAlive", "true");
999                 if ("true".equalsIgnoreCase(s)) {
1000                     reuseStrategyCopy = DefaultConnectionReuseStrategy.INSTANCE;
1001                 } else {
1002                     reuseStrategyCopy = NoConnectionReuseStrategy.INSTANCE;
1003                 }
1004             } else {
1005                 reuseStrategyCopy = DefaultConnectionReuseStrategy.INSTANCE;
1006             }
1007         }
1008         ConnectionKeepAliveStrategy keepAliveStrategyCopy = this.keepAliveStrategy;
1009         if (keepAliveStrategyCopy == null) {
1010             keepAliveStrategyCopy = DefaultConnectionKeepAliveStrategy.INSTANCE;
1011         }
1012         AuthenticationStrategy targetAuthStrategyCopy = this.targetAuthStrategy;
1013         if (targetAuthStrategyCopy == null) {
1014             targetAuthStrategyCopy = TargetAuthenticationStrategy.INSTANCE;
1015         }
1016         AuthenticationStrategy proxyAuthStrategyCopy = this.proxyAuthStrategy;
1017         if (proxyAuthStrategyCopy == null) {
1018             proxyAuthStrategyCopy = ProxyAuthenticationStrategy.INSTANCE;
1019         }
1020         UserTokenHandler userTokenHandlerCopy = this.userTokenHandler;
1021         if (userTokenHandlerCopy == null) {
1022             if (!connectionStateDisabled) {
1023                 userTokenHandlerCopy = DefaultUserTokenHandler.INSTANCE;
1024             } else {
1025                 userTokenHandlerCopy = NoopUserTokenHandler.INSTANCE;
1026             }
1027         }
1028 
1029         String userAgentCopy = this.userAgent;
1030         if (userAgentCopy == null) {
1031             if (systemProperties) {
1032                 userAgentCopy = System.getProperty("http.agent");
1033             }
1034             if (userAgentCopy == null) {
1035                 userAgentCopy = VersionInfo.getUserAgent("Apache-HttpClient",
1036                         "org.apache.http.client", getClass());
1037             }
1038         }
1039 
1040         ClientExecChain execChain = createMainExec(
1041                 requestExecCopy,
1042                 connManagerCopy,
1043                 reuseStrategyCopy,
1044                 keepAliveStrategyCopy,
1045                 new ImmutableHttpProcessor(new RequestTargetHost(), new RequestUserAgent(userAgentCopy)),
1046                 targetAuthStrategyCopy,
1047                 proxyAuthStrategyCopy,
1048                 userTokenHandlerCopy);
1049 
1050         execChain = decorateMainExec(execChain);
1051 
1052         HttpProcessor httpprocessorCopy = this.httpprocessor;
1053         if (httpprocessorCopy == null) {
1054 
1055             final HttpProcessorBuilder b = HttpProcessorBuilder.create();
1056             if (requestFirst != null) {
1057                 for (final HttpRequestInterceptor i: requestFirst) {
1058                     b.addFirst(i);
1059                 }
1060             }
1061             if (responseFirst != null) {
1062                 for (final HttpResponseInterceptor i: responseFirst) {
1063                     b.addFirst(i);
1064                 }
1065             }
1066             b.addAll(
1067                     new RequestDefaultHeaders(defaultHeaders),
1068                     new RequestContent(),
1069                     new RequestTargetHost(),
1070                     new RequestClientConnControl(),
1071                     new RequestUserAgent(userAgentCopy),
1072                     new RequestExpectContinue());
1073             if (!cookieManagementDisabled) {
1074                 b.add(new RequestAddCookies());
1075             }
1076             if (!contentCompressionDisabled) {
1077                 if (contentDecoderMap != null) {
1078                     final List<String> encodings = new ArrayList<String>(contentDecoderMap.keySet());
1079                     Collections.sort(encodings);
1080                     b.add(new RequestAcceptEncoding(encodings));
1081                 } else {
1082                     b.add(new RequestAcceptEncoding());
1083                 }
1084             }
1085             if (!authCachingDisabled) {
1086                 b.add(new RequestAuthCache());
1087             }
1088             if (!cookieManagementDisabled) {
1089                 b.add(new ResponseProcessCookies());
1090             }
1091             if (!contentCompressionDisabled) {
1092                 if (contentDecoderMap != null) {
1093                     final RegistryBuilder<InputStreamFactory> b2 = RegistryBuilder.create();
1094                     for (Map.Entry<String, InputStreamFactory> entry: contentDecoderMap.entrySet()) {
1095                         b2.register(entry.getKey(), entry.getValue());
1096                     }
1097                     b.add(new ResponseContentEncoding(b2.build()));
1098                 } else {
1099                     b.add(new ResponseContentEncoding());
1100                 }
1101             }
1102             if (requestLast != null) {
1103                 for (final HttpRequestInterceptor i: requestLast) {
1104                     b.addLast(i);
1105                 }
1106             }
1107             if (responseLast != null) {
1108                 for (final HttpResponseInterceptor i: responseLast) {
1109                     b.addLast(i);
1110                 }
1111             }
1112             httpprocessorCopy = b.build();
1113         }
1114         execChain = new ProtocolExec(execChain, httpprocessorCopy);
1115 
1116         execChain = decorateProtocolExec(execChain);
1117 
1118         // Add request retry executor, if not disabled
1119         if (!automaticRetriesDisabled) {
1120             HttpRequestRetryHandler retryHandlerCopy = this.retryHandler;
1121             if (retryHandlerCopy == null) {
1122                 retryHandlerCopy = DefaultHttpRequestRetryHandler.INSTANCE;
1123             }
1124             execChain = new RetryExec(execChain, retryHandlerCopy);
1125         }
1126 
1127         HttpRoutePlanner routePlannerCopy = this.routePlanner;
1128         if (routePlannerCopy == null) {
1129             SchemePortResolver schemePortResolverCopy = this.schemePortResolver;
1130             if (schemePortResolverCopy == null) {
1131                 schemePortResolverCopy = DefaultSchemePortResolver.INSTANCE;
1132             }
1133             if (proxy != null) {
1134                 routePlannerCopy = new DefaultProxyRoutePlanner(proxy, schemePortResolverCopy);
1135             } else if (systemProperties) {
1136                 routePlannerCopy = new SystemDefaultRoutePlanner(
1137                         schemePortResolverCopy, ProxySelector.getDefault());
1138             } else {
1139                 routePlannerCopy = new DefaultRoutePlanner(schemePortResolverCopy);
1140             }
1141         }
1142         // Add redirect executor, if not disabled
1143         if (!redirectHandlingDisabled) {
1144             RedirectStrategy redirectStrategyCopy = this.redirectStrategy;
1145             if (redirectStrategyCopy == null) {
1146                 redirectStrategyCopy = DefaultRedirectStrategy.INSTANCE;
1147             }
1148             execChain = new RedirectExec(execChain, routePlannerCopy, redirectStrategyCopy);
1149         }
1150 
1151         // Optionally, add service unavailable retry executor
1152         final ServiceUnavailableRetryStrategy serviceUnavailStrategyCopy = this.serviceUnavailStrategy;
1153         if (serviceUnavailStrategyCopy != null) {
1154             execChain = new ServiceUnavailableRetryExec(execChain, serviceUnavailStrategyCopy);
1155         }
1156         // Optionally, add connection back-off executor
1157         if (this.backoffManager != null && this.connectionBackoffStrategy != null) {
1158             execChain = new BackoffStrategyExec(execChain, this.connectionBackoffStrategy, this.backoffManager);
1159         }
1160 
1161         Lookup<AuthSchemeProvider> authSchemeRegistryCopy = this.authSchemeRegistry;
1162         if (authSchemeRegistryCopy == null) {
1163             authSchemeRegistryCopy = RegistryBuilder.<AuthSchemeProvider>create()
1164                 .register(AuthSchemes.BASIC, new BasicSchemeFactory())
1165                 .register(AuthSchemes.DIGEST, new DigestSchemeFactory())
1166                 .register(AuthSchemes.NTLM, new NTLMSchemeFactory())
1167                 .register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory())
1168                 .register(AuthSchemes.KERBEROS, new KerberosSchemeFactory())
1169                 .build();
1170         }
1171         Lookup<CookieSpecProvider> cookieSpecRegistryCopy = this.cookieSpecRegistry;
1172         if (cookieSpecRegistryCopy == null) {
1173             cookieSpecRegistryCopy = CookieSpecRegistries.createDefault(publicSuffixMatcherCopy);
1174         }
1175 
1176         CookieStore defaultCookieStore = this.cookieStore;
1177         if (defaultCookieStore == null) {
1178             defaultCookieStore = new BasicCookieStore();
1179         }
1180 
1181         CredentialsProvider defaultCredentialsProvider = this.credentialsProvider;
1182         if (defaultCredentialsProvider == null) {
1183             if (systemProperties) {
1184                 defaultCredentialsProvider = new SystemDefaultCredentialsProvider();
1185             } else {
1186                 defaultCredentialsProvider = new BasicCredentialsProvider();
1187             }
1188         }
1189 
1190         List<Closeable> closeablesCopy = closeables != null ? new ArrayList<Closeable>(closeables) : null;
1191         if (!this.connManagerShared) {
1192             if (closeablesCopy == null) {
1193                 closeablesCopy = new ArrayList<Closeable>(1);
1194             }
1195             final HttpClientConnectionManager cm = connManagerCopy;
1196 
1197             if (evictExpiredConnections || evictIdleConnections) {
1198                 final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor(cm,
1199                         maxIdleTime > 0 ? maxIdleTime : 10, maxIdleTimeUnit != null ? maxIdleTimeUnit : TimeUnit.SECONDS);
1200                 closeablesCopy.add(new Closeable() {
1201 
1202                     @Override
1203                     public void close() throws IOException {
1204                         connectionEvictor.shutdown();
1205                     }
1206 
1207                 });
1208                 connectionEvictor.start();
1209             }
1210             closeablesCopy.add(new Closeable() {
1211 
1212                 @Override
1213                 public void close() throws IOException {
1214                     cm.shutdown();
1215                 }
1216 
1217             });
1218         }
1219 
1220         return new InternalHttpClient(
1221                 execChain,
1222                 connManagerCopy,
1223                 routePlannerCopy,
1224                 cookieSpecRegistryCopy,
1225                 authSchemeRegistryCopy,
1226                 defaultCookieStore,
1227                 defaultCredentialsProvider,
1228                 defaultRequestConfig != null ? defaultRequestConfig : RequestConfig.DEFAULT,
1229                 closeablesCopy);
1230     }
1231 
1232 }