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