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