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