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