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.nio.client;
29  
30  import java.net.ProxySelector;
31  import java.util.Collection;
32  import java.util.LinkedList;
33  import java.util.concurrent.Executors;
34  import java.util.concurrent.ThreadFactory;
35  
36  import javax.net.ssl.HostnameVerifier;
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.auth.AuthSchemeProvider;
45  import org.apache.http.client.AuthenticationStrategy;
46  import org.apache.http.client.CookieStore;
47  import org.apache.http.client.CredentialsProvider;
48  import org.apache.http.client.RedirectStrategy;
49  import org.apache.http.client.UserTokenHandler;
50  import org.apache.http.client.config.AuthSchemes;
51  import org.apache.http.client.config.CookieSpecs;
52  import org.apache.http.client.config.RequestConfig;
53  import org.apache.http.client.protocol.RequestAddCookies;
54  import org.apache.http.client.protocol.RequestAuthCache;
55  import org.apache.http.client.protocol.RequestClientConnControl;
56  import org.apache.http.client.protocol.RequestDefaultHeaders;
57  import org.apache.http.client.protocol.RequestExpectContinue;
58  import org.apache.http.client.protocol.ResponseProcessCookies;
59  import org.apache.http.config.ConnectionConfig;
60  import org.apache.http.config.Lookup;
61  import org.apache.http.config.RegistryBuilder;
62  import org.apache.http.conn.ConnectionKeepAliveStrategy;
63  import org.apache.http.conn.SchemePortResolver;
64  import org.apache.http.conn.routing.HttpRoutePlanner;
65  import org.apache.http.conn.ssl.DefaultHostnameVerifier;
66  import org.apache.http.conn.ssl.X509HostnameVerifier;
67  import org.apache.http.conn.util.PublicSuffixMatcher;
68  import org.apache.http.conn.util.PublicSuffixMatcherLoader;
69  import org.apache.http.cookie.CookieSpecProvider;
70  import org.apache.http.impl.DefaultConnectionReuseStrategy;
71  import org.apache.http.impl.NoConnectionReuseStrategy;
72  import org.apache.http.impl.auth.BasicSchemeFactory;
73  import org.apache.http.impl.auth.DigestSchemeFactory;
74  import org.apache.http.impl.auth.KerberosSchemeFactory;
75  import org.apache.http.impl.auth.NTLMSchemeFactory;
76  import org.apache.http.impl.auth.SPNegoSchemeFactory;
77  import org.apache.http.impl.client.BasicCookieStore;
78  import org.apache.http.impl.client.BasicCredentialsProvider;
79  import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
80  import org.apache.http.impl.client.DefaultRedirectStrategy;
81  import org.apache.http.impl.client.NoopUserTokenHandler;
82  import org.apache.http.impl.client.ProxyAuthenticationStrategy;
83  import org.apache.http.impl.client.TargetAuthenticationStrategy;
84  import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
85  import org.apache.http.impl.conn.DefaultRoutePlanner;
86  import org.apache.http.impl.conn.DefaultSchemePortResolver;
87  import org.apache.http.impl.conn.SystemDefaultRoutePlanner;
88  import org.apache.http.impl.cookie.DefaultCookieSpecProvider;
89  import org.apache.http.impl.cookie.IgnoreSpecProvider;
90  import org.apache.http.impl.cookie.NetscapeDraftSpecProvider;
91  import org.apache.http.impl.cookie.RFC6265CookieSpecProvider;
92  import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
93  import org.apache.http.impl.nio.reactor.IOReactorConfig;
94  import org.apache.http.nio.NHttpClientEventHandler;
95  import org.apache.http.nio.conn.NHttpClientConnectionManager;
96  import org.apache.http.nio.conn.NoopIOSessionStrategy;
97  import org.apache.http.nio.conn.SchemeIOSessionStrategy;
98  import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
99  import org.apache.http.nio.protocol.HttpAsyncRequestExecutor;
100 import org.apache.http.nio.reactor.ConnectingIOReactor;
101 import org.apache.http.protocol.HttpProcessor;
102 import org.apache.http.protocol.HttpProcessorBuilder;
103 import org.apache.http.protocol.RequestContent;
104 import org.apache.http.protocol.RequestTargetHost;
105 import org.apache.http.protocol.RequestUserAgent;
106 import org.apache.http.ssl.SSLContexts;
107 import org.apache.http.util.TextUtils;
108 import org.apache.http.util.VersionInfo;
109 
110 /**
111  * Builder for {@link CloseableHttpAsyncClient} instances.
112  * <p>
113  * When a particular component is not explicitly this class will
114  * use its default implementation. System properties will be taken
115  * into account when configuring the default implementations when
116  * {@link #useSystemProperties()} method is called prior to calling
117  * {@link #build()}.
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>ssl.KeyManagerFactory.algorithm</li>
125  *  <li>javax.net.ssl.keyStoreType</li>
126  *  <li>javax.net.ssl.keyStore</li>
127  *  <li>javax.net.ssl.keyStoreProvider</li>
128  *  <li>javax.net.ssl.keyStorePassword</li>
129  *  <li>https.protocols</li>
130  *  <li>https.cipherSuites</li>
131  *  <li>http.proxyHost</li>
132  *  <li>http.proxyPort</li>
133  *  <li>http.keepAlive</li>
134  *  <li>http.maxConnections</li>
135  *  <li>http.agent</li>
136  * </ul>
137  * <p>
138  * Please note that some settings used by this class can be mutually
139  * exclusive and may not apply when building {@link CloseableHttpAsyncClient}
140  * instances.
141  *
142  * @since 4.0
143  */
144 public class HttpAsyncClientBuilder {
145 
146     private NHttpClientConnectionManager connManager;
147     private boolean connManagerShared;
148     private SchemePortResolver schemePortResolver;
149     private SchemeIOSessionStrategy sslStrategy;
150     private HostnameVerifier hostnameVerifier;
151     private SSLContext sslcontext;
152     private ConnectionReuseStrategy reuseStrategy;
153     private ConnectionKeepAliveStrategy keepAliveStrategy;
154     private AuthenticationStrategy targetAuthStrategy;
155     private AuthenticationStrategy proxyAuthStrategy;
156     private UserTokenHandler userTokenHandler;
157     private HttpProcessor httpprocessor;
158 
159     private LinkedList<HttpRequestInterceptor> requestFirst;
160     private LinkedList<HttpRequestInterceptor> requestLast;
161     private LinkedList<HttpResponseInterceptor> responseFirst;
162     private LinkedList<HttpResponseInterceptor> responseLast;
163 
164     private HttpRoutePlanner routePlanner;
165     private RedirectStrategy redirectStrategy;
166     private Lookup<AuthSchemeProvider> authSchemeRegistry;
167     private Lookup<CookieSpecProvider> cookieSpecRegistry;
168     private CookieStore cookieStore;
169     private CredentialsProvider credentialsProvider;
170     private String userAgent;
171     private HttpHost proxy;
172     private Collection<? extends Header> defaultHeaders;
173     private IOReactorConfig defaultIOReactorConfig;
174     private ConnectionConfig defaultConnectionConfig;
175     private RequestConfig defaultRequestConfig;
176 
177     private ThreadFactory threadFactory;
178     private NHttpClientEventHandler eventHandler;
179 
180     private PublicSuffixMatcher publicSuffixMatcher;
181 
182     private boolean systemProperties;
183     private boolean cookieManagementDisabled;
184     private boolean authCachingDisabled;
185     private boolean connectionStateDisabled;
186 
187     private int maxConnTotal = 0;
188     private int maxConnPerRoute = 0;
189 
190     public static HttpAsyncClientBuilder create() {
191         return new HttpAsyncClientBuilder();
192     }
193 
194     protected HttpAsyncClientBuilder() {
195         super();
196     }
197 
198     /**
199      * Assigns file containing public suffix matcher. Instances of this class can be created
200      * with {@link org.apache.http.conn.util.PublicSuffixMatcherLoader}.
201      *
202      * @see org.apache.http.conn.util.PublicSuffixMatcher
203      * @see org.apache.http.conn.util.PublicSuffixMatcherLoader
204      *
205      *   @since 4.1
206      */
207     public final HttpAsyncClientBuilder setPublicSuffixMatcher(final PublicSuffixMatcher publicSuffixMatcher) {
208         this.publicSuffixMatcher = publicSuffixMatcher;
209         return this;
210     }
211 
212     /**
213      * Assigns {@link NHttpClientConnectionManager} instance.
214      */
215     public final HttpAsyncClientBuilder setConnectionManager(
216             final NHttpClientConnectionManager connManager) {
217         this.connManager = connManager;
218         return this;
219     }
220 
221     /**
222      * Defines the connection manager is to be shared by multiple
223      * client instances.
224      * <p>
225      * If the connection manager is shared its life-cycle is expected
226      * to be managed by the caller and it will not be shut down
227      * if the client is closed.
228      *
229      * @param shared defines whether or not the connection manager can be shared
230      *  by multiple clients.
231      *
232      * @since 4.1
233      */
234     public final HttpAsyncClientBuilder setConnectionManagerShared(
235             final boolean shared) {
236         this.connManagerShared = shared;
237         return this;
238     }
239 
240     /**
241      * Assigns {@link SchemePortResolver} instance.
242      */
243     public final HttpAsyncClientBuilder setSchemePortResolver(
244             final SchemePortResolver schemePortResolver) {
245         this.schemePortResolver = schemePortResolver;
246         return this;
247     }
248 
249     /**
250      * Assigns maximum total connection value.
251      * <p>
252      * Please note this value can be overridden by the {@link #setConnectionManager(
253      *   org.apache.http.nio.conn.NHttpClientConnectionManager)} method.
254      */
255     public final HttpAsyncClientBuilder setMaxConnTotal(final int maxConnTotal) {
256         this.maxConnTotal = maxConnTotal;
257         return this;
258     }
259 
260     /**
261      * Assigns maximum connection per route value.
262      * <p>
263      * Please note this value can be overridden by the {@link #setConnectionManager(
264      *   org.apache.http.nio.conn.NHttpClientConnectionManager)} method.
265      */
266     public final HttpAsyncClientBuilder setMaxConnPerRoute(final int maxConnPerRoute) {
267         this.maxConnPerRoute = maxConnPerRoute;
268         return this;
269     }
270 
271     /**
272      * Assigns {@link ConnectionReuseStrategy} instance.
273      */
274     public final HttpAsyncClientBuilder setConnectionReuseStrategy(
275             final ConnectionReuseStrategy reuseStrategy) {
276         this.reuseStrategy = reuseStrategy;
277         return this;
278     }
279 
280     /**
281      * Assigns {@link ConnectionKeepAliveStrategy} instance.
282      */
283     public final HttpAsyncClientBuilder setKeepAliveStrategy(
284             final ConnectionKeepAliveStrategy keepAliveStrategy) {
285         this.keepAliveStrategy = keepAliveStrategy;
286         return this;
287     }
288 
289     /**
290      * Assigns {@link UserTokenHandler} instance.
291      * <p>
292      * Please note this value can be overridden by the {@link #disableConnectionState()}
293      * method.
294      */
295     public final HttpAsyncClientBuilder setUserTokenHandler(final UserTokenHandler userTokenHandler) {
296         this.userTokenHandler = userTokenHandler;
297         return this;
298     }
299 
300     /**
301      * Assigns {@link AuthenticationStrategy} instance for proxy
302      * authentication.
303      */
304     public final HttpAsyncClientBuilder setTargetAuthenticationStrategy(
305             final AuthenticationStrategy targetAuthStrategy) {
306         this.targetAuthStrategy = targetAuthStrategy;
307         return this;
308     }
309 
310     /**
311      * Assigns {@link AuthenticationStrategy} instance for target
312      * host authentication.
313      */
314     public final HttpAsyncClientBuilder setProxyAuthenticationStrategy(
315             final AuthenticationStrategy proxyAuthStrategy) {
316         this.proxyAuthStrategy = proxyAuthStrategy;
317         return this;
318     }
319 
320     /**
321      * Assigns {@link HttpProcessor} instance.
322      */
323     public final HttpAsyncClientBuilder setHttpProcessor(final HttpProcessor httpprocessor) {
324         this.httpprocessor = httpprocessor;
325         return this;
326     }
327 
328     /**
329      * Adds this protocol interceptor to the head of the protocol processing list.
330      * <p>
331      * Please note this value can be overridden by the {@link #setHttpProcessor(
332      * org.apache.http.protocol.HttpProcessor)} method.
333      */
334     public final HttpAsyncClientBuilder addInterceptorFirst(final HttpResponseInterceptor itcp) {
335         if (itcp == null) {
336             return this;
337         }
338         if (responseFirst == null) {
339             responseFirst = new LinkedList<HttpResponseInterceptor>();
340         }
341         responseFirst.addFirst(itcp);
342         return this;
343     }
344 
345     /**
346      * Adds this protocol interceptor to the tail of the protocol processing list.
347      * <p>
348      * Please note this value can be overridden by the {@link #setHttpProcessor(
349      * org.apache.http.protocol.HttpProcessor)} method.
350      */
351     public final HttpAsyncClientBuilder addInterceptorLast(final HttpResponseInterceptor itcp) {
352         if (itcp == null) {
353             return this;
354         }
355         if (responseLast == null) {
356             responseLast = new LinkedList<HttpResponseInterceptor>();
357         }
358         responseLast.addLast(itcp);
359         return this;
360     }
361 
362     /**
363      * Adds this protocol interceptor to the head of the protocol processing list.
364      * <p>
365      * Please note this value can be overridden by the {@link #setHttpProcessor(
366      * org.apache.http.protocol.HttpProcessor)} method.
367      */
368     public final HttpAsyncClientBuilder addInterceptorFirst(final HttpRequestInterceptor itcp) {
369         if (itcp == null) {
370             return this;
371         }
372         if (requestFirst == null) {
373             requestFirst = new LinkedList<HttpRequestInterceptor>();
374         }
375         requestFirst.addFirst(itcp);
376         return this;
377     }
378 
379     /**
380      * Adds this protocol interceptor to the tail of the protocol processing list.
381      * <p>
382      * Please note this value can be overridden by the {@link #setHttpProcessor(
383      * org.apache.http.protocol.HttpProcessor)} method.
384      */
385     public final HttpAsyncClientBuilder addInterceptorLast(final HttpRequestInterceptor itcp) {
386         if (itcp == null) {
387             return this;
388         }
389         if (requestLast == null) {
390             requestLast = new LinkedList<HttpRequestInterceptor>();
391         }
392         requestLast.addLast(itcp);
393         return this;
394     }
395 
396     /**
397      * Assigns {@link HttpRoutePlanner} instance.
398      */
399     public final HttpAsyncClientBuilder setRoutePlanner(final HttpRoutePlanner routePlanner) {
400         this.routePlanner = routePlanner;
401         return this;
402     }
403 
404     /**
405      * Assigns {@link RedirectStrategy} instance.
406      */
407     public final HttpAsyncClientBuilder setRedirectStrategy(final RedirectStrategy redirectStrategy) {
408         this.redirectStrategy = redirectStrategy;
409         return this;
410     }
411 
412     /**
413      * Assigns default {@link CookieStore} instance which will be used for
414      * request execution if not explicitly set in the client execution context.
415      */
416     public final HttpAsyncClientBuilder setDefaultCookieStore(final CookieStore cookieStore) {
417         this.cookieStore = cookieStore;
418         return this;
419     }
420 
421     /**
422      * Assigns default {@link CredentialsProvider} instance which will be used
423      * for request execution if not explicitly set in the client execution
424      * context.
425      */
426     public final HttpAsyncClientBuilder setDefaultCredentialsProvider(
427             final CredentialsProvider credentialsProvider) {
428         this.credentialsProvider = credentialsProvider;
429         return this;
430     }
431 
432 
433     /**
434      * Assigns default {@link org.apache.http.auth.AuthScheme} registry which will
435      * be used for request execution if not explicitly set in the client execution
436      * context.
437      */
438     public final HttpAsyncClientBuilder setDefaultAuthSchemeRegistry(
439             final Lookup<AuthSchemeProvider> authSchemeRegistry) {
440         this.authSchemeRegistry = authSchemeRegistry;
441         return this;
442     }
443 
444     /**
445      * Assigns default {@link org.apache.http.cookie.CookieSpec} registry which will
446      * be used for request execution if not explicitly set in the client execution
447      * context.
448      */
449     public final HttpAsyncClientBuilder setDefaultCookieSpecRegistry(
450             final Lookup<CookieSpecProvider> cookieSpecRegistry) {
451         this.cookieSpecRegistry = cookieSpecRegistry;
452         return this;
453     }
454 
455     /**
456      * Assigns {@code User-Agent} value.
457      * <p>
458      * Please note this value can be overridden by the {@link #setHttpProcessor(
459      * org.apache.http.protocol.HttpProcessor)} method.
460      */
461     public final HttpAsyncClientBuilder setUserAgent(final String userAgent) {
462         this.userAgent = userAgent;
463         return this;
464     }
465 
466     /**
467      * Assigns default proxy value.
468      * <p>
469      * Please note this value can be overridden by the {@link #setRoutePlanner(
470      *   org.apache.http.conn.routing.HttpRoutePlanner)} method.
471      */
472     public final HttpAsyncClientBuilder setProxy(final HttpHost proxy) {
473         this.proxy = proxy;
474         return this;
475     }
476 
477     /**
478      * Assigns {@link SchemeIOSessionStrategy} instance.
479      * <p>
480      * Please note this value can be overridden by the {@link #setConnectionManager(
481      *   org.apache.http.nio.conn.NHttpClientConnectionManager)} method.
482      */
483     public final HttpAsyncClientBuilder setSSLStrategy(final SchemeIOSessionStrategy strategy) {
484         this.sslStrategy = strategy;
485         return this;
486     }
487 
488     /**
489      * Assigns {@link SSLContext} instance.
490      * <p>
491      * Please note this value can be overridden by the {@link #setConnectionManager(
492      *   org.apache.http.nio.conn.NHttpClientConnectionManager)} and the {@link #setSSLStrategy(
493      *   org.apache.http.nio.conn.SchemeIOSessionStrategy)} methods.
494      */
495     public final HttpAsyncClientBuilder setSSLContext(final SSLContext sslcontext) {
496         this.sslcontext = sslcontext;
497         return this;
498     }
499 
500     /**
501      * Assigns {@link X509HostnameVerifier} instance.
502      * <p>
503      * Please note this value can be overridden by the {@link #setConnectionManager(
504      *   org.apache.http.nio.conn.NHttpClientConnectionManager)} and the {@link #setSSLStrategy(
505      *   org.apache.http.nio.conn.SchemeIOSessionStrategy)} methods.
506      *
507      * @deprecated (4.1) use {@link #setSSLHostnameVerifier(javax.net.ssl.HostnameVerifier)}
508      */
509     @Deprecated
510     public final HttpAsyncClientBuilder setHostnameVerifier(final X509HostnameVerifier hostnameVerifier) {
511         this.hostnameVerifier = hostnameVerifier;
512         return this;
513     }
514 
515     /**
516      * Assigns {@link javax.net.ssl.HostnameVerifier} instance.
517      * <p>
518      * Please note this value can be overridden by the {@link #setConnectionManager(
519      *   org.apache.http.nio.conn.NHttpClientConnectionManager)} and the {@link #setSSLStrategy(
520      *   org.apache.http.nio.conn.SchemeIOSessionStrategy)} methods.
521      *
522      * @since 4.1
523      */
524     public final HttpAsyncClientBuilder setSSLHostnameVerifier(final HostnameVerifier hostnameVerifier) {
525         this.hostnameVerifier = hostnameVerifier;
526         return this;
527     }
528 
529     /**
530      * Assigns default request header values.
531      * <p>
532      * Please note this value can be overridden by the {@link #setHttpProcessor(
533      * org.apache.http.protocol.HttpProcessor)} method.
534      */
535     public final HttpAsyncClientBuilder setDefaultHeaders(final Collection<? extends Header> defaultHeaders) {
536         this.defaultHeaders = defaultHeaders;
537         return this;
538     }
539 
540     /**
541      * Assigns default {@link IOReactorConfig}.
542      * <p>
543      * Please note this value can be overridden by the {@link #setConnectionManager(
544      *   org.apache.http.nio.conn.NHttpClientConnectionManager)} method.
545      */
546     public final HttpAsyncClientBuilder setDefaultIOReactorConfig(final IOReactorConfig config) {
547         this.defaultIOReactorConfig = config;
548         return this;
549     }
550 
551     /**
552      * Assigns default {@link ConnectionConfig}.
553      * <p>
554      * Please note this value can be overridden by the {@link #setConnectionManager(
555      *   org.apache.http.nio.conn.NHttpClientConnectionManager)} method.
556      */
557     public final HttpAsyncClientBuilder setDefaultConnectionConfig(final ConnectionConfig config) {
558         this.defaultConnectionConfig = config;
559         return this;
560     }
561 
562     /**
563      * Assigns default {@link RequestConfig} instance which will be used
564      * for request execution if not explicitly set in the client execution
565      * context.
566      */
567     public final HttpAsyncClientBuilder setDefaultRequestConfig(final RequestConfig config) {
568         this.defaultRequestConfig = config;
569         return this;
570     }
571 
572     /**
573      * Assigns {@link ThreadFactory} instance.
574      */
575     public final HttpAsyncClientBuilder setThreadFactory(final ThreadFactory threadFactory) {
576         this.threadFactory = threadFactory;
577         return this;
578     }
579 
580     /**
581      * Assigns {@link NHttpClientEventHandler} instance.
582      *
583      * @since 4.1
584      */
585     public final HttpAsyncClientBuilder setEventHandler(final NHttpClientEventHandler eventHandler) {
586         this.eventHandler = eventHandler;
587         return this;
588     }
589 
590     /**
591      * Disables connection state tracking.
592      */
593     public final HttpAsyncClientBuilder disableConnectionState() {
594         connectionStateDisabled = true;
595         return this;
596     }
597 
598     /**
599      * Disables state (cookie) management.
600      * <p>
601      * Please note this value can be overridden by the {@link #setHttpProcessor(
602      * org.apache.http.protocol.HttpProcessor)} method.
603      */
604     public final HttpAsyncClientBuilder disableCookieManagement() {
605         cookieManagementDisabled = true;
606         return this;
607     }
608 
609     /**
610      * Disables authentication scheme caching.
611      * <p>
612      * Please note this value can be overridden by the {@link #setHttpProcessor(
613      * org.apache.http.protocol.HttpProcessor)} method.
614      */
615     public final HttpAsyncClientBuilder disableAuthCaching() {
616         authCachingDisabled = true;
617         return this;
618     }
619 
620     /**
621      * Use system properties when creating and configuring default
622      * implementations.
623      */
624     public final HttpAsyncClientBuilder useSystemProperties() {
625         systemProperties = true;
626         return this;
627     }
628 
629     private static String[] split(final String s) {
630         if (TextUtils.isBlank(s)) {
631             return null;
632         }
633         return s.split(" *, *");
634     }
635 
636     public CloseableHttpAsyncClient build() {
637 
638         PublicSuffixMatcher publicSuffixMatcher = this.publicSuffixMatcher;
639         if (publicSuffixMatcher == null) {
640             publicSuffixMatcher = PublicSuffixMatcherLoader.getDefault();
641         }
642 
643         NHttpClientConnectionManager connManager = this.connManager;
644         if (connManager == null) {
645             SchemeIOSessionStrategy sslStrategy = this.sslStrategy;
646             if (sslStrategy == null) {
647                 SSLContext sslcontext = this.sslcontext;
648                 if (sslcontext == null) {
649                     if (systemProperties) {
650                         sslcontext = SSLContexts.createSystemDefault();
651                     } else {
652                         sslcontext = SSLContexts.createDefault();
653                     }
654                 }
655                 final String[] supportedProtocols = systemProperties ? split(
656                         System.getProperty("https.protocols")) : null;
657                 final String[] supportedCipherSuites = systemProperties ? split(
658                         System.getProperty("https.cipherSuites")) : null;
659                 HostnameVerifier hostnameVerifier = this.hostnameVerifier;
660                 if (hostnameVerifier == null) {
661                     hostnameVerifier = new DefaultHostnameVerifier(publicSuffixMatcher);
662                 }
663                 sslStrategy = new SSLIOSessionStrategy(
664                         sslcontext, supportedProtocols, supportedCipherSuites, hostnameVerifier);
665             }
666             final ConnectingIOReactor ioreactor = IOReactorUtils.create(
667                 defaultIOReactorConfig != null ? defaultIOReactorConfig : IOReactorConfig.DEFAULT, threadFactory);
668             final PoolingNHttpClientConnectionManager poolingmgr = new PoolingNHttpClientConnectionManager(
669                     ioreactor,
670                     RegistryBuilder.<SchemeIOSessionStrategy>create()
671                         .register("http", NoopIOSessionStrategy.INSTANCE)
672                         .register("https", sslStrategy)
673                         .build());
674             if (defaultConnectionConfig != null) {
675                 poolingmgr.setDefaultConnectionConfig(defaultConnectionConfig);
676             }
677             if (systemProperties) {
678                 String s = System.getProperty("http.keepAlive", "true");
679                 if ("true".equalsIgnoreCase(s)) {
680                     s = System.getProperty("http.maxConnections", "5");
681                     final int max = Integer.parseInt(s);
682                     poolingmgr.setDefaultMaxPerRoute(max);
683                     poolingmgr.setMaxTotal(2 * max);
684                 }
685             } else {
686                 if (maxConnTotal > 0) {
687                     poolingmgr.setMaxTotal(maxConnTotal);
688                 }
689                 if (maxConnPerRoute > 0) {
690                     poolingmgr.setDefaultMaxPerRoute(maxConnPerRoute);
691                 }
692             }
693             connManager = poolingmgr;
694         }
695         ConnectionReuseStrategy reuseStrategy = this.reuseStrategy;
696         if (reuseStrategy == null) {
697             if (systemProperties) {
698                 final String s = System.getProperty("http.keepAlive", "true");
699                 if ("true".equalsIgnoreCase(s)) {
700                     reuseStrategy = DefaultConnectionReuseStrategy.INSTANCE;
701                 } else {
702                     reuseStrategy = NoConnectionReuseStrategy.INSTANCE;
703                 }
704             } else {
705                 reuseStrategy = DefaultConnectionReuseStrategy.INSTANCE;
706             }
707         }
708         ConnectionKeepAliveStrategy keepAliveStrategy = this.keepAliveStrategy;
709         if (keepAliveStrategy == null) {
710             keepAliveStrategy = DefaultConnectionKeepAliveStrategy.INSTANCE;
711         }
712         AuthenticationStrategy targetAuthStrategy = this.targetAuthStrategy;
713         if (targetAuthStrategy == null) {
714             targetAuthStrategy = TargetAuthenticationStrategy.INSTANCE;
715         }
716         AuthenticationStrategy proxyAuthStrategy = this.proxyAuthStrategy;
717         if (proxyAuthStrategy == null) {
718             proxyAuthStrategy = ProxyAuthenticationStrategy.INSTANCE;
719         }
720         UserTokenHandler userTokenHandler = this.userTokenHandler;
721         if (userTokenHandler == null) {
722             if (!connectionStateDisabled) {
723                 userTokenHandler = DefaultAsyncUserTokenHandler.INSTANCE;
724             } else {
725                 userTokenHandler = NoopUserTokenHandler.INSTANCE;
726             }
727         }
728         SchemePortResolver schemePortResolver = this.schemePortResolver;
729         if (schemePortResolver == null) {
730             schemePortResolver = DefaultSchemePortResolver.INSTANCE;
731         }
732 
733         HttpProcessor httpprocessor = this.httpprocessor;
734         if (httpprocessor == null) {
735 
736             String userAgent = this.userAgent;
737             if (userAgent == null) {
738                 if (systemProperties) {
739                     userAgent = System.getProperty("http.agent");
740                 }
741                 if (userAgent == null) {
742                     userAgent = VersionInfo.getUserAgent(
743                             "Apache-HttpAsyncClient",
744                             "org.apache.http.nio.client", getClass());
745                 }
746             }
747 
748             final HttpProcessorBuilder b = HttpProcessorBuilder.create();
749             if (requestFirst != null) {
750                 for (final HttpRequestInterceptor i: requestFirst) {
751                     b.addFirst(i);
752                 }
753             }
754             if (responseFirst != null) {
755                 for (final HttpResponseInterceptor i: responseFirst) {
756                     b.addFirst(i);
757                 }
758             }
759             b.addAll(
760                     new RequestDefaultHeaders(defaultHeaders),
761                     new RequestContent(),
762                     new RequestTargetHost(),
763                     new RequestClientConnControl(),
764                     new RequestUserAgent(userAgent),
765                     new RequestExpectContinue());
766             if (!cookieManagementDisabled) {
767                 b.add(new RequestAddCookies());
768             }
769             if (!authCachingDisabled) {
770                 b.add(new RequestAuthCache());
771             }
772             if (!cookieManagementDisabled) {
773                 b.add(new ResponseProcessCookies());
774             }
775             if (requestLast != null) {
776                 for (final HttpRequestInterceptor i: requestLast) {
777                     b.addLast(i);
778                 }
779             }
780             if (responseLast != null) {
781                 for (final HttpResponseInterceptor i: responseLast) {
782                     b.addLast(i);
783                 }
784             }
785             httpprocessor = b.build();
786         }
787         // Add redirect executor, if not disabled
788         HttpRoutePlanner routePlanner = this.routePlanner;
789         if (routePlanner == null) {
790             if (proxy != null) {
791                 routePlanner = new DefaultProxyRoutePlanner(proxy, schemePortResolver);
792             } else if (systemProperties) {
793                 routePlanner = new SystemDefaultRoutePlanner(
794                         schemePortResolver, ProxySelector.getDefault());
795             } else {
796                 routePlanner = new DefaultRoutePlanner(schemePortResolver);
797             }
798         }
799         Lookup<AuthSchemeProvider> authSchemeRegistry = this.authSchemeRegistry;
800         if (authSchemeRegistry == null) {
801             authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
802                 .register(AuthSchemes.BASIC, new BasicSchemeFactory())
803                 .register(AuthSchemes.DIGEST, new DigestSchemeFactory())
804                 .register(AuthSchemes.NTLM, new NTLMSchemeFactory())
805                 .register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory())
806                 .register(AuthSchemes.KERBEROS, new KerberosSchemeFactory())
807                 .build();
808         }
809         Lookup<CookieSpecProvider> cookieSpecRegistry = this.cookieSpecRegistry;
810         if (cookieSpecRegistry == null) {
811             final CookieSpecProvider defaultProvider = new DefaultCookieSpecProvider(publicSuffixMatcher);
812             final CookieSpecProvider laxStandardProvider = new RFC6265CookieSpecProvider(
813                     RFC6265CookieSpecProvider.CompatibilityLevel.RELAXED, publicSuffixMatcher);
814             final CookieSpecProvider strictStandardProvider = new RFC6265CookieSpecProvider(
815                     RFC6265CookieSpecProvider.CompatibilityLevel.STRICT, publicSuffixMatcher);
816             cookieSpecRegistry = RegistryBuilder.<CookieSpecProvider>create()
817                     .register(CookieSpecs.DEFAULT, defaultProvider)
818                     .register("best-match", defaultProvider)
819                     .register("compatibility", defaultProvider)
820                     .register(CookieSpecs.STANDARD, laxStandardProvider)
821                     .register(CookieSpecs.STANDARD_STRICT, strictStandardProvider)
822                     .register(CookieSpecs.NETSCAPE, new NetscapeDraftSpecProvider())
823                     .register(CookieSpecs.IGNORE_COOKIES, new IgnoreSpecProvider())
824                     .build();
825         }
826 
827         CookieStore defaultCookieStore = this.cookieStore;
828         if (defaultCookieStore == null) {
829             defaultCookieStore = new BasicCookieStore();
830         }
831 
832         CredentialsProvider defaultCredentialsProvider = this.credentialsProvider;
833         if (defaultCredentialsProvider == null) {
834             defaultCredentialsProvider = new BasicCredentialsProvider();
835         }
836 
837         RedirectStrategy redirectStrategy = this.redirectStrategy;
838         if (redirectStrategy == null) {
839             redirectStrategy = DefaultRedirectStrategy.INSTANCE;
840         }
841 
842         RequestConfig defaultRequestConfig = this.defaultRequestConfig;
843         if (defaultRequestConfig == null) {
844             defaultRequestConfig = RequestConfig.DEFAULT;
845         }
846 
847         final MainClientExec exec = new MainClientExec(
848             httpprocessor,
849             routePlanner,
850             redirectStrategy,
851             targetAuthStrategy,
852             proxyAuthStrategy,
853             userTokenHandler);
854 
855         ThreadFactory threadFactory = null;
856         NHttpClientEventHandler eventHandler = null;
857         if (!this.connManagerShared) {
858             threadFactory = this.threadFactory;
859             if (threadFactory == null) {
860                 threadFactory = Executors.defaultThreadFactory();
861             }
862             eventHandler = this.eventHandler;
863             if (eventHandler == null) {
864                 eventHandler = new HttpAsyncRequestExecutor();
865             }
866         }
867         return new InternalHttpAsyncClient(
868             connManager,
869             reuseStrategy,
870             keepAliveStrategy,
871             threadFactory,
872             eventHandler,
873             exec,
874             cookieSpecRegistry,
875             authSchemeRegistry,
876             defaultCookieStore,
877             defaultCredentialsProvider,
878             defaultRequestConfig);
879     }
880 
881 }