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