1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.hc.client5.http.impl.async;
29
30 import java.io.Closeable;
31 import java.io.IOException;
32 import java.net.ProxySelector;
33 import java.security.AccessController;
34 import java.security.PrivilegedAction;
35 import java.util.ArrayList;
36 import java.util.Collection;
37 import java.util.LinkedList;
38 import java.util.List;
39 import java.util.concurrent.ThreadFactory;
40
41 import org.apache.hc.client5.http.AuthenticationStrategy;
42 import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
43 import org.apache.hc.client5.http.HttpRequestRetryStrategy;
44 import org.apache.hc.client5.http.SchemePortResolver;
45 import org.apache.hc.client5.http.UserTokenHandler;
46 import org.apache.hc.client5.http.async.AsyncExecChainHandler;
47 import org.apache.hc.client5.http.auth.AuthSchemeFactory;
48 import org.apache.hc.client5.http.auth.StandardAuthScheme;
49 import org.apache.hc.client5.http.auth.CredentialsProvider;
50 import org.apache.hc.client5.http.config.RequestConfig;
51 import org.apache.hc.client5.http.cookie.BasicCookieStore;
52 import org.apache.hc.client5.http.cookie.CookieSpecFactory;
53 import org.apache.hc.client5.http.cookie.CookieStore;
54 import org.apache.hc.client5.http.impl.ChainElement;
55 import org.apache.hc.client5.http.impl.CookieSpecSupport;
56 import org.apache.hc.client5.http.impl.DefaultAuthenticationStrategy;
57 import org.apache.hc.client5.http.impl.DefaultConnectionKeepAliveStrategy;
58 import org.apache.hc.client5.http.impl.DefaultHttpRequestRetryStrategy;
59 import org.apache.hc.client5.http.impl.DefaultRedirectStrategy;
60 import org.apache.hc.client5.http.impl.DefaultSchemePortResolver;
61 import org.apache.hc.client5.http.impl.DefaultUserTokenHandler;
62 import org.apache.hc.client5.http.impl.IdleConnectionEvictor;
63 import org.apache.hc.client5.http.impl.NoopUserTokenHandler;
64 import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
65 import org.apache.hc.client5.http.impl.auth.BasicSchemeFactory;
66 import org.apache.hc.client5.http.impl.auth.DigestSchemeFactory;
67 import org.apache.hc.client5.http.impl.auth.KerberosSchemeFactory;
68 import org.apache.hc.client5.http.impl.auth.NTLMSchemeFactory;
69 import org.apache.hc.client5.http.impl.auth.SPNegoSchemeFactory;
70 import org.apache.hc.client5.http.impl.auth.SystemDefaultCredentialsProvider;
71 import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
72 import org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner;
73 import org.apache.hc.client5.http.impl.routing.DefaultRoutePlanner;
74 import org.apache.hc.client5.http.impl.routing.SystemDefaultRoutePlanner;
75 import org.apache.hc.client5.http.nio.AsyncClientConnectionManager;
76 import org.apache.hc.client5.http.protocol.RedirectStrategy;
77 import org.apache.hc.client5.http.protocol.RequestAddCookies;
78 import org.apache.hc.client5.http.protocol.RequestAuthCache;
79 import org.apache.hc.client5.http.protocol.RequestDefaultHeaders;
80 import org.apache.hc.client5.http.protocol.RequestExpectContinue;
81 import org.apache.hc.client5.http.protocol.ResponseProcessCookies;
82 import org.apache.hc.client5.http.routing.HttpRoutePlanner;
83 import org.apache.hc.core5.annotation.Internal;
84 import org.apache.hc.core5.concurrent.DefaultThreadFactory;
85 import org.apache.hc.core5.function.Callback;
86 import org.apache.hc.core5.http.ConnectionReuseStrategy;
87 import org.apache.hc.core5.http.Header;
88 import org.apache.hc.core5.http.HttpException;
89 import org.apache.hc.core5.http.HttpHost;
90 import org.apache.hc.core5.http.HttpRequest;
91 import org.apache.hc.core5.http.HttpRequestInterceptor;
92 import org.apache.hc.core5.http.HttpResponse;
93 import org.apache.hc.core5.http.HttpResponseInterceptor;
94 import org.apache.hc.core5.http.config.CharCodingConfig;
95 import org.apache.hc.core5.http.config.Http1Config;
96 import org.apache.hc.core5.http.config.Lookup;
97 import org.apache.hc.core5.http.config.NamedElementChain;
98 import org.apache.hc.core5.http.config.RegistryBuilder;
99 import org.apache.hc.core5.http.impl.DefaultConnectionReuseStrategy;
100 import org.apache.hc.core5.http.nio.AsyncPushConsumer;
101 import org.apache.hc.core5.http.nio.HandlerFactory;
102 import org.apache.hc.core5.http.nio.command.ShutdownCommand;
103 import org.apache.hc.core5.http.protocol.DefaultHttpProcessor;
104 import org.apache.hc.core5.http.protocol.HttpContext;
105 import org.apache.hc.core5.http.protocol.HttpProcessor;
106 import org.apache.hc.core5.http.protocol.HttpProcessorBuilder;
107 import org.apache.hc.core5.http.protocol.RequestTargetHost;
108 import org.apache.hc.core5.http.protocol.RequestUserAgent;
109 import org.apache.hc.core5.http2.HttpVersionPolicy;
110 import org.apache.hc.core5.http2.config.H2Config;
111 import org.apache.hc.core5.http2.protocol.H2RequestConnControl;
112 import org.apache.hc.core5.http2.protocol.H2RequestContent;
113 import org.apache.hc.core5.http2.protocol.H2RequestTargetHost;
114 import org.apache.hc.core5.io.CloseMode;
115 import org.apache.hc.core5.pool.ConnPoolControl;
116 import org.apache.hc.core5.reactor.Command;
117 import org.apache.hc.core5.reactor.DefaultConnectingIOReactor;
118 import org.apache.hc.core5.reactor.IOEventHandlerFactory;
119 import org.apache.hc.core5.reactor.IOReactorConfig;
120 import org.apache.hc.core5.reactor.IOSession;
121 import org.apache.hc.core5.util.Args;
122 import org.apache.hc.core5.util.TimeValue;
123 import org.apache.hc.core5.util.VersionInfo;
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158 public class HttpAsyncClientBuilder {
159
160 private static class RequestInterceptorEntry {
161
162 enum Postion { FIRST, LAST }
163
164 final RequestInterceptorEntry.Postion postion;
165 final HttpRequestInterceptor interceptor;
166
167 private RequestInterceptorEntry(final RequestInterceptorEntry.Postion postion, final HttpRequestInterceptor interceptor) {
168 this.postion = postion;
169 this.interceptor = interceptor;
170 }
171 }
172
173 private static class ResponseInterceptorEntry {
174
175 enum Postion { FIRST, LAST }
176
177 final ResponseInterceptorEntry.Postion postion;
178 final HttpResponseInterceptor interceptor;
179
180 private ResponseInterceptorEntry(final ResponseInterceptorEntry.Postion postion, final HttpResponseInterceptor interceptor) {
181 this.postion = postion;
182 this.interceptor = interceptor;
183 }
184 }
185
186 private static class ExecInterceptorEntry {
187
188 enum Postion { BEFORE, AFTER, REPLACE, FIRST, LAST }
189
190 final ExecInterceptorEntry.Postion postion;
191 final String name;
192 final AsyncExecChainHandler interceptor;
193 final String existing;
194
195 private ExecInterceptorEntry(
196 final ExecInterceptorEntry.Postion postion,
197 final String name,
198 final AsyncExecChainHandler interceptor,
199 final String existing) {
200 this.postion = postion;
201 this.name = name;
202 this.interceptor = interceptor;
203 this.existing = existing;
204 }
205
206 }
207
208 private HttpVersionPolicy versionPolicy;
209 private AsyncClientConnectionManager connManager;
210 private boolean connManagerShared;
211 private IOReactorConfig ioReactorConfig;
212 private Http1Config h1Config;
213 private H2Config h2Config;
214 private CharCodingConfig charCodingConfig;
215 private SchemePortResolver schemePortResolver;
216 private ConnectionKeepAliveStrategy keepAliveStrategy;
217 private UserTokenHandler userTokenHandler;
218 private AuthenticationStrategy targetAuthStrategy;
219 private AuthenticationStrategy proxyAuthStrategy;
220
221 private LinkedList<RequestInterceptorEntry> requestInterceptors;
222 private LinkedList<ResponseInterceptorEntry> responseInterceptors;
223 private LinkedList<ExecInterceptorEntry> execInterceptors;
224
225 private HttpRoutePlanner routePlanner;
226 private RedirectStrategy redirectStrategy;
227 private HttpRequestRetryStrategy retryStrategy;
228
229 private ConnectionReuseStrategy reuseStrategy;
230
231 private Lookup<AuthSchemeFactory> authSchemeRegistry;
232 private Lookup<CookieSpecFactory> cookieSpecRegistry;
233 private CookieStore cookieStore;
234 private CredentialsProvider credentialsProvider;
235
236 private String userAgent;
237 private HttpHost proxy;
238 private Collection<? extends Header> defaultHeaders;
239 private RequestConfig defaultRequestConfig;
240 private boolean evictExpiredConnections;
241 private boolean evictIdleConnections;
242 private TimeValue maxIdleTime;
243
244 private boolean systemProperties;
245 private boolean automaticRetriesDisabled;
246 private boolean redirectHandlingDisabled;
247 private boolean cookieManagementDisabled;
248 private boolean authCachingDisabled;
249 private boolean connectionStateDisabled;
250
251 private ThreadFactory threadFactory;
252
253 private List<Closeable> closeables;
254
255 public static HttpAsyncClientBuilder create() {
256 return new HttpAsyncClientBuilder();
257 }
258
259 protected HttpAsyncClientBuilder() {
260 super();
261 }
262
263
264
265
266 public final HttpAsyncClientBuilder setVersionPolicy(final HttpVersionPolicy versionPolicy) {
267 this.versionPolicy = versionPolicy;
268 return this;
269 }
270
271
272
273
274 public final HttpAsyncClientBuilder setHttp1Config(final Http1Config h1Config) {
275 this.h1Config = h1Config;
276 return this;
277 }
278
279
280
281
282 public final HttpAsyncClientBuilder setH2Config(final H2Config h2Config) {
283 this.h2Config = h2Config;
284 return this;
285 }
286
287
288
289
290 public final HttpAsyncClientBuilder setConnectionManager(final AsyncClientConnectionManager connManager) {
291 this.connManager = connManager;
292 return this;
293 }
294
295
296
297
298
299
300
301
302
303
304
305
306 public final HttpAsyncClientBuilder setConnectionManagerShared(final boolean shared) {
307 this.connManagerShared = shared;
308 return this;
309 }
310
311
312
313
314 public final HttpAsyncClientBuilder setIOReactorConfig(final IOReactorConfig ioReactorConfig) {
315 this.ioReactorConfig = ioReactorConfig;
316 return this;
317 }
318
319
320
321
322 public final HttpAsyncClientBuilder setCharCodingConfig(final CharCodingConfig charCodingConfig) {
323 this.charCodingConfig = charCodingConfig;
324 return this;
325 }
326
327
328
329
330
331
332 public final HttpAsyncClientBuilder setConnectionReuseStrategy(final ConnectionReuseStrategy reuseStrategy) {
333 this.reuseStrategy = reuseStrategy;
334 return this;
335 }
336
337
338
339
340 public final HttpAsyncClientBuilder setKeepAliveStrategy(final ConnectionKeepAliveStrategy keepAliveStrategy) {
341 this.keepAliveStrategy = keepAliveStrategy;
342 return this;
343 }
344
345
346
347
348
349
350
351
352 public final HttpAsyncClientBuilder setUserTokenHandler(final UserTokenHandler userTokenHandler) {
353 this.userTokenHandler = userTokenHandler;
354 return this;
355 }
356
357
358
359
360
361 public final HttpAsyncClientBuilder setTargetAuthenticationStrategy(
362 final AuthenticationStrategy targetAuthStrategy) {
363 this.targetAuthStrategy = targetAuthStrategy;
364 return this;
365 }
366
367
368
369
370
371 public final HttpAsyncClientBuilder setProxyAuthenticationStrategy(
372 final AuthenticationStrategy proxyAuthStrategy) {
373 this.proxyAuthStrategy = proxyAuthStrategy;
374 return this;
375 }
376
377
378
379
380 public final HttpAsyncClientBuilder addResponseInterceptorFirst(final HttpResponseInterceptor interceptor) {
381 Args.notNull(interceptor, "Interceptor");
382 if (responseInterceptors == null) {
383 responseInterceptors = new LinkedList<>();
384 }
385 responseInterceptors.add(new ResponseInterceptorEntry(ResponseInterceptorEntry.Postion.FIRST, interceptor));
386 return this;
387 }
388
389
390
391
392 public final HttpAsyncClientBuilder addResponseInterceptorLast(final HttpResponseInterceptor interceptor) {
393 Args.notNull(interceptor, "Interceptor");
394 if (responseInterceptors == null) {
395 responseInterceptors = new LinkedList<>();
396 }
397 responseInterceptors.add(new ResponseInterceptorEntry(ResponseInterceptorEntry.Postion.LAST, interceptor));
398 return this;
399 }
400
401
402
403
404 public final HttpAsyncClientBuilder addExecInterceptorBefore(final String existing, final String name, final AsyncExecChainHandler interceptor) {
405 Args.notBlank(existing, "Existing");
406 Args.notBlank(name, "Name");
407 Args.notNull(interceptor, "Interceptor");
408 if (execInterceptors == null) {
409 execInterceptors = new LinkedList<>();
410 }
411 execInterceptors.add(new ExecInterceptorEntry(ExecInterceptorEntry.Postion.BEFORE, name, interceptor, existing));
412 return this;
413 }
414
415
416
417
418 public final HttpAsyncClientBuilder addExecInterceptorAfter(final String existing, final String name, final AsyncExecChainHandler interceptor) {
419 Args.notBlank(existing, "Existing");
420 Args.notBlank(name, "Name");
421 Args.notNull(interceptor, "Interceptor");
422 if (execInterceptors == null) {
423 execInterceptors = new LinkedList<>();
424 }
425 execInterceptors.add(new ExecInterceptorEntry(ExecInterceptorEntry.Postion.AFTER, name, interceptor, existing));
426 return this;
427 }
428
429
430
431
432 public final HttpAsyncClientBuilder replaceExecInterceptor(final String existing, final AsyncExecChainHandler interceptor) {
433 Args.notBlank(existing, "Existing");
434 Args.notNull(interceptor, "Interceptor");
435 if (execInterceptors == null) {
436 execInterceptors = new LinkedList<>();
437 }
438 execInterceptors.add(new ExecInterceptorEntry(ExecInterceptorEntry.Postion.REPLACE, existing, interceptor, existing));
439 return this;
440 }
441
442
443
444
445 public final HttpAsyncClientBuilder addExecInterceptorFirst(final String name, final AsyncExecChainHandler interceptor) {
446 Args.notNull(name, "Name");
447 Args.notNull(interceptor, "Interceptor");
448 if (execInterceptors == null) {
449 execInterceptors = new LinkedList<>();
450 }
451 execInterceptors.add(new ExecInterceptorEntry(ExecInterceptorEntry.Postion.FIRST, name, interceptor, null));
452 return this;
453 }
454
455
456
457
458 public final HttpAsyncClientBuilder addExecInterceptorLast(final String name, final AsyncExecChainHandler interceptor) {
459 Args.notNull(name, "Name");
460 Args.notNull(interceptor, "Interceptor");
461 if (execInterceptors == null) {
462 execInterceptors = new LinkedList<>();
463 }
464 execInterceptors.add(new ExecInterceptorEntry(ExecInterceptorEntry.Postion.LAST, name, interceptor, null));
465 return this;
466 }
467
468
469
470
471 public final HttpAsyncClientBuilder addRequestInterceptorFirst(final HttpRequestInterceptor interceptor) {
472 Args.notNull(interceptor, "Interceptor");
473 if (requestInterceptors == null) {
474 requestInterceptors = new LinkedList<>();
475 }
476 requestInterceptors.add(new RequestInterceptorEntry(RequestInterceptorEntry.Postion.FIRST, interceptor));
477 return this;
478 }
479
480
481
482
483 public final HttpAsyncClientBuilder addRequestInterceptorLast(final HttpRequestInterceptor interceptor) {
484 Args.notNull(interceptor, "Interceptor");
485 if (requestInterceptors == null) {
486 requestInterceptors = new LinkedList<>();
487 }
488 requestInterceptors.add(new RequestInterceptorEntry(RequestInterceptorEntry.Postion.LAST, interceptor));
489 return this;
490 }
491
492
493
494
495
496
497
498 public final HttpAsyncClientBuilder setRetryStrategy(final HttpRequestRetryStrategy retryStrategy) {
499 this.retryStrategy = retryStrategy;
500 return this;
501 }
502
503
504
505
506
507
508
509
510 public HttpAsyncClientBuilder setRedirectStrategy(final RedirectStrategy redirectStrategy) {
511 this.redirectStrategy = redirectStrategy;
512 return this;
513 }
514
515
516
517
518 public final HttpAsyncClientBuilder setSchemePortResolver(final SchemePortResolver schemePortResolver) {
519 this.schemePortResolver = schemePortResolver;
520 return this;
521 }
522
523
524
525
526 public final HttpAsyncClientBuilder setThreadFactory(final ThreadFactory threadFactory) {
527 this.threadFactory = threadFactory;
528 return this;
529 }
530
531
532
533
534 public final HttpAsyncClientBuilder setUserAgent(final String userAgent) {
535 this.userAgent = userAgent;
536 return this;
537 }
538
539
540
541
542 public final HttpAsyncClientBuilder setDefaultHeaders(final Collection<? extends Header> defaultHeaders) {
543 this.defaultHeaders = defaultHeaders;
544 return this;
545 }
546
547
548
549
550
551
552
553 public final HttpAsyncClientBuilder setProxy(final HttpHost proxy) {
554 this.proxy = proxy;
555 return this;
556 }
557
558
559
560
561 public final HttpAsyncClientBuilder setRoutePlanner(final HttpRoutePlanner routePlanner) {
562 this.routePlanner = routePlanner;
563 return this;
564 }
565
566
567
568
569
570
571 public final HttpAsyncClientBuilder setDefaultCredentialsProvider(final CredentialsProvider credentialsProvider) {
572 this.credentialsProvider = credentialsProvider;
573 return this;
574 }
575
576
577
578
579
580
581 public final HttpAsyncClientBuilder setDefaultAuthSchemeRegistry(final Lookup<AuthSchemeFactory> authSchemeRegistry) {
582 this.authSchemeRegistry = authSchemeRegistry;
583 return this;
584 }
585
586
587
588
589
590
591 public final HttpAsyncClientBuilder setDefaultCookieSpecRegistry(final Lookup<CookieSpecFactory> cookieSpecRegistry) {
592 this.cookieSpecRegistry = cookieSpecRegistry;
593 return this;
594 }
595
596
597
598
599
600 public final HttpAsyncClientBuilder setDefaultCookieStore(final CookieStore cookieStore) {
601 this.cookieStore = cookieStore;
602 return this;
603 }
604
605
606
607
608
609
610 public final HttpAsyncClientBuilder setDefaultRequestConfig(final RequestConfig config) {
611 this.defaultRequestConfig = config;
612 return this;
613 }
614
615
616
617
618
619 public final HttpAsyncClientBuilder useSystemProperties() {
620 this.systemProperties = true;
621 return this;
622 }
623
624
625
626
627 public final HttpAsyncClientBuilder disableConnectionState() {
628 connectionStateDisabled = true;
629 return this;
630 }
631
632
633
634
635 public final HttpAsyncClientBuilder disableRedirectHandling() {
636 redirectHandlingDisabled = true;
637 return this;
638 }
639
640
641
642
643 public final HttpAsyncClientBuilder disableAutomaticRetries() {
644 automaticRetriesDisabled = true;
645 return this;
646 }
647
648
649
650
651 public final HttpAsyncClientBuilder disableCookieManagement() {
652 this.cookieManagementDisabled = true;
653 return this;
654 }
655
656
657
658
659 public final HttpAsyncClientBuilder disableAuthCaching() {
660 this.authCachingDisabled = true;
661 return this;
662 }
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677 public final HttpAsyncClientBuilder evictExpiredConnections() {
678 evictExpiredConnections = true;
679 return this;
680 }
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699 public final HttpAsyncClientBuilder evictIdleConnections(final TimeValue maxIdleTime) {
700 this.evictIdleConnections = true;
701 this.maxIdleTime = maxIdleTime;
702 return this;
703 }
704
705
706
707
708
709
710 @Internal
711 protected void customizeExecChain(final NamedElementChain<AsyncExecChainHandler> execChainDefinition) {
712 }
713
714
715
716
717
718
719 @Internal
720 protected void addCloseable(final Closeable closeable) {
721 if (closeable == null) {
722 return;
723 }
724 if (closeables == null) {
725 closeables = new ArrayList<>();
726 }
727 closeables.add(closeable);
728 }
729
730 public CloseableHttpAsyncClient build() {
731 AsyncClientConnectionManager connManagerCopy = this.connManager;
732 if (connManagerCopy == null) {
733 connManagerCopy = PoolingAsyncClientConnectionManagerBuilder.create().build();
734 }
735
736 ConnectionKeepAliveStrategy keepAliveStrategyCopy = this.keepAliveStrategy;
737 if (keepAliveStrategyCopy == null) {
738 keepAliveStrategyCopy = DefaultConnectionKeepAliveStrategy.INSTANCE;
739 }
740
741 UserTokenHandler userTokenHandlerCopy = this.userTokenHandler;
742 if (userTokenHandlerCopy == null) {
743 if (!connectionStateDisabled) {
744 userTokenHandlerCopy = DefaultUserTokenHandler.INSTANCE;
745 } else {
746 userTokenHandlerCopy = NoopUserTokenHandler.INSTANCE;
747 }
748 }
749
750 final NamedElementChain<AsyncExecChainHandler> execChainDefinition = new NamedElementChain<>();
751 execChainDefinition.addLast(
752 new HttpAsyncMainClientExec(keepAliveStrategyCopy, userTokenHandlerCopy),
753 ChainElement.MAIN_TRANSPORT.name());
754
755 AuthenticationStrategy targetAuthStrategyCopy = this.targetAuthStrategy;
756 if (targetAuthStrategyCopy == null) {
757 targetAuthStrategyCopy = DefaultAuthenticationStrategy.INSTANCE;
758 }
759 AuthenticationStrategy proxyAuthStrategyCopy = this.proxyAuthStrategy;
760 if (proxyAuthStrategyCopy == null) {
761 proxyAuthStrategyCopy = DefaultAuthenticationStrategy.INSTANCE;
762 }
763
764 String userAgentCopy = this.userAgent;
765 if (userAgentCopy == null) {
766 if (systemProperties) {
767 userAgentCopy = getProperty("http.agent", null);
768 }
769 if (userAgentCopy == null) {
770 userAgentCopy = VersionInfo.getSoftwareInfo("Apache-HttpAsyncClient",
771 "org.apache.hc.client5", getClass());
772 }
773 }
774
775 execChainDefinition.addFirst(
776 new AsyncConnectExec(
777 new DefaultHttpProcessor(new RequestTargetHost(), new RequestUserAgent(userAgentCopy)),
778 proxyAuthStrategyCopy),
779 ChainElement.CONNECT.name());
780
781 final HttpProcessorBuilder b = HttpProcessorBuilder.create();
782 if (requestInterceptors != null) {
783 for (final RequestInterceptorEntry entry: requestInterceptors) {
784 if (entry.postion == RequestInterceptorEntry.Postion.FIRST) {
785 b.addFirst(entry.interceptor);
786 }
787 }
788 }
789 if (responseInterceptors != null) {
790 for (final ResponseInterceptorEntry entry: responseInterceptors) {
791 if (entry.postion == ResponseInterceptorEntry.Postion.FIRST) {
792 b.addFirst(entry.interceptor);
793 }
794 }
795 }
796 b.addAll(
797 new RequestDefaultHeaders(defaultHeaders),
798 new RequestUserAgent(userAgentCopy),
799 new RequestExpectContinue());
800 if (!cookieManagementDisabled) {
801 b.add(new RequestAddCookies());
802 }
803 if (!authCachingDisabled) {
804 b.add(new RequestAuthCache());
805 }
806 if (!cookieManagementDisabled) {
807 b.add(new ResponseProcessCookies());
808 }
809 if (requestInterceptors != null) {
810 for (final RequestInterceptorEntry entry: requestInterceptors) {
811 if (entry.postion == RequestInterceptorEntry.Postion.LAST) {
812 b.addLast(entry.interceptor);
813 }
814 }
815 }
816 if (responseInterceptors != null) {
817 for (final ResponseInterceptorEntry entry: responseInterceptors) {
818 if (entry.postion == ResponseInterceptorEntry.Postion.LAST) {
819 b.addLast(entry.interceptor);
820 }
821 }
822 }
823
824 final HttpProcessor httpProcessor = b.build();
825 execChainDefinition.addFirst(
826 new AsyncProtocolExec(httpProcessor, targetAuthStrategyCopy, proxyAuthStrategyCopy),
827 ChainElement.PROTOCOL.name());
828
829
830 if (!automaticRetriesDisabled) {
831 HttpRequestRetryStrategy retryStrategyCopy = this.retryStrategy;
832 if (retryStrategyCopy == null) {
833 retryStrategyCopy = DefaultHttpRequestRetryStrategy.INSTANCE;
834 }
835 execChainDefinition.addFirst(
836 new AsyncHttpRequestRetryExec(retryStrategyCopy),
837 ChainElement.RETRY.name());
838 }
839
840 HttpRoutePlanner routePlannerCopy = this.routePlanner;
841 if (routePlannerCopy == null) {
842 SchemePortResolver schemePortResolverCopy = this.schemePortResolver;
843 if (schemePortResolverCopy == null) {
844 schemePortResolverCopy = DefaultSchemePortResolver.INSTANCE;
845 }
846 if (proxy != null) {
847 routePlannerCopy = new DefaultProxyRoutePlanner(proxy, schemePortResolverCopy);
848 } else if (systemProperties) {
849 final ProxySelector defaultProxySelector = AccessController.doPrivileged(new PrivilegedAction<ProxySelector>() {
850 @Override
851 public ProxySelector run() {
852 return ProxySelector.getDefault();
853 }
854 });
855 routePlannerCopy = new SystemDefaultRoutePlanner(
856 schemePortResolverCopy, defaultProxySelector);
857 } else {
858 routePlannerCopy = new DefaultRoutePlanner(schemePortResolverCopy);
859 }
860 }
861
862
863 if (!redirectHandlingDisabled) {
864 RedirectStrategy redirectStrategyCopy = this.redirectStrategy;
865 if (redirectStrategyCopy == null) {
866 redirectStrategyCopy = DefaultRedirectStrategy.INSTANCE;
867 }
868 execChainDefinition.addFirst(
869 new AsyncRedirectExec(routePlannerCopy, redirectStrategyCopy),
870 ChainElement.REDIRECT.name());
871 }
872
873 List<Closeable> closeablesCopy = closeables != null ? new ArrayList<>(closeables) : null;
874 if (!this.connManagerShared) {
875 if (closeablesCopy == null) {
876 closeablesCopy = new ArrayList<>(1);
877 }
878 if (evictExpiredConnections || evictIdleConnections) {
879 if (connManagerCopy instanceof ConnPoolControl) {
880 final IdleConnectionEvictornEvictor.html#IdleConnectionEvictor">IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor((ConnPoolControl<?>) connManagerCopy,
881 maxIdleTime, maxIdleTime);
882 closeablesCopy.add(new Closeable() {
883
884 @Override
885 public void close() throws IOException {
886 connectionEvictor.shutdown();
887 }
888
889 });
890 connectionEvictor.start();
891 }
892 }
893 closeablesCopy.add(connManagerCopy);
894 }
895 ConnectionReuseStrategy reuseStrategyCopy = this.reuseStrategy;
896 if (reuseStrategyCopy == null) {
897 if (systemProperties) {
898 final String s = getProperty("http.keepAlive", "true");
899 if ("true".equalsIgnoreCase(s)) {
900 reuseStrategyCopy = DefaultConnectionReuseStrategy.INSTANCE;
901 } else {
902 reuseStrategyCopy = new ConnectionReuseStrategy() {
903 @Override
904 public boolean keepAlive(
905 final HttpRequest request, final HttpResponse response, final HttpContext context) {
906 return false;
907 }
908 };
909 }
910 } else {
911 reuseStrategyCopy = DefaultConnectionReuseStrategy.INSTANCE;
912 }
913 }
914 final AsyncPushConsumerRegistrymerRegistry.html#AsyncPushConsumerRegistry">AsyncPushConsumerRegistry pushConsumerRegistry = new AsyncPushConsumerRegistry();
915 final IOEventHandlerFactory ioEventHandlerFactory = new HttpAsyncClientEventHandlerFactory(
916 new DefaultHttpProcessor(new H2RequestContent(), new H2RequestTargetHost(), new H2RequestConnControl()),
917 new HandlerFactory<AsyncPushConsumer>() {
918
919 @Override
920 public AsyncPushConsumer create(final HttpRequest request, final HttpContext context) throws HttpException {
921 return pushConsumerRegistry.get(request);
922 }
923
924 },
925 versionPolicy != null ? versionPolicy : HttpVersionPolicy.NEGOTIATE,
926 h2Config != null ? h2Config : H2Config.DEFAULT,
927 h1Config != null ? h1Config : Http1Config.DEFAULT,
928 charCodingConfig != null ? charCodingConfig : CharCodingConfig.DEFAULT,
929 reuseStrategyCopy);
930 final DefaultConnectingIOReactor ioReactor = new DefaultConnectingIOReactor(
931 ioEventHandlerFactory,
932 ioReactorConfig != null ? ioReactorConfig : IOReactorConfig.DEFAULT,
933 threadFactory != null ? threadFactory : new DefaultThreadFactory("httpclient-dispatch", true),
934 LoggingIOSessionDecorator.INSTANCE,
935 LoggingExceptionCallback.INSTANCE,
936 null,
937 new Callback<IOSession>() {
938
939 @Override
940 public void execute(final IOSession ioSession) {
941 ioSession.enqueue(new ShutdownCommand(CloseMode.GRACEFUL), Command.Priority.IMMEDIATE);
942 }
943
944 });
945
946 if (execInterceptors != null) {
947 for (final ExecInterceptorEntry entry: execInterceptors) {
948 switch (entry.postion) {
949 case AFTER:
950 execChainDefinition.addAfter(entry.existing, entry.interceptor, entry.name);
951 break;
952 case BEFORE:
953 execChainDefinition.addBefore(entry.existing, entry.interceptor, entry.name);
954 break;
955 case REPLACE:
956 execChainDefinition.replace(entry.existing, entry.interceptor);
957 break;
958 case FIRST:
959 execChainDefinition.addFirst(entry.interceptor, entry.name);
960 break;
961 case LAST:
962
963
964 execChainDefinition.addBefore(ChainElement.MAIN_TRANSPORT.name(), entry.interceptor, entry.name);
965 break;
966 }
967 }
968 }
969
970 customizeExecChain(execChainDefinition);
971
972 NamedElementChain<AsyncExecChainHandler>.Node current = execChainDefinition.getLast();
973 AsyncExecChainElement execChain = null;
974 while (current != null) {
975 execChain = new AsyncExecChainElement(current.getValue(), execChain);
976 current = current.getPrevious();
977 }
978
979 Lookup<AuthSchemeFactory> authSchemeRegistryCopy = this.authSchemeRegistry;
980 if (authSchemeRegistryCopy == null) {
981 authSchemeRegistryCopy = RegistryBuilder.<AuthSchemeFactory>create()
982 .register(StandardAuthScheme.BASIC, BasicSchemeFactory.INSTANCE)
983 .register(StandardAuthScheme.DIGEST, DigestSchemeFactory.INSTANCE)
984 .register(StandardAuthScheme.NTLM, NTLMSchemeFactory.INSTANCE)
985 .register(StandardAuthScheme.SPNEGO, SPNegoSchemeFactory.DEFAULT)
986 .register(StandardAuthScheme.KERBEROS, KerberosSchemeFactory.DEFAULT)
987 .build();
988 }
989 Lookup<CookieSpecFactory> cookieSpecRegistryCopy = this.cookieSpecRegistry;
990 if (cookieSpecRegistryCopy == null) {
991 cookieSpecRegistryCopy = CookieSpecSupport.createDefault();
992 }
993
994 CookieStore cookieStoreCopy = this.cookieStore;
995 if (cookieStoreCopy == null) {
996 cookieStoreCopy = new BasicCookieStore();
997 }
998
999 CredentialsProvider credentialsProviderCopy = this.credentialsProvider;
1000 if (credentialsProviderCopy == null) {
1001 if (systemProperties) {
1002 credentialsProviderCopy = new SystemDefaultCredentialsProvider();
1003 } else {
1004 credentialsProviderCopy = new BasicCredentialsProvider();
1005 }
1006 }
1007
1008 return new InternalHttpAsyncClient(
1009 ioReactor,
1010 execChain,
1011 pushConsumerRegistry,
1012 threadFactory != null ? threadFactory : new DefaultThreadFactory("httpclient-main", true),
1013 connManagerCopy,
1014 routePlannerCopy,
1015 versionPolicy != null ? versionPolicy : HttpVersionPolicy.NEGOTIATE,
1016 cookieSpecRegistryCopy,
1017 authSchemeRegistryCopy,
1018 cookieStoreCopy,
1019 credentialsProviderCopy,
1020 defaultRequestConfig,
1021 closeablesCopy);
1022 }
1023
1024 private String getProperty(final String key, final String defaultValue) {
1025 return AccessController.doPrivileged(new PrivilegedAction<String>() {
1026 @Override
1027 public String run() {
1028 return System.getProperty(key, defaultValue);
1029 }
1030 });
1031 }
1032
1033 }