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