|
39 | 39 | import javax.net.ssl.SSLContext;
|
40 | 40 | import javax.net.ssl.TrustManager;
|
41 | 41 | import javax.net.ssl.X509TrustManager;
|
| 42 | +import org.apache.hc.client5.http.ClientProtocolException; |
42 | 43 | import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
|
43 | 44 | import org.apache.hc.client5.http.DnsResolver;
|
44 | 45 | import org.apache.hc.client5.http.auth.AuthSchemeFactory;
|
45 | 46 | import org.apache.hc.client5.http.auth.CredentialsProvider;
|
46 | 47 | import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase;
|
| 48 | +import org.apache.hc.client5.http.config.ConnectionConfig; |
47 | 49 | import org.apache.hc.client5.http.impl.DefaultSchemePortResolver;
|
48 | 50 | import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
|
49 | 51 | import org.apache.hc.client5.http.impl.classic.HttpClients;
|
|
53 | 55 | import org.apache.hc.client5.http.io.HttpClientConnectionManager;
|
54 | 56 | import org.apache.hc.client5.http.protocol.HttpClientContext;
|
55 | 57 | import org.apache.hc.client5.http.routing.HttpRoutePlanner;
|
| 58 | +import org.apache.hc.client5.http.routing.RoutingSupport; |
56 | 59 | import org.apache.hc.client5.http.ssl.DefaultHostnameVerifier;
|
57 | 60 | import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
|
58 |
| -import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; |
| 61 | +import org.apache.hc.client5.http.ssl.TlsSocketStrategy; |
| 62 | +import org.apache.hc.core5.http.ClassicHttpRequest; |
59 | 63 | import org.apache.hc.core5.http.ClassicHttpResponse;
|
60 | 64 | import org.apache.hc.core5.http.Header;
|
61 | 65 | import org.apache.hc.core5.http.HttpEntity;
|
|
70 | 74 | import org.apache.hc.core5.pool.PoolStats;
|
71 | 75 | import org.apache.hc.core5.ssl.SSLInitializationException;
|
72 | 76 | import org.apache.hc.core5.util.TimeValue;
|
| 77 | +import org.apache.hc.core5.util.Timeout; |
73 | 78 | import software.amazon.awssdk.annotations.SdkPreviewApi;
|
74 | 79 | import software.amazon.awssdk.annotations.SdkPublicApi;
|
75 | 80 | import software.amazon.awssdk.annotations.SdkTestInternalApi;
|
@@ -285,14 +290,25 @@ private HttpExecuteResponse execute(HttpUriRequestBase apacheRequest, MetricColl
|
285 | 290 | HttpClientContext localRequestContext = Apache5Utils.newClientContext(requestConfig.proxyConfiguration());
|
286 | 291 | THREAD_LOCAL_REQUEST_METRIC_COLLECTOR.set(metricCollector);
|
287 | 292 | try {
|
288 |
| - HttpResponse httpResponse = httpClient.execute(apacheRequest, localRequestContext); |
289 |
| - // Create a connection-aware input stream that closes the response when closed |
| 293 | + HttpHost target = determineTarget(apacheRequest); |
| 294 | + ClassicHttpResponse httpResponse = httpClient.executeOpen(target, apacheRequest, localRequestContext); |
290 | 295 | return createResponse(httpResponse, apacheRequest);
|
291 | 296 | } finally {
|
292 | 297 | THREAD_LOCAL_REQUEST_METRIC_COLLECTOR.remove();
|
293 | 298 | }
|
294 | 299 | }
|
295 | 300 |
|
| 301 | + /** |
| 302 | + * Determines the target host from the request using Apache HttpClient's official routing support utility. |
| 303 | + */ |
| 304 | + private static HttpHost determineTarget(ClassicHttpRequest request) throws IOException { |
| 305 | + try { |
| 306 | + return RoutingSupport.determineHost(request); |
| 307 | + } catch (HttpException ex) { |
| 308 | + throw new ClientProtocolException(ex); |
| 309 | + } |
| 310 | + } |
| 311 | + |
296 | 312 | private HttpUriRequestBase toApacheRequest(HttpExecuteRequest request) {
|
297 | 313 | return apacheHttpRequestFactory.create(request, requestConfig);
|
298 | 314 | }
|
@@ -355,7 +371,6 @@ private Apache5HttpRequestConfig createRequestConfig(DefaultBuilder builder,
|
355 | 371 | AttributeMap resolvedOptions) {
|
356 | 372 | return Apache5HttpRequestConfig.builder()
|
357 | 373 | .socketTimeout(resolvedOptions.get(SdkHttpConfigurationOption.READ_TIMEOUT))
|
358 |
| - .connectionTimeout(resolvedOptions.get(SdkHttpConfigurationOption.CONNECTION_TIMEOUT)) |
359 | 374 | .connectionAcquireTimeout(
|
360 | 375 | resolvedOptions.get(SdkHttpConfigurationOption.CONNECTION_ACQUIRE_TIMEOUT))
|
361 | 376 | .proxyConfiguration(builder.proxyConfiguration)
|
@@ -464,12 +479,15 @@ public interface Builder extends SdkHttpClient.Builder<Apache5HttpClient.Builder
|
464 | 479 | Builder dnsResolver(DnsResolver dnsResolver);
|
465 | 480 |
|
466 | 481 | /**
|
467 |
| - * Configuration that defines a custom Socket factory. If set to a null value, a default factory is used. |
468 |
| - * <p> |
469 |
| - * When set to a non-null value, the use of a custom factory implies the configuration options TRUST_ALL_CERTIFICATES, |
470 |
| - * TLS_TRUST_MANAGERS_PROVIDER, and TLS_KEY_MANAGERS_PROVIDER are ignored. |
| 482 | + * Configure a custom TLS strategy for SSL/TLS connections. |
| 483 | + * This is the preferred method over the ConnectionSocketFactory. |
| 484 | + * |
| 485 | + * @param tlsSocketStrategy The TLS strategy to use for upgrading connections to TLS. |
| 486 | + * If null, default TLS configuration will be used. |
| 487 | + * @return This builder for method chaining |
| 488 | +
|
471 | 489 | */
|
472 |
| - Builder socketFactory(SSLConnectionSocketFactory socketFactory); |
| 490 | + Builder tlsSocketStrategy(TlsSocketStrategy tlsSocketStrategy); |
473 | 491 |
|
474 | 492 | /**
|
475 | 493 | * Configuration that defines an HTTP route planner that computes the route an HTTP request should take.
|
@@ -527,7 +545,7 @@ private static final class DefaultBuilder implements Builder {
|
527 | 545 | private HttpRoutePlanner httpRoutePlanner;
|
528 | 546 | private CredentialsProvider credentialsProvider;
|
529 | 547 | private DnsResolver dnsResolver;
|
530 |
| - private SSLConnectionSocketFactory socketFactory; |
| 548 | + private TlsSocketStrategy tlsStrategy; |
531 | 549 |
|
532 | 550 | private DefaultBuilder() {
|
533 | 551 | }
|
@@ -649,15 +667,11 @@ public void setDnsResolver(DnsResolver dnsResolver) {
|
649 | 667 | }
|
650 | 668 |
|
651 | 669 | @Override
|
652 |
| - public Builder socketFactory(SSLConnectionSocketFactory socketFactory) { |
653 |
| - this.socketFactory = socketFactory; |
| 670 | + public Builder tlsSocketStrategy(TlsSocketStrategy tlsSocketStrategy) { |
| 671 | + this.tlsStrategy = tlsSocketStrategy; |
654 | 672 | return this;
|
655 | 673 | }
|
656 | 674 |
|
657 |
| - public void setSocketFactory(SSLConnectionSocketFactory socketFactory) { |
658 |
| - socketFactory(socketFactory); |
659 |
| - } |
660 |
| - |
661 | 675 | @Override
|
662 | 676 | public Builder httpRoutePlanner(HttpRoutePlanner httpRoutePlanner) {
|
663 | 677 | this.httpRoutePlanner = httpRoutePlanner;
|
@@ -731,31 +745,44 @@ public SdkHttpClient buildWithDefaults(AttributeMap serviceDefaults) {
|
731 | 745 | private static class ApacheConnectionManagerFactory {
|
732 | 746 |
|
733 | 747 | public PoolingHttpClientConnectionManager create(Apache5HttpClient.DefaultBuilder configuration,
|
734 |
| - AttributeMap standardOptions) { |
735 |
| - // TODO : Deprecated method needs to be removed with new replacements |
736 |
| - SSLConnectionSocketFactory sslsf = getPreferredSocketFactory(configuration, standardOptions); |
| 748 | + AttributeMap standardOptions) { |
| 749 | + |
| 750 | + TlsSocketStrategy tlsStrategy = getPreferredTlsStrategy(configuration, standardOptions); |
737 | 751 |
|
738 | 752 | PoolingHttpClientConnectionManagerBuilder builder =
|
739 | 753 | PoolingHttpClientConnectionManagerBuilder.create()
|
740 |
| - .setSSLSocketFactory(sslsf) |
| 754 | + .setTlsSocketStrategy(tlsStrategy) |
741 | 755 | .setSchemePortResolver(DefaultSchemePortResolver.INSTANCE)
|
742 | 756 | .setDnsResolver(configuration.dnsResolver);
|
743 |
| - Duration connectionTtl = standardOptions.get(SdkHttpConfigurationOption.CONNECTION_TIME_TO_LIVE); |
744 |
| - if (!connectionTtl.isZero()) { |
745 |
| - // Skip TTL=0 to maintain backward compatibility (infinite in 4.x vs immediate expiration in 5.x) |
746 |
| - builder.setConnectionTimeToLive(TimeValue.of(connectionTtl.toMillis(), TimeUnit.MILLISECONDS)); |
747 |
| - } |
748 | 757 | builder.setMaxConnPerRoute(standardOptions.get(SdkHttpConfigurationOption.MAX_CONNECTIONS));
|
749 | 758 | builder.setMaxConnTotal(standardOptions.get(SdkHttpConfigurationOption.MAX_CONNECTIONS));
|
750 | 759 | builder.setDefaultSocketConfig(buildSocketConfig(standardOptions));
|
| 760 | + builder.setDefaultConnectionConfig(getConnectionConfig(standardOptions)); |
751 | 761 | return builder.build();
|
752 | 762 | }
|
753 | 763 |
|
754 |
| - private SSLConnectionSocketFactory getPreferredSocketFactory(Apache5HttpClient.DefaultBuilder configuration, |
755 |
| - AttributeMap standardOptions) { |
756 |
| - return Optional.ofNullable(configuration.socketFactory) |
757 |
| - .orElseGet(() -> new SdkTlsSocketFactory(getSslContext(standardOptions), |
758 |
| - getHostNameVerifier(standardOptions))); |
| 764 | + private static ConnectionConfig getConnectionConfig(AttributeMap standardOptions) { |
| 765 | + ConnectionConfig.Builder connectionConfigBuilder = |
| 766 | + ConnectionConfig.custom() |
| 767 | + .setConnectTimeout(Timeout.ofMilliseconds( |
| 768 | + standardOptions.get(SdkHttpConfigurationOption.CONNECTION_TIMEOUT).toMillis())) |
| 769 | + .setSocketTimeout(Timeout.ofMilliseconds( |
| 770 | + standardOptions.get(SdkHttpConfigurationOption.READ_TIMEOUT).toMillis())); |
| 771 | + Duration connectionTtl = standardOptions.get(SdkHttpConfigurationOption.CONNECTION_TIME_TO_LIVE); |
| 772 | + if (!connectionTtl.isZero()) { |
| 773 | + // Skip TTL=0 to maintain backward compatibility (infinite in 4.x vs immediate expiration in 5.x) |
| 774 | + connectionConfigBuilder.setTimeToLive(TimeValue.ofMilliseconds(connectionTtl.toMillis())); |
| 775 | + } |
| 776 | + return connectionConfigBuilder.build(); |
| 777 | + } |
| 778 | + |
| 779 | + private TlsSocketStrategy getPreferredTlsStrategy(Apache5HttpClient.DefaultBuilder configuration, |
| 780 | + AttributeMap standardOptions) { |
| 781 | + if (configuration.tlsStrategy != null) { |
| 782 | + return configuration.tlsStrategy; |
| 783 | + } |
| 784 | + return new SdkTlsSocketFactory(getSslContext(standardOptions), |
| 785 | + getHostNameVerifier(standardOptions)); |
759 | 786 | }
|
760 | 787 |
|
761 | 788 |
|
|
0 commit comments