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