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