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 final PoolingAsyncClientConnectionManagerBuilder connectionManagerBuilder = PoolingAsyncClientConnectionManagerBuilder.create();
783 if (systemProperties) {
784 connectionManagerBuilder.useSystemProperties();
785 }
786 connManagerCopy = connectionManagerBuilder.build();
787 }
788
789 ConnectionKeepAliveStrategy keepAliveStrategyCopy = this.keepAliveStrategy;
790 if (keepAliveStrategyCopy == null) {
791 keepAliveStrategyCopy = DefaultConnectionKeepAliveStrategy.INSTANCE;
792 }
793
794 UserTokenHandler userTokenHandlerCopy = this.userTokenHandler;
795 if (userTokenHandlerCopy == null) {
796 if (!connectionStateDisabled) {
797 userTokenHandlerCopy = DefaultUserTokenHandler.INSTANCE;
798 } else {
799 userTokenHandlerCopy = NoopUserTokenHandler.INSTANCE;
800 }
801 }
802
803 AuthenticationStrategy targetAuthStrategyCopy = this.targetAuthStrategy;
804 if (targetAuthStrategyCopy == null) {
805 targetAuthStrategyCopy = DefaultAuthenticationStrategy.INSTANCE;
806 }
807 AuthenticationStrategy proxyAuthStrategyCopy = this.proxyAuthStrategy;
808 if (proxyAuthStrategyCopy == null) {
809 proxyAuthStrategyCopy = DefaultAuthenticationStrategy.INSTANCE;
810 }
811
812 String userAgentCopy = this.userAgent;
813 if (userAgentCopy == null) {
814 if (systemProperties) {
815 userAgentCopy = getProperty("http.agent", null);
816 }
817 if (userAgentCopy == null) {
818 userAgentCopy = VersionInfo.getSoftwareInfo("Apache-HttpAsyncClient",
819 "org.apache.hc.client5", getClass());
820 }
821 }
822
823 final HttpProcessorBuilder b = HttpProcessorBuilder.create();
824 if (requestInterceptors != null) {
825 for (final RequestInterceptorEntry entry: requestInterceptors) {
826 if (entry.position == RequestInterceptorEntry.Position.FIRST) {
827 b.addFirst(entry.interceptor);
828 }
829 }
830 }
831 if (responseInterceptors != null) {
832 for (final ResponseInterceptorEntry entry: responseInterceptors) {
833 if (entry.position == ResponseInterceptorEntry.Position.FIRST) {
834 b.addFirst(entry.interceptor);
835 }
836 }
837 }
838 b.addAll(
839 new RequestDefaultHeaders(defaultHeaders),
840 new RequestUserAgent(userAgentCopy),
841 new RequestExpectContinue(),
842 new H2RequestContent(),
843 new H2RequestTargetHost(),
844 new H2RequestConnControl());
845 if (!cookieManagementDisabled) {
846 b.add(RequestAddCookies.INSTANCE);
847 }
848 if (!cookieManagementDisabled) {
849 b.add(ResponseProcessCookies.INSTANCE);
850 }
851 if (requestInterceptors != null) {
852 for (final RequestInterceptorEntry entry: requestInterceptors) {
853 if (entry.position == RequestInterceptorEntry.Position.LAST) {
854 b.addLast(entry.interceptor);
855 }
856 }
857 }
858 if (responseInterceptors != null) {
859 for (final ResponseInterceptorEntry entry: responseInterceptors) {
860 if (entry.position == ResponseInterceptorEntry.Position.LAST) {
861 b.addLast(entry.interceptor);
862 }
863 }
864 }
865
866 final HttpProcessor httpProcessor = b.build();
867
868 final NamedElementChain<AsyncExecChainHandler> execChainDefinition = new NamedElementChain<>();
869 execChainDefinition.addLast(
870 new HttpAsyncMainClientExec(httpProcessor, keepAliveStrategyCopy, userTokenHandlerCopy),
871 ChainElement.MAIN_TRANSPORT.name());
872
873 execChainDefinition.addFirst(
874 new AsyncConnectExec(
875 new DefaultHttpProcessor(new RequestTargetHost(), new RequestUserAgent(userAgentCopy)),
876 proxyAuthStrategyCopy,
877 schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE,
878 authCachingDisabled),
879 ChainElement.CONNECT.name());
880
881 execChainDefinition.addFirst(
882 new AsyncProtocolExec(
883 targetAuthStrategyCopy,
884 proxyAuthStrategyCopy,
885 schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE,
886 authCachingDisabled),
887 ChainElement.PROTOCOL.name());
888
889
890 if (!automaticRetriesDisabled) {
891 HttpRequestRetryStrategy retryStrategyCopy = this.retryStrategy;
892 if (retryStrategyCopy == null) {
893 retryStrategyCopy = DefaultHttpRequestRetryStrategy.INSTANCE;
894 }
895 execChainDefinition.addFirst(
896 new AsyncHttpRequestRetryExec(retryStrategyCopy),
897 ChainElement.RETRY.name());
898 }
899
900 HttpRoutePlanner routePlannerCopy = this.routePlanner;
901 if (routePlannerCopy == null) {
902 SchemePortResolver schemePortResolverCopy = this.schemePortResolver;
903 if (schemePortResolverCopy == null) {
904 schemePortResolverCopy = DefaultSchemePortResolver.INSTANCE;
905 }
906 if (proxy != null) {
907 routePlannerCopy = new DefaultProxyRoutePlanner(proxy, schemePortResolverCopy);
908 } else if (this.proxySelector != null) {
909 routePlannerCopy = new SystemDefaultRoutePlanner(schemePortResolverCopy, this.proxySelector);
910 } else if (systemProperties) {
911 final ProxySelector defaultProxySelector = AccessController.doPrivileged((PrivilegedAction<ProxySelector>) ProxySelector::getDefault);
912 routePlannerCopy = new SystemDefaultRoutePlanner(schemePortResolverCopy, defaultProxySelector);
913 } else {
914 routePlannerCopy = new DefaultRoutePlanner(schemePortResolverCopy);
915 }
916 }
917
918
919 if (!redirectHandlingDisabled) {
920 RedirectStrategy redirectStrategyCopy = this.redirectStrategy;
921 if (redirectStrategyCopy == null) {
922 redirectStrategyCopy = DefaultRedirectStrategy.INSTANCE;
923 }
924 execChainDefinition.addFirst(
925 new AsyncRedirectExec(routePlannerCopy, redirectStrategyCopy),
926 ChainElement.REDIRECT.name());
927 }
928
929 List<Closeable> closeablesCopy = closeables != null ? new ArrayList<>(closeables) : null;
930 if (!this.connManagerShared) {
931 if (closeablesCopy == null) {
932 closeablesCopy = new ArrayList<>(1);
933 }
934 if (evictExpiredConnections || evictIdleConnections) {
935 if (connManagerCopy instanceof ConnPoolControl) {
936 final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor((ConnPoolControl<?>) connManagerCopy,
937 maxIdleTime, maxIdleTime);
938 closeablesCopy.add(connectionEvictor::shutdown);
939 connectionEvictor.start();
940 }
941 }
942 closeablesCopy.add(connManagerCopy);
943 }
944 ConnectionReuseStrategy reuseStrategyCopy = this.reuseStrategy;
945 if (reuseStrategyCopy == null) {
946 if (systemProperties) {
947 final String s = getProperty("http.keepAlive", "true");
948 if ("true".equalsIgnoreCase(s)) {
949 reuseStrategyCopy = DefaultClientConnectionReuseStrategy.INSTANCE;
950 } else {
951 reuseStrategyCopy = (request, response, context) -> false;
952 }
953 } else {
954 reuseStrategyCopy = DefaultClientConnectionReuseStrategy.INSTANCE;
955 }
956 }
957 final AsyncPushConsumerRegistry pushConsumerRegistry = new AsyncPushConsumerRegistry();
958 final IOEventHandlerFactory ioEventHandlerFactory = new HttpAsyncClientProtocolNegotiationStarter(
959 HttpProcessorBuilder.create().build(),
960 (request, context) -> pushConsumerRegistry.get(request),
961 h2Config != null ? h2Config : H2Config.DEFAULT,
962 h1Config != null ? h1Config : Http1Config.DEFAULT,
963 charCodingConfig != null ? charCodingConfig : CharCodingConfig.DEFAULT,
964 reuseStrategyCopy);
965 final DefaultConnectingIOReactor ioReactor = new DefaultConnectingIOReactor(
966 ioEventHandlerFactory,
967 ioReactorConfig != null ? ioReactorConfig : IOReactorConfig.DEFAULT,
968 threadFactory != null ? threadFactory : new DefaultThreadFactory("httpclient-dispatch", true),
969 ioSessionDecorator != null ? ioSessionDecorator : LoggingIOSessionDecorator.INSTANCE,
970 ioReactorExceptionCallback != null ? ioReactorExceptionCallback : LoggingExceptionCallback.INSTANCE,
971 ioSessionListener,
972 ioSession -> ioSession.enqueue(new ShutdownCommand(CloseMode.GRACEFUL), Command.Priority.IMMEDIATE));
973
974 if (execInterceptors != null) {
975 for (final ExecInterceptorEntry entry: execInterceptors) {
976 switch (entry.position) {
977 case AFTER:
978 execChainDefinition.addAfter(entry.existing, entry.interceptor, entry.name);
979 break;
980 case BEFORE:
981 execChainDefinition.addBefore(entry.existing, entry.interceptor, entry.name);
982 break;
983 case REPLACE:
984 execChainDefinition.replace(entry.existing, entry.interceptor);
985 break;
986 case FIRST:
987 execChainDefinition.addFirst(entry.interceptor, entry.name);
988 break;
989 case LAST:
990
991
992 execChainDefinition.addBefore(ChainElement.MAIN_TRANSPORT.name(), entry.interceptor, entry.name);
993 break;
994 }
995 }
996 }
997
998 customizeExecChain(execChainDefinition);
999
1000 NamedElementChain<AsyncExecChainHandler>.Node current = execChainDefinition.getLast();
1001 AsyncExecChainElement execChain = null;
1002 while (current != null) {
1003 execChain = new AsyncExecChainElement(current.getValue(), execChain);
1004 current = current.getPrevious();
1005 }
1006
1007 Lookup<AuthSchemeFactory> authSchemeRegistryCopy = this.authSchemeRegistry;
1008 if (authSchemeRegistryCopy == null) {
1009 authSchemeRegistryCopy = RegistryBuilder.<AuthSchemeFactory>create()
1010 .register(StandardAuthScheme.BASIC, BasicSchemeFactory.INSTANCE)
1011 .register(StandardAuthScheme.DIGEST, DigestSchemeFactory.INSTANCE)
1012 .register(StandardAuthScheme.BEARER, BearerSchemeFactory.INSTANCE)
1013 .build();
1014 }
1015 Lookup<CookieSpecFactory> cookieSpecRegistryCopy = this.cookieSpecRegistry;
1016 if (cookieSpecRegistryCopy == null) {
1017 cookieSpecRegistryCopy = CookieSpecSupport.createDefault();
1018 }
1019
1020 CookieStore cookieStoreCopy = this.cookieStore;
1021 if (cookieStoreCopy == null) {
1022 cookieStoreCopy = new BasicCookieStore();
1023 }
1024
1025 CredentialsProvider credentialsProviderCopy = this.credentialsProvider;
1026 if (credentialsProviderCopy == null) {
1027 if (systemProperties) {
1028 credentialsProviderCopy = new SystemDefaultCredentialsProvider();
1029 } else {
1030 credentialsProviderCopy = new BasicCredentialsProvider();
1031 }
1032 }
1033
1034 return new InternalHttpAsyncClient(
1035 ioReactor,
1036 execChain,
1037 pushConsumerRegistry,
1038 threadFactory != null ? threadFactory : new DefaultThreadFactory("httpclient-main", true),
1039 connManagerCopy,
1040 routePlannerCopy,
1041 tlsConfig,
1042 cookieSpecRegistryCopy,
1043 authSchemeRegistryCopy,
1044 cookieStoreCopy,
1045 credentialsProviderCopy,
1046 defaultRequestConfig,
1047 closeablesCopy);
1048 }
1049
1050 private String getProperty(final String key, final String defaultValue) {
1051 return AccessController.doPrivileged((PrivilegedAction<String>) () -> System.getProperty(key, defaultValue));
1052 }
1053
1054 }