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 connManagerCopy = PoolingHttpClientConnectionManagerBuilder.create().build();
753 }
754 ConnectionReuseStrategy reuseStrategyCopy = this.reuseStrategy;
755 if (reuseStrategyCopy == null) {
756 if (systemProperties) {
757 final String s = System.getProperty("http.keepAlive", "true");
758 if ("true".equalsIgnoreCase(s)) {
759 reuseStrategyCopy = DefaultClientConnectionReuseStrategy.INSTANCE;
760 } else {
761 reuseStrategyCopy = (request, response, context) -> false;
762 }
763 } else {
764 reuseStrategyCopy = DefaultClientConnectionReuseStrategy.INSTANCE;
765 }
766 }
767
768 ConnectionKeepAliveStrategy keepAliveStrategyCopy = this.keepAliveStrategy;
769 if (keepAliveStrategyCopy == null) {
770 keepAliveStrategyCopy = DefaultConnectionKeepAliveStrategy.INSTANCE;
771 }
772 AuthenticationStrategy targetAuthStrategyCopy = this.targetAuthStrategy;
773 if (targetAuthStrategyCopy == null) {
774 targetAuthStrategyCopy = DefaultAuthenticationStrategy.INSTANCE;
775 }
776 AuthenticationStrategy proxyAuthStrategyCopy = this.proxyAuthStrategy;
777 if (proxyAuthStrategyCopy == null) {
778 proxyAuthStrategyCopy = DefaultAuthenticationStrategy.INSTANCE;
779 }
780 UserTokenHandler userTokenHandlerCopy = this.userTokenHandler;
781 if (userTokenHandlerCopy == null) {
782 if (!connectionStateDisabled) {
783 userTokenHandlerCopy = DefaultUserTokenHandler.INSTANCE;
784 } else {
785 userTokenHandlerCopy = NoopUserTokenHandler.INSTANCE;
786 }
787 }
788
789 String userAgentCopy = this.userAgent;
790 if (userAgentCopy == null) {
791 if (systemProperties) {
792 userAgentCopy = System.getProperty("http.agent");
793 }
794 if (userAgentCopy == null && !defaultUserAgentDisabled) {
795 userAgentCopy = VersionInfo.getSoftwareInfo("Apache-HttpClient",
796 "org.apache.hc.client5", getClass());
797 }
798 }
799
800 final HttpProcessorBuilder b = HttpProcessorBuilder.create();
801 if (requestInterceptors != null) {
802 for (final RequestInterceptorEntry entry: requestInterceptors) {
803 if (entry.position == RequestInterceptorEntry.Position.FIRST) {
804 b.addFirst(entry.interceptor);
805 }
806 }
807 }
808 if (responseInterceptors != null) {
809 for (final ResponseInterceptorEntry entry: responseInterceptors) {
810 if (entry.position == ResponseInterceptorEntry.Position.FIRST) {
811 b.addFirst(entry.interceptor);
812 }
813 }
814 }
815 b.addAll(
816 new RequestDefaultHeaders(defaultHeaders),
817 new RequestContent(),
818 new RequestTargetHost(),
819 new RequestClientConnControl(),
820 new RequestUserAgent(userAgentCopy),
821 new RequestExpectContinue());
822 if (!cookieManagementDisabled) {
823 b.add(RequestAddCookies.INSTANCE);
824 }
825 if (!cookieManagementDisabled) {
826 b.add(ResponseProcessCookies.INSTANCE);
827 }
828 if (requestInterceptors != null) {
829 for (final RequestInterceptorEntry entry: requestInterceptors) {
830 if (entry.position == RequestInterceptorEntry.Position.LAST) {
831 b.addLast(entry.interceptor);
832 }
833 }
834 }
835 if (responseInterceptors != null) {
836 for (final ResponseInterceptorEntry entry: responseInterceptors) {
837 if (entry.position == ResponseInterceptorEntry.Position.LAST) {
838 b.addLast(entry.interceptor);
839 }
840 }
841 }
842 final HttpProcessor httpProcessor = b.build();
843
844 final NamedElementChain<ExecChainHandler> execChainDefinition = new NamedElementChain<>();
845 execChainDefinition.addLast(
846 new MainClientExec(connManagerCopy, httpProcessor, reuseStrategyCopy, keepAliveStrategyCopy, userTokenHandlerCopy),
847 ChainElement.MAIN_TRANSPORT.name());
848 execChainDefinition.addFirst(
849 new ConnectExec(
850 reuseStrategyCopy,
851 new DefaultHttpProcessor(new RequestTargetHost(), new RequestUserAgent(userAgentCopy)),
852 proxyAuthStrategyCopy,
853 schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE,
854 authCachingDisabled),
855 ChainElement.CONNECT.name());
856
857 execChainDefinition.addFirst(
858 new ProtocolExec(
859 targetAuthStrategyCopy,
860 proxyAuthStrategyCopy,
861 schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE,
862 authCachingDisabled),
863 ChainElement.PROTOCOL.name());
864
865
866 if (!automaticRetriesDisabled) {
867 HttpRequestRetryStrategy retryStrategyCopy = this.retryStrategy;
868 if (retryStrategyCopy == null) {
869 retryStrategyCopy = DefaultHttpRequestRetryStrategy.INSTANCE;
870 }
871 execChainDefinition.addFirst(
872 new HttpRequestRetryExec(retryStrategyCopy),
873 ChainElement.RETRY.name());
874 }
875
876 HttpRoutePlanner routePlannerCopy = this.routePlanner;
877 if (routePlannerCopy == null) {
878 SchemePortResolver schemePortResolverCopy = this.schemePortResolver;
879 if (schemePortResolverCopy == null) {
880 schemePortResolverCopy = DefaultSchemePortResolver.INSTANCE;
881 }
882 if (proxy != null) {
883 routePlannerCopy = new DefaultProxyRoutePlanner(proxy, schemePortResolverCopy);
884 } else if (this.proxySelector != null) {
885 routePlannerCopy = new SystemDefaultRoutePlanner(schemePortResolverCopy, this.proxySelector);
886 } else if (systemProperties) {
887 final ProxySelector defaultProxySelector = AccessController.doPrivileged((PrivilegedAction<ProxySelector>) ProxySelector::getDefault);
888 routePlannerCopy = new SystemDefaultRoutePlanner(schemePortResolverCopy, defaultProxySelector);
889 } else {
890 routePlannerCopy = new DefaultRoutePlanner(schemePortResolverCopy);
891 }
892 }
893
894 if (!contentCompressionDisabled) {
895 if (contentDecoderMap != null) {
896 final List<String> encodings = new ArrayList<>(contentDecoderMap.keySet());
897 final RegistryBuilder<InputStreamFactory> b2 = RegistryBuilder.create();
898 for (final Map.Entry<String, InputStreamFactory> entry: contentDecoderMap.entrySet()) {
899 b2.register(entry.getKey(), entry.getValue());
900 }
901 final Registry<InputStreamFactory> decoderRegistry = b2.build();
902 execChainDefinition.addFirst(
903 new ContentCompressionExec(encodings, decoderRegistry, true),
904 ChainElement.COMPRESS.name());
905 } else {
906 execChainDefinition.addFirst(new ContentCompressionExec(true), ChainElement.COMPRESS.name());
907 }
908 }
909
910
911 if (!redirectHandlingDisabled) {
912 RedirectStrategy redirectStrategyCopy = this.redirectStrategy;
913 if (redirectStrategyCopy == null) {
914 redirectStrategyCopy = DefaultRedirectStrategy.INSTANCE;
915 }
916 execChainDefinition.addFirst(
917 new RedirectExec(routePlannerCopy, redirectStrategyCopy),
918 ChainElement.REDIRECT.name());
919 }
920
921
922 if (this.backoffManager != null && this.connectionBackoffStrategy != null) {
923 execChainDefinition.addFirst(new BackoffStrategyExec(this.connectionBackoffStrategy, this.backoffManager),
924 ChainElement.BACK_OFF.name());
925 }
926
927 if (execInterceptors != null) {
928 for (final ExecInterceptorEntry entry: execInterceptors) {
929 switch (entry.position) {
930 case AFTER:
931 execChainDefinition.addAfter(entry.existing, entry.interceptor, entry.name);
932 break;
933 case BEFORE:
934 execChainDefinition.addBefore(entry.existing, entry.interceptor, entry.name);
935 break;
936 case REPLACE:
937 execChainDefinition.replace(entry.existing, entry.interceptor);
938 break;
939 case FIRST:
940 execChainDefinition.addFirst(entry.interceptor, entry.name);
941 break;
942 case LAST:
943
944
945 execChainDefinition.addBefore(ChainElement.MAIN_TRANSPORT.name(), entry.interceptor, entry.name);
946 break;
947 }
948 }
949 }
950
951 customizeExecChain(execChainDefinition);
952
953 NamedElementChain<ExecChainHandler>.Node current = execChainDefinition.getLast();
954 ExecChainElement execChain = null;
955 while (current != null) {
956 execChain = new ExecChainElement(current.getValue(), execChain);
957 current = current.getPrevious();
958 }
959
960 Lookup<AuthSchemeFactory> authSchemeRegistryCopy = this.authSchemeRegistry;
961 if (authSchemeRegistryCopy == null) {
962 authSchemeRegistryCopy = RegistryBuilder.<AuthSchemeFactory>create()
963 .register(StandardAuthScheme.BASIC, BasicSchemeFactory.INSTANCE)
964 .register(StandardAuthScheme.DIGEST, DigestSchemeFactory.INSTANCE)
965 .register(StandardAuthScheme.BEARER, BearerSchemeFactory.INSTANCE)
966 .build();
967 }
968 Lookup<CookieSpecFactory> cookieSpecRegistryCopy = this.cookieSpecRegistry;
969 if (cookieSpecRegistryCopy == null) {
970 cookieSpecRegistryCopy = CookieSpecSupport.createDefault();
971 }
972
973 CookieStore defaultCookieStore = this.cookieStore;
974 if (defaultCookieStore == null) {
975 defaultCookieStore = new BasicCookieStore();
976 }
977
978 CredentialsProvider defaultCredentialsProvider = this.credentialsProvider;
979 if (defaultCredentialsProvider == null) {
980 if (systemProperties) {
981 defaultCredentialsProvider = new SystemDefaultCredentialsProvider();
982 } else {
983 defaultCredentialsProvider = new BasicCredentialsProvider();
984 }
985 }
986
987 List<Closeable> closeablesCopy = closeables != null ? new ArrayList<>(closeables) : null;
988 if (!this.connManagerShared) {
989 if (closeablesCopy == null) {
990 closeablesCopy = new ArrayList<>(1);
991 }
992 if (evictExpiredConnections || evictIdleConnections) {
993 if (connManagerCopy instanceof ConnPoolControl) {
994 final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor((ConnPoolControl<?>) connManagerCopy,
995 maxIdleTime, maxIdleTime);
996 closeablesCopy.add(() -> {
997 connectionEvictor.shutdown();
998 try {
999 connectionEvictor.awaitTermination(Timeout.ofSeconds(1));
1000 } catch (final InterruptedException interrupted) {
1001 Thread.currentThread().interrupt();
1002 }
1003 });
1004 connectionEvictor.start();
1005 }
1006 }
1007 closeablesCopy.add(connManagerCopy);
1008 }
1009
1010 return new InternalHttpClient(
1011 connManagerCopy,
1012 requestExecCopy,
1013 execChain,
1014 routePlannerCopy,
1015 cookieSpecRegistryCopy,
1016 authSchemeRegistryCopy,
1017 defaultCookieStore,
1018 defaultCredentialsProvider,
1019 defaultRequestConfig != null ? defaultRequestConfig : RequestConfig.DEFAULT,
1020 closeablesCopy);
1021 }
1022
1023 }