diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/build.gradle b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/build.gradle index 6bcba07f56..4ead0f7327 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/build.gradle +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/build.gradle @@ -11,9 +11,7 @@ dependencies { api("com.fasterxml.jackson.module:jackson-module-parameter-names") api("net.java.dev.jna:jna-platform") api("org.apache.commons:commons-compress:1.19") - api("org.apache.httpcomponents:httpclient") { - exclude(group: "commons-logging", module: "commons-logging") - } + api("org.apache.httpcomponents.client5:httpclient5") api("org.springframework:spring-core") api("org.tomlj:tomlj:1.0.0") diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerApi.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerApi.java index 6ebdfb8fa7..c8b7fda0c2 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerApi.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerApi.java @@ -26,7 +26,7 @@ import java.util.List; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; -import org.apache.http.client.utils.URIBuilder; +import org.apache.hc.core5.net.URIBuilder; import org.springframework.boot.buildpack.platform.docker.configuration.DockerHost; import org.springframework.boot.buildpack.platform.docker.transport.HttpTransport; diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/HttpClientTransport.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/HttpClientTransport.java index 6c4ea53db2..bf2aa2982b 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/HttpClientTransport.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/HttpClientTransport.java @@ -21,20 +21,20 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URI; +import java.net.URISyntaxException; -import org.apache.http.HttpEntity; -import org.apache.http.HttpHost; -import org.apache.http.StatusLine; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpDelete; -import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.methods.HttpPut; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.entity.AbstractHttpEntity; -import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.hc.client5.http.classic.HttpClient; +import org.apache.hc.client5.http.classic.methods.HttpDelete; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.classic.methods.HttpPut; +import org.apache.hc.client5.http.classic.methods.HttpUriRequest; +import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.io.entity.AbstractHttpEntity; +import org.apache.hc.core5.http.message.StatusLine; import org.springframework.boot.buildpack.platform.io.Content; import org.springframework.boot.buildpack.platform.io.IOConsumer; @@ -54,11 +54,11 @@ abstract class HttpClientTransport implements HttpTransport { static final String REGISTRY_AUTH_HEADER = "X-Registry-Auth"; - private final CloseableHttpClient client; + private final HttpClient client; private final HttpHost host; - protected HttpClientTransport(CloseableHttpClient client, HttpHost host) { + protected HttpClientTransport(HttpClient client, HttpHost host) { Assert.notNull(client, "Client must not be null"); Assert.notNull(host, "Host must not be null"); this.client = client; @@ -130,13 +130,12 @@ abstract class HttpClientTransport implements HttpTransport { return execute(new HttpDelete(uri)); } - private Response execute(HttpEntityEnclosingRequestBase request, String contentType, - IOConsumer writer) { + private Response execute(HttpUriRequestBase request, String contentType, IOConsumer writer) { request.setEntity(new WritableHttpEntity(contentType, writer)); return execute(request); } - private Response execute(HttpEntityEnclosingRequestBase request, String registryAuth) { + private Response execute(HttpUriRequestBase request, String registryAuth) { if (StringUtils.hasText(registryAuth)) { request.setHeader(REGISTRY_AUTH_HEADER, registryAuth); } @@ -145,19 +144,19 @@ abstract class HttpClientTransport implements HttpTransport { private Response execute(HttpUriRequest request) { try { - CloseableHttpResponse response = this.client.execute(this.host, request); - StatusLine statusLine = response.getStatusLine(); - int statusCode = statusLine.getStatusCode(); - HttpEntity entity = response.getEntity(); + ClassicHttpResponse response = this.client.execute(this.host, request); + int statusCode = response.getCode(); if (statusCode >= 400 && statusCode <= 500) { + HttpEntity entity = response.getEntity(); Errors errors = (statusCode != 500) ? getErrorsFromResponse(entity) : null; Message message = getMessageFromResponse(entity); - throw new DockerEngineException(this.host.toHostString(), request.getURI(), statusCode, + StatusLine statusLine = new StatusLine(response); + throw new DockerEngineException(this.host.toHostString(), request.getUri(), statusCode, statusLine.getReasonPhrase(), errors, message); } return new HttpClientResponse(response); } - catch (IOException ex) { + catch (IOException | URISyntaxException ex) { throw new DockerConnectionException(this.host.toHostString(), ex); } } @@ -193,7 +192,7 @@ abstract class HttpClientTransport implements HttpTransport { private final IOConsumer writer; WritableHttpEntity(String contentType, IOConsumer writer) { - setContentType(contentType); + super(contentType, "UTF-8"); this.writer = writer; } @@ -204,7 +203,7 @@ abstract class HttpClientTransport implements HttpTransport { @Override public long getContentLength() { - if (this.contentType != null && this.contentType.getValue().equals("application/json")) { + if (this.getContentType() != null && this.getContentType().equals("application/json")) { return calculateStringContentLength(); } return -1; @@ -236,6 +235,10 @@ abstract class HttpClientTransport implements HttpTransport { } } + @Override + public void close() throws IOException { + } + } /** @@ -243,9 +246,9 @@ abstract class HttpClientTransport implements HttpTransport { */ private static class HttpClientResponse implements Response { - private final CloseableHttpResponse response; + private final ClassicHttpResponse response; - HttpClientResponse(CloseableHttpResponse response) { + HttpClientResponse(ClassicHttpResponse response) { this.response = response; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/LocalHttpClientTransport.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/LocalHttpClientTransport.java index 297160cff3..8389d8655e 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/LocalHttpClientTransport.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/LocalHttpClientTransport.java @@ -20,23 +20,24 @@ import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; +import java.net.URISyntaxException; import java.net.UnknownHostException; import com.sun.jna.Platform; -import org.apache.http.HttpHost; -import org.apache.http.config.Registry; -import org.apache.http.config.RegistryBuilder; -import org.apache.http.conn.DnsResolver; -import org.apache.http.conn.HttpClientConnectionManager; -import org.apache.http.conn.SchemePortResolver; -import org.apache.http.conn.UnsupportedSchemeException; -import org.apache.http.conn.socket.ConnectionSocketFactory; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.impl.conn.BasicHttpClientConnectionManager; -import org.apache.http.protocol.HttpContext; -import org.apache.http.util.Args; +import org.apache.hc.client5.http.DnsResolver; +import org.apache.hc.client5.http.SchemePortResolver; +import org.apache.hc.client5.http.classic.HttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.BasicHttpClientConnectionManager; +import org.apache.hc.client5.http.io.HttpClientConnectionManager; +import org.apache.hc.client5.http.socket.ConnectionSocketFactory; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.config.Registry; +import org.apache.hc.core5.http.config.RegistryBuilder; +import org.apache.hc.core5.http.protocol.HttpContext; +import org.apache.hc.core5.util.Args; +import org.apache.hc.core5.util.TimeValue; import org.springframework.boot.buildpack.platform.docker.configuration.ResolvedDockerHost; import org.springframework.boot.buildpack.platform.socket.DomainSocket; @@ -50,9 +51,18 @@ import org.springframework.boot.buildpack.platform.socket.NamedPipeSocket; */ final class LocalHttpClientTransport extends HttpClientTransport { - private static final HttpHost LOCAL_DOCKER_HOST = HttpHost.create("docker://localhost"); + private static final HttpHost LOCAL_DOCKER_HOST; - private LocalHttpClientTransport(CloseableHttpClient client) { + static { + try { + LOCAL_DOCKER_HOST = HttpHost.create("docker://localhost"); + } + catch (URISyntaxException ex) { + throw new RuntimeException("Error creating local Docker host address", ex); + } + } + + private LocalHttpClientTransport(HttpClient client) { super(client, LOCAL_DOCKER_HOST); } @@ -85,11 +95,16 @@ final class LocalHttpClientTransport extends HttpClientTransport { */ private static class LocalDnsResolver implements DnsResolver { - private static final InetAddress[] LOOPBACK = new InetAddress[] { InetAddress.getLoopbackAddress() }; + private static final InetAddress LOOPBACK = InetAddress.getLoopbackAddress(); @Override public InetAddress[] resolve(String host) throws UnknownHostException { - return LOOPBACK; + return new InetAddress[] { LOOPBACK }; + } + + @Override + public String resolveCanonicalHostname(String host) throws UnknownHostException { + return LOOPBACK.getCanonicalHostName(); } } @@ -115,9 +130,10 @@ final class LocalHttpClientTransport extends HttpClientTransport { } @Override - public Socket connectSocket(int connectTimeout, Socket sock, HttpHost host, InetSocketAddress remoteAddress, - InetSocketAddress localAddress, HttpContext context) throws IOException { - return sock; + public Socket connectSocket(TimeValue connectTimeout, Socket socket, HttpHost host, + InetSocketAddress remoteAddress, InetSocketAddress localAddress, HttpContext context) + throws IOException { + return socket; } } @@ -130,13 +146,13 @@ final class LocalHttpClientTransport extends HttpClientTransport { private static final int DEFAULT_DOCKER_PORT = 2376; @Override - public int resolve(HttpHost host) throws UnsupportedSchemeException { + public int resolve(HttpHost host) { Args.notNull(host, "HTTP host"); String name = host.getSchemeName(); if ("docker".equals(name)) { return DEFAULT_DOCKER_PORT; } - throw new UnsupportedSchemeException(name + " protocol is not supported"); + return -1; } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransport.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransport.java index 26453f49aa..1dcc688991 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransport.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransport.java @@ -16,14 +16,18 @@ package org.springframework.boot.buildpack.platform.docker.transport; +import java.net.URISyntaxException; + import javax.net.ssl.SSLContext; -import org.apache.http.HttpHost; -import org.apache.http.conn.socket.LayeredConnectionSocketFactory; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.HttpClients; +import org.apache.hc.client5.http.classic.HttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; +import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; +import org.apache.hc.core5.http.HttpHost; import org.springframework.boot.buildpack.platform.docker.configuration.DockerHost; import org.springframework.boot.buildpack.platform.docker.configuration.ResolvedDockerHost; @@ -38,7 +42,7 @@ import org.springframework.util.Assert; */ final class RemoteHttpClientTransport extends HttpClientTransport { - private RemoteHttpClientTransport(CloseableHttpClient client, HttpHost host) { + private RemoteHttpClientTransport(HttpClient client, HttpHost host) { super(client, host); } @@ -51,17 +55,24 @@ final class RemoteHttpClientTransport extends HttpClientTransport { if (!dockerHost.isRemote()) { return null; } - return create(dockerHost, sslContextFactory, HttpHost.create(dockerHost.getAddress())); + try { + return create(dockerHost, sslContextFactory, HttpHost.create(dockerHost.getAddress())); + } + catch (URISyntaxException ex) { + return null; + } } private static RemoteHttpClientTransport create(DockerHost host, SslContextFactory sslContextFactory, HttpHost tcpHost) { HttpClientBuilder builder = HttpClients.custom(); if (host.isSecure()) { - builder.setSSLSocketFactory(getSecureConnectionSocketFactory(host, sslContextFactory)); + PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create() + .setSSLSocketFactory(getSecureConnectionSocketFactory(host, sslContextFactory)).build(); + builder.setConnectionManager(connectionManager); } String scheme = host.isSecure() ? "https" : "http"; - HttpHost httpHost = new HttpHost(tcpHost.getHostName(), tcpHost.getPort(), scheme); + HttpHost httpHost = new HttpHost(scheme, tcpHost.getHostName(), tcpHost.getPort()); return new RemoteHttpClientTransport(builder.build(), httpHost); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/HttpClientTransportTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/HttpClientTransportTests.java index b415e5ed4a..2f77941c5d 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/HttpClientTransportTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/HttpClientTransportTests.java @@ -20,21 +20,19 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URI; +import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; -import org.apache.http.HttpEntity; -import org.apache.http.HttpEntityEnclosingRequest; -import org.apache.http.HttpHeaders; -import org.apache.http.HttpHost; -import org.apache.http.HttpRequest; -import org.apache.http.StatusLine; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpDelete; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.methods.HttpPut; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.hc.client5.http.classic.HttpClient; +import org.apache.hc.client5.http.classic.methods.HttpDelete; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.classic.methods.HttpPut; +import org.apache.hc.client5.http.classic.methods.HttpUriRequest; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.HttpHeaders; +import org.apache.hc.core5.http.HttpHost; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -67,13 +65,10 @@ class HttpClientTransportTests { private static final String APPLICATION_X_TAR = "application/x-tar"; @Mock - private CloseableHttpClient client; + private HttpClient client; @Mock - private CloseableHttpResponse response; - - @Mock - private StatusLine statusLine; + private ClassicHttpResponse response; @Mock private HttpEntity entity; @@ -101,12 +96,12 @@ class HttpClientTransportTests { void getShouldExecuteHttpGet() throws Exception { givenClientWillReturnResponse(); given(this.entity.getContent()).willReturn(this.content); - given(this.statusLine.getStatusCode()).willReturn(200); + given(this.response.getCode()).willReturn(200); Response response = this.http.get(this.uri); then(this.client).should().execute(this.hostCaptor.capture(), this.requestCaptor.capture()); HttpUriRequest request = this.requestCaptor.getValue(); assertThat(request).isInstanceOf(HttpGet.class); - assertThat(request.getURI()).isEqualTo(this.uri); + assertThat(request.getUri()).isEqualTo(this.uri); assertThat(request.getFirstHeader(HttpHeaders.CONTENT_TYPE)).isNull(); assertThat(response.getContent()).isSameAs(this.content); } @@ -115,12 +110,12 @@ class HttpClientTransportTests { void postShouldExecuteHttpPost() throws Exception { givenClientWillReturnResponse(); given(this.entity.getContent()).willReturn(this.content); - given(this.statusLine.getStatusCode()).willReturn(200); + given(this.response.getCode()).willReturn(200); Response response = this.http.post(this.uri); then(this.client).should().execute(this.hostCaptor.capture(), this.requestCaptor.capture()); HttpUriRequest request = this.requestCaptor.getValue(); assertThat(request).isInstanceOf(HttpPost.class); - assertThat(request.getURI()).isEqualTo(this.uri); + assertThat(request.getUri()).isEqualTo(this.uri); assertThat(request.getFirstHeader(HttpHeaders.CONTENT_TYPE)).isNull(); assertThat(request.getFirstHeader(HttpClientTransport.REGISTRY_AUTH_HEADER)).isNull(); assertThat(response.getContent()).isSameAs(this.content); @@ -130,12 +125,12 @@ class HttpClientTransportTests { void postWithRegistryAuthShouldExecuteHttpPostWithHeader() throws Exception { givenClientWillReturnResponse(); given(this.entity.getContent()).willReturn(this.content); - given(this.statusLine.getStatusCode()).willReturn(200); + given(this.response.getCode()).willReturn(200); Response response = this.http.post(this.uri, "auth token"); then(this.client).should().execute(this.hostCaptor.capture(), this.requestCaptor.capture()); HttpUriRequest request = this.requestCaptor.getValue(); assertThat(request).isInstanceOf(HttpPost.class); - assertThat(request.getURI()).isEqualTo(this.uri); + assertThat(request.getUri()).isEqualTo(this.uri); assertThat(request.getFirstHeader(HttpHeaders.CONTENT_TYPE)).isNull(); assertThat(request.getFirstHeader(HttpClientTransport.REGISTRY_AUTH_HEADER).getValue()).isEqualTo("auth token"); assertThat(response.getContent()).isSameAs(this.content); @@ -145,12 +140,12 @@ class HttpClientTransportTests { void postWithEmptyRegistryAuthShouldExecuteHttpPostWithoutHeader() throws Exception { givenClientWillReturnResponse(); given(this.entity.getContent()).willReturn(this.content); - given(this.statusLine.getStatusCode()).willReturn(200); + given(this.response.getCode()).willReturn(200); Response response = this.http.post(this.uri, ""); then(this.client).should().execute(this.hostCaptor.capture(), this.requestCaptor.capture()); HttpUriRequest request = this.requestCaptor.getValue(); assertThat(request).isInstanceOf(HttpPost.class); - assertThat(request.getURI()).isEqualTo(this.uri); + assertThat(request.getUri()).isEqualTo(this.uri); assertThat(request.getFirstHeader(HttpHeaders.CONTENT_TYPE)).isNull(); assertThat(request.getFirstHeader(HttpClientTransport.REGISTRY_AUTH_HEADER)).isNull(); assertThat(response.getContent()).isSameAs(this.content); @@ -161,17 +156,17 @@ class HttpClientTransportTests { String content = "test"; givenClientWillReturnResponse(); given(this.entity.getContent()).willReturn(this.content); - given(this.statusLine.getStatusCode()).willReturn(200); + given(this.response.getCode()).willReturn(200); Response response = this.http.post(this.uri, APPLICATION_JSON, (out) -> StreamUtils.copy(content, StandardCharsets.UTF_8, out)); then(this.client).should().execute(this.hostCaptor.capture(), this.requestCaptor.capture()); HttpUriRequest request = this.requestCaptor.getValue(); - HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity(); + HttpEntity entity = request.getEntity(); assertThat(request).isInstanceOf(HttpPost.class); - assertThat(request.getURI()).isEqualTo(this.uri); + assertThat(request.getUri()).isEqualTo(this.uri); assertThat(entity.isRepeatable()).isFalse(); assertThat(entity.getContentLength()).isEqualTo(content.length()); - assertThat(entity.getContentType().getValue()).isEqualTo(APPLICATION_JSON); + assertThat(entity.getContentType()).isEqualTo(APPLICATION_JSON); assertThat(entity.isStreaming()).isTrue(); assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(entity::getContent); assertThat(writeToString(entity)).isEqualTo(content); @@ -183,17 +178,17 @@ class HttpClientTransportTests { String content = "test"; givenClientWillReturnResponse(); given(this.entity.getContent()).willReturn(this.content); - given(this.statusLine.getStatusCode()).willReturn(200); + given(this.response.getCode()).willReturn(200); Response response = this.http.post(this.uri, APPLICATION_X_TAR, (out) -> StreamUtils.copy(content, StandardCharsets.UTF_8, out)); then(this.client).should().execute(this.hostCaptor.capture(), this.requestCaptor.capture()); HttpUriRequest request = this.requestCaptor.getValue(); - HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity(); + HttpEntity entity = request.getEntity(); assertThat(request).isInstanceOf(HttpPost.class); - assertThat(request.getURI()).isEqualTo(this.uri); + assertThat(request.getUri()).isEqualTo(this.uri); assertThat(entity.isRepeatable()).isFalse(); assertThat(entity.getContentLength()).isEqualTo(-1); - assertThat(entity.getContentType().getValue()).isEqualTo(APPLICATION_X_TAR); + assertThat(entity.getContentType()).isEqualTo(APPLICATION_X_TAR); assertThat(entity.isStreaming()).isTrue(); assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(entity::getContent); assertThat(writeToString(entity)).isEqualTo(content); @@ -205,17 +200,17 @@ class HttpClientTransportTests { String content = "test"; givenClientWillReturnResponse(); given(this.entity.getContent()).willReturn(this.content); - given(this.statusLine.getStatusCode()).willReturn(200); + given(this.response.getCode()).willReturn(200); Response response = this.http.put(this.uri, APPLICATION_JSON, (out) -> StreamUtils.copy(content, StandardCharsets.UTF_8, out)); then(this.client).should().execute(this.hostCaptor.capture(), this.requestCaptor.capture()); HttpUriRequest request = this.requestCaptor.getValue(); - HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity(); + HttpEntity entity = request.getEntity(); assertThat(request).isInstanceOf(HttpPut.class); - assertThat(request.getURI()).isEqualTo(this.uri); + assertThat(request.getUri()).isEqualTo(this.uri); assertThat(entity.isRepeatable()).isFalse(); assertThat(entity.getContentLength()).isEqualTo(content.length()); - assertThat(entity.getContentType().getValue()).isEqualTo(APPLICATION_JSON); + assertThat(entity.getContentType()).isEqualTo(APPLICATION_JSON); assertThat(entity.isStreaming()).isTrue(); assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(entity::getContent); assertThat(writeToString(entity)).isEqualTo(content); @@ -227,17 +222,17 @@ class HttpClientTransportTests { String content = "test"; givenClientWillReturnResponse(); given(this.entity.getContent()).willReturn(this.content); - given(this.statusLine.getStatusCode()).willReturn(200); + given(this.response.getCode()).willReturn(200); Response response = this.http.put(this.uri, APPLICATION_X_TAR, (out) -> StreamUtils.copy(content, StandardCharsets.UTF_8, out)); then(this.client).should().execute(this.hostCaptor.capture(), this.requestCaptor.capture()); HttpUriRequest request = this.requestCaptor.getValue(); - HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity(); + HttpEntity entity = request.getEntity(); assertThat(request).isInstanceOf(HttpPut.class); - assertThat(request.getURI()).isEqualTo(this.uri); + assertThat(request.getUri()).isEqualTo(this.uri); assertThat(entity.isRepeatable()).isFalse(); assertThat(entity.getContentLength()).isEqualTo(-1); - assertThat(entity.getContentType().getValue()).isEqualTo(APPLICATION_X_TAR); + assertThat(entity.getContentType()).isEqualTo(APPLICATION_X_TAR); assertThat(entity.isStreaming()).isTrue(); assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(entity::getContent); assertThat(writeToString(entity)).isEqualTo(content); @@ -245,15 +240,15 @@ class HttpClientTransportTests { } @Test - void deleteShouldExecuteHttpDelete() throws IOException { + void deleteShouldExecuteHttpDelete() throws Exception { givenClientWillReturnResponse(); given(this.entity.getContent()).willReturn(this.content); - given(this.statusLine.getStatusCode()).willReturn(200); + given(this.response.getCode()).willReturn(200); Response response = this.http.delete(this.uri); then(this.client).should().execute(this.hostCaptor.capture(), this.requestCaptor.capture()); HttpUriRequest request = this.requestCaptor.getValue(); assertThat(request).isInstanceOf(HttpDelete.class); - assertThat(request.getURI()).isEqualTo(this.uri); + assertThat(request.getUri()).isEqualTo(this.uri); assertThat(request.getFirstHeader(HttpHeaders.CONTENT_TYPE)).isNull(); assertThat(response.getContent()).isSameAs(this.content); } @@ -262,7 +257,7 @@ class HttpClientTransportTests { void executeWhenResponseIsIn400RangeShouldThrowDockerException() throws IOException { givenClientWillReturnResponse(); given(this.entity.getContent()).willReturn(getClass().getResourceAsStream("errors.json")); - given(this.statusLine.getStatusCode()).willReturn(404); + given(this.response.getCode()).willReturn(404); assertThatExceptionOfType(DockerEngineException.class).isThrownBy(() -> this.http.get(this.uri)) .satisfies((ex) -> { assertThat(ex.getErrors()).hasSize(2); @@ -273,7 +268,7 @@ class HttpClientTransportTests { @Test void executeWhenResponseIsIn500RangeWithNoContentShouldThrowDockerException() throws IOException { givenClientWillReturnResponse(); - given(this.statusLine.getStatusCode()).willReturn(500); + given(this.response.getCode()).willReturn(500); assertThatExceptionOfType(DockerEngineException.class).isThrownBy(() -> this.http.get(this.uri)) .satisfies((ex) -> { assertThat(ex.getErrors()).isNull(); @@ -285,7 +280,7 @@ class HttpClientTransportTests { void executeWhenResponseIsIn500RangeWithMessageShouldThrowDockerException() throws IOException { givenClientWillReturnResponse(); given(this.entity.getContent()).willReturn(getClass().getResourceAsStream("message.json")); - given(this.statusLine.getStatusCode()).willReturn(500); + given(this.response.getCode()).willReturn(500); assertThatExceptionOfType(DockerEngineException.class).isThrownBy(() -> this.http.get(this.uri)) .satisfies((ex) -> { assertThat(ex.getErrors()).isNull(); @@ -297,7 +292,7 @@ class HttpClientTransportTests { void executeWhenResponseIsIn500RangeWithOtherContentShouldThrowDockerException() throws IOException { givenClientWillReturnResponse(); given(this.entity.getContent()).willReturn(this.content); - given(this.statusLine.getStatusCode()).willReturn(500); + given(this.response.getCode()).willReturn(500); assertThatExceptionOfType(DockerEngineException.class).isThrownBy(() -> this.http.get(this.uri)) .satisfies((ex) -> { assertThat(ex.getErrors()).isNull(); @@ -307,7 +302,7 @@ class HttpClientTransportTests { @Test void executeWhenClientThrowsIOExceptionRethrowsAsDockerException() throws IOException { - given(this.client.execute(any(HttpHost.class), any(HttpRequest.class))) + given(this.client.execute(any(HttpHost.class), any(HttpUriRequest.class))) .willThrow(new IOException("test IO exception")); assertThatExceptionOfType(DockerConnectionException.class).isThrownBy(() -> this.http.get(this.uri)) .satisfies((ex) -> assertThat(ex.getMessage()).contains("test IO exception")); @@ -320,9 +315,8 @@ class HttpClientTransportTests { } private void givenClientWillReturnResponse() throws IOException { - given(this.client.execute(any(HttpHost.class), any(HttpRequest.class))).willReturn(this.response); + given(this.client.execute(any(HttpHost.class), any(HttpUriRequest.class))).willReturn(this.response); given(this.response.getEntity()).willReturn(this.entity); - given(this.response.getStatusLine()).willReturn(this.statusLine); } /** @@ -330,7 +324,7 @@ class HttpClientTransportTests { */ static class TestHttpClientTransport extends HttpClientTransport { - protected TestHttpClientTransport(CloseableHttpClient client) { + protected TestHttpClientTransport(HttpClient client) throws URISyntaxException { super(client, HttpHost.create("docker://localhost")); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransportTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransportTests.java index 0bf2fb3685..d124f6c443 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransportTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransportTests.java @@ -20,7 +20,7 @@ import java.util.function.Consumer; import javax.net.ssl.SSLContext; -import org.apache.http.HttpHost; +import org.apache.hc.core5.http.HttpHost; import org.junit.jupiter.api.Test; import org.springframework.boot.buildpack.platform.docker.configuration.DockerHost; diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-test-support/src/main/java/org/springframework/boot/testsupport/gradle/testkit/GradleBuild.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-test-support/src/main/java/org/springframework/boot/testsupport/gradle/testkit/GradleBuild.java index b1fa01c228..0e8e0144c1 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-test-support/src/main/java/org/springframework/boot/testsupport/gradle/testkit/GradleBuild.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-test-support/src/main/java/org/springframework/boot/testsupport/gradle/testkit/GradleBuild.java @@ -41,8 +41,8 @@ import io.spring.gradle.dependencymanagement.DependencyManagementPlugin; import io.spring.gradle.dependencymanagement.dsl.DependencyManagementExtension; import org.antlr.v4.runtime.Lexer; import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.http.HttpRequest; -import org.apache.http.conn.HttpClientConnectionManager; +import org.apache.hc.client5.http.io.HttpClientConnectionManager; +import org.apache.hc.core5.http.HttpRequest; import org.gradle.testkit.runner.BuildResult; import org.gradle.testkit.runner.GradleRunner; import org.gradle.util.GradleVersion;