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.BearerSchemeFactory;
68 import org.apache.hc.client5.http.impl.auth.DigestSchemeFactory;
69 import org.apache.hc.client5.http.impl.auth.SystemDefaultCredentialsProvider;
70 import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
71 import org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner;
72 import org.apache.hc.client5.http.impl.routing.DefaultRoutePlanner;
73 import org.apache.hc.client5.http.impl.routing.SystemDefaultRoutePlanner;
74 import org.apache.hc.client5.http.nio.AsyncClientConnectionManager;
75 import org.apache.hc.client5.http.protocol.RedirectStrategy;
76 import org.apache.hc.client5.http.protocol.RequestAddCookies;
77 import org.apache.hc.client5.http.protocol.RequestDefaultHeaders;
78 import org.apache.hc.client5.http.protocol.RequestExpectContinue;
79 import org.apache.hc.client5.http.protocol.ResponseProcessCookies;
80 import org.apache.hc.client5.http.routing.HttpRoutePlanner;
81 import org.apache.hc.core5.annotation.Internal;
82 import org.apache.hc.core5.concurrent.DefaultThreadFactory;
83 import org.apache.hc.core5.function.Callback;
84 import org.apache.hc.core5.function.Decorator;
85 import org.apache.hc.core5.http.ConnectionReuseStrategy;
86 import org.apache.hc.core5.http.Header;
87 import org.apache.hc.core5.http.HttpHost;
88 import org.apache.hc.core5.http.HttpRequestInterceptor;
89 import org.apache.hc.core5.http.HttpResponseInterceptor;
90 import org.apache.hc.core5.http.config.CharCodingConfig;
91 import org.apache.hc.core5.http.config.Http1Config;
92 import org.apache.hc.core5.http.config.Lookup;
93 import org.apache.hc.core5.http.config.NamedElementChain;
94 import org.apache.hc.core5.http.config.RegistryBuilder;
95 import org.apache.hc.core5.http.nio.command.ShutdownCommand;
96 import org.apache.hc.core5.http.protocol.DefaultHttpProcessor;
97 import org.apache.hc.core5.http.protocol.HttpProcessor;
98 import org.apache.hc.core5.http.protocol.HttpProcessorBuilder;
99 import org.apache.hc.core5.http.protocol.RequestTargetHost;
100 import org.apache.hc.core5.http.protocol.RequestUserAgent;
101 import org.apache.hc.core5.http2.HttpVersionPolicy;
102 import org.apache.hc.core5.http2.config.H2Config;
103 import org.apache.hc.core5.http2.protocol.H2RequestConnControl;
104 import org.apache.hc.core5.http2.protocol.H2RequestContent;
105 import org.apache.hc.core5.http2.protocol.H2RequestTargetHost;
106 import org.apache.hc.core5.io.CloseMode;
107 import org.apache.hc.core5.pool.ConnPoolControl;
108 import org.apache.hc.core5.reactor.Command;
109 import org.apache.hc.core5.reactor.DefaultConnectingIOReactor;
110 import org.apache.hc.core5.reactor.IOEventHandlerFactory;
111 import org.apache.hc.core5.reactor.IOReactorConfig;
112 import org.apache.hc.core5.reactor.IOSession;
113 import org.apache.hc.core5.reactor.IOSessionListener;
114 import org.apache.hc.core5.util.Args;
115 import org.apache.hc.core5.util.TimeValue;
116 import org.apache.hc.core5.util.VersionInfo;
117
118
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 public class HttpAsyncClientBuilder {
152
153 private static class RequestInterceptorEntry {
154
155 enum Position { FIRST, LAST }
156
157 final RequestInterceptorEntry.Position position;
158 final HttpRequestInterceptor interceptor;
159
160 private RequestInterceptorEntry(final RequestInterceptorEntry.Position position, final HttpRequestInterceptor interceptor) {
161 this.position = position;
162 this.interceptor = interceptor;
163 }
164 }
165
166 private static class ResponseInterceptorEntry {
167
168 enum Position { FIRST, LAST }
169
170 final ResponseInterceptorEntry.Position position;
171 final HttpResponseInterceptor interceptor;
172
173 private ResponseInterceptorEntry(final ResponseInterceptorEntry.Position position, final HttpResponseInterceptor interceptor) {
174 this.position = position;
175 this.interceptor = interceptor;
176 }
177 }
178
179 private static class ExecInterceptorEntry {
180
181 enum Position { BEFORE, AFTER, REPLACE, FIRST, LAST }
182
183 final ExecInterceptorEntry.Position position;
184 final String name;
185 final AsyncExecChainHandler interceptor;
186 final String existing;
187
188 private ExecInterceptorEntry(
189 final ExecInterceptorEntry.Position position,
190 final String name,
191 final AsyncExecChainHandler interceptor,
192 final String existing) {
193 this.position = position;
194 this.name = name;
195 this.interceptor = interceptor;
196 this.existing = existing;
197 }
198
199 }
200
201
202
203
204 @Deprecated
205 private TlsConfig tlsConfig;
206 private AsyncClientConnectionManager connManager;
207 private boolean connManagerShared;
208 private IOReactorConfig ioReactorConfig;
209 private IOSessionListener ioSessionListener;
210 private Callback<Exception> ioReactorExceptionCallback;
211 private Http1Config h1Config;
212 private H2Config h2Config;
213 private CharCodingConfig charCodingConfig;
214 private SchemePortResolver schemePortResolver;
215 private ConnectionKeepAliveStrategy keepAliveStrategy;
216 private UserTokenHandler userTokenHandler;
217 private AuthenticationStrategy targetAuthStrategy;
218 private AuthenticationStrategy proxyAuthStrategy;
219 private Decorator<IOSession> ioSessionDecorator;
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 private ProxySelector proxySelector;
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
589
590
591 public final HttpAsyncClientBuilder setProxySelector(final ProxySelector proxySelector) {
592 this.proxySelector = proxySelector;
593 return this;
594 }
595
596
597
598
599
600
601
602 public final HttpAsyncClientBuilder setProxy(final HttpHost proxy) {
603 this.proxy = proxy;
604 return this;
605 }
606
607
608
609
610 public final HttpAsyncClientBuilder setRoutePlanner(final HttpRoutePlanner routePlanner) {
611 this.routePlanner = routePlanner;
612 return this;
613 }
614
615
616
617
618
619
620 public final HttpAsyncClientBuilder setDefaultCredentialsProvider(final CredentialsProvider credentialsProvider) {
621 this.credentialsProvider = credentialsProvider;
622 return this;
623 }
624
625
626
627
628
629
630 public final HttpAsyncClientBuilder setDefaultAuthSchemeRegistry(final Lookup<AuthSchemeFactory> authSchemeRegistry) {
631 this.authSchemeRegistry = authSchemeRegistry;
632 return this;
633 }
634
635
636
637
638
639
640 public final HttpAsyncClientBuilder setDefaultCookieSpecRegistry(final Lookup<CookieSpecFactory> cookieSpecRegistry) {
641 this.cookieSpecRegistry = cookieSpecRegistry;
642 return this;
643 }
644
645
646
647
648
649 public final HttpAsyncClientBuilder setDefaultCookieStore(final CookieStore cookieStore) {
650 this.cookieStore = cookieStore;
651 return this;
652 }
653
654
655
656
657
658
659 public final HttpAsyncClientBuilder setDefaultRequestConfig(final RequestConfig config) {
660 this.defaultRequestConfig = config;
661 return this;
662 }
663
664
665
666
667
668 public final HttpAsyncClientBuilder useSystemProperties() {
669 this.systemProperties = true;
670 return this;
671 }
672
673
674
675
676 public final HttpAsyncClientBuilder disableConnectionState() {
677 connectionStateDisabled = true;
678 return this;
679 }
680
681
682
683
684 public final HttpAsyncClientBuilder disableRedirectHandling() {
685 redirectHandlingDisabled = true;
686 return this;
687 }
688
689
690
691
692 public final HttpAsyncClientBuilder disableAutomaticRetries() {
693 automaticRetriesDisabled = true;
694 return this;
695 }
696
697
698
699
700 public final HttpAsyncClientBuilder disableCookieManagement() {
701 this.cookieManagementDisabled = true;
702 return this;
703 }
704
705
706
707
708 public final HttpAsyncClientBuilder disableAuthCaching() {
709 this.authCachingDisabled = true;
710 return this;
711 }
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726 public final HttpAsyncClientBuilder evictExpiredConnections() {
727 evictExpiredConnections = true;
728 return this;
729 }
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748 public final HttpAsyncClientBuilder evictIdleConnections(final TimeValue maxIdleTime) {
749 this.evictIdleConnections = true;
750 this.maxIdleTime = maxIdleTime;
751 return this;
752 }
753
754
755
756
757
758
759 @Internal
760 protected void customizeExecChain(final NamedElementChain<AsyncExecChainHandler> execChainDefinition) {
761 }
762
763
764
765
766
767
768 @Internal
769 protected void addCloseable(final Closeable closeable) {
770 if (closeable == null) {
771 return;
772 }
773 if (closeables == null) {
774 closeables = new ArrayList<>();
775 }
776 closeables.add(closeable);
777 }
778 @SuppressWarnings("deprecated")
779 public CloseableHttpAsyncClient build() {
780 AsyncClientConnectionManager connManagerCopy = this.connManager;
781 if (connManagerCopy == null) {
782 connManagerCopy = PoolingAsyncClientConnectionManagerBuilder.create().build();
783 }
784
785 ConnectionKeepAliveStrategy keepAliveStrategyCopy = this.keepAliveStrategy;
786 if (keepAliveStrategyCopy == null) {
787 keepAliveStrategyCopy = DefaultConnectionKeepAliveStrategy.INSTANCE;
788 }
789
790 UserTokenHandler userTokenHandlerCopy = this.userTokenHandler;
791 if (userTokenHandlerCopy == null) {
792 if (!connectionStateDisabled) {
793 userTokenHandlerCopy = DefaultUserTokenHandler.INSTANCE;
794 } else {
795 userTokenHandlerCopy = NoopUserTokenHandler.INSTANCE;
796 }
797 }
798
799 AuthenticationStrategy targetAuthStrategyCopy = this.targetAuthStrategy;
800 if (targetAuthStrategyCopy == null) {
801 targetAuthStrategyCopy = DefaultAuthenticationStrategy.INSTANCE;
802 }
803 AuthenticationStrategy proxyAuthStrategyCopy = this.proxyAuthStrategy;
804 if (proxyAuthStrategyCopy == null) {
805 proxyAuthStrategyCopy = DefaultAuthenticationStrategy.INSTANCE;
806 }
807
808 String userAgentCopy = this.userAgent;
809 if (userAgentCopy == null) {
810 if (systemProperties) {
811 userAgentCopy = getProperty("http.agent", null);
812 }
813 if (userAgentCopy == null) {
814 userAgentCopy = VersionInfo.getSoftwareInfo("Apache-HttpAsyncClient",
815 "org.apache.hc.client5", getClass());
816 }
817 }
818
819 final HttpProcessorBuilder b = HttpProcessorBuilder.create();
820 if (requestInterceptors != null) {
821 for (final RequestInterceptorEntry entry: requestInterceptors) {
822 if (entry.position == RequestInterceptorEntry.Position.FIRST) {
823 b.addFirst(entry.interceptor);
824 }
825 }
826 }
827 if (responseInterceptors != null) {
828 for (final ResponseInterceptorEntry entry: responseInterceptors) {
829 if (entry.position == ResponseInterceptorEntry.Position.FIRST) {
830 b.addFirst(entry.interceptor);
831 }
832 }
833 }
834 b.addAll(
835 new H2RequestTargetHost(),
836 new RequestDefaultHeaders(defaultHeaders),
837 new RequestUserAgent(userAgentCopy),
838 new RequestExpectContinue(),
839 new H2RequestContent(),
840 new H2RequestConnControl());
841 if (!cookieManagementDisabled) {
842 b.add(RequestAddCookies.INSTANCE);
843 }
844 if (!cookieManagementDisabled) {
845 b.add(ResponseProcessCookies.INSTANCE);
846 }
847 if (requestInterceptors != null) {
848 for (final RequestInterceptorEntry entry: requestInterceptors) {
849 if (entry.position == RequestInterceptorEntry.Position.LAST) {
850 b.addLast(entry.interceptor);
851 }
852 }
853 }
854 if (responseInterceptors != null) {
855 for (final ResponseInterceptorEntry entry: responseInterceptors) {
856 if (entry.position == ResponseInterceptorEntry.Position.LAST) {
857 b.addLast(entry.interceptor);
858 }
859 }
860 }
861
862 final HttpProcessor httpProcessor = b.build();
863
864 final NamedElementChain<AsyncExecChainHandler> execChainDefinition = new NamedElementChain<>();
865 execChainDefinition.addLast(
866 new HttpAsyncMainClientExec(httpProcessor, keepAliveStrategyCopy, userTokenHandlerCopy),
867 ChainElement.MAIN_TRANSPORT.name());
868
869 execChainDefinition.addFirst(
870 new AsyncConnectExec(
871 new DefaultHttpProcessor(new RequestTargetHost(), new RequestUserAgent(userAgentCopy)),
872 proxyAuthStrategyCopy,
873 schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE,
874 authCachingDisabled),
875 ChainElement.CONNECT.name());
876
877 execChainDefinition.addFirst(
878 new AsyncProtocolExec(
879 targetAuthStrategyCopy,
880 proxyAuthStrategyCopy,
881 schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE,
882 authCachingDisabled),
883 ChainElement.PROTOCOL.name());
884
885
886 if (!automaticRetriesDisabled) {
887 HttpRequestRetryStrategy retryStrategyCopy = this.retryStrategy;
888 if (retryStrategyCopy == null) {
889 retryStrategyCopy = DefaultHttpRequestRetryStrategy.INSTANCE;
890 }
891 execChainDefinition.addFirst(
892 new AsyncHttpRequestRetryExec(retryStrategyCopy),
893 ChainElement.RETRY.name());
894 }
895
896 HttpRoutePlanner routePlannerCopy = this.routePlanner;
897 if (routePlannerCopy == null) {
898 SchemePortResolver schemePortResolverCopy = this.schemePortResolver;
899 if (schemePortResolverCopy == null) {
900 schemePortResolverCopy = DefaultSchemePortResolver.INSTANCE;
901 }
902 if (proxy != null) {
903 routePlannerCopy = new DefaultProxyRoutePlanner(proxy, schemePortResolverCopy);
904 } else if (this.proxySelector != null) {
905 routePlannerCopy = new SystemDefaultRoutePlanner(schemePortResolverCopy, this.proxySelector);
906 } else if (systemProperties) {
907 final ProxySelector defaultProxySelector = AccessController.doPrivileged((PrivilegedAction<ProxySelector>) ProxySelector::getDefault);
908 routePlannerCopy = new SystemDefaultRoutePlanner(schemePortResolverCopy, defaultProxySelector);
909 } else {
910 routePlannerCopy = new DefaultRoutePlanner(schemePortResolverCopy);
911 }
912 }
913
914
915 if (!redirectHandlingDisabled) {
916 RedirectStrategy redirectStrategyCopy = this.redirectStrategy;
917 if (redirectStrategyCopy == null) {
918 redirectStrategyCopy = DefaultRedirectStrategy.INSTANCE;
919 }
920 execChainDefinition.addFirst(
921 new AsyncRedirectExec(routePlannerCopy, redirectStrategyCopy),
922 ChainElement.REDIRECT.name());
923 }
924
925 List<Closeable> closeablesCopy = closeables != null ? new ArrayList<>(closeables) : null;
926 if (!this.connManagerShared) {
927 if (closeablesCopy == null) {
928 closeablesCopy = new ArrayList<>(1);
929 }
930 if (evictExpiredConnections || evictIdleConnections) {
931 if (connManagerCopy instanceof ConnPoolControl) {
932 final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor((ConnPoolControl<?>) connManagerCopy,
933 maxIdleTime, maxIdleTime);
934 closeablesCopy.add(connectionEvictor::shutdown);
935 connectionEvictor.start();
936 }
937 }
938 closeablesCopy.add(connManagerCopy);
939 }
940 ConnectionReuseStrategy reuseStrategyCopy = this.reuseStrategy;
941 if (reuseStrategyCopy == null) {
942 if (systemProperties) {
943 final String s = getProperty("http.keepAlive", "true");
944 if ("true".equalsIgnoreCase(s)) {
945 reuseStrategyCopy = DefaultClientConnectionReuseStrategy.INSTANCE;
946 } else {
947 reuseStrategyCopy = (request, response, context) -> false;
948 }
949 } else {
950 reuseStrategyCopy = DefaultClientConnectionReuseStrategy.INSTANCE;
951 }
952 }
953 final AsyncPushConsumerRegistry pushConsumerRegistry = new AsyncPushConsumerRegistry();
954 final IOEventHandlerFactory ioEventHandlerFactory = new HttpAsyncClientProtocolNegotiationStarter(
955 HttpProcessorBuilder.create().build(),
956 (request, context) -> pushConsumerRegistry.get(request),
957 h2Config != null ? h2Config : H2Config.DEFAULT,
958 h1Config != null ? h1Config : Http1Config.DEFAULT,
959 charCodingConfig != null ? charCodingConfig : CharCodingConfig.DEFAULT,
960 reuseStrategyCopy);
961 final DefaultConnectingIOReactor ioReactor = new DefaultConnectingIOReactor(
962 ioEventHandlerFactory,
963 ioReactorConfig != null ? ioReactorConfig : IOReactorConfig.DEFAULT,
964 threadFactory != null ? threadFactory : new DefaultThreadFactory("httpclient-dispatch", true),
965 ioSessionDecorator != null ? ioSessionDecorator : LoggingIOSessionDecorator.INSTANCE,
966 ioReactorExceptionCallback != null ? ioReactorExceptionCallback : LoggingExceptionCallback.INSTANCE,
967 ioSessionListener,
968 ioSession -> ioSession.enqueue(new ShutdownCommand(CloseMode.GRACEFUL), Command.Priority.IMMEDIATE));
969
970 if (execInterceptors != null) {
971 for (final ExecInterceptorEntry entry: execInterceptors) {
972 switch (entry.position) {
973 case AFTER:
974 execChainDefinition.addAfter(entry.existing, entry.interceptor, entry.name);
975 break;
976 case BEFORE:
977 execChainDefinition.addBefore(entry.existing, entry.interceptor, entry.name);
978 break;
979 case REPLACE:
980 execChainDefinition.replace(entry.existing, entry.interceptor);
981 break;
982 case FIRST:
983 execChainDefinition.addFirst(entry.interceptor, entry.name);
984 break;
985 case LAST:
986
987
988 execChainDefinition.addBefore(ChainElement.MAIN_TRANSPORT.name(), entry.interceptor, entry.name);
989 break;
990 }
991 }
992 }
993
994 customizeExecChain(execChainDefinition);
995
996 NamedElementChain<AsyncExecChainHandler>.Node current = execChainDefinition.getLast();
997 AsyncExecChainElement execChain = null;
998 while (current != null) {
999 execChain = new AsyncExecChainElement(current.getValue(), execChain);
1000 current = current.getPrevious();
1001 }
1002
1003 Lookup<AuthSchemeFactory> authSchemeRegistryCopy = this.authSchemeRegistry;
1004 if (authSchemeRegistryCopy == null) {
1005 authSchemeRegistryCopy = RegistryBuilder.<AuthSchemeFactory>create()
1006 .register(StandardAuthScheme.BASIC, BasicSchemeFactory.INSTANCE)
1007 .register(StandardAuthScheme.DIGEST, DigestSchemeFactory.INSTANCE)
1008 .register(StandardAuthScheme.BEARER, BearerSchemeFactory.INSTANCE)
1009 .build();
1010 }
1011 Lookup<CookieSpecFactory> cookieSpecRegistryCopy = this.cookieSpecRegistry;
1012 if (cookieSpecRegistryCopy == null) {
1013 cookieSpecRegistryCopy = CookieSpecSupport.createDefault();
1014 }
1015
1016 CookieStore cookieStoreCopy = this.cookieStore;
1017 if (cookieStoreCopy == null) {
1018 cookieStoreCopy = new BasicCookieStore();
1019 }
1020
1021 CredentialsProvider credentialsProviderCopy = this.credentialsProvider;
1022 if (credentialsProviderCopy == null) {
1023 if (systemProperties) {
1024 credentialsProviderCopy = new SystemDefaultCredentialsProvider();
1025 } else {
1026 credentialsProviderCopy = new BasicCredentialsProvider();
1027 }
1028 }
1029
1030 return new InternalHttpAsyncClient(
1031 ioReactor,
1032 execChain,
1033 pushConsumerRegistry,
1034 threadFactory != null ? threadFactory : new DefaultThreadFactory("httpclient-main", true),
1035 connManagerCopy,
1036 routePlannerCopy,
1037 tlsConfig,
1038 cookieSpecRegistryCopy,
1039 authSchemeRegistryCopy,
1040 cookieStoreCopy,
1041 credentialsProviderCopy,
1042 defaultRequestConfig,
1043 closeablesCopy);
1044 }
1045
1046 private String getProperty(final String key, final String defaultValue) {
1047 return AccessController.doPrivileged((PrivilegedAction<String>) () -> System.getProperty(key, defaultValue));
1048 }
1049
1050 }