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/04/27 11:13:06 UTC

[httpcomponents-client] 04/04: Moved connection management related settings from RequestConfig to new class ConnectionConfig

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

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

commit 605f6c397cd60c1e3c33a19d9aa894137e2aafc1
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Thu Mar 25 22:09:29 2021 +0100

    Moved connection management related settings from RequestConfig to new class ConnectionConfig
---
 .../async/AbstractHttp1IntegrationTestBase.java    |   6 +-
 .../hc/client5/testing/async/TestH2Async.java      |   4 +
 .../client5/testing/async/TestH2AsyncRedirect.java |   4 +
 .../testing/async/TestH2ClientAuthentication.java  |   4 +
 .../hc/client5/testing/async/TestH2Reactive.java   |   4 +
 .../hc/client5/testing/async/TestHttp1Async.java   |   6 +-
 .../testing/async/TestHttp1AsyncRedirects.java     |   6 +-
 .../TestHttp1AsyncStatefulConnManagement.java      |   6 +-
 .../async/TestHttp1ClientAuthentication.java       |   6 +-
 .../client5/testing/async/TestHttp1Reactive.java   |   6 +-
 .../client5/testing/sync/LocalServerTestBase.java  |   6 +-
 .../hc/client5/http/config/ConnectionConfig.java   | 205 +++++++++++++++++++++
 .../hc/client5/http/config/RequestConfig.java      |  23 ++-
 .../http/impl/async/H2AsyncClientBuilder.java      |  30 ++-
 .../http/impl/async/InternalH2AsyncClient.java     |   5 +-
 .../impl/async/InternalH2AsyncExecRuntime.java     |   9 +-
 .../http/impl/async/InternalH2ConnPool.java        | 102 ++++++++++
 .../http/impl/async/MinimalH2AsyncClient.java      |  16 +-
 .../impl/io/BasicHttpClientConnectionManager.java  |  29 ++-
 .../io/PoolingHttpClientConnectionManager.java     | 119 +++++++++---
 .../PoolingHttpClientConnectionManagerBuilder.java |  61 ++++--
 .../nio/PoolingAsyncClientConnectionManager.java   |  83 ++++++---
 ...PoolingAsyncClientConnectionManagerBuilder.java |  40 +++-
 .../hc/client5/http/config/TestRequestConfig.java  |   6 -
 .../client5/http/examples/ClientConfiguration.java |  19 +-
 25 files changed, 691 insertions(+), 114 deletions(-)

diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttp1IntegrationTestBase.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttp1IntegrationTestBase.java
index 2a7a51d..964e1d3 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttp1IntegrationTestBase.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttp1IntegrationTestBase.java
@@ -30,6 +30,7 @@ package org.apache.hc.client5.testing.async;
 import java.net.InetSocketAddress;
 import java.util.concurrent.Future;
 
+import org.apache.hc.client5.http.config.ConnectionConfig;
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
 import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;
@@ -69,6 +70,10 @@ public abstract class AbstractHttp1IntegrationTestBase extends AbstractServerTes
         @Override
         protected void before() throws Throwable {
             connManager = PoolingAsyncClientConnectionManagerBuilder.create()
+                    .setDefaultConnectionConfig(ConnectionConfig.custom()
+                            .setConnectTimeout(TIMEOUT)
+                            .setSocketTimeout(TIMEOUT)
+                            .build())
                     .setTlsStrategy(new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext()))
                     .build();
         }
@@ -91,7 +96,6 @@ public abstract class AbstractHttp1IntegrationTestBase extends AbstractServerTes
             clientBuilder = HttpAsyncClientBuilder.create()
                     .setDefaultRequestConfig(RequestConfig.custom()
                             .setConnectionRequestTimeout(TIMEOUT)
-                            .setConnectTimeout(TIMEOUT)
                             .build())
                     .setConnectionManager(connManager);
         }
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2Async.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2Async.java
index 2076143..a6795d1 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2Async.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2Async.java
@@ -29,6 +29,7 @@ package org.apache.hc.client5.testing.async;
 import java.util.Arrays;
 import java.util.Collection;
 
+import org.apache.hc.client5.http.config.ConnectionConfig;
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
 import org.apache.hc.client5.http.impl.async.H2AsyncClientBuilder;
@@ -63,7 +64,10 @@ public class TestH2Async extends AbstractHttpAsyncFundamentalsTest<CloseableHttp
             clientBuilder = H2AsyncClientBuilder.create()
                     .setDefaultRequestConfig(RequestConfig.custom()
                             .setConnectionRequestTimeout(TIMEOUT)
+                            .build())
+                    .setDefaultConnectionConfig(ConnectionConfig.custom()
                             .setConnectTimeout(TIMEOUT)
+                            .setSocketTimeout(TIMEOUT)
                             .build())
                     .setTlsStrategy(new BasicClientTlsStrategy(SSLTestContexts.createClientSSLContext()));
         }
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2AsyncRedirect.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2AsyncRedirect.java
index ed23143..c4697dd 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2AsyncRedirect.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2AsyncRedirect.java
@@ -29,6 +29,7 @@ package org.apache.hc.client5.testing.async;
 import java.util.Arrays;
 import java.util.Collection;
 
+import org.apache.hc.client5.http.config.ConnectionConfig;
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
 import org.apache.hc.client5.http.impl.async.H2AsyncClientBuilder;
@@ -66,7 +67,10 @@ public class TestH2AsyncRedirect extends AbstractHttpAsyncRedirectsTest<Closeabl
             clientBuilder = H2AsyncClientBuilder.create()
                     .setDefaultRequestConfig(RequestConfig.custom()
                             .setConnectionRequestTimeout(TIMEOUT)
+                            .build())
+                    .setDefaultConnectionConfig(ConnectionConfig.custom()
                             .setConnectTimeout(TIMEOUT)
+                            .setSocketTimeout(TIMEOUT)
                             .build())
                     .setTlsStrategy(new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext()));
         }
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2ClientAuthentication.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2ClientAuthentication.java
index fa3a01b..52adf5a 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2ClientAuthentication.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2ClientAuthentication.java
@@ -31,6 +31,7 @@ import java.util.Collection;
 
 import org.apache.hc.client5.http.AuthenticationStrategy;
 import org.apache.hc.client5.http.auth.AuthSchemeFactory;
+import org.apache.hc.client5.http.config.ConnectionConfig;
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
 import org.apache.hc.client5.http.impl.async.H2AsyncClientBuilder;
@@ -67,7 +68,10 @@ public class TestH2ClientAuthentication extends AbstractHttpAsyncClientAuthentic
             clientBuilder = H2AsyncClientBuilder.create()
                     .setDefaultRequestConfig(RequestConfig.custom()
                             .setConnectionRequestTimeout(TIMEOUT)
+                            .build())
+                    .setDefaultConnectionConfig(ConnectionConfig.custom()
                             .setConnectTimeout(TIMEOUT)
+                            .setSocketTimeout(TIMEOUT)
                             .build())
                     .setTlsStrategy(new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext()));
         }
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2Reactive.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2Reactive.java
index 76bd0df..989e51c 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2Reactive.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2Reactive.java
@@ -29,6 +29,7 @@ package org.apache.hc.client5.testing.async;
 import java.util.Arrays;
 import java.util.Collection;
 
+import org.apache.hc.client5.http.config.ConnectionConfig;
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
 import org.apache.hc.client5.http.impl.async.H2AsyncClientBuilder;
@@ -63,7 +64,10 @@ public class TestH2Reactive extends AbstractHttpReactiveFundamentalsTest<Closeab
             clientBuilder = H2AsyncClientBuilder.create()
                     .setDefaultRequestConfig(RequestConfig.custom()
                             .setConnectionRequestTimeout(TIMEOUT)
+                            .build())
+                    .setDefaultConnectionConfig(ConnectionConfig.custom()
                             .setConnectTimeout(TIMEOUT)
+                            .setSocketTimeout(TIMEOUT)
                             .build())
                     .setTlsStrategy(new BasicClientTlsStrategy(SSLTestContexts.createClientSSLContext()));
         }
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1Async.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1Async.java
index b76256c..38b12b8 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1Async.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1Async.java
@@ -32,6 +32,7 @@ import java.util.concurrent.Future;
 
 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.ConnectionConfig;
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
 import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;
@@ -74,6 +75,10 @@ public class TestHttp1Async extends AbstractHttpAsyncFundamentalsTest<CloseableH
         protected void before() throws Throwable {
             connManager = PoolingAsyncClientConnectionManagerBuilder.create()
                     .setTlsStrategy(new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext()))
+                    .setDefaultConnectionConfig(ConnectionConfig.custom()
+                            .setConnectTimeout(TIMEOUT)
+                            .setSocketTimeout(TIMEOUT)
+                            .build())
                     .build();
         }
 
@@ -95,7 +100,6 @@ public class TestHttp1Async extends AbstractHttpAsyncFundamentalsTest<CloseableH
             clientBuilder = HttpAsyncClientBuilder.create()
                     .setDefaultRequestConfig(RequestConfig.custom()
                             .setConnectionRequestTimeout(TIMEOUT)
-                            .setConnectTimeout(TIMEOUT)
                             .build())
                     .setConnectionManager(connManager);
         }
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1AsyncRedirects.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1AsyncRedirects.java
index 67f3ca7..f0a2ba6 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1AsyncRedirects.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1AsyncRedirects.java
@@ -34,6 +34,7 @@ import java.util.concurrent.Future;
 
 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.ConnectionConfig;
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
 import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;
@@ -88,6 +89,10 @@ public class TestHttp1AsyncRedirects extends AbstractHttpAsyncRedirectsTest<Clos
         protected void before() throws Throwable {
             connManager = PoolingAsyncClientConnectionManagerBuilder.create()
                     .setTlsStrategy(new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext()))
+                    .setDefaultConnectionConfig(ConnectionConfig.custom()
+                            .setConnectTimeout(TIMEOUT)
+                            .setSocketTimeout(TIMEOUT)
+                            .build())
                     .build();
         }
 
@@ -109,7 +114,6 @@ public class TestHttp1AsyncRedirects extends AbstractHttpAsyncRedirectsTest<Clos
             clientBuilder = HttpAsyncClientBuilder.create()
                     .setDefaultRequestConfig(RequestConfig.custom()
                             .setConnectionRequestTimeout(TIMEOUT)
-                            .setConnectTimeout(TIMEOUT)
                             .build())
                     .setConnectionManager(connManager);
         }
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1AsyncStatefulConnManagement.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1AsyncStatefulConnManagement.java
index fdbc72b..5d1cbb3 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1AsyncStatefulConnManagement.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1AsyncStatefulConnManagement.java
@@ -32,6 +32,7 @@ import org.apache.hc.client5.http.UserTokenHandler;
 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.config.ConnectionConfig;
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
 import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;
@@ -68,6 +69,10 @@ public class TestHttp1AsyncStatefulConnManagement extends AbstractIntegrationTes
         protected void before() throws Throwable {
             connManager = PoolingAsyncClientConnectionManagerBuilder.create()
                     .setTlsStrategy(new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext()))
+                    .setDefaultConnectionConfig(ConnectionConfig.custom()
+                            .setConnectTimeout(TIMEOUT)
+                            .setSocketTimeout(TIMEOUT)
+                            .build())
                     .build();
         }
 
@@ -88,7 +93,6 @@ public class TestHttp1AsyncStatefulConnManagement extends AbstractIntegrationTes
         protected void before() throws Throwable {
             clientBuilder = HttpAsyncClientBuilder.create()
                     .setDefaultRequestConfig(RequestConfig.custom()
-                            .setConnectTimeout(TIMEOUT)
                             .setConnectionRequestTimeout(TIMEOUT)
                             .build())
                     .setConnectionManager(connManager);
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1ClientAuthentication.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1ClientAuthentication.java
index 4bfca6f..b4b049d 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1ClientAuthentication.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1ClientAuthentication.java
@@ -37,6 +37,7 @@ import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
 import org.apache.hc.client5.http.auth.AuthSchemeFactory;
 import org.apache.hc.client5.http.auth.AuthScope;
 import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
+import org.apache.hc.client5.http.config.ConnectionConfig;
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
 import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;
@@ -84,6 +85,10 @@ public class TestHttp1ClientAuthentication extends AbstractHttpAsyncClientAuthen
         protected void before() throws Throwable {
             connManager = PoolingAsyncClientConnectionManagerBuilder.create()
                     .setTlsStrategy(new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext()))
+                    .setDefaultConnectionConfig(ConnectionConfig.custom()
+                            .setConnectTimeout(TIMEOUT)
+                            .setSocketTimeout(TIMEOUT)
+                            .build())
                     .build();
         }
 
@@ -105,7 +110,6 @@ public class TestHttp1ClientAuthentication extends AbstractHttpAsyncClientAuthen
             clientBuilder = HttpAsyncClientBuilder.create()
                     .setDefaultRequestConfig(RequestConfig.custom()
                             .setConnectionRequestTimeout(TIMEOUT)
-                            .setConnectTimeout(TIMEOUT)
                             .build())
                     .setConnectionManager(connManager);
         }
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1Reactive.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1Reactive.java
index eee59b5..02fd4f4 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1Reactive.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1Reactive.java
@@ -32,6 +32,7 @@ import java.util.Collection;
 
 import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
 import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
+import org.apache.hc.client5.http.config.ConnectionConfig;
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
 import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;
@@ -80,6 +81,10 @@ public class TestHttp1Reactive extends AbstractHttpReactiveFundamentalsTest<Clos
         protected void before() throws Throwable {
             connManager = PoolingAsyncClientConnectionManagerBuilder.create()
                     .setTlsStrategy(new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext()))
+                    .setDefaultConnectionConfig(ConnectionConfig.custom()
+                            .setConnectTimeout(TIMEOUT)
+                            .setSocketTimeout(TIMEOUT)
+                            .build())
                     .build();
         }
 
@@ -101,7 +106,6 @@ public class TestHttp1Reactive extends AbstractHttpReactiveFundamentalsTest<Clos
             clientBuilder = HttpAsyncClientBuilder.create()
                     .setDefaultRequestConfig(RequestConfig.custom()
                             .setConnectionRequestTimeout(TIMEOUT)
-                            .setConnectTimeout(TIMEOUT)
                             .build())
                     .setConnectionManager(connManager);
         }
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/LocalServerTestBase.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/LocalServerTestBase.java
index 07a98b5..21486f7 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/LocalServerTestBase.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/LocalServerTestBase.java
@@ -29,6 +29,7 @@ package org.apache.hc.client5.testing.sync;
 
 import java.io.IOException;
 
+import org.apache.hc.client5.http.config.ConnectionConfig;
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
 import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
@@ -110,10 +111,13 @@ public abstract class LocalServerTestBase {
             connManager.setDefaultSocketConfig(SocketConfig.custom()
                     .setSoTimeout(TIMEOUT)
                     .build());
+            connManager.setDefaultConnectionConfig(ConnectionConfig.custom()
+                    .setConnectTimeout(TIMEOUT)
+                    .build());
+
             clientBuilder = HttpClientBuilder.create()
                     .setDefaultRequestConfig(RequestConfig.custom()
                             .setConnectionRequestTimeout(TIMEOUT)
-                            .setConnectTimeout(TIMEOUT)
                             .build())
                     .setConnectionManager(connManager);
         }
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
new file mode 100644
index 0000000..97ed585
--- /dev/null
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/config/ConnectionConfig.java
@@ -0,0 +1,205 @@
+/*
+ * ====================================================================
+ * 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.concurrent.TimeUnit;
+
+import org.apache.hc.core5.annotation.Contract;
+import org.apache.hc.core5.annotation.ThreadingBehavior;
+import org.apache.hc.core5.util.TimeValue;
+import org.apache.hc.core5.util.Timeout;
+
+/**
+ * Immutable class encapsulating connection initialization and management settings.
+ *
+ * @since 5.2
+ */
+@Contract(threading = ThreadingBehavior.IMMUTABLE)
+public class ConnectionConfig implements Cloneable {
+
+    private static final Timeout DEFAULT_CONNECT_TIMEOUT = Timeout.ofMinutes(3);
+
+    public static final ConnectionConfig DEFAULT = new Builder().build();
+
+    private final Timeout connectTimeout;
+    private final Timeout socketTimeout;
+    private final TimeValue validateAfterInactivity;
+
+    /**
+     * Intended for CDI compatibility
+     */
+    protected ConnectionConfig() {
+        this(DEFAULT_CONNECT_TIMEOUT, null, null);
+    }
+
+    ConnectionConfig(
+            final Timeout connectTimeout,
+            final Timeout socketTimeout,
+            final TimeValue validateAfterInactivity) {
+        super();
+        this.connectTimeout = connectTimeout;
+        this.socketTimeout = socketTimeout;
+        this.validateAfterInactivity = validateAfterInactivity;
+    }
+
+    /**
+     * @see Builder#setSocketTimeout(Timeout)
+     */
+    public Timeout getSocketTimeout() {
+        return socketTimeout;
+    }
+
+    /**
+     * @see Builder#setConnectTimeout(Timeout)
+     */
+    public Timeout getConnectTimeout() {
+        return connectTimeout;
+    }
+
+    /**
+     * @see Builder#setValidateAfterInactivity(TimeValue)
+     */
+    public TimeValue getValidateAfterInactivity() {
+        return validateAfterInactivity;
+    }
+
+    @Override
+    protected ConnectionConfig clone() throws CloneNotSupportedException {
+        return (ConnectionConfig) super.clone();
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append("[");
+        builder.append(", connectTimeout=").append(connectTimeout);
+        builder.append(", socketTimeout=").append(socketTimeout);
+        builder.append(", validateAfterInactivity=").append(validateAfterInactivity);
+        builder.append("]");
+        return builder.toString();
+    }
+
+    public static ConnectionConfig.Builder custom() {
+        return new Builder();
+    }
+
+    public static ConnectionConfig.Builder copy(final ConnectionConfig config) {
+        return new Builder()
+                .setConnectTimeout(config.getConnectTimeout())
+                .setSocketTimeout(config.getSocketTimeout())
+                .setValidateAfterInactivity(config.getValidateAfterInactivity());
+    }
+
+    public static class Builder {
+
+        private Timeout socketTimeout;
+        private Timeout connectTimeout;
+        private TimeValue validateAfterInactivity;
+
+        Builder() {
+            super();
+            this.connectTimeout = DEFAULT_CONNECT_TIMEOUT;
+        }
+
+
+        /**
+         * @see #setSocketTimeout(Timeout)
+         */
+        public Builder setSocketTimeout(final int soTimeout, final TimeUnit timeUnit) {
+            this.socketTimeout = Timeout.of(soTimeout, timeUnit);
+            return this;
+        }
+
+        /**
+         * Determines the default socket timeout value for I/O operations.
+         * <p>
+         * Default: {@code null}
+         * </p>
+         *
+         * @return the default socket timeout value for I/O operations.
+         */
+        public Builder setSocketTimeout(final Timeout soTimeout) {
+            this.socketTimeout = soTimeout;
+            return this;
+        }
+
+        /**
+         * 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>
+         * <p>
+         * Default: 3 minutes
+         * </p>
+         */
+        public Builder setConnectTimeout(final Timeout connectTimeout) {
+            this.connectTimeout = connectTimeout;
+            return this;
+        }
+
+        /**
+         * @see #setConnectTimeout(Timeout)
+         */
+        public Builder setConnectTimeout(final long connectTimeout, final TimeUnit timeUnit) {
+            this.connectTimeout = Timeout.of(connectTimeout, timeUnit);
+            return this;
+        }
+
+        /**
+         * Defines period of inactivity after which persistent connections must
+         * be re-validated prior to being leased to the consumer. Negative values passed
+         * to this method disable connection validation.
+         * <p>
+         * Default: {@code null}
+         * </p>
+         */
+        public Builder setValidateAfterInactivity(final TimeValue validateAfterInactivity) {
+            this.validateAfterInactivity = validateAfterInactivity;
+            return this;
+        }
+
+        /**
+         * @see #setValidateAfterInactivity(TimeValue)
+         */
+        public Builder setValidateAfterInactivity(final long validateAfterInactivity, final TimeUnit timeUnit) {
+            this.validateAfterInactivity = TimeValue.of(validateAfterInactivity, timeUnit);
+            return this;
+        }
+
+        public ConnectionConfig build() {
+            return new ConnectionConfig(
+                    connectTimeout != null ? connectTimeout : DEFAULT_CONNECT_TIMEOUT,
+                    socketTimeout,
+                    validateAfterInactivity);
+        }
+
+    }
+
+}
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/config/RequestConfig.java b/httpclient5/src/main/java/org/apache/hc/client5/http/config/RequestConfig.java
index 9bcf749..b3a7860 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/config/RequestConfig.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/config/RequestConfig.java
@@ -43,7 +43,6 @@ import org.apache.hc.core5.util.Timeout;
 public class RequestConfig implements Cloneable {
 
     private static final Timeout DEFAULT_CONNECTION_REQUEST_TIMEOUT = Timeout.ofMinutes(3);
-    private static final Timeout DEFAULT_CONNECT_TIMEOUT = Timeout.ofMinutes(3);
     private static final TimeValue DEFAULT_CONN_KEEP_ALIVE = TimeValue.ofMinutes(3);
 
     public static final RequestConfig DEFAULT = new Builder().build();
@@ -69,7 +68,7 @@ public class RequestConfig implements Cloneable {
     */
     protected RequestConfig() {
         this(false, null, null, false, false, 0, false, null, null,
-                DEFAULT_CONNECTION_REQUEST_TIMEOUT, DEFAULT_CONNECT_TIMEOUT, null, DEFAULT_CONN_KEEP_ALIVE, false, false);
+                DEFAULT_CONNECTION_REQUEST_TIMEOUT, null, null, DEFAULT_CONN_KEEP_ALIVE, false, false);
     }
 
     RequestConfig(
@@ -115,7 +114,11 @@ public class RequestConfig implements Cloneable {
 
     /**
      * @see Builder#setProxy(HttpHost)
+     *
+     * @deprecated Use {@link org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner}
+     * or a custom {@link org.apache.hc.client5.http.routing.HttpRoutePlanner}.
      */
+    @Deprecated
     public HttpHost getProxy() {
         return proxy;
     }
@@ -178,7 +181,10 @@ public class RequestConfig implements Cloneable {
 
     /**
      * @see Builder#setConnectTimeout(Timeout)
+     *
+     * @deprecated Use {@link ConnectionConfig#getConnectTimeout()}.
      */
+    @Deprecated
     public Timeout getConnectTimeout() {
         return connectTimeout;
     }
@@ -286,7 +292,6 @@ public class RequestConfig implements Cloneable {
             this.maxRedirects = 50;
             this.authenticationEnabled = true;
             this.connectionRequestTimeout = DEFAULT_CONNECTION_REQUEST_TIMEOUT;
-            this.connectTimeout = DEFAULT_CONNECT_TIMEOUT;
             this.contentCompressionEnabled = true;
             this.hardCancellationEnabled = true;
         }
@@ -323,7 +328,11 @@ public class RequestConfig implements Cloneable {
          * <p>
          * Default: {@code null}
          * </p>
+         *
+         * @deprecated Use {@link org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner}
+         * or a custom {@link org.apache.hc.client5.http.routing.HttpRoutePlanner}.
          */
+        @Deprecated
         public Builder setProxy(final HttpHost proxy) {
             this.proxy = proxy;
             return this;
@@ -444,7 +453,10 @@ public class RequestConfig implements Cloneable {
          * <p>
          * Default: 3 minutes
          * </p>
+         *
+         * @deprecated Use {@link ConnectionConfig.Builder#setConnectTimeout(Timeout)}.
          */
+        @Deprecated
         public Builder setConnectTimeout(final Timeout connectTimeout) {
             this.connectTimeout = connectTimeout;
             return this;
@@ -452,7 +464,10 @@ public class RequestConfig implements Cloneable {
 
         /**
          * @see #setConnectTimeout(Timeout)
+         *
+         * @deprecated Use {@link ConnectionConfig.Builder#setConnectTimeout(long, TimeUnit)}.
          */
+        @Deprecated
         public Builder setConnectTimeout(final long connectTimeout, final TimeUnit timeUnit) {
             this.connectTimeout = Timeout.of(connectTimeout, timeUnit);
             return this;
@@ -570,7 +585,7 @@ public class RequestConfig implements Cloneable {
                     targetPreferredAuthSchemes,
                     proxyPreferredAuthSchemes,
                     connectionRequestTimeout != null ? connectionRequestTimeout : DEFAULT_CONNECTION_REQUEST_TIMEOUT,
-                    connectTimeout != null ? connectTimeout : DEFAULT_CONNECT_TIMEOUT,
+                    connectTimeout,
                     responseTimeout,
                     connectionKeepAlive != null ? connectionKeepAlive : DEFAULT_CONN_KEEP_ALIVE,
                     contentCompressionEnabled,
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/H2AsyncClientBuilder.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/H2AsyncClientBuilder.java
index 6c2a0dc..494e925 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/H2AsyncClientBuilder.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/H2AsyncClientBuilder.java
@@ -45,6 +45,7 @@ import org.apache.hc.client5.http.async.AsyncExecChainHandler;
 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.ConnectionConfig;
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.cookie.BasicCookieStore;
 import org.apache.hc.client5.http.cookie.CookieSpecFactory;
@@ -74,7 +75,9 @@ import org.apache.hc.client5.http.routing.HttpRoutePlanner;
 import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
 import org.apache.hc.core5.annotation.Internal;
 import org.apache.hc.core5.concurrent.DefaultThreadFactory;
+import org.apache.hc.core5.function.Resolver;
 import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.HttpRequestInterceptor;
 import org.apache.hc.core5.http.HttpResponseInterceptor;
 import org.apache.hc.core5.http.config.CharCodingConfig;
@@ -89,7 +92,6 @@ import org.apache.hc.core5.http.protocol.HttpProcessorBuilder;
 import org.apache.hc.core5.http.protocol.RequestTargetHost;
 import org.apache.hc.core5.http.protocol.RequestUserAgent;
 import org.apache.hc.core5.http2.config.H2Config;
-import org.apache.hc.core5.http2.nio.pool.H2ConnPool;
 import org.apache.hc.core5.http2.protocol.H2RequestConnControl;
 import org.apache.hc.core5.http2.protocol.H2RequestContent;
 import org.apache.hc.core5.http2.protocol.H2RequestTargetHost;
@@ -189,6 +191,7 @@ public class H2AsyncClientBuilder {
     private String userAgent;
     private Collection<? extends Header> defaultHeaders;
     private RequestConfig defaultRequestConfig;
+    private Resolver<HttpHost, ConnectionConfig> connectionConfigResolver;
     private boolean evictIdleConnections;
     private TimeValue maxIdleTime;
 
@@ -501,6 +504,26 @@ public class H2AsyncClientBuilder {
     }
 
     /**
+     * Assigns {@link Resolver} for {@link ConnectionConfig} on a per host basis.
+     *
+     * @since 5.2
+     */
+    public final H2AsyncClientBuilder setConnectionConfigResolver(final Resolver<HttpHost, ConnectionConfig> connectionConfigResolver) {
+        this.connectionConfigResolver = connectionConfigResolver;
+        return this;
+    }
+
+    /**
+     * Assigns the same {@link ConnectionConfig} for all hosts.
+     *
+     * @since 5.2
+     */
+    public final H2AsyncClientBuilder setDefaultConnectionConfig(final ConnectionConfig connectionConfig) {
+        this.connectionConfigResolver = (host) -> connectionConfig;
+        return this;
+    }
+
+    /**
      * Use system properties when creating and configuring default
      * implementations.
      */
@@ -784,7 +807,8 @@ public class H2AsyncClientBuilder {
         }
 
         final MultihomeConnectionInitiator connectionInitiator = new MultihomeConnectionInitiator(ioReactor, dnsResolver);
-        final H2ConnPool connPool = new H2ConnPool(connectionInitiator, host -> null, tlsStrategyCopy);
+        final InternalH2ConnPool connPool = new InternalH2ConnPool(connectionInitiator, host -> null, tlsStrategyCopy);
+        connPool.setConnectionConfigResolver(connectionConfigResolver);
 
         List<Closeable> closeablesCopy = closeables != null ? new ArrayList<>(closeables) : null;
         if (closeablesCopy == null) {
@@ -821,7 +845,7 @@ public class H2AsyncClientBuilder {
 
         private final Thread thread;
 
-        public IdleConnectionEvictor(final H2ConnPool connPool, final TimeValue maxIdleTime) {
+        public IdleConnectionEvictor(final InternalH2ConnPool connPool, final TimeValue maxIdleTime) {
             this.thread = new DefaultThreadFactory("idle-connection-evictor", true).newThread(() -> {
                 try {
                     while (!Thread.currentThread().isInterrupted()) {
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalH2AsyncClient.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalH2AsyncClient.java
index 6ebaf66..cb758f6 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalH2AsyncClient.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalH2AsyncClient.java
@@ -47,7 +47,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.nio.pool.H2ConnPool;
 import org.apache.hc.core5.reactor.DefaultConnectingIOReactor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -68,14 +67,14 @@ public final class InternalH2AsyncClient extends InternalAbstractHttpAsyncClient
 
     private static final Logger LOG = LoggerFactory.getLogger(InternalH2AsyncClient.class);
     private final HttpRoutePlanner routePlanner;
-    private final H2ConnPool connPool;
+    private final InternalH2ConnPool connPool;
 
     InternalH2AsyncClient(
             final DefaultConnectingIOReactor ioReactor,
             final AsyncExecChainElement execChain,
             final AsyncPushConsumerRegistry pushConsumerRegistry,
             final ThreadFactory threadFactory,
-            final H2ConnPool connPool,
+            final InternalH2ConnPool connPool,
             final HttpRoutePlanner routePlanner,
             final Lookup<CookieSpecFactory> cookieSpecRegistry,
             final Lookup<AuthSchemeFactory> authSchemeRegistry,
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalH2AsyncExecRuntime.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalH2AsyncExecRuntime.java
index 957eeac..84411e2 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalH2AsyncExecRuntime.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalH2AsyncExecRuntime.java
@@ -44,7 +44,6 @@ 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.http.nio.command.RequestExecutionCommand;
-import org.apache.hc.core5.http2.nio.pool.H2ConnPool;
 import org.apache.hc.core5.io.CloseMode;
 import org.apache.hc.core5.reactor.Command;
 import org.apache.hc.core5.reactor.IOSession;
@@ -56,14 +55,14 @@ import org.slf4j.Logger;
 class InternalH2AsyncExecRuntime implements AsyncExecRuntime {
 
     private final Logger log;
-    private final H2ConnPool connPool;
+    private final InternalH2ConnPool connPool;
     private final HandlerFactory<AsyncPushConsumer> pushHandlerFactory;
     private final AtomicReference<Endpoint> sessionRef;
     private volatile boolean reusable;
 
     InternalH2AsyncExecRuntime(
             final Logger log,
-            final H2ConnPool connPool,
+            final InternalH2ConnPool connPool,
             final HandlerFactory<AsyncPushConsumer> pushHandlerFactory) {
         super();
         this.log = log;
@@ -91,9 +90,7 @@ class InternalH2AsyncExecRuntime implements AsyncExecRuntime {
             if (log.isDebugEnabled()) {
                 log.debug("{} acquiring endpoint ({})", id, connectTimeout);
             }
-            return Operations.cancellable(connPool.getSession(
-                    target,
-                    connectTimeout,
+            return Operations.cancellable(connPool.getSession(target, connectTimeout,
                     new FutureCallback<IOSession>() {
 
                         @Override
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalH2ConnPool.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalH2ConnPool.java
new file mode 100644
index 0000000..fb089dd
--- /dev/null
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalH2ConnPool.java
@@ -0,0 +1,102 @@
+/*
+ * ====================================================================
+ * 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.impl.async;
+
+import org.apache.hc.client5.http.config.ConnectionConfig;
+import org.apache.hc.core5.concurrent.CallbackContribution;
+import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.function.Resolver;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
+import org.apache.hc.core5.http2.nio.pool.H2ConnPool;
+import org.apache.hc.core5.io.CloseMode;
+import org.apache.hc.core5.io.ModalCloseable;
+import org.apache.hc.core5.reactor.ConnectionInitiator;
+import org.apache.hc.core5.reactor.IOSession;
+import org.apache.hc.core5.util.TimeValue;
+import org.apache.hc.core5.util.Timeout;
+
+import java.net.InetSocketAddress;
+import java.util.concurrent.Future;
+
+class InternalH2ConnPool implements ModalCloseable {
+
+    private final H2ConnPool connPool;
+
+    private volatile Resolver<HttpHost, ConnectionConfig> connectionConfigResolver;
+
+    InternalH2ConnPool(final ConnectionInitiator connectionInitiator,
+                       final Resolver<HttpHost, InetSocketAddress> addressResolver,
+                       final TlsStrategy tlsStrategy) {
+        this.connPool = new H2ConnPool(connectionInitiator, addressResolver, tlsStrategy);
+    }
+
+    public void close(final CloseMode closeMode) {
+        connPool.close(closeMode);
+    }
+
+    public void close() {
+        connPool.close();
+    }
+
+    private ConnectionConfig resolveConnectionConfig(final HttpHost httpHost) {
+        final Resolver<HttpHost, ConnectionConfig> resolver = this.connectionConfigResolver;
+        final ConnectionConfig connectionConfig = resolver != null ? resolver.resolve(httpHost) : null;
+        return connectionConfig != null ? connectionConfig : ConnectionConfig.DEFAULT;
+    }
+
+    public Future<IOSession> getSession(
+            final HttpHost endpoint,
+            final Timeout connectTimeout,
+            final FutureCallback<IOSession> callback) {
+        final ConnectionConfig connectionConfig = resolveConnectionConfig(endpoint);
+        return connPool.getSession(
+                endpoint,
+                connectTimeout != null ? connectTimeout : connectionConfig.getConnectTimeout(),
+                new CallbackContribution<IOSession>(callback) {
+
+                    @Override
+                    public void completed(final IOSession ioSession) {
+                        final Timeout socketTimeout = connectionConfig.getSocketTimeout();
+                        if (socketTimeout != null) {
+                            ioSession.setSocketTimeout(socketTimeout);
+                        }
+                        callback.completed(ioSession);
+                    }
+
+                });
+    }
+
+    public void closeIdle(final TimeValue idleTime) {
+        connPool.closeIdle(idleTime);
+    }
+
+    public void setConnectionConfigResolver(final Resolver<HttpHost, ConnectionConfig> connectionConfigResolver) {
+        this.connectionConfigResolver = connectionConfigResolver;
+    }
+
+}
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/MinimalH2AsyncClient.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/MinimalH2AsyncClient.java
index 6d91ff8..fe0f7fd 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/MinimalH2AsyncClient.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/MinimalH2AsyncClient.java
@@ -35,6 +35,7 @@ import java.util.concurrent.ThreadFactory;
 
 import org.apache.hc.client5.http.DnsResolver;
 import org.apache.hc.client5.http.config.Configurable;
+import org.apache.hc.client5.http.config.ConnectionConfig;
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.impl.ConnPoolSupport;
 import org.apache.hc.client5.http.impl.ExecSupport;
@@ -46,6 +47,7 @@ import org.apache.hc.core5.annotation.ThreadingBehavior;
 import org.apache.hc.core5.concurrent.Cancellable;
 import org.apache.hc.core5.concurrent.ComplexCancellable;
 import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.function.Resolver;
 import org.apache.hc.core5.http.EntityDetails;
 import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpException;
@@ -61,7 +63,6 @@ import org.apache.hc.core5.http.nio.command.RequestExecutionCommand;
 import org.apache.hc.core5.http.nio.command.ShutdownCommand;
 import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
 import org.apache.hc.core5.http.protocol.HttpContext;
-import org.apache.hc.core5.http2.nio.pool.H2ConnPool;
 import org.apache.hc.core5.io.CloseMode;
 import org.apache.hc.core5.reactor.Command;
 import org.apache.hc.core5.reactor.ConnectionInitiator;
@@ -90,7 +91,7 @@ import org.slf4j.LoggerFactory;
 public final class MinimalH2AsyncClient extends AbstractMinimalHttpAsyncClientBase {
 
     private static final Logger LOG = LoggerFactory.getLogger(MinimalH2AsyncClient.class);
-    private final H2ConnPool connPool;
+    private final InternalH2ConnPool connPool;
     private final ConnectionInitiator connectionInitiator;
 
     MinimalH2AsyncClient(
@@ -112,7 +113,7 @@ public final class MinimalH2AsyncClient extends AbstractMinimalHttpAsyncClientBa
                 pushConsumerRegistry,
                 threadFactory);
         this.connectionInitiator = new MultihomeConnectionInitiator(getConnectionInitiator(), dnsResolver);
-        this.connPool = new H2ConnPool(this.connectionInitiator, object -> null, tlsStrategy);
+        this.connPool = new InternalH2ConnPool(this.connectionInitiator, object -> null, tlsStrategy);
     }
 
     @Override
@@ -249,4 +250,13 @@ public final class MinimalH2AsyncClient extends AbstractMinimalHttpAsyncClientBa
         return cancellable;
     }
 
+    /**
+     * Sets {@link Resolver} for {@link ConnectionConfig} on a per host basis.
+     *
+     * @since 5.2
+     */
+    public void setConnectionConfigResolver(final Resolver<HttpHost, ConnectionConfig> connectionConfigResolver) {
+        connPool.setConnectionConfigResolver(connectionConfigResolver);
+    }
+
 }
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 230c304..337c1dc 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.impl.ConnPoolSupport;
+import org.apache.hc.client5.http.config.ConnectionConfig;
 import org.apache.hc.client5.http.impl.ConnectionShutdownException;
 import org.apache.hc.client5.http.io.ConnectionEndpoint;
 import org.apache.hc.client5.http.io.HttpClientConnectionManager;
@@ -107,6 +108,7 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
     private long expiry;
     private boolean leased;
     private SocketConfig socketConfig;
+    private ConnectionConfig connectionConfig;
 
     private final AtomicBoolean closed;
 
@@ -187,6 +189,20 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
         this.socketConfig = socketConfig != null ? socketConfig : SocketConfig.DEFAULT;
     }
 
+    /**
+     * @since 5.2
+     */
+    public synchronized ConnectionConfig getConnectionConfig() {
+        return connectionConfig;
+    }
+
+    /**
+     * @since 5.2
+     */
+    public synchronized void setConnectionConfig(final ConnectionConfig connectionConfig) {
+        this.connectionConfig = connectionConfig != null ? connectionConfig : ConnectionConfig.DEFAULT;
+    }
+
     public LeaseRequest lease(final String id, final HttpRoute route, final Object state) {
         return lease(id, route, Timeout.DISABLED, state);
     }
@@ -328,7 +344,7 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
     }
 
     @Override
-    public void connect(final ConnectionEndpoint endpoint, final TimeValue connectTimeout, final HttpContext context) throws IOException {
+    public synchronized void connect(final ConnectionEndpoint endpoint, final TimeValue timeout, final HttpContext context) throws IOException {
         Args.notNull(endpoint, "Endpoint");
 
         final InternalConnectionEndpoint internalEndpoint = cast(endpoint);
@@ -342,17 +358,24 @@ 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 ManagedHttpClientConnection connection = internalEndpoint.getConnection();
         this.connectionOperator.connect(
-                internalEndpoint.getConnection(),
+                connection,
                 host,
                 route.getLocalSocketAddress(),
                 connectTimeout,
                 this.socketConfig,
                 context);
+        final Timeout socketTimeout = config.getSocketTimeout();
+        if (socketTimeout != null) {
+            connection.setSocketTimeout(socketTimeout);
+        }
     }
 
     @Override
-    public void upgrade(
+    public synchronized void upgrade(
             final ConnectionEndpoint endpoint,
             final HttpContext context) throws IOException {
         Args.notNull(endpoint, "Endpoint");
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 13b3998..c6eeb27 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
@@ -26,19 +26,10 @@
  */
 package org.apache.hc.client5.http.impl.io;
 
-import java.io.IOException;
-import java.util.Set;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.atomic.AtomicReference;
-
 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.impl.ConnPoolSupport;
 import org.apache.hc.client5.http.impl.ConnectionShutdownException;
 import org.apache.hc.client5.http.io.ConnectionEndpoint;
@@ -52,6 +43,7 @@ import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
 import org.apache.hc.core5.annotation.Contract;
 import org.apache.hc.core5.annotation.Internal;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
+import org.apache.hc.core5.function.Resolver;
 import org.apache.hc.core5.http.ClassicHttpRequest;
 import org.apache.hc.core5.http.ClassicHttpResponse;
 import org.apache.hc.core5.http.HttpException;
@@ -80,6 +72,16 @@ import org.apache.hc.core5.util.Timeout;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.IOException;
+import java.util.Set;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+
 /**
  * {@code ClientConnectionPoolManager} maintains a pool of
  * {@link ManagedHttpClientConnection}s and is able to service connection requests
@@ -112,8 +114,8 @@ public class PoolingHttpClientConnectionManager
     private final HttpConnectionFactory<ManagedHttpClientConnection> connFactory;
     private final AtomicBoolean closed;
 
-    private volatile SocketConfig defaultSocketConfig;
-    private volatile TimeValue validateAfterInactivity;
+    private volatile Resolver<HttpRoute, SocketConfig> socketConfigResolver;
+    private volatile Resolver<HttpRoute, ConnectionConfig> connectionConfigResolver;
 
     public PoolingHttpClientConnectionManager() {
         this(RegistryBuilder.<ConnectionSocketFactory>create()
@@ -203,7 +205,6 @@ public class PoolingHttpClientConnectionManager
         }
         this.connFactory = connFactory != null ? connFactory : ManagedHttpClientConnectionFactory.INSTANCE;
         this.closed = new AtomicBoolean(false);
-        this.validateAfterInactivity = TimeValue.ofSeconds(2L);
     }
 
     @Internal
@@ -241,6 +242,23 @@ public class PoolingHttpClientConnectionManager
         throw new IllegalStateException("Unexpected endpoint class: " + endpoint.getClass());
     }
 
+    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 TimeValue resolveValidateAfterInactivity(final ConnectionConfig connectionConfig) {
+        final TimeValue timeValue = connectionConfig.getValidateAfterInactivity();
+        return timeValue != null ? timeValue : TimeValue.ofSeconds(2);
+    }
+
     public LeaseRequest lease(final String id, final HttpRoute route, final Object state) {
         return lease(id, route, Timeout.DISABLED, state);
     }
@@ -280,12 +298,13 @@ public class PoolingHttpClientConnectionManager
                 if (LOG.isDebugEnabled()) {
                     LOG.debug("{} endpoint leased {}", id, ConnPoolSupport.formatStats(route, state, pool));
                 }
+                final ConnectionConfig connectionConfig = resolveConnectionConfig(route);
+                final TimeValue timeValue = resolveValidateAfterInactivity(connectionConfig);
                 try {
-                    final TimeValue validateAfterInactivitySnapshot = validateAfterInactivity;
-                    if (TimeValue.isNonNegative(validateAfterInactivitySnapshot)) {
+                    if (TimeValue.isNonNegative(timeValue)) {
                         final ManagedHttpClientConnection conn = poolEntry.getConnection();
                         if (conn != null
-                                && poolEntry.getUpdated() + validateAfterInactivitySnapshot.toMilliseconds() <= System.currentTimeMillis()) {
+                                && poolEntry.getUpdated() + timeValue.toMilliseconds() <= System.currentTimeMillis()) {
                             boolean stale;
                             try {
                                 stale = conn.isStale();
@@ -382,7 +401,7 @@ public class PoolingHttpClientConnectionManager
     }
 
     @Override
-    public void connect(final ConnectionEndpoint endpoint, final TimeValue connectTimeout, final HttpContext context) throws IOException {
+    public void connect(final ConnectionEndpoint endpoint, final TimeValue timeout, final HttpContext context) throws IOException {
         Args.notNull(endpoint, "Managed endpoint");
         final InternalConnectionEndpoint internalEndpoint = cast(endpoint);
         if (internalEndpoint.isConnected()) {
@@ -399,21 +418,27 @@ public class PoolingHttpClientConnectionManager
         } else {
             host = route.getTargetHost();
         }
+        final SocketConfig socketConfig = resolveSocketConfig(route);
+        final ConnectionConfig connectionConfig = resolveConnectionConfig(route);
+        final TimeValue connectTimeout = timeout != null ? timeout : connectionConfig.getConnectTimeout();
         if (LOG.isDebugEnabled()) {
             LOG.debug("{} connecting endpoint to {} ({})", ConnPoolSupport.getId(endpoint), host, connectTimeout);
         }
         final ManagedHttpClientConnection conn = poolEntry.getConnection();
-        final SocketConfig defaultSocketConfigSnapshot = defaultSocketConfig;
         this.connectionOperator.connect(
                 conn,
                 host,
                 route.getLocalSocketAddress(),
-                connectTimeout,
-                defaultSocketConfigSnapshot != null ? defaultSocketConfigSnapshot : SocketConfig.DEFAULT,
+                timeout,
+                socketConfig,
                 context);
         if (LOG.isDebugEnabled()) {
             LOG.debug("{} connected {}", ConnPoolSupport.getId(endpoint), ConnPoolSupport.getId(conn));
         }
+        final Timeout socketTimeout = connectionConfig.getSocketTimeout();
+        if (socketTimeout != null) {
+            conn.setSocketTimeout(socketTimeout);
+        }
     }
 
     @Override
@@ -485,21 +510,56 @@ public class PoolingHttpClientConnectionManager
         return this.pool.getStats(route);
     }
 
-    public SocketConfig getDefaultSocketConfig() {
-        return this.defaultSocketConfig;
+    /**
+     * Sets the same {@link SocketConfig} for all routes
+     */
+    public void setDefaultSocketConfig(final SocketConfig config) {
+        this.socketConfigResolver = (route) -> config;
     }
 
-    public void setDefaultSocketConfig(final SocketConfig defaultSocketConfig) {
-        this.defaultSocketConfig = defaultSocketConfig;
+    /**
+     * Sets {@link Resolver} of {@link SocketConfig} on a per route basis.
+     *
+     * @since 5.2
+     */
+    public void setSocketConfigResolver(final Resolver<HttpRoute, SocketConfig> socketConfigResolver) {
+        this.socketConfigResolver = socketConfigResolver;
+    }
+
+    /**
+     * Sets the same {@link ConnectionConfig} for all routes
+     *
+     * @since 5.2
+     */
+    public void setDefaultConnectionConfig(final ConnectionConfig config) {
+        this.connectionConfigResolver = (route) -> config;
     }
 
     /**
-     * @see #setValidateAfterInactivity(TimeValue)
+     * Sets {@link Resolver} of {@link ConnectionConfig} on a per route basis.
      *
+     * @since 5.2
+     */
+    public void setConnectionConfigResolver(final Resolver<HttpRoute, ConnectionConfig> connectionConfigResolver) {
+        this.connectionConfigResolver = connectionConfigResolver;
+    }
+
+    /**
+     * @deprecated Use custom {@link #setConnectionConfigResolver(Resolver)}
+     */
+    @Deprecated
+    public SocketConfig getDefaultSocketConfig() {
+        return SocketConfig.DEFAULT;
+    }
+
+    /**
      * @since 4.4
+     *
+     * @deprecated Use {@link #setConnectionConfigResolver(Resolver)}.
      */
+    @Deprecated
     public TimeValue getValidateAfterInactivity() {
-        return validateAfterInactivity;
+        return ConnectionConfig.DEFAULT.getValidateAfterInactivity();
     }
 
     /**
@@ -509,9 +569,14 @@ public class PoolingHttpClientConnectionManager
      * detect connections that have become stale (half-closed) while kept inactive in the pool.
      *
      * @since 4.4
+     *
+     * @deprecated Use {@link #setConnectionConfigResolver(Resolver)}.
      */
+    @Deprecated
     public void setValidateAfterInactivity(final TimeValue validateAfterInactivity) {
-        this.validateAfterInactivity = validateAfterInactivity;
+        setDefaultConnectionConfig(ConnectionConfig.custom()
+                .setValidateAfterInactivity(validateAfterInactivity)
+                .build());
     }
 
     private static final AtomicLong COUNT = new AtomicLong(0);
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 2dd506b..e52f9ac 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
@@ -28,12 +28,15 @@
 package org.apache.hc.client5.http.impl.io;
 
 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.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.URIScheme;
 import org.apache.hc.core5.http.config.RegistryBuilder;
 import org.apache.hc.core5.http.io.HttpConnectionFactory;
@@ -76,7 +79,8 @@ public class PoolingHttpClientConnectionManagerBuilder {
     private DnsResolver dnsResolver;
     private PoolConcurrencyPolicy poolConcurrencyPolicy;
     private PoolReusePolicy poolReusePolicy;
-    private SocketConfig defaultSocketConfig;
+    private Resolver<HttpRoute, SocketConfig> socketConfigResolver;
+    private Resolver<HttpRoute, ConnectionConfig> connectionConfigResolver;
 
     private boolean systemProperties;
 
@@ -84,7 +88,6 @@ public class PoolingHttpClientConnectionManagerBuilder {
     private int maxConnPerRoute;
 
     private TimeValue timeToLive;
-    private TimeValue validateAfterInactivity;
 
     public static PoolingHttpClientConnectionManagerBuilder create() {
         return new PoolingHttpClientConnectionManagerBuilder();
@@ -161,10 +164,42 @@ public class PoolingHttpClientConnectionManagerBuilder {
     }
 
     /**
-     * Assigns default {@link SocketConfig}.
+     * Assigns the same {@link SocketConfig} for all routes.
      */
     public final PoolingHttpClientConnectionManagerBuilder setDefaultSocketConfig(final SocketConfig config) {
-        this.defaultSocketConfig = config;
+        this.socketConfigResolver = (route) -> config;
+        return this;
+    }
+
+    /**
+     * Assigns {@link Resolver} of {@link SocketConfig} on a per route basis.
+     *
+     * @since 5.2
+     */
+    public final PoolingHttpClientConnectionManagerBuilder setSocketConfigResolver(
+            final Resolver<HttpRoute, SocketConfig> socketConfigResolver) {
+        this.socketConfigResolver = socketConfigResolver;
+        return this;
+    }
+
+    /**
+     * Assigns the same {@link ConnectionConfig} for all routes.
+     *
+     * @since 5.2
+     */
+    public final PoolingHttpClientConnectionManagerBuilder setDefaultConnectionConfig(final ConnectionConfig config) {
+        this.connectionConfigResolver = (route) -> config;
+        return this;
+    }
+
+    /**
+     * Assigns {@link Resolver} of {@link ConnectionConfig} on a per route basis.
+     *
+     * @since 5.2
+     */
+    public final PoolingHttpClientConnectionManagerBuilder setConnectionConfigResolver(
+            final Resolver<HttpRoute, ConnectionConfig> connectionConfigResolver) {
+        this.connectionConfigResolver = connectionConfigResolver;
         return this;
     }
 
@@ -180,10 +215,13 @@ public class PoolingHttpClientConnectionManagerBuilder {
      * Sets period after inactivity after which persistent
      * connections must be checked to ensure they are still valid.
      *
-     * @see org.apache.hc.core5.http.io.HttpClientConnection#isStale()
+     * @deprecated Use {@link #setDefaultConnectionConfig(ConnectionConfig)}.
      */
+    @Deprecated
     public final PoolingHttpClientConnectionManagerBuilder setValidateAfterInactivity(final TimeValue validateAfterInactivity) {
-        this.validateAfterInactivity = validateAfterInactivity;
+        setDefaultConnectionConfig(ConnectionConfig.custom()
+                .setValidateAfterInactivity(validateAfterInactivity)
+                .build());
         return this;
     }
 
@@ -197,8 +235,7 @@ public class PoolingHttpClientConnectionManagerBuilder {
     }
 
     public PoolingHttpClientConnectionManager build() {
-        @SuppressWarnings("resource")
-        final PoolingHttpClientConnectionManager poolingmgr = new PoolingHttpClientConnectionManager(
+        @SuppressWarnings("resource") final PoolingHttpClientConnectionManager poolingmgr = new PoolingHttpClientConnectionManager(
                 RegistryBuilder.<ConnectionSocketFactory>create()
                         .register(URIScheme.HTTP.id, PlainConnectionSocketFactory.getSocketFactory())
                         .register(URIScheme.HTTPS.id, sslSocketFactory != null ? sslSocketFactory :
@@ -212,12 +249,8 @@ public class PoolingHttpClientConnectionManagerBuilder {
                 schemePortResolver,
                 dnsResolver,
                 connectionFactory);
-        if (validateAfterInactivity != null) {
-            poolingmgr.setValidateAfterInactivity(validateAfterInactivity);
-        }
-        if (defaultSocketConfig != null) {
-            poolingmgr.setDefaultSocketConfig(defaultSocketConfig);
-        }
+        poolingmgr.setSocketConfigResolver(socketConfigResolver);
+        poolingmgr.setConnectionConfigResolver(connectionConfigResolver);
         if (maxConnTotal > 0) {
             poolingmgr.setMaxTotal(maxConnTotal);
         }
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 dc59ce8..21cb5b3 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
@@ -37,6 +37,7 @@ import java.util.concurrent.atomic.AtomicReference;
 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.impl.ConnPoolSupport;
 import org.apache.hc.client5.http.impl.ConnectionShutdownException;
 import org.apache.hc.client5.http.nio.AsyncClientConnectionManager;
@@ -49,6 +50,7 @@ import org.apache.hc.core5.annotation.Internal;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
 import org.apache.hc.core5.concurrent.ComplexFuture;
 import org.apache.hc.core5.concurrent.FutureCallback;
+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;
@@ -111,7 +113,7 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
     private final AsyncClientConnectionOperator connectionOperator;
     private final AtomicBoolean closed;
 
-    private volatile TimeValue validateAfterInactivity;
+    private volatile Resolver<HttpRoute, ConnectionConfig> connectionConfigResolver;
 
     public PoolingAsyncClientConnectionManager() {
         this(RegistryBuilder.<TlsStrategy>create()
@@ -210,6 +212,12 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
         throw new IllegalStateException("Unexpected endpoint class: " + endpoint.getClass());
     }
 
+    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;
+    }
+
     @Override
     public Future<AsyncConnectionEndpoint> lease(
             final String id,
@@ -221,6 +229,7 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
             LOG.debug("{} endpoint lease request ({}) {}", id, requestTimeout, ConnPoolSupport.formatStats(route, state, pool));
         }
         final ComplexFuture<AsyncConnectionEndpoint> resultFuture = new ComplexFuture<>(callback);
+        final ConnectionConfig connectionConfig = resolveConnectionConfig(route);
         final Future<PoolEntry<HttpRoute, ManagedAsyncClientConnection>> leaseFuture = pool.lease(
                 route, state, requestTimeout, new FutureCallback<PoolEntry<HttpRoute, ManagedAsyncClientConnection>>() {
 
@@ -242,25 +251,20 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
                     @Override
                     public void completed(final PoolEntry<HttpRoute, ManagedAsyncClientConnection> poolEntry) {
                         final ManagedAsyncClientConnection connection = poolEntry.getConnection();
-                        if (connection != null) {
-                            if (connection.isOpen()) {
-                                final ProtocolVersion protocolVersion = connection.getProtocolVersion();
-                                if (protocolVersion != null && protocolVersion.greaterEquals(HttpVersion.HTTP_2_0)) {
-                                    final TimeValue timeValue = PoolingAsyncClientConnectionManager.this.validateAfterInactivity;
-                                    if (TimeValue.isNonNegative(timeValue) &&
-                                            poolEntry.getUpdated() + timeValue.toMilliseconds() <= System.currentTimeMillis()) {
-                                        connection.submitCommand(new PingCommand(new BasicPingHandler(result -> {
-                                            if (result == null || !result) {
-                                                if (LOG.isDebugEnabled()) {
-                                                    LOG.debug("{} connection {} is stale", id, ConnPoolSupport.getId(connection));
-                                                }
-                                                poolEntry.discardConnection(CloseMode.IMMEDIATE);
-                                            }
-                                            leaseCompleted(poolEntry);
-                                        })), Command.Priority.IMMEDIATE);
-                                        return;
+                        final TimeValue timeValue = connectionConfig != null ? connectionConfig.getValidateAfterInactivity() : null;
+                        if (TimeValue.isNonNegative(timeValue) && connection != null &&
+                                poolEntry.getUpdated() + timeValue.toMilliseconds() <= System.currentTimeMillis()) {
+                            final ProtocolVersion protocolVersion = connection.getProtocolVersion();
+                            if (protocolVersion != null && protocolVersion.greaterEquals(HttpVersion.HTTP_2_0)) {
+                                connection.submitCommand(new PingCommand(new BasicPingHandler(result -> {
+                                    if (result == null || !result) {
+                                        if (LOG.isDebugEnabled()) {
+                                            LOG.debug("{} connection {} is stale", id, ConnPoolSupport.getId(connection));
+                                        }
+                                        poolEntry.discardConnection(CloseMode.IMMEDIATE);
                                     }
-                                }
+                                    leaseCompleted(poolEntry);
+                                })), Command.Priority.IMMEDIATE);
                             } else {
                                 if (LOG.isDebugEnabled()) {
                                     LOG.debug("{} connection {} is closed", id, ConnPoolSupport.getId(connection));
@@ -336,13 +340,12 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
     public Future<AsyncConnectionEndpoint> connect(
             final AsyncConnectionEndpoint endpoint,
             final ConnectionInitiator connectionInitiator,
-            final Timeout connectTimeout,
+            final Timeout timeout,
             final Object attachment,
             final HttpContext context,
             final FutureCallback<AsyncConnectionEndpoint> callback) {
         Args.notNull(endpoint, "Endpoint");
         Args.notNull(connectionInitiator, "Connection initiator");
-        Args.notNull(connectTimeout, "Timeout");
         final InternalConnectionEndpoint internalEndpoint = cast(endpoint);
         final ComplexFuture<AsyncConnectionEndpoint> resultFuture = new ComplexFuture<>(callback);
         if (internalEndpoint.isConnected()) {
@@ -358,6 +361,9 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
             host = route.getTargetHost();
         }
         final InetSocketAddress localAddress = route.getLocalSocketAddress();
+        final ConnectionConfig connectionConfig = resolveConnectionConfig(route);
+        final Timeout connectTimeout = timeout != null ? timeout : connectionConfig.getConnectTimeout();
+
         if (LOG.isDebugEnabled()) {
             LOG.debug("{} connecting endpoint to {} ({})", ConnPoolSupport.getId(endpoint), host, connectTimeout);
         }
@@ -370,6 +376,10 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
                             if (LOG.isDebugEnabled()) {
                                 LOG.debug("{} connected {}", ConnPoolSupport.getId(endpoint), ConnPoolSupport.getId(connection));
                             }
+                            final Timeout socketTimeout = connectionConfig.getSocketTimeout();
+                            if (socketTimeout != null) {
+                                connection.setSocketTimeout(socketTimeout);
+                            }
                             poolEntry.assignConnection(connection);
                             resultFuture.completed(internalEndpoint);
                         } catch (final RuntimeException ex) {
@@ -463,8 +473,30 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
         return pool.getStats(route);
     }
 
+    /**
+     * Sets the same {@link ConnectionConfig} for all routes
+     *
+     * @since 5.2
+     */
+    public void setDefaultConnectionConfig(final ConnectionConfig config) {
+        this.connectionConfigResolver = (route) -> config;
+    }
+
+    /**
+     * Sets {@link Resolver} of {@link ConnectionConfig} on a per route basis.
+     *
+     * @since 5.2
+     */
+    public void setConnectionConfigResolver(final Resolver<HttpRoute, ConnectionConfig> connectionConfigResolver) {
+        this.connectionConfigResolver = connectionConfigResolver;
+    }
+
+    /**
+     * @deprecated Use custom {@link #setConnectionConfigResolver(Resolver)}
+     */
+    @Deprecated
     public TimeValue getValidateAfterInactivity() {
-        return validateAfterInactivity;
+        return ConnectionConfig.DEFAULT.getValidateAfterInactivity();
     }
 
     /**
@@ -473,9 +505,14 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
      * FutureCallback)} leased} to the consumer. Negative values passed
      * to this method disable connection validation. This check helps detect connections
      * that have become stale (half-closed) while kept inactive in the pool.
+     *
+     * @deprecated Use {@link #setConnectionConfigResolver(Resolver)}.
      */
+    @Deprecated
     public void setValidateAfterInactivity(final TimeValue validateAfterInactivity) {
-        this.validateAfterInactivity = validateAfterInactivity;
+        setDefaultConnectionConfig(ConnectionConfig.custom()
+                .setValidateAfterInactivity(validateAfterInactivity)
+                .build());
     }
 
     private static final AtomicLong COUNT = new AtomicLong(0);
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 c1dd8ae..a8d44b0 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
@@ -28,10 +28,14 @@
 package org.apache.hc.client5.http.impl.nio;
 
 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.ssl.ConscryptClientTlsStrategy;
 import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
+import org.apache.hc.core5.function.Resolver;
 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;
 import org.apache.hc.core5.pool.PoolConcurrencyPolicy;
 import org.apache.hc.core5.pool.PoolReusePolicy;
@@ -77,8 +81,9 @@ public class PoolingAsyncClientConnectionManagerBuilder {
     private int maxConnTotal;
     private int maxConnPerRoute;
 
+    private Resolver<HttpRoute, SocketConfig> socketConfigResolver;
+    private Resolver<HttpRoute, ConnectionConfig> connectionConfigResolver;
     private TimeValue timeToLive;
-    private TimeValue validateAfterInactivity;
 
     public static PoolingAsyncClientConnectionManagerBuilder create() {
         return new PoolingAsyncClientConnectionManagerBuilder();
@@ -146,6 +151,28 @@ public class PoolingAsyncClientConnectionManagerBuilder {
     }
 
     /**
+     * Assigns the same {@link ConnectionConfig} for all routes.
+     *
+     * @since 5.2
+     */
+    public final PoolingAsyncClientConnectionManagerBuilder setDefaultConnectionConfig(final ConnectionConfig config) {
+        this.connectionConfigResolver = (route) -> config;
+        return this;
+    }
+
+    /**
+     * Assigns {@link Resolver} of {@link ConnectionConfig} on a per route basis.
+     *
+     * @since 5.2
+     */
+    public final PoolingAsyncClientConnectionManagerBuilder setConnectionConfigResolver(
+            final Resolver<HttpRoute, ConnectionConfig> connectionConfigResolver) {
+        this.connectionConfigResolver = connectionConfigResolver;
+        return this;
+    }
+
+
+    /**
      * Sets maximum time to live for persistent connections
      */
     public final PoolingAsyncClientConnectionManagerBuilder setConnectionTimeToLive(final TimeValue timeToLive) {
@@ -157,10 +184,13 @@ public class PoolingAsyncClientConnectionManagerBuilder {
      * Sets period after inactivity after which persistent
      * connections must be checked to ensure they are still valid.
      *
-     * @see org.apache.hc.core5.http.io.HttpClientConnection#isStale()
+     * @deprecated Use {@link #setConnectionConfigResolver(Resolver)}.
      */
+    @Deprecated
     public final PoolingAsyncClientConnectionManagerBuilder setValidateAfterInactivity(final TimeValue validateAfterInactivity) {
-        this.validateAfterInactivity = validateAfterInactivity;
+        setDefaultConnectionConfig(ConnectionConfig.custom()
+                .setValidateAfterInactivity(validateAfterInactivity)
+                .build());
         return this;
     }
 
@@ -201,9 +231,7 @@ public class PoolingAsyncClientConnectionManagerBuilder {
                 timeToLive,
                 schemePortResolver,
                 dnsResolver);
-        if (validateAfterInactivity != null) {
-            poolingmgr.setValidateAfterInactivity(validateAfterInactivity);
-        }
+        poolingmgr.setConnectionConfigResolver(connectionConfigResolver);
         if (maxConnTotal > 0) {
             poolingmgr.setMaxTotal(maxConnTotal);
         }
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/config/TestRequestConfig.java b/httpclient5/src/test/java/org/apache/hc/client5/http/config/TestRequestConfig.java
index e0035d8..572bba0 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/config/TestRequestConfig.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/config/TestRequestConfig.java
@@ -32,7 +32,6 @@ import java.util.concurrent.TimeUnit;
 
 import org.apache.hc.client5.http.auth.StandardAuthScheme;
 import org.apache.hc.client5.http.cookie.StandardCookieSpec;
-import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.util.TimeValue;
 import org.apache.hc.core5.util.Timeout;
 import org.junit.Assert;
@@ -49,7 +48,6 @@ public class TestRequestConfig {
     @Test
     public void testDefaults() {
         final RequestConfig config = RequestConfig.DEFAULT;
-        Assert.assertEquals(Timeout.ofMinutes(3), config.getConnectTimeout());
         Assert.assertEquals(Timeout.ofMinutes(3), config.getConnectionRequestTimeout());
         Assert.assertEquals(false, config.isExpectContinueEnabled());
         Assert.assertEquals(true, config.isAuthenticationEnabled());
@@ -66,7 +64,6 @@ public class TestRequestConfig {
     @Test
     public void testBuildAndCopy() throws Exception {
         final RequestConfig config0 = RequestConfig.custom()
-                .setConnectTimeout(33, TimeUnit.MILLISECONDS)
                 .setConnectionRequestTimeout(44, TimeUnit.MILLISECONDS)
                 .setExpectContinueEnabled(true)
                 .setAuthenticationEnabled(false)
@@ -74,13 +71,11 @@ public class TestRequestConfig {
                 .setCircularRedirectsAllowed(true)
                 .setMaxRedirects(100)
                 .setCookieSpec(StandardCookieSpec.STRICT)
-                .setProxy(new HttpHost("someproxy"))
                 .setTargetPreferredAuthSchemes(Collections.singletonList(StandardAuthScheme.NTLM))
                 .setProxyPreferredAuthSchemes(Collections.singletonList(StandardAuthScheme.DIGEST))
                 .setContentCompressionEnabled(false)
                 .build();
         final RequestConfig config = RequestConfig.copy(config0).build();
-        Assert.assertEquals(TimeValue.ofMilliseconds(33), config.getConnectTimeout());
         Assert.assertEquals(TimeValue.ofMilliseconds(44), config.getConnectionRequestTimeout());
         Assert.assertEquals(true, config.isExpectContinueEnabled());
         Assert.assertEquals(false, config.isAuthenticationEnabled());
@@ -88,7 +83,6 @@ public class TestRequestConfig {
         Assert.assertEquals(true, config.isCircularRedirectsAllowed());
         Assert.assertEquals(100, config.getMaxRedirects());
         Assert.assertEquals(StandardCookieSpec.STRICT, config.getCookieSpec());
-        Assert.assertEquals(new HttpHost("someproxy"), config.getProxy());
         Assert.assertEquals(Collections.singletonList(StandardAuthScheme.NTLM), config.getTargetPreferredAuthSchemes());
         Assert.assertEquals(Collections.singletonList(StandardAuthScheme.DIGEST), config.getProxyPreferredAuthSchemes());
         Assert.assertEquals(false, config.isContentCompressionEnabled());
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientConfiguration.java b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientConfiguration.java
index 7a61c7f..4ec5ab2 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientConfiguration.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientConfiguration.java
@@ -42,6 +42,7 @@ import org.apache.hc.client5.http.SystemDefaultDnsResolver;
 import org.apache.hc.client5.http.auth.StandardAuthScheme;
 import org.apache.hc.client5.http.auth.CredentialsProvider;
 import org.apache.hc.client5.http.classic.methods.HttpGet;
+import org.apache.hc.client5.http.config.ConnectionConfig;
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.cookie.BasicCookieStore;
 import org.apache.hc.client5.http.cookie.StandardCookieSpec;
@@ -172,15 +173,17 @@ public class ClientConfiguration {
                 socketFactoryRegistry, PoolConcurrencyPolicy.STRICT, PoolReusePolicy.LIFO, TimeValue.ofMinutes(5),
                 null, dnsResolver, null);
 
-        // Create socket configuration
-        final SocketConfig socketConfig = SocketConfig.custom()
-            .setTcpNoDelay(true)
-            .build();
         // Configure the connection manager to use socket configuration either
         // by default or for a specific host.
-        connManager.setDefaultSocketConfig(socketConfig);
-        // Validate connections after 1 sec of inactivity
-        connManager.setValidateAfterInactivity(TimeValue.ofSeconds(10));
+        connManager.setDefaultSocketConfig(SocketConfig.custom()
+                .setTcpNoDelay(true)
+                .build());
+        // Validate connections after 10 sec of inactivity
+        connManager.setDefaultConnectionConfig(ConnectionConfig.custom()
+                .setConnectTimeout(Timeout.ofSeconds(30))
+                .setSocketTimeout(Timeout.ofSeconds(30))
+                .setValidateAfterInactivity(TimeValue.ofSeconds(10))
+                .build());
 
         // Configure total max or per route limits for persistent connections
         // that can be kept in the pool or leased by the connection manager.
@@ -214,8 +217,6 @@ public class ClientConfiguration {
             // They will take precedence over the one set at the client level.
             final RequestConfig requestConfig = RequestConfig.copy(defaultRequestConfig)
                     .setConnectionRequestTimeout(Timeout.ofSeconds(5))
-                    .setConnectTimeout(Timeout.ofSeconds(5))
-                    .setProxy(new HttpHost("myotherproxy", 8080))
                     .build();
             httpget.setConfig(requestConfig);