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