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