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.net.ProxySelector;
32  import java.util.ArrayList;
33  import java.util.Collection;
34  import java.util.LinkedList;
35  import java.util.List;
36  
37  import javax.net.ssl.SSLContext;
38  
39  import org.apache.http.ConnectionReuseStrategy;
40  import org.apache.http.Header;
41  import org.apache.http.HttpHost;
42  import org.apache.http.HttpRequestInterceptor;
43  import org.apache.http.HttpResponseInterceptor;
44  import org.apache.http.annotation.NotThreadSafe;
45  import org.apache.http.auth.AuthSchemeProvider;
46  import org.apache.http.client.AuthenticationStrategy;
47  import org.apache.http.client.BackoffManager;
48  import org.apache.http.client.ConnectionBackoffStrategy;
49  import org.apache.http.client.CookieStore;
50  import org.apache.http.client.CredentialsProvider;
51  import org.apache.http.client.HttpClient;
52  import org.apache.http.client.HttpRequestRetryHandler;
53  import org.apache.http.client.RedirectStrategy;
54  import org.apache.http.client.ServiceUnavailableRetryStrategy;
55  import org.apache.http.client.UserTokenHandler;
56  import org.apache.http.client.config.AuthSchemes;
57  import org.apache.http.client.config.CookieSpecs;
58  import org.apache.http.client.config.RequestConfig;
59  import org.apache.http.client.protocol.RequestAcceptEncoding;
60  import org.apache.http.client.protocol.RequestAddCookies;
61  import org.apache.http.client.protocol.RequestAuthCache;
62  import org.apache.http.client.protocol.RequestClientConnControl;
63  import org.apache.http.client.protocol.RequestDefaultHeaders;
64  import org.apache.http.client.protocol.RequestExpectContinue;
65  import org.apache.http.client.protocol.ResponseContentEncoding;
66  import org.apache.http.client.protocol.ResponseProcessCookies;
67  import org.apache.http.config.ConnectionConfig;
68  import org.apache.http.config.Lookup;
69  import org.apache.http.config.RegistryBuilder;
70  import org.apache.http.config.SocketConfig;
71  import org.apache.http.conn.ConnectionKeepAliveStrategy;
72  import org.apache.http.conn.HttpClientConnectionManager;
73  import org.apache.http.conn.SchemePortResolver;
74  import org.apache.http.conn.routing.HttpRoutePlanner;
75  import org.apache.http.conn.socket.ConnectionSocketFactory;
76  import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
77  import org.apache.http.conn.socket.PlainSocketFactory;
78  import org.apache.http.conn.ssl.SSLSocketFactory;
79  import org.apache.http.cookie.CookieSpecProvider;
80  import org.apache.http.impl.DefaultConnectionReuseStrategy;
81  import org.apache.http.impl.NoConnectionReuseStrategy;
82  import org.apache.http.impl.auth.BasicSchemeFactory;
83  import org.apache.http.impl.auth.DigestSchemeFactory;
84  import org.apache.http.impl.auth.KerberosSchemeFactory;
85  import org.apache.http.impl.auth.NTLMSchemeFactory;
86  import org.apache.http.impl.auth.SPNegoSchemeFactory;
87  import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
88  import org.apache.http.impl.conn.DefaultRoutePlanner;
89  import org.apache.http.impl.conn.DefaultSchemePortResolver;
90  import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
91  import org.apache.http.impl.conn.SystemDefaultRoutePlanner;
92  import org.apache.http.impl.cookie.BestMatchSpecFactory;
93  import org.apache.http.impl.cookie.BrowserCompatSpecFactory;
94  import org.apache.http.impl.cookie.IgnoreSpecFactory;
95  import org.apache.http.impl.cookie.NetscapeDraftSpecFactory;
96  import org.apache.http.impl.cookie.RFC2109SpecFactory;
97  import org.apache.http.impl.cookie.RFC2965SpecFactory;
98  import org.apache.http.impl.execchain.BackoffStrategyExec;
99  import org.apache.http.impl.execchain.ClientExecChain;
100 import org.apache.http.impl.execchain.MainClientExec;
101 import org.apache.http.impl.execchain.ProtocolExec;
102 import org.apache.http.impl.execchain.RedirectExec;
103 import org.apache.http.impl.execchain.RetryExec;
104 import org.apache.http.impl.execchain.ServiceUnavailableRetryExec;
105 import org.apache.http.protocol.HttpProcessor;
106 import org.apache.http.protocol.HttpProcessorBuilder;
107 import org.apache.http.protocol.HttpRequestExecutor;
108 import org.apache.http.protocol.RequestContent;
109 import org.apache.http.protocol.RequestTargetHost;
110 import org.apache.http.protocol.RequestUserAgent;
111 import org.apache.http.util.VersionInfo;
112 
113 /**
114  * {@link HttpClient} builder.
115  * <p>
116  * The following system properties are taken into account by this class
117  *  if the {@link #useSystemProperties()} method is called.
118  * <ul>
119  *  <li>ssl.TrustManagerFactory.algorithm</li>
120  *  <li>javax.net.ssl.trustStoreType</li>
121  *  <li>javax.net.ssl.trustStore</li>
122  *  <li>javax.net.ssl.trustStoreProvider</li>
123  *  <li>javax.net.ssl.trustStorePassword</li>
124  *  <li>java.home</li>
125  *  <li>ssl.KeyManagerFactory.algorithm</li>
126  *  <li>javax.net.ssl.keyStoreType</li>
127  *  <li>javax.net.ssl.keyStore</li>
128  *  <li>javax.net.ssl.keyStoreProvider</li>
129  *  <li>javax.net.ssl.keyStorePassword</li>
130  *  <li>http.proxyHost</li>
131  *  <li>http.proxyPort</li>
132  *  <li>http.nonProxyHosts</li>
133  *  <li>http.keepAlive</li>
134  *  <li>http.maxConnections</li>
135  *  <li>http.agent</li>
136  * </ul>
137  * </p>
138  *
139  * @since 4.3
140  */
141 @NotThreadSafe
142 public class HttpClientBuilder {
143 
144     private HttpRequestExecutor requestExec;
145     private LayeredConnectionSocketFactory sslSocketFactory;
146     private SSLContext sslcontext;
147     private HttpClientConnectionManager connManager;
148     private SchemePortResolver schemePortResolver;
149     private ConnectionReuseStrategy reuseStrategy;
150     private ConnectionKeepAliveStrategy keepAliveStrategy;
151     private AuthenticationStrategy targetAuthStrategy;
152     private AuthenticationStrategy proxyAuthStrategy;
153     private UserTokenHandler userTokenHandler;
154     private HttpProcessor httpprocessor;
155 
156     private LinkedList<HttpRequestInterceptor> requestFirst;
157     private LinkedList<HttpRequestInterceptor> requestLast;
158     private LinkedList<HttpResponseInterceptor> responseFirst;
159     private LinkedList<HttpResponseInterceptor> responseLast;
160 
161     private HttpRequestRetryHandler retryHandler;
162     private HttpRoutePlanner routePlanner;
163     private RedirectStrategy redirectStrategy;
164     private ConnectionBackoffStrategy connectionBackoffStrategy;
165     private BackoffManager backoffManager;
166     private ServiceUnavailableRetryStrategy serviceUnavailStrategy;
167     private Lookup<AuthSchemeProvider> authSchemeRegistry;
168     private Lookup<CookieSpecProvider> cookieSpecRegistry;
169     private CookieStore cookieStore;
170     private CredentialsProvider credentialsProvider;
171     private String userAgent;
172     private HttpHost proxy;
173     private Collection<? extends Header> defaultHeaders;
174     private SocketConfig defaultSocketConfig;
175     private ConnectionConfig defaultConnectionConfig;
176     private RequestConfig defaultRequestConfig;
177 
178     private boolean systemProperties;
179     private boolean redirectHandlingDisabled;
180     private boolean automaticRetriesDisabled;
181     private boolean contentCompressionDisabled;
182     private boolean cookieManagementDisabled;
183     private boolean authCachingDisabled;
184     private boolean connectionStateDisabled;
185 
186     private int maxConnTotal = 0;
187     private int maxConnPerRoute = 0;
188 
189     private List<Closeable> closeables;
190 
191     public static HttpClientBuilder create() {
192         return new HttpClientBuilder();
193     }
194 
195     protected HttpClientBuilder() {
196         super();
197     }
198 
199     public final HttpClientBuilder setRequestExecutor(final HttpRequestExecutor requestExec) {
200         this.requestExec = requestExec;
201         return this;
202     }
203 
204     public final HttpClientBuilder setSSLSocketFactory(
205             final LayeredConnectionSocketFactory sslSocketFactory) {
206         this.sslSocketFactory = sslSocketFactory;
207         return this;
208     }
209 
210     public final HttpClientBuilder setConnectionManager(
211             final HttpClientConnectionManager connManager) {
212         this.connManager = connManager;
213         return this;
214     }
215 
216     public final HttpClientBuilder setSchemePortResolver(
217             final SchemePortResolver schemePortResolver) {
218         this.schemePortResolver = schemePortResolver;
219         return this;
220     }
221 
222     public final HttpClientBuilder setMaxConnTotal(final int maxConnTotal) {
223         this.maxConnTotal = maxConnTotal;
224         return this;
225     }
226 
227     public final HttpClientBuilder setMaxConnPerRoute(final int maxConnPerRoute) {
228         this.maxConnPerRoute = maxConnPerRoute;
229         return this;
230     }
231 
232     public final HttpClientBuilder setConnectionReuseStrategy(
233             final ConnectionReuseStrategy reuseStrategy) {
234         this.reuseStrategy = reuseStrategy;
235         return this;
236     }
237 
238     public final HttpClientBuilder setKeepAliveStrategy(
239             final ConnectionKeepAliveStrategy keepAliveStrategy) {
240         this.keepAliveStrategy = keepAliveStrategy;
241         return this;
242     }
243 
244     public final HttpClientBuilder setUserTokenHandler(final UserTokenHandler userTokenHandler) {
245         this.userTokenHandler = userTokenHandler;
246         return this;
247     }
248 
249     public final HttpClientBuilder setTargetAuthenticationStrategy(
250             final AuthenticationStrategy targetAuthStrategy) {
251         this.targetAuthStrategy = targetAuthStrategy;
252         return this;
253     }
254 
255     public final HttpClientBuilder setProxyAuthenticationStrategy(
256             final AuthenticationStrategy proxyAuthStrategy) {
257         this.proxyAuthStrategy = proxyAuthStrategy;
258         return this;
259     }
260 
261     public final HttpClientBuilder setHttpProcessor(final HttpProcessor httpprocessor) {
262         this.httpprocessor = httpprocessor;
263         return this;
264     }
265 
266     public final HttpClientBuilder addInterceptorFirst(final HttpResponseInterceptor itcp) {
267         if (itcp == null) {
268             return this;
269         }
270         if (responseFirst == null) {
271             responseFirst = new LinkedList<HttpResponseInterceptor>();
272         }
273         responseFirst.addFirst(itcp);
274         return this;
275     }
276 
277     public final HttpClientBuilder addInterceptorLast(final HttpResponseInterceptor itcp) {
278         if (itcp == null) {
279             return this;
280         }
281         if (responseLast == null) {
282             responseLast = new LinkedList<HttpResponseInterceptor>();
283         }
284         responseLast.addLast(itcp);
285         return this;
286     }
287 
288     public final HttpClientBuilder addInterceptorFirst(final HttpRequestInterceptor itcp) {
289         if (itcp == null) {
290             return this;
291         }
292         if (requestFirst == null) {
293             requestFirst = new LinkedList<HttpRequestInterceptor>();
294         }
295         requestFirst.addFirst(itcp);
296         return this;
297     }
298 
299     public final HttpClientBuilder addInterceptorLast(final HttpRequestInterceptor itcp) {
300         if (itcp == null) {
301             return this;
302         }
303         if (requestLast == null) {
304             requestLast = new LinkedList<HttpRequestInterceptor>();
305         }
306         requestLast.addLast(itcp);
307         return this;
308     }
309 
310     public final HttpClientBuilder setRetryHandler(final HttpRequestRetryHandler retryHandler) {
311         this.retryHandler = retryHandler;
312         return this;
313     }
314 
315     public final HttpClientBuilder setRoutePlanner(final HttpRoutePlanner routePlanner) {
316         this.routePlanner = routePlanner;
317         return this;
318     }
319 
320     public final HttpClientBuilder setRedirectStrategy(final RedirectStrategy redirectStrategy) {
321         this.redirectStrategy = redirectStrategy;
322         return this;
323     }
324 
325     public final HttpClientBuilder setConnectionBackoffStrategy(
326             final ConnectionBackoffStrategy connectionBackoffStrategy) {
327         this.connectionBackoffStrategy = connectionBackoffStrategy;
328         return this;
329     }
330 
331     public final HttpClientBuilder setBackoffManager(final BackoffManager backoffManager) {
332         this.backoffManager = backoffManager;
333         return this;
334     }
335 
336     public final HttpClientBuilder setServiceUnavailableRetryStrategy(
337             final ServiceUnavailableRetryStrategy serviceUnavailStrategy) {
338         this.serviceUnavailStrategy = serviceUnavailStrategy;
339         return this;
340     }
341 
342     public final HttpClientBuilder setDefaultCookieStore(final CookieStore cookieStore) {
343         this.cookieStore = cookieStore;
344         return this;
345     }
346 
347     public final HttpClientBuilder setDefaultCredentialsProvider(
348             final CredentialsProvider credentialsProvider) {
349         this.credentialsProvider = credentialsProvider;
350         return this;
351     }
352 
353     public final HttpClientBuilder setDefaultAuthSchemeRegistry(
354             final Lookup<AuthSchemeProvider> authSchemeRegistry) {
355         this.authSchemeRegistry = authSchemeRegistry;
356         return this;
357     }
358 
359     public final HttpClientBuilder setDefaultCookieSpecRegistry(
360             final Lookup<CookieSpecProvider> cookieSpecRegistry) {
361         this.cookieSpecRegistry = cookieSpecRegistry;
362         return this;
363     }
364 
365     public final HttpClientBuilder setUserAgent(final String userAgent) {
366         this.userAgent = userAgent;
367         return this;
368     }
369 
370     public final HttpClientBuilder setProxy(final HttpHost proxy) {
371         this.proxy = proxy;
372         return this;
373     }
374 
375     public final HttpClientBuilder setDefaultHeaders(final Collection<? extends Header> defaultHeaders) {
376         this.defaultHeaders = defaultHeaders;
377         return this;
378     }
379 
380     public final HttpClientBuilder setDefaultSocketConfig(final SocketConfig config) {
381         this.defaultSocketConfig = config;
382         return this;
383     }
384 
385     public final HttpClientBuilder setDefaultConnectionConfig(final ConnectionConfig config) {
386         this.defaultConnectionConfig = config;
387         return this;
388     }
389 
390     public final HttpClientBuilder setDefaultRequestConfig(final RequestConfig config) {
391         this.defaultRequestConfig = config;
392         return this;
393     }
394 
395     public final HttpClientBuilder disableRedirectHandling() {
396         redirectHandlingDisabled = true;
397         return this;
398     }
399 
400     public final HttpClientBuilder disableAutomaticRetries() {
401         automaticRetriesDisabled = true;
402         return this;
403     }
404 
405     public final HttpClientBuilder disableConnectionState() {
406         connectionStateDisabled = true;
407         return this;
408     }
409 
410     public final HttpClientBuilder disableContentCompression() {
411         contentCompressionDisabled = true;
412         return this;
413     }
414 
415     public final HttpClientBuilder useSystemProperties() {
416         systemProperties = true;
417         return this;
418     }
419 
420     protected ClientExecChain decorateMainExec(final ClientExecChain mainExec) {
421         return mainExec;
422     }
423 
424     protected ClientExecChain decorateProtocolExec(final ClientExecChain protocolExec) {
425         return protocolExec;
426     }
427 
428     protected void addCloseable(final Closeable closeable) {
429         if (closeable == null) {
430             return;
431         }
432         if (closeables == null) {
433             closeables = new ArrayList<Closeable>();
434         }
435         closeables.add(closeable);
436     }
437 
438 
439     public CloseableHttpClient build() {
440         // Create main request executor
441         HttpRequestExecutor requestExec = this.requestExec;
442         if (requestExec == null) {
443             requestExec = new HttpRequestExecutor();
444         }
445         HttpClientConnectionManager connManager = this.connManager;
446         if (connManager == null) {
447             LayeredConnectionSocketFactory sslSocketFactory = this.sslSocketFactory;
448             if (sslSocketFactory == null) {
449                 if (sslcontext != null) {
450                     sslSocketFactory = new SSLSocketFactory(sslcontext);
451                 } else {
452                     if (systemProperties) {
453                         sslSocketFactory = SSLSocketFactory.getSystemSocketFactory();
454                     } else {
455                         sslSocketFactory = SSLSocketFactory.getSocketFactory();
456                     }
457                 }
458             }
459             final PoolingHttpClientConnectionManager poolingmgr = new PoolingHttpClientConnectionManager(
460                     RegistryBuilder.<ConnectionSocketFactory>create()
461                         .register("http", PlainSocketFactory.getSocketFactory())
462                         .register("https", sslSocketFactory)
463                         .build());
464             if (defaultSocketConfig != null) {
465                 poolingmgr.setDefaultSocketConfig(defaultSocketConfig);
466             }
467             if (defaultConnectionConfig != null) {
468                 poolingmgr.setDefaultConnectionConfig(defaultConnectionConfig);
469             }
470             if (systemProperties) {
471                 String s = System.getProperty("http.keepAlive", "true");
472                 if ("true".equalsIgnoreCase(s)) {
473                     s = System.getProperty("http.maxConnections", "5");
474                     final int max = Integer.parseInt(s);
475                     poolingmgr.setDefaultMaxPerRoute(max);
476                     poolingmgr.setMaxTotal(2 * max);
477                 }
478             } else {
479                 if (maxConnTotal > 0) {
480                     poolingmgr.setMaxTotal(maxConnTotal);
481                 }
482                 if (maxConnPerRoute > 0) {
483                     poolingmgr.setDefaultMaxPerRoute(maxConnPerRoute);
484                 }
485             }
486             connManager = poolingmgr;
487         }
488         ConnectionReuseStrategy reuseStrategy = this.reuseStrategy;
489         if (reuseStrategy == null) {
490             if (systemProperties) {
491                 final String s = System.getProperty("http.keepAlive", "true");
492                 if ("true".equalsIgnoreCase(s)) {
493                     reuseStrategy = DefaultConnectionReuseStrategy.INSTANCE;
494                 } else {
495                     reuseStrategy = NoConnectionReuseStrategy.INSTANCE;
496                 }
497             } else {
498                 reuseStrategy = DefaultConnectionReuseStrategy.INSTANCE;
499             }
500         }
501         ConnectionKeepAliveStrategy keepAliveStrategy = this.keepAliveStrategy;
502         if (keepAliveStrategy == null) {
503             keepAliveStrategy = DefaultConnectionKeepAliveStrategy.INSTANCE;
504         }
505         AuthenticationStrategy targetAuthStrategy = this.targetAuthStrategy;
506         if (targetAuthStrategy == null) {
507             targetAuthStrategy = TargetAuthenticationStrategy.INSTANCE;
508         }
509         AuthenticationStrategy proxyAuthStrategy = this.proxyAuthStrategy;
510         if (proxyAuthStrategy == null) {
511             proxyAuthStrategy = ProxyAuthenticationStrategy.INSTANCE;
512         }
513         UserTokenHandler userTokenHandler = this.userTokenHandler;
514         if (userTokenHandler == null) {
515             if (!connectionStateDisabled) {
516                 userTokenHandler = DefaultUserTokenHandler.INSTANCE;
517             } else {
518                 userTokenHandler = NoopUserTokenHandler.INSTANCE;
519             }
520         }
521         SchemePortResolver schemePortResolver = this.schemePortResolver;
522         if (schemePortResolver == null) {
523             schemePortResolver = DefaultSchemePortResolver.INSTANCE;
524         }
525 
526         ClientExecChain execChain = new MainClientExec(
527                 requestExec,
528                 connManager,
529                 reuseStrategy,
530                 keepAliveStrategy,
531                 targetAuthStrategy,
532                 proxyAuthStrategy,
533                 userTokenHandler);
534 
535         execChain = decorateMainExec(execChain);
536 
537         HttpProcessor httpprocessor = this.httpprocessor;
538         if (httpprocessor == null) {
539 
540             String userAgent = this.userAgent;
541             if (userAgent == null) {
542                 if (systemProperties) {
543                     userAgent = System.getProperty("http.agent");
544                 } else {
545                     final VersionInfo vi = VersionInfo.loadVersionInfo("org.apache.http.client",
546                             HttpClientBuilder.class.getClassLoader());
547                     final String release = vi != null ? vi.getRelease() : VersionInfo.UNAVAILABLE;
548                     userAgent = "Apache-HttpClient/" + release + " (java 1.5)";
549                 }
550             }
551 
552             final HttpProcessorBuilder b = HttpProcessorBuilder.create();
553             if (requestFirst != null) {
554                 for (final HttpRequestInterceptor i: requestFirst) {
555                     b.addFirst(i);
556                 }
557             }
558             if (responseFirst != null) {
559                 for (final HttpResponseInterceptor i: responseFirst) {
560                     b.addFirst(i);
561                 }
562             }
563             b.addAll(
564                     new RequestDefaultHeaders(defaultHeaders),
565                     new RequestContent(),
566                     new RequestTargetHost(),
567                     new RequestClientConnControl(),
568                     new RequestUserAgent(userAgent),
569                     new RequestExpectContinue());
570             if (!cookieManagementDisabled) {
571                 b.add(new RequestAddCookies());
572             }
573             if (!contentCompressionDisabled) {
574                 b.add(new RequestAcceptEncoding());
575             }
576             if (!authCachingDisabled) {
577                 b.add(new RequestAuthCache());
578             }
579             if (!cookieManagementDisabled) {
580                 b.add(new ResponseProcessCookies());
581             }
582             if (!contentCompressionDisabled) {
583                 b.add(new ResponseContentEncoding());
584             }
585             if (requestLast != null) {
586                 for (final HttpRequestInterceptor i: requestLast) {
587                     b.addLast(i);
588                 }
589             }
590             if (responseLast != null) {
591                 for (final HttpResponseInterceptor i: responseLast) {
592                     b.addLast(i);
593                 }
594             }
595             httpprocessor = b.build();
596         }
597         execChain = new ProtocolExec(execChain, httpprocessor);
598 
599         execChain = decorateProtocolExec(execChain);
600 
601         // Add request retry executor, if not disabled
602         if (!automaticRetriesDisabled) {
603             HttpRequestRetryHandler retryHandler = this.retryHandler;
604             if (retryHandler == null) {
605                 retryHandler = DefaultHttpRequestRetryHandler.INSTANCE;
606             }
607             execChain = new RetryExec(execChain, retryHandler);
608         }
609 
610         // Add redirect executor, if not disabled
611         HttpRoutePlanner routePlanner = this.routePlanner;
612         if (routePlanner == null) {
613             if (proxy != null) {
614                 routePlanner = new DefaultProxyRoutePlanner(proxy, schemePortResolver);
615             } else if (systemProperties) {
616                 routePlanner = new SystemDefaultRoutePlanner(
617                         schemePortResolver, ProxySelector.getDefault());
618             } else {
619                 routePlanner = new DefaultRoutePlanner(schemePortResolver);
620             }
621         }
622         if (!redirectHandlingDisabled) {
623             RedirectStrategy redirectStrategy = this.redirectStrategy;
624             if (redirectStrategy == null) {
625                 redirectStrategy = DefaultRedirectStrategy.INSTANCE;
626             }
627             execChain = new RedirectExec(execChain, routePlanner, redirectStrategy);
628         }
629 
630         // Optionally, add service unavailable retry executor
631         final ServiceUnavailableRetryStrategy serviceUnavailStrategy = this.serviceUnavailStrategy;
632         if (serviceUnavailStrategy != null) {
633             execChain = new ServiceUnavailableRetryExec(execChain, serviceUnavailStrategy);
634         }
635         // Optionally, add connection back-off executor
636         final BackoffManager backoffManager = this.backoffManager;
637         final ConnectionBackoffStrategy connectionBackoffStrategy = this.connectionBackoffStrategy;
638         if (backoffManager != null && connectionBackoffStrategy != null) {
639             execChain = new BackoffStrategyExec(execChain, connectionBackoffStrategy, backoffManager);
640         }
641 
642         Lookup<AuthSchemeProvider> authSchemeRegistry = this.authSchemeRegistry;
643         if (authSchemeRegistry == null) {
644             authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
645                 .register(AuthSchemes.BASIC, new BasicSchemeFactory())
646                 .register(AuthSchemes.DIGEST, new DigestSchemeFactory())
647                 .register(AuthSchemes.NTLM, new NTLMSchemeFactory())
648                 .register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory())
649                 .register(AuthSchemes.KERBEROS, new KerberosSchemeFactory())
650                 .build();
651         }
652         Lookup<CookieSpecProvider> cookieSpecRegistry = this.cookieSpecRegistry;
653         if (cookieSpecRegistry == null) {
654             cookieSpecRegistry = RegistryBuilder.<CookieSpecProvider>create()
655                 .register(CookieSpecs.BEST_MATCH, new BestMatchSpecFactory())
656                 .register(CookieSpecs.BROWSER_COMPATIBILITY, new BrowserCompatSpecFactory())
657                 .register(CookieSpecs.NETSCAPE, new NetscapeDraftSpecFactory())
658                 .register(CookieSpecs.RFC_2109, new RFC2109SpecFactory())
659                 .register(CookieSpecs.RFC_2965, new RFC2965SpecFactory())
660                 .register(CookieSpecs.IGNORE_COOKIES, new IgnoreSpecFactory())
661                 .build();
662         }
663 
664         CookieStore defaultCookieStore = this.cookieStore;
665         if (defaultCookieStore == null) {
666             defaultCookieStore = new BasicCookieStore();
667         }
668 
669         CredentialsProvider defaultCredentialsProvider = this.credentialsProvider;
670         if (defaultCredentialsProvider == null) {
671             defaultCredentialsProvider = new BasicCredentialsProvider();
672         }
673 
674         return new InternalHttpClient(
675                 execChain,
676                 connManager,
677                 routePlanner,
678                 cookieSpecRegistry,
679                 authSchemeRegistry,
680                 defaultCookieStore,
681                 defaultCredentialsProvider,
682                 defaultRequestConfig != null ? defaultRequestConfig : RequestConfig.DEFAULT,
683                 closeables != null ? new ArrayList<Closeable>(closeables) : null);
684     }
685 
686 }