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