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.io.IOException;
32 import java.net.ProxySelector;
33 import java.util.ArrayList;
34 import java.util.Collection;
35 import java.util.LinkedHashMap;
36 import java.util.LinkedList;
37 import java.util.List;
38 import java.util.Map;
39
40 import org.apache.hc.client5.http.AuthenticationStrategy;
41 import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
42 import org.apache.hc.client5.http.HttpRequestRetryStrategy;
43 import org.apache.hc.client5.http.SchemePortResolver;
44 import org.apache.hc.client5.http.UserTokenHandler;
45 import org.apache.hc.client5.http.auth.AuthSchemeFactory;
46 import org.apache.hc.client5.http.auth.StandardAuthScheme;
47 import org.apache.hc.client5.http.auth.CredentialsProvider;
48 import org.apache.hc.client5.http.classic.BackoffManager;
49 import org.apache.hc.client5.http.classic.ConnectionBackoffStrategy;
50 import org.apache.hc.client5.http.classic.ExecChainHandler;
51 import org.apache.hc.client5.http.config.RequestConfig;
52 import org.apache.hc.client5.http.cookie.BasicCookieStore;
53 import org.apache.hc.client5.http.cookie.CookieSpecFactory;
54 import org.apache.hc.client5.http.cookie.CookieStore;
55 import org.apache.hc.client5.http.entity.InputStreamFactory;
56 import org.apache.hc.client5.http.impl.ChainElement;
57 import org.apache.hc.client5.http.impl.CookieSpecSupport;
58 import org.apache.hc.client5.http.impl.DefaultAuthenticationStrategy;
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.RequestAuthCache;
81 import org.apache.hc.client5.http.protocol.RequestClientConnControl;
82 import org.apache.hc.client5.http.protocol.RequestDefaultHeaders;
83 import org.apache.hc.client5.http.protocol.RequestExpectContinue;
84 import org.apache.hc.client5.http.protocol.ResponseProcessCookies;
85 import org.apache.hc.client5.http.routing.HttpRoutePlanner;
86 import org.apache.hc.core5.annotation.Internal;
87 import org.apache.hc.core5.http.ConnectionReuseStrategy;
88 import org.apache.hc.core5.http.Header;
89 import org.apache.hc.core5.http.HttpHost;
90 import org.apache.hc.core5.http.HttpRequest;
91 import org.apache.hc.core5.http.HttpRequestInterceptor;
92 import org.apache.hc.core5.http.HttpResponse;
93 import org.apache.hc.core5.http.HttpResponseInterceptor;
94 import org.apache.hc.core5.http.config.Lookup;
95 import org.apache.hc.core5.http.config.NamedElementChain;
96 import org.apache.hc.core5.http.config.Registry;
97 import org.apache.hc.core5.http.config.RegistryBuilder;
98 import org.apache.hc.core5.http.impl.DefaultConnectionReuseStrategy;
99 import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
100 import org.apache.hc.core5.http.protocol.DefaultHttpProcessor;
101 import org.apache.hc.core5.http.protocol.HttpContext;
102 import org.apache.hc.core5.http.protocol.HttpProcessor;
103 import org.apache.hc.core5.http.protocol.HttpProcessorBuilder;
104 import org.apache.hc.core5.http.protocol.RequestContent;
105 import org.apache.hc.core5.http.protocol.RequestTargetHost;
106 import org.apache.hc.core5.http.protocol.RequestUserAgent;
107 import org.apache.hc.core5.pool.ConnPoolControl;
108 import org.apache.hc.core5.util.Args;
109 import org.apache.hc.core5.util.TimeValue;
110 import org.apache.hc.core5.util.Timeout;
111 import org.apache.hc.core5.util.VersionInfo;
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
139 public class HttpClientBuilder {
140
141 private static class RequestInterceptorEntry {
142
143 enum Postion { FIRST, LAST }
144
145 final Postion postion;
146 final HttpRequestInterceptor interceptor;
147
148 private RequestInterceptorEntry(final Postion postion, final HttpRequestInterceptor interceptor) {
149 this.postion = postion;
150 this.interceptor = interceptor;
151 }
152 }
153
154 private static class ResponseInterceptorEntry {
155
156 enum Postion { FIRST, LAST }
157
158 final Postion postion;
159 final HttpResponseInterceptor interceptor;
160
161 private ResponseInterceptorEntry(final Postion postion, final HttpResponseInterceptor interceptor) {
162 this.postion = postion;
163 this.interceptor = interceptor;
164 }
165 }
166
167 private static class ExecInterceptorEntry {
168
169 enum Postion { BEFORE, AFTER, REPLACE, FIRST, LAST }
170
171 final Postion postion;
172 final String name;
173 final ExecChainHandler interceptor;
174 final String existing;
175
176 private ExecInterceptorEntry(
177 final Postion postion,
178 final String name,
179 final ExecChainHandler interceptor,
180 final String existing) {
181 this.postion = postion;
182 this.name = name;
183 this.interceptor = interceptor;
184 this.existing = existing;
185 }
186
187 }
188
189 private HttpRequestExecutor requestExec;
190 private HttpClientConnectionManager connManager;
191 private boolean connManagerShared;
192 private SchemePortResolver schemePortResolver;
193 private ConnectionReuseStrategy reuseStrategy;
194 private ConnectionKeepAliveStrategy keepAliveStrategy;
195 private AuthenticationStrategy targetAuthStrategy;
196 private AuthenticationStrategy proxyAuthStrategy;
197 private UserTokenHandler userTokenHandler;
198
199 private LinkedList<RequestInterceptorEntry> requestInterceptors;
200 private LinkedList<ResponseInterceptorEntry> responseInterceptors;
201 private LinkedList<ExecInterceptorEntry> execInterceptors;
202
203 private HttpRequestRetryStrategy retryStrategy;
204 private HttpRoutePlanner routePlanner;
205 private RedirectStrategy redirectStrategy;
206 private ConnectionBackoffStrategy connectionBackoffStrategy;
207 private BackoffManager backoffManager;
208 private Lookup<AuthSchemeFactory> authSchemeRegistry;
209 private Lookup<CookieSpecFactory> cookieSpecRegistry;
210 private LinkedHashMap<String, InputStreamFactory> contentDecoderMap;
211 private CookieStore cookieStore;
212 private CredentialsProvider credentialsProvider;
213 private String userAgent;
214 private HttpHost proxy;
215 private Collection<? extends Header> defaultHeaders;
216 private RequestConfig defaultRequestConfig;
217 private boolean evictExpiredConnections;
218 private boolean evictIdleConnections;
219 private TimeValue maxIdleTime;
220
221 private boolean systemProperties;
222 private boolean redirectHandlingDisabled;
223 private boolean automaticRetriesDisabled;
224 private boolean contentCompressionDisabled;
225 private boolean cookieManagementDisabled;
226 private boolean authCachingDisabled;
227 private boolean connectionStateDisabled;
228 private boolean defaultUserAgentDisabled;
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.Postion.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.Postion.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.Postion.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.Postion.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.Postion.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.Postion.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.Postion.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.Postion.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.Postion.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 @Internal
710 protected void customizeExecChain(final NamedElementChain<ExecChainHandler> execChainDefinition) {
711 }
712
713
714
715
716
717
718 @Internal
719 protected void addCloseable(final Closeable closeable) {
720 if (closeable == null) {
721 return;
722 }
723 if (closeables == null) {
724 closeables = new ArrayList<>();
725 }
726 closeables.add(closeable);
727 }
728
729 public CloseableHttpClient build() {
730
731
732 HttpRequestExecutor requestExecCopy = this.requestExec;
733 if (requestExecCopy == null) {
734 requestExecCopy = new HttpRequestExecutor();
735 }
736 HttpClientConnectionManager connManagerCopy = this.connManager;
737 if (connManagerCopy == null) {
738 connManagerCopy = PoolingHttpClientConnectionManagerBuilder.create().build();
739 }
740 ConnectionReuseStrategy reuseStrategyCopy = this.reuseStrategy;
741 if (reuseStrategyCopy == null) {
742 if (systemProperties) {
743 final String s = System.getProperty("http.keepAlive", "true");
744 if ("true".equalsIgnoreCase(s)) {
745 reuseStrategyCopy = DefaultConnectionReuseStrategy.INSTANCE;
746 } else {
747 reuseStrategyCopy = new ConnectionReuseStrategy() {
748 @Override
749 public boolean keepAlive(
750 final HttpRequest request, final HttpResponse response, final HttpContext context) {
751 return false;
752 }
753 };
754 }
755 } else {
756 reuseStrategyCopy = DefaultConnectionReuseStrategy.INSTANCE;
757 }
758 }
759
760 ConnectionKeepAliveStrategy keepAliveStrategyCopy = this.keepAliveStrategy;
761 if (keepAliveStrategyCopy == null) {
762 keepAliveStrategyCopy = DefaultConnectionKeepAliveStrategy.INSTANCE;
763 }
764 AuthenticationStrategy targetAuthStrategyCopy = this.targetAuthStrategy;
765 if (targetAuthStrategyCopy == null) {
766 targetAuthStrategyCopy = DefaultAuthenticationStrategy.INSTANCE;
767 }
768 AuthenticationStrategy proxyAuthStrategyCopy = this.proxyAuthStrategy;
769 if (proxyAuthStrategyCopy == null) {
770 proxyAuthStrategyCopy = DefaultAuthenticationStrategy.INSTANCE;
771 }
772 UserTokenHandler userTokenHandlerCopy = this.userTokenHandler;
773 if (userTokenHandlerCopy == null) {
774 if (!connectionStateDisabled) {
775 userTokenHandlerCopy = DefaultUserTokenHandler.INSTANCE;
776 } else {
777 userTokenHandlerCopy = NoopUserTokenHandler.INSTANCE;
778 }
779 }
780
781 String userAgentCopy = this.userAgent;
782 if (userAgentCopy == null) {
783 if (systemProperties) {
784 userAgentCopy = System.getProperty("http.agent");
785 }
786 if (userAgentCopy == null && !defaultUserAgentDisabled) {
787 userAgentCopy = VersionInfo.getSoftwareInfo("Apache-HttpClient",
788 "org.apache.hc.client5", getClass());
789 }
790 }
791
792 final NamedElementChain<ExecChainHandler> execChainDefinition = new NamedElementChain<>();
793 execChainDefinition.addLast(
794 new MainClientExec(connManagerCopy, reuseStrategyCopy, keepAliveStrategyCopy, userTokenHandlerCopy),
795 ChainElement.MAIN_TRANSPORT.name());
796 execChainDefinition.addFirst(
797 new ConnectExec(
798 reuseStrategyCopy,
799 new DefaultHttpProcessor(new RequestTargetHost(), new RequestUserAgent(userAgentCopy)),
800 proxyAuthStrategyCopy),
801 ChainElement.CONNECT.name());
802
803 final HttpProcessorBuilder b = HttpProcessorBuilder.create();
804 if (requestInterceptors != null) {
805 for (final RequestInterceptorEntry entry: requestInterceptors) {
806 if (entry.postion == RequestInterceptorEntry.Postion.FIRST) {
807 b.addFirst(entry.interceptor);
808 }
809 }
810 }
811 if (responseInterceptors != null) {
812 for (final ResponseInterceptorEntry entry: responseInterceptors) {
813 if (entry.postion == ResponseInterceptorEntry.Postion.FIRST) {
814 b.addFirst(entry.interceptor);
815 }
816 }
817 }
818 b.addAll(
819 new RequestDefaultHeaders(defaultHeaders),
820 new RequestContent(),
821 new RequestTargetHost(),
822 new RequestClientConnControl(),
823 new RequestUserAgent(userAgentCopy),
824 new RequestExpectContinue());
825 if (!cookieManagementDisabled) {
826 b.add(new RequestAddCookies());
827 }
828 if (!authCachingDisabled) {
829 b.add(new RequestAuthCache());
830 }
831 if (!cookieManagementDisabled) {
832 b.add(new ResponseProcessCookies());
833 }
834 if (requestInterceptors != null) {
835 for (final RequestInterceptorEntry entry: requestInterceptors) {
836 if (entry.postion == RequestInterceptorEntry.Postion.LAST) {
837 b.addLast(entry.interceptor);
838 }
839 }
840 }
841 if (responseInterceptors != null) {
842 for (final ResponseInterceptorEntry entry: responseInterceptors) {
843 if (entry.postion == ResponseInterceptorEntry.Postion.LAST) {
844 b.addLast(entry.interceptor);
845 }
846 }
847 }
848 final HttpProcessor httpProcessor = b.build();
849 execChainDefinition.addFirst(
850 new ProtocolExec(httpProcessor, targetAuthStrategyCopy, proxyAuthStrategyCopy),
851 ChainElement.PROTOCOL.name());
852
853
854 if (!automaticRetriesDisabled) {
855 HttpRequestRetryStrategy retryStrategyCopy = this.retryStrategy;
856 if (retryStrategyCopy == null) {
857 retryStrategyCopy = DefaultHttpRequestRetryStrategy.INSTANCE;
858 }
859 execChainDefinition.addFirst(
860 new HttpRequestRetryExec(retryStrategyCopy),
861 ChainElement.RETRY.name());
862 }
863
864 HttpRoutePlanner routePlannerCopy = this.routePlanner;
865 if (routePlannerCopy == null) {
866 SchemePortResolver schemePortResolverCopy = this.schemePortResolver;
867 if (schemePortResolverCopy == null) {
868 schemePortResolverCopy = DefaultSchemePortResolver.INSTANCE;
869 }
870 if (proxy != null) {
871 routePlannerCopy = new DefaultProxyRoutePlanner(proxy, schemePortResolverCopy);
872 } else if (systemProperties) {
873 routePlannerCopy = new SystemDefaultRoutePlanner(
874 schemePortResolverCopy, ProxySelector.getDefault());
875 } else {
876 routePlannerCopy = new DefaultRoutePlanner(schemePortResolverCopy);
877 }
878 }
879
880 if (!contentCompressionDisabled) {
881 if (contentDecoderMap != null) {
882 final List<String> encodings = new ArrayList<>(contentDecoderMap.keySet());
883 final RegistryBuilder<InputStreamFactory> b2 = RegistryBuilder.create();
884 for (final Map.Entry<String, InputStreamFactory> entry: contentDecoderMap.entrySet()) {
885 b2.register(entry.getKey(), entry.getValue());
886 }
887 final Registry<InputStreamFactory> decoderRegistry = b2.build();
888 execChainDefinition.addFirst(
889 new ContentCompressionExec(encodings, decoderRegistry, true),
890 ChainElement.COMPRESS.name());
891 } else {
892 execChainDefinition.addFirst(new ContentCompressionExec(true), ChainElement.COMPRESS.name());
893 }
894 }
895
896
897 if (!redirectHandlingDisabled) {
898 RedirectStrategy redirectStrategyCopy = this.redirectStrategy;
899 if (redirectStrategyCopy == null) {
900 redirectStrategyCopy = DefaultRedirectStrategy.INSTANCE;
901 }
902 execChainDefinition.addFirst(
903 new RedirectExec(routePlannerCopy, redirectStrategyCopy),
904 ChainElement.REDIRECT.name());
905 }
906
907
908 if (this.backoffManager != null && this.connectionBackoffStrategy != null) {
909 execChainDefinition.addFirst(new BackoffStrategyExec(this.connectionBackoffStrategy, this.backoffManager),
910 ChainElement.BACK_OFF.name());
911 }
912
913 if (execInterceptors != null) {
914 for (final ExecInterceptorEntry entry: execInterceptors) {
915 switch (entry.postion) {
916 case AFTER:
917 execChainDefinition.addAfter(entry.existing, entry.interceptor, entry.name);
918 break;
919 case BEFORE:
920 execChainDefinition.addBefore(entry.existing, entry.interceptor, entry.name);
921 break;
922 case REPLACE:
923 execChainDefinition.replace(entry.existing, entry.interceptor);
924 break;
925 case FIRST:
926 execChainDefinition.addFirst(entry.interceptor, entry.name);
927 break;
928 case LAST:
929 execChainDefinition.addLast(entry.interceptor, entry.name);
930 break;
931 }
932 }
933 }
934
935 customizeExecChain(execChainDefinition);
936
937 NamedElementChain<ExecChainHandler>.Node current = execChainDefinition.getLast();
938 ExecChainElement execChain = null;
939 while (current != null) {
940 execChain = new ExecChainElement(current.getValue(), execChain);
941 current = current.getPrevious();
942 }
943
944 Lookup<AuthSchemeFactory> authSchemeRegistryCopy = this.authSchemeRegistry;
945 if (authSchemeRegistryCopy == null) {
946 authSchemeRegistryCopy = RegistryBuilder.<AuthSchemeFactory>create()
947 .register(StandardAuthScheme.BASIC, BasicSchemeFactory.INSTANCE)
948 .register(StandardAuthScheme.DIGEST, DigestSchemeFactory.INSTANCE)
949 .register(StandardAuthScheme.NTLM, NTLMSchemeFactory.INSTANCE)
950 .register(StandardAuthScheme.SPNEGO, SPNegoSchemeFactory.DEFAULT)
951 .register(StandardAuthScheme.KERBEROS, KerberosSchemeFactory.DEFAULT)
952 .build();
953 }
954 Lookup<CookieSpecFactory> cookieSpecRegistryCopy = this.cookieSpecRegistry;
955 if (cookieSpecRegistryCopy == null) {
956 cookieSpecRegistryCopy = CookieSpecSupport.createDefault();
957 }
958
959 CookieStore defaultCookieStore = this.cookieStore;
960 if (defaultCookieStore == null) {
961 defaultCookieStore = new BasicCookieStore();
962 }
963
964 CredentialsProvider defaultCredentialsProvider = this.credentialsProvider;
965 if (defaultCredentialsProvider == null) {
966 if (systemProperties) {
967 defaultCredentialsProvider = new SystemDefaultCredentialsProvider();
968 } else {
969 defaultCredentialsProvider = new BasicCredentialsProvider();
970 }
971 }
972
973 List<Closeable> closeablesCopy = closeables != null ? new ArrayList<>(closeables) : null;
974 if (!this.connManagerShared) {
975 if (closeablesCopy == null) {
976 closeablesCopy = new ArrayList<>(1);
977 }
978 if (evictExpiredConnections || evictIdleConnections) {
979 if (connManagerCopy instanceof ConnPoolControl) {
980 final IdleConnectionEvictornEvictor.html#IdleConnectionEvictor">IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor((ConnPoolControl<?>) connManagerCopy,
981 maxIdleTime, maxIdleTime);
982 closeablesCopy.add(new Closeable() {
983
984 @Override
985 public void close() throws IOException {
986 connectionEvictor.shutdown();
987 try {
988 connectionEvictor.awaitTermination(Timeout.ofSeconds(1));
989 } catch (final InterruptedException interrupted) {
990 Thread.currentThread().interrupt();
991 }
992 }
993
994 });
995 connectionEvictor.start();
996 }
997 }
998 closeablesCopy.add(connManagerCopy);
999 }
1000
1001 return new InternalHttpClient(
1002 connManagerCopy,
1003 requestExecCopy,
1004 execChain,
1005 routePlannerCopy,
1006 cookieSpecRegistryCopy,
1007 authSchemeRegistryCopy,
1008 defaultCookieStore,
1009 defaultCredentialsProvider,
1010 defaultRequestConfig != null ? defaultRequestConfig : RequestConfig.DEFAULT,
1011 closeablesCopy);
1012 }
1013
1014 }