View Javadoc

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