Internal connection operators to make use of the target name from the request URI authority

This commit is contained in:
Oleg Kalnichevski 2024-01-26 11:06:18 +01:00
parent 91ab690e50
commit e6e873d88b
15 changed files with 455 additions and 147 deletions

View File

@ -95,12 +95,12 @@ class InternalH2AsyncExecRuntime implements AsyncExecRuntime {
if (log.isDebugEnabled()) {
log.debug("{} acquiring endpoint ({})", id, connectTimeout);
}
return Operations.cancellable(connPool.getSession(target, connectTimeout,
return Operations.cancellable(connPool.getSession(route, connectTimeout,
new FutureCallback<IOSession>() {
@Override
public void completed(final IOSession ioSession) {
sessionRef.set(new Endpoint(target, ioSession));
sessionRef.set(new Endpoint(route, ioSession));
reusable = true;
if (log.isDebugEnabled()) {
log.debug("{} acquired endpoint", id);
@ -184,19 +184,19 @@ class InternalH2AsyncExecRuntime implements AsyncExecRuntime {
callback.completed(this);
return Operations.nonCancellable();
}
final HttpHost target = endpoint.target;
final HttpRoute route = endpoint.route;
final RequestConfig requestConfig = context.getRequestConfig();
@SuppressWarnings("deprecation")
final Timeout connectTimeout = requestConfig.getConnectTimeout();
if (log.isDebugEnabled()) {
log.debug("{} connecting endpoint ({})", ConnPoolSupport.getId(endpoint), connectTimeout);
}
return Operations.cancellable(connPool.getSession(target, connectTimeout,
return Operations.cancellable(connPool.getSession(route, connectTimeout,
new FutureCallback<IOSession>() {
@Override
public void completed(final IOSession ioSession) {
sessionRef.set(new Endpoint(target, ioSession));
sessionRef.set(new Endpoint(route, ioSession));
reusable = true;
if (log.isDebugEnabled()) {
log.debug("{} endpoint connected", ConnPoolSupport.getId(endpoint));
@ -263,15 +263,15 @@ class InternalH2AsyncExecRuntime implements AsyncExecRuntime {
new RequestExecutionCommand(exchangeHandler, pushHandlerFactory, complexCancellable, context),
Command.Priority.NORMAL);
} else {
final HttpHost target = endpoint.target;
final HttpRoute route = endpoint.route;
final RequestConfig requestConfig = context.getRequestConfig();
@SuppressWarnings("deprecation")
final Timeout connectTimeout = requestConfig.getConnectTimeout();
connPool.getSession(target, connectTimeout, new FutureCallback<IOSession>() {
connPool.getSession(route, connectTimeout, new FutureCallback<IOSession>() {
@Override
public void completed(final IOSession ioSession) {
sessionRef.set(new Endpoint(target, ioSession));
sessionRef.set(new Endpoint(route, ioSession));
reusable = true;
if (log.isDebugEnabled()) {
log.debug("{} start execution {}", ConnPoolSupport.getId(endpoint), id);
@ -309,11 +309,11 @@ class InternalH2AsyncExecRuntime implements AsyncExecRuntime {
static class Endpoint implements Identifiable {
final HttpHost target;
final HttpRoute route;
final IOSession session;
Endpoint(final HttpHost target, final IOSession session) {
this.target = target;
Endpoint(final HttpRoute route, final IOSession session) {
this.route = route;
this.session = session;
}

View File

@ -29,40 +29,49 @@ package org.apache.hc.client5.http.impl.async;
import java.net.InetSocketAddress;
import java.util.concurrent.Future;
import org.apache.hc.client5.http.HttpRoute;
import org.apache.hc.client5.http.config.ConnectionConfig;
import org.apache.hc.core5.concurrent.CallbackContribution;
import org.apache.hc.core5.concurrent.FutureCallback;
import org.apache.hc.core5.function.Callback;
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.nio.command.ShutdownCommand;
import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
import org.apache.hc.core5.http2.nio.pool.H2ConnPool;
import org.apache.hc.core5.http2.nio.command.PingCommand;
import org.apache.hc.core5.http2.nio.support.BasicPingHandler;
import org.apache.hc.core5.io.CloseMode;
import org.apache.hc.core5.io.ModalCloseable;
import org.apache.hc.core5.net.NamedEndpoint;
import org.apache.hc.core5.reactor.AbstractIOSessionPool;
import org.apache.hc.core5.reactor.Command;
import org.apache.hc.core5.reactor.ConnectionInitiator;
import org.apache.hc.core5.reactor.IOSession;
import org.apache.hc.core5.reactor.ssl.TransportSecurityLayer;
import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;
class InternalH2ConnPool implements ModalCloseable {
private final H2ConnPool connPool;
private final SessionPool sessionPool;
private volatile Resolver<HttpHost, ConnectionConfig> connectionConfigResolver;
InternalH2ConnPool(final ConnectionInitiator connectionInitiator,
final Resolver<HttpHost, InetSocketAddress> addressResolver,
final TlsStrategy tlsStrategy) {
this.connPool = new H2ConnPool(connectionInitiator, addressResolver, tlsStrategy);
this.sessionPool = new SessionPool(connectionInitiator, addressResolver, tlsStrategy);
}
@Override
public void close(final CloseMode closeMode) {
connPool.close(closeMode);
sessionPool.close(closeMode);
}
@Override
public void close() {
connPool.close();
sessionPool.close();
}
private ConnectionConfig resolveConnectionConfig(final HttpHost httpHost) {
@ -72,12 +81,12 @@ class InternalH2ConnPool implements ModalCloseable {
}
public Future<IOSession> getSession(
final HttpHost endpoint,
final HttpRoute route,
final Timeout connectTimeout,
final FutureCallback<IOSession> callback) {
final ConnectionConfig connectionConfig = resolveConnectionConfig(endpoint);
return connPool.getSession(
endpoint,
final ConnectionConfig connectionConfig = resolveConnectionConfig(route.getTargetHost());
return sessionPool.getSession(
route,
connectTimeout != null ? connectTimeout : connectionConfig.getConnectTimeout(),
new CallbackContribution<IOSession>(callback) {
@ -94,11 +103,113 @@ class InternalH2ConnPool implements ModalCloseable {
}
public void closeIdle(final TimeValue idleTime) {
connPool.closeIdle(idleTime);
sessionPool.closeIdle(idleTime);
}
public void setConnectionConfigResolver(final Resolver<HttpHost, ConnectionConfig> connectionConfigResolver) {
this.connectionConfigResolver = connectionConfigResolver;
}
public TimeValue getValidateAfterInactivity() {
return sessionPool.validateAfterInactivity;
}
public void setValidateAfterInactivity(final TimeValue timeValue) {
sessionPool.validateAfterInactivity = timeValue;
}
static class SessionPool extends AbstractIOSessionPool<HttpRoute> {
private final ConnectionInitiator connectionInitiator;
private final Resolver<HttpHost, InetSocketAddress> addressResolver;
private final TlsStrategy tlsStrategy;
private volatile TimeValue validateAfterInactivity = TimeValue.NEG_ONE_MILLISECOND;
SessionPool(final ConnectionInitiator connectionInitiator,
final Resolver<HttpHost, InetSocketAddress> addressResolver,
final TlsStrategy tlsStrategy) {
this.connectionInitiator = connectionInitiator;
this.addressResolver = addressResolver;
this.tlsStrategy = tlsStrategy;
}
@Override
protected Future<IOSession> connectSession(final HttpRoute route,
final Timeout connectTimeout,
final FutureCallback<IOSession> callback) {
final HttpHost target = route.getTargetHost();
final InetSocketAddress localAddress = route.getLocalSocketAddress();
final InetSocketAddress remoteAddress = addressResolver.resolve(target);
return connectionInitiator.connect(
target,
remoteAddress,
localAddress,
connectTimeout,
null,
new CallbackContribution<IOSession>(callback) {
@Override
public void completed(final IOSession ioSession) {
if (tlsStrategy != null
&& URIScheme.HTTPS.same(target.getSchemeName())
&& ioSession instanceof TransportSecurityLayer) {
final NamedEndpoint tlsName = route.getTargetName() != null ? route.getTargetName() : target;
tlsStrategy.upgrade(
(TransportSecurityLayer) ioSession,
tlsName,
null,
connectTimeout,
new CallbackContribution<TransportSecurityLayer>(callback) {
@Override
public void completed(final TransportSecurityLayer transportSecurityLayer) {
callback.completed(ioSession);
}
});
ioSession.setSocketTimeout(connectTimeout);
} else {
callback.completed(ioSession);
}
}
});
}
@Override
protected void validateSession(final IOSession ioSession,
final Callback<Boolean> callback) {
if (ioSession.isOpen()) {
final TimeValue timeValue = validateAfterInactivity;
if (TimeValue.isNonNegative(timeValue)) {
final long lastAccessTime = Math.min(ioSession.getLastReadTime(), ioSession.getLastWriteTime());
final long deadline = lastAccessTime + timeValue.toMilliseconds();
if (deadline <= System.currentTimeMillis()) {
final Timeout socketTimeoutMillis = ioSession.getSocketTimeout();
ioSession.enqueue(new PingCommand(new BasicPingHandler(result -> {
ioSession.setSocketTimeout(socketTimeoutMillis);
callback.execute(result);
})), Command.Priority.NORMAL);
return;
}
}
callback.execute(true);
} else {
callback.execute(false);
}
}
@Override
protected void closeSession(final IOSession ioSession,
final CloseMode closeMode) {
if (closeMode == CloseMode.GRACEFUL) {
ioSession.enqueue(ShutdownCommand.GRACEFUL, Command.Priority.NORMAL);
} else {
ioSession.close(closeMode);
}
}
}
}

View File

@ -34,6 +34,7 @@ import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import org.apache.hc.client5.http.DnsResolver;
import org.apache.hc.client5.http.HttpRoute;
import org.apache.hc.client5.http.config.Configurable;
import org.apache.hc.client5.http.config.ConnectionConfig;
import org.apache.hc.client5.http.config.RequestConfig;
@ -141,7 +142,7 @@ public final class MinimalH2AsyncClient extends AbstractMinimalHttpAsyncClientBa
final Timeout connectTimeout = requestConfig.getConnectTimeout();
final HttpHost target = new HttpHost(request.getScheme(), request.getAuthority());
final Future<IOSession> sessionFuture = connPool.getSession(target, connectTimeout,
final Future<IOSession> sessionFuture = connPool.getSession(new HttpRoute(target), connectTimeout,
new FutureCallback<IOSession>() {
@Override

View File

@ -477,24 +477,20 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
return;
}
final HttpRoute route = internalEndpoint.getRoute();
final HttpHost host;
if (route.getProxyHost() != null) {
host = route.getProxyHost();
} else {
host = route.getTargetHost();
}
final HttpHost firstHop = route.getProxyHost() != null ? route.getProxyHost() : route.getTargetHost();
final Timeout connectTimeout = timeout != null ? Timeout.of(timeout.getDuration(), timeout.getTimeUnit()) : connectionConfig.getConnectTimeout();
final ManagedHttpClientConnection connection = internalEndpoint.getConnection();
if (LOG.isDebugEnabled()) {
LOG.debug("{} connecting endpoint to {} ({})", ConnPoolSupport.getId(endpoint), host, connectTimeout);
LOG.debug("{} connecting endpoint to {} ({})", ConnPoolSupport.getId(endpoint), firstHop, connectTimeout);
}
this.connectionOperator.connect(
connection,
host,
firstHop,
route.getTargetName(),
route.getLocalSocketAddress(),
connectTimeout,
socketConfig,
tlsConfig,
route.isTunnelled() ? null : tlsConfig,
context);
if (LOG.isDebugEnabled()) {
LOG.debug("{} connected {}", ConnPoolSupport.getId(endpoint), ConnPoolSupport.getId(conn));
@ -517,9 +513,11 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
Args.notNull(endpoint, "Endpoint");
Args.notNull(route, "HTTP route");
final InternalConnectionEndpoint internalEndpoint = cast(endpoint);
final HttpRoute route = internalEndpoint.getRoute();
this.connectionOperator.upgrade(
internalEndpoint.getConnection(),
internalEndpoint.getRoute().getTargetHost(),
route.getTargetHost(),
route.getTargetName(),
tlsConfig,
context);
} finally {

View File

@ -58,6 +58,7 @@ import org.apache.hc.core5.http.config.Lookup;
import org.apache.hc.core5.http.io.SocketConfig;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.io.Closer;
import org.apache.hc.core5.net.NamedEndpoint;
import org.apache.hc.core5.util.Args;
import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;
@ -147,52 +148,52 @@ public class DefaultHttpClientConnectionOperator implements HttpClientConnection
final SocketConfig socketConfig,
final HttpContext context) throws IOException {
final Timeout timeout = connectTimeout != null ? Timeout.of(connectTimeout.getDuration(), connectTimeout.getTimeUnit()) : null;
connect(conn, host, localAddress, timeout, socketConfig, null, context);
connect(conn, host, null, localAddress, timeout, socketConfig, null, context);
}
@Override
public void connect(
final ManagedHttpClientConnection conn,
final HttpHost host,
final HttpHost endpointHost,
final NamedEndpoint endpointName,
final InetSocketAddress localAddress,
final Timeout connectTimeout,
final SocketConfig socketConfig,
final Object attachment,
final HttpContext context) throws IOException {
Args.notNull(conn, "Connection");
Args.notNull(host, "Host");
Args.notNull(endpointHost, "Host");
Args.notNull(socketConfig, "Socket config");
Args.notNull(context, "Context");
final InetAddress[] remoteAddresses;
if (host.getAddress() != null) {
remoteAddresses = new InetAddress[] { host.getAddress() };
if (endpointHost.getAddress() != null) {
remoteAddresses = new InetAddress[] { endpointHost.getAddress() };
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("{} resolving remote address", host.getHostName());
LOG.debug("{} resolving remote address", endpointHost.getHostName());
}
remoteAddresses = this.dnsResolver.resolve(host.getHostName());
remoteAddresses = this.dnsResolver.resolve(endpointHost.getHostName());
if (LOG.isDebugEnabled()) {
LOG.debug("{} resolved to {}", host.getHostName(), remoteAddresses == null ? "null" : Arrays.asList(remoteAddresses));
LOG.debug("{} resolved to {}", endpointHost.getHostName(), remoteAddresses == null ? "null" : Arrays.asList(remoteAddresses));
}
if (remoteAddresses == null || remoteAddresses.length == 0) {
throw new UnknownHostException(host.getHostName());
throw new UnknownHostException(endpointHost.getHostName());
}
}
final Timeout soTimeout = socketConfig.getSoTimeout();
final SocketAddress socksProxyAddress = socketConfig.getSocksProxyAddress();
final Proxy socksProxy = socksProxyAddress != null ? new Proxy(Proxy.Type.SOCKS, socksProxyAddress) : null;
final int port = this.schemePortResolver.resolve(host.getSchemeName(), host);
final int port = this.schemePortResolver.resolve(endpointHost.getSchemeName(), endpointHost);
for (int i = 0; i < remoteAddresses.length; i++) {
final InetAddress address = remoteAddresses[i];
final boolean last = i == remoteAddresses.length - 1;
final InetSocketAddress remoteAddress = new InetSocketAddress(address, port);
if (LOG.isDebugEnabled()) {
LOG.debug("{}:{} connecting {}->{} ({})",
host.getHostName(), host.getPort(), localAddress, remoteAddress, connectTimeout);
LOG.debug("{} connecting {}->{} ({})", endpointHost, localAddress, remoteAddress, connectTimeout);
}
final Socket socket = detachedSocketFactory.create(socksProxy);
try {
@ -220,14 +221,18 @@ public class DefaultHttpClientConnectionOperator implements HttpClientConnection
}
socket.connect(remoteAddress, TimeValue.isPositive(connectTimeout) ? connectTimeout.toMillisecondsIntBound() : 0);
conn.bind(socket);
conn.setSocketTimeout(soTimeout);
if (LOG.isDebugEnabled()) {
LOG.debug("{}:{} connected {}->{} as {}",
host.getHostName(), host.getPort(), localAddress, remoteAddress, ConnPoolSupport.getId(conn));
LOG.debug("{} {} connected {}->{}", ConnPoolSupport.getId(conn), endpointHost,
conn.getLocalAddress(), conn.getRemoteAddress());
}
final TlsSocketStrategy tlsSocketStrategy = tlsSocketStrategyLookup != null ? tlsSocketStrategyLookup.lookup(host.getSchemeName()) : null;
conn.setSocketTimeout(soTimeout);
final TlsSocketStrategy tlsSocketStrategy = tlsSocketStrategyLookup != null ? tlsSocketStrategyLookup.lookup(endpointHost.getSchemeName()) : null;
if (tlsSocketStrategy != null) {
final Socket upgradedSocket = tlsSocketStrategy.upgrade(socket, host.getHostName(), port, attachment, context);
final NamedEndpoint tlsName = endpointName != null ? endpointName : endpointHost;
if (LOG.isDebugEnabled()) {
LOG.debug("{} {} upgrading to TLS", ConnPoolSupport.getId(conn), tlsName);
}
final Socket upgradedSocket = tlsSocketStrategy.upgrade(socket, tlsName.getHostName(), tlsName.getPort(), attachment, context);
conn.bind(upgradedSocket);
}
return;
@ -238,14 +243,12 @@ public class DefaultHttpClientConnectionOperator implements HttpClientConnection
Closer.closeQuietly(socket);
if (last) {
if (LOG.isDebugEnabled()) {
LOG.debug("{}:{} connection to {} failed ({}); terminating operation",
host.getHostName(), host.getPort(), remoteAddress, ex.getClass());
LOG.debug("{} connection to {} failed ({}); terminating operation", endpointHost, remoteAddress, ex.getClass());
}
throw ConnectExceptionSupport.enhance(ex, host, remoteAddresses);
throw ConnectExceptionSupport.enhance(ex, endpointHost, remoteAddresses);
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("{}:{} connection to {} failed ({}); retrying connection to the next address",
host.getHostName(), host.getPort(), remoteAddress, ex.getClass());
LOG.debug("{} connection to {} failed ({}); retrying connection to the next address", endpointHost, remoteAddress, ex.getClass());
}
}
}
@ -257,24 +260,28 @@ public class DefaultHttpClientConnectionOperator implements HttpClientConnection
final ManagedHttpClientConnection conn,
final HttpHost host,
final HttpContext context) throws IOException {
upgrade(conn, host, null, context);
upgrade(conn, host, null, null, context);
}
@Override
public void upgrade(
final ManagedHttpClientConnection conn,
final HttpHost host,
final HttpHost endpointHost,
final NamedEndpoint endpointName,
final Object attachment,
final HttpContext context) throws IOException {
final Socket socket = conn.getSocket();
if (socket == null) {
throw new ConnectionClosedException("Connection is closed");
}
final String newProtocol = URIScheme.HTTP.same(host.getSchemeName()) ? URIScheme.HTTPS.id : host.getSchemeName();
final String newProtocol = URIScheme.HTTP.same(endpointHost.getSchemeName()) ? URIScheme.HTTPS.id : endpointHost.getSchemeName();
final TlsSocketStrategy tlsSocketStrategy = tlsSocketStrategyLookup != null ? tlsSocketStrategyLookup.lookup(newProtocol) : null;
if (tlsSocketStrategy != null) {
final int port = this.schemePortResolver.resolve(newProtocol, host);
final SSLSocket upgradedSocket = tlsSocketStrategy.upgrade(socket, host.getHostName(), port, attachment, context);
final NamedEndpoint tlsName = endpointName != null ? endpointName : endpointHost;
if (LOG.isDebugEnabled()) {
LOG.debug("{} upgrading to TLS {}:{}", ConnPoolSupport.getId(conn), tlsName.getHostName(), tlsName.getPort());
}
final SSLSocket upgradedSocket = tlsSocketStrategy.upgrade(socket, tlsName.getHostName(), tlsName.getPort(), attachment, context);
conn.bind(upgradedSocket);
} else {
throw new UnsupportedSchemeException(newProtocol + " protocol is not supported");

View File

@ -474,22 +474,22 @@ public class PoolingHttpClientConnectionManager
poolEntry.assignConnection(connFactory.createConnection(null));
}
final HttpRoute route = poolEntry.getRoute();
final HttpHost host = route.getProxyHost() != null ? route.getProxyHost() : route.getTargetHost();
final HttpHost firstHop = route.getProxyHost() != null ? route.getProxyHost() : route.getTargetHost();
final SocketConfig socketConfig = resolveSocketConfig(route);
final ConnectionConfig connectionConfig = resolveConnectionConfig(route);
final TlsConfig tlsConfig = resolveTlsConfig(host);
final Timeout connectTimeout = timeout != null ? Timeout.of(timeout.getDuration(), timeout.getTimeUnit()) : connectionConfig.getConnectTimeout();
if (LOG.isDebugEnabled()) {
LOG.debug("{} connecting endpoint to {} ({})", ConnPoolSupport.getId(endpoint), host, connectTimeout);
LOG.debug("{} connecting endpoint to {} ({})", ConnPoolSupport.getId(endpoint), firstHop, connectTimeout);
}
final ManagedHttpClientConnection conn = poolEntry.getConnection();
this.connectionOperator.connect(
conn,
host,
firstHop,
route.getTargetName(),
route.getLocalSocketAddress(),
connectTimeout,
socketConfig,
tlsConfig,
route.isTunnelled() ? null : resolveTlsConfig(route.getTargetHost()),
context);
if (LOG.isDebugEnabled()) {
LOG.debug("{} connected {}", ConnPoolSupport.getId(endpoint), ConnPoolSupport.getId(conn));
@ -505,9 +505,15 @@ public class PoolingHttpClientConnectionManager
Args.notNull(endpoint, "Managed endpoint");
final InternalConnectionEndpoint internalEndpoint = cast(endpoint);
final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry = internalEndpoint.getValidatedPoolEntry();
final HttpHost target = poolEntry.getRoute().getTargetHost();
final HttpRoute route = poolEntry.getRoute();
final HttpHost target = route.getTargetHost();
final TlsConfig tlsConfig = resolveTlsConfig(target);
this.connectionOperator.upgrade(poolEntry.getConnection(), target, tlsConfig, context);
this.connectionOperator.upgrade(
poolEntry.getConnection(),
target,
route.getTargetName(),
tlsConfig,
context);
}
@Override

View File

@ -36,6 +36,7 @@ import org.apache.hc.client5.http.DnsResolver;
import org.apache.hc.client5.http.SchemePortResolver;
import org.apache.hc.client5.http.UnsupportedSchemeException;
import org.apache.hc.client5.http.config.TlsConfig;
import org.apache.hc.client5.http.impl.ConnPoolSupport;
import org.apache.hc.client5.http.impl.DefaultSchemePortResolver;
import org.apache.hc.client5.http.nio.AsyncClientConnectionOperator;
import org.apache.hc.client5.http.nio.ManagedAsyncClientConnection;
@ -49,14 +50,19 @@ import org.apache.hc.core5.http.URIScheme;
import org.apache.hc.core5.http.config.Lookup;
import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.net.NamedEndpoint;
import org.apache.hc.core5.reactor.ConnectionInitiator;
import org.apache.hc.core5.reactor.IOSession;
import org.apache.hc.core5.reactor.ssl.TransportSecurityLayer;
import org.apache.hc.core5.util.Args;
import org.apache.hc.core5.util.Timeout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
final class DefaultAsyncClientConnectionOperator implements AsyncClientConnectionOperator {
private static final Logger LOG = LoggerFactory.getLogger(DefaultAsyncClientConnectionOperator.class);
private final SchemePortResolver schemePortResolver;
private final MultihomeIOSessionRequester sessionRequester;
private final Lookup<TlsStrategy> tlsStrategyLookup;
@ -78,25 +84,31 @@ final class DefaultAsyncClientConnectionOperator implements AsyncClientConnectio
final Timeout connectTimeout,
final Object attachment,
final FutureCallback<ManagedAsyncClientConnection> callback) {
return connect(connectionInitiator, host, localAddress, connectTimeout,
return connect(connectionInitiator, host, null, localAddress, connectTimeout,
attachment, null, callback);
}
@Override
public Future<ManagedAsyncClientConnection> connect(
final ConnectionInitiator connectionInitiator,
final HttpHost host,
final HttpHost endpointHost,
final NamedEndpoint endpointName,
final SocketAddress localAddress,
final Timeout connectTimeout,
final Object attachment,
final HttpContext context,
final FutureCallback<ManagedAsyncClientConnection> callback) {
Args.notNull(connectionInitiator, "Connection initiator");
Args.notNull(host, "Host");
Args.notNull(endpointHost, "Host");
final ComplexFuture<ManagedAsyncClientConnection> future = new ComplexFuture<>(callback);
final HttpHost remoteEndpoint = RoutingSupport.normalize(host, schemePortResolver);
final InetAddress remoteAddress = host.getAddress();
final HttpHost remoteEndpoint = RoutingSupport.normalize(endpointHost, schemePortResolver);
final InetAddress remoteAddress = endpointHost.getAddress();
final TlsConfig tlsConfig = attachment instanceof TlsConfig ? (TlsConfig) attachment : TlsConfig.DEFAULT;
if (LOG.isDebugEnabled()) {
LOG.debug("{} connecting {}->{} ({})", endpointHost, localAddress, remoteAddress, connectTimeout);
}
final Future<IOSession> sessionFuture = sessionRequester.connect(
connectionInitiator,
remoteEndpoint,
@ -109,14 +121,22 @@ final class DefaultAsyncClientConnectionOperator implements AsyncClientConnectio
@Override
public void completed(final IOSession session) {
final DefaultManagedAsyncClientConnection connection = new DefaultManagedAsyncClientConnection(session);
final TlsStrategy tlsStrategy = tlsStrategyLookup != null ? tlsStrategyLookup.lookup(host.getSchemeName()) : null;
if (LOG.isDebugEnabled()) {
LOG.debug("{} {} connected {}->{}", ConnPoolSupport.getId(connection), endpointHost,
connection.getLocalAddress(), connection.getRemoteAddress());
}
final TlsStrategy tlsStrategy = tlsStrategyLookup != null ? tlsStrategyLookup.lookup(endpointHost.getSchemeName()) : null;
if (tlsStrategy != null) {
try {
final Timeout socketTimeout = connection.getSocketTimeout();
final Timeout handshakeTimeout = tlsConfig.getHandshakeTimeout();
final NamedEndpoint tlsName = endpointName != null ? endpointName : endpointHost;
if (LOG.isDebugEnabled()) {
LOG.debug("{} {} upgrading to TLS", ConnPoolSupport.getId(connection), tlsName);
}
tlsStrategy.upgrade(
connection,
host,
tlsName,
attachment,
handshakeTimeout != null ? handshakeTimeout : connectTimeout,
new FutureContribution<TransportSecurityLayer>(future) {
@ -156,32 +176,27 @@ final class DefaultAsyncClientConnectionOperator implements AsyncClientConnectio
final ManagedAsyncClientConnection connection,
final HttpHost host,
final Object attachment) {
upgrade(connection, host, attachment, null, null);
upgrade(connection, host, null, attachment, null, null);
}
@Override
public void upgrade(
final ManagedAsyncClientConnection connection,
final HttpHost host,
final Object attachment,
final HttpContext context) {
upgrade(connection, host, attachment, context, null);
}
@Override
public void upgrade(
final ManagedAsyncClientConnection connection,
final HttpHost host,
final HttpHost endpointHost,
final NamedEndpoint endpointName,
final Object attachment,
final HttpContext context,
final FutureCallback<ManagedAsyncClientConnection> callback) {
final String newProtocol = URIScheme.HTTP.same(host.getSchemeName()) ? URIScheme.HTTPS.id : host.getSchemeName();
final HttpHost remoteEndpoint = RoutingSupport.normalize(host, schemePortResolver);
final String newProtocol = URIScheme.HTTP.same(endpointHost.getSchemeName()) ? URIScheme.HTTPS.id : endpointHost.getSchemeName();
final TlsStrategy tlsStrategy = tlsStrategyLookup != null ? tlsStrategyLookup.lookup(newProtocol) : null;
if (tlsStrategy != null) {
final NamedEndpoint tlsName = endpointName != null ? endpointName : endpointHost;
if (LOG.isDebugEnabled()) {
LOG.debug("{} {} upgrading to TLS", ConnPoolSupport.getId(connection), tlsName);
}
tlsStrategy.upgrade(
connection,
remoteEndpoint,
tlsName,
attachment,
null,
new CallbackContribution<TransportSecurityLayer>(callback) {

View File

@ -27,7 +27,6 @@
package org.apache.hc.client5.http.impl.nio;
import java.net.InetSocketAddress;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@ -441,25 +440,20 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
}
final PoolEntry<HttpRoute, ManagedAsyncClientConnection> poolEntry = internalEndpoint.getPoolEntry();
final HttpRoute route = poolEntry.getRoute();
final HttpHost host;
if (route.getProxyHost() != null) {
host = route.getProxyHost();
} else {
host = route.getTargetHost();
}
final InetSocketAddress localAddress = route.getLocalSocketAddress();
final HttpHost firstHop = route.getProxyHost() != null ? route.getProxyHost(): route.getTargetHost();
final ConnectionConfig connectionConfig = resolveConnectionConfig(route);
final Timeout connectTimeout = timeout != null ? timeout : connectionConfig.getConnectTimeout();
if (LOG.isDebugEnabled()) {
LOG.debug("{} connecting endpoint to {} ({})", ConnPoolSupport.getId(endpoint), host, connectTimeout);
LOG.debug("{} connecting endpoint to {} ({})", ConnPoolSupport.getId(endpoint), firstHop, connectTimeout);
}
final Future<ManagedAsyncClientConnection> connectFuture = connectionOperator.connect(
connectionInitiator,
host,
localAddress,
firstHop,
route.getTargetName(),
route.getLocalSocketAddress(),
connectTimeout,
route.isTunnelled() ? null : resolveTlsConfig(host),
route.isTunnelled() ? null : resolveTlsConfig(route.getTargetHost()),
context,
new FutureCallback<ManagedAsyncClientConnection>() {
@ -508,6 +502,7 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
connectionOperator.upgrade(
poolEntry.getConnection(),
target,
route.getTargetName(),
attachment != null ? attachment : resolveTlsConfig(target),
context,
new CallbackContribution<ManagedAsyncClientConnection>(callback) {

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.io.SocketConfig;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.net.NamedEndpoint;
import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;
@ -70,24 +71,27 @@ public interface HttpClientConnectionOperator {
* Connect the given managed connection to the remote endpoint.
*
* @param conn the managed connection.
* @param host the address of the opposite endpoint.
* @param endpointHost the address of the remote endpoint.
* @param endpointName the name of the remote endpoint, if different from the endpoint host name,
* {@code null} otherwise. Usually taken from the request URU authority.
* @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
* @since 5.4
*/
default void connect(
ManagedHttpClientConnection conn,
HttpHost host,
HttpHost endpointHost,
NamedEndpoint endpointName,
InetSocketAddress localAddress,
Timeout connectTimeout,
SocketConfig socketConfig,
Object attachment,
HttpContext context) throws IOException {
connect(conn, host, localAddress, connectTimeout, socketConfig, context);
connect(conn, endpointHost, localAddress, connectTimeout, socketConfig, context);
}
/**
@ -108,7 +112,9 @@ public interface HttpClientConnectionOperator {
* by using the TLS security protocol.
*
* @param conn the managed connection.
* @param host the address of the opposite endpoint with TLS security.
* @param endpointHost the address of the remote endpoint.
* @param endpointName the name of the remote endpoint, if different from the endpoint host name,
* {@code null} otherwise. Usually taken from the request URU authority.
* @param attachment connect request attachment.
* @param context the execution context.
*
@ -116,10 +122,11 @@ public interface HttpClientConnectionOperator {
*/
default void upgrade(
ManagedHttpClientConnection conn,
HttpHost host,
HttpHost endpointHost,
NamedEndpoint endpointName,
Object attachment,
HttpContext context) throws IOException {
upgrade(conn, host, context);
upgrade(conn, endpointHost, context);
}
}

View File

@ -36,6 +36,7 @@ import org.apache.hc.core5.annotation.ThreadingBehavior;
import org.apache.hc.core5.concurrent.FutureCallback;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.net.NamedEndpoint;
import org.apache.hc.core5.reactor.ConnectionInitiator;
import org.apache.hc.core5.util.Timeout;
@ -73,24 +74,27 @@ public interface AsyncClientConnectionOperator {
* the provided {@link ConnectionInitiator}.
*
* @param connectionInitiator the connection initiator.
* @param host the address of the opposite endpoint.
* @param endpointHost the address of the remote endpoint.
* @param endpointName the name of the remote endpoint, if different from the endpoint host name,
* {@code null} otherwise. Usually taken from the request URU authority.
* @param localAddress the address of the local endpoint.
* @param connectTimeout the timeout of the connect operation.
* @param attachment the attachment, which can be any object representing custom parameter
* of the operation.
* @param context the execution context.
* @param callback the future result callback.
* @since 5.2
* @since 5.4
*/
default Future<ManagedAsyncClientConnection> connect(
ConnectionInitiator connectionInitiator,
HttpHost host,
HttpHost endpointHost,
NamedEndpoint endpointName,
SocketAddress localAddress,
Timeout connectTimeout,
Object attachment,
HttpContext context,
FutureCallback<ManagedAsyncClientConnection> callback) {
return connect(connectionInitiator, host, localAddress, connectTimeout,
return connect(connectionInitiator, endpointHost, localAddress, connectTimeout,
attachment, callback);
}
@ -110,38 +114,26 @@ public interface AsyncClientConnectionOperator {
* by using the TLS security protocol.
*
* @param conn the managed connection.
* @param host the address of the opposite endpoint with TLS security.
* @param endpointHost the address of the remote endpoint.
* @param endpointName the name of the remote endpoint, if different from the endpoint host name,
* {@code null} otherwise. Usually taken from the request URU authority.
* @param attachment the attachment, which can be any object representing custom parameter
* of the operation.
* @param context the execution context.
* @param callback the future result callback.
* @since 5.2
* @since 5.4
*/
default void upgrade(
ManagedAsyncClientConnection conn,
HttpHost host,
HttpHost endpointHost,
NamedEndpoint endpointName,
Object attachment,
HttpContext context,
FutureCallback<ManagedAsyncClientConnection> callback) {
upgrade(conn, host, attachment, context);
upgrade(conn, endpointHost, attachment);
if (callback != null) {
callback.completed(conn);
}
}
/**
* 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 the attachment, which can be any object representing custom parameter
* of the operation.
* @param context the execution context.
* @since 5.2
*/
default void upgrade(ManagedAsyncClientConnection conn, HttpHost host, Object attachment, HttpContext context) {
upgrade(conn, host, attachment);
}
}

View File

@ -0,0 +1,106 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.hc.client5.http.examples;
import java.util.concurrent.Future;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
import org.apache.hc.client5.http.async.methods.SimpleRequestProducer;
import org.apache.hc.client5.http.async.methods.SimpleResponseConsumer;
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.core5.concurrent.FutureCallback;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.message.StatusLine;
import org.apache.hc.core5.io.CloseMode;
/**
* This example demonstrates how to use SNI to send requests to a virtual HTTPS
* endpoint using the async I/O.
*/
public class AsyncClientSNI {
public static void main(final String[] args) throws Exception {
try (final CloseableHttpAsyncClient client = HttpAsyncClients.createSystem()) {
client.start();
final HttpHost target = new HttpHost("https", "www.google.com");
final SimpleHttpRequest request = SimpleRequestBuilder.get()
.setUri("https://www.google.ch/")
.build();
final HttpClientContext clientContext = HttpClientContext.create();
System.out.println("Executing request " + request);
final Future<SimpleHttpResponse> future = client.execute(
target,
SimpleRequestProducer.create(request),
SimpleResponseConsumer.create(),
null,
clientContext,
new FutureCallback<SimpleHttpResponse>() {
@Override
public void completed(final SimpleHttpResponse response) {
System.out.println(request + "->" + new StatusLine(response));
final SSLSession sslSession = clientContext.getSSLSession();
if (sslSession != null) {
try {
System.out.println("Peer: " + sslSession.getPeerPrincipal());
System.out.println("TLS protocol: " + sslSession.getProtocol());
System.out.println("TLS cipher suite: " + sslSession.getCipherSuite());
} catch (final SSLPeerUnverifiedException ignore) {
}
}
}
@Override
public void failed(final Exception ex) {
System.out.println(request + "->" + ex);
}
@Override
public void cancelled() {
System.out.println(request + " cancelled");
}
});
future.get();
System.out.println("Shutting down");
client.close(CloseMode.GRACEFUL);
}
}
}

View File

@ -0,0 +1,73 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.hc.client5.http.examples;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.message.StatusLine;
/**
* This example demonstrates how to use SNI to send requests to a virtual HTTPS
* endpoint using the classic I/O.
*/
public class ClientSNI {
public final static void main(final String[] args) throws Exception {
try (CloseableHttpClient httpclient = HttpClients.createSystem()) {
final HttpHost target = new HttpHost("https", "www.google.com");
final HttpGet httpget = new HttpGet("https://www.google.ch/");
System.out.println("Executing request " + httpget.getMethod() + " " + httpget.getUri());
final HttpClientContext clientContext = HttpClientContext.create();
httpclient.execute(target, httpget, clientContext, response -> {
System.out.println("----------------------------------------");
System.out.println(httpget + "->" + new StatusLine(response));
EntityUtils.consume(response.getEntity());
final SSLSession sslSession = clientContext.getSSLSession();
if (sslSession != null) {
try {
System.out.println("Peer: " + sslSession.getPeerPrincipal());
System.out.println("TLS protocol: " + sslSession.getProtocol());
System.out.println("TLS cipher suite: " + sslSession.getCipherSuite());
} catch (final SSLPeerUnverifiedException ignore) {
}
}
return null;
});
}
}
}

View File

@ -402,7 +402,7 @@ public class TestBasicHttpClientConnectionManager {
Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target.getSchemeName(), target);
Mockito.verify(detachedSocketFactory, Mockito.times(1)).create(null);
Mockito.verify(socket, Mockito.times(1)).connect(new InetSocketAddress(remote, 8443), 234);
Mockito.verify(tlsSocketStrategy).upgrade(socket, "somehost", 8443, tlsConfig, context);
Mockito.verify(tlsSocketStrategy).upgrade(socket, "somehost", 443, tlsConfig, context);
mgr.connect(endpoint1, TimeValue.ofMilliseconds(123), context);
@ -410,7 +410,7 @@ public class TestBasicHttpClientConnectionManager {
Mockito.verify(schemePortResolver, Mockito.times(2)).resolve(target.getSchemeName(), target);
Mockito.verify(detachedSocketFactory, Mockito.times(2)).create(null);
Mockito.verify(socket, Mockito.times(1)).connect(new InetSocketAddress(remote, 8443), 123);
Mockito.verify(tlsSocketStrategy, Mockito.times(2)).upgrade(socket, "somehost", 8443, tlsConfig, context);
Mockito.verify(tlsSocketStrategy, Mockito.times(2)).upgrade(socket, "somehost", 443, tlsConfig, context);
}
@Test
@ -458,9 +458,8 @@ public class TestBasicHttpClientConnectionManager {
mgr.upgrade(endpoint1, context);
Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target.getSchemeName(), target);
Mockito.verify(tlsSocketStrategy, Mockito.times(1)).upgrade(
socket, "somehost", 8443, tlsConfig, context);
socket, "somehost", 443, tlsConfig, context);
}

View File

@ -102,7 +102,7 @@ public class TestHttpClientConnectionOperator {
.setSoLinger(50, TimeUnit.MILLISECONDS)
.build();
final InetSocketAddress localAddress = new InetSocketAddress(local, 0);
connectionOperator.connect(conn, host, localAddress, Timeout.ofMilliseconds(123), socketConfig, null, context);
connectionOperator.connect(conn, host, null, localAddress, Timeout.ofMilliseconds(123), socketConfig, null, context);
Mockito.verify(socket).setKeepAlive(true);
Mockito.verify(socket).setReuseAddress(true);
@ -137,17 +137,17 @@ public class TestHttpClientConnectionOperator {
Mockito.when(tlsSocketStrategy.upgrade(
Mockito.same(socket),
Mockito.eq("somehost"),
Mockito.eq(443),
Mockito.anyInt(),
Mockito.any(),
Mockito.any())).thenReturn(upgradedSocket);
final InetSocketAddress localAddress = new InetSocketAddress(local, 0);
connectionOperator.connect(conn, host, localAddress,
connectionOperator.connect(conn, host, null, localAddress,
Timeout.ofMilliseconds(123), SocketConfig.DEFAULT, tlsConfig, context);
Mockito.verify(socket).connect(new InetSocketAddress(ip1, 443), 123);
Mockito.verify(conn, Mockito.times(2)).bind(socket);
Mockito.verify(tlsSocketStrategy).upgrade(socket, "somehost", 443, tlsConfig, context);
Mockito.verify(tlsSocketStrategy).upgrade(socket, "somehost", -1, tlsConfig, context);
Mockito.verify(conn, Mockito.times(1)).bind(upgradedSocket);
}
@ -203,7 +203,7 @@ public class TestHttpClientConnectionOperator {
final InetSocketAddress localAddress = new InetSocketAddress(local, 0);
final TlsConfig tlsConfig = TlsConfig.custom()
.build();
connectionOperator.connect(conn, host, localAddress,
connectionOperator.connect(conn, host, null, localAddress,
Timeout.ofMilliseconds(123), SocketConfig.DEFAULT, tlsConfig, context);
Mockito.verify(socket, Mockito.times(2)).bind(localAddress);
@ -225,7 +225,7 @@ public class TestHttpClientConnectionOperator {
final InetSocketAddress localAddress = new InetSocketAddress(local, 0);
final TlsConfig tlsConfig = TlsConfig.custom()
.build();
connectionOperator.connect(conn, host, localAddress,
connectionOperator.connect(conn, host, null, localAddress,
Timeout.ofMilliseconds(123), SocketConfig.DEFAULT, tlsConfig, context);
Mockito.verify(socket).bind(localAddress);
@ -242,17 +242,16 @@ public class TestHttpClientConnectionOperator {
Mockito.when(conn.isOpen()).thenReturn(true);
Mockito.when(conn.getSocket()).thenReturn(socket);
Mockito.when(tlsSocketStrategyLookup.lookup("https")).thenReturn(tlsSocketStrategy);
Mockito.when(schemePortResolver.resolve(host.getSchemeName(), host)).thenReturn(443);
final SSLSocket upgradedSocket = Mockito.mock(SSLSocket.class);
Mockito.when(tlsSocketStrategy.upgrade(
Mockito.any(),
Mockito.eq("somehost"),
Mockito.eq(443),
Mockito.anyInt(),
Mockito.eq(Timeout.ofMilliseconds(345)),
Mockito.any())).thenReturn(upgradedSocket);
connectionOperator.upgrade(conn, host, Timeout.ofMilliseconds(345), context);
connectionOperator.upgrade(conn, host, null, Timeout.ofMilliseconds(345), context);
Mockito.verify(conn).bind(upgradedSocket);
}

View File

@ -270,7 +270,7 @@ public class TestPoolingHttpClientConnectionManager {
Mockito.when(tlsSocketStrategy.upgrade(
Mockito.same(socket),
Mockito.eq("somehost"),
Mockito.eq(8443),
Mockito.anyInt(),
Mockito.any(),
Mockito.any())).thenReturn(upgradedSocket);
@ -280,7 +280,7 @@ public class TestPoolingHttpClientConnectionManager {
Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target.getSchemeName(), target);
Mockito.verify(detachedSocketFactory, Mockito.times(1)).create(null);
Mockito.verify(socket, Mockito.times(1)).connect(new InetSocketAddress(remote, 8443), 234);
Mockito.verify(tlsSocketStrategy).upgrade(socket, "somehost", 8443, tlsConfig, context);
Mockito.verify(tlsSocketStrategy).upgrade(socket, "somehost", 443, tlsConfig, context);
mgr.connect(endpoint1, TimeValue.ofMilliseconds(123), context);
@ -288,7 +288,7 @@ public class TestPoolingHttpClientConnectionManager {
Mockito.verify(schemePortResolver, Mockito.times(2)).resolve(target.getSchemeName(), target);
Mockito.verify(detachedSocketFactory, Mockito.times(2)).create(null);
Mockito.verify(socket, Mockito.times(1)).connect(new InetSocketAddress(remote, 8443), 123);
Mockito.verify(tlsSocketStrategy, Mockito.times(2)).upgrade(socket, "somehost", 8443, tlsConfig, context);
Mockito.verify(tlsSocketStrategy, Mockito.times(2)).upgrade(socket, "somehost", 443, tlsConfig, context);
}
@Test
@ -347,9 +347,8 @@ public class TestPoolingHttpClientConnectionManager {
mgr.upgrade(endpoint1, context);
Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target.getSchemeName(), target);
Mockito.verify(tlsSocketStrategy, Mockito.times(1)).upgrade(
socket, "somehost", 8443, tlsConfig, context);
socket, "somehost", 443, tlsConfig, context);
}
}