From c6d64afcb16c33d76431bd46f9443c3974f04a41 Mon Sep 17 00:00:00 2001 From: Dimitris Mandalidis Date: Sat, 21 Dec 2024 10:04:21 +0200 Subject: [PATCH] Switch to apache5 connector (fixes #817) --- CHANGELOG.md | 5 ++ pom.xml | 2 +- .../docker/client/DockerCertificates.java | 4 +- .../client/UnixConnectionSocketFactory.java | 24 ++++----- .../client/builder/DockerClientBuilder.java | 49 ++++++++++++------- .../npipe/NpipeConnectionSocketFactory.java | 15 +++--- .../NpipeConnectionSocketFactoryTest.java | 9 ++-- .../UnixConnectionSocketFactoryTest.java | 9 ++-- 8 files changed, 67 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 00c47014..5b758cb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,11 @@ to achieve JAX-RS version compatibility * **breaking** Google OAuth2 support was dropped * Users are advised to copy `ContainerRegistryAuthSupplier` from a `docker-client` 8.x version and maintain it on their own side. +* Switch to apache5 connector (fixes #817) +* Bump org.bouncycastle:bcpkix-jdk18on from 1.78.1 to 1.79 +* Bump com.fasterxml.jackson:jackson-bom from 2.18.0 to 2.18.2 +* Bump ch.qos.logback:logback-classic from 1.5.11 to 1.5.14 + ## 8.0.3 - notable changes diff --git a/pom.xml b/pom.xml index e60c455d..21c9c728 100644 --- a/pom.xml +++ b/pom.xml @@ -141,7 +141,7 @@ org.glassfish.jersey.connectors - jersey-apache-connector + jersey-apache5-connector ${version.jersey} diff --git a/src/main/java/org/mandas/docker/client/DockerCertificates.java b/src/main/java/org/mandas/docker/client/DockerCertificates.java index aaae2537..a82ce20e 100644 --- a/src/main/java/org/mandas/docker/client/DockerCertificates.java +++ b/src/main/java/org/mandas/docker/client/DockerCertificates.java @@ -53,8 +53,8 @@ import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; -import org.apache.http.conn.ssl.NoopHostnameVerifier; -import org.apache.http.ssl.SSLContexts; +import org.apache.hc.client5.http.ssl.NoopHostnameVerifier; +import org.apache.hc.core5.ssl.SSLContexts; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.openssl.PEMKeyPair; import org.bouncycastle.openssl.PEMParser; diff --git a/src/main/java/org/mandas/docker/client/UnixConnectionSocketFactory.java b/src/main/java/org/mandas/docker/client/UnixConnectionSocketFactory.java index d3f3e2a3..e22cd972 100644 --- a/src/main/java/org/mandas/docker/client/UnixConnectionSocketFactory.java +++ b/src/main/java/org/mandas/docker/client/UnixConnectionSocketFactory.java @@ -25,19 +25,19 @@ import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; -import java.net.SocketTimeoutException; import java.net.URI; +import org.apache.hc.client5.http.socket.ConnectionSocketFactory; +import org.apache.hc.core5.annotation.Contract; +import org.apache.hc.core5.annotation.ThreadingBehavior; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.protocol.HttpContext; +import org.apache.hc.core5.util.TimeValue; + import jnr.unixsocket.UnixSocket; import jnr.unixsocket.UnixSocketAddress; import jnr.unixsocket.UnixSocketChannel; -import org.apache.http.HttpHost; -import org.apache.http.annotation.Contract; -import org.apache.http.annotation.ThreadingBehavior; -import org.apache.http.conn.ConnectTimeoutException; -import org.apache.http.conn.socket.ConnectionSocketFactory; -import org.apache.http.protocol.HttpContext; /** * Provides a ConnectionSocketFactory for connecting Apache HTTP clients to Unix sockets. @@ -70,7 +70,7 @@ public UnixSocket createSocket(final HttpContext context) throws IOException { } @Override - public Socket connectSocket(final int connectTimeout, + public Socket connectSocket(final TimeValue connectTimeout, final Socket socket, final HttpHost host, final InetSocketAddress remoteAddress, @@ -80,12 +80,8 @@ public Socket connectSocket(final int connectTimeout, throw new AssertionError("Unexpected socket: " + socket); } - socket.setSoTimeout(connectTimeout); - try { - socket.getChannel().connect(new UnixSocketAddress(socketFile)); - } catch (SocketTimeoutException e) { - throw new ConnectTimeoutException(e, null, remoteAddress.getAddress()); - } + socket.setSoTimeout((int) connectTimeout.toDuration().toMillis()); + socket.getChannel().connect(new UnixSocketAddress(socketFile)); return socket; } } diff --git a/src/main/java/org/mandas/docker/client/builder/DockerClientBuilder.java b/src/main/java/org/mandas/docker/client/builder/DockerClientBuilder.java index 3b357056..9ac86a8a 100644 --- a/src/main/java/org/mandas/docker/client/builder/DockerClientBuilder.java +++ b/src/main/java/org/mandas/docker/client/builder/DockerClientBuilder.java @@ -32,22 +32,27 @@ import java.net.URI; import java.nio.file.Path; import java.nio.file.Paths; +import java.time.Duration; import java.util.HashMap; import java.util.Map; import java.util.NoSuchElementException; import java.util.Optional; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.config.Registry; -import org.apache.http.config.RegistryBuilder; -import org.apache.http.conn.HttpClientConnectionManager; -import org.apache.http.conn.socket.ConnectionSocketFactory; -import org.apache.http.conn.socket.PlainConnectionSocketFactory; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.impl.conn.BasicHttpClientConnectionManager; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; -import org.glassfish.jersey.apache.connector.ApacheClientProperties; -import org.glassfish.jersey.apache.connector.ApacheConnectorProvider; +import org.apache.hc.client5.http.config.ConnectionConfig; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.impl.DefaultHttpRequestRetryStrategy; +import org.apache.hc.client5.http.impl.io.BasicHttpClientConnectionManager; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; +import org.apache.hc.client5.http.io.HttpClientConnectionManager; +import org.apache.hc.client5.http.socket.ConnectionSocketFactory; +import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; +import org.apache.hc.core5.http.config.Registry; +import org.apache.hc.core5.http.config.RegistryBuilder; +import org.apache.hc.core5.util.TimeValue; +import org.apache.hc.core5.util.Timeout; +import org.glassfish.jersey.apache5.connector.Apache5ClientProperties; +import org.glassfish.jersey.apache5.connector.Apache5ConnectorProvider; import org.glassfish.jersey.client.ClientConfig; import org.glassfish.jersey.client.ClientProperties; import org.glassfish.jersey.client.RequestEntityProcessing; @@ -126,9 +131,8 @@ private Client createClient() { final HttpClientConnectionManager cm = getConnectionManager(uri, schemeRegistry, connectionPoolSize); final RequestConfig requestConfig = RequestConfig.custom() - .setConnectionRequestTimeout((int) connectTimeoutMillis) - .setConnectTimeout((int) connectTimeoutMillis) - .setSocketTimeout((int) readTimeoutMillis) + .setConnectionRequestTimeout(Timeout.of(Duration.ofMillis(connectTimeoutMillis))) + .setResponseTimeout(Timeout.of(Duration.ofMillis(readTimeoutMillis))) .build(); ClientConfig config = new ClientConfig(JacksonFeature.class); @@ -137,11 +141,14 @@ private Client createClient() { config = updateProxy(config); } + DefaultHttpRequestRetryStrategy retryStrategy = new DefaultHttpRequestRetryStrategy(0, TimeValue.ZERO_MILLISECONDS); + config - .connectorProvider(new ApacheConnectorProvider()) - .property(ApacheClientProperties.CONNECTION_MANAGER, cm) - .property(ApacheClientProperties.CONNECTION_MANAGER_SHARED, "true") - .property(ApacheClientProperties.REQUEST_CONFIG, requestConfig); + .connectorProvider(new Apache5ConnectorProvider()) + .property(Apache5ClientProperties.CONNECTION_MANAGER, cm) + .property(Apache5ClientProperties.CONNECTION_MANAGER_SHARED, "true") + .property(Apache5ClientProperties.REQUEST_CONFIG, requestConfig) + .property(Apache5ClientProperties.RETRY_STRATEGY, retryStrategy); if (entityProcessing != null) { switch (entityProcessing) { @@ -408,9 +415,15 @@ private HttpClientConnectionManager getConnectionManager(URI uri, Registry connectionConfig); cm.setDefaultMaxPerRoute(cm.getMaxTotal()); return cm; } diff --git a/src/main/java/org/mandas/docker/client/npipe/NpipeConnectionSocketFactory.java b/src/main/java/org/mandas/docker/client/npipe/NpipeConnectionSocketFactory.java index 52677245..8f7ba921 100644 --- a/src/main/java/org/mandas/docker/client/npipe/NpipeConnectionSocketFactory.java +++ b/src/main/java/org/mandas/docker/client/npipe/NpipeConnectionSocketFactory.java @@ -27,11 +27,12 @@ import java.net.Socket; import java.net.URI; -import org.apache.http.HttpHost; -import org.apache.http.annotation.Contract; -import org.apache.http.annotation.ThreadingBehavior; -import org.apache.http.conn.socket.ConnectionSocketFactory; -import org.apache.http.protocol.HttpContext; +import org.apache.hc.client5.http.socket.ConnectionSocketFactory; +import org.apache.hc.core5.annotation.Contract; +import org.apache.hc.core5.annotation.ThreadingBehavior; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.protocol.HttpContext; +import org.apache.hc.core5.util.TimeValue; /** * Provides a ConnectionSocketFactory for connecting Apache HTTP clients to windows named pipe. @@ -64,7 +65,7 @@ public Socket createSocket(final HttpContext context) throws IOException { } @Override - public Socket connectSocket(final int connectTimeout, + public Socket connectSocket(final TimeValue connectTimeout, final Socket socket, final HttpHost host, final InetSocketAddress remoteAddress, @@ -73,7 +74,7 @@ public Socket connectSocket(final int connectTimeout, if (!(socket instanceof NamedPipeSocket)) { throw new AssertionError("Unexpected socket: " + socket); } - socket.connect(new NpipeSocketAddress(socketFile), connectTimeout); + socket.connect(new NpipeSocketAddress(socketFile), (int) connectTimeout.toDuration().toMillis()); return socket; } } diff --git a/src/test/java/org/mandas/docker/client/NpipeConnectionSocketFactoryTest.java b/src/test/java/org/mandas/docker/client/NpipeConnectionSocketFactoryTest.java index 64ff9c21..9a4d3a1a 100644 --- a/src/test/java/org/mandas/docker/client/NpipeConnectionSocketFactoryTest.java +++ b/src/test/java/org/mandas/docker/client/NpipeConnectionSocketFactoryTest.java @@ -33,8 +33,9 @@ import javax.net.ssl.SSLSocket; -import org.apache.http.HttpHost; -import org.apache.http.protocol.HttpContext; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.protocol.HttpContext; +import org.apache.hc.core5.util.TimeValue; import org.hamcrest.core.IsInstanceOf; import org.junit.Before; import org.junit.Test; @@ -64,7 +65,7 @@ public void testSanitizeUri() throws Exception { public void testConnectSocket() throws Exception { final NamedPipeSocket npipeSocket = mock(NamedPipeSocket.class); when(npipeSocket.getChannel()).thenReturn(mock(SocketChannel.class)); - final Socket socket = sut.connectSocket(10, npipeSocket, HttpHost.create("http://foo.com"), + final Socket socket = sut.connectSocket(TimeValue.ofMilliseconds(10), npipeSocket, HttpHost.create("http://foo.com"), mock(InetSocketAddress.class), mock(InetSocketAddress.class), mock(HttpContext.class)); assertThat(socket, IsInstanceOf.instanceOf(NamedPipeSocket.class)); assertThat((NamedPipeSocket) socket, equalTo(npipeSocket)); @@ -72,7 +73,7 @@ public void testConnectSocket() throws Exception { @Test(expected = AssertionError.class) public void testConnectSocketNotUnixSocket() throws Exception { - sut.connectSocket(10, mock(SSLSocket.class), HttpHost.create("http://foo.com"), + sut.connectSocket(TimeValue.ofMilliseconds(10), mock(SSLSocket.class), HttpHost.create("http://foo.com"), mock(InetSocketAddress.class), mock(InetSocketAddress.class), mock(HttpContext.class)); } diff --git a/src/test/java/org/mandas/docker/client/UnixConnectionSocketFactoryTest.java b/src/test/java/org/mandas/docker/client/UnixConnectionSocketFactoryTest.java index ca6ea2b7..226f4a2a 100644 --- a/src/test/java/org/mandas/docker/client/UnixConnectionSocketFactoryTest.java +++ b/src/test/java/org/mandas/docker/client/UnixConnectionSocketFactoryTest.java @@ -34,8 +34,9 @@ import javax.net.ssl.SSLSocket; -import org.apache.http.HttpHost; -import org.apache.http.protocol.HttpContext; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.protocol.HttpContext; +import org.apache.hc.core5.util.TimeValue; import org.hamcrest.core.IsInstanceOf; import org.junit.Before; import org.junit.Test; @@ -65,7 +66,7 @@ public void testSanitizeUri() throws Exception { public void testConnectSocket() throws Exception { final UnixSocket unixSocket = mock(UnixSocket.class); when(unixSocket.getChannel()).thenReturn(mock(SocketChannel.class)); - final Socket socket = sut.connectSocket(10, unixSocket, HttpHost.create("http://foo.com"), + final Socket socket = sut.connectSocket(TimeValue.ofMilliseconds(10), unixSocket, HttpHost.create("http://foo.com"), mock(InetSocketAddress.class), mock(InetSocketAddress.class), mock(HttpContext.class)); verify(unixSocket).setSoTimeout(10); assertThat(socket, IsInstanceOf.instanceOf(UnixSocket.class)); @@ -74,7 +75,7 @@ public void testConnectSocket() throws Exception { @Test(expected = AssertionError.class) public void testConnectSocketNotUnixSocket() throws Exception { - sut.connectSocket(10, mock(SSLSocket.class), HttpHost.create("http://foo.com"), + sut.connectSocket(TimeValue.ofMilliseconds(10), mock(SSLSocket.class), HttpHost.create("http://foo.com"), mock(InetSocketAddress.class), mock(InetSocketAddress.class), mock(HttpContext.class)); }