001/*
002 * ====================================================================
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *   http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied.  See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 * ====================================================================
020 *
021 * This software consists of voluntary contributions made by many
022 * individuals on behalf of the Apache Software Foundation.  For more
023 * information on the Apache Software Foundation, please see
024 * <http://www.apache.org/>.
025 *
026 */
027
028package org.apache.http.impl.client;
029
030import java.io.Closeable;
031import java.io.IOException;
032import java.net.ProxySelector;
033import java.util.ArrayList;
034import java.util.Collection;
035import java.util.Collections;
036import java.util.LinkedList;
037import java.util.List;
038import java.util.Map;
039import java.util.concurrent.TimeUnit;
040
041import javax.net.ssl.HostnameVerifier;
042import javax.net.ssl.SSLContext;
043import javax.net.ssl.SSLSocketFactory;
044
045import org.apache.http.ConnectionReuseStrategy;
046import org.apache.http.Header;
047import org.apache.http.HttpHost;
048import org.apache.http.HttpRequestInterceptor;
049import org.apache.http.HttpResponseInterceptor;
050import org.apache.http.auth.AuthSchemeProvider;
051import org.apache.http.client.AuthenticationStrategy;
052import org.apache.http.client.BackoffManager;
053import org.apache.http.client.ConnectionBackoffStrategy;
054import org.apache.http.client.CookieStore;
055import org.apache.http.client.CredentialsProvider;
056import org.apache.http.client.HttpRequestRetryHandler;
057import org.apache.http.client.RedirectStrategy;
058import org.apache.http.client.ServiceUnavailableRetryStrategy;
059import org.apache.http.client.UserTokenHandler;
060import org.apache.http.client.config.AuthSchemes;
061import org.apache.http.client.config.RequestConfig;
062import org.apache.http.client.entity.InputStreamFactory;
063import org.apache.http.client.protocol.RequestAcceptEncoding;
064import org.apache.http.client.protocol.RequestAddCookies;
065import org.apache.http.client.protocol.RequestAuthCache;
066import org.apache.http.client.protocol.RequestClientConnControl;
067import org.apache.http.client.protocol.RequestDefaultHeaders;
068import org.apache.http.client.protocol.RequestExpectContinue;
069import org.apache.http.client.protocol.ResponseContentEncoding;
070import org.apache.http.client.protocol.ResponseProcessCookies;
071import org.apache.http.config.ConnectionConfig;
072import org.apache.http.config.Lookup;
073import org.apache.http.config.RegistryBuilder;
074import org.apache.http.config.SocketConfig;
075import org.apache.http.conn.ConnectionKeepAliveStrategy;
076import org.apache.http.conn.DnsResolver;
077import org.apache.http.conn.HttpClientConnectionManager;
078import org.apache.http.conn.SchemePortResolver;
079import org.apache.http.conn.routing.HttpRoutePlanner;
080import org.apache.http.conn.socket.ConnectionSocketFactory;
081import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
082import org.apache.http.conn.socket.PlainConnectionSocketFactory;
083import org.apache.http.conn.ssl.DefaultHostnameVerifier;
084import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
085import org.apache.http.conn.ssl.X509HostnameVerifier;
086import org.apache.http.conn.util.PublicSuffixMatcher;
087import org.apache.http.conn.util.PublicSuffixMatcherLoader;
088import org.apache.http.cookie.CookieSpecProvider;
089import org.apache.http.impl.NoConnectionReuseStrategy;
090import org.apache.http.impl.auth.BasicSchemeFactory;
091import org.apache.http.impl.auth.DigestSchemeFactory;
092import org.apache.http.impl.auth.KerberosSchemeFactory;
093import org.apache.http.impl.auth.NTLMSchemeFactory;
094import org.apache.http.impl.auth.SPNegoSchemeFactory;
095import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
096import org.apache.http.impl.conn.DefaultRoutePlanner;
097import org.apache.http.impl.conn.DefaultSchemePortResolver;
098import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
099import org.apache.http.impl.conn.SystemDefaultRoutePlanner;
100import org.apache.http.impl.execchain.BackoffStrategyExec;
101import org.apache.http.impl.execchain.ClientExecChain;
102import org.apache.http.impl.execchain.MainClientExec;
103import org.apache.http.impl.execchain.ProtocolExec;
104import org.apache.http.impl.execchain.RedirectExec;
105import org.apache.http.impl.execchain.RetryExec;
106import org.apache.http.impl.execchain.ServiceUnavailableRetryExec;
107import org.apache.http.protocol.HttpProcessor;
108import org.apache.http.protocol.HttpProcessorBuilder;
109import org.apache.http.protocol.HttpRequestExecutor;
110import org.apache.http.protocol.ImmutableHttpProcessor;
111import org.apache.http.protocol.RequestContent;
112import org.apache.http.protocol.RequestTargetHost;
113import org.apache.http.protocol.RequestUserAgent;
114import org.apache.http.ssl.SSLContexts;
115import org.apache.http.util.TextUtils;
116import 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 */
155public 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}