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