From 29876f614cb760842c55bd25dcefa509899e3b41 Mon Sep 17 00:00:00 2001 From: IvanBorislavovDimitrov Date: Wed, 4 Jun 2025 13:29:56 +0300 Subject: [PATCH] Adopt apache http client 5 LMCROSSITXSADEPLOY-1549 --- multiapps-controller-core-test/pom.xml | 4 +- .../src/main/java/module-info.java | 4 +- .../controller/core/test/HttpClientMock.java | 23 ++-- .../controller/core/test/HttpMocks.java | 5 +- .../core/test/HttpResponseMock.java | 24 ++-- multiapps-controller-core/pom.xml | 4 + .../src/main/java/module-info.java | 4 +- .../CloudControllerHeaderConfiguration.java | 3 +- .../core/http/CookieSpecification.java | 45 ------ .../controller/core/http/CsrfHttpClient.java | 128 ++++++------------ .../core/http/HttpClientFactory.java | 96 ------------- .../core/http/TimeoutHttpExecutor.java | 45 ------ .../core/http/CsrfHttpClientTest.java | 98 ++++++++------ .../core/http/TimeoutHttpExecutorTest.java | 69 ---------- .../src/main/java/module-info.java | 4 +- .../client/ShutdownClientFactory.java | 44 ++++-- .../shutdown/client/ShutdownClientImpl.java | 17 ++- pom.xml | 12 +- 18 files changed, 172 insertions(+), 457 deletions(-) delete mode 100644 multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/http/CookieSpecification.java delete mode 100644 multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/http/HttpClientFactory.java delete mode 100644 multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/http/TimeoutHttpExecutor.java delete mode 100644 multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/http/TimeoutHttpExecutorTest.java diff --git a/multiapps-controller-core-test/pom.xml b/multiapps-controller-core-test/pom.xml index c036d3543b..05f651ce57 100644 --- a/multiapps-controller-core-test/pom.xml +++ b/multiapps-controller-core-test/pom.xml @@ -14,8 +14,8 @@ - org.apache.httpcomponents - httpclient + org.apache.httpcomponents.client5 + httpclient5 org.cloudfoundry.multiapps diff --git a/multiapps-controller-core-test/src/main/java/module-info.java b/multiapps-controller-core-test/src/main/java/module-info.java index 44e2856712..a8439a9498 100644 --- a/multiapps-controller-core-test/src/main/java/module-info.java +++ b/multiapps-controller-core-test/src/main/java/module-info.java @@ -2,10 +2,10 @@ exports org.cloudfoundry.multiapps.controller.core.test; - requires transitive org.apache.httpcomponents.httpcore; requires transitive org.cloudfoundry.multiapps.mta; - requires org.apache.httpcomponents.httpclient; + requires org.apache.httpcomponents.client5.httpclient5; + requires org.apache.httpcomponents.core5.httpcore5; requires org.cloudfoundry.multiapps.common; requires org.cloudfoundry.multiapps.common.test; requires org.junit.jupiter.api; diff --git a/multiapps-controller-core-test/src/main/java/org/cloudfoundry/multiapps/controller/core/test/HttpClientMock.java b/multiapps-controller-core-test/src/main/java/org/cloudfoundry/multiapps/controller/core/test/HttpClientMock.java index 70b2a6372a..e4863f63fc 100644 --- a/multiapps-controller-core-test/src/main/java/org/cloudfoundry/multiapps/controller/core/test/HttpClientMock.java +++ b/multiapps-controller-core-test/src/main/java/org/cloudfoundry/multiapps/controller/core/test/HttpClientMock.java @@ -2,12 +2,12 @@ import java.io.IOException; import java.util.List; - -import org.apache.http.HttpHost; -import org.apache.http.HttpResponse; -import org.apache.http.client.ResponseHandler; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.protocol.HttpContext; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.core5.http.ClassicHttpRequest; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.HttpResponse; +import org.apache.hc.core5.http.io.HttpClientResponseHandler; +import org.apache.hc.core5.http.protocol.HttpContext; import org.cloudfoundry.multiapps.common.Nullable; import org.immutables.value.Value; import org.mockito.ArgumentMatchers; @@ -23,9 +23,6 @@ public abstract class HttpClientMock { @Nullable public abstract Throwable getException(); - @Nullable - public abstract String getResponseHandlerReturnValue(); - @Value.Derived public CloseableHttpClient getMock() { try { @@ -49,12 +46,10 @@ public CloseableHttpClient getMock() { Mockito.when(httpClient.execute(ArgumentMatchers. any(), ArgumentMatchers.any(), ArgumentMatchers. any())) .thenAnswer(answer); + Mockito.when( + httpClient.execute(ArgumentMatchers. any(), ArgumentMatchers.> any())) + .thenAnswer(answer); - if (getResponseHandlerReturnValue() != null) { - Mockito.when(httpClient.execute(ArgumentMatchers.any(), ArgumentMatchers.any(), - ArgumentMatchers.> any())) - .thenReturn(getResponseHandlerReturnValue()); - } return httpClient; } catch (IOException e) { throw new IllegalStateException(e); diff --git a/multiapps-controller-core-test/src/main/java/org/cloudfoundry/multiapps/controller/core/test/HttpMocks.java b/multiapps-controller-core-test/src/main/java/org/cloudfoundry/multiapps/controller/core/test/HttpMocks.java index f6a25bee7f..c53a98edb3 100644 --- a/multiapps-controller-core-test/src/main/java/org/cloudfoundry/multiapps/controller/core/test/HttpMocks.java +++ b/multiapps-controller-core-test/src/main/java/org/cloudfoundry/multiapps/controller/core/test/HttpMocks.java @@ -1,9 +1,8 @@ package org.cloudfoundry.multiapps.controller.core.test; import java.util.function.UnaryOperator; - -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; public class HttpMocks { diff --git a/multiapps-controller-core-test/src/main/java/org/cloudfoundry/multiapps/controller/core/test/HttpResponseMock.java b/multiapps-controller-core-test/src/main/java/org/cloudfoundry/multiapps/controller/core/test/HttpResponseMock.java index a574978b50..640d7db12d 100644 --- a/multiapps-controller-core-test/src/main/java/org/cloudfoundry/multiapps/controller/core/test/HttpResponseMock.java +++ b/multiapps-controller-core-test/src/main/java/org/cloudfoundry/multiapps/controller/core/test/HttpResponseMock.java @@ -3,16 +3,12 @@ import java.nio.charset.StandardCharsets; import java.util.Map; import java.util.Map.Entry; - -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.ProtocolVersion; -import org.apache.http.StatusLine; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.entity.StringEntity; -import org.apache.http.message.BasicHeader; -import org.apache.http.message.BasicStatusLine; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.HttpResponse; +import org.apache.hc.core5.http.io.entity.StringEntity; +import org.apache.hc.core5.http.message.BasicHeader; import org.immutables.value.Value; import org.mockito.Mockito; @@ -28,18 +24,14 @@ public abstract class HttpResponseMock { @Value.Derived public CloseableHttpResponse getMock() { CloseableHttpResponse response = Mockito.mock(CloseableHttpResponse.class); - Mockito.when(response.getStatusLine()) - .thenReturn(createStatusLine(getStatusCode())); + Mockito.when(response.getCode()) + .thenReturn(getStatusCode()); Mockito.when(response.getEntity()) .thenReturn(createHttpEntity(getBody())); mockHeaders(response); return response; } - private static StatusLine createStatusLine(int statusCode) { - return new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), statusCode, null); - } - private static HttpEntity createHttpEntity(String body) { return new StringEntity(body, StandardCharsets.UTF_8); } diff --git a/multiapps-controller-core/pom.xml b/multiapps-controller-core/pom.xml index dd1e73f133..18bc1f250f 100644 --- a/multiapps-controller-core/pom.xml +++ b/multiapps-controller-core/pom.xml @@ -111,5 +111,9 @@ jakarta.inject jakarta.inject-api + + org.apache.httpcomponents.client5 + httpclient5 + diff --git a/multiapps-controller-core/src/main/java/module-info.java b/multiapps-controller-core/src/main/java/module-info.java index f50b149a4e..325b230667 100644 --- a/multiapps-controller-core/src/main/java/module-info.java +++ b/multiapps-controller-core/src/main/java/module-info.java @@ -59,8 +59,8 @@ requires org.apache.commons.collections4; requires org.apache.commons.io; requires org.apache.commons.lang3; - requires org.apache.httpcomponents.httpclient; - requires org.apache.httpcomponents.httpcore; + requires org.apache.httpcomponents.client5.httpclient5; + requires org.apache.httpcomponents.core5.httpcore5; requires org.cloudfoundry.multiapps.common; requires org.cloudfoundry.multiapps.controller.api; requires org.slf4j; diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/CloudControllerHeaderConfiguration.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/CloudControllerHeaderConfiguration.java index d16037a850..dcb5dc1011 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/CloudControllerHeaderConfiguration.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/CloudControllerHeaderConfiguration.java @@ -1,10 +1,9 @@ package org.cloudfoundry.multiapps.controller.core.cf; import java.util.Map; - import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.http.HttpHeaders; +import org.apache.hc.core5.http.HttpHeaders; import org.cloudfoundry.multiapps.controller.core.Constants; public class CloudControllerHeaderConfiguration { diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/http/CookieSpecification.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/http/CookieSpecification.java deleted file mode 100644 index 0afc76b1b4..0000000000 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/http/CookieSpecification.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.cloudfoundry.multiapps.controller.core.http; - -import java.text.MessageFormat; - -import org.apache.http.client.config.CookieSpecs; - -public enum CookieSpecification { - - BROWSER_COMPATIBILITY(CookieSpecs.BROWSER_COMPATIBILITY), NETSCAPE(CookieSpecs.NETSCAPE), STANDARD( - CookieSpecs.STANDARD), STANDARD_STRICT(CookieSpecs.STANDARD_STRICT), BEST_MATCH( - CookieSpecs.BEST_MATCH), DEFAULT(CookieSpecs.DEFAULT), IGNORE_COOKIES(CookieSpecs.IGNORE_COOKIES); - - private final String value; - - CookieSpecification(String value) { - this.value = value; - } - - public static CookieSpecification fromString(String value) { - switch (value) { - case CookieSpecs.BROWSER_COMPATIBILITY: - return CookieSpecification.BROWSER_COMPATIBILITY; - case CookieSpecs.NETSCAPE: - return CookieSpecification.NETSCAPE; - case CookieSpecs.STANDARD: - return CookieSpecification.STANDARD; - case CookieSpecs.STANDARD_STRICT: - return CookieSpecification.STANDARD_STRICT; - case CookieSpecs.BEST_MATCH: - return CookieSpecification.BEST_MATCH; - case CookieSpecs.DEFAULT: - return CookieSpecification.DEFAULT; - case CookieSpecs.IGNORE_COOKIES: - return CookieSpecification.IGNORE_COOKIES; - default: - throw new IllegalStateException(MessageFormat.format("{0} is not a valid cookie specification.", value)); - } - } - - @Override - public String toString() { - return value; - } - -} diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/http/CsrfHttpClient.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/http/CsrfHttpClient.java index c821e7652d..58f07c2d27 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/http/CsrfHttpClient.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/http/CsrfHttpClient.java @@ -1,105 +1,54 @@ package org.cloudfoundry.multiapps.controller.core.http; -import java.io.Closeable; import java.io.IOException; -import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Map.Entry; - -import org.apache.http.Header; -import org.apache.http.HttpHost; -import org.apache.http.HttpRequest; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.client.HttpClient; -import org.apache.http.client.ResponseHandler; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpHead; -import org.apache.http.client.methods.HttpOptions; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.conn.ClientConnectionManager; -import org.apache.http.params.HttpParams; -import org.apache.http.protocol.HttpContext; -import org.apache.http.util.EntityUtils; - -public class CsrfHttpClient implements HttpClient, Closeable { +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.classic.methods.HttpHead; +import org.apache.hc.client5.http.classic.methods.HttpOptions; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.core5.http.ClassicHttpRequest; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.HttpRequest; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.http.protocol.HttpContext; +import org.apache.hc.core5.io.CloseMode; + +public class CsrfHttpClient extends CloseableHttpClient { public static final String CSRF_TOKEN_HEADER_NAME = "X-CSRF-TOKEN"; public static final String CSRF_TOKEN_HEADER_FETCH_VALUE = "Fetch"; public static final String CSRF_TOKEN_HEADER_REQUIRED_VALUE = "Required"; - private static final List NON_PROTECTED_METHODS = Arrays.asList(HttpGet.METHOD_NAME, HttpOptions.METHOD_NAME, - HttpHead.METHOD_NAME); + private static final List NON_PROTECTED_METHODS = List.of(HttpGet.METHOD_NAME, HttpOptions.METHOD_NAME, + HttpHead.METHOD_NAME); - private final HttpClient delegate; + private final CloseableHttpClient delegate; private String csrfToken; private final String csrfGetTokenUrl; private final Map httpRequestHeaders; private boolean isTokenInitialized; - public CsrfHttpClient(HttpClient httpClient, String csrfGetTokenUrl, Map httpRequestHeaders) { + public CsrfHttpClient(CloseableHttpClient httpClient, String csrfGetTokenUrl, Map httpRequestHeaders) { this.delegate = httpClient; this.csrfGetTokenUrl = csrfGetTokenUrl; this.httpRequestHeaders = httpRequestHeaders; } @Override - public HttpParams getParams() { - return delegate.getParams(); - } - - @Override - public ClientConnectionManager getConnectionManager() { - return delegate.getConnectionManager(); - } - - @Override - public HttpResponse execute(HttpUriRequest request) throws IOException { - return executeRequest(request, () -> delegate.execute(request)); - } - - @Override - public HttpResponse execute(HttpUriRequest request, HttpContext context) throws IOException { - return executeRequest(request, () -> delegate.execute(request, context)); - } - - @Override - public HttpResponse execute(HttpHost target, HttpRequest request) throws IOException { - return executeRequest(request, () -> delegate.execute(target, request)); - } - - @Override - public HttpResponse execute(HttpHost target, HttpRequest request, HttpContext context) throws IOException { + protected CloseableHttpResponse doExecute(HttpHost target, ClassicHttpRequest request, HttpContext context) throws IOException { return executeRequest(request, () -> delegate.execute(target, request, context)); } - @Override - public T execute(HttpUriRequest request, ResponseHandler responseHandler) throws IOException { - return executeRequest(request, () -> delegate.execute(request, responseHandler)); - } - - @Override - public T execute(HttpUriRequest request, ResponseHandler responseHandler, HttpContext context) throws IOException { - return executeRequest(request, () -> delegate.execute(request, responseHandler, context)); - } - - @Override - public T execute(HttpHost target, HttpRequest request, ResponseHandler responseHandler) throws IOException { - return executeRequest(request, () -> delegate.execute(target, request, responseHandler)); - } - - @Override - public T execute(HttpHost target, HttpRequest request, ResponseHandler responseHandler, HttpContext context) - throws IOException { - return executeRequest(request, () -> delegate.execute(target, request, responseHandler, context)); - } - private T executeRequest(HttpRequest request, Executor executionSupplier) throws IOException { T result = executeWithCsrfTokenSetting(request, executionSupplier); - if (!(result instanceof HttpResponse)) { + if (!(result instanceof ClassicHttpResponse response)) { return result; } - HttpResponse response = (HttpResponse) result; if (isRetryNeeded(request, response)) { result = executeWithCsrfTokenSetting(request, executionSupplier); } @@ -130,8 +79,7 @@ private void setCrsfToken(HttpRequest request) throws IOException { } private boolean isProtectionRequired(HttpRequest request) { - return !NON_PROTECTED_METHODS.contains(request.getRequestLine() - .getMethod()); + return !NON_PROTECTED_METHODS.contains(request.getMethod()); } private void initializeToken(boolean force) throws IOException { @@ -151,20 +99,20 @@ private String fetchNewCsrfToken() throws IOException { HttpGet fetchTokenRequest = new HttpGet(csrfGetTokenUrl); fetchTokenRequest.addHeader(CSRF_TOKEN_HEADER_NAME, CSRF_TOKEN_HEADER_FETCH_VALUE); setHttpRequestHeaders(fetchTokenRequest); - HttpResponse response = delegate.execute(fetchTokenRequest); - EntityUtils.consume(response.getEntity()); - if (response.containsHeader(CSRF_TOKEN_HEADER_NAME)) { - return response.getFirstHeader(CSRF_TOKEN_HEADER_NAME) - .getValue(); - } - - return null; + return delegate.execute(fetchTokenRequest, response -> { + EntityUtils.consume(response.getEntity()); + if (response.containsHeader(CSRF_TOKEN_HEADER_NAME)) { + return response.getFirstHeader(CSRF_TOKEN_HEADER_NAME) + .getValue(); + } + return null; + }); } /** * Checks if a request has failed due to an expired session(token is not valid anymore) and regenerates the token if needed. */ - private boolean isRetryNeeded(HttpRequest request, HttpResponse response) throws IOException { + private boolean isRetryNeeded(HttpRequest request, ClassicHttpResponse response) throws IOException { if (!isProtectionRequired(request)) { // The request was not protected so the error was not caused by // missing token. @@ -173,8 +121,7 @@ private boolean isRetryNeeded(HttpRequest request, HttpResponse response) throws // The token was initialized but probably the session has expired. If it // is so, then the token needs to be regenerated and request retried. - if (isTokenInitialized && (response.getStatusLine() - .getStatusCode() == HttpStatus.SC_FORBIDDEN)) { + if (isTokenInitialized && (response.getCode() == HttpStatus.SC_FORBIDDEN)) { Header csrfTokenHeader = response.getFirstHeader(CSRF_TOKEN_HEADER_NAME); @@ -195,9 +142,12 @@ private boolean isRetryNeeded(HttpRequest request, HttpResponse response) throws @Override public void close() throws IOException { - if (delegate instanceof Closeable) { - ((Closeable) delegate).close(); - } + delegate.close(); + } + + @Override + public void close(CloseMode closeMode) { + delegate.close(closeMode); } private interface Executor { diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/http/HttpClientFactory.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/http/HttpClientFactory.java deleted file mode 100644 index 4d5c578ecc..0000000000 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/http/HttpClientFactory.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.cloudfoundry.multiapps.controller.core.http; - -import java.net.ProxySelector; -import java.nio.charset.StandardCharsets; -import java.util.Base64; -import java.util.Collections; -import java.util.concurrent.TimeUnit; - -import org.apache.http.client.HttpRequestRetryHandler; -import org.apache.http.client.ServiceUnavailableRetryStrategy; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.conn.routing.HttpRoutePlanner; -import org.apache.http.conn.socket.LayeredConnectionSocketFactory; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; -import org.apache.http.impl.client.DefaultServiceUnavailableRetryStrategy; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.conn.SystemDefaultRoutePlanner; -import org.apache.http.message.BasicHeader; - -public class HttpClientFactory { - - private static final int CONNECT_TIMEOUT = (int) TimeUnit.MINUTES.toMillis(2); - private static final int SOCKET_TIMEOUT = (int) TimeUnit.MINUTES.toMillis(3); - - private final LayeredConnectionSocketFactory sslSocketFactory; - private CookieSpecification cookieSpecification = CookieSpecification.DEFAULT; - - public HttpClientFactory(LayeredConnectionSocketFactory sslSocketFactory) { - this.sslSocketFactory = sslSocketFactory; - } - - public HttpClientFactory withCookieSpecification(CookieSpecification cookieSpecification) { - this.cookieSpecification = cookieSpecification; - return this; - } - - public CloseableHttpClient createBasicAuthHttpClient(String username, String password) { - String authorizationHeaderValue = "Basic " + encodeCredentials(username, password); - return createHttpClientBuilder().setDefaultHeaders(Collections.singletonList(createAuthorizationHeader(authorizationHeaderValue))) - .build(); - } - - public CloseableHttpClient createOAuthHttpClient(String token) { - String authorizationHeaderValue = "Bearer " + token; - return createHttpClientBuilder().setDefaultHeaders(Collections.singletonList(createAuthorizationHeader(authorizationHeaderValue))) - .build(); - } - - public CloseableHttpClient createNoAuthHttpClient() { - return createHttpClientBuilder().build(); - } - - private String encodeCredentials(String username, String password) { - Base64.Encoder encoder = Base64.getEncoder(); - return encoder.encodeToString((username + ":" + password).getBytes(StandardCharsets.UTF_8)); - } - - private HttpClientBuilder createHttpClientBuilder() { - return HttpClientBuilder.create() - .setSSLSocketFactory(sslSocketFactory) - .setRoutePlanner(createRoutePlanner()) - .setDefaultRequestConfig(createDefaultRequestConfig()) - .setRetryHandler(createRetryHandler()) - .setServiceUnavailableRetryStrategy(createServiceUnavailableRetryStrategy()); - } - - private HttpRoutePlanner createRoutePlanner() { - // If http.nonProxyHosts is not set, then "localhost" is used as a default value, which prevents setting a proxy on localhost. - if (System.getProperty("http.nonProxyHosts") == null) { - System.setProperty("http.nonProxyHosts", ""); - } - return new SystemDefaultRoutePlanner(ProxySelector.getDefault()); - } - - private RequestConfig createDefaultRequestConfig() { - return RequestConfig.custom() - .setConnectTimeout(CONNECT_TIMEOUT) - .setSocketTimeout(SOCKET_TIMEOUT) - .setCookieSpec(cookieSpecification.toString()) - .build(); - } - - private HttpRequestRetryHandler createRetryHandler() { - return new DefaultHttpRequestRetryHandler(3, true); - } - - private BasicHeader createAuthorizationHeader(String value) { - return new BasicHeader("Authorization", value); - } - - private ServiceUnavailableRetryStrategy createServiceUnavailableRetryStrategy() { - return new DefaultServiceUnavailableRetryStrategy(3, 2000); - } - -} diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/http/TimeoutHttpExecutor.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/http/TimeoutHttpExecutor.java deleted file mode 100644 index 1ea9b59049..0000000000 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/http/TimeoutHttpExecutor.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.cloudfoundry.multiapps.controller.core.http; - -import java.io.IOException; -import java.util.Timer; -import java.util.TimerTask; -import java.util.function.Function; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpUriRequest; -import org.cloudfoundry.multiapps.common.SLException; - -public class TimeoutHttpExecutor { - - private final HttpClient client; - - public TimeoutHttpExecutor(HttpClient client) { - this.client = client; - } - - public T executeWithTimeout(HttpUriRequest request, long timeoutInMillis, Function responseHandler) { - TimerTask abortRequestTask = buildAbortRequestTimerTask(request); - Timer timeoutEnforcer = new Timer(true); - timeoutEnforcer.schedule(abortRequestTask, timeoutInMillis); - try { - final HttpResponse response = client.execute(request); - return responseHandler.apply(response); - } catch (IOException e) { - throw new SLException(e, e.getMessage()); - } finally { - abortRequestTask.cancel(); - timeoutEnforcer.cancel(); - } - } - - private TimerTask buildAbortRequestTimerTask(HttpUriRequest request) { - return new TimerTask() { - @Override - public void run() { - if (!request.isAborted()) { - request.abort(); - } - } - }; - } -} \ No newline at end of file diff --git a/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/http/CsrfHttpClientTest.java b/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/http/CsrfHttpClientTest.java index a8ca0d1b2b..99421381e7 100644 --- a/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/http/CsrfHttpClientTest.java +++ b/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/http/CsrfHttpClientTest.java @@ -2,17 +2,20 @@ import java.io.IOException; import java.util.Collections; - -import org.apache.http.HttpRequest; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.protocol.HttpContext; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.core5.http.ClassicHttpRequest; +import org.apache.hc.core5.http.HttpResponse; +import org.apache.hc.core5.http.io.HttpClientResponseHandler; +import org.apache.hc.core5.http.protocol.HttpContext; import org.cloudfoundry.multiapps.controller.core.test.HttpMocks; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatchers; import org.mockito.Mockito; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; class CsrfHttpClientTest { @@ -20,17 +23,21 @@ class CsrfHttpClientTest { private static final String FOO_TOKEN = "foo"; private static final String BAR_TOKEN = "bar"; private static final String RESPONSE_HANDLER_RETURN_VALUE = "baz"; + private static final String TEST_URL = "https://dummy"; + private static final String TEST_CSRF_URL = "dummy"; private static final HttpResponse OK_RESPONSE = HttpMocks.mockResponse(builder -> builder.body(BODY) .statusCode(200)); private static final HttpResponse OK_RESPONSE_WITH_FOO_TOKEN = HttpMocks.mockResponse(builder -> builder.body(BODY) .statusCode(200) - .putHeader(CsrfHttpClient.CSRF_TOKEN_HEADER_NAME, - FOO_TOKEN)); + .putHeader( + CsrfHttpClient.CSRF_TOKEN_HEADER_NAME, + FOO_TOKEN)); private static final HttpResponse OK_RESPONSE_WITH_BAR_TOKEN = HttpMocks.mockResponse(builder -> builder.body(BODY) .statusCode(200) - .putHeader(CsrfHttpClient.CSRF_TOKEN_HEADER_NAME, - BAR_TOKEN)); + .putHeader( + CsrfHttpClient.CSRF_TOKEN_HEADER_NAME, + BAR_TOKEN)); private static final HttpResponse FORBIDDEN_RESPONSE = HttpMocks.mockResponse(b -> b.statusCode(403) .body(BODY) .putHeader(CsrfHttpClient.CSRF_TOKEN_HEADER_NAME, @@ -38,39 +45,40 @@ class CsrfHttpClientTest { @Test void testExecuteRequestWithNoProtectionNeeded() throws IOException { - HttpClient httpClient = HttpMocks.mockClient(builder -> builder.addResponse(OK_RESPONSE)); - HttpRequest request = Mockito.spy(new HttpGet()); + CloseableHttpClient httpClient = HttpMocks.mockClient(builder -> builder.addResponse(OK_RESPONSE)); + ClassicHttpRequest request = Mockito.spy(new HttpGet(TEST_URL)); HttpResponse response = getResultFromExecution(httpClient, client -> client.execute(null, request)); Mockito.verify(request, Mockito.never()) .setHeader(Mockito.anyString(), Mockito.anyString()); - Assertions.assertEquals(200, response.getStatusLine() - .getStatusCode()); + Assertions.assertEquals(200, response.getCode()); } @Test void testExecuteSimpleRequestWithNoRetryShouldReturnTheResponse() throws IOException { - HttpClient httpClient = HttpMocks.mockClient(builder -> builder.addResponse(OK_RESPONSE_WITH_FOO_TOKEN)); - HttpRequest request = Mockito.spy(new HttpPost()); + CloseableHttpClient httpClient = HttpMocks.mockClient(builder -> builder.addResponse(OK_RESPONSE_WITH_FOO_TOKEN)); + ClassicHttpRequest request = Mockito.spy(new HttpPost(TEST_URL)); + when(httpClient.execute(any(), ArgumentMatchers.> any())).thenReturn(FOO_TOKEN); - HttpResponse response = getResultFromExecution(httpClient, "dummy", client -> client.execute(null, request)); + HttpResponse response = getResultFromExecution(httpClient, TEST_CSRF_URL, client -> client.execute(null, request)); Mockito.verify(request) .setHeader(CsrfHttpClient.CSRF_TOKEN_HEADER_NAME, FOO_TOKEN); - Assertions.assertEquals(200, response.getStatusLine() - .getStatusCode()); + Assertions.assertEquals(200, response.getCode()); } @Test void testExecuteSimpleRequestWithRetryNeeded() throws IOException { - HttpClient httpClient = HttpMocks.mockClient(builder -> builder.addResponse(OK_RESPONSE_WITH_FOO_TOKEN) - .addResponse(FORBIDDEN_RESPONSE) - .addResponse(OK_RESPONSE_WITH_BAR_TOKEN)); - HttpRequest request = Mockito.spy(new HttpPost()); + CloseableHttpClient httpClient = HttpMocks.mockClient(builder -> builder.addResponse(OK_RESPONSE_WITH_FOO_TOKEN) + .addResponse(FORBIDDEN_RESPONSE) + .addResponse(OK_RESPONSE_WITH_BAR_TOKEN)); + ClassicHttpRequest request = Mockito.spy(new HttpPost(TEST_URL)); + when(httpClient.execute(any(), ArgumentMatchers.> any())).thenReturn(FOO_TOKEN) + .thenReturn(BAR_TOKEN); - HttpResponse response = getResultFromExecution(httpClient, "dummy", client -> client.execute(null, request)); + HttpResponse response = getResultFromExecution(httpClient, TEST_CSRF_URL, client -> client.execute(null, request)); Mockito.verify(request) .setHeader(CsrfHttpClient.CSRF_TOKEN_HEADER_NAME, FOO_TOKEN); @@ -78,53 +86,52 @@ void testExecuteSimpleRequestWithRetryNeeded() throws IOException { Mockito.verify(request) .setHeader(CsrfHttpClient.CSRF_TOKEN_HEADER_NAME, BAR_TOKEN); - Assertions.assertEquals(200, response.getStatusLine() - .getStatusCode()); + Assertions.assertEquals(200, response.getCode()); } @Test void testExecuteWithContext() throws IOException { - HttpClient httpClient = HttpMocks.mockClient(builder -> builder.addResponse(OK_RESPONSE)); - HttpRequest request = Mockito.spy(new HttpGet()); + CloseableHttpClient httpClient = HttpMocks.mockClient(builder -> builder.addResponse(OK_RESPONSE)); + ClassicHttpRequest request = Mockito.spy(new HttpGet(TEST_URL)); - HttpResponse response = getResultFromExecution(httpClient, "dummy", client -> client.execute(null, request, (HttpContext) null)); + HttpResponse response = getResultFromExecution(httpClient, TEST_CSRF_URL, + client -> client.execute(null, request, (HttpContext) null)); Mockito.verify(request, Mockito.never()) .setHeader(Mockito.anyString(), Mockito.anyString()); - Assertions.assertEquals(200, response.getStatusLine() - .getStatusCode()); + Assertions.assertEquals(200, response.getCode()); } @Test void testExecuteWithTarget() throws IOException { - HttpClient httpClient = HttpMocks.mockClient(builder -> builder.addResponse(OK_RESPONSE)); - HttpRequest request = Mockito.spy(new HttpGet()); + CloseableHttpClient httpClient = HttpMocks.mockClient(builder -> builder.addResponse(OK_RESPONSE)); + ClassicHttpRequest request = Mockito.spy(new HttpGet(TEST_URL)); - HttpResponse response = getResultFromExecution(httpClient, "dummy", client -> client.execute(null, request, (HttpContext) null)); + HttpResponse response = getResultFromExecution(httpClient, TEST_CSRF_URL, + client -> client.execute(null, request, (HttpContext) null)); Mockito.verify(request, Mockito.never()) .setHeader(Mockito.anyString(), Mockito.anyString()); - Assertions.assertEquals(200, response.getStatusLine() - .getStatusCode()); + Assertions.assertEquals(200, response.getCode()); } @Test void testExecuteWithResponseHandler() throws IOException { - HttpClient httpClient = HttpMocks.mockClient(builder -> builder.addResponse(OK_RESPONSE) - .responseHandlerReturnValue(RESPONSE_HANDLER_RETURN_VALUE)); - HttpRequest request = Mockito.spy(new HttpGet()); + CloseableHttpClient httpClient = HttpMocks.mockClient(builder -> builder.addResponse(OK_RESPONSE)); + ClassicHttpRequest request = Mockito.spy(new HttpGet(TEST_URL)); - String result = getResultFromExecution(httpClient, client -> client.execute(null, request, response -> null)); + String result = getResultFromExecution(httpClient, + client -> client.execute(null, request, response -> RESPONSE_HANDLER_RETURN_VALUE)); Assertions.assertEquals(RESPONSE_HANDLER_RETURN_VALUE, result); } @Test void testWithNoUrlSet() throws IOException { - HttpClient httpClient = HttpMocks.mockClient(builder -> builder.addResponse(OK_RESPONSE)); - HttpRequest request = Mockito.spy(new HttpPost()); + CloseableHttpClient httpClient = HttpMocks.mockClient(builder -> builder.addResponse(OK_RESPONSE)); + ClassicHttpRequest request = Mockito.spy(new HttpPost(TEST_URL)); HttpResponse response = getResultFromExecution(httpClient, client -> client.execute(null, request)); @@ -134,11 +141,12 @@ void testWithNoUrlSet() throws IOException { .setHeader(Mockito.anyString(), Mockito.anyString()); } - private T getResultFromExecution(HttpClient mockHttpClient, TestHttpExecutor executor) throws IOException { + private T getResultFromExecution(CloseableHttpClient mockHttpClient, TestHttpExecutor executor) throws IOException { return getResultFromExecution(mockHttpClient, null, executor); } - private T getResultFromExecution(HttpClient mockHttpClient, String csrfUrl, TestHttpExecutor executor) throws IOException { + private T getResultFromExecution(CloseableHttpClient mockHttpClient, String csrfUrl, TestHttpExecutor executor) + throws IOException { try (CsrfHttpClient client = new CsrfHttpClient(mockHttpClient, csrfUrl, Collections.emptyMap())) { return executor.execute(client); } diff --git a/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/http/TimeoutHttpExecutorTest.java b/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/http/TimeoutHttpExecutorTest.java deleted file mode 100644 index ed7ef964b0..0000000000 --- a/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/http/TimeoutHttpExecutorTest.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.cloudfoundry.multiapps.controller.core.http; - -import java.io.IOException; -import java.util.function.Function; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpUriRequest; -import org.cloudfoundry.multiapps.common.SLException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -class TimeoutHttpExecutorTest { - - private HttpClient mockHttpClient; - private HttpUriRequest mockRequest; - private HttpResponse mockResponse; - private TimeoutHttpExecutor timeoutHttpExecutor; - - @BeforeEach - void setUp() { - mockHttpClient = mock(HttpClient.class); - mockRequest = mock(HttpUriRequest.class); - mockResponse = mock(HttpResponse.class); - timeoutHttpExecutor = new TimeoutHttpExecutor(mockHttpClient); - } - - @Test - void testExecuteWithTimeoutSuccessfulExecution() throws IOException { - when(mockHttpClient.execute(mockRequest)).thenReturn(mockResponse); - Function responseHandler = response -> "Success"; - - String result = timeoutHttpExecutor.executeWithTimeout(mockRequest, 1000, responseHandler); - - assertEquals("Success", result); - verify(mockHttpClient, times(1)).execute(mockRequest); - verify(mockRequest, never()).abort(); - } - - @Test - void testExecuteWithTimeoutRequestAbortedDueToTimeout() throws IOException { - when(mockHttpClient.execute(mockRequest)).thenAnswer(invocation -> { - Thread.sleep(200); // Simulate a delay - return mockResponse; - }); - Function responseHandler = response -> "Success"; - - timeoutHttpExecutor.executeWithTimeout(mockRequest, 100, responseHandler); - verify(mockRequest, times(1)).abort(); - } - - @Test - void testExecuteWithTimeoutIOExceptionThrown() throws IOException { - when(mockHttpClient.execute(mockRequest)).thenThrow(new IOException("Connection error")); - Function responseHandler = response -> "Success"; - - SLException exception = assertThrows(SLException.class, - () -> timeoutHttpExecutor.executeWithTimeout(mockRequest, 1000, responseHandler)); - assertEquals("Connection error", exception.getMessage()); - verify(mockRequest, never()).abort(); - } - -} diff --git a/multiapps-controller-shutdown-client/src/main/java/module-info.java b/multiapps-controller-shutdown-client/src/main/java/module-info.java index 1168475de5..a861f53a96 100644 --- a/multiapps-controller-shutdown-client/src/main/java/module-info.java +++ b/multiapps-controller-shutdown-client/src/main/java/module-info.java @@ -7,8 +7,8 @@ requires com.sap.cloudfoundry.client.facade; requires com.fasterxml.jackson.annotation; - requires org.apache.httpcomponents.httpclient; - requires org.apache.httpcomponents.httpcore; + requires org.apache.httpcomponents.client5.httpclient5; + requires org.apache.httpcomponents.core5.httpcore5; requires org.cloudfoundry.multiapps.common; requires org.slf4j; diff --git a/multiapps-controller-shutdown-client/src/main/java/org/cloudfoundry/multiapps/controller/shutdown/client/ShutdownClientFactory.java b/multiapps-controller-shutdown-client/src/main/java/org/cloudfoundry/multiapps/controller/shutdown/client/ShutdownClientFactory.java index 50ca1960ea..1377cb4925 100644 --- a/multiapps-controller-shutdown-client/src/main/java/org/cloudfoundry/multiapps/controller/shutdown/client/ShutdownClientFactory.java +++ b/multiapps-controller-shutdown-client/src/main/java/org/cloudfoundry/multiapps/controller/shutdown/client/ShutdownClientFactory.java @@ -3,12 +3,17 @@ import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.Map; - -import org.apache.http.HttpHeaders; -import org.apache.http.client.ServiceUnavailableRetryStrategy; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.DefaultServiceUnavailableRetryStrategy; -import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.hc.client5.http.HttpRequestRetryStrategy; +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.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; +import org.apache.hc.core5.http.HttpHeaders; +import org.apache.hc.core5.http.io.SocketConfig; +import org.apache.hc.core5.util.TimeValue; +import org.apache.hc.core5.util.Timeout; import org.cloudfoundry.multiapps.common.util.MapUtil; import org.cloudfoundry.multiapps.controller.core.http.CsrfHttpClient; import org.cloudfoundry.multiapps.controller.shutdown.client.configuration.ShutdownClientConfiguration; @@ -18,11 +23,13 @@ public class ShutdownClientFactory { private static final String CSRF_TOKEN_ENDPOINT = "/api/v1/csrf-token"; private static final int RETRY_COUNT = 5; private static final int RETRY_INTERVAL_IN_MILLIS = 5000; + private static final Timeout CONNECT_TIMEOUT = Timeout.ofMinutes(2); + private static final Timeout SOCKET_TIMEOUT = Timeout.ofMinutes(5); + private static final Timeout RESPONSE_TIMEOUT = Timeout.ofMinutes(10); public ShutdownClient createShutdownClient(ShutdownClientConfiguration configuration) { return new ShutdownClientImpl(configuration.getApplicationUrl(), defaultHttpHeaders -> createCsrfHttpClient(configuration, defaultHttpHeaders)); - } private CsrfHttpClient createCsrfHttpClient(ShutdownClientConfiguration configuration, Map defaultHttpHeaders) { @@ -34,12 +41,29 @@ private CsrfHttpClient createCsrfHttpClient(ShutdownClientConfiguration configur private CloseableHttpClient createHttpClient() { return HttpClientBuilder.create() - .setServiceUnavailableRetryStrategy(createServiceUnavailableRetryStrategy()) + .setRetryStrategy(createRetryStrategy()) + .setConnectionManager(PoolingHttpClientConnectionManagerBuilder.create() + .setDefaultSocketConfig( + SocketConfig.custom() + .setSoTimeout( + SOCKET_TIMEOUT) + .build()) + .setDefaultConnectionConfig( + ConnectionConfig.custom() + .setConnectTimeout( + CONNECT_TIMEOUT) + .setSocketTimeout( + SOCKET_TIMEOUT) + .build()) + .build()) + .setDefaultRequestConfig(RequestConfig.custom() + .setResponseTimeout(RESPONSE_TIMEOUT) + .build()) .build(); } - private ServiceUnavailableRetryStrategy createServiceUnavailableRetryStrategy() { - return new DefaultServiceUnavailableRetryStrategy(RETRY_COUNT, RETRY_INTERVAL_IN_MILLIS); + private HttpRequestRetryStrategy createRetryStrategy() { + return new DefaultHttpRequestRetryStrategy(RETRY_COUNT, TimeValue.ofMilliseconds(RETRY_INTERVAL_IN_MILLIS)); } private String computeCsrfTokenUrl(ShutdownClientConfiguration configuration) { diff --git a/multiapps-controller-shutdown-client/src/main/java/org/cloudfoundry/multiapps/controller/shutdown/client/ShutdownClientImpl.java b/multiapps-controller-shutdown-client/src/main/java/org/cloudfoundry/multiapps/controller/shutdown/client/ShutdownClientImpl.java index 04d7cbbda3..6e17b73587 100644 --- a/multiapps-controller-shutdown-client/src/main/java/org/cloudfoundry/multiapps/controller/shutdown/client/ShutdownClientImpl.java +++ b/multiapps-controller-shutdown-client/src/main/java/org/cloudfoundry/multiapps/controller/shutdown/client/ShutdownClientImpl.java @@ -5,12 +5,12 @@ import java.text.MessageFormat; import java.util.Map; import java.util.UUID; - -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.util.EntityUtils; +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.HttpUriRequest; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.ParseException; +import org.apache.hc.core5.http.io.entity.EntityUtils; import org.cloudfoundry.multiapps.common.util.JsonUtil; import org.cloudfoundry.multiapps.controller.core.http.CsrfHttpClient; import org.cloudfoundry.multiapps.controller.core.model.ApplicationShutdown; @@ -50,8 +50,7 @@ private String getShutdownEndpoint() { private ApplicationShutdown makeShutdownApiRequest(UUID applicationGuid, int applicationInstanceIndex, HttpUriRequest httpRequest) { try (CsrfHttpClient csrfHttpClient = createCsrfHttpClient(applicationGuid, applicationInstanceIndex)) { - HttpResponse response = csrfHttpClient.execute(httpRequest); - return parse(response); + return csrfHttpClient.execute(httpRequest, ShutdownClientImpl::parse); } catch (IOException e) { throw new IllegalStateException(MessageFormat.format("Could not parse shutdown API response: {0}", e.getMessage()), e); } @@ -66,7 +65,7 @@ private static String computeApplicationInstanceHeaderValue(UUID applicationGuid return String.format("%s:%d", applicationGuid, applicationInstanceIndex); } - private static ApplicationShutdown parse(HttpResponse response) throws IOException { + private static ApplicationShutdown parse(ClassicHttpResponse response) throws IOException, ParseException { String body = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); return parse(body); } diff --git a/pom.xml b/pom.xml index 3aec6abcb0..303ef56922 100644 --- a/pom.xml +++ b/pom.xml @@ -26,8 +26,8 @@ 2.19.0 4.5.0 2.4 - 4.5.14 - 4.4.16 + 5.5 + 5.3.4 3.0.4 6.8.0 @@ -482,14 +482,14 @@ - org.apache.httpcomponents - httpcore + org.apache.httpcomponents.core5 + httpcore5 ${httpcore.version} - org.apache.httpcomponents - httpclient + org.apache.httpcomponents.client5 + httpclient5 ${httpclient.version}