Skip to content

Commit

Permalink
Callbacks for Connection initialization
Browse files Browse the repository at this point in the history
  • Loading branch information
tippl committed Mar 16, 2024
1 parent ccff406 commit 12e53da
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import org.apache.hc.client5.http.config.TlsConfig;
import org.apache.hc.client5.http.impl.ConnPoolSupport;
import org.apache.hc.client5.http.impl.ConnectionShutdownException;
import org.apache.hc.client5.http.io.ConnectionCallback;
import org.apache.hc.client5.http.io.ConnectionEndpoint;
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
import org.apache.hc.client5.http.io.HttpClientConnectionOperator;
Expand Down Expand Up @@ -137,6 +138,20 @@ public BasicHttpClientConnectionManager(
this.lock = new ReentrantLock();
}

/**
* @since 5.4
*/
public static BasicHttpClientConnectionManager create(
final SchemePortResolver schemePortResolver,
final DnsResolver dnsResolver,
final Lookup<TlsSocketStrategy> tlsSocketStrategyRegistry,
final HttpConnectionFactory<ManagedHttpClientConnection> connFactory,
final ConnectionCallback connectionCallback) {
return new BasicHttpClientConnectionManager(
new DefaultHttpClientConnectionOperator(schemePortResolver, dnsResolver, tlsSocketStrategyRegistry, connectionCallback),
connFactory);
}

/**
* @since 5.4
*/
Expand All @@ -146,7 +161,7 @@ public static BasicHttpClientConnectionManager create(
final Lookup<TlsSocketStrategy> tlsSocketStrategyRegistry,
final HttpConnectionFactory<ManagedHttpClientConnection> connFactory) {
return new BasicHttpClientConnectionManager(
new DefaultHttpClientConnectionOperator(schemePortResolver, dnsResolver, tlsSocketStrategyRegistry),
new DefaultHttpClientConnectionOperator(schemePortResolver, dnsResolver, tlsSocketStrategyRegistry, null),
connFactory);
}

Expand All @@ -157,7 +172,7 @@ public static BasicHttpClientConnectionManager create(
final Lookup<TlsSocketStrategy> tlsSocketStrategyRegistry,
final HttpConnectionFactory<ManagedHttpClientConnection> connFactory) {
return new BasicHttpClientConnectionManager(
new DefaultHttpClientConnectionOperator(null, null, tlsSocketStrategyRegistry), connFactory);
new DefaultHttpClientConnectionOperator(null, null, tlsSocketStrategyRegistry, null), connFactory);
}

/**
Expand All @@ -166,7 +181,7 @@ public static BasicHttpClientConnectionManager create(
public static BasicHttpClientConnectionManager create(
final Lookup<TlsSocketStrategy> tlsSocketStrategyRegistry) {
return new BasicHttpClientConnectionManager(
new DefaultHttpClientConnectionOperator(null, null, tlsSocketStrategyRegistry), null);
new DefaultHttpClientConnectionOperator(null, null, tlsSocketStrategyRegistry, null), null);
}

/**
Expand Down Expand Up @@ -205,7 +220,7 @@ public BasicHttpClientConnectionManager() {
this(new DefaultHttpClientConnectionOperator(null, null,
RegistryBuilder.<TlsSocketStrategy>create()
.register(URIScheme.HTTPS.id, DefaultClientTlsStrategy.createDefault())
.build()),
.build(), null),
null);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import org.apache.hc.client5.http.UnsupportedSchemeException;
import org.apache.hc.client5.http.impl.ConnPoolSupport;
import org.apache.hc.client5.http.impl.DefaultSchemePortResolver;
import org.apache.hc.client5.http.io.ConnectionCallback;
import org.apache.hc.client5.http.io.DetachedSocketFactory;
import org.apache.hc.client5.http.io.HttpClientConnectionOperator;
import org.apache.hc.client5.http.io.ManagedHttpClientConnection;
Expand Down Expand Up @@ -91,6 +92,7 @@ public Socket create(final Proxy socksProxy) throws IOException {
private final Lookup<TlsSocketStrategy> tlsSocketStrategyLookup;
private final SchemePortResolver schemePortResolver;
private final DnsResolver dnsResolver;
private final ConnectionCallback connectionCallback;

/**
* @deprecated Provided for backward compatibility
Expand All @@ -111,14 +113,16 @@ public DefaultHttpClientConnectionOperator(
final DetachedSocketFactory detachedSocketFactory,
final SchemePortResolver schemePortResolver,
final DnsResolver dnsResolver,
final Lookup<TlsSocketStrategy> tlsSocketStrategyLookup) {
final Lookup<TlsSocketStrategy> tlsSocketStrategyLookup,
final ConnectionCallback connectionCallback) {
super();
this.detachedSocketFactory = Args.notNull(detachedSocketFactory, "Plain socket factory");
this.tlsSocketStrategyLookup = Args.notNull(tlsSocketStrategyLookup, "Socket factory registry");
this.schemePortResolver = schemePortResolver != null ? schemePortResolver :
DefaultSchemePortResolver.INSTANCE;
this.dnsResolver = dnsResolver != null ? dnsResolver :
SystemDefaultDnsResolver.INSTANCE;
this.connectionCallback = connectionCallback;
}

/**
Expand All @@ -129,14 +133,15 @@ public DefaultHttpClientConnectionOperator(
final Lookup<org.apache.hc.client5.http.socket.ConnectionSocketFactory> socketFactoryRegistry,
final SchemePortResolver schemePortResolver,
final DnsResolver dnsResolver) {
this(PLAIN_SOCKET_FACTORY, schemePortResolver, dnsResolver, adapt(socketFactoryRegistry));
this(PLAIN_SOCKET_FACTORY, schemePortResolver, dnsResolver, adapt(socketFactoryRegistry), null);
}

public DefaultHttpClientConnectionOperator(
final SchemePortResolver schemePortResolver,
final DnsResolver dnsResolver,
final Lookup<TlsSocketStrategy> tlsSocketStrategyLookup) {
this(PLAIN_SOCKET_FACTORY, schemePortResolver, dnsResolver, tlsSocketStrategyLookup);
final Lookup<TlsSocketStrategy> tlsSocketStrategyLookup,
final ConnectionCallback connectionCallback) {
this(PLAIN_SOCKET_FACTORY, schemePortResolver, dnsResolver, tlsSocketStrategyLookup, connectionCallback);
}

@Override
Expand Down Expand Up @@ -169,12 +174,18 @@ public void connect(
if (endpointHost.getAddress() != null) {
remoteAddresses = new InetAddress[] { endpointHost.getAddress() };
} else {
if (connectionCallback != null) {
connectionCallback.onBeforeDnsResolve(context);
}
if (LOG.isDebugEnabled()) {
LOG.debug("{} resolving remote address", endpointHost.getHostName());
}

remoteAddresses = this.dnsResolver.resolve(endpointHost.getHostName());

if (connectionCallback != null) {
connectionCallback.onAfterDnsResolve(context);
}
if (LOG.isDebugEnabled()) {
LOG.debug("{} resolved to {}", endpointHost.getHostName(), remoteAddresses == null ? "null" : Arrays.asList(remoteAddresses));
}
Expand All @@ -192,6 +203,9 @@ public void connect(
final InetAddress address = remoteAddresses[i];
final boolean last = i == remoteAddresses.length - 1;
final InetSocketAddress remoteAddress = new InetSocketAddress(address, port);
if (connectionCallback != null) {
connectionCallback.onBeforeSocketConnect(context, endpointHost);
}
if (LOG.isDebugEnabled()) {
LOG.debug("{} connecting {}->{} ({})", endpointHost, localAddress, remoteAddress, connectTimeout);
}
Expand Down Expand Up @@ -221,6 +235,9 @@ public void connect(
}
socket.connect(remoteAddress, TimeValue.isPositive(connectTimeout) ? connectTimeout.toMillisecondsIntBound() : 0);
conn.bind(socket);
if (connectionCallback != null) {
connectionCallback.onAfterSocketConnect(context, endpointHost);
}
if (LOG.isDebugEnabled()) {
LOG.debug("{} {} connected {}->{}", ConnPoolSupport.getId(conn), endpointHost,
conn.getLocalAddress(), conn.getRemoteAddress());
Expand All @@ -229,11 +246,20 @@ public void connect(
final TlsSocketStrategy tlsSocketStrategy = tlsSocketStrategyLookup != null ? tlsSocketStrategyLookup.lookup(endpointHost.getSchemeName()) : null;
if (tlsSocketStrategy != null) {
final NamedEndpoint tlsName = endpointName != null ? endpointName : endpointHost;
if (connectionCallback != null) {
connectionCallback.onBeforeTlsHandshake(context, 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);
if (connectionCallback != null) {
connectionCallback.onAfterTlsHandshake(context, endpointHost);
}
if (LOG.isDebugEnabled()) {
LOG.debug("{} {} upgraded to TLS", ConnPoolSupport.getId(conn), tlsName);
}
}
return;
} catch (final RuntimeException ex) {
Expand Down Expand Up @@ -278,11 +304,20 @@ public void upgrade(
final TlsSocketStrategy tlsSocketStrategy = tlsSocketStrategyLookup != null ? tlsSocketStrategyLookup.lookup(newProtocol) : null;
if (tlsSocketStrategy != null) {
final NamedEndpoint tlsName = endpointName != null ? endpointName : endpointHost;
if (connectionCallback != null) {
connectionCallback.onBeforeTlsHandshake(context, 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);
if (connectionCallback != null) {
connectionCallback.onAfterTlsHandshake(context, endpointHost);
}
if (LOG.isDebugEnabled()) {
LOG.debug("{} upgraded to TLS {}:{}", ConnPoolSupport.getId(conn), tlsName.getHostName(), tlsName.getPort());
}
} else {
throw new UnsupportedSchemeException(newProtocol + " protocol is not supported");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public PoolingHttpClientConnectionManager() {
this(new DefaultHttpClientConnectionOperator(null, null,
RegistryBuilder.<TlsSocketStrategy>create()
.register(URIScheme.HTTPS.id, DefaultClientTlsStrategy.createDefault())
.build()),
.build(), null),
PoolConcurrencyPolicy.STRICT,
PoolReusePolicy.LIFO,
TimeValue.NEG_ONE_MILLISECOND,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
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.ConnectionCallback;
import org.apache.hc.client5.http.io.ManagedHttpClientConnection;
import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
import org.apache.hc.client5.http.ssl.TlsSocketStrategy;
Expand Down Expand Up @@ -84,6 +85,7 @@ public class PoolingHttpClientConnectionManagerBuilder {
private Resolver<HttpRoute, SocketConfig> socketConfigResolver;
private Resolver<HttpRoute, ConnectionConfig> connectionConfigResolver;
private Resolver<HttpHost, TlsConfig> tlsConfigResolver;
private ConnectionCallback connectionCallback;

private boolean systemProperties;

Expand Down Expand Up @@ -237,6 +239,16 @@ public final PoolingHttpClientConnectionManagerBuilder setTlsConfigResolver(
return this;
}

/**
* Assigns {@link ConnectionCallback} instance.
*
* @since 5.4
*/
public final PoolingHttpClientConnectionManagerBuilder setConnectionCallback(final ConnectionCallback connectionCallback) {
this.connectionCallback = connectionCallback;
return this;
}

/**
* Sets maximum time to live for persistent connections
*
Expand Down Expand Up @@ -281,7 +293,8 @@ public PoolingHttpClientConnectionManager build() {
(systemProperties ?
DefaultClientTlsStrategy.createSystemDefault() :
DefaultClientTlsStrategy.createDefault()))
.build()),
.build(),
connectionCallback),
poolConcurrencyPolicy,
poolReusePolicy,
null,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* ====================================================================
* 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.io;

import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.protocol.HttpContext;

/**
* A callback interface that gets invoked upon different steps of connection initialization.
* Useful for measuring duration of initialization steps.
*
* @since 5.4
*/
public interface ConnectionCallback {

void onBeforeDnsResolve(HttpContext httpContext);

void onAfterDnsResolve(HttpContext httpContext);

void onBeforeSocketConnect(HttpContext httpContext, HttpHost endpointHost);

void onAfterSocketConnect(HttpContext httpContext, HttpHost endpointHost);

void onBeforeTlsHandshake(HttpContext httpContext, HttpHost endpointHost);

void onAfterTlsHandshake(HttpContext httpContext, HttpHost endpointHost);

}
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public class TestBasicHttpClientConnectionManager {
public void setup() throws Exception {
MockitoAnnotations.openMocks(this);
mgr = new BasicHttpClientConnectionManager(new DefaultHttpClientConnectionOperator(
detachedSocketFactory, schemePortResolver, dnsResolver, tlsSocketStrategyLookup),
detachedSocketFactory, schemePortResolver, dnsResolver, tlsSocketStrategyLookup, null),
connFactory);
}

Expand Down
Loading

0 comments on commit 12e53da

Please sign in to comment.