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