HTTPCLIENT-2135: TLS configuration on a per-host basis

This commit is contained in:
Oleg Kalnichevski 2021-09-12 14:54:32 +02:00
parent 4b7551a466
commit b10d43f2bb
37 changed files with 866 additions and 198 deletions

View File

@ -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.SimpleHttpResponse;
import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder; import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
import org.apache.hc.client5.http.config.RequestConfig; 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.DefaultHttpRequestRetryStrategy;
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder; import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;
@ -102,12 +103,14 @@ public class TestHttp1RequestReExecution extends AbstractIntegrationTestBase<Clo
@Override @Override
protected void before() throws Throwable { 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() clientBuilder = HttpAsyncClientBuilder.create()
.setDefaultRequestConfig(RequestConfig.custom() .setDefaultRequestConfig(RequestConfig.custom()
.setConnectionRequestTimeout(TIMEOUT) .setConnectionRequestTimeout(TIMEOUT)
.build()) .build())
.setConnectionManager(connManager) .setConnectionManager(connManager);
.setVersionPolicy(version.greaterEquals(HttpVersion.HTTP_2) ? HttpVersionPolicy.FORCE_HTTP_2 : HttpVersionPolicy.FORCE_HTTP_1);
} }
}; };

View File

@ -34,9 +34,9 @@ import java.util.Random;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; 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.HttpAsyncClients;
import org.apache.hc.client5.http.impl.async.MinimalHttpAsyncClient; 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.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
import org.apache.hc.client5.http.protocol.HttpClientContext; import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy; import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
@ -85,19 +85,19 @@ public class TestHttpAsyncMinimal extends AbstractHttpAsyncFundamentalsTest<Mini
@Override @Override
protected MinimalHttpAsyncClient createClient() throws Exception { protected MinimalHttpAsyncClient createClient() throws Exception {
final PoolingAsyncClientConnectionManager connectionManager = PoolingAsyncClientConnectionManagerBuilder.create() return HttpAsyncClients.createMinimal(
.setTlsStrategy(new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext())) H2Config.DEFAULT,
.build(); Http1Config.DEFAULT,
final IOReactorConfig ioReactorConfig = IOReactorConfig.custom() IOReactorConfig.custom()
.setSoTimeout(TIMEOUT) .setSoTimeout(TIMEOUT)
.build(); .build(),
if (version.greaterEquals(HttpVersion.HTTP_2)) { PoolingAsyncClientConnectionManagerBuilder.create()
return HttpAsyncClients.createMinimal( .setTlsStrategy(new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext()))
HttpVersionPolicy.FORCE_HTTP_2, H2Config.DEFAULT, Http1Config.DEFAULT, ioReactorConfig, connectionManager); .setDefaultTlsConfig(TlsConfig.custom()
} else { .setVersionPolicy(version.greaterEquals(HttpVersion.HTTP_2)
return HttpAsyncClients.createMinimal( ? HttpVersionPolicy.FORCE_HTTP_2 : HttpVersionPolicy.FORCE_HTTP_1)
HttpVersionPolicy.FORCE_HTTP_1, H2Config.DEFAULT, Http1Config.DEFAULT, ioReactorConfig, connectionManager); .build())
} .build());
} }
@Override @Override

View File

@ -34,9 +34,9 @@ import java.util.Random;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; 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.HttpAsyncClients;
import org.apache.hc.client5.http.impl.async.MinimalHttpAsyncClient; 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.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
import org.apache.hc.client5.http.protocol.HttpClientContext; import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy; import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
@ -85,19 +85,19 @@ public class TestHttpMinimalReactive extends AbstractHttpReactiveFundamentalsTes
@Override @Override
protected MinimalHttpAsyncClient createClient() throws Exception { protected MinimalHttpAsyncClient createClient() throws Exception {
final PoolingAsyncClientConnectionManager connectionManager = PoolingAsyncClientConnectionManagerBuilder.create() return HttpAsyncClients.createMinimal(
.setTlsStrategy(new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext())) H2Config.DEFAULT,
.build(); Http1Config.DEFAULT,
final IOReactorConfig ioReactorConfig = IOReactorConfig.custom() IOReactorConfig.custom()
.setSoTimeout(TIMEOUT) .setSoTimeout(TIMEOUT)
.build(); .build(),
if (version.greaterEquals(HttpVersion.HTTP_2)) { PoolingAsyncClientConnectionManagerBuilder.create()
return HttpAsyncClients.createMinimal( .setTlsStrategy(new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext()))
HttpVersionPolicy.FORCE_HTTP_2, H2Config.DEFAULT, Http1Config.DEFAULT, ioReactorConfig, connectionManager); .setDefaultTlsConfig(TlsConfig.custom()
} else { .setVersionPolicy(version.greaterEquals(HttpVersion.HTTP_2)
return HttpAsyncClients.createMinimal( ? HttpVersionPolicy.FORCE_HTTP_2 : HttpVersionPolicy.FORCE_HTTP_1)
HttpVersionPolicy.FORCE_HTTP_1, H2Config.DEFAULT, Http1Config.DEFAULT, ioReactorConfig, connectionManager); .build())
} .build());
} }
@Override @Override

View File

@ -35,13 +35,12 @@ import java.util.concurrent.TimeoutException;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; 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.SimpleHttpRequest;
import org.apache.hc.client5.http.async.methods.SimpleHttpResponse; 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.SimpleRequestBuilder;
import org.apache.hc.client5.http.cache.CacheResponseStatus; import org.apache.hc.client5.http.cache.CacheResponseStatus;
import org.apache.hc.client5.http.cache.HttpCacheContext; 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.async.CloseableHttpAsyncClient;
import org.apache.hc.client5.http.impl.cache.CacheConfig; import org.apache.hc.client5.http.impl.cache.CacheConfig;
import org.apache.hc.client5.http.impl.cache.CachingHttpAsyncClients; 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 { CachingHttpAsyncClientCompatibilityTest(final HttpVersion protocolVersion, final HttpHost target) throws Exception {
this.protocolVersion = protocolVersion; this.protocolVersion = protocolVersion;
this.target = target; this.target = target;
final SSLContext sslContext = SSLContexts.custom()
.loadTrustMaterial(getClass().getResource("/test-ca.keystore"), "nopassword".toCharArray()).build();
this.connManager = PoolingAsyncClientConnectionManagerBuilder.create() 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(); .build();
this.client = CachingHttpAsyncClients.custom() this.client = CachingHttpAsyncClients.custom()
.setCacheConfig(CacheConfig.custom() .setCacheConfig(CacheConfig.custom()
.setMaxObjectSize(20480) .setMaxObjectSize(20480)
.build()) .build())
.setResourceFactory(HeapResourceFactory.INSTANCE) .setResourceFactory(HeapResourceFactory.INSTANCE)
.setVersionPolicy(this.protocolVersion == HttpVersion.HTTP_2 ? HttpVersionPolicy.FORCE_HTTP_2 : HttpVersionPolicy.FORCE_HTTP_1)
.setConnectionManager(this.connManager) .setConnectionManager(this.connManager)
.build(); .build();
} }

View File

@ -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.Credentials;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
import org.apache.hc.client5.http.config.RequestConfig; 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.CloseableHttpAsyncClient;
import org.apache.hc.client5.http.impl.async.HttpAsyncClients; import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider; 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(); .loadTrustMaterial(getClass().getResource("/test-ca.keystore"), "nopassword".toCharArray()).build();
this.connManager = PoolingAsyncClientConnectionManagerBuilder.create() this.connManager = PoolingAsyncClientConnectionManagerBuilder.create()
.setTlsStrategy(new DefaultClientTlsStrategy(sslContext)) .setTlsStrategy(new DefaultClientTlsStrategy(sslContext))
.setDefaultTlsConfig(TlsConfig.custom()
.setVersionPolicy(versionPolicy)
.build())
.build(); .build();
this.client = HttpAsyncClients.custom() this.client = HttpAsyncClients.custom()
.setVersionPolicy(this.versionPolicy)
.setConnectionManager(this.connManager) .setConnectionManager(this.connManager)
.setProxy(this.proxy) .setProxy(this.proxy)
.setDefaultRequestConfig(requestConfig) .setDefaultRequestConfig(requestConfig)

View File

@ -82,7 +82,7 @@ public class TestConnectionManagement extends LocalServerTestBase {
final LeaseRequest leaseRequest1 = this.connManager.lease("id1", route,null); final LeaseRequest leaseRequest1 = this.connManager.lease("id1", route,null);
final ConnectionEndpoint endpoint1 = leaseRequest1.get(Timeout.ZERO_MILLISECONDS); 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( final HttpProcessor httpProcessor = new DefaultHttpProcessor(
new RequestTargetHost(), new RequestContent(), new RequestConnControl()); new RequestTargetHost(), new RequestContent(), new RequestConnControl());
@ -104,7 +104,7 @@ public class TestConnectionManagement extends LocalServerTestBase {
final ConnectionEndpoint endpoint2 = leaseRequest3.get(Timeout.ZERO_MILLISECONDS); final ConnectionEndpoint endpoint2 = leaseRequest3.get(Timeout.ZERO_MILLISECONDS);
Assert.assertFalse(endpoint2.isConnected()); 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)) { try (final ClassicHttpResponse response2 = endpoint2.execute("id2", request, exec, context)) {
Assert.assertEquals(HttpStatus.SC_OK, response2.getCode()); 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 LeaseRequest leaseRequest1 = this.connManager.lease("id1", route,null);
final ConnectionEndpoint endpoint1 = leaseRequest1.get(Timeout.ZERO_MILLISECONDS); 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( final HttpProcessor httpProcessor = new DefaultHttpProcessor(
new RequestTargetHost(), new RequestContent(), new RequestConnControl()); new RequestTargetHost(), new RequestContent(), new RequestConnControl());
@ -168,7 +168,7 @@ public class TestConnectionManagement extends LocalServerTestBase {
final ConnectionEndpoint endpoint2 = leaseRequest3.get(Timeout.ZERO_MILLISECONDS); final ConnectionEndpoint endpoint2 = leaseRequest3.get(Timeout.ZERO_MILLISECONDS);
Assert.assertFalse(endpoint2.isConnected()); 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)) { try (final ClassicHttpResponse response2 = endpoint2.execute("id2", request, exec, context)) {
Assert.assertEquals(HttpStatus.SC_OK, response2.getCode()); Assert.assertEquals(HttpStatus.SC_OK, response2.getCode());
@ -193,7 +193,7 @@ public class TestConnectionManagement extends LocalServerTestBase {
Assert.assertFalse(endpoint4.isConnected()); Assert.assertFalse(endpoint4.isConnected());
// repeat the communication, no need to prepare the request again // 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)) { try (final ClassicHttpResponse response4 = endpoint4.execute("id4", request, exec, context)) {
Assert.assertEquals(HttpStatus.SC_OK, response4.getCode()); 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 LeaseRequest leaseRequest1 = this.connManager.lease("id1", route,null);
final ConnectionEndpoint endpoint1 = leaseRequest1.get(Timeout.ZERO_MILLISECONDS); 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.getTotalStats().getLeased());
Assert.assertEquals(1, this.connManager.getStats(route).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 LeaseRequest leaseRequest1 = this.connManager.lease("id1", route,null);
final ConnectionEndpoint endpoint1 = leaseRequest1.get(Timeout.ZERO_MILLISECONDS); 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.getTotalStats().getLeased());
Assert.assertEquals(1, this.connManager.getStats(route).getLeased()); Assert.assertEquals(1, this.connManager.getStats(route).getLeased());

View File

@ -126,7 +126,6 @@ public class ConnectionConfig implements Cloneable {
this.connectTimeout = DEFAULT_CONNECT_TIMEOUT; this.connectTimeout = DEFAULT_CONNECT_TIMEOUT;
} }
/** /**
* @see #setSocketTimeout(Timeout) * @see #setSocketTimeout(Timeout)
*/ */
@ -138,7 +137,7 @@ public class ConnectionConfig implements Cloneable {
/** /**
* Determines the default socket timeout value for I/O operations. * Determines the default socket timeout value for I/O operations.
* <p> * <p>
* Default: {@code null} * Default: {@code null} (undefined)
* </p> * </p>
* *
* @return the default socket timeout value for I/O operations. * @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. * 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> * <p>
* A timeout value of zero is interpreted as an infinite timeout. * A timeout value of zero is interpreted as an infinite timeout.
* </p> * </p>
@ -177,7 +174,7 @@ public class ConnectionConfig implements Cloneable {
* be re-validated prior to being leased to the consumer. Negative values passed * be re-validated prior to being leased to the consumer. Negative values passed
* to this method disable connection validation. * to this method disable connection validation.
* <p> * <p>
* Default: {@code null} * Default: {@code null} (undefined)
* </p> * </p>
*/ */
public Builder setValidateAfterInactivity(final TimeValue validateAfterInactivity) { public Builder setValidateAfterInactivity(final TimeValue validateAfterInactivity) {

View File

@ -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);
}
}
}

View File

@ -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.CredentialsProvider;
import org.apache.hc.client5.http.auth.StandardAuthScheme; import org.apache.hc.client5.http.auth.StandardAuthScheme;
import org.apache.hc.client5.http.config.RequestConfig; 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.BasicCookieStore;
import org.apache.hc.client5.http.cookie.CookieSpecFactory; import org.apache.hc.client5.http.cookie.CookieSpecFactory;
import org.apache.hc.client5.http.cookie.CookieStore; 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 AsyncClientConnectionManager connManager;
private boolean connManagerShared; private boolean connManagerShared;
private IOReactorConfig ioReactorConfig; private IOReactorConfig ioReactorConfig;
@ -254,9 +259,12 @@ public class HttpAsyncClientBuilder {
/** /**
* Sets HTTP protocol version policy. * Sets HTTP protocol version policy.
*
* @deprecated Use {@link TlsConfig} and connection nanager methods
*/ */
@Deprecated
public final HttpAsyncClientBuilder setVersionPolicy(final HttpVersionPolicy versionPolicy) { public final HttpAsyncClientBuilder setVersionPolicy(final HttpVersionPolicy versionPolicy) {
this.versionPolicy = versionPolicy; this.tlsConfig = versionPolicy != null ? TlsConfig.custom().setVersionPolicy(versionPolicy).build() : null;
return this; return this;
} }
@ -903,7 +911,6 @@ public class HttpAsyncClientBuilder {
final IOEventHandlerFactory ioEventHandlerFactory = new HttpAsyncClientEventHandlerFactory( final IOEventHandlerFactory ioEventHandlerFactory = new HttpAsyncClientEventHandlerFactory(
new DefaultHttpProcessor(new H2RequestContent(), new H2RequestTargetHost(), new H2RequestConnControl()), new DefaultHttpProcessor(new H2RequestContent(), new H2RequestTargetHost(), new H2RequestConnControl()),
(request, context) -> pushConsumerRegistry.get(request), (request, context) -> pushConsumerRegistry.get(request),
versionPolicy != null ? versionPolicy : HttpVersionPolicy.NEGOTIATE,
h2Config != null ? h2Config : H2Config.DEFAULT, h2Config != null ? h2Config : H2Config.DEFAULT,
h1Config != null ? h1Config : Http1Config.DEFAULT, h1Config != null ? h1Config : Http1Config.DEFAULT,
charCodingConfig != null ? charCodingConfig : CharCodingConfig.DEFAULT, charCodingConfig != null ? charCodingConfig : CharCodingConfig.DEFAULT,
@ -986,7 +993,7 @@ public class HttpAsyncClientBuilder {
threadFactory != null ? threadFactory : new DefaultThreadFactory("httpclient-main", true), threadFactory != null ? threadFactory : new DefaultThreadFactory("httpclient-main", true),
connManagerCopy, connManagerCopy,
routePlannerCopy, routePlannerCopy,
versionPolicy != null ? versionPolicy : HttpVersionPolicy.NEGOTIATE, tlsConfig,
cookieSpecRegistryCopy, cookieSpecRegistryCopy,
authSchemeRegistryCopy, authSchemeRegistryCopy,
cookieStoreCopy, cookieStoreCopy,

View File

@ -74,7 +74,6 @@ class HttpAsyncClientEventHandlerFactory implements IOEventHandlerFactory {
private final HttpProcessor httpProcessor; private final HttpProcessor httpProcessor;
private final HandlerFactory<AsyncPushConsumer> exchangeHandlerFactory; private final HandlerFactory<AsyncPushConsumer> exchangeHandlerFactory;
private final HttpVersionPolicy versionPolicy;
private final H2Config h2Config; private final H2Config h2Config;
private final Http1Config h1Config; private final Http1Config h1Config;
private final CharCodingConfig charCodingConfig; private final CharCodingConfig charCodingConfig;
@ -85,14 +84,12 @@ class HttpAsyncClientEventHandlerFactory implements IOEventHandlerFactory {
HttpAsyncClientEventHandlerFactory( HttpAsyncClientEventHandlerFactory(
final HttpProcessor httpProcessor, final HttpProcessor httpProcessor,
final HandlerFactory<AsyncPushConsumer> exchangeHandlerFactory, final HandlerFactory<AsyncPushConsumer> exchangeHandlerFactory,
final HttpVersionPolicy versionPolicy,
final H2Config h2Config, final H2Config h2Config,
final Http1Config h1Config, final Http1Config h1Config,
final CharCodingConfig charCodingConfig, final CharCodingConfig charCodingConfig,
final ConnectionReuseStrategy connectionReuseStrategy) { final ConnectionReuseStrategy connectionReuseStrategy) {
this.httpProcessor = Args.notNull(httpProcessor, "HTTP processor"); this.httpProcessor = Args.notNull(httpProcessor, "HTTP processor");
this.exchangeHandlerFactory = exchangeHandlerFactory; this.exchangeHandlerFactory = exchangeHandlerFactory;
this.versionPolicy = versionPolicy != null ? versionPolicy : HttpVersionPolicy.NEGOTIATE;
this.h2Config = h2Config != null ? h2Config : H2Config.DEFAULT; this.h2Config = h2Config != null ? h2Config : H2Config.DEFAULT;
this.h1Config = h1Config != null ? h1Config : Http1Config.DEFAULT; this.h1Config = h1Config != null ? h1Config : Http1Config.DEFAULT;
this.charCodingConfig = charCodingConfig != null ? charCodingConfig : CharCodingConfig.DEFAULT; this.charCodingConfig = charCodingConfig != null ? charCodingConfig : CharCodingConfig.DEFAULT;
@ -238,7 +235,7 @@ class HttpAsyncClientEventHandlerFactory implements IOEventHandlerFactory {
ioSession, ioSession,
http1StreamHandlerFactory, http1StreamHandlerFactory,
http2StreamHandlerFactory, http2StreamHandlerFactory,
attachment instanceof HttpVersionPolicy ? (HttpVersionPolicy) attachment : versionPolicy); attachment instanceof HttpVersionPolicy ? (HttpVersionPolicy) attachment : null);
} }
final ClientHttp1StreamDuplexerFactory http1StreamHandlerFactory = new ClientHttp1StreamDuplexerFactory( final ClientHttp1StreamDuplexerFactory http1StreamHandlerFactory = new ClientHttp1StreamDuplexerFactory(
httpProcessor, httpProcessor,
@ -258,7 +255,7 @@ class HttpAsyncClientEventHandlerFactory implements IOEventHandlerFactory {
ioSession, ioSession,
http1StreamHandlerFactory, http1StreamHandlerFactory,
http2StreamHandlerFactory, http2StreamHandlerFactory,
attachment instanceof HttpVersionPolicy ? (HttpVersionPolicy) attachment : versionPolicy); attachment instanceof HttpVersionPolicy ? (HttpVersionPolicy) attachment : null);
} }
} }

View File

@ -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.DnsResolver;
import org.apache.hc.client5.http.SchemePortResolver; import org.apache.hc.client5.http.SchemePortResolver;
import org.apache.hc.client5.http.SystemDefaultDnsResolver; 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.DefaultClientConnectionReuseStrategy;
import org.apache.hc.client5.http.impl.DefaultSchemePortResolver; import org.apache.hc.client5.http.impl.DefaultSchemePortResolver;
import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder; import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
@ -122,26 +123,29 @@ public final class HttpAsyncClients {
private static MinimalHttpAsyncClient createMinimalHttpAsyncClientImpl( private static MinimalHttpAsyncClient createMinimalHttpAsyncClientImpl(
final IOEventHandlerFactory eventHandlerFactory, final IOEventHandlerFactory eventHandlerFactory,
final AsyncPushConsumerRegistry pushConsumerRegistry, final AsyncPushConsumerRegistry pushConsumerRegistry,
final HttpVersionPolicy versionPolicy,
final IOReactorConfig ioReactorConfig, final IOReactorConfig ioReactorConfig,
final AsyncClientConnectionManager connmgr, final AsyncClientConnectionManager connmgr,
final SchemePortResolver schemePortResolver) { final SchemePortResolver schemePortResolver,
final TlsConfig tlsConfig) {
return new MinimalHttpAsyncClient( return new MinimalHttpAsyncClient(
eventHandlerFactory, eventHandlerFactory,
pushConsumerRegistry, pushConsumerRegistry,
versionPolicy,
ioReactorConfig, ioReactorConfig,
new DefaultThreadFactory("httpclient-main", true), new DefaultThreadFactory("httpclient-main", true),
new DefaultThreadFactory("httpclient-dispatch", true), new DefaultThreadFactory("httpclient-dispatch", true),
connmgr, connmgr,
schemePortResolver); schemePortResolver,
tlsConfig);
} }
/** /**
* Creates {@link MinimalHttpAsyncClient} instance optimized for * Creates {@link MinimalHttpAsyncClient} instance optimized for
* HTTP/1.1 and HTTP/2 message transport without advanced HTTP protocol * HTTP/1.1 and HTTP/2 message transport without advanced HTTP protocol
* functionality. * functionality.
*
* @deprecated Use {@link #createMinimal(H2Config, Http1Config, IOReactorConfig, AsyncClientConnectionManager)}
*/ */
@Deprecated
public static MinimalHttpAsyncClient createMinimal( public static MinimalHttpAsyncClient createMinimal(
final HttpVersionPolicy versionPolicy, final HttpVersionPolicy versionPolicy,
final H2Config h2Config, final H2Config h2Config,
@ -153,16 +157,60 @@ public final class HttpAsyncClients {
new HttpAsyncClientEventHandlerFactory( new HttpAsyncClientEventHandlerFactory(
createMinimalProtocolProcessor(), createMinimalProtocolProcessor(),
(request, context) -> pushConsumerRegistry.get(request), (request, context) -> pushConsumerRegistry.get(request),
versionPolicy,
h2Config, h2Config,
h1Config, h1Config,
CharCodingConfig.DEFAULT, CharCodingConfig.DEFAULT,
DefaultClientConnectionReuseStrategy.INSTANCE), DefaultClientConnectionReuseStrategy.INSTANCE),
pushConsumerRegistry, pushConsumerRegistry,
versionPolicy,
ioReactorConfig, ioReactorConfig,
connmgr, 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,
final IOReactorConfig ioReactorConfig) {
return createMinimal(versionPolicy, h2Config, h1Config, ioReactorConfig,
PoolingAsyncClientConnectionManagerBuilder.create().build());
} }
/** /**
@ -171,11 +219,10 @@ public final class HttpAsyncClients {
* functionality. * functionality.
*/ */
public static MinimalHttpAsyncClient createMinimal( public static MinimalHttpAsyncClient createMinimal(
final HttpVersionPolicy versionPolicy,
final H2Config h2Config, final H2Config h2Config,
final Http1Config h1Config, final Http1Config h1Config,
final IOReactorConfig ioReactorConfig) { final IOReactorConfig ioReactorConfig) {
return createMinimal(versionPolicy, h2Config, h1Config, ioReactorConfig, return createMinimal(h2Config, h1Config, ioReactorConfig,
PoolingAsyncClientConnectionManagerBuilder.create().build()); PoolingAsyncClientConnectionManagerBuilder.create().build());
} }

View File

@ -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.AuthSchemeFactory;
import org.apache.hc.client5.http.auth.CredentialsProvider; import org.apache.hc.client5.http.auth.CredentialsProvider;
import org.apache.hc.client5.http.config.RequestConfig; 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.CookieSpecFactory;
import org.apache.hc.client5.http.cookie.CookieStore; import org.apache.hc.client5.http.cookie.CookieStore;
import org.apache.hc.client5.http.nio.AsyncClientConnectionManager; 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.config.Lookup;
import org.apache.hc.core5.http.nio.AsyncPushConsumer; import org.apache.hc.core5.http.nio.AsyncPushConsumer;
import org.apache.hc.core5.http.nio.HandlerFactory; import org.apache.hc.core5.http.nio.HandlerFactory;
import org.apache.hc.core5.http2.HttpVersionPolicy;
import org.apache.hc.core5.reactor.DefaultConnectingIOReactor; import org.apache.hc.core5.reactor.DefaultConnectingIOReactor;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -71,7 +71,7 @@ public final class InternalHttpAsyncClient extends InternalAbstractHttpAsyncClie
private static final Logger LOG = LoggerFactory.getLogger(InternalHttpAsyncClient.class); private static final Logger LOG = LoggerFactory.getLogger(InternalHttpAsyncClient.class);
private final AsyncClientConnectionManager manager; private final AsyncClientConnectionManager manager;
private final HttpRoutePlanner routePlanner; private final HttpRoutePlanner routePlanner;
private final HttpVersionPolicy versionPolicy; private final TlsConfig tlsConfig;
InternalHttpAsyncClient( InternalHttpAsyncClient(
final DefaultConnectingIOReactor ioReactor, final DefaultConnectingIOReactor ioReactor,
@ -80,7 +80,7 @@ public final class InternalHttpAsyncClient extends InternalAbstractHttpAsyncClie
final ThreadFactory threadFactory, final ThreadFactory threadFactory,
final AsyncClientConnectionManager manager, final AsyncClientConnectionManager manager,
final HttpRoutePlanner routePlanner, final HttpRoutePlanner routePlanner,
final HttpVersionPolicy versionPolicy, final TlsConfig tlsConfig,
final Lookup<CookieSpecFactory> cookieSpecRegistry, final Lookup<CookieSpecFactory> cookieSpecRegistry,
final Lookup<AuthSchemeFactory> authSchemeRegistry, final Lookup<AuthSchemeFactory> authSchemeRegistry,
final CookieStore cookieStore, final CookieStore cookieStore,
@ -91,12 +91,12 @@ public final class InternalHttpAsyncClient extends InternalAbstractHttpAsyncClie
cookieSpecRegistry, authSchemeRegistry, cookieStore, credentialsProvider, defaultConfig, closeables); cookieSpecRegistry, authSchemeRegistry, cookieStore, credentialsProvider, defaultConfig, closeables);
this.manager = manager; this.manager = manager;
this.routePlanner = routePlanner; this.routePlanner = routePlanner;
this.versionPolicy = versionPolicy; this.tlsConfig = tlsConfig;
} }
@Override @Override
AsyncExecRuntime createAsyncExecRuntime(final HandlerFactory<AsyncPushConsumer> pushHandlerFactory) { AsyncExecRuntime createAsyncExecRuntime(final HandlerFactory<AsyncPushConsumer> pushHandlerFactory) {
return new InternalHttpAsyncExecRuntime(LOG, manager, getConnectionInitiator(), pushHandlerFactory, versionPolicy); return new InternalHttpAsyncExecRuntime(LOG, manager, getConnectionInitiator(), pushHandlerFactory, tlsConfig);
} }
@Override @Override

View File

@ -33,6 +33,7 @@ import java.util.concurrent.atomic.AtomicReference;
import org.apache.hc.client5.http.HttpRoute; import org.apache.hc.client5.http.HttpRoute;
import org.apache.hc.client5.http.async.AsyncExecRuntime; import org.apache.hc.client5.http.async.AsyncExecRuntime;
import org.apache.hc.client5.http.config.RequestConfig; 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.ConnPoolSupport;
import org.apache.hc.client5.http.impl.Operations; import org.apache.hc.client5.http.impl.Operations;
import org.apache.hc.client5.http.nio.AsyncClientConnectionManager; 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.AsyncClientExchangeHandler;
import org.apache.hc.core5.http.nio.AsyncPushConsumer; import org.apache.hc.core5.http.nio.AsyncPushConsumer;
import org.apache.hc.core5.http.nio.HandlerFactory; 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.io.CloseMode;
import org.apache.hc.core5.reactor.ConnectionInitiator; import org.apache.hc.core5.reactor.ConnectionInitiator;
import org.apache.hc.core5.util.TimeValue; import org.apache.hc.core5.util.TimeValue;
@ -57,7 +57,11 @@ class InternalHttpAsyncExecRuntime implements AsyncExecRuntime {
private final AsyncClientConnectionManager manager; private final AsyncClientConnectionManager manager;
private final ConnectionInitiator connectionInitiator; private final ConnectionInitiator connectionInitiator;
private final HandlerFactory<AsyncPushConsumer> pushHandlerFactory; 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 final AtomicReference<AsyncConnectionEndpoint> endpointRef;
private volatile boolean reusable; private volatile boolean reusable;
private volatile Object state; private volatile Object state;
@ -68,14 +72,14 @@ class InternalHttpAsyncExecRuntime implements AsyncExecRuntime {
final AsyncClientConnectionManager manager, final AsyncClientConnectionManager manager,
final ConnectionInitiator connectionInitiator, final ConnectionInitiator connectionInitiator,
final HandlerFactory<AsyncPushConsumer> pushHandlerFactory, final HandlerFactory<AsyncPushConsumer> pushHandlerFactory,
final HttpVersionPolicy versionPolicy) { final TlsConfig tlsConfig) {
super(); super();
this.log = log; this.log = log;
this.manager = manager; this.manager = manager;
this.connectionInitiator = connectionInitiator; this.connectionInitiator = connectionInitiator;
this.pushHandlerFactory = pushHandlerFactory; this.pushHandlerFactory = pushHandlerFactory;
this.versionPolicy = versionPolicy; this.tlsConfig = tlsConfig;
this.endpointRef = new AtomicReference<>(); this.endpointRef = new AtomicReference<>(null);
this.validDuration = TimeValue.NEG_ONE_MILLISECOND; this.validDuration = TimeValue.NEG_ONE_MILLISECOND;
} }
@ -213,7 +217,7 @@ class InternalHttpAsyncExecRuntime implements AsyncExecRuntime {
endpoint, endpoint,
connectionInitiator, connectionInitiator,
connectTimeout, connectTimeout,
versionPolicy, tlsConfig,
context, context,
new CallbackContribution<AsyncConnectionEndpoint>(callback) { new CallbackContribution<AsyncConnectionEndpoint>(callback) {
@ -242,7 +246,7 @@ class InternalHttpAsyncExecRuntime implements AsyncExecRuntime {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("{} upgrading endpoint", ConnPoolSupport.getId(endpoint)); 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 @Override
public void completed(final AsyncConnectionEndpoint endpoint) { public void completed(final AsyncConnectionEndpoint endpoint) {
@ -320,7 +324,7 @@ class InternalHttpAsyncExecRuntime implements AsyncExecRuntime {
@Override @Override
public AsyncExecRuntime fork() { public AsyncExecRuntime fork() {
return new InternalHttpAsyncExecRuntime(log, manager, connectionInitiator, pushHandlerFactory, versionPolicy); return new InternalHttpAsyncExecRuntime(log, manager, connectionInitiator, pushHandlerFactory, tlsConfig);
} }
} }

View File

@ -39,6 +39,7 @@ import org.apache.hc.client5.http.HttpRoute;
import org.apache.hc.client5.http.SchemePortResolver; import org.apache.hc.client5.http.SchemePortResolver;
import org.apache.hc.client5.http.config.Configurable; import org.apache.hc.client5.http.config.Configurable;
import org.apache.hc.client5.http.config.RequestConfig; 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.ConnPoolSupport;
import org.apache.hc.client5.http.impl.DefaultSchemePortResolver; import org.apache.hc.client5.http.impl.DefaultSchemePortResolver;
import org.apache.hc.client5.http.impl.ExecSupport; 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.RequestChannel;
import org.apache.hc.core5.http.nio.command.ShutdownCommand; import org.apache.hc.core5.http.nio.command.ShutdownCommand;
import org.apache.hc.core5.http.protocol.HttpContext; 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.CloseMode;
import org.apache.hc.core5.io.Closer; import org.apache.hc.core5.io.Closer;
import org.apache.hc.core5.reactor.Command; 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 static final Logger LOG = LoggerFactory.getLogger(MinimalHttpAsyncClient.class);
private final AsyncClientConnectionManager manager; private final AsyncClientConnectionManager manager;
private final SchemePortResolver schemePortResolver; private final SchemePortResolver schemePortResolver;
private final HttpVersionPolicy versionPolicy; private final TlsConfig tlsConfig;
MinimalHttpAsyncClient( MinimalHttpAsyncClient(
final IOEventHandlerFactory eventHandlerFactory, final IOEventHandlerFactory eventHandlerFactory,
final AsyncPushConsumerRegistry pushConsumerRegistry, final AsyncPushConsumerRegistry pushConsumerRegistry,
final HttpVersionPolicy versionPolicy,
final IOReactorConfig reactorConfig, final IOReactorConfig reactorConfig,
final ThreadFactory threadFactory, final ThreadFactory threadFactory,
final ThreadFactory workerThreadFactory, final ThreadFactory workerThreadFactory,
final AsyncClientConnectionManager manager, final AsyncClientConnectionManager manager,
final SchemePortResolver schemePortResolver) { final SchemePortResolver schemePortResolver,
final TlsConfig tlsConfig) {
super(new DefaultConnectingIOReactor( super(new DefaultConnectingIOReactor(
eventHandlerFactory, eventHandlerFactory,
reactorConfig, reactorConfig,
@ -124,7 +124,7 @@ public final class MinimalHttpAsyncClient extends AbstractMinimalHttpAsyncClient
threadFactory); threadFactory);
this.manager = manager; this.manager = manager;
this.schemePortResolver = schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE; this.schemePortResolver = schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE;
this.versionPolicy = versionPolicy != null ? versionPolicy : HttpVersionPolicy.NEGOTIATE; this.tlsConfig = tlsConfig;
} }
private Future<AsyncConnectionEndpoint> leaseEndpoint( private Future<AsyncConnectionEndpoint> leaseEndpoint(
@ -153,7 +153,7 @@ public final class MinimalHttpAsyncClient extends AbstractMinimalHttpAsyncClient
connectionEndpoint, connectionEndpoint,
getConnectionInitiator(), getConnectionInitiator(),
connectTimeout, connectTimeout,
versionPolicy, tlsConfig,
clientContext, clientContext,
new FutureCallback<AsyncConnectionEndpoint>() { new FutureCallback<AsyncConnectionEndpoint>() {

View File

@ -39,6 +39,7 @@ import org.apache.hc.client5.http.DnsResolver;
import org.apache.hc.client5.http.HttpRoute; import org.apache.hc.client5.http.HttpRoute;
import org.apache.hc.client5.http.SchemePortResolver; import org.apache.hc.client5.http.SchemePortResolver;
import org.apache.hc.client5.http.config.ConnectionConfig; 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.ConnPoolSupport;
import org.apache.hc.client5.http.impl.ConnectionShutdownException; import org.apache.hc.client5.http.impl.ConnectionShutdownException;
import org.apache.hc.client5.http.io.ConnectionEndpoint; import org.apache.hc.client5.http.io.ConnectionEndpoint;
@ -109,6 +110,7 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
private boolean leased; private boolean leased;
private SocketConfig socketConfig; private SocketConfig socketConfig;
private ConnectionConfig connectionConfig; private ConnectionConfig connectionConfig;
private TlsConfig tlsConfig;
private final AtomicBoolean closed; private final AtomicBoolean closed;
@ -142,6 +144,8 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
this.id = String.format("ep-%010d", COUNT.getAndIncrement()); this.id = String.format("ep-%010d", COUNT.getAndIncrement());
this.expiry = Long.MAX_VALUE; this.expiry = Long.MAX_VALUE;
this.socketConfig = SocketConfig.DEFAULT; this.socketConfig = SocketConfig.DEFAULT;
this.connectionConfig = ConnectionConfig.DEFAULT;
this.tlsConfig = TlsConfig.DEFAULT;
this.closed = new AtomicBoolean(false); this.closed = new AtomicBoolean(false);
this.validateAfterInactivity = TimeValue.ofSeconds(2L); this.validateAfterInactivity = TimeValue.ofSeconds(2L);
} }
@ -203,6 +207,13 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
this.connectionConfig = connectionConfig != null ? connectionConfig : ConnectionConfig.DEFAULT; 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) { public LeaseRequest lease(final String id, final HttpRoute route, final Object state) {
return lease(id, route, Timeout.DISABLED, state); return lease(id, route, Timeout.DISABLED, state);
} }
@ -358,8 +369,7 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
} else { } else {
host = route.getTargetHost(); host = route.getTargetHost();
} }
final ConnectionConfig config = connectionConfig != null ? connectionConfig : ConnectionConfig.DEFAULT; final Timeout connectTimeout = timeout != null ? Timeout.of(timeout.getDuration(), timeout.getTimeUnit()) : connectionConfig.getConnectTimeout();
final TimeValue connectTimeout = timeout != null ? timeout : config.getConnectTimeout();
final ManagedHttpClientConnection connection = internalEndpoint.getConnection(); final ManagedHttpClientConnection connection = internalEndpoint.getConnection();
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("{} connecting endpoint to {} ({})", ConnPoolSupport.getId(endpoint), host, connectTimeout); LOG.debug("{} connecting endpoint to {} ({})", ConnPoolSupport.getId(endpoint), host, connectTimeout);
@ -369,12 +379,13 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
host, host,
route.getLocalSocketAddress(), route.getLocalSocketAddress(),
connectTimeout, connectTimeout,
this.socketConfig, socketConfig,
tlsConfig,
context); context);
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("{} connected {}", ConnPoolSupport.getId(endpoint), ConnPoolSupport.getId(conn)); LOG.debug("{} connected {}", ConnPoolSupport.getId(endpoint), ConnPoolSupport.getId(conn));
} }
final Timeout socketTimeout = config.getSocketTimeout(); final Timeout socketTimeout = connectionConfig.getSocketTimeout();
if (socketTimeout != null) { if (socketTimeout != null) {
connection.setSocketTimeout(socketTimeout); connection.setSocketTimeout(socketTimeout);
} }
@ -387,9 +398,11 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
Args.notNull(endpoint, "Endpoint"); Args.notNull(endpoint, "Endpoint");
Args.notNull(route, "HTTP route"); Args.notNull(route, "HTTP route");
final InternalConnectionEndpoint internalEndpoint = cast(endpoint); final InternalConnectionEndpoint internalEndpoint = cast(endpoint);
final ConnectionConfig config = connectionConfig != null ? connectionConfig : ConnectionConfig.DEFAULT;
this.connectionOperator.upgrade( this.connectionOperator.upgrade(
internalEndpoint.getConnection(), internalEndpoint.getConnection(),
internalEndpoint.getRoute().getTargetHost(), internalEndpoint.getRoute().getTargetHost(),
tlsConfig,
context); context);
} }

View File

@ -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.http.protocol.HttpContext;
import org.apache.hc.core5.util.Args; import org.apache.hc.core5.util.Args;
import org.apache.hc.core5.util.TimeValue; import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -107,6 +108,19 @@ public class DefaultHttpClientConnectionOperator implements HttpClientConnection
final TimeValue connectTimeout, final TimeValue connectTimeout,
final SocketConfig socketConfig, final SocketConfig socketConfig,
final HttpContext context) throws IOException { 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(conn, "Connection");
Args.notNull(host, "Host"); Args.notNull(host, "Host");
Args.notNull(socketConfig, "Socket config"); 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); final int port = this.schemePortResolver.resolve(host);
for (int i = 0; i < remoteAddresses.length; i++) { for (int i = 0; i < remoteAddresses.length; i++) {
final InetAddress address = remoteAddresses[i]; final InetAddress address = remoteAddresses[i];
final boolean last = i == remoteAddresses.length - 1; final boolean last = i == remoteAddresses.length - 1;
Socket sock = sf.createSocket(context); Socket sock = sf.createSocket(context);
sock.setSoTimeout(socketConfig.getSoTimeout().toMillisecondsIntBound()); if (soTimeout != null) {
sock.setSoTimeout(soTimeout.toMillisecondsIntBound());
}
sock.setReuseAddress(socketConfig.isSoReuseAddress()); sock.setReuseAddress(socketConfig.isSoReuseAddress());
sock.setTcpNoDelay(socketConfig.isTcpNoDelay()); sock.setTcpNoDelay(socketConfig.isTcpNoDelay());
sock.setKeepAlive(socketConfig.isSoKeepAlive()); sock.setKeepAlive(socketConfig.isSoKeepAlive());
@ -160,8 +178,9 @@ public class DefaultHttpClientConnectionOperator implements HttpClientConnection
host.getHostName(), host.getPort(), localAddress, remoteAddress, connectTimeout); host.getHostName(), host.getPort(), localAddress, remoteAddress, connectTimeout);
} }
try { try {
sock = sf.connectSocket(connectTimeout, sock, host, remoteAddress, localAddress, context); sock = sf.connectSocket(sock, host, remoteAddress, localAddress, connectTimeout, attachment, context);
conn.bind(sock); conn.bind(sock);
conn.setSocketTimeout(soTimeout);
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("{}:{} connected {}->{} as {}", LOG.debug("{}:{} connected {}->{} as {}",
host.getHostName(), host.getPort(), localAddress, remoteAddress, ConnPoolSupport.getId(conn)); host.getHostName(), host.getPort(), localAddress, remoteAddress, ConnPoolSupport.getId(conn));
@ -189,6 +208,15 @@ public class DefaultHttpClientConnectionOperator implements HttpClientConnection
final ManagedHttpClientConnection conn, final ManagedHttpClientConnection conn,
final HttpHost host, final HttpHost host,
final HttpContext context) throws IOException { 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 HttpClientContext clientContext = HttpClientContext.adapt(context);
final Lookup<ConnectionSocketFactory> registry = getSocketFactoryRegistry(clientContext); final Lookup<ConnectionSocketFactory> registry = getSocketFactoryRegistry(clientContext);
final ConnectionSocketFactory sf = registry.lookup(host.getSchemeName()); final ConnectionSocketFactory sf = registry.lookup(host.getSchemeName());
@ -206,7 +234,7 @@ public class DefaultHttpClientConnectionOperator implements HttpClientConnection
throw new ConnectionClosedException("Connection is closed"); throw new ConnectionClosedException("Connection is closed");
} }
final int port = this.schemePortResolver.resolve(host); 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); conn.bind(sock);
} }

View File

@ -39,6 +39,7 @@ import org.apache.hc.client5.http.DnsResolver;
import org.apache.hc.client5.http.HttpRoute; import org.apache.hc.client5.http.HttpRoute;
import org.apache.hc.client5.http.SchemePortResolver; import org.apache.hc.client5.http.SchemePortResolver;
import org.apache.hc.client5.http.config.ConnectionConfig; 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.ConnPoolSupport;
import org.apache.hc.client5.http.impl.ConnectionShutdownException; import org.apache.hc.client5.http.impl.ConnectionShutdownException;
import org.apache.hc.client5.http.io.ConnectionEndpoint; 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, SocketConfig> socketConfigResolver;
private volatile Resolver<HttpRoute, ConnectionConfig> connectionConfigResolver; private volatile Resolver<HttpRoute, ConnectionConfig> connectionConfigResolver;
private volatile Resolver<HttpHost, TlsConfig> tlsConfigResolver;
public PoolingHttpClientConnectionManager() { public PoolingHttpClientConnectionManager() {
this(RegistryBuilder.<ConnectionSocketFactory>create() this(RegistryBuilder.<ConnectionSocketFactory>create()
@ -241,16 +243,22 @@ public class PoolingHttpClientConnectionManager
throw new IllegalStateException("Unexpected endpoint class: " + endpoint.getClass()); 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) { private ConnectionConfig resolveConnectionConfig(final HttpRoute route) {
final Resolver<HttpRoute, ConnectionConfig> resolver = this.connectionConfigResolver; final Resolver<HttpRoute, ConnectionConfig> resolver = this.connectionConfigResolver;
final ConnectionConfig connectionConfig = resolver != null ? resolver.resolve(route) : null; final ConnectionConfig connectionConfig = resolver != null ? resolver.resolve(route) : null;
return connectionConfig != null ? connectionConfig : ConnectionConfig.DEFAULT; return connectionConfig != null ? connectionConfig : ConnectionConfig.DEFAULT;
} }
private SocketConfig resolveSocketConfig(final HttpRoute route) { private TlsConfig resolveTlsConfig(final HttpHost host) {
final Resolver<HttpRoute, SocketConfig> resolver = this.socketConfigResolver; final Resolver<HttpHost, TlsConfig> resolver = this.tlsConfigResolver;
final SocketConfig socketConfig = resolver != null ? resolver.resolve(route) : null; final TlsConfig tlsConfig = resolver != null ? resolver.resolve(host) : null;
return socketConfig != null ? socketConfig : SocketConfig.DEFAULT; return tlsConfig != null ? tlsConfig : TlsConfig.DEFAULT;
} }
private TimeValue resolveValidateAfterInactivity(final ConnectionConfig connectionConfig) { private TimeValue resolveValidateAfterInactivity(final ConnectionConfig connectionConfig) {
@ -401,15 +409,11 @@ public class PoolingHttpClientConnectionManager
poolEntry.assignConnection(connFactory.createConnection(null)); poolEntry.assignConnection(connFactory.createConnection(null));
} }
final HttpRoute route = poolEntry.getRoute(); final HttpRoute route = poolEntry.getRoute();
final HttpHost host; final HttpHost host = route.getProxyHost() != null ? route.getProxyHost() : route.getTargetHost();
if (route.getProxyHost() != null) {
host = route.getProxyHost();
} else {
host = route.getTargetHost();
}
final SocketConfig socketConfig = resolveSocketConfig(route); final SocketConfig socketConfig = resolveSocketConfig(route);
final ConnectionConfig connectionConfig = resolveConnectionConfig(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()) { if (LOG.isDebugEnabled()) {
LOG.debug("{} connecting endpoint to {} ({})", ConnPoolSupport.getId(endpoint), host, connectTimeout); LOG.debug("{} connecting endpoint to {} ({})", ConnPoolSupport.getId(endpoint), host, connectTimeout);
} }
@ -418,8 +422,9 @@ public class PoolingHttpClientConnectionManager
conn, conn,
host, host,
route.getLocalSocketAddress(), route.getLocalSocketAddress(),
timeout, connectTimeout,
socketConfig, socketConfig,
tlsConfig,
context); context);
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("{} connected {}", ConnPoolSupport.getId(endpoint), ConnPoolSupport.getId(conn)); LOG.debug("{} connected {}", ConnPoolSupport.getId(endpoint), ConnPoolSupport.getId(conn));
@ -436,7 +441,9 @@ public class PoolingHttpClientConnectionManager
final InternalConnectionEndpoint internalEndpoint = cast(endpoint); final InternalConnectionEndpoint internalEndpoint = cast(endpoint);
final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry = internalEndpoint.getValidatedPoolEntry(); final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry = internalEndpoint.getValidatedPoolEntry();
final HttpRoute route = poolEntry.getRoute(); 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 @Override
@ -533,6 +540,24 @@ public class PoolingHttpClientConnectionManager
this.connectionConfigResolver = connectionConfigResolver; this.connectionConfigResolver = connectionConfigResolver;
} }
/**
* 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 Use custom {@link #setConnectionConfigResolver(Resolver)}
*/ */

View File

@ -31,12 +31,14 @@ import org.apache.hc.client5.http.DnsResolver;
import org.apache.hc.client5.http.HttpRoute; import org.apache.hc.client5.http.HttpRoute;
import org.apache.hc.client5.http.SchemePortResolver; import org.apache.hc.client5.http.SchemePortResolver;
import org.apache.hc.client5.http.config.ConnectionConfig; 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.io.ManagedHttpClientConnection;
import org.apache.hc.client5.http.socket.ConnectionSocketFactory; import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory; import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory; import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.core5.function.Resolver; 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.URIScheme;
import org.apache.hc.core5.http.config.RegistryBuilder; import org.apache.hc.core5.http.config.RegistryBuilder;
import org.apache.hc.core5.http.io.HttpConnectionFactory; import org.apache.hc.core5.http.io.HttpConnectionFactory;
@ -81,6 +83,7 @@ public class PoolingHttpClientConnectionManagerBuilder {
private PoolReusePolicy poolReusePolicy; private PoolReusePolicy poolReusePolicy;
private Resolver<HttpRoute, SocketConfig> socketConfigResolver; private Resolver<HttpRoute, SocketConfig> socketConfigResolver;
private Resolver<HttpRoute, ConnectionConfig> connectionConfigResolver; private Resolver<HttpRoute, ConnectionConfig> connectionConfigResolver;
private Resolver<HttpHost, TlsConfig> tlsConfigResolver;
private boolean systemProperties; private boolean systemProperties;
@ -203,6 +206,27 @@ public class PoolingHttpClientConnectionManagerBuilder {
return this; return this;
} }
/**
* 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 * Sets maximum time to live for persistent connections
*/ */
@ -251,6 +275,7 @@ public class PoolingHttpClientConnectionManagerBuilder {
connectionFactory); connectionFactory);
poolingmgr.setSocketConfigResolver(socketConfigResolver); poolingmgr.setSocketConfigResolver(socketConfigResolver);
poolingmgr.setConnectionConfigResolver(connectionConfigResolver); poolingmgr.setConnectionConfigResolver(connectionConfigResolver);
poolingmgr.setTlsConfigResolver(tlsConfigResolver);
if (maxConnTotal > 0) { if (maxConnTotal > 0) {
poolingmgr.setMaxTotal(maxConnTotal); poolingmgr.setMaxTotal(maxConnTotal);
} }

View File

@ -34,6 +34,7 @@ import java.util.concurrent.Future;
import org.apache.hc.client5.http.DnsResolver; import org.apache.hc.client5.http.DnsResolver;
import org.apache.hc.client5.http.SchemePortResolver; 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.impl.DefaultSchemePortResolver;
import org.apache.hc.client5.http.nio.AsyncClientConnectionOperator; import org.apache.hc.client5.http.nio.AsyncClientConnectionOperator;
import org.apache.hc.client5.http.nio.ManagedAsyncClientConnection; 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 HttpHost remoteEndpoint = RoutingSupport.normalize(host, schemePortResolver);
final InetAddress remoteAddress = host.getAddress(); final InetAddress remoteAddress = host.getAddress();
final TlsStrategy tlsStrategy = tlsStrategyLookup != null ? tlsStrategyLookup.lookup(host.getSchemeName()) : null; 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( final Future<IOSession> sessionFuture = sessionRequester.connect(
connectionInitiator, connectionInitiator,
remoteEndpoint, remoteEndpoint,
remoteAddress != null ? new InetSocketAddress(remoteAddress, remoteEndpoint.getPort()) : null, remoteAddress != null ? new InetSocketAddress(remoteAddress, remoteEndpoint.getPort()) : null,
localAddress, localAddress,
connectTimeout, connectTimeout,
attachment, tlsConfig.getHttpVersionPolicy(),
new FutureCallback<IOSession>() { new FutureCallback<IOSession>() {
@Override @Override
@ -95,15 +97,18 @@ final class DefaultAsyncClientConnectionOperator implements AsyncClientConnectio
final DefaultManagedAsyncClientConnection connection = new DefaultManagedAsyncClientConnection(session); final DefaultManagedAsyncClientConnection connection = new DefaultManagedAsyncClientConnection(session);
if (tlsStrategy != null && URIScheme.HTTPS.same(host.getSchemeName())) { if (tlsStrategy != null && URIScheme.HTTPS.same(host.getSchemeName())) {
try { try {
final Timeout socketTimeout = connection.getSocketTimeout();
final Timeout handshakeTimeout = tlsConfig.getHandshakeTimeout();
tlsStrategy.upgrade( tlsStrategy.upgrade(
connection, connection,
host, host,
attachment, attachment,
null, handshakeTimeout != null ? handshakeTimeout : connectTimeout,
new FutureContribution<TransportSecurityLayer>(future) { new FutureContribution<TransportSecurityLayer>(future) {
@Override @Override
public void completed(final TransportSecurityLayer transportSecurityLayer) { public void completed(final TransportSecurityLayer transportSecurityLayer) {
connection.setSocketTimeout(socketTimeout);
future.completed(connection); future.completed(connection);
} }

View File

@ -41,6 +41,7 @@ import org.apache.hc.client5.http.DnsResolver;
import org.apache.hc.client5.http.HttpRoute; import org.apache.hc.client5.http.HttpRoute;
import org.apache.hc.client5.http.SchemePortResolver; import org.apache.hc.client5.http.SchemePortResolver;
import org.apache.hc.client5.http.config.ConnectionConfig; 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.ConnPoolSupport;
import org.apache.hc.client5.http.impl.ConnectionShutdownException; import org.apache.hc.client5.http.impl.ConnectionShutdownException;
import org.apache.hc.client5.http.nio.AsyncClientConnectionManager; import org.apache.hc.client5.http.nio.AsyncClientConnectionManager;
@ -123,6 +124,7 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
private final AtomicBoolean closed; private final AtomicBoolean closed;
private volatile Resolver<HttpRoute, ConnectionConfig> connectionConfigResolver; private volatile Resolver<HttpRoute, ConnectionConfig> connectionConfigResolver;
private volatile Resolver<HttpHost, TlsConfig> tlsConfigResolver;
public PoolingAsyncClientConnectionManager() { public PoolingAsyncClientConnectionManager() {
this(RegistryBuilder.<TlsStrategy>create() this(RegistryBuilder.<TlsStrategy>create()
@ -227,6 +229,15 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
return connectionConfig != null ? connectionConfig : ConnectionConfig.DEFAULT; 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 @Override
public Future<AsyncConnectionEndpoint> lease( public Future<AsyncConnectionEndpoint> lease(
final String id, final String id,
@ -400,6 +411,7 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
} }
final InetSocketAddress localAddress = route.getLocalSocketAddress(); final InetSocketAddress localAddress = route.getLocalSocketAddress();
final ConnectionConfig connectionConfig = resolveConnectionConfig(route); final ConnectionConfig connectionConfig = resolveConnectionConfig(route);
final TlsConfig tlsConfig = resolveTlsConfig(host, attachment);
final Timeout connectTimeout = timeout != null ? timeout : connectionConfig.getConnectTimeout(); final Timeout connectTimeout = timeout != null ? timeout : connectionConfig.getConnectTimeout();
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
@ -410,7 +422,9 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
host, host,
localAddress, localAddress,
connectTimeout, connectTimeout,
route.isTunnelled() ? HttpVersionPolicy.FORCE_HTTP_1 : attachment, route.isTunnelled() ? TlsConfig.copy(tlsConfig)
.setVersionPolicy(HttpVersionPolicy.FORCE_HTTP_1)
.build() : tlsConfig,
new FutureCallback<ManagedAsyncClientConnection>() { new FutureCallback<ManagedAsyncClientConnection>() {
@Override @Override
@ -455,10 +469,12 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
final InternalConnectionEndpoint internalEndpoint = cast(endpoint); final InternalConnectionEndpoint internalEndpoint = cast(endpoint);
final PoolEntry<HttpRoute, ManagedAsyncClientConnection> poolEntry = internalEndpoint.getValidatedPoolEntry(); final PoolEntry<HttpRoute, ManagedAsyncClientConnection> poolEntry = internalEndpoint.getValidatedPoolEntry();
final HttpRoute route = poolEntry.getRoute(); final HttpRoute route = poolEntry.getRoute();
final HttpHost host = route.getProxyHost() != null ? route.getProxyHost() : route.getTargetHost();
final TlsConfig tlsConfig = resolveTlsConfig(host, attachment);
connectionOperator.upgrade( connectionOperator.upgrade(
poolEntry.getConnection(), poolEntry.getConnection(),
route.getTargetHost(), route.getTargetHost(),
attachment, attachment != null ? attachment : tlsConfig,
new CallbackContribution<ManagedAsyncClientConnection>(callback) { new CallbackContribution<ManagedAsyncClientConnection>(callback) {
@Override @Override
@ -566,6 +582,24 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
this.connectionConfigResolver = connectionConfigResolver; this.connectionConfigResolver = connectionConfigResolver;
} }
/**
* 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 Use custom {@link #setConnectionConfigResolver(Resolver)}
*/ */

View File

@ -31,9 +31,11 @@ import org.apache.hc.client5.http.DnsResolver;
import org.apache.hc.client5.http.HttpRoute; import org.apache.hc.client5.http.HttpRoute;
import org.apache.hc.client5.http.SchemePortResolver; import org.apache.hc.client5.http.SchemePortResolver;
import org.apache.hc.client5.http.config.ConnectionConfig; 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.ConscryptClientTlsStrategy;
import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy; import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
import org.apache.hc.core5.function.Resolver; 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.config.RegistryBuilder;
import org.apache.hc.core5.http.io.SocketConfig; import org.apache.hc.core5.http.io.SocketConfig;
import org.apache.hc.core5.http.nio.ssl.TlsStrategy; import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
@ -83,6 +85,7 @@ public class PoolingAsyncClientConnectionManagerBuilder {
private Resolver<HttpRoute, SocketConfig> socketConfigResolver; private Resolver<HttpRoute, SocketConfig> socketConfigResolver;
private Resolver<HttpRoute, ConnectionConfig> connectionConfigResolver; private Resolver<HttpRoute, ConnectionConfig> connectionConfigResolver;
private Resolver<HttpHost, TlsConfig> tlsConfigResolver;
private TimeValue timeToLive; private TimeValue timeToLive;
public static PoolingAsyncClientConnectionManagerBuilder create() { public static PoolingAsyncClientConnectionManagerBuilder create() {
@ -171,6 +174,26 @@ public class PoolingAsyncClientConnectionManagerBuilder {
return this; 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 * Sets maximum time to live for persistent connections
@ -232,6 +255,7 @@ public class PoolingAsyncClientConnectionManagerBuilder {
schemePortResolver, schemePortResolver,
dnsResolver); dnsResolver);
poolingmgr.setConnectionConfigResolver(connectionConfigResolver); poolingmgr.setConnectionConfigResolver(connectionConfigResolver);
poolingmgr.setTlsConfigResolver(tlsConfigResolver);
if (maxConnTotal > 0) { if (maxConnTotal > 0) {
poolingmgr.setMaxTotal(maxConnTotal); poolingmgr.setMaxTotal(maxConnTotal);
} }

View File

@ -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.io.SocketConfig;
import org.apache.hc.core5.http.protocol.HttpContext; import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.util.TimeValue; import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;
/** /**
* Connection operator that performs connection connect and upgrade operations. * Connection operator that performs connection connect and upgrade operations.
@ -65,6 +66,30 @@ public interface HttpClientConnectionOperator {
SocketConfig socketConfig, SocketConfig socketConfig,
HttpContext context) throws IOException; 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 * Upgrades transport security of the given managed connection
* by using the TLS security protocol. * by using the TLS security protocol.
@ -78,4 +103,23 @@ public interface HttpClientConnectionOperator {
HttpHost host, HttpHost host,
HttpContext context) throws IOException; 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);
}
} }

View File

@ -67,7 +67,6 @@ public interface AsyncClientConnectionOperator {
Object attachment, Object attachment,
FutureCallback<ManagedAsyncClientConnection> callback); FutureCallback<ManagedAsyncClientConnection> callback);
/** /**
* Upgrades transport security of the given managed connection * Upgrades transport security of the given managed connection
* by using the TLS security protocol. * by using the TLS security protocol.

View File

@ -36,6 +36,7 @@ import org.apache.hc.core5.annotation.ThreadingBehavior;
import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.protocol.HttpContext; import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.util.TimeValue; import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;
/** /**
* A factory for creating and connecting connection sockets. * A factory for creating and connecting connection sockets.
@ -81,4 +82,35 @@ public interface ConnectionSocketFactory {
InetSocketAddress localAddress, InetSocketAddress localAddress,
HttpContext context) throws IOException; 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);
}
} }

View File

@ -62,4 +62,30 @@ public interface LayeredConnectionSocketFactory extends ConnectionSocketFactory
int port, int port,
HttpContext context) throws IOException; 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);
}
} }

View File

@ -38,6 +38,7 @@ import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSession; 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.Contract;
import org.apache.hc.core5.annotation.ThreadingBehavior; import org.apache.hc.core5.annotation.ThreadingBehavior;
import org.apache.hc.core5.concurrent.FutureCallback; import org.apache.hc.core5.concurrent.FutureCallback;
@ -109,17 +110,23 @@ abstract class AbstractClientTlsStrategy implements TlsStrategy {
final FutureCallback<TransportSecurityLayer> callback) { final FutureCallback<TransportSecurityLayer> callback) {
tlsSession.startTls(sslContext, endpoint, sslBufferManagement, (e, sslEngine) -> { tlsSession.startTls(sslContext, endpoint, sslBufferManagement, (e, sslEngine) -> {
final HttpVersionPolicy versionPolicy = attachment instanceof HttpVersionPolicy ? final TlsConfig tlsConfig = attachment instanceof TlsConfig ? (TlsConfig) attachment : TlsConfig.DEFAULT;
(HttpVersionPolicy) attachment : HttpVersionPolicy.NEGOTIATE; final HttpVersionPolicy versionPolicy = tlsConfig.getHttpVersionPolicy();
final SSLParameters sslParameters = sslEngine.getSSLParameters(); final SSLParameters sslParameters = sslEngine.getSSLParameters();
final String[] supportedProtocols = tlsConfig.getSupportedProtocols();
if (supportedProtocols != null) { if (supportedProtocols != null) {
sslParameters.setProtocols(supportedProtocols); sslParameters.setProtocols(supportedProtocols);
} else if (this.supportedProtocols != null) {
sslParameters.setProtocols(this.supportedProtocols);
} else if (versionPolicy != HttpVersionPolicy.FORCE_HTTP_1) { } else if (versionPolicy != HttpVersionPolicy.FORCE_HTTP_1) {
sslParameters.setProtocols(TLS.excludeWeak(sslParameters.getProtocols())); sslParameters.setProtocols(TLS.excludeWeak(sslParameters.getProtocols()));
} }
final String[] supportedCipherSuites = tlsConfig.getSupportedCipherSuites();
if (supportedCipherSuites != null) { if (supportedCipherSuites != null) {
sslParameters.setCipherSuites(supportedCipherSuites); sslParameters.setCipherSuites(supportedCipherSuites);
} else if (this.supportedCipherSuites != null) {
sslParameters.setCipherSuites(this.supportedCipherSuites);
} else if (versionPolicy == HttpVersionPolicy.FORCE_HTTP_2) { } else if (versionPolicy == HttpVersionPolicy.FORCE_HTTP_2) {
sslParameters.setCipherSuites(TlsCiphers.excludeH2Blacklisted(sslParameters.getCipherSuites())); sslParameters.setCipherSuites(TlsCiphers.excludeH2Blacklisted(sslParameters.getCipherSuites()));
} }
@ -135,6 +142,7 @@ abstract class AbstractClientTlsStrategy implements TlsStrategy {
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("Enabled protocols: {}", Arrays.asList(sslEngine.getEnabledProtocols())); LOG.debug("Enabled protocols: {}", Arrays.asList(sslEngine.getEnabledProtocols()));
LOG.debug("Enabled cipher suites:{}", Arrays.asList(sslEngine.getEnabledCipherSuites())); LOG.debug("Enabled cipher suites:{}", Arrays.asList(sslEngine.getEnabledCipherSuites()));
LOG.debug("Starting handshake ({})", handshakeTimeout);
} }
}, (e, sslEngine) -> { }, (e, sslEngine) -> {
verifySession(endpoint.getHostName(), sslEngine.getSession()); verifySession(endpoint.getHostName(), sslEngine.getSession());

View File

@ -47,6 +47,7 @@ import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket; 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.client5.http.socket.LayeredConnectionSocketFactory;
import org.apache.hc.core5.annotation.Contract; import org.apache.hc.core5.annotation.Contract;
import org.apache.hc.core5.annotation.ThreadingBehavior; 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.Args;
import org.apache.hc.core5.util.Asserts; import org.apache.hc.core5.util.Asserts;
import org.apache.hc.core5.util.TimeValue; import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -200,6 +202,19 @@ public class SSLConnectionSocketFactory implements LayeredConnectionSocketFactor
final InetSocketAddress remoteAddress, final InetSocketAddress remoteAddress,
final InetSocketAddress localAddress, final InetSocketAddress localAddress,
final HttpContext context) throws IOException { 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(host, "HTTP host");
Args.notNull(remoteAddress, "Remote address"); Args.notNull(remoteAddress, "Remote address");
final Socket sock = socket != null ? socket : createSocket(context); final Socket sock = socket != null ? socket : createSocket(context);
@ -214,7 +229,7 @@ public class SSLConnectionSocketFactory implements LayeredConnectionSocketFactor
// only to this library // only to this library
try { try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> { AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
sock.connect(remoteAddress, connectTimeout != null ? connectTimeout.toMillisecondsIntBound() : 0); sock.connect(remoteAddress, Timeout.defaultsToDisabled(connectTimeout).toMillisecondsIntBound());
return null; return null;
}); });
} catch (final PrivilegedActionException e) { } catch (final PrivilegedActionException e) {
@ -230,12 +245,10 @@ public class SSLConnectionSocketFactory implements LayeredConnectionSocketFactor
// Setup SSL layering if necessary // Setup SSL layering if necessary
if (sock instanceof SSLSocket) { if (sock instanceof SSLSocket) {
final SSLSocket sslsock = (SSLSocket) sock; final SSLSocket sslsock = (SSLSocket) sock;
LOG.debug("Starting handshake"); executeHandshake(sslsock, host.getHostName(), attachment);
sslsock.startHandshake();
verifyHostname(sslsock, host.getHostName());
return sock; return sock;
} }
return createLayeredSocket(sock, host.getHostName(), remoteAddress.getPort(), context); return createLayeredSocket(sock, host.getHostName(), remoteAddress.getPort(), attachment, context);
} }
@Override @Override
@ -244,11 +257,27 @@ public class SSLConnectionSocketFactory implements LayeredConnectionSocketFactor
final String target, final String target,
final int port, final int port,
final HttpContext context) throws IOException { final HttpContext context) throws IOException {
return createLayeredSocket(socket, target, port, context);
}
@Override
public Socket createLayeredSocket(
final Socket socket,
final String target,
final int port,
final Object attachment,
final HttpContext context) throws IOException {
final SSLSocket sslsock = (SSLSocket) this.socketFactory.createSocket( final SSLSocket sslsock = (SSLSocket) this.socketFactory.createSocket(
socket, socket,
target, target,
port, port,
true); 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) { if (supportedProtocols != null) {
sslsock.setEnabledProtocols(supportedProtocols); sslsock.setEnabledProtocols(supportedProtocols);
} else { } else {
@ -259,17 +288,20 @@ public class SSLConnectionSocketFactory implements LayeredConnectionSocketFactor
} else { } else {
sslsock.setEnabledCipherSuites(TlsCiphers.excludeWeak(sslsock.getEnabledCipherSuites())); sslsock.setEnabledCipherSuites(TlsCiphers.excludeWeak(sslsock.getEnabledCipherSuites()));
} }
final Timeout handshakeTimeout = tlsConfig.getHandshakeTimeout();
if (handshakeTimeout != null) {
sslsock.setSoTimeout(handshakeTimeout.toMillisecondsIntBound());
}
prepareSocket(sslsock);
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("Enabled protocols: {}", (Object) sslsock.getEnabledProtocols()); LOG.debug("Enabled protocols: {}", (Object) sslsock.getEnabledProtocols());
LOG.debug("Enabled cipher suites: {}", (Object) sslsock.getEnabledCipherSuites()); LOG.debug("Enabled cipher suites: {}", (Object) sslsock.getEnabledCipherSuites());
LOG.debug("Starting handshake ({})", handshakeTimeout);
} }
prepareSocket(sslsock);
LOG.debug("Starting handshake");
sslsock.startHandshake(); sslsock.startHandshake();
verifyHostname(sslsock, target); verifyHostname(sslsock, target);
return sslsock;
} }
private void verifyHostname(final SSLSocket sslsock, final String hostname) throws IOException { private void verifyHostname(final SSLSocket sslsock, final String hostname) throws IOException {

View File

@ -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.nio.support.BasicResponseConsumer;
import org.apache.hc.core5.http.protocol.HttpContext; import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.http.support.BasicRequestBuilder; 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.http2.config.H2Config;
import org.apache.hc.core5.io.CloseMode; import org.apache.hc.core5.io.CloseMode;
import org.apache.hc.core5.reactor.IOReactorConfig; 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. * 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 { public static void main(final String[] args) throws Exception {
final IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
.setSoTimeout(Timeout.ofSeconds(5))
.build();
final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal( final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal(
HttpVersionPolicy.NEGOTIATE,
H2Config.DEFAULT, H2Config.DEFAULT,
Http1Config.DEFAULT, Http1Config.DEFAULT,
ioReactorConfig); IOReactorConfig.DEFAULT);
client.start(); client.start();

View File

@ -32,13 +32,16 @@ import java.util.List;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; 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.HttpAsyncClients;
import org.apache.hc.client5.http.impl.async.MinimalHttpAsyncClient; 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.ContentType;
import org.apache.hc.core5.http.EntityDetails; import org.apache.hc.core5.http.EntityDetails;
import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.HttpException; import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.HttpResponse; 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.BasicHttpRequest;
import org.apache.hc.core5.http.message.StatusLine; import org.apache.hc.core5.http.message.StatusLine;
import org.apache.hc.core5.http.nio.AsyncClientExchangeHandler; 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.http2.config.H2Config;
import org.apache.hc.core5.io.CloseMode; import org.apache.hc.core5.io.CloseMode;
import org.apache.hc.core5.reactor.IOReactorConfig; 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. * 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 { public static void main(final String[] args) throws Exception {
final IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
.setSoTimeout(Timeout.ofSeconds(5))
.build();
final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal( 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(); client.start();

View File

@ -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.SimpleRequestBuilder;
import org.apache.hc.client5.http.async.methods.SimpleRequestProducer; import org.apache.hc.client5.http.async.methods.SimpleRequestProducer;
import org.apache.hc.client5.http.async.methods.SimpleResponseConsumer; 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.HttpAsyncClients;
import org.apache.hc.client5.http.impl.async.MinimalHttpAsyncClient; 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.concurrent.FutureCallback;
import org.apache.hc.core5.http.HttpHost; 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.message.StatusLine;
import org.apache.hc.core5.http.nio.AsyncClientEndpoint; import org.apache.hc.core5.http.nio.AsyncClientEndpoint;
import org.apache.hc.core5.http2.HttpVersionPolicy; import org.apache.hc.core5.http2.HttpVersionPolicy;
import org.apache.hc.core5.http2.config.H2Config; import org.apache.hc.core5.http2.config.H2Config;
import org.apache.hc.core5.io.CloseMode; import org.apache.hc.core5.io.CloseMode;
import org.apache.hc.core5.reactor.IOReactorConfig; import org.apache.hc.core5.reactor.IOReactorConfig;
import org.apache.hc.core5.util.Timeout;
/** /**
* This example demonstrates concurrent (multiplexed) execution of multiple * This example demonstrates concurrent (multiplexed) execution of multiple
@ -55,12 +57,15 @@ public class AsyncClientH2Multiplexing {
public static void main(final String[] args) throws Exception { public static void main(final String[] args) throws Exception {
final IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
.setSoTimeout(Timeout.ofSeconds(5))
.build();
final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal( 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(); client.start();

View File

@ -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.AbstractBinPushConsumer;
import org.apache.hc.client5.http.async.methods.AbstractCharResponseConsumer; 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.CloseableHttpAsyncClient;
import org.apache.hc.client5.http.impl.async.HttpAsyncClients; 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.ContentType;
import org.apache.hc.core5.http.HttpException; import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.HttpRequest; 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.HttpVersionPolicy;
import org.apache.hc.core5.http2.config.H2Config; import org.apache.hc.core5.http2.config.H2Config;
import org.apache.hc.core5.io.CloseMode; 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. * 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 { 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() final CloseableHttpAsyncClient client = HttpAsyncClients.custom()
.setIOReactorConfig(ioReactorConfig) .setH2Config(H2Config.custom()
.setPushEnabled(true)
.build())
.setConnectionManager(PoolingAsyncClientConnectionManagerBuilder.create()
.setDefaultTlsConfig(TlsConfig.custom()
.setVersionPolicy(HttpVersionPolicy.FORCE_HTTP_2) .setVersionPolicy(HttpVersionPolicy.FORCE_HTTP_2)
.setH2Config(h2Config) .build())
.build())
.build(); .build();
client.start(); client.start();

View File

@ -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.SimpleRequestBuilder;
import org.apache.hc.client5.http.async.methods.SimpleRequestProducer; import org.apache.hc.client5.http.async.methods.SimpleRequestProducer;
import org.apache.hc.client5.http.async.methods.SimpleResponseConsumer; 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.HttpAsyncClients;
import org.apache.hc.client5.http.impl.async.MinimalHttpAsyncClient; 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.concurrent.FutureCallback;
import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.config.Http1Config; import org.apache.hc.core5.http.config.Http1Config;
import org.apache.hc.core5.http.message.StatusLine; import org.apache.hc.core5.http.message.StatusLine;
import org.apache.hc.core5.http.nio.AsyncClientEndpoint; import org.apache.hc.core5.http.nio.AsyncClientEndpoint;
import org.apache.hc.core5.http2.HttpVersionPolicy; 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.io.CloseMode;
import org.apache.hc.core5.reactor.IOReactorConfig; 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. * 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 { public static void main(final String[] args) throws Exception {
final IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
.setSoTimeout(Timeout.ofSeconds(5))
.build();
final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal( 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(); client.start();

View File

@ -45,7 +45,6 @@ import org.apache.hc.core5.concurrent.FutureCallback;
import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.message.StatusLine; import org.apache.hc.core5.http.message.StatusLine;
import org.apache.hc.core5.http.nio.ssl.TlsStrategy; import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
import org.apache.hc.core5.http2.HttpVersionPolicy;
import org.apache.hc.core5.io.CloseMode; import org.apache.hc.core5.io.CloseMode;
/** /**
@ -74,7 +73,6 @@ public class AsyncClientTlsAlpn {
.setTlsStrategy(tlsStrategy) .setTlsStrategy(tlsStrategy)
.build(); .build();
try (final CloseableHttpAsyncClient client = HttpAsyncClients.custom() try (final CloseableHttpAsyncClient client = HttpAsyncClients.custom()
.setVersionPolicy(HttpVersionPolicy.NEGOTIATE)
.setConnectionManager(cm) .setConnectionManager(cm)
.build()) { .build()) {

View File

@ -40,13 +40,11 @@ import org.apache.hc.core5.http.HttpResponse;
import org.apache.hc.core5.http.Message; import org.apache.hc.core5.http.Message;
import org.apache.hc.core5.http.config.Http1Config; import org.apache.hc.core5.http.config.Http1Config;
import org.apache.hc.core5.http.nio.support.BasicRequestProducer; 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.http2.config.H2Config;
import org.apache.hc.core5.io.CloseMode; import org.apache.hc.core5.io.CloseMode;
import org.apache.hc.core5.reactive.ReactiveEntityProducer; import org.apache.hc.core5.reactive.ReactiveEntityProducer;
import org.apache.hc.core5.reactive.ReactiveResponseConsumer; import org.apache.hc.core5.reactive.ReactiveResponseConsumer;
import org.apache.hc.core5.reactor.IOReactorConfig; import org.apache.hc.core5.reactor.IOReactorConfig;
import org.apache.hc.core5.util.Timeout;
import org.reactivestreams.Publisher; import org.reactivestreams.Publisher;
import io.reactivex.Flowable; import io.reactivex.Flowable;
@ -59,15 +57,10 @@ public class ReactiveClientFullDuplexExchange {
public static void main(final String[] args) throws Exception { public static void main(final String[] args) throws Exception {
final IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
.setSoTimeout(Timeout.ofSeconds(5))
.build();
final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal( final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal(
HttpVersionPolicy.NEGOTIATE,
H2Config.DEFAULT, H2Config.DEFAULT,
Http1Config.DEFAULT, Http1Config.DEFAULT,
ioReactorConfig); IOReactorConfig.DEFAULT);
client.start(); client.start();

View File

@ -30,10 +30,13 @@ package org.apache.hc.client5.http.impl.io;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.Socket; import java.net.Socket;
import java.util.concurrent.TimeUnit;
import org.apache.hc.client5.http.DnsResolver; import org.apache.hc.client5.http.DnsResolver;
import org.apache.hc.client5.http.HttpRoute; import org.apache.hc.client5.http.HttpRoute;
import org.apache.hc.client5.http.SchemePortResolver; 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.ConnectionEndpoint;
import org.apache.hc.client5.http.io.LeaseRequest; import org.apache.hc.client5.http.io.LeaseRequest;
import org.apache.hc.client5.http.io.ManagedHttpClientConnection; import org.apache.hc.client5.http.io.ManagedHttpClientConnection;
@ -361,26 +364,55 @@ public class TestBasicHttpClientConnectionManager {
mgr.setSocketConfig(sconfig); 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(dnsResolver.resolve("somehost")).thenReturn(new InetAddress[] {remote});
Mockito.when(schemePortResolver.resolve(target)).thenReturn(8443); Mockito.when(schemePortResolver.resolve(target)).thenReturn(8443);
Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(plainSocketFactory); Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(plainSocketFactory);
Mockito.when(plainSocketFactory.createSocket(Mockito.any())).thenReturn(socket); Mockito.when(plainSocketFactory.createSocket(Mockito.any())).thenReturn(socket);
Mockito.when(plainSocketFactory.connectSocket( Mockito.when(plainSocketFactory.connectSocket(
Mockito.any(),
Mockito.eq(socket), Mockito.eq(socket),
Mockito.any(), Mockito.any(),
Mockito.any(), Mockito.any(),
Mockito.any(), Mockito.any(),
Mockito.any(),
Mockito.any(),
Mockito.any())).thenReturn(socket); 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(dnsResolver, Mockito.times(1)).resolve("somehost");
Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target); Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
Mockito.verify(plainSocketFactory, Mockito.times(1)).createSocket(context); 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(remote, 8443),
new InetSocketAddress(local, 0), context); 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),
Timeout.ofMilliseconds(123),
tlsConfig,
context);
} }
@Test @Test
@ -402,6 +434,15 @@ public class TestBasicHttpClientConnectionManager {
mgr.setSocketConfig(sconfig); 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(dnsResolver.resolve("someproxy")).thenReturn(new InetAddress[] {remote});
Mockito.when(schemePortResolver.resolve(proxy)).thenReturn(8080); Mockito.when(schemePortResolver.resolve(proxy)).thenReturn(8080);
Mockito.when(schemePortResolver.resolve(target)).thenReturn(8443); Mockito.when(schemePortResolver.resolve(target)).thenReturn(8443);
@ -409,21 +450,27 @@ public class TestBasicHttpClientConnectionManager {
Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(sslSocketFactory); Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(sslSocketFactory);
Mockito.when(plainSocketFactory.createSocket(Mockito.any())).thenReturn(socket); Mockito.when(plainSocketFactory.createSocket(Mockito.any())).thenReturn(socket);
Mockito.when(plainSocketFactory.connectSocket( Mockito.when(plainSocketFactory.connectSocket(
Mockito.any(),
Mockito.eq(socket), Mockito.eq(socket),
Mockito.any(), Mockito.any(),
Mockito.any(), Mockito.any(),
Mockito.any(), Mockito.any(),
Mockito.any(),
Mockito.any(),
Mockito.any())).thenReturn(socket); 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(dnsResolver, Mockito.times(1)).resolve("someproxy");
Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(proxy); Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(proxy);
Mockito.verify(plainSocketFactory, Mockito.times(1)).createSocket(context); 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(remote, 8080),
new InetSocketAddress(local, 0), context); new InetSocketAddress(local, 0),
Timeout.ofMilliseconds(234),
tlsConfig,
context);
Mockito.when(conn.getSocket()).thenReturn(socket); Mockito.when(conn.getSocket()).thenReturn(socket);
@ -431,7 +478,7 @@ public class TestBasicHttpClientConnectionManager {
Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target); Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
Mockito.verify(sslSocketFactory, Mockito.times(1)).createLayeredSocket( Mockito.verify(sslSocketFactory, Mockito.times(1)).createLayeredSocket(
socket, "somehost", 8443, context); socket, "somehost", 8443, tlsConfig, context);
} }
} }

View File

@ -39,6 +39,7 @@ import org.apache.hc.client5.http.DnsResolver;
import org.apache.hc.client5.http.HttpHostConnectException; import org.apache.hc.client5.http.HttpHostConnectException;
import org.apache.hc.client5.http.SchemePortResolver; import org.apache.hc.client5.http.SchemePortResolver;
import org.apache.hc.client5.http.UnsupportedSchemeException; 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.io.ManagedHttpClientConnection;
import org.apache.hc.client5.http.socket.ConnectionSocketFactory; import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory; 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.BasicHttpContext;
import org.apache.hc.core5.http.protocol.HttpContext; import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.util.TimeValue; import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -96,6 +98,7 @@ public class TestHttpClientConnectionOperator {
Mockito.any(), Mockito.any(),
Mockito.any(), Mockito.any(),
Mockito.any(), Mockito.any(),
Mockito.any(),
Mockito.any())).thenReturn(socket); Mockito.any())).thenReturn(socket);
final SocketConfig socketConfig = SocketConfig.custom() final SocketConfig socketConfig = SocketConfig.custom()
@ -105,8 +108,11 @@ public class TestHttpClientConnectionOperator {
.setTcpNoDelay(true) .setTcpNoDelay(true)
.setSoLinger(50, TimeUnit.MILLISECONDS) .setSoLinger(50, TimeUnit.MILLISECONDS)
.build(); .build();
final TlsConfig tlsConfig = TlsConfig.custom()
.build();
final InetSocketAddress localAddress = new InetSocketAddress(local, 0); 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).setKeepAlive(true);
Mockito.verify(socket).setReuseAddress(true); Mockito.verify(socket).setReuseAddress(true);
@ -115,11 +121,12 @@ public class TestHttpClientConnectionOperator {
Mockito.verify(socket).setTcpNoDelay(true); Mockito.verify(socket).setTcpNoDelay(true);
Mockito.verify(plainSocketFactory).connectSocket( Mockito.verify(plainSocketFactory).connectSocket(
TimeValue.ofMilliseconds(1000),
socket, socket,
host, host,
new InetSocketAddress(ip1, 80), new InetSocketAddress(ip1, 80),
localAddress, localAddress,
Timeout.ofMilliseconds(123),
tlsConfig,
context); context);
Mockito.verify(conn, Mockito.times(2)).bind(socket); 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(), Mockito.any(),
Mockito.any(),
Mockito.any())).thenThrow(new SocketTimeoutException()); Mockito.any())).thenThrow(new SocketTimeoutException());
Assert.assertThrows(ConnectTimeoutException.class, () -> Assert.assertThrows(ConnectTimeoutException.class, () ->
@ -165,6 +173,7 @@ public class TestHttpClientConnectionOperator {
Mockito.any(), Mockito.any(),
Mockito.any(), Mockito.any(),
Mockito.any(), Mockito.any(),
Mockito.any(),
Mockito.any())).thenThrow(new ConnectException()); Mockito.any())).thenThrow(new ConnectException());
Assert.assertThrows(HttpHostConnectException.class, () -> Assert.assertThrows(HttpHostConnectException.class, () ->
@ -185,29 +194,35 @@ public class TestHttpClientConnectionOperator {
Mockito.when(schemePortResolver.resolve(host)).thenReturn(80); Mockito.when(schemePortResolver.resolve(host)).thenReturn(80);
Mockito.when(plainSocketFactory.createSocket(Mockito.any())).thenReturn(socket); Mockito.when(plainSocketFactory.createSocket(Mockito.any())).thenReturn(socket);
Mockito.when(plainSocketFactory.connectSocket( Mockito.when(plainSocketFactory.connectSocket(
Mockito.any(),
Mockito.any(), Mockito.any(),
Mockito.any(), Mockito.any(),
Mockito.eq(new InetSocketAddress(ip1, 80)), Mockito.eq(new InetSocketAddress(ip1, 80)),
Mockito.any(), Mockito.any(),
Mockito.any(),
Mockito.any(),
Mockito.any())).thenThrow(new ConnectException()); Mockito.any())).thenThrow(new ConnectException());
Mockito.when(plainSocketFactory.connectSocket( Mockito.when(plainSocketFactory.connectSocket(
Mockito.any(),
Mockito.any(), Mockito.any(),
Mockito.any(), Mockito.any(),
Mockito.eq(new InetSocketAddress(ip2, 80)), Mockito.eq(new InetSocketAddress(ip2, 80)),
Mockito.any(), Mockito.any(),
Mockito.any(),
Mockito.any(),
Mockito.any())).thenReturn(socket); Mockito.any())).thenReturn(socket);
final InetSocketAddress localAddress = new InetSocketAddress(local, 0); 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( Mockito.verify(plainSocketFactory).connectSocket(
TimeValue.ofMilliseconds(1000),
socket, socket,
host, host,
new InetSocketAddress(ip2, 80), new InetSocketAddress(ip2, 80),
localAddress, localAddress,
Timeout.ofMilliseconds(123),
tlsConfig,
context); context);
Mockito.verify(conn, Mockito.times(3)).bind(socket); 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(), Mockito.any(),
Mockito.any(),
Mockito.any())).thenReturn(socket); Mockito.any())).thenReturn(socket);
final InetSocketAddress localAddress = new InetSocketAddress(local, 0); 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( Mockito.verify(plainSocketFactory).connectSocket(
TimeValue.ofMilliseconds(1000),
socket, socket,
host, host,
new InetSocketAddress(ip, 80), new InetSocketAddress(ip, 80),
localAddress, localAddress,
Timeout.ofMilliseconds(123),
tlsConfig,
context); context);
Mockito.verify(dnsResolver, Mockito.never()).resolve(Mockito.anyString()); Mockito.verify(dnsResolver, Mockito.never()).resolve(Mockito.anyString());
Mockito.verify(conn, Mockito.times(2)).bind(socket); Mockito.verify(conn, Mockito.times(2)).bind(socket);
@ -258,9 +278,10 @@ public class TestHttpClientConnectionOperator {
Mockito.any(), Mockito.any(),
Mockito.eq("somehost"), Mockito.eq("somehost"),
Mockito.eq(443), Mockito.eq(443),
Mockito.eq(Timeout.ofMilliseconds(345)),
Mockito.any())).thenReturn(socket); Mockito.any())).thenReturn(socket);
connectionOperator.upgrade(conn, host, context); connectionOperator.upgrade(conn, host, Timeout.ofMilliseconds(345), context);
Mockito.verify(conn).bind(socket); Mockito.verify(conn).bind(socket);
} }

View File

@ -37,6 +37,8 @@ import java.util.concurrent.TimeoutException;
import org.apache.hc.client5.http.DnsResolver; import org.apache.hc.client5.http.DnsResolver;
import org.apache.hc.client5.http.HttpRoute; import org.apache.hc.client5.http.HttpRoute;
import org.apache.hc.client5.http.SchemePortResolver; 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.ConnectionEndpoint;
import org.apache.hc.client5.http.io.LeaseRequest; import org.apache.hc.client5.http.io.LeaseRequest;
import org.apache.hc.client5.http.io.ManagedHttpClientConnection; import org.apache.hc.client5.http.io.ManagedHttpClientConnection;
@ -247,26 +249,55 @@ public class TestPoolingHttpClientConnectionManager {
mgr.setDefaultSocketConfig(sconfig); 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(dnsResolver.resolve("somehost")).thenReturn(new InetAddress[]{remote});
Mockito.when(schemePortResolver.resolve(target)).thenReturn(8443); Mockito.when(schemePortResolver.resolve(target)).thenReturn(8443);
Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(plainSocketFactory); Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(plainSocketFactory);
Mockito.when(plainSocketFactory.createSocket(Mockito.any())).thenReturn(socket); Mockito.when(plainSocketFactory.createSocket(Mockito.any())).thenReturn(socket);
Mockito.when(plainSocketFactory.connectSocket( Mockito.when(plainSocketFactory.connectSocket(
Mockito.any(),
Mockito.eq(socket), Mockito.eq(socket),
Mockito.any(), Mockito.any(),
Mockito.any(), Mockito.any(),
Mockito.any(), Mockito.any(),
Mockito.any(),
Mockito.any(),
Mockito.any())).thenReturn(socket); 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(dnsResolver, Mockito.times(1)).resolve("somehost");
Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target); Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
Mockito.verify(plainSocketFactory, Mockito.times(1)).createSocket(context); 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(remote, 8443),
new InetSocketAddress(local, 0), context); 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),
Timeout.ofMilliseconds(123),
tlsConfig,
context);
} }
@Test @Test
@ -301,6 +332,15 @@ public class TestPoolingHttpClientConnectionManager {
mgr.setDefaultSocketConfig(sconfig); 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(dnsResolver.resolve("someproxy")).thenReturn(new InetAddress[] {remote});
Mockito.when(schemePortResolver.resolve(proxy)).thenReturn(8080); Mockito.when(schemePortResolver.resolve(proxy)).thenReturn(8080);
Mockito.when(schemePortResolver.resolve(target)).thenReturn(8443); Mockito.when(schemePortResolver.resolve(target)).thenReturn(8443);
@ -308,21 +348,27 @@ public class TestPoolingHttpClientConnectionManager {
Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(sslsf); Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(sslsf);
Mockito.when(plainsf.createSocket(Mockito.any())).thenReturn(mockSock); Mockito.when(plainsf.createSocket(Mockito.any())).thenReturn(mockSock);
Mockito.when(plainsf.connectSocket( Mockito.when(plainsf.connectSocket(
Mockito.any(),
Mockito.eq(mockSock), Mockito.eq(mockSock),
Mockito.any(), Mockito.any(),
Mockito.any(), Mockito.any(),
Mockito.any(), Mockito.any(),
Mockito.any(),
Mockito.any(),
Mockito.any())).thenReturn(mockSock); 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(dnsResolver, Mockito.times(1)).resolve("someproxy");
Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(proxy); Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(proxy);
Mockito.verify(plainsf, Mockito.times(1)).createSocket(context); 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(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.isOpen()).thenReturn(true);
Mockito.when(conn.getSocket()).thenReturn(mockSock); Mockito.when(conn.getSocket()).thenReturn(mockSock);
@ -331,7 +377,7 @@ public class TestPoolingHttpClientConnectionManager {
Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target); Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
Mockito.verify(sslsf, Mockito.times(1)).createLayeredSocket( Mockito.verify(sslsf, Mockito.times(1)).createLayeredSocket(
mockSock, "somehost", 8443, context); mockSock, "somehost", 8443, tlsConfig, context);
} }
} }