You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2021/10/23 16:34:42 UTC

[httpcomponents-client] branch master updated (36056a4 -> fff0976)

This is an automated email from the ASF dual-hosted git repository.

olegk pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git.


 discard 36056a4  Make IOReactor IO session decorator configurable.
 discard 3618e6a  Upgraded HttpCore to version 5.2-alpha2
 discard af09804  Change loop that don't loop for "if" conditions.
 discard d9299be  * Fix javadoc typo. * Use java array declarations instead of "c" way.
    omit 4f4ec62  Re-use core URIScheme instead of String.
    omit b44a09f  Don't initialize AtomicReference to its default value.
    omit 97a7caf  HTTPCLIENT-2182: access to SSLSession attributes via reflection disallowed as of Java 16. Core TLS functions now use new Java 1.8 API introduced by 8u251 update
    omit 861c071  HTTPCLIENT-2135: TLS configuration on a per-host basis
     new b10d43f  HTTPCLIENT-2135: TLS configuration on a per-host basis
     new 8b73f6b  HTTPCLIENT-2182: access to SSLSession attributes via reflection disallowed as of Java 16. Core TLS functions now use new Java 1.8 API introduced by 8u251 update
     new 2384017  Don't initialize AtomicReference to its default value.
     new bc7aae7  Re-use core URIScheme instead of String.
     new 0124293  * Fix javadoc typo. * Use java array declarations instead of "c" way.
     new 277c722  Change loop that don't loop for "if" conditions.
     new eb22ef3  Upgraded HttpCore to version 5.2-alpha2
     new fff0976  Make IOReactor IO session decorator configurable.

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (36056a4)
            \
             N -- N -- N   refs/heads/master (fff0976)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 8 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../PoolingHttpClientConnectionManagerBuilder.java | 25 ++++++++++++++++++++++
 .../http/examples/AsyncClientCustomSSL.java        | 12 -----------
 2 files changed, 25 insertions(+), 12 deletions(-)

[httpcomponents-client] 01/08: HTTPCLIENT-2135: TLS configuration on a per-host basis

Posted by ol...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git

commit b10d43f2bb810913c421eb1ad6fe08b277692750
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Sun Sep 12 14:54:32 2021 +0200

    HTTPCLIENT-2135: TLS configuration on a per-host basis
---
 .../testing/async/TestHttp1RequestReExecution.java |   7 +-
 .../testing/async/TestHttpAsyncMinimal.java        |  28 +--
 .../testing/async/TestHttpMinimalReactive.java     |  28 +--
 .../CachingHttpAsyncClientCompatibilityTest.java   |  14 +-
 .../external/HttpAsyncClientCompatibilityTest.java |   5 +-
 .../testing/sync/TestConnectionManagement.java     |  14 +-
 .../hc/client5/http/config/ConnectionConfig.java   |   7 +-
 .../apache/hc/client5/http/config/TlsConfig.java   | 203 +++++++++++++++++++++
 .../http/impl/async/HttpAsyncClientBuilder.java    |  15 +-
 .../async/HttpAsyncClientEventHandlerFactory.java  |   7 +-
 .../client5/http/impl/async/HttpAsyncClients.java  |  61 ++++++-
 .../http/impl/async/InternalHttpAsyncClient.java   |  10 +-
 .../impl/async/InternalHttpAsyncExecRuntime.java   |  20 +-
 .../http/impl/async/MinimalHttpAsyncClient.java    |  12 +-
 .../impl/io/BasicHttpClientConnectionManager.java  |  21 ++-
 .../io/DefaultHttpClientConnectionOperator.java    |  34 +++-
 .../io/PoolingHttpClientConnectionManager.java     |  51 ++++--
 .../PoolingHttpClientConnectionManagerBuilder.java |  25 +++
 .../nio/DefaultAsyncClientConnectionOperator.java  |   9 +-
 .../nio/PoolingAsyncClientConnectionManager.java   |  38 +++-
 ...PoolingAsyncClientConnectionManagerBuilder.java |  24 +++
 .../http/io/HttpClientConnectionOperator.java      |  44 +++++
 .../http/nio/AsyncClientConnectionOperator.java    |   1 -
 .../http/socket/ConnectionSocketFactory.java       |  32 ++++
 .../socket/LayeredConnectionSocketFactory.java     |  26 +++
 .../http/ssl/AbstractClientTlsStrategy.java        |  12 +-
 .../http/ssl/SSLConnectionSocketFactory.java       |  50 ++++-
 .../examples/AsyncClientFullDuplexExchange.java    |   9 +-
 .../examples/AsyncClientH2FullDuplexExchange.java  |  17 +-
 .../http/examples/AsyncClientH2Multiplexing.java   |  17 +-
 .../http/examples/AsyncClientH2ServerPush.java     |  23 +--
 .../http/examples/AsyncClientHttp1Pipelining.java  |  17 +-
 .../client5/http/examples/AsyncClientTlsAlpn.java  |   2 -
 .../examples/ReactiveClientFullDuplexExchange.java |   9 +-
 .../io/TestBasicHttpClientConnectionManager.java   |  65 ++++++-
 .../impl/io/TestHttpClientConnectionOperator.java  |  39 +++-
 .../io/TestPoolingHttpClientConnectionManager.java |  64 ++++++-
 37 files changed, 864 insertions(+), 196 deletions(-)

diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1RequestReExecution.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1RequestReExecution.java
index 4a7f002..cb7a465 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1RequestReExecution.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1RequestReExecution.java
@@ -34,6 +34,7 @@ import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
 import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
 import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.config.TlsConfig;
 import org.apache.hc.client5.http.impl.DefaultHttpRequestRetryStrategy;
 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
 import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;
@@ -102,12 +103,14 @@ public class TestHttp1RequestReExecution extends AbstractIntegrationTestBase<Clo
 
         @Override
         protected void before() throws Throwable {
+            connManager.setDefaultTlsConfig(TlsConfig.custom()
+                            .setVersionPolicy(version.greaterEquals(HttpVersion.HTTP_2) ? HttpVersionPolicy.FORCE_HTTP_2 : HttpVersionPolicy.FORCE_HTTP_1)
+                    .build());
             clientBuilder = HttpAsyncClientBuilder.create()
                     .setDefaultRequestConfig(RequestConfig.custom()
                             .setConnectionRequestTimeout(TIMEOUT)
                             .build())
-                    .setConnectionManager(connManager)
-                    .setVersionPolicy(version.greaterEquals(HttpVersion.HTTP_2) ? HttpVersionPolicy.FORCE_HTTP_2 : HttpVersionPolicy.FORCE_HTTP_1);
+                    .setConnectionManager(connManager);
         }
 
     };
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsyncMinimal.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsyncMinimal.java
index 5c5c073..d4ccb31 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsyncMinimal.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsyncMinimal.java
@@ -34,9 +34,9 @@ import java.util.Random;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.hc.client5.http.config.TlsConfig;
 import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
 import org.apache.hc.client5.http.impl.async.MinimalHttpAsyncClient;
-import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager;
 import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
 import org.apache.hc.client5.http.protocol.HttpClientContext;
 import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
@@ -85,19 +85,19 @@ public class TestHttpAsyncMinimal extends AbstractHttpAsyncFundamentalsTest<Mini
 
     @Override
     protected MinimalHttpAsyncClient createClient() throws Exception {
-        final PoolingAsyncClientConnectionManager connectionManager = PoolingAsyncClientConnectionManagerBuilder.create()
-                .setTlsStrategy(new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext()))
-                .build();
-        final IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
-                .setSoTimeout(TIMEOUT)
-                .build();
-        if (version.greaterEquals(HttpVersion.HTTP_2)) {
-            return HttpAsyncClients.createMinimal(
-                    HttpVersionPolicy.FORCE_HTTP_2, H2Config.DEFAULT, Http1Config.DEFAULT, ioReactorConfig, connectionManager);
-        } else {
-            return HttpAsyncClients.createMinimal(
-                    HttpVersionPolicy.FORCE_HTTP_1, H2Config.DEFAULT, Http1Config.DEFAULT, ioReactorConfig, connectionManager);
-        }
+        return HttpAsyncClients.createMinimal(
+                H2Config.DEFAULT,
+                Http1Config.DEFAULT,
+                IOReactorConfig.custom()
+                        .setSoTimeout(TIMEOUT)
+                        .build(),
+                PoolingAsyncClientConnectionManagerBuilder.create()
+                        .setTlsStrategy(new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext()))
+                        .setDefaultTlsConfig(TlsConfig.custom()
+                                .setVersionPolicy(version.greaterEquals(HttpVersion.HTTP_2)
+                                        ? HttpVersionPolicy.FORCE_HTTP_2 : HttpVersionPolicy.FORCE_HTTP_1)
+                                .build())
+                        .build());
     }
 
     @Override
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpMinimalReactive.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpMinimalReactive.java
index 5cbad43..24749dc 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpMinimalReactive.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpMinimalReactive.java
@@ -34,9 +34,9 @@ import java.util.Random;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.hc.client5.http.config.TlsConfig;
 import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
 import org.apache.hc.client5.http.impl.async.MinimalHttpAsyncClient;
-import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager;
 import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
 import org.apache.hc.client5.http.protocol.HttpClientContext;
 import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
@@ -85,19 +85,19 @@ public class TestHttpMinimalReactive extends AbstractHttpReactiveFundamentalsTes
 
     @Override
     protected MinimalHttpAsyncClient createClient() throws Exception {
-        final PoolingAsyncClientConnectionManager connectionManager = PoolingAsyncClientConnectionManagerBuilder.create()
-                .setTlsStrategy(new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext()))
-                .build();
-        final IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
-                .setSoTimeout(TIMEOUT)
-                .build();
-        if (version.greaterEquals(HttpVersion.HTTP_2)) {
-            return HttpAsyncClients.createMinimal(
-                    HttpVersionPolicy.FORCE_HTTP_2, H2Config.DEFAULT, Http1Config.DEFAULT, ioReactorConfig, connectionManager);
-        } else {
-            return HttpAsyncClients.createMinimal(
-                    HttpVersionPolicy.FORCE_HTTP_1, H2Config.DEFAULT, Http1Config.DEFAULT, ioReactorConfig, connectionManager);
-        }
+        return HttpAsyncClients.createMinimal(
+                H2Config.DEFAULT,
+                Http1Config.DEFAULT,
+                IOReactorConfig.custom()
+                        .setSoTimeout(TIMEOUT)
+                        .build(),
+                PoolingAsyncClientConnectionManagerBuilder.create()
+                        .setTlsStrategy(new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext()))
+                        .setDefaultTlsConfig(TlsConfig.custom()
+                                .setVersionPolicy(version.greaterEquals(HttpVersion.HTTP_2)
+                                        ? HttpVersionPolicy.FORCE_HTTP_2 : HttpVersionPolicy.FORCE_HTTP_1)
+                                .build())
+                        .build());
     }
 
     @Override
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/external/CachingHttpAsyncClientCompatibilityTest.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/external/CachingHttpAsyncClientCompatibilityTest.java
index 72a219d..c4f3090 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/external/CachingHttpAsyncClientCompatibilityTest.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/external/CachingHttpAsyncClientCompatibilityTest.java
@@ -35,13 +35,12 @@ import java.util.concurrent.TimeoutException;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import javax.net.ssl.SSLContext;
-
 import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
 import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
 import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
 import org.apache.hc.client5.http.cache.CacheResponseStatus;
 import org.apache.hc.client5.http.cache.HttpCacheContext;
+import org.apache.hc.client5.http.config.TlsConfig;
 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
 import org.apache.hc.client5.http.impl.cache.CacheConfig;
 import org.apache.hc.client5.http.impl.cache.CachingHttpAsyncClients;
@@ -88,17 +87,20 @@ public class CachingHttpAsyncClientCompatibilityTest {
     CachingHttpAsyncClientCompatibilityTest(final HttpVersion protocolVersion, final HttpHost target) throws Exception {
         this.protocolVersion = protocolVersion;
         this.target = target;
-        final SSLContext sslContext = SSLContexts.custom()
-                .loadTrustMaterial(getClass().getResource("/test-ca.keystore"), "nopassword".toCharArray()).build();
         this.connManager = PoolingAsyncClientConnectionManagerBuilder.create()
-                .setTlsStrategy(new DefaultClientTlsStrategy(sslContext))
+                .setTlsStrategy(new DefaultClientTlsStrategy(SSLContexts.custom()
+                        .loadTrustMaterial(getClass().getResource("/test-ca.keystore"), "nopassword".toCharArray())
+                        .build()))
+                .setDefaultTlsConfig(TlsConfig.custom()
+                        .setVersionPolicy(this.protocolVersion == HttpVersion.HTTP_2 ?
+                                HttpVersionPolicy.FORCE_HTTP_2 : HttpVersionPolicy.FORCE_HTTP_1)
+                        .build())
                 .build();
         this.client = CachingHttpAsyncClients.custom()
                 .setCacheConfig(CacheConfig.custom()
                         .setMaxObjectSize(20480)
                         .build())
                 .setResourceFactory(HeapResourceFactory.INSTANCE)
-                .setVersionPolicy(this.protocolVersion == HttpVersion.HTTP_2 ? HttpVersionPolicy.FORCE_HTTP_2 : HttpVersionPolicy.FORCE_HTTP_1)
                 .setConnectionManager(this.connManager)
                 .build();
     }
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/external/HttpAsyncClientCompatibilityTest.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/external/HttpAsyncClientCompatibilityTest.java
index c5903c5..ee3317b 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/external/HttpAsyncClientCompatibilityTest.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/external/HttpAsyncClientCompatibilityTest.java
@@ -40,6 +40,7 @@ import org.apache.hc.client5.http.auth.AuthScope;
 import org.apache.hc.client5.http.auth.Credentials;
 import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
 import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.config.TlsConfig;
 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
 import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
 import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
@@ -139,9 +140,11 @@ public class HttpAsyncClientCompatibilityTest {
                 .loadTrustMaterial(getClass().getResource("/test-ca.keystore"), "nopassword".toCharArray()).build();
         this.connManager = PoolingAsyncClientConnectionManagerBuilder.create()
                 .setTlsStrategy(new DefaultClientTlsStrategy(sslContext))
+                .setDefaultTlsConfig(TlsConfig.custom()
+                        .setVersionPolicy(versionPolicy)
+                        .build())
                 .build();
         this.client = HttpAsyncClients.custom()
-                .setVersionPolicy(this.versionPolicy)
                 .setConnectionManager(this.connManager)
                 .setProxy(this.proxy)
                 .setDefaultRequestConfig(requestConfig)
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestConnectionManagement.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestConnectionManagement.java
index 9b1f8fd..824e4fa 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestConnectionManagement.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestConnectionManagement.java
@@ -82,7 +82,7 @@ public class TestConnectionManagement extends LocalServerTestBase {
         final LeaseRequest leaseRequest1 = this.connManager.lease("id1", route,null);
         final ConnectionEndpoint endpoint1 = leaseRequest1.get(Timeout.ZERO_MILLISECONDS);
 
-        this.connManager.connect(endpoint1, TimeValue.NEG_ONE_MILLISECOND, context);
+        this.connManager.connect(endpoint1, null, context);
 
         final HttpProcessor httpProcessor = new DefaultHttpProcessor(
                 new RequestTargetHost(), new RequestContent(), new RequestConnControl());
@@ -104,7 +104,7 @@ public class TestConnectionManagement extends LocalServerTestBase {
         final ConnectionEndpoint endpoint2 = leaseRequest3.get(Timeout.ZERO_MILLISECONDS);
         Assert.assertFalse(endpoint2.isConnected());
 
-        this.connManager.connect(endpoint2, TimeValue.NEG_ONE_MILLISECOND, context);
+        this.connManager.connect(endpoint2, null, context);
 
         try (final ClassicHttpResponse response2 = endpoint2.execute("id2", request, exec, context)) {
             Assert.assertEquals(HttpStatus.SC_OK, response2.getCode());
@@ -145,7 +145,7 @@ public class TestConnectionManagement extends LocalServerTestBase {
 
         final LeaseRequest leaseRequest1 = this.connManager.lease("id1", route,null);
         final ConnectionEndpoint endpoint1 = leaseRequest1.get(Timeout.ZERO_MILLISECONDS);
-        this.connManager.connect(endpoint1, TimeValue.NEG_ONE_MILLISECOND, context);
+        this.connManager.connect(endpoint1, null, context);
 
         final HttpProcessor httpProcessor = new DefaultHttpProcessor(
                 new RequestTargetHost(), new RequestContent(), new RequestConnControl());
@@ -168,7 +168,7 @@ public class TestConnectionManagement extends LocalServerTestBase {
         final ConnectionEndpoint endpoint2 = leaseRequest3.get(Timeout.ZERO_MILLISECONDS);
         Assert.assertFalse(endpoint2.isConnected());
 
-        this.connManager.connect(endpoint2, TimeValue.NEG_ONE_MILLISECOND, context);
+        this.connManager.connect(endpoint2, null, context);
 
         try (final ClassicHttpResponse response2 = endpoint2.execute("id2", request, exec, context)) {
             Assert.assertEquals(HttpStatus.SC_OK, response2.getCode());
@@ -193,7 +193,7 @@ public class TestConnectionManagement extends LocalServerTestBase {
         Assert.assertFalse(endpoint4.isConnected());
 
         // repeat the communication, no need to prepare the request again
-        this.connManager.connect(endpoint4, TimeValue.NEG_ONE_MILLISECOND, context);
+        this.connManager.connect(endpoint4, null, context);
 
         try (final ClassicHttpResponse response4 = endpoint4.execute("id4", request, exec, context)) {
             Assert.assertEquals(HttpStatus.SC_OK, response4.getCode());
@@ -213,7 +213,7 @@ public class TestConnectionManagement extends LocalServerTestBase {
 
         final LeaseRequest leaseRequest1 = this.connManager.lease("id1", route,null);
         final ConnectionEndpoint endpoint1 = leaseRequest1.get(Timeout.ZERO_MILLISECONDS);
-        this.connManager.connect(endpoint1, TimeValue.NEG_ONE_MILLISECOND, context);
+        this.connManager.connect(endpoint1, null, context);
 
         Assert.assertEquals(1, this.connManager.getTotalStats().getLeased());
         Assert.assertEquals(1, this.connManager.getStats(route).getLeased());
@@ -262,7 +262,7 @@ public class TestConnectionManagement extends LocalServerTestBase {
 
         final LeaseRequest leaseRequest1 = this.connManager.lease("id1", route,null);
         final ConnectionEndpoint endpoint1 = leaseRequest1.get(Timeout.ZERO_MILLISECONDS);
-        this.connManager.connect(endpoint1, TimeValue.NEG_ONE_MILLISECOND, context);
+        this.connManager.connect(endpoint1, null, context);
 
         Assert.assertEquals(1, this.connManager.getTotalStats().getLeased());
         Assert.assertEquals(1, this.connManager.getStats(route).getLeased());
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/config/ConnectionConfig.java b/httpclient5/src/main/java/org/apache/hc/client5/http/config/ConnectionConfig.java
index 97ed585..38ead6f 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/config/ConnectionConfig.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/config/ConnectionConfig.java
@@ -126,7 +126,6 @@ public class ConnectionConfig implements Cloneable {
             this.connectTimeout = DEFAULT_CONNECT_TIMEOUT;
         }
 
-
         /**
          * @see #setSocketTimeout(Timeout)
          */
@@ -138,7 +137,7 @@ public class ConnectionConfig implements Cloneable {
         /**
          * Determines the default socket timeout value for I/O operations.
          * <p>
-         * Default: {@code null}
+         * Default: {@code null} (undefined)
          * </p>
          *
          * @return the default socket timeout value for I/O operations.
@@ -150,8 +149,6 @@ public class ConnectionConfig implements Cloneable {
 
         /**
          * Determines the timeout until a new connection is fully established.
-         * This may also include transport security negotiation exchanges
-         * such as {@code SSL} or {@code TLS} protocol negotiation).
          * <p>
          * A timeout value of zero is interpreted as an infinite timeout.
          * </p>
@@ -177,7 +174,7 @@ public class ConnectionConfig implements Cloneable {
          * be re-validated prior to being leased to the consumer. Negative values passed
          * to this method disable connection validation.
          * <p>
-         * Default: {@code null}
+         * Default: {@code null} (undefined)
          * </p>
          */
         public Builder setValidateAfterInactivity(final TimeValue validateAfterInactivity) {
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/config/TlsConfig.java b/httpclient5/src/main/java/org/apache/hc/client5/http/config/TlsConfig.java
new file mode 100644
index 0000000..7a014e2
--- /dev/null
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/config/TlsConfig.java
@@ -0,0 +1,203 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.client5.http.config;
+
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.hc.core5.annotation.Contract;
+import org.apache.hc.core5.annotation.ThreadingBehavior;
+import org.apache.hc.core5.http2.HttpVersionPolicy;
+import org.apache.hc.core5.util.Timeout;
+
+/**
+ * Immutable class encapsulating TLS protocol settings.
+ *
+ * @since 5.2
+ */
+@Contract(threading = ThreadingBehavior.IMMUTABLE)
+public class TlsConfig implements Cloneable {
+
+    public static final TlsConfig DEFAULT = new Builder().build();
+
+    private final Timeout handshakeTimeout;
+    private final String[] supportedProtocols;
+    private final String[] supportedCipherSuites;
+    private final HttpVersionPolicy httpVersionPolicy;
+
+    /**
+     * Intended for CDI compatibility
+     */
+    protected TlsConfig() {
+        this(null, null, null, null);
+    }
+
+    TlsConfig(
+            final Timeout handshakeTimeout,
+            final String[] supportedProtocols,
+            final String[] supportedCipherSuites,
+            final HttpVersionPolicy httpVersionPolicy) {
+        super();
+        this.handshakeTimeout = handshakeTimeout;
+        this.supportedProtocols = supportedProtocols;
+        this.supportedCipherSuites = supportedCipherSuites;
+        this.httpVersionPolicy = httpVersionPolicy;
+    }
+
+    /**
+     * @see Builder#setHandshakeTimeout(Timeout)
+     */
+    public Timeout getHandshakeTimeout() {
+        return handshakeTimeout;
+    }
+
+    /**
+     * @see Builder#setSupportedProtocols(String...)
+     */
+    public String[] getSupportedProtocols() {
+        return supportedProtocols != null ? supportedProtocols.clone() : null;
+    }
+
+    /**
+     * @see Builder#setSupportedCipherSuites(String...)
+     */
+    public String[] getSupportedCipherSuites() {
+        return supportedCipherSuites != null ? supportedCipherSuites.clone() : null;
+    }
+
+    /**
+     * @see Builder#setVersionPolicy(HttpVersionPolicy)
+     */
+    public HttpVersionPolicy getHttpVersionPolicy() {
+        return httpVersionPolicy;
+    }
+
+    @Override
+    protected TlsConfig clone() throws CloneNotSupportedException {
+        return (TlsConfig) super.clone();
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append("[");
+        builder.append("handshakeTimeout=").append(handshakeTimeout);
+        builder.append(", supportedProtocols=").append(Arrays.asList(supportedProtocols));
+        builder.append(", supportedCipherSuites=").append(Arrays.asList(supportedCipherSuites));
+        builder.append(", httpVersionPolicy=").append(httpVersionPolicy);
+        builder.append("]");
+        return builder.toString();
+    }
+
+    public static TlsConfig.Builder custom() {
+        return new Builder();
+    }
+
+    public static TlsConfig.Builder copy(final TlsConfig config) {
+        return new Builder()
+                .setHandshakeTimeout(config.getHandshakeTimeout())
+                .setSupportedProtocols(config.getSupportedProtocols())
+                .setSupportedCipherSuites(config.getSupportedCipherSuites())
+                .setVersionPolicy(config.getHttpVersionPolicy());
+    }
+
+    public static class Builder {
+
+        private Timeout handshakeTimeout;
+        private String[] supportedProtocols;
+        private String[] supportedCipherSuites;
+        private HttpVersionPolicy versionPolicy;
+
+        /**
+         * Determines the timeout used by TLS session negotiation exchanges (session handshake).
+         * <p>
+         * A timeout value of zero is interpreted as an infinite timeout.
+         * </p>
+         * <p>
+         * Default: {@code null} (undefined)
+         * </p>
+         */
+        public Builder setHandshakeTimeout(final Timeout handshakeTimeout) {
+            this.handshakeTimeout = handshakeTimeout;
+            return this;
+        }
+
+        /**
+         * @see #setHandshakeTimeout(Timeout)
+         */
+        public Builder setHandshakeTimeout(final long handshakeTimeout, final TimeUnit timeUnit) {
+            this.handshakeTimeout = Timeout.of(handshakeTimeout, timeUnit);
+            return this;
+        }
+
+        /**
+         * Determines supported TLS protocols.
+         * <p>
+         * Default: {@code null} (undefined)
+         * </p>
+         */
+        public Builder setSupportedProtocols(final String... supportedProtocols) {
+            this.supportedProtocols = supportedProtocols;
+            return this;
+        }
+
+        /**
+         * Determines supported cipher suites.
+         * <p>
+         * Default: {@code null} (undefined)
+         * </p>
+         */
+        public Builder setSupportedCipherSuites(final String... supportedCipherSuites) {
+            this.supportedCipherSuites = supportedCipherSuites;
+            return this;
+        }
+
+        /**
+         * Determines the HTTP protocol policy. By default, connections are expected to use TLS ALPN
+         * extension to negotiate the application protocol to be used by both endpoints.
+         * </p>
+         * <p>
+         * Default: {@link HttpVersionPolicy#NEGOTIATE}
+         * </p>
+         */
+        public Builder setVersionPolicy(final HttpVersionPolicy versionPolicy) {
+            this.versionPolicy = versionPolicy;
+            return this;
+        }
+
+        public TlsConfig build() {
+            return new TlsConfig(
+                    handshakeTimeout,
+                    supportedProtocols,
+                    supportedCipherSuites,
+                    versionPolicy != null ? versionPolicy : HttpVersionPolicy.NEGOTIATE);
+        }
+
+    }
+
+}
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java
index 6127ce0..394a228 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java
@@ -47,6 +47,7 @@ import org.apache.hc.client5.http.auth.AuthSchemeFactory;
 import org.apache.hc.client5.http.auth.CredentialsProvider;
 import org.apache.hc.client5.http.auth.StandardAuthScheme;
 import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.config.TlsConfig;
 import org.apache.hc.client5.http.cookie.BasicCookieStore;
 import org.apache.hc.client5.http.cookie.CookieSpecFactory;
 import org.apache.hc.client5.http.cookie.CookieStore;
@@ -196,7 +197,11 @@ public class HttpAsyncClientBuilder {
 
     }
 
-    private HttpVersionPolicy versionPolicy;
+    /**
+     * @deprecated TLS should be configured by the connection manager
+     */
+    @Deprecated
+    private TlsConfig tlsConfig;
     private AsyncClientConnectionManager connManager;
     private boolean connManagerShared;
     private IOReactorConfig ioReactorConfig;
@@ -254,9 +259,12 @@ public class HttpAsyncClientBuilder {
 
     /**
      * Sets HTTP protocol version policy.
+     *
+     * @deprecated Use {@link TlsConfig} and connection nanager methods
      */
+    @Deprecated
     public final HttpAsyncClientBuilder setVersionPolicy(final HttpVersionPolicy versionPolicy) {
-        this.versionPolicy = versionPolicy;
+        this.tlsConfig = versionPolicy != null ? TlsConfig.custom().setVersionPolicy(versionPolicy).build() : null;
         return this;
     }
 
@@ -903,7 +911,6 @@ public class HttpAsyncClientBuilder {
         final IOEventHandlerFactory ioEventHandlerFactory = new HttpAsyncClientEventHandlerFactory(
                 new DefaultHttpProcessor(new H2RequestContent(), new H2RequestTargetHost(), new H2RequestConnControl()),
                 (request, context) -> pushConsumerRegistry.get(request),
-                versionPolicy != null ? versionPolicy : HttpVersionPolicy.NEGOTIATE,
                 h2Config != null ? h2Config : H2Config.DEFAULT,
                 h1Config != null ? h1Config : Http1Config.DEFAULT,
                 charCodingConfig != null ? charCodingConfig : CharCodingConfig.DEFAULT,
@@ -986,7 +993,7 @@ public class HttpAsyncClientBuilder {
                 threadFactory != null ? threadFactory : new DefaultThreadFactory("httpclient-main", true),
                 connManagerCopy,
                 routePlannerCopy,
-                versionPolicy != null ? versionPolicy : HttpVersionPolicy.NEGOTIATE,
+                tlsConfig,
                 cookieSpecRegistryCopy,
                 authSchemeRegistryCopy,
                 cookieStoreCopy,
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientEventHandlerFactory.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientEventHandlerFactory.java
index e543421..15e98de 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientEventHandlerFactory.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientEventHandlerFactory.java
@@ -74,7 +74,6 @@ class HttpAsyncClientEventHandlerFactory implements IOEventHandlerFactory {
 
     private final HttpProcessor httpProcessor;
     private final HandlerFactory<AsyncPushConsumer> exchangeHandlerFactory;
-    private final HttpVersionPolicy versionPolicy;
     private final H2Config h2Config;
     private final Http1Config h1Config;
     private final CharCodingConfig charCodingConfig;
@@ -85,14 +84,12 @@ class HttpAsyncClientEventHandlerFactory implements IOEventHandlerFactory {
     HttpAsyncClientEventHandlerFactory(
             final HttpProcessor httpProcessor,
             final HandlerFactory<AsyncPushConsumer> exchangeHandlerFactory,
-            final HttpVersionPolicy versionPolicy,
             final H2Config h2Config,
             final Http1Config h1Config,
             final CharCodingConfig charCodingConfig,
             final ConnectionReuseStrategy connectionReuseStrategy) {
         this.httpProcessor = Args.notNull(httpProcessor, "HTTP processor");
         this.exchangeHandlerFactory = exchangeHandlerFactory;
-        this.versionPolicy = versionPolicy != null ? versionPolicy : HttpVersionPolicy.NEGOTIATE;
         this.h2Config = h2Config != null ? h2Config : H2Config.DEFAULT;
         this.h1Config = h1Config != null ? h1Config : Http1Config.DEFAULT;
         this.charCodingConfig = charCodingConfig != null ? charCodingConfig : CharCodingConfig.DEFAULT;
@@ -238,7 +235,7 @@ class HttpAsyncClientEventHandlerFactory implements IOEventHandlerFactory {
                             ioSession,
                             http1StreamHandlerFactory,
                             http2StreamHandlerFactory,
-                            attachment instanceof HttpVersionPolicy ? (HttpVersionPolicy) attachment : versionPolicy);
+                            attachment instanceof HttpVersionPolicy ? (HttpVersionPolicy) attachment : null);
         }
         final ClientHttp1StreamDuplexerFactory http1StreamHandlerFactory = new ClientHttp1StreamDuplexerFactory(
                 httpProcessor,
@@ -258,7 +255,7 @@ class HttpAsyncClientEventHandlerFactory implements IOEventHandlerFactory {
                 ioSession,
                 http1StreamHandlerFactory,
                 http2StreamHandlerFactory,
-                attachment instanceof HttpVersionPolicy ? (HttpVersionPolicy) attachment : versionPolicy);
+                attachment instanceof HttpVersionPolicy ? (HttpVersionPolicy) attachment : null);
    }
 
 }
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClients.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClients.java
index f7214ed..ea8ec3a 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClients.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClients.java
@@ -30,6 +30,7 @@ package org.apache.hc.client5.http.impl.async;
 import org.apache.hc.client5.http.DnsResolver;
 import org.apache.hc.client5.http.SchemePortResolver;
 import org.apache.hc.client5.http.SystemDefaultDnsResolver;
+import org.apache.hc.client5.http.config.TlsConfig;
 import org.apache.hc.client5.http.impl.DefaultClientConnectionReuseStrategy;
 import org.apache.hc.client5.http.impl.DefaultSchemePortResolver;
 import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
@@ -122,26 +123,29 @@ public final class HttpAsyncClients {
     private static MinimalHttpAsyncClient createMinimalHttpAsyncClientImpl(
             final IOEventHandlerFactory eventHandlerFactory,
             final AsyncPushConsumerRegistry pushConsumerRegistry,
-            final HttpVersionPolicy versionPolicy,
             final IOReactorConfig ioReactorConfig,
             final AsyncClientConnectionManager connmgr,
-            final SchemePortResolver schemePortResolver) {
+            final SchemePortResolver schemePortResolver,
+            final TlsConfig tlsConfig) {
         return new MinimalHttpAsyncClient(
                 eventHandlerFactory,
                 pushConsumerRegistry,
-                versionPolicy,
                 ioReactorConfig,
                 new DefaultThreadFactory("httpclient-main", true),
                 new DefaultThreadFactory("httpclient-dispatch", true),
                 connmgr,
-                schemePortResolver);
+                schemePortResolver,
+                tlsConfig);
     }
 
     /**
      * Creates {@link MinimalHttpAsyncClient} instance optimized for
      * HTTP/1.1 and HTTP/2 message transport without advanced HTTP protocol
      * functionality.
+     *
+     * @deprecated Use {@link #createMinimal(H2Config, Http1Config, IOReactorConfig, AsyncClientConnectionManager)}
      */
+    @Deprecated
     public static MinimalHttpAsyncClient createMinimal(
             final HttpVersionPolicy versionPolicy,
             final H2Config h2Config,
@@ -153,24 +157,54 @@ public final class HttpAsyncClients {
                 new HttpAsyncClientEventHandlerFactory(
                         createMinimalProtocolProcessor(),
                         (request, context) -> pushConsumerRegistry.get(request),
-                        versionPolicy,
                         h2Config,
                         h1Config,
                         CharCodingConfig.DEFAULT,
                         DefaultClientConnectionReuseStrategy.INSTANCE),
                 pushConsumerRegistry,
-                versionPolicy,
                 ioReactorConfig,
                 connmgr,
-                DefaultSchemePortResolver.INSTANCE);
+                DefaultSchemePortResolver.INSTANCE,
+                versionPolicy != null ? TlsConfig.custom().setVersionPolicy(versionPolicy).build() : null);
     }
 
     /**
      * Creates {@link MinimalHttpAsyncClient} instance optimized for
      * HTTP/1.1 and HTTP/2 message transport without advanced HTTP protocol
      * functionality.
+     *
+     * @since 5.2
      */
     public static MinimalHttpAsyncClient createMinimal(
+            final H2Config h2Config,
+            final Http1Config h1Config,
+            final IOReactorConfig ioReactorConfig,
+            final AsyncClientConnectionManager connmgr) {
+        final AsyncPushConsumerRegistry pushConsumerRegistry = new AsyncPushConsumerRegistry();
+        return createMinimalHttpAsyncClientImpl(
+                new HttpAsyncClientEventHandlerFactory(
+                        createMinimalProtocolProcessor(),
+                        (request, context) -> pushConsumerRegistry.get(request),
+                        h2Config,
+                        h1Config,
+                        CharCodingConfig.DEFAULT,
+                        DefaultClientConnectionReuseStrategy.INSTANCE),
+                pushConsumerRegistry,
+                ioReactorConfig,
+                connmgr,
+                DefaultSchemePortResolver.INSTANCE,
+                null);
+    }
+
+    /**
+     * Creates {@link MinimalHttpAsyncClient} instance optimized for
+     * HTTP/1.1 and HTTP/2 message transport without advanced HTTP protocol
+     * functionality.
+     *
+     * @deprecated Use {@link #createMinimal(H2Config, Http1Config, IOReactorConfig)}
+     */
+    @Deprecated
+    public static MinimalHttpAsyncClient createMinimal(
             final HttpVersionPolicy versionPolicy,
             final H2Config h2Config,
             final Http1Config h1Config,
@@ -184,6 +218,19 @@ public final class HttpAsyncClients {
      * HTTP/1.1 and HTTP/2 message transport without advanced HTTP protocol
      * functionality.
      */
+    public static MinimalHttpAsyncClient createMinimal(
+            final H2Config h2Config,
+            final Http1Config h1Config,
+            final IOReactorConfig ioReactorConfig) {
+        return createMinimal(h2Config, h1Config, ioReactorConfig,
+                PoolingAsyncClientConnectionManagerBuilder.create().build());
+    }
+
+    /**
+     * Creates {@link MinimalHttpAsyncClient} instance optimized for
+     * HTTP/1.1 and HTTP/2 message transport without advanced HTTP protocol
+     * functionality.
+     */
     public static MinimalHttpAsyncClient createMinimal(final H2Config h2Config, final Http1Config h1Config) {
         return createMinimal(HttpVersionPolicy.NEGOTIATE, h2Config, h1Config, IOReactorConfig.DEFAULT);
     }
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttpAsyncClient.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttpAsyncClient.java
index 2dc8a42..746fe62 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttpAsyncClient.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttpAsyncClient.java
@@ -35,6 +35,7 @@ import org.apache.hc.client5.http.async.AsyncExecRuntime;
 import org.apache.hc.client5.http.auth.AuthSchemeFactory;
 import org.apache.hc.client5.http.auth.CredentialsProvider;
 import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.config.TlsConfig;
 import org.apache.hc.client5.http.cookie.CookieSpecFactory;
 import org.apache.hc.client5.http.cookie.CookieStore;
 import org.apache.hc.client5.http.nio.AsyncClientConnectionManager;
@@ -48,7 +49,6 @@ import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.config.Lookup;
 import org.apache.hc.core5.http.nio.AsyncPushConsumer;
 import org.apache.hc.core5.http.nio.HandlerFactory;
-import org.apache.hc.core5.http2.HttpVersionPolicy;
 import org.apache.hc.core5.reactor.DefaultConnectingIOReactor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -71,7 +71,7 @@ public final class InternalHttpAsyncClient extends InternalAbstractHttpAsyncClie
     private static final Logger LOG = LoggerFactory.getLogger(InternalHttpAsyncClient.class);
     private final AsyncClientConnectionManager manager;
     private final HttpRoutePlanner routePlanner;
-    private final HttpVersionPolicy versionPolicy;
+    private final TlsConfig tlsConfig;
 
     InternalHttpAsyncClient(
             final DefaultConnectingIOReactor ioReactor,
@@ -80,7 +80,7 @@ public final class InternalHttpAsyncClient extends InternalAbstractHttpAsyncClie
             final ThreadFactory threadFactory,
             final AsyncClientConnectionManager manager,
             final HttpRoutePlanner routePlanner,
-            final HttpVersionPolicy versionPolicy,
+            final TlsConfig tlsConfig,
             final Lookup<CookieSpecFactory> cookieSpecRegistry,
             final Lookup<AuthSchemeFactory> authSchemeRegistry,
             final CookieStore cookieStore,
@@ -91,12 +91,12 @@ public final class InternalHttpAsyncClient extends InternalAbstractHttpAsyncClie
                 cookieSpecRegistry, authSchemeRegistry, cookieStore, credentialsProvider, defaultConfig, closeables);
         this.manager = manager;
         this.routePlanner = routePlanner;
-        this.versionPolicy = versionPolicy;
+        this.tlsConfig = tlsConfig;
     }
 
     @Override
     AsyncExecRuntime createAsyncExecRuntime(final HandlerFactory<AsyncPushConsumer> pushHandlerFactory) {
-        return new InternalHttpAsyncExecRuntime(LOG, manager, getConnectionInitiator(), pushHandlerFactory, versionPolicy);
+        return new InternalHttpAsyncExecRuntime(LOG, manager, getConnectionInitiator(), pushHandlerFactory, tlsConfig);
     }
 
     @Override
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttpAsyncExecRuntime.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttpAsyncExecRuntime.java
index 3903403..ad7c565 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttpAsyncExecRuntime.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttpAsyncExecRuntime.java
@@ -33,6 +33,7 @@ import java.util.concurrent.atomic.AtomicReference;
 import org.apache.hc.client5.http.HttpRoute;
 import org.apache.hc.client5.http.async.AsyncExecRuntime;
 import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.config.TlsConfig;
 import org.apache.hc.client5.http.impl.ConnPoolSupport;
 import org.apache.hc.client5.http.impl.Operations;
 import org.apache.hc.client5.http.nio.AsyncClientConnectionManager;
@@ -44,7 +45,6 @@ import org.apache.hc.core5.concurrent.FutureCallback;
 import org.apache.hc.core5.http.nio.AsyncClientExchangeHandler;
 import org.apache.hc.core5.http.nio.AsyncPushConsumer;
 import org.apache.hc.core5.http.nio.HandlerFactory;
-import org.apache.hc.core5.http2.HttpVersionPolicy;
 import org.apache.hc.core5.io.CloseMode;
 import org.apache.hc.core5.reactor.ConnectionInitiator;
 import org.apache.hc.core5.util.TimeValue;
@@ -57,7 +57,11 @@ class InternalHttpAsyncExecRuntime implements AsyncExecRuntime {
     private final AsyncClientConnectionManager manager;
     private final ConnectionInitiator connectionInitiator;
     private final HandlerFactory<AsyncPushConsumer> pushHandlerFactory;
-    private final HttpVersionPolicy versionPolicy;
+    /**
+     * @deprecated TLS should be configured by the connection manager
+     */
+    @Deprecated
+    private final TlsConfig tlsConfig;
     private final AtomicReference<AsyncConnectionEndpoint> endpointRef;
     private volatile boolean reusable;
     private volatile Object state;
@@ -68,14 +72,14 @@ class InternalHttpAsyncExecRuntime implements AsyncExecRuntime {
             final AsyncClientConnectionManager manager,
             final ConnectionInitiator connectionInitiator,
             final HandlerFactory<AsyncPushConsumer> pushHandlerFactory,
-            final HttpVersionPolicy versionPolicy) {
+            final TlsConfig tlsConfig) {
         super();
         this.log = log;
         this.manager = manager;
         this.connectionInitiator = connectionInitiator;
         this.pushHandlerFactory = pushHandlerFactory;
-        this.versionPolicy = versionPolicy;
-        this.endpointRef = new AtomicReference<>();
+        this.tlsConfig = tlsConfig;
+        this.endpointRef = new AtomicReference<>(null);
         this.validDuration = TimeValue.NEG_ONE_MILLISECOND;
     }
 
@@ -213,7 +217,7 @@ class InternalHttpAsyncExecRuntime implements AsyncExecRuntime {
                 endpoint,
                 connectionInitiator,
                 connectTimeout,
-                versionPolicy,
+                tlsConfig,
                 context,
                 new CallbackContribution<AsyncConnectionEndpoint>(callback) {
 
@@ -242,7 +246,7 @@ class InternalHttpAsyncExecRuntime implements AsyncExecRuntime {
         if (log.isDebugEnabled()) {
             log.debug("{} upgrading endpoint", ConnPoolSupport.getId(endpoint));
         }
-        manager.upgrade(endpoint, versionPolicy, context, new CallbackContribution<AsyncConnectionEndpoint>(callback) {
+        manager.upgrade(endpoint, tlsConfig, context, new CallbackContribution<AsyncConnectionEndpoint>(callback) {
 
             @Override
             public void completed(final AsyncConnectionEndpoint endpoint) {
@@ -320,7 +324,7 @@ class InternalHttpAsyncExecRuntime implements AsyncExecRuntime {
 
     @Override
     public AsyncExecRuntime fork() {
-        return new InternalHttpAsyncExecRuntime(log, manager, connectionInitiator, pushHandlerFactory, versionPolicy);
+        return new InternalHttpAsyncExecRuntime(log, manager, connectionInitiator, pushHandlerFactory, tlsConfig);
     }
 
 }
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/MinimalHttpAsyncClient.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/MinimalHttpAsyncClient.java
index 6a7bb4e..5521eaf 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/MinimalHttpAsyncClient.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/MinimalHttpAsyncClient.java
@@ -39,6 +39,7 @@ import org.apache.hc.client5.http.HttpRoute;
 import org.apache.hc.client5.http.SchemePortResolver;
 import org.apache.hc.client5.http.config.Configurable;
 import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.config.TlsConfig;
 import org.apache.hc.client5.http.impl.ConnPoolSupport;
 import org.apache.hc.client5.http.impl.DefaultSchemePortResolver;
 import org.apache.hc.client5.http.impl.ExecSupport;
@@ -69,7 +70,6 @@ import org.apache.hc.core5.http.nio.HandlerFactory;
 import org.apache.hc.core5.http.nio.RequestChannel;
 import org.apache.hc.core5.http.nio.command.ShutdownCommand;
 import org.apache.hc.core5.http.protocol.HttpContext;
-import org.apache.hc.core5.http2.HttpVersionPolicy;
 import org.apache.hc.core5.io.CloseMode;
 import org.apache.hc.core5.io.Closer;
 import org.apache.hc.core5.reactor.Command;
@@ -101,17 +101,17 @@ public final class MinimalHttpAsyncClient extends AbstractMinimalHttpAsyncClient
     private static final Logger LOG = LoggerFactory.getLogger(MinimalHttpAsyncClient.class);
     private final AsyncClientConnectionManager manager;
     private final SchemePortResolver schemePortResolver;
-    private final HttpVersionPolicy versionPolicy;
+    private final TlsConfig tlsConfig;
 
     MinimalHttpAsyncClient(
             final IOEventHandlerFactory eventHandlerFactory,
             final AsyncPushConsumerRegistry pushConsumerRegistry,
-            final HttpVersionPolicy versionPolicy,
             final IOReactorConfig reactorConfig,
             final ThreadFactory threadFactory,
             final ThreadFactory workerThreadFactory,
             final AsyncClientConnectionManager manager,
-            final SchemePortResolver schemePortResolver) {
+            final SchemePortResolver schemePortResolver,
+            final TlsConfig tlsConfig) {
         super(new DefaultConnectingIOReactor(
                         eventHandlerFactory,
                         reactorConfig,
@@ -124,7 +124,7 @@ public final class MinimalHttpAsyncClient extends AbstractMinimalHttpAsyncClient
                 threadFactory);
         this.manager = manager;
         this.schemePortResolver = schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE;
-        this.versionPolicy = versionPolicy != null ? versionPolicy : HttpVersionPolicy.NEGOTIATE;
+        this.tlsConfig = tlsConfig;
     }
 
     private Future<AsyncConnectionEndpoint> leaseEndpoint(
@@ -153,7 +153,7 @@ public final class MinimalHttpAsyncClient extends AbstractMinimalHttpAsyncClient
                                     connectionEndpoint,
                                     getConnectionInitiator(),
                                     connectTimeout,
-                                    versionPolicy,
+                                    tlsConfig,
                                     clientContext,
                                     new FutureCallback<AsyncConnectionEndpoint>() {
 
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/BasicHttpClientConnectionManager.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/BasicHttpClientConnectionManager.java
index b9866c1..a67b3ad 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/BasicHttpClientConnectionManager.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/BasicHttpClientConnectionManager.java
@@ -39,6 +39,7 @@ import org.apache.hc.client5.http.DnsResolver;
 import org.apache.hc.client5.http.HttpRoute;
 import org.apache.hc.client5.http.SchemePortResolver;
 import org.apache.hc.client5.http.config.ConnectionConfig;
+import org.apache.hc.client5.http.config.TlsConfig;
 import org.apache.hc.client5.http.impl.ConnPoolSupport;
 import org.apache.hc.client5.http.impl.ConnectionShutdownException;
 import org.apache.hc.client5.http.io.ConnectionEndpoint;
@@ -109,6 +110,7 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
     private boolean leased;
     private SocketConfig socketConfig;
     private ConnectionConfig connectionConfig;
+    private TlsConfig tlsConfig;
 
     private final AtomicBoolean closed;
 
@@ -142,6 +144,8 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
         this.id = String.format("ep-%010d", COUNT.getAndIncrement());
         this.expiry = Long.MAX_VALUE;
         this.socketConfig = SocketConfig.DEFAULT;
+        this.connectionConfig = ConnectionConfig.DEFAULT;
+        this.tlsConfig = TlsConfig.DEFAULT;
         this.closed = new AtomicBoolean(false);
         this.validateAfterInactivity = TimeValue.ofSeconds(2L);
     }
@@ -203,6 +207,13 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
         this.connectionConfig = connectionConfig != null ? connectionConfig : ConnectionConfig.DEFAULT;
     }
 
+    /**
+     * @since 5.2
+     */
+    public synchronized void setTlsConfig(final TlsConfig tlsConfig) {
+        this.tlsConfig = tlsConfig != null ? tlsConfig : TlsConfig.DEFAULT;
+    }
+
     public LeaseRequest lease(final String id, final HttpRoute route, final Object state) {
         return lease(id, route, Timeout.DISABLED, state);
     }
@@ -358,8 +369,7 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
         } else {
             host = route.getTargetHost();
         }
-        final ConnectionConfig config = connectionConfig != null ? connectionConfig : ConnectionConfig.DEFAULT;
-        final TimeValue connectTimeout = timeout != null ? timeout : config.getConnectTimeout();
+        final Timeout connectTimeout = timeout != null ? Timeout.of(timeout.getDuration(), timeout.getTimeUnit()) : connectionConfig.getConnectTimeout();
         final ManagedHttpClientConnection connection = internalEndpoint.getConnection();
         if (LOG.isDebugEnabled()) {
             LOG.debug("{} connecting endpoint to {} ({})", ConnPoolSupport.getId(endpoint), host, connectTimeout);
@@ -369,12 +379,13 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
                 host,
                 route.getLocalSocketAddress(),
                 connectTimeout,
-                this.socketConfig,
+                socketConfig,
+                tlsConfig,
                 context);
         if (LOG.isDebugEnabled()) {
             LOG.debug("{} connected {}", ConnPoolSupport.getId(endpoint), ConnPoolSupport.getId(conn));
         }
-        final Timeout socketTimeout = config.getSocketTimeout();
+        final Timeout socketTimeout = connectionConfig.getSocketTimeout();
         if (socketTimeout != null) {
             connection.setSocketTimeout(socketTimeout);
         }
@@ -387,9 +398,11 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
         Args.notNull(endpoint, "Endpoint");
         Args.notNull(route, "HTTP route");
         final InternalConnectionEndpoint internalEndpoint = cast(endpoint);
+        final ConnectionConfig config = connectionConfig != null ? connectionConfig : ConnectionConfig.DEFAULT;
         this.connectionOperator.upgrade(
                 internalEndpoint.getConnection(),
                 internalEndpoint.getRoute().getTargetHost(),
+                tlsConfig,
                 context);
     }
 
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/DefaultHttpClientConnectionOperator.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/DefaultHttpClientConnectionOperator.java
index 926f588..8f7eef8 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/DefaultHttpClientConnectionOperator.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/DefaultHttpClientConnectionOperator.java
@@ -54,6 +54,7 @@ import org.apache.hc.core5.http.io.SocketConfig;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.util.Args;
 import org.apache.hc.core5.util.TimeValue;
+import org.apache.hc.core5.util.Timeout;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -107,6 +108,19 @@ public class DefaultHttpClientConnectionOperator implements HttpClientConnection
             final TimeValue connectTimeout,
             final SocketConfig socketConfig,
             final HttpContext context) throws IOException {
+        final Timeout timeout = connectTimeout != null ? Timeout.of(connectTimeout.getDuration(), connectTimeout.getTimeUnit()) : null;
+        connect(conn, host, localAddress, timeout, socketConfig, null, context);
+    }
+
+    @Override
+    public void connect(
+            final ManagedHttpClientConnection conn,
+            final HttpHost host,
+            final InetSocketAddress localAddress,
+            final Timeout connectTimeout,
+            final SocketConfig socketConfig,
+            final Object attachment,
+            final HttpContext context) throws IOException {
         Args.notNull(conn, "Connection");
         Args.notNull(host, "Host");
         Args.notNull(socketConfig, "Socket config");
@@ -131,13 +145,17 @@ public class DefaultHttpClientConnectionOperator implements HttpClientConnection
             }
         }
 
+        final Timeout soTimeout = socketConfig.getSoTimeout();
+
         final int port = this.schemePortResolver.resolve(host);
         for (int i = 0; i < remoteAddresses.length; i++) {
             final InetAddress address = remoteAddresses[i];
             final boolean last = i == remoteAddresses.length - 1;
 
             Socket sock = sf.createSocket(context);
-            sock.setSoTimeout(socketConfig.getSoTimeout().toMillisecondsIntBound());
+            if (soTimeout != null) {
+                sock.setSoTimeout(soTimeout.toMillisecondsIntBound());
+            }
             sock.setReuseAddress(socketConfig.isSoReuseAddress());
             sock.setTcpNoDelay(socketConfig.isTcpNoDelay());
             sock.setKeepAlive(socketConfig.isSoKeepAlive());
@@ -160,8 +178,9 @@ public class DefaultHttpClientConnectionOperator implements HttpClientConnection
                         host.getHostName(), host.getPort(), localAddress, remoteAddress, connectTimeout);
             }
             try {
-                sock = sf.connectSocket(connectTimeout, sock, host, remoteAddress, localAddress, context);
+                sock = sf.connectSocket(sock, host, remoteAddress, localAddress, connectTimeout, attachment, context);
                 conn.bind(sock);
+                conn.setSocketTimeout(soTimeout);
                 if (LOG.isDebugEnabled()) {
                     LOG.debug("{}:{} connected {}->{} as {}",
                             host.getHostName(), host.getPort(), localAddress, remoteAddress, ConnPoolSupport.getId(conn));
@@ -189,6 +208,15 @@ public class DefaultHttpClientConnectionOperator implements HttpClientConnection
             final ManagedHttpClientConnection conn,
             final HttpHost host,
             final HttpContext context) throws IOException {
+        upgrade(conn, host, null, context);
+    }
+
+    @Override
+    public void upgrade(
+            final ManagedHttpClientConnection conn,
+            final HttpHost host,
+            final Object attachment,
+            final HttpContext context) throws IOException {
         final HttpClientContext clientContext = HttpClientContext.adapt(context);
         final Lookup<ConnectionSocketFactory> registry = getSocketFactoryRegistry(clientContext);
         final ConnectionSocketFactory sf = registry.lookup(host.getSchemeName());
@@ -206,7 +234,7 @@ public class DefaultHttpClientConnectionOperator implements HttpClientConnection
             throw new ConnectionClosedException("Connection is closed");
         }
         final int port = this.schemePortResolver.resolve(host);
-        sock = lsf.createLayeredSocket(sock, host.getHostName(), port, context);
+        sock = lsf.createLayeredSocket(sock, host.getHostName(), port, attachment, context);
         conn.bind(sock);
     }
 
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManager.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManager.java
index 22a29e9..8c415fc 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManager.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManager.java
@@ -39,6 +39,7 @@ import org.apache.hc.client5.http.DnsResolver;
 import org.apache.hc.client5.http.HttpRoute;
 import org.apache.hc.client5.http.SchemePortResolver;
 import org.apache.hc.client5.http.config.ConnectionConfig;
+import org.apache.hc.client5.http.config.TlsConfig;
 import org.apache.hc.client5.http.impl.ConnPoolSupport;
 import org.apache.hc.client5.http.impl.ConnectionShutdownException;
 import org.apache.hc.client5.http.io.ConnectionEndpoint;
@@ -115,6 +116,7 @@ public class PoolingHttpClientConnectionManager
 
     private volatile Resolver<HttpRoute, SocketConfig> socketConfigResolver;
     private volatile Resolver<HttpRoute, ConnectionConfig> connectionConfigResolver;
+    private volatile Resolver<HttpHost, TlsConfig> tlsConfigResolver;
 
     public PoolingHttpClientConnectionManager() {
         this(RegistryBuilder.<ConnectionSocketFactory>create()
@@ -241,16 +243,22 @@ public class PoolingHttpClientConnectionManager
         throw new IllegalStateException("Unexpected endpoint class: " + endpoint.getClass());
     }
 
+    private SocketConfig resolveSocketConfig(final HttpRoute route) {
+        final Resolver<HttpRoute, SocketConfig> resolver = this.socketConfigResolver;
+        final SocketConfig socketConfig = resolver != null ? resolver.resolve(route) : null;
+        return socketConfig != null ? socketConfig : SocketConfig.DEFAULT;
+    }
+
     private ConnectionConfig resolveConnectionConfig(final HttpRoute route) {
         final Resolver<HttpRoute, ConnectionConfig> resolver = this.connectionConfigResolver;
         final ConnectionConfig connectionConfig = resolver != null ? resolver.resolve(route) : null;
         return connectionConfig != null ? connectionConfig : ConnectionConfig.DEFAULT;
     }
 
-    private SocketConfig resolveSocketConfig(final HttpRoute route) {
-        final Resolver<HttpRoute, SocketConfig> resolver = this.socketConfigResolver;
-        final SocketConfig socketConfig = resolver != null ? resolver.resolve(route) : null;
-        return socketConfig != null ? socketConfig : SocketConfig.DEFAULT;
+    private TlsConfig resolveTlsConfig(final HttpHost host) {
+        final Resolver<HttpHost, TlsConfig> resolver = this.tlsConfigResolver;
+        final TlsConfig tlsConfig = resolver != null ? resolver.resolve(host) : null;
+        return tlsConfig != null ? tlsConfig : TlsConfig.DEFAULT;
     }
 
     private TimeValue resolveValidateAfterInactivity(final ConnectionConfig connectionConfig) {
@@ -401,15 +409,11 @@ public class PoolingHttpClientConnectionManager
             poolEntry.assignConnection(connFactory.createConnection(null));
         }
         final HttpRoute route = poolEntry.getRoute();
-        final HttpHost host;
-        if (route.getProxyHost() != null) {
-            host = route.getProxyHost();
-        } else {
-            host = route.getTargetHost();
-        }
+        final HttpHost host = route.getProxyHost() != null ? route.getProxyHost() : route.getTargetHost();
         final SocketConfig socketConfig = resolveSocketConfig(route);
         final ConnectionConfig connectionConfig = resolveConnectionConfig(route);
-        final TimeValue connectTimeout = timeout != null ? timeout : connectionConfig.getConnectTimeout();
+        final TlsConfig tlsConfig = resolveTlsConfig(host);
+        final Timeout connectTimeout = timeout != null ? Timeout.of(timeout.getDuration(), timeout.getTimeUnit()) : connectionConfig.getConnectTimeout();
         if (LOG.isDebugEnabled()) {
             LOG.debug("{} connecting endpoint to {} ({})", ConnPoolSupport.getId(endpoint), host, connectTimeout);
         }
@@ -418,8 +422,9 @@ public class PoolingHttpClientConnectionManager
                 conn,
                 host,
                 route.getLocalSocketAddress(),
-                timeout,
+                connectTimeout,
                 socketConfig,
+                tlsConfig,
                 context);
         if (LOG.isDebugEnabled()) {
             LOG.debug("{} connected {}", ConnPoolSupport.getId(endpoint), ConnPoolSupport.getId(conn));
@@ -436,7 +441,9 @@ public class PoolingHttpClientConnectionManager
         final InternalConnectionEndpoint internalEndpoint = cast(endpoint);
         final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry = internalEndpoint.getValidatedPoolEntry();
         final HttpRoute route = poolEntry.getRoute();
-        this.connectionOperator.upgrade(poolEntry.getConnection(), route.getTargetHost(), context);
+        final HttpHost host = route.getProxyHost() != null ? route.getProxyHost() : route.getTargetHost();
+        final TlsConfig tlsConfig = resolveTlsConfig(host);
+        this.connectionOperator.upgrade(poolEntry.getConnection(), route.getTargetHost(), tlsConfig, context);
     }
 
     @Override
@@ -534,6 +541,24 @@ public class PoolingHttpClientConnectionManager
     }
 
     /**
+     * Sets the same {@link ConnectionConfig} for all hosts
+     *
+     * @since 5.2
+     */
+    public void setDefaultTlsConfig(final TlsConfig config) {
+        this.tlsConfigResolver = (host) -> config;
+    }
+
+    /**
+     * Sets {@link Resolver} of {@link TlsConfig} on a per host basis.
+     *
+     * @since 5.2
+     */
+    public void setTlsConfigResolver(final Resolver<HttpHost, TlsConfig> tlsConfigResolver) {
+        this.tlsConfigResolver = tlsConfigResolver;
+    }
+
+    /**
      * @deprecated Use custom {@link #setConnectionConfigResolver(Resolver)}
      */
     @Deprecated
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManagerBuilder.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManagerBuilder.java
index e52f9ac..c150e23 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManagerBuilder.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManagerBuilder.java
@@ -31,12 +31,14 @@ import org.apache.hc.client5.http.DnsResolver;
 import org.apache.hc.client5.http.HttpRoute;
 import org.apache.hc.client5.http.SchemePortResolver;
 import org.apache.hc.client5.http.config.ConnectionConfig;
+import org.apache.hc.client5.http.config.TlsConfig;
 import org.apache.hc.client5.http.io.ManagedHttpClientConnection;
 import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
 import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
 import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
 import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
 import org.apache.hc.core5.function.Resolver;
+import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.URIScheme;
 import org.apache.hc.core5.http.config.RegistryBuilder;
 import org.apache.hc.core5.http.io.HttpConnectionFactory;
@@ -81,6 +83,7 @@ public class PoolingHttpClientConnectionManagerBuilder {
     private PoolReusePolicy poolReusePolicy;
     private Resolver<HttpRoute, SocketConfig> socketConfigResolver;
     private Resolver<HttpRoute, ConnectionConfig> connectionConfigResolver;
+    private Resolver<HttpHost, TlsConfig> tlsConfigResolver;
 
     private boolean systemProperties;
 
@@ -204,6 +207,27 @@ public class PoolingHttpClientConnectionManagerBuilder {
     }
 
     /**
+     * Assigns the same {@link TlsConfig} for all hosts.
+     *
+     * @since 5.2
+     */
+    public final PoolingHttpClientConnectionManagerBuilder setDefaultTlsConfig(final TlsConfig config) {
+        this.tlsConfigResolver = (host) -> config;
+        return this;
+    }
+
+    /**
+     * Assigns {@link Resolver} of {@link TlsConfig} on a per host basis.
+     *
+     * @since 5.2
+     */
+    public final PoolingHttpClientConnectionManagerBuilder setTlsConfigResolver(
+            final Resolver<HttpHost, TlsConfig> tlsConfigResolver) {
+        this.tlsConfigResolver = tlsConfigResolver;
+        return this;
+    }
+
+    /**
      * Sets maximum time to live for persistent connections
      */
     public final PoolingHttpClientConnectionManagerBuilder setConnectionTimeToLive(final TimeValue timeToLive) {
@@ -251,6 +275,7 @@ public class PoolingHttpClientConnectionManagerBuilder {
                 connectionFactory);
         poolingmgr.setSocketConfigResolver(socketConfigResolver);
         poolingmgr.setConnectionConfigResolver(connectionConfigResolver);
+        poolingmgr.setTlsConfigResolver(tlsConfigResolver);
         if (maxConnTotal > 0) {
             poolingmgr.setMaxTotal(maxConnTotal);
         }
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/DefaultAsyncClientConnectionOperator.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/DefaultAsyncClientConnectionOperator.java
index a781e9b..130eb6b 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/DefaultAsyncClientConnectionOperator.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/DefaultAsyncClientConnectionOperator.java
@@ -34,6 +34,7 @@ import java.util.concurrent.Future;
 
 import org.apache.hc.client5.http.DnsResolver;
 import org.apache.hc.client5.http.SchemePortResolver;
+import org.apache.hc.client5.http.config.TlsConfig;
 import org.apache.hc.client5.http.impl.DefaultSchemePortResolver;
 import org.apache.hc.client5.http.nio.AsyncClientConnectionOperator;
 import org.apache.hc.client5.http.nio.ManagedAsyncClientConnection;
@@ -81,13 +82,14 @@ final class DefaultAsyncClientConnectionOperator implements AsyncClientConnectio
         final HttpHost remoteEndpoint = RoutingSupport.normalize(host, schemePortResolver);
         final InetAddress remoteAddress = host.getAddress();
         final TlsStrategy tlsStrategy = tlsStrategyLookup != null ? tlsStrategyLookup.lookup(host.getSchemeName()) : null;
+        final TlsConfig tlsConfig = attachment instanceof TlsConfig ? (TlsConfig) attachment : TlsConfig.DEFAULT;
         final Future<IOSession> sessionFuture = sessionRequester.connect(
                 connectionInitiator,
                 remoteEndpoint,
                 remoteAddress != null ? new InetSocketAddress(remoteAddress, remoteEndpoint.getPort()) : null,
                 localAddress,
                 connectTimeout,
-                attachment,
+                tlsConfig.getHttpVersionPolicy(),
                 new FutureCallback<IOSession>() {
 
                     @Override
@@ -95,15 +97,18 @@ final class DefaultAsyncClientConnectionOperator implements AsyncClientConnectio
                         final DefaultManagedAsyncClientConnection connection = new DefaultManagedAsyncClientConnection(session);
                         if (tlsStrategy != null && URIScheme.HTTPS.same(host.getSchemeName())) {
                             try {
+                                final Timeout socketTimeout = connection.getSocketTimeout();
+                                final Timeout handshakeTimeout = tlsConfig.getHandshakeTimeout();
                                 tlsStrategy.upgrade(
                                         connection,
                                         host,
                                         attachment,
-                                        null,
+                                        handshakeTimeout != null ? handshakeTimeout : connectTimeout,
                                         new FutureContribution<TransportSecurityLayer>(future) {
 
                                             @Override
                                             public void completed(final TransportSecurityLayer transportSecurityLayer) {
+                                                connection.setSocketTimeout(socketTimeout);
                                                 future.completed(connection);
                                             }
 
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManager.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManager.java
index 3617b59..d507154 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManager.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManager.java
@@ -41,6 +41,7 @@ import org.apache.hc.client5.http.DnsResolver;
 import org.apache.hc.client5.http.HttpRoute;
 import org.apache.hc.client5.http.SchemePortResolver;
 import org.apache.hc.client5.http.config.ConnectionConfig;
+import org.apache.hc.client5.http.config.TlsConfig;
 import org.apache.hc.client5.http.impl.ConnPoolSupport;
 import org.apache.hc.client5.http.impl.ConnectionShutdownException;
 import org.apache.hc.client5.http.nio.AsyncClientConnectionManager;
@@ -123,6 +124,7 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
     private final AtomicBoolean closed;
 
     private volatile Resolver<HttpRoute, ConnectionConfig> connectionConfigResolver;
+    private volatile Resolver<HttpHost, TlsConfig> tlsConfigResolver;
 
     public PoolingAsyncClientConnectionManager() {
         this(RegistryBuilder.<TlsStrategy>create()
@@ -227,6 +229,15 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
         return connectionConfig != null ? connectionConfig : ConnectionConfig.DEFAULT;
     }
 
+    private TlsConfig resolveTlsConfig(final HttpHost host, final Object attachment) {
+        if (attachment instanceof TlsConfig) {
+            return (TlsConfig) attachment;
+         }
+        final Resolver<HttpHost, TlsConfig> resolver = this.tlsConfigResolver;
+        final TlsConfig tlsConfig = resolver != null ? resolver.resolve(host) : null;
+        return tlsConfig != null ? tlsConfig : TlsConfig.DEFAULT;
+    }
+
     @Override
     public Future<AsyncConnectionEndpoint> lease(
             final String id,
@@ -400,6 +411,7 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
         }
         final InetSocketAddress localAddress = route.getLocalSocketAddress();
         final ConnectionConfig connectionConfig = resolveConnectionConfig(route);
+        final TlsConfig tlsConfig = resolveTlsConfig(host, attachment);
         final Timeout connectTimeout = timeout != null ? timeout : connectionConfig.getConnectTimeout();
 
         if (LOG.isDebugEnabled()) {
@@ -410,7 +422,9 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
                 host,
                 localAddress,
                 connectTimeout,
-                route.isTunnelled() ? HttpVersionPolicy.FORCE_HTTP_1 : attachment,
+                route.isTunnelled() ? TlsConfig.copy(tlsConfig)
+                        .setVersionPolicy(HttpVersionPolicy.FORCE_HTTP_1)
+                        .build() : tlsConfig,
                 new FutureCallback<ManagedAsyncClientConnection>() {
 
                     @Override
@@ -455,10 +469,12 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
         final InternalConnectionEndpoint internalEndpoint = cast(endpoint);
         final PoolEntry<HttpRoute, ManagedAsyncClientConnection> poolEntry = internalEndpoint.getValidatedPoolEntry();
         final HttpRoute route = poolEntry.getRoute();
+        final HttpHost host = route.getProxyHost() != null ? route.getProxyHost() : route.getTargetHost();
+        final TlsConfig tlsConfig = resolveTlsConfig(host, attachment);
         connectionOperator.upgrade(
                 poolEntry.getConnection(),
                 route.getTargetHost(),
-                attachment,
+                attachment != null ? attachment : tlsConfig,
                 new CallbackContribution<ManagedAsyncClientConnection>(callback) {
 
                     @Override
@@ -567,6 +583,24 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
     }
 
     /**
+     * Sets the same {@link ConnectionConfig} for all hosts
+     *
+     * @since 5.2
+     */
+    public void setDefaultTlsConfig(final TlsConfig config) {
+        this.tlsConfigResolver = (host) -> config;
+    }
+
+    /**
+     * Sets {@link Resolver} of {@link TlsConfig} on a per host basis.
+     *
+     * @since 5.2
+     */
+    public void setTlsConfigResolver(final Resolver<HttpHost, TlsConfig> tlsConfigResolver) {
+        this.tlsConfigResolver = tlsConfigResolver;
+    }
+
+    /**
      * @deprecated Use custom {@link #setConnectionConfigResolver(Resolver)}
      */
     @Deprecated
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManagerBuilder.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManagerBuilder.java
index a8d44b0..122e000 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManagerBuilder.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManagerBuilder.java
@@ -31,9 +31,11 @@ import org.apache.hc.client5.http.DnsResolver;
 import org.apache.hc.client5.http.HttpRoute;
 import org.apache.hc.client5.http.SchemePortResolver;
 import org.apache.hc.client5.http.config.ConnectionConfig;
+import org.apache.hc.client5.http.config.TlsConfig;
 import org.apache.hc.client5.http.ssl.ConscryptClientTlsStrategy;
 import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
 import org.apache.hc.core5.function.Resolver;
+import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.config.RegistryBuilder;
 import org.apache.hc.core5.http.io.SocketConfig;
 import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
@@ -83,6 +85,7 @@ public class PoolingAsyncClientConnectionManagerBuilder {
 
     private Resolver<HttpRoute, SocketConfig> socketConfigResolver;
     private Resolver<HttpRoute, ConnectionConfig> connectionConfigResolver;
+    private Resolver<HttpHost, TlsConfig> tlsConfigResolver;
     private TimeValue timeToLive;
 
     public static PoolingAsyncClientConnectionManagerBuilder create() {
@@ -171,6 +174,26 @@ public class PoolingAsyncClientConnectionManagerBuilder {
         return this;
     }
 
+    /**
+     * Assigns the same {@link TlsConfig} for all hosts.
+     *
+     * @since 5.2
+     */
+    public final PoolingAsyncClientConnectionManagerBuilder setDefaultTlsConfig(final TlsConfig config) {
+        this.tlsConfigResolver = (host) -> config;
+        return this;
+    }
+
+    /**
+     * Assigns {@link Resolver} of {@link TlsConfig} on a per host basis.
+     *
+     * @since 5.2
+     */
+    public final PoolingAsyncClientConnectionManagerBuilder setTlsConfigResolver(
+            final Resolver<HttpHost, TlsConfig> tlsConfigResolver) {
+        this.tlsConfigResolver = tlsConfigResolver;
+        return this;
+    }
 
     /**
      * Sets maximum time to live for persistent connections
@@ -232,6 +255,7 @@ public class PoolingAsyncClientConnectionManagerBuilder {
                 schemePortResolver,
                 dnsResolver);
         poolingmgr.setConnectionConfigResolver(connectionConfigResolver);
+        poolingmgr.setTlsConfigResolver(tlsConfigResolver);
         if (maxConnTotal > 0) {
             poolingmgr.setMaxTotal(maxConnTotal);
         }
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/io/HttpClientConnectionOperator.java b/httpclient5/src/main/java/org/apache/hc/client5/http/io/HttpClientConnectionOperator.java
index d1bf4fa..f533fef 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/io/HttpClientConnectionOperator.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/io/HttpClientConnectionOperator.java
@@ -37,6 +37,7 @@ import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.io.SocketConfig;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.util.TimeValue;
+import org.apache.hc.core5.util.Timeout;
 
 /**
  * Connection operator that performs connection connect and upgrade operations.
@@ -66,6 +67,30 @@ public interface HttpClientConnectionOperator {
             HttpContext context) throws IOException;
 
     /**
+     * Connect the given managed connection to the remote endpoint.
+     *
+     * @param conn the managed connection.
+     * @param host the address of the opposite endpoint.
+     * @param localAddress the address of the local endpoint.
+     * @param connectTimeout the timeout of the connect operation.
+     * @param socketConfig the socket configuration.
+     * @param attachment connect request attachment.
+     * @param context the execution context.
+     *
+     * @since 5.2
+     */
+    default void connect(
+            ManagedHttpClientConnection conn,
+            HttpHost host,
+            InetSocketAddress localAddress,
+            Timeout connectTimeout,
+            SocketConfig socketConfig,
+            Object attachment,
+            HttpContext context) throws IOException {
+        connect(conn, host, localAddress, connectTimeout, socketConfig, context);
+    }
+
+    /**
      * Upgrades transport security of the given managed connection
      * by using the TLS security protocol.
      *
@@ -78,4 +103,23 @@ public interface HttpClientConnectionOperator {
             HttpHost host,
             HttpContext context) throws IOException;
 
+    /**
+     * Upgrades transport security of the given managed connection
+     * by using the TLS security protocol.
+     *
+     * @param conn the managed connection.
+     * @param host the address of the opposite endpoint with TLS security.
+     * @param attachment connect request attachment.
+     * @param context the execution context.
+     *
+     * @since 5.2
+     */
+    default void upgrade(
+            ManagedHttpClientConnection conn,
+            HttpHost host,
+            Object attachment,
+            HttpContext context) throws IOException {
+        upgrade(conn, host, context);
+    }
+
 }
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/nio/AsyncClientConnectionOperator.java b/httpclient5/src/main/java/org/apache/hc/client5/http/nio/AsyncClientConnectionOperator.java
index af12604..f368e79 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/nio/AsyncClientConnectionOperator.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/nio/AsyncClientConnectionOperator.java
@@ -67,7 +67,6 @@ public interface AsyncClientConnectionOperator {
             Object attachment,
             FutureCallback<ManagedAsyncClientConnection> callback);
 
-
     /**
      * Upgrades transport security of the given managed connection
      * by using the TLS security protocol.
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/socket/ConnectionSocketFactory.java b/httpclient5/src/main/java/org/apache/hc/client5/http/socket/ConnectionSocketFactory.java
index 88cafd0..f8d2e6f 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/socket/ConnectionSocketFactory.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/socket/ConnectionSocketFactory.java
@@ -36,6 +36,7 @@ import org.apache.hc.core5.annotation.ThreadingBehavior;
 import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.util.TimeValue;
+import org.apache.hc.core5.util.Timeout;
 
 /**
  * A factory for creating and connecting connection sockets.
@@ -81,4 +82,35 @@ public interface ConnectionSocketFactory {
         InetSocketAddress localAddress,
         HttpContext context) throws IOException;
 
+    /**
+     * Connects the socket to the target host with the given resolved remote address.
+     *
+     * @param socket the socket to connect, as obtained from {@link #createSocket(HttpContext)}.
+     * {@code null} indicates that a new socket should be created and connected.
+     * @param host target host as specified by the caller (end user).
+     * @param remoteAddress the resolved remote address to connect to.
+     * @param localAddress the local address to bind the socket to, or {@code null} for any.
+     * @param connectTimeout connect timeout.
+     * @param attachment connect request attachment.
+     * @param context the actual HTTP context.
+     *
+     * @return  the connected socket. The returned object may be different
+     *          from the {@code sock} argument if this factory supports
+     *          a layered protocol.
+     *
+     * @throws IOException if an I/O error occurs
+     *
+     * @since 5.2
+     */
+    default Socket connectSocket(
+            Socket socket,
+            HttpHost host,
+            InetSocketAddress remoteAddress,
+            InetSocketAddress localAddress,
+            Timeout connectTimeout,
+            Object attachment,
+            HttpContext context) throws IOException {
+        return connectSocket(connectTimeout, socket, host, remoteAddress, localAddress, context);
+    }
+
 }
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/socket/LayeredConnectionSocketFactory.java b/httpclient5/src/main/java/org/apache/hc/client5/http/socket/LayeredConnectionSocketFactory.java
index d35c296..36dfa80 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/socket/LayeredConnectionSocketFactory.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/socket/LayeredConnectionSocketFactory.java
@@ -62,4 +62,30 @@ public interface LayeredConnectionSocketFactory extends ConnectionSocketFactory
         int port,
         HttpContext context) throws IOException;
 
+    /**
+     * Returns a socket connected to the given host that is layered over an
+     * existing socket.  Used primarily for creating secure sockets through
+     * proxies.
+     *
+     * @param socket the existing socket
+     * @param target the name of the target host.
+     * @param port the port to connect to on the target host.
+     * @param context the actual HTTP context.
+     * @param attachment connect request attachment.
+     *
+     * @return Socket a new socket
+     *
+     * @throws IOException if an I/O error occurs while creating the socket
+     *
+     * @since 5.2
+     */
+    default Socket createLayeredSocket(
+            Socket socket,
+            String target,
+            int port,
+            Object attachment,
+            HttpContext context) throws IOException {
+        return createLayeredSocket(socket, target, port, context);
+    }
+
 }
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/ssl/AbstractClientTlsStrategy.java b/httpclient5/src/main/java/org/apache/hc/client5/http/ssl/AbstractClientTlsStrategy.java
index 45a66f7..21c72c3 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/ssl/AbstractClientTlsStrategy.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/ssl/AbstractClientTlsStrategy.java
@@ -38,6 +38,7 @@ import javax.net.ssl.SSLHandshakeException;
 import javax.net.ssl.SSLParameters;
 import javax.net.ssl.SSLSession;
 
+import org.apache.hc.client5.http.config.TlsConfig;
 import org.apache.hc.core5.annotation.Contract;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
 import org.apache.hc.core5.concurrent.FutureCallback;
@@ -109,17 +110,23 @@ abstract class AbstractClientTlsStrategy implements TlsStrategy {
             final FutureCallback<TransportSecurityLayer> callback) {
         tlsSession.startTls(sslContext, endpoint, sslBufferManagement, (e, sslEngine) -> {
 
-            final HttpVersionPolicy versionPolicy = attachment instanceof HttpVersionPolicy ?
-                    (HttpVersionPolicy) attachment : HttpVersionPolicy.NEGOTIATE;
+            final TlsConfig tlsConfig = attachment instanceof TlsConfig ? (TlsConfig) attachment : TlsConfig.DEFAULT;
+            final HttpVersionPolicy versionPolicy = tlsConfig.getHttpVersionPolicy();
 
             final SSLParameters sslParameters = sslEngine.getSSLParameters();
+            final String[] supportedProtocols = tlsConfig.getSupportedProtocols();
             if (supportedProtocols != null) {
                 sslParameters.setProtocols(supportedProtocols);
+            } else if (this.supportedProtocols != null) {
+                sslParameters.setProtocols(this.supportedProtocols);
             } else if (versionPolicy != HttpVersionPolicy.FORCE_HTTP_1) {
                 sslParameters.setProtocols(TLS.excludeWeak(sslParameters.getProtocols()));
             }
+            final String[] supportedCipherSuites = tlsConfig.getSupportedCipherSuites();
             if (supportedCipherSuites != null) {
                 sslParameters.setCipherSuites(supportedCipherSuites);
+            } else if (this.supportedCipherSuites != null) {
+                sslParameters.setCipherSuites(this.supportedCipherSuites);
             } else if (versionPolicy == HttpVersionPolicy.FORCE_HTTP_2) {
                 sslParameters.setCipherSuites(TlsCiphers.excludeH2Blacklisted(sslParameters.getCipherSuites()));
             }
@@ -135,6 +142,7 @@ abstract class AbstractClientTlsStrategy implements TlsStrategy {
             if (LOG.isDebugEnabled()) {
                 LOG.debug("Enabled protocols: {}", Arrays.asList(sslEngine.getEnabledProtocols()));
                 LOG.debug("Enabled cipher suites:{}", Arrays.asList(sslEngine.getEnabledCipherSuites()));
+                LOG.debug("Starting handshake ({})", handshakeTimeout);
             }
         }, (e, sslEngine) -> {
             verifySession(endpoint.getHostName(), sslEngine.getSession());
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/ssl/SSLConnectionSocketFactory.java b/httpclient5/src/main/java/org/apache/hc/client5/http/ssl/SSLConnectionSocketFactory.java
index 2a29e91..59a8df5 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/ssl/SSLConnectionSocketFactory.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/ssl/SSLConnectionSocketFactory.java
@@ -47,6 +47,7 @@ import javax.net.ssl.SSLHandshakeException;
 import javax.net.ssl.SSLSession;
 import javax.net.ssl.SSLSocket;
 
+import org.apache.hc.client5.http.config.TlsConfig;
 import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
 import org.apache.hc.core5.annotation.Contract;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
@@ -60,6 +61,7 @@ import org.apache.hc.core5.ssl.SSLInitializationException;
 import org.apache.hc.core5.util.Args;
 import org.apache.hc.core5.util.Asserts;
 import org.apache.hc.core5.util.TimeValue;
+import org.apache.hc.core5.util.Timeout;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -200,6 +202,19 @@ public class SSLConnectionSocketFactory implements LayeredConnectionSocketFactor
             final InetSocketAddress remoteAddress,
             final InetSocketAddress localAddress,
             final HttpContext context) throws IOException {
+        final Timeout timeout = connectTimeout != null ? Timeout.of(connectTimeout.getDuration(), connectTimeout.getTimeUnit()) : null;
+        return connectSocket(socket, host, remoteAddress, localAddress, timeout, timeout, context);
+    }
+
+    @Override
+    public Socket connectSocket(
+            final Socket socket,
+            final HttpHost host,
+            final InetSocketAddress remoteAddress,
+            final InetSocketAddress localAddress,
+            final Timeout connectTimeout,
+            final Object attachment,
+            final HttpContext context) throws IOException {
         Args.notNull(host, "HTTP host");
         Args.notNull(remoteAddress, "Remote address");
         final Socket sock = socket != null ? socket : createSocket(context);
@@ -214,7 +229,7 @@ public class SSLConnectionSocketFactory implements LayeredConnectionSocketFactor
             // only to this library
             try {
                 AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
-                    sock.connect(remoteAddress, connectTimeout != null ? connectTimeout.toMillisecondsIntBound() : 0);
+                    sock.connect(remoteAddress, Timeout.defaultsToDisabled(connectTimeout).toMillisecondsIntBound());
                     return null;
                 });
             } catch (final PrivilegedActionException e) {
@@ -230,12 +245,19 @@ public class SSLConnectionSocketFactory implements LayeredConnectionSocketFactor
         // Setup SSL layering if necessary
         if (sock instanceof SSLSocket) {
             final SSLSocket sslsock = (SSLSocket) sock;
-            LOG.debug("Starting handshake");
-            sslsock.startHandshake();
-            verifyHostname(sslsock, host.getHostName());
+            executeHandshake(sslsock, host.getHostName(), attachment);
             return sock;
         }
-        return createLayeredSocket(sock, host.getHostName(), remoteAddress.getPort(), context);
+        return createLayeredSocket(sock, host.getHostName(), remoteAddress.getPort(), attachment, context);
+    }
+
+    @Override
+    public Socket createLayeredSocket(
+            final Socket socket,
+            final String target,
+            final int port,
+            final HttpContext context) throws IOException {
+        return createLayeredSocket(socket, target, port, context);
     }
 
     @Override
@@ -243,12 +265,19 @@ public class SSLConnectionSocketFactory implements LayeredConnectionSocketFactor
             final Socket socket,
             final String target,
             final int port,
+            final Object attachment,
             final HttpContext context) throws IOException {
         final SSLSocket sslsock = (SSLSocket) this.socketFactory.createSocket(
                 socket,
                 target,
                 port,
                 true);
+        executeHandshake(sslsock, target, attachment);
+        return sslsock;
+    }
+
+    private void executeHandshake(final SSLSocket sslsock, final String target, final Object attachment) throws IOException {
+        final TlsConfig tlsConfig = attachment instanceof TlsConfig ? (TlsConfig) attachment : TlsConfig.DEFAULT;
         if (supportedProtocols != null) {
             sslsock.setEnabledProtocols(supportedProtocols);
         } else {
@@ -259,17 +288,20 @@ public class SSLConnectionSocketFactory implements LayeredConnectionSocketFactor
         } else {
             sslsock.setEnabledCipherSuites(TlsCiphers.excludeWeak(sslsock.getEnabledCipherSuites()));
         }
+        final Timeout handshakeTimeout = tlsConfig.getHandshakeTimeout();
+        if (handshakeTimeout != null) {
+            sslsock.setSoTimeout(handshakeTimeout.toMillisecondsIntBound());
+        }
+
+        prepareSocket(sslsock);
 
         if (LOG.isDebugEnabled()) {
             LOG.debug("Enabled protocols: {}", (Object) sslsock.getEnabledProtocols());
             LOG.debug("Enabled cipher suites: {}", (Object) sslsock.getEnabledCipherSuites());
+            LOG.debug("Starting handshake ({})", handshakeTimeout);
         }
-
-        prepareSocket(sslsock);
-        LOG.debug("Starting handshake");
         sslsock.startHandshake();
         verifyHostname(sslsock, target);
-        return sslsock;
     }
 
     private void verifyHostname(final SSLSocket sslsock, final String hostname) throws IOException {
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientFullDuplexExchange.java b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientFullDuplexExchange.java
index a396ca3..a30661c 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientFullDuplexExchange.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientFullDuplexExchange.java
@@ -52,11 +52,9 @@ import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
 import org.apache.hc.core5.http.nio.support.BasicResponseConsumer;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.http.support.BasicRequestBuilder;
-import org.apache.hc.core5.http2.HttpVersionPolicy;
 import org.apache.hc.core5.http2.config.H2Config;
 import org.apache.hc.core5.io.CloseMode;
 import org.apache.hc.core5.reactor.IOReactorConfig;
-import org.apache.hc.core5.util.Timeout;
 
 /**
  * This example demonstrates a full-duplex, streaming HTTP/1.1 message exchange.
@@ -65,15 +63,10 @@ public class AsyncClientFullDuplexExchange {
 
     public static void main(final String[] args) throws Exception {
 
-        final IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
-                .setSoTimeout(Timeout.ofSeconds(5))
-                .build();
-
         final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal(
-                HttpVersionPolicy.NEGOTIATE,
                 H2Config.DEFAULT,
                 Http1Config.DEFAULT,
-                ioReactorConfig);
+                IOReactorConfig.DEFAULT);
 
         client.start();
 
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientH2FullDuplexExchange.java b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientH2FullDuplexExchange.java
index aa90bb2..b221c7f 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientH2FullDuplexExchange.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientH2FullDuplexExchange.java
@@ -32,13 +32,16 @@ import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.hc.client5.http.config.TlsConfig;
 import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
 import org.apache.hc.client5.http.impl.async.MinimalHttpAsyncClient;
+import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
 import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.EntityDetails;
 import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpException;
 import org.apache.hc.core5.http.HttpResponse;
+import org.apache.hc.core5.http.config.Http1Config;
 import org.apache.hc.core5.http.message.BasicHttpRequest;
 import org.apache.hc.core5.http.message.StatusLine;
 import org.apache.hc.core5.http.nio.AsyncClientExchangeHandler;
@@ -55,7 +58,6 @@ import org.apache.hc.core5.http2.HttpVersionPolicy;
 import org.apache.hc.core5.http2.config.H2Config;
 import org.apache.hc.core5.io.CloseMode;
 import org.apache.hc.core5.reactor.IOReactorConfig;
-import org.apache.hc.core5.util.Timeout;
 
 /**
  * This example demonstrates a full-duplex, streaming HTTP/2 message exchange.
@@ -64,12 +66,15 @@ public class AsyncClientH2FullDuplexExchange {
 
     public static void main(final String[] args) throws Exception {
 
-        final IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
-                .setSoTimeout(Timeout.ofSeconds(5))
-                .build();
-
         final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal(
-                HttpVersionPolicy.FORCE_HTTP_2, H2Config.DEFAULT, null, ioReactorConfig);
+                H2Config.DEFAULT,
+                Http1Config.DEFAULT,
+                IOReactorConfig.DEFAULT,
+                PoolingAsyncClientConnectionManagerBuilder.create()
+                        .setDefaultTlsConfig(TlsConfig.custom()
+                                .setVersionPolicy(HttpVersionPolicy.FORCE_HTTP_2)
+                                .build())
+                        .build());
 
         client.start();
 
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientH2Multiplexing.java b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientH2Multiplexing.java
index 9a4077f..442dc66 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientH2Multiplexing.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientH2Multiplexing.java
@@ -35,17 +35,19 @@ import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
 import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
 import org.apache.hc.client5.http.async.methods.SimpleRequestProducer;
 import org.apache.hc.client5.http.async.methods.SimpleResponseConsumer;
+import org.apache.hc.client5.http.config.TlsConfig;
 import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
 import org.apache.hc.client5.http.impl.async.MinimalHttpAsyncClient;
+import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
 import org.apache.hc.core5.concurrent.FutureCallback;
 import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.config.Http1Config;
 import org.apache.hc.core5.http.message.StatusLine;
 import org.apache.hc.core5.http.nio.AsyncClientEndpoint;
 import org.apache.hc.core5.http2.HttpVersionPolicy;
 import org.apache.hc.core5.http2.config.H2Config;
 import org.apache.hc.core5.io.CloseMode;
 import org.apache.hc.core5.reactor.IOReactorConfig;
-import org.apache.hc.core5.util.Timeout;
 
 /**
  * This example demonstrates concurrent (multiplexed) execution of multiple
@@ -55,12 +57,15 @@ public class AsyncClientH2Multiplexing {
 
     public static void main(final String[] args) throws Exception {
 
-        final IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
-                .setSoTimeout(Timeout.ofSeconds(5))
-                .build();
-
         final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal(
-                HttpVersionPolicy.FORCE_HTTP_2, H2Config.DEFAULT, null, ioReactorConfig);
+                H2Config.DEFAULT,
+                Http1Config.DEFAULT,
+                IOReactorConfig.DEFAULT,
+                PoolingAsyncClientConnectionManagerBuilder.create()
+                        .setDefaultTlsConfig(TlsConfig.custom()
+                                .setVersionPolicy(HttpVersionPolicy.FORCE_HTTP_2)
+                                .build())
+                        .build());
 
         client.start();
 
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientH2ServerPush.java b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientH2ServerPush.java
index 2881d9b..dc36ade 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientH2ServerPush.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientH2ServerPush.java
@@ -33,8 +33,10 @@ import java.util.concurrent.Future;
 
 import org.apache.hc.client5.http.async.methods.AbstractBinPushConsumer;
 import org.apache.hc.client5.http.async.methods.AbstractCharResponseConsumer;
+import org.apache.hc.client5.http.config.TlsConfig;
 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
 import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
+import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
 import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.HttpException;
 import org.apache.hc.core5.http.HttpRequest;
@@ -46,8 +48,6 @@ import org.apache.hc.core5.http.support.BasicRequestBuilder;
 import org.apache.hc.core5.http2.HttpVersionPolicy;
 import org.apache.hc.core5.http2.config.H2Config;
 import org.apache.hc.core5.io.CloseMode;
-import org.apache.hc.core5.reactor.IOReactorConfig;
-import org.apache.hc.core5.util.Timeout;
 
 /**
  * This example demonstrates handling of HTTP/2 message exchanges pushed by the server.
@@ -56,18 +56,15 @@ public class AsyncClientH2ServerPush {
 
     public static void main(final String[] args) throws Exception {
 
-        final IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
-                .setSoTimeout(Timeout.ofSeconds(5))
-                .build();
-
-        final H2Config h2Config = H2Config.custom()
-                .setPushEnabled(true)
-                .build();
-
         final CloseableHttpAsyncClient client = HttpAsyncClients.custom()
-                .setIOReactorConfig(ioReactorConfig)
-                .setVersionPolicy(HttpVersionPolicy.FORCE_HTTP_2)
-                .setH2Config(h2Config)
+                .setH2Config(H2Config.custom()
+                        .setPushEnabled(true)
+                        .build())
+                .setConnectionManager(PoolingAsyncClientConnectionManagerBuilder.create()
+                        .setDefaultTlsConfig(TlsConfig.custom()
+                                .setVersionPolicy(HttpVersionPolicy.FORCE_HTTP_2)
+                                .build())
+                        .build())
                 .build();
 
         client.start();
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientHttp1Pipelining.java b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientHttp1Pipelining.java
index 548c4ed..4e93955 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientHttp1Pipelining.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientHttp1Pipelining.java
@@ -35,17 +35,19 @@ import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
 import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
 import org.apache.hc.client5.http.async.methods.SimpleRequestProducer;
 import org.apache.hc.client5.http.async.methods.SimpleResponseConsumer;
+import org.apache.hc.client5.http.config.TlsConfig;
 import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
 import org.apache.hc.client5.http.impl.async.MinimalHttpAsyncClient;
+import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
 import org.apache.hc.core5.concurrent.FutureCallback;
 import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.config.Http1Config;
 import org.apache.hc.core5.http.message.StatusLine;
 import org.apache.hc.core5.http.nio.AsyncClientEndpoint;
 import org.apache.hc.core5.http2.HttpVersionPolicy;
+import org.apache.hc.core5.http2.config.H2Config;
 import org.apache.hc.core5.io.CloseMode;
 import org.apache.hc.core5.reactor.IOReactorConfig;
-import org.apache.hc.core5.util.Timeout;
 
 /**
  * This example demonstrates pipelined execution of multiple HTTP/1.1 message exchanges.
@@ -54,12 +56,15 @@ public class AsyncClientHttp1Pipelining {
 
     public static void main(final String[] args) throws Exception {
 
-        final IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
-                .setSoTimeout(Timeout.ofSeconds(5))
-                .build();
-
         final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal(
-                HttpVersionPolicy.FORCE_HTTP_1, null, Http1Config.DEFAULT, ioReactorConfig);
+                H2Config.DEFAULT,
+                Http1Config.DEFAULT,
+                IOReactorConfig.DEFAULT,
+                PoolingAsyncClientConnectionManagerBuilder.create()
+                        .setDefaultTlsConfig(TlsConfig.custom()
+                                .setVersionPolicy(HttpVersionPolicy.FORCE_HTTP_1)
+                                .build())
+                        .build());
 
         client.start();
 
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientTlsAlpn.java b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientTlsAlpn.java
index 22c1e37..97db267 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientTlsAlpn.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientTlsAlpn.java
@@ -45,7 +45,6 @@ import org.apache.hc.core5.concurrent.FutureCallback;
 import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.message.StatusLine;
 import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
-import org.apache.hc.core5.http2.HttpVersionPolicy;
 import org.apache.hc.core5.io.CloseMode;
 
 /**
@@ -74,7 +73,6 @@ public class AsyncClientTlsAlpn {
                 .setTlsStrategy(tlsStrategy)
                 .build();
         try (final CloseableHttpAsyncClient client = HttpAsyncClients.custom()
-                .setVersionPolicy(HttpVersionPolicy.NEGOTIATE)
                 .setConnectionManager(cm)
                 .build()) {
 
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ReactiveClientFullDuplexExchange.java b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ReactiveClientFullDuplexExchange.java
index 9bb6630..e4fcf56 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ReactiveClientFullDuplexExchange.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ReactiveClientFullDuplexExchange.java
@@ -40,13 +40,11 @@ import org.apache.hc.core5.http.HttpResponse;
 import org.apache.hc.core5.http.Message;
 import org.apache.hc.core5.http.config.Http1Config;
 import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
-import org.apache.hc.core5.http2.HttpVersionPolicy;
 import org.apache.hc.core5.http2.config.H2Config;
 import org.apache.hc.core5.io.CloseMode;
 import org.apache.hc.core5.reactive.ReactiveEntityProducer;
 import org.apache.hc.core5.reactive.ReactiveResponseConsumer;
 import org.apache.hc.core5.reactor.IOReactorConfig;
-import org.apache.hc.core5.util.Timeout;
 import org.reactivestreams.Publisher;
 
 import io.reactivex.Flowable;
@@ -59,15 +57,10 @@ public class ReactiveClientFullDuplexExchange {
 
     public static void main(final String[] args) throws Exception {
 
-        final IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
-                .setSoTimeout(Timeout.ofSeconds(5))
-                .build();
-
         final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal(
-                HttpVersionPolicy.NEGOTIATE,
                 H2Config.DEFAULT,
                 Http1Config.DEFAULT,
-                ioReactorConfig);
+                IOReactorConfig.DEFAULT);
 
         client.start();
 
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/io/TestBasicHttpClientConnectionManager.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/io/TestBasicHttpClientConnectionManager.java
index 76f199d..1733f4e 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/io/TestBasicHttpClientConnectionManager.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/io/TestBasicHttpClientConnectionManager.java
@@ -30,10 +30,13 @@ package org.apache.hc.client5.http.impl.io;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.Socket;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.hc.client5.http.DnsResolver;
 import org.apache.hc.client5.http.HttpRoute;
 import org.apache.hc.client5.http.SchemePortResolver;
+import org.apache.hc.client5.http.config.ConnectionConfig;
+import org.apache.hc.client5.http.config.TlsConfig;
 import org.apache.hc.client5.http.io.ConnectionEndpoint;
 import org.apache.hc.client5.http.io.LeaseRequest;
 import org.apache.hc.client5.http.io.ManagedHttpClientConnection;
@@ -361,26 +364,55 @@ public class TestBasicHttpClientConnectionManager {
 
         mgr.setSocketConfig(sconfig);
 
+        final ConnectionConfig connectionConfig = ConnectionConfig.custom()
+                .setConnectTimeout(234, TimeUnit.MILLISECONDS)
+                .build();
+        mgr.setConnectionConfig(connectionConfig);
+        final TlsConfig tlsConfig = TlsConfig.custom()
+                .setHandshakeTimeout(345, TimeUnit.MILLISECONDS)
+                .build();
+        mgr.setTlsConfig(tlsConfig);
+
         Mockito.when(dnsResolver.resolve("somehost")).thenReturn(new InetAddress[] {remote});
         Mockito.when(schemePortResolver.resolve(target)).thenReturn(8443);
         Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(plainSocketFactory);
         Mockito.when(plainSocketFactory.createSocket(Mockito.any())).thenReturn(socket);
         Mockito.when(plainSocketFactory.connectSocket(
-                Mockito.any(),
                 Mockito.eq(socket),
                 Mockito.any(),
                 Mockito.any(),
                 Mockito.any(),
+                Mockito.any(),
+                Mockito.any(),
                 Mockito.any())).thenReturn(socket);
 
-        mgr.connect(endpoint1, TimeValue.ofMilliseconds(123), context);
+        mgr.connect(endpoint1, null, context);
 
         Mockito.verify(dnsResolver, Mockito.times(1)).resolve("somehost");
         Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
         Mockito.verify(plainSocketFactory, Mockito.times(1)).createSocket(context);
-        Mockito.verify(plainSocketFactory, Mockito.times(1)).connectSocket(TimeValue.ofMilliseconds(123), socket, target,
+        Mockito.verify(plainSocketFactory, Mockito.times(1)).connectSocket(
+                socket,
+                target,
+                new InetSocketAddress(remote, 8443),
+                new InetSocketAddress(local, 0),
+                Timeout.ofMilliseconds(234),
+                tlsConfig,
+                context);
+
+        mgr.connect(endpoint1, TimeValue.ofMilliseconds(123), context);
+
+        Mockito.verify(dnsResolver, Mockito.times(2)).resolve("somehost");
+        Mockito.verify(schemePortResolver, Mockito.times(2)).resolve(target);
+        Mockito.verify(plainSocketFactory, Mockito.times(2)).createSocket(context);
+        Mockito.verify(plainSocketFactory, Mockito.times(1)).connectSocket(
+                socket,
+                target,
                 new InetSocketAddress(remote, 8443),
-                new InetSocketAddress(local, 0), context);
+                new InetSocketAddress(local, 0),
+                Timeout.ofMilliseconds(123),
+                tlsConfig,
+                context);
     }
 
     @Test
@@ -402,6 +434,15 @@ public class TestBasicHttpClientConnectionManager {
 
         mgr.setSocketConfig(sconfig);
 
+        final ConnectionConfig connectionConfig = ConnectionConfig.custom()
+                .setConnectTimeout(234, TimeUnit.MILLISECONDS)
+                .build();
+        mgr.setConnectionConfig(connectionConfig);
+        final TlsConfig tlsConfig = TlsConfig.custom()
+                .setHandshakeTimeout(345, TimeUnit.MILLISECONDS)
+                .build();
+        mgr.setTlsConfig(tlsConfig);
+
         Mockito.when(dnsResolver.resolve("someproxy")).thenReturn(new InetAddress[] {remote});
         Mockito.when(schemePortResolver.resolve(proxy)).thenReturn(8080);
         Mockito.when(schemePortResolver.resolve(target)).thenReturn(8443);
@@ -409,21 +450,27 @@ public class TestBasicHttpClientConnectionManager {
         Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(sslSocketFactory);
         Mockito.when(plainSocketFactory.createSocket(Mockito.any())).thenReturn(socket);
         Mockito.when(plainSocketFactory.connectSocket(
-                Mockito.any(),
                 Mockito.eq(socket),
                 Mockito.any(),
                 Mockito.any(),
                 Mockito.any(),
+                Mockito.any(),
+                Mockito.any(),
                 Mockito.any())).thenReturn(socket);
 
-        mgr.connect(endpoint1, TimeValue.ofMilliseconds(123), context);
+        mgr.connect(endpoint1, null, context);
 
         Mockito.verify(dnsResolver, Mockito.times(1)).resolve("someproxy");
         Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(proxy);
         Mockito.verify(plainSocketFactory, Mockito.times(1)).createSocket(context);
-        Mockito.verify(plainSocketFactory, Mockito.times(1)).connectSocket(TimeValue.ofMilliseconds(123), socket, proxy,
+        Mockito.verify(plainSocketFactory, Mockito.times(1)).connectSocket(
+                socket,
+                proxy,
                 new InetSocketAddress(remote, 8080),
-                new InetSocketAddress(local, 0), context);
+                new InetSocketAddress(local, 0),
+                Timeout.ofMilliseconds(234),
+                tlsConfig,
+                context);
 
         Mockito.when(conn.getSocket()).thenReturn(socket);
 
@@ -431,7 +478,7 @@ public class TestBasicHttpClientConnectionManager {
 
         Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
         Mockito.verify(sslSocketFactory, Mockito.times(1)).createLayeredSocket(
-                socket, "somehost", 8443, context);
+                socket, "somehost", 8443, tlsConfig, context);
     }
 
 }
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/io/TestHttpClientConnectionOperator.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/io/TestHttpClientConnectionOperator.java
index 34bb77a..f83c787 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/io/TestHttpClientConnectionOperator.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/io/TestHttpClientConnectionOperator.java
@@ -39,6 +39,7 @@ import org.apache.hc.client5.http.DnsResolver;
 import org.apache.hc.client5.http.HttpHostConnectException;
 import org.apache.hc.client5.http.SchemePortResolver;
 import org.apache.hc.client5.http.UnsupportedSchemeException;
+import org.apache.hc.client5.http.config.TlsConfig;
 import org.apache.hc.client5.http.io.ManagedHttpClientConnection;
 import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
 import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
@@ -48,6 +49,7 @@ import org.apache.hc.core5.http.io.SocketConfig;
 import org.apache.hc.core5.http.protocol.BasicHttpContext;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.util.TimeValue;
+import org.apache.hc.core5.util.Timeout;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -96,6 +98,7 @@ public class TestHttpClientConnectionOperator {
                 Mockito.any(),
                 Mockito.any(),
                 Mockito.any(),
+                Mockito.any(),
                 Mockito.any())).thenReturn(socket);
 
         final SocketConfig socketConfig = SocketConfig.custom()
@@ -105,8 +108,11 @@ public class TestHttpClientConnectionOperator {
             .setTcpNoDelay(true)
             .setSoLinger(50, TimeUnit.MILLISECONDS)
             .build();
+        final TlsConfig tlsConfig = TlsConfig.custom()
+                .build();
         final InetSocketAddress localAddress = new InetSocketAddress(local, 0);
-        connectionOperator.connect(conn, host, localAddress, TimeValue.ofMilliseconds(1000), socketConfig, context);
+        connectionOperator.connect(conn, host, localAddress,
+                Timeout.ofMilliseconds(123), socketConfig, tlsConfig, context);
 
         Mockito.verify(socket).setKeepAlive(true);
         Mockito.verify(socket).setReuseAddress(true);
@@ -115,11 +121,12 @@ public class TestHttpClientConnectionOperator {
         Mockito.verify(socket).setTcpNoDelay(true);
 
         Mockito.verify(plainSocketFactory).connectSocket(
-                TimeValue.ofMilliseconds(1000),
                 socket,
                 host,
                 new InetSocketAddress(ip1, 80),
                 localAddress,
+                Timeout.ofMilliseconds(123),
+                tlsConfig,
                 context);
         Mockito.verify(conn, Mockito.times(2)).bind(socket);
     }
@@ -141,6 +148,7 @@ public class TestHttpClientConnectionOperator {
                 Mockito.any(),
                 Mockito.any(),
                 Mockito.any(),
+                Mockito.any(),
                 Mockito.any())).thenThrow(new SocketTimeoutException());
 
         Assert.assertThrows(ConnectTimeoutException.class, () ->
@@ -165,6 +173,7 @@ public class TestHttpClientConnectionOperator {
                 Mockito.any(),
                 Mockito.any(),
                 Mockito.any(),
+                Mockito.any(),
                 Mockito.any())).thenThrow(new ConnectException());
 
         Assert.assertThrows(HttpHostConnectException.class, () ->
@@ -187,27 +196,33 @@ public class TestHttpClientConnectionOperator {
         Mockito.when(plainSocketFactory.connectSocket(
                 Mockito.any(),
                 Mockito.any(),
-                Mockito.any(),
                 Mockito.eq(new InetSocketAddress(ip1, 80)),
                 Mockito.any(),
+                Mockito.any(),
+                Mockito.any(),
                 Mockito.any())).thenThrow(new ConnectException());
         Mockito.when(plainSocketFactory.connectSocket(
                 Mockito.any(),
                 Mockito.any(),
-                Mockito.any(),
                 Mockito.eq(new InetSocketAddress(ip2, 80)),
                 Mockito.any(),
+                Mockito.any(),
+                Mockito.any(),
                 Mockito.any())).thenReturn(socket);
 
         final InetSocketAddress localAddress = new InetSocketAddress(local, 0);
-        connectionOperator.connect(conn, host, localAddress, TimeValue.ofMilliseconds(1000), SocketConfig.DEFAULT, context);
+        final TlsConfig tlsConfig = TlsConfig.custom()
+                .build();
+        connectionOperator.connect(conn, host, localAddress,
+                Timeout.ofMilliseconds(123), SocketConfig.DEFAULT, tlsConfig, context);
 
         Mockito.verify(plainSocketFactory).connectSocket(
-                TimeValue.ofMilliseconds(1000),
                 socket,
                 host,
                 new InetSocketAddress(ip2, 80),
                 localAddress,
+                Timeout.ofMilliseconds(123),
+                tlsConfig,
                 context);
         Mockito.verify(conn, Mockito.times(3)).bind(socket);
     }
@@ -228,17 +243,22 @@ public class TestHttpClientConnectionOperator {
                 Mockito.any(),
                 Mockito.any(),
                 Mockito.any(),
+                Mockito.any(),
                 Mockito.any())).thenReturn(socket);
 
         final InetSocketAddress localAddress = new InetSocketAddress(local, 0);
-        connectionOperator.connect(conn, host, localAddress, TimeValue.ofMilliseconds(1000), SocketConfig.DEFAULT, context);
+        final TlsConfig tlsConfig = TlsConfig.custom()
+                .build();
+        connectionOperator.connect(conn, host, localAddress,
+                Timeout.ofMilliseconds(123), SocketConfig.DEFAULT, tlsConfig, context);
 
         Mockito.verify(plainSocketFactory).connectSocket(
-                TimeValue.ofMilliseconds(1000),
                 socket,
                 host,
                 new InetSocketAddress(ip, 80),
                 localAddress,
+                Timeout.ofMilliseconds(123),
+                tlsConfig,
                 context);
         Mockito.verify(dnsResolver, Mockito.never()).resolve(Mockito.anyString());
         Mockito.verify(conn, Mockito.times(2)).bind(socket);
@@ -258,9 +278,10 @@ public class TestHttpClientConnectionOperator {
                 Mockito.any(),
                 Mockito.eq("somehost"),
                 Mockito.eq(443),
+                Mockito.eq(Timeout.ofMilliseconds(345)),
                 Mockito.any())).thenReturn(socket);
 
-        connectionOperator.upgrade(conn, host, context);
+        connectionOperator.upgrade(conn, host, Timeout.ofMilliseconds(345), context);
 
         Mockito.verify(conn).bind(socket);
     }
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/io/TestPoolingHttpClientConnectionManager.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/io/TestPoolingHttpClientConnectionManager.java
index 29dbdd9..f837d28 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/io/TestPoolingHttpClientConnectionManager.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/io/TestPoolingHttpClientConnectionManager.java
@@ -37,6 +37,8 @@ import java.util.concurrent.TimeoutException;
 import org.apache.hc.client5.http.DnsResolver;
 import org.apache.hc.client5.http.HttpRoute;
 import org.apache.hc.client5.http.SchemePortResolver;
+import org.apache.hc.client5.http.config.ConnectionConfig;
+import org.apache.hc.client5.http.config.TlsConfig;
 import org.apache.hc.client5.http.io.ConnectionEndpoint;
 import org.apache.hc.client5.http.io.LeaseRequest;
 import org.apache.hc.client5.http.io.ManagedHttpClientConnection;
@@ -247,26 +249,55 @@ public class TestPoolingHttpClientConnectionManager {
 
         mgr.setDefaultSocketConfig(sconfig);
 
+        final ConnectionConfig connectionConfig = ConnectionConfig.custom()
+                .setConnectTimeout(234, TimeUnit.MILLISECONDS)
+                .build();
+        mgr.setDefaultConnectionConfig(connectionConfig);
+        final TlsConfig tlsConfig = TlsConfig.custom()
+                .setHandshakeTimeout(345, TimeUnit.MILLISECONDS)
+                .build();
+        mgr.setDefaultTlsConfig(tlsConfig);
+
         Mockito.when(dnsResolver.resolve("somehost")).thenReturn(new InetAddress[]{remote});
         Mockito.when(schemePortResolver.resolve(target)).thenReturn(8443);
         Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(plainSocketFactory);
         Mockito.when(plainSocketFactory.createSocket(Mockito.any())).thenReturn(socket);
         Mockito.when(plainSocketFactory.connectSocket(
-                Mockito.any(),
                 Mockito.eq(socket),
                 Mockito.any(),
                 Mockito.any(),
                 Mockito.any(),
+                Mockito.any(),
+                Mockito.any(),
                 Mockito.any())).thenReturn(socket);
 
-        mgr.connect(endpoint1, TimeValue.ofMilliseconds(123), context);
+        mgr.connect(endpoint1, null, context);
 
         Mockito.verify(dnsResolver, Mockito.times(1)).resolve("somehost");
         Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
         Mockito.verify(plainSocketFactory, Mockito.times(1)).createSocket(context);
-        Mockito.verify(plainSocketFactory, Mockito.times(1)).connectSocket(TimeValue.ofMilliseconds(123), socket, target,
+        Mockito.verify(plainSocketFactory, Mockito.times(1)).connectSocket(
+                socket,
+                target,
+                new InetSocketAddress(remote, 8443),
+                new InetSocketAddress(local, 0),
+                Timeout.ofMilliseconds(234),
+                tlsConfig,
+                context);
+
+        mgr.connect(endpoint1, TimeValue.ofMilliseconds(123), context);
+
+        Mockito.verify(dnsResolver, Mockito.times(2)).resolve("somehost");
+        Mockito.verify(schemePortResolver, Mockito.times(2)).resolve(target);
+        Mockito.verify(plainSocketFactory, Mockito.times(2)).createSocket(context);
+        Mockito.verify(plainSocketFactory, Mockito.times(1)).connectSocket(
+                socket,
+                target,
                 new InetSocketAddress(remote, 8443),
-                new InetSocketAddress(local, 0), context);
+                new InetSocketAddress(local, 0),
+                Timeout.ofMilliseconds(123),
+                tlsConfig,
+                context);
     }
 
     @Test
@@ -301,6 +332,15 @@ public class TestPoolingHttpClientConnectionManager {
 
         mgr.setDefaultSocketConfig(sconfig);
 
+        final ConnectionConfig connectionConfig = ConnectionConfig.custom()
+                .setConnectTimeout(234, TimeUnit.MILLISECONDS)
+                .build();
+        mgr.setDefaultConnectionConfig(connectionConfig);
+        final TlsConfig tlsConfig = TlsConfig.custom()
+                .setHandshakeTimeout(345, TimeUnit.MILLISECONDS)
+                .build();
+        mgr.setDefaultTlsConfig(tlsConfig);
+
         Mockito.when(dnsResolver.resolve("someproxy")).thenReturn(new InetAddress[] {remote});
         Mockito.when(schemePortResolver.resolve(proxy)).thenReturn(8080);
         Mockito.when(schemePortResolver.resolve(target)).thenReturn(8443);
@@ -308,21 +348,27 @@ public class TestPoolingHttpClientConnectionManager {
         Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(sslsf);
         Mockito.when(plainsf.createSocket(Mockito.any())).thenReturn(mockSock);
         Mockito.when(plainsf.connectSocket(
-                Mockito.any(),
                 Mockito.eq(mockSock),
                 Mockito.any(),
                 Mockito.any(),
                 Mockito.any(),
+                Mockito.any(),
+                Mockito.any(),
                 Mockito.any())).thenReturn(mockSock);
 
-        mgr.connect(endpoint1, TimeValue.ofMilliseconds(123), context);
+        mgr.connect(endpoint1, null, context);
 
         Mockito.verify(dnsResolver, Mockito.times(1)).resolve("someproxy");
         Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(proxy);
         Mockito.verify(plainsf, Mockito.times(1)).createSocket(context);
-        Mockito.verify(plainsf, Mockito.times(1)).connectSocket(TimeValue.ofMilliseconds(123), mockSock, proxy,
+        Mockito.verify(plainsf, Mockito.times(1)).connectSocket(
+                mockSock,
+                proxy,
                 new InetSocketAddress(remote, 8080),
-                new InetSocketAddress(local, 0), context);
+                new InetSocketAddress(local, 0),
+                Timeout.ofMilliseconds(234),
+                tlsConfig,
+                context);
 
         Mockito.when(conn.isOpen()).thenReturn(true);
         Mockito.when(conn.getSocket()).thenReturn(mockSock);
@@ -331,7 +377,7 @@ public class TestPoolingHttpClientConnectionManager {
 
         Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
         Mockito.verify(sslsf, Mockito.times(1)).createLayeredSocket(
-                mockSock, "somehost", 8443, context);
+                mockSock, "somehost", 8443, tlsConfig, context);
     }
 
 }

[httpcomponents-client] 04/08: Re-use core URIScheme instead of String.

Posted by ol...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git

commit bc7aae743ac7705f58af0ea9943ad464cb8e70d7
Author: Arturo Bernal <ar...@gmail.com>
AuthorDate: Sun Oct 17 12:56:38 2021 +0200

    Re-use core URIScheme instead of String.
---
 .../hc/client5/http/impl/auth/SystemDefaultCredentialsProvider.java   | 4 ++--
 .../hc/client5/http/impl/nio/PoolingAsyncClientConnectionManager.java | 3 ++-
 .../http/impl/nio/PoolingAsyncClientConnectionManagerBuilder.java     | 3 ++-
 .../org/apache/hc/client5/http/impl/routing/DefaultRoutePlanner.java  | 3 ++-
 4 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/SystemDefaultCredentialsProvider.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/SystemDefaultCredentialsProvider.java
index 7e7e201..99add9f 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/SystemDefaultCredentialsProvider.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/SystemDefaultCredentialsProvider.java
@@ -118,9 +118,9 @@ public class SystemDefaultCredentialsProvider implements CredentialsStore {
                 // https.proxyUser/https.proxyPassword. We cannot simply use the protocol from
                 // the origin since a proxy retrieved from https.proxyHost/https.proxyPort will
                 // still use http as protocol
-                systemcreds = getProxyCredentials("http", authScope);
+                systemcreds = getProxyCredentials(URIScheme.HTTP.getId(), authScope);
                 if (systemcreds == null) {
-                    systemcreds = getProxyCredentials("https", authScope);
+                    systemcreds = getProxyCredentials(URIScheme.HTTPS.getId(), authScope);
                 }
             }
             if (systemcreds != null) {
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManager.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManager.java
index d507154..3db4ca1 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManager.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManager.java
@@ -60,6 +60,7 @@ import org.apache.hc.core5.function.Resolver;
 import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.HttpVersion;
 import org.apache.hc.core5.http.ProtocolVersion;
+import org.apache.hc.core5.http.URIScheme;
 import org.apache.hc.core5.http.config.Lookup;
 import org.apache.hc.core5.http.config.RegistryBuilder;
 import org.apache.hc.core5.http.nio.AsyncClientExchangeHandler;
@@ -128,7 +129,7 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
 
     public PoolingAsyncClientConnectionManager() {
         this(RegistryBuilder.<TlsStrategy>create()
-                .register("https", DefaultClientTlsStrategy.getDefault())
+                .register(URIScheme.HTTPS.getId(), DefaultClientTlsStrategy.getDefault())
                 .build());
     }
 
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManagerBuilder.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManagerBuilder.java
index 122e000..941f412 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManagerBuilder.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManagerBuilder.java
@@ -36,6 +36,7 @@ import org.apache.hc.client5.http.ssl.ConscryptClientTlsStrategy;
 import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
 import org.apache.hc.core5.function.Resolver;
 import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.URIScheme;
 import org.apache.hc.core5.http.config.RegistryBuilder;
 import org.apache.hc.core5.http.io.SocketConfig;
 import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
@@ -247,7 +248,7 @@ public class PoolingAsyncClientConnectionManagerBuilder {
         }
         final PoolingAsyncClientConnectionManager poolingmgr = new PoolingAsyncClientConnectionManager(
                 RegistryBuilder.<TlsStrategy>create()
-                        .register("https", tlsStrategyCopy)
+                        .register(URIScheme.HTTPS.getId(), tlsStrategyCopy)
                         .build(),
                 poolConcurrencyPolicy,
                 poolReusePolicy,
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/DefaultRoutePlanner.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/DefaultRoutePlanner.java
index f8b4621..fac55af 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/DefaultRoutePlanner.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/DefaultRoutePlanner.java
@@ -41,6 +41,7 @@ import org.apache.hc.core5.annotation.ThreadingBehavior;
 import org.apache.hc.core5.http.HttpException;
 import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.ProtocolException;
+import org.apache.hc.core5.http.URIScheme;
 import org.apache.hc.core5.http.protocol.HttpContext;
 
 /**
@@ -75,7 +76,7 @@ public class DefaultRoutePlanner implements HttpRoutePlanner {
         if (target.getPort() < 0) {
             throw new ProtocolException("Unroutable protocol scheme: " + target);
         }
-        final boolean secure = target.getSchemeName().equalsIgnoreCase("https");
+        final boolean secure = target.getSchemeName().equalsIgnoreCase(URIScheme.HTTPS.getId());
         if (proxy == null) {
             return new HttpRoute(target, determineLocalAddress(target, context), secure);
         }

[httpcomponents-client] 06/08: Change loop that don't loop for "if" conditions.

Posted by ol...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git

commit 277c7228c3c626b93b298dc94aee4a7895851715
Author: Arturo Bernal <ar...@gmail.com>
AuthorDate: Sun Oct 17 15:46:36 2021 +0200

    Change loop that don't loop for "if" conditions.
---
 .../org/apache/hc/client5/http/impl/cache/ResponseCachingPolicy.java    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseCachingPolicy.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseCachingPolicy.java
index 9c787b6..9408669 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseCachingPolicy.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseCachingPolicy.java
@@ -302,7 +302,7 @@ class ResponseCachingPolicy {
 
     private boolean from1_0Origin(final HttpResponse response) {
         final Iterator<HeaderElement> it = MessageSupport.iterate(response, HeaderConstants.VIA);
-        while (it.hasNext()) {
+        if (it.hasNext()) {
             final HeaderElement elt = it.next();
             final String proto = elt.toString().split("\\s")[0];
             if (proto.contains("/")) {

[httpcomponents-client] 07/08: Upgraded HttpCore to version 5.2-alpha2

Posted by ol...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git

commit eb22ef30fc6962cbd3cdd0557809dae34f40a527
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Wed Oct 20 14:50:45 2021 +0200

    Upgraded HttpCore to version 5.2-alpha2
---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 469ae36..e6b96a2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -62,7 +62,7 @@
   <properties>
     <maven.compiler.source>1.8</maven.compiler.source>
     <maven.compiler.target>1.8</maven.compiler.target>
-    <httpcore.version>5.2-alpha1</httpcore.version>
+    <httpcore.version>5.2-alpha2</httpcore.version>
     <log4j.version>2.14.1</log4j.version>
     <commons-codec.version>1.15</commons-codec.version>
     <conscrypt.version>2.5.2</conscrypt.version>

[httpcomponents-client] 02/08: HTTPCLIENT-2182: access to SSLSession attributes via reflection disallowed as of Java 16. Core TLS functions now use new Java 1.8 API introduced by 8u251 update

Posted by ol...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git

commit 8b73f6b83ca85193662b26204cf57d8d025a8465
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Wed Oct 13 11:44:33 2021 +0200

    HTTPCLIENT-2182: access to SSLSession attributes via reflection disallowed as of Java 16. Core TLS functions now use new Java 1.8 API introduced by 8u251 update
---
 .../client5/http/ssl/ClientTlsStrategyBuilder.java |  23 ++--
 .../client5/http/ssl/DefaultClientTlsStrategy.java |  14 ++-
 .../http/examples/AsyncClientCustomSSL.java        |  12 --
 .../client5/http/examples/AsyncClientTlsAlpn.java  | 125 ---------------------
 4 files changed, 20 insertions(+), 154 deletions(-)

diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/ssl/ClientTlsStrategyBuilder.java b/httpclient5/src/main/java/org/apache/hc/client5/http/ssl/ClientTlsStrategyBuilder.java
index 52657e3..3f4e35a 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/ssl/ClientTlsStrategyBuilder.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/ssl/ClientTlsStrategyBuilder.java
@@ -30,7 +30,6 @@ package org.apache.hc.client5.http.ssl;
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLEngine;
-import javax.net.ssl.SSLSession;
 
 import org.apache.hc.core5.function.Factory;
 import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
@@ -38,7 +37,6 @@ import org.apache.hc.core5.http.ssl.TLS;
 import org.apache.hc.core5.reactor.ssl.SSLBufferMode;
 import org.apache.hc.core5.reactor.ssl.TlsDetails;
 import org.apache.hc.core5.ssl.SSLContexts;
-import org.apache.hc.core5.util.ReflectionUtils;
 
 /**
  * Builder for client {@link TlsStrategy} instances.
@@ -77,6 +75,10 @@ public class ClientTlsStrategyBuilder {
     private String[] ciphers;
     private SSLBufferMode sslBufferMode;
     private HostnameVerifier hostnameVerifier;
+    /**
+     * @deprecated To be removed.
+     */
+    @Deprecated
     private Factory<SSLEngine, TlsDetails> tlsDetailsFactory;
     private boolean systemProperties;
 
@@ -133,7 +135,10 @@ public class ClientTlsStrategyBuilder {
 
     /**
      * Assigns {@link TlsDetails} {@link Factory} instance.
+     *
+     * @deprecated Do not use.
      */
+    @Deprecated
     public ClientTlsStrategyBuilder setTlsDetailsFactory(final Factory<SSLEngine, TlsDetails> tlsDetailsFactory) {
         this.tlsDetailsFactory = tlsDetailsFactory;
         return this;
@@ -148,6 +153,7 @@ public class ClientTlsStrategyBuilder {
         return this;
     }
 
+    @SuppressWarnings("deprecation")
     public TlsStrategy build() {
         final SSLContext sslContextCopy;
         if (sslContext != null) {
@@ -167,24 +173,13 @@ public class ClientTlsStrategyBuilder {
         } else {
             ciphersCopy = systemProperties ? HttpsSupport.getSystemCipherSuits() : null;
         }
-        final Factory<SSLEngine, TlsDetails> tlsDetailsFactoryCopy;
-        if (tlsDetailsFactory != null) {
-            tlsDetailsFactoryCopy = tlsDetailsFactory;
-        } else {
-            tlsDetailsFactoryCopy = sslEngine -> {
-                final SSLSession sslSession = sslEngine.getSession();
-                final String applicationProtocol = ReflectionUtils.callGetter(sslEngine,
-                    "ApplicationProtocol", String.class);
-                return new TlsDetails(sslSession, applicationProtocol);
-            };
-        }
         return new DefaultClientTlsStrategy(
                 sslContextCopy,
                 tlsVersionsCopy,
                 ciphersCopy,
                 sslBufferMode != null ? sslBufferMode : SSLBufferMode.STATIC,
                 hostnameVerifier != null ? hostnameVerifier : HttpsSupport.getDefaultHostnameVerifier(),
-                tlsDetailsFactoryCopy);
+                tlsDetailsFactory);
     }
 
 }
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/ssl/DefaultClientTlsStrategy.java b/httpclient5/src/main/java/org/apache/hc/client5/http/ssl/DefaultClientTlsStrategy.java
index 872605d..dfa2664 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/ssl/DefaultClientTlsStrategy.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/ssl/DefaultClientTlsStrategy.java
@@ -63,8 +63,16 @@ public class DefaultClientTlsStrategy extends AbstractClientTlsStrategy {
                 HttpsSupport.getDefaultHostnameVerifier());
     }
 
-    private final Factory<SSLEngine, TlsDetails> tlsDetailsFactory;
+    /**
+     * @deprecated To be removed.
+     */
+    @Deprecated
+    private Factory<SSLEngine, TlsDetails> tlsDetailsFactory;
 
+    /**
+     * @deprecated Use {@link DefaultClientTlsStrategy#DefaultClientTlsStrategy(SSLContext, String[], String[], SSLBufferMode, HostnameVerifier)}
+     */
+    @Deprecated
     public DefaultClientTlsStrategy(
             final SSLContext sslContext,
             final String[] supportedProtocols,
@@ -82,13 +90,13 @@ public class DefaultClientTlsStrategy extends AbstractClientTlsStrategy {
             final String[] supportedCipherSuites,
             final SSLBufferMode sslBufferManagement,
             final HostnameVerifier hostnameVerifier) {
-        this(sslContext, supportedProtocols, supportedCipherSuites, sslBufferManagement, hostnameVerifier, null);
+        super(sslContext, supportedProtocols, supportedCipherSuites, sslBufferManagement, hostnameVerifier);
     }
 
     public DefaultClientTlsStrategy(
             final SSLContext sslcontext,
             final HostnameVerifier hostnameVerifier) {
-        this(sslcontext, null, null, SSLBufferMode.STATIC, hostnameVerifier, null);
+        this(sslcontext, null, null, SSLBufferMode.STATIC, hostnameVerifier);
     }
 
     public DefaultClientTlsStrategy(final SSLContext sslcontext) {
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientCustomSSL.java b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientCustomSSL.java
index 34176e4..12e28eb 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientCustomSSL.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientCustomSSL.java
@@ -66,18 +66,6 @@ public class AsyncClientCustomSSL {
                 .build();
         final TlsStrategy tlsStrategy = ClientTlsStrategyBuilder.create()
                 .setSslContext(sslcontext)
-                // IMPORTANT uncomment the following method when running Java 9 or older
-                // in order for ALPN support to work and avoid the illegal reflective
-                // access operation warning
-                /*
-                .setTlsDetailsFactory(new Factory<SSLEngine, TlsDetails>() {
-
-                    @Override
-                    public TlsDetails create(final SSLEngine sslEngine) {
-                        return new TlsDetails(sslEngine.getSession(), sslEngine.getApplicationProtocol());
-                    }
-                })
-                */
                 .build();
 
         final PoolingAsyncClientConnectionManager cm = PoolingAsyncClientConnectionManagerBuilder.create()
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientTlsAlpn.java b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientTlsAlpn.java
deleted file mode 100644
index 97db267..0000000
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientTlsAlpn.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-package org.apache.hc.client5.http.examples;
-
-import java.util.concurrent.Future;
-
-import javax.net.ssl.SSLSession;
-
-import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
-import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
-import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
-import org.apache.hc.client5.http.async.methods.SimpleRequestProducer;
-import org.apache.hc.client5.http.async.methods.SimpleResponseConsumer;
-import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
-import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
-import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager;
-import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
-import org.apache.hc.client5.http.protocol.HttpClientContext;
-import org.apache.hc.client5.http.ssl.ClientTlsStrategyBuilder;
-import org.apache.hc.core5.concurrent.FutureCallback;
-import org.apache.hc.core5.http.HttpHost;
-import org.apache.hc.core5.http.message.StatusLine;
-import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
-import org.apache.hc.core5.io.CloseMode;
-
-/**
- * This example demonstrates how to avoid the illegal reflective access operation warning
- * when running with Oracle JRE 9 or newer.
- */
-public class AsyncClientTlsAlpn {
-
-    public final static void main(final String[] args) throws Exception {
-        final TlsStrategy tlsStrategy = ClientTlsStrategyBuilder.create()
-                .useSystemProperties()
-                // IMPORTANT uncomment the following method when running Java 9 or older
-                // in order for ALPN support to work and avoid the illegal reflective
-                // access operation warning
-                /*
-                .setTlsDetailsFactory(new Factory<SSLEngine, TlsDetails>() {
-
-                    @Override
-                    public TlsDetails create(final SSLEngine sslEngine) {
-                        return new TlsDetails(sslEngine.getSession(), sslEngine.getApplicationProtocol());
-                    }
-                })
-                */
-                .build();
-        final PoolingAsyncClientConnectionManager cm = PoolingAsyncClientConnectionManagerBuilder.create()
-                .setTlsStrategy(tlsStrategy)
-                .build();
-        try (final CloseableHttpAsyncClient client = HttpAsyncClients.custom()
-                .setConnectionManager(cm)
-                .build()) {
-
-            client.start();
-
-            final HttpHost target = new HttpHost("https", "nghttp2.org");
-            final HttpClientContext clientContext = HttpClientContext.create();
-
-            final SimpleHttpRequest request = SimpleRequestBuilder.get()
-                    .setHttpHost(target)
-                    .setPath("/httpbin/")
-                    .build();
-
-            System.out.println("Executing request " + request);
-            final Future<SimpleHttpResponse> future = client.execute(
-                    SimpleRequestProducer.create(request),
-                    SimpleResponseConsumer.create(),
-                    clientContext,
-                    new FutureCallback<SimpleHttpResponse>() {
-
-                        @Override
-                        public void completed(final SimpleHttpResponse response) {
-                            System.out.println(request + "->" + new StatusLine(response));
-                            final SSLSession sslSession = clientContext.getSSLSession();
-                            if (sslSession != null) {
-                                System.out.println("SSL protocol " + sslSession.getProtocol());
-                                System.out.println("SSL cipher suite " + sslSession.getCipherSuite());
-                            }
-                            System.out.println(response.getBody());
-                        }
-
-                        @Override
-                        public void failed(final Exception ex) {
-                            System.out.println(request + "->" + ex);
-                        }
-
-                        @Override
-                        public void cancelled() {
-                            System.out.println(request + " cancelled");
-                        }
-
-                    });
-            future.get();
-
-            System.out.println("Shutting down");
-            client.close(CloseMode.GRACEFUL);
-        }
-    }
-
-}

[httpcomponents-client] 03/08: Don't initialize AtomicReference to its default value.

Posted by ol...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git

commit 238401731bbc53dc1aac23a58447b199ed4c5db5
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Wed Oct 13 16:04:10 2021 -0400

    Don't initialize AtomicReference to its default value.
---
 .../apache/hc/client5/http/impl/async/InternalHttpAsyncExecRuntime.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttpAsyncExecRuntime.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttpAsyncExecRuntime.java
index ad7c565..a7f5d65 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttpAsyncExecRuntime.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttpAsyncExecRuntime.java
@@ -79,7 +79,7 @@ class InternalHttpAsyncExecRuntime implements AsyncExecRuntime {
         this.connectionInitiator = connectionInitiator;
         this.pushHandlerFactory = pushHandlerFactory;
         this.tlsConfig = tlsConfig;
-        this.endpointRef = new AtomicReference<>(null);
+        this.endpointRef = new AtomicReference<>();
         this.validDuration = TimeValue.NEG_ONE_MILLISECOND;
     }
 

[httpcomponents-client] 05/08: * Fix javadoc typo. * Use java array declarations instead of "c" way.

Posted by ol...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git

commit 012429391ca318076a9dde8e9053653d9a3c9af6
Author: Arturo Bernal <ar...@gmail.com>
AuthorDate: Sun Oct 17 09:40:12 2021 +0200

    * Fix javadoc typo.
    * Use java array declarations instead of "c" way.
---
 .../java/org/apache/hc/client5/http/cookie/CookiePathComparator.java    | 2 +-
 .../hc/client5/http/impl/DefaultClientConnectionReuseStrategy.java      | 2 +-
 .../org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java   | 2 +-
 .../main/java/org/apache/hc/client5/http/impl/auth/NTLMEngineImpl.java  | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/cookie/CookiePathComparator.java b/httpclient5/src/main/java/org/apache/hc/client5/http/cookie/CookiePathComparator.java
index e3749c4..192ad18 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/cookie/CookiePathComparator.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/cookie/CookiePathComparator.java
@@ -41,7 +41,7 @@ import org.apache.hc.core5.annotation.ThreadingBehavior;
  *
  * <p>
  * This comparator assumes that Path attributes of two cookies
- * path-match a commmon request-URI. Otherwise, the result of the
+ * path-match a common request-URI. Otherwise, the result of the
  * comparison is undefined.
  * </p>
  *
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/DefaultClientConnectionReuseStrategy.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/DefaultClientConnectionReuseStrategy.java
index f17accf..b28b30e 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/DefaultClientConnectionReuseStrategy.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/DefaultClientConnectionReuseStrategy.java
@@ -37,7 +37,7 @@ import org.apache.hc.core5.http.protocol.HttpContext;
 
 /**
  * Extension of core {@link DefaultConnectionReuseStrategy} that treats
- * CONNECT method exchnages involved in proxy tunnelling as a special case.
+ * CONNECT method exchanges involved in proxy tunnelling as a special case.
  *
  * @since 5.2
  */
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java
index 394a228..35d4af1 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java
@@ -260,7 +260,7 @@ public class HttpAsyncClientBuilder {
     /**
      * Sets HTTP protocol version policy.
      *
-     * @deprecated Use {@link TlsConfig} and connection nanager methods
+     * @deprecated Use {@link TlsConfig} and connection manager methods
      */
     @Deprecated
     public final HttpAsyncClientBuilder setVersionPolicy(final HttpVersionPolicy versionPolicy) {
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/NTLMEngineImpl.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/NTLMEngineImpl.java
index d87ee94..3bf9f61 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/NTLMEngineImpl.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/NTLMEngineImpl.java
@@ -917,7 +917,7 @@ final class NTLMEngineImpl implements NTLMEngine {
             return sig;
         }
 
-        private boolean validateSignature( final byte[] signature, final byte message[] )
+        private boolean validateSignature( final byte[] signature, final byte[] message )
         {
             final byte[] computedSignature = computeSignature( message );
             //            log.info( "SSSSS validateSignature("+seqNumber+")\n"

[httpcomponents-client] 08/08: Make IOReactor IO session decorator configurable.

Posted by ol...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git

commit fff097615bea52776a9bac3df1751d1965ddea9a
Author: Arturo Bernal <ar...@gmail.com>
AuthorDate: Sat Oct 23 09:12:38 2021 +0200

    Make IOReactor IO session decorator configurable.
---
 .../client5/http/impl/async/HttpAsyncClientBuilder.java   | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java
index 35d4af1..16db56e 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java
@@ -83,6 +83,7 @@ import org.apache.hc.client5.http.routing.HttpRoutePlanner;
 import org.apache.hc.core5.annotation.Internal;
 import org.apache.hc.core5.concurrent.DefaultThreadFactory;
 import org.apache.hc.core5.function.Callback;
+import org.apache.hc.core5.function.Decorator;
 import org.apache.hc.core5.http.ConnectionReuseStrategy;
 import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpHost;
@@ -110,6 +111,7 @@ import org.apache.hc.core5.reactor.Command;
 import org.apache.hc.core5.reactor.DefaultConnectingIOReactor;
 import org.apache.hc.core5.reactor.IOEventHandlerFactory;
 import org.apache.hc.core5.reactor.IOReactorConfig;
+import org.apache.hc.core5.reactor.IOSession;
 import org.apache.hc.core5.util.Args;
 import org.apache.hc.core5.util.TimeValue;
 import org.apache.hc.core5.util.VersionInfo;
@@ -214,6 +216,7 @@ public class HttpAsyncClientBuilder {
     private UserTokenHandler userTokenHandler;
     private AuthenticationStrategy targetAuthStrategy;
     private AuthenticationStrategy proxyAuthStrategy;
+    private Decorator<IOSession> ioSessionDecorator;
 
     private LinkedList<RequestInterceptorEntry> requestInterceptors;
     private LinkedList<ResponseInterceptorEntry> responseInterceptors;
@@ -385,6 +388,16 @@ public class HttpAsyncClientBuilder {
     }
 
     /**
+     * Sets the {@link IOSession} {@link Decorator} that will be use with the client's IOReactor.
+     *
+     * @since 5.2
+     */
+    public final HttpAsyncClientBuilder setIoSessionDecorator(final Decorator<IOSession> ioSessionDecorator) {
+        this.ioSessionDecorator = ioSessionDecorator;
+        return this;
+    }
+
+    /**
      * Adds this protocol interceptor to the head of the protocol processing list.
      */
     public final HttpAsyncClientBuilder addResponseInterceptorFirst(final HttpResponseInterceptor interceptor) {
@@ -919,7 +932,7 @@ public class HttpAsyncClientBuilder {
                 ioEventHandlerFactory,
                 ioReactorConfig != null ? ioReactorConfig : IOReactorConfig.DEFAULT,
                 threadFactory != null ? threadFactory : new DefaultThreadFactory("httpclient-dispatch", true),
-                LoggingIOSessionDecorator.INSTANCE,
+                ioSessionDecorator != null ? ioSessionDecorator : LoggingIOSessionDecorator.INSTANCE,
                 ioReactorExceptionCallback != null ? ioReactorExceptionCallback : LoggingExceptionCallback.INSTANCE,
                 null,
                 ioSession -> ioSession.enqueue(new ShutdownCommand(CloseMode.GRACEFUL), Command.Priority.IMMEDIATE));