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