From 87cf12a36cc41bd35b4d3bbdc3b84d63d1031ed8 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 13 Nov 2024 11:49:58 -0800 Subject: [PATCH] Add withDefaultRequestConfigManagerCustomizer method Update `HttpComponentsClientHttpRequestFactoryBuilder` with a new `withDefaultRequestConfigManagerCustomizer` method, primarily to help disable the protocol upgrade setting. Closes gh-43139 --- ...onentsClientHttpRequestFactoryBuilder.java | 54 ++++++++++++++----- ...sClientHttpRequestFactoryBuilderTests.java | 7 ++- 2 files changed, 47 insertions(+), 14 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/http/client/HttpComponentsClientHttpRequestFactoryBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/http/client/HttpComponentsClientHttpRequestFactoryBuilder.java index 5f8436af860..926ddd14dad 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/http/client/HttpComponentsClientHttpRequestFactoryBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/http/client/HttpComponentsClientHttpRequestFactoryBuilder.java @@ -26,6 +26,7 @@ import java.util.function.Consumer; import java.util.function.Function; import org.apache.hc.client5.http.classic.HttpClient; +import org.apache.hc.client5.http.config.RequestConfig; import org.apache.hc.client5.http.impl.DefaultRedirectStrategy; import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; @@ -64,23 +65,33 @@ public final class HttpComponentsClientHttpRequestFactoryBuilder private final Consumer socketConfigCustomizer; + private final Consumer defaultRequestConfigManagerCustomizer; + private final Function tlsSocketStrategyFactory; HttpComponentsClientHttpRequestFactoryBuilder() { - this(Collections.emptyList(), emptyCustomizer(), emptyCustomizer(), emptyCustomizer(), + this(Collections.emptyList(), emptyCustomizer(), emptyCustomizer(), emptyCustomizer(), emptyCustomizer(), HttpComponentsClientHttpRequestFactoryBuilder::createTlsSocketStrategy); } + private static TlsSocketStrategy createTlsSocketStrategy(SslBundle sslBundle) { + SslOptions options = sslBundle.getOptions(); + return new DefaultClientTlsStrategy(sslBundle.createSslContext(), options.getEnabledProtocols(), + options.getCiphers(), null, new DefaultHostnameVerifier()); + } + private HttpComponentsClientHttpRequestFactoryBuilder( List> customizers, Consumer httpClientCustomizer, Consumer connectionManagerCustomizer, Consumer socketConfigCustomizer, + Consumer defaultRequestConfigManagerCustomizer, Function tlsSocketStrategyFactory) { super(customizers); this.httpClientCustomizer = httpClientCustomizer; this.connectionManagerCustomizer = connectionManagerCustomizer; this.socketConfigCustomizer = socketConfigCustomizer; + this.defaultRequestConfigManagerCustomizer = defaultRequestConfigManagerCustomizer; this.tlsSocketStrategyFactory = tlsSocketStrategyFactory; } @@ -89,7 +100,7 @@ public final class HttpComponentsClientHttpRequestFactoryBuilder Consumer customizer) { return new HttpComponentsClientHttpRequestFactoryBuilder(mergedCustomizers(customizer), this.httpClientCustomizer, this.connectionManagerCustomizer, this.socketConfigCustomizer, - this.tlsSocketStrategyFactory); + this.defaultRequestConfigManagerCustomizer, this.tlsSocketStrategyFactory); } @Override @@ -97,7 +108,7 @@ public final class HttpComponentsClientHttpRequestFactoryBuilder Collection> customizers) { return new HttpComponentsClientHttpRequestFactoryBuilder(mergedCustomizers(customizers), this.httpClientCustomizer, this.connectionManagerCustomizer, this.socketConfigCustomizer, - this.tlsSocketStrategyFactory); + this.defaultRequestConfigManagerCustomizer, this.tlsSocketStrategyFactory); } /** @@ -111,7 +122,7 @@ public final class HttpComponentsClientHttpRequestFactoryBuilder Assert.notNull(httpClientCustomizer, "'httpClientCustomizer' must not be null"); return new HttpComponentsClientHttpRequestFactoryBuilder(getCustomizers(), this.httpClientCustomizer.andThen(httpClientCustomizer), this.connectionManagerCustomizer, - this.socketConfigCustomizer, this.tlsSocketStrategyFactory); + this.socketConfigCustomizer, this.defaultRequestConfigManagerCustomizer, this.tlsSocketStrategyFactory); } /** @@ -126,7 +137,7 @@ public final class HttpComponentsClientHttpRequestFactoryBuilder Assert.notNull(connectionManagerCustomizer, "'connectionManagerCustomizer' must not be null"); return new HttpComponentsClientHttpRequestFactoryBuilder(getCustomizers(), this.httpClientCustomizer, this.connectionManagerCustomizer.andThen(connectionManagerCustomizer), this.socketConfigCustomizer, - this.tlsSocketStrategyFactory); + this.defaultRequestConfigManagerCustomizer, this.tlsSocketStrategyFactory); } /** @@ -141,7 +152,7 @@ public final class HttpComponentsClientHttpRequestFactoryBuilder Assert.notNull(socketConfigCustomizer, "'socketConfigCustomizer' must not be null"); return new HttpComponentsClientHttpRequestFactoryBuilder(getCustomizers(), this.httpClientCustomizer, this.connectionManagerCustomizer, this.socketConfigCustomizer.andThen(socketConfigCustomizer), - this.tlsSocketStrategyFactory); + this.defaultRequestConfigManagerCustomizer, this.tlsSocketStrategyFactory); } /** @@ -155,7 +166,25 @@ public final class HttpComponentsClientHttpRequestFactoryBuilder Function tlsSocketStrategyFactory) { Assert.notNull(tlsSocketStrategyFactory, "'tlsSocketStrategyFactory' must not be null"); return new HttpComponentsClientHttpRequestFactoryBuilder(getCustomizers(), this.httpClientCustomizer, - this.connectionManagerCustomizer, this.socketConfigCustomizer, tlsSocketStrategyFactory); + this.connectionManagerCustomizer, this.socketConfigCustomizer, + this.defaultRequestConfigManagerCustomizer, tlsSocketStrategyFactory); + } + + /** + * Return a new {@link HttpComponentsClientHttpRequestFactoryBuilder} that applies + * additional customization to the underlying + * {@link org.apache.hc.client5.http.config.RequestConfig.Builder} used for default + * requests. + * @param defaultRequestConfigManagerCustomizer the customizer to apply + * @return a new {@link HttpComponentsClientHttpRequestFactoryBuilder} instance + */ + public HttpComponentsClientHttpRequestFactoryBuilder withDefaultRequestConfigManagerCustomizer( + Consumer defaultRequestConfigManagerCustomizer) { + Assert.notNull(defaultRequestConfigManagerCustomizer, + "'defaultRequestConfigManagerCustomizer' must not be null"); + return new HttpComponentsClientHttpRequestFactoryBuilder(getCustomizers(), this.httpClientCustomizer, + this.connectionManagerCustomizer, this.socketConfigCustomizer, defaultRequestConfigManagerCustomizer, + this.tlsSocketStrategyFactory); } @Override @@ -172,7 +201,8 @@ public final class HttpComponentsClientHttpRequestFactoryBuilder HttpClientBuilder builder = HttpClientBuilder.create() .useSystemProperties() .setRedirectStrategy(asRedirectStrategy(settings.redirects())) - .setConnectionManager(createConnectionManager(settings)); + .setConnectionManager(createConnectionManager(settings)) + .setDefaultRequestConfig(createDefaultRequestConfig()); this.httpClientCustomizer.accept(builder); return builder.build(); } @@ -204,10 +234,10 @@ public final class HttpComponentsClientHttpRequestFactoryBuilder return builder.build(); } - private static TlsSocketStrategy createTlsSocketStrategy(SslBundle sslBundle) { - SslOptions options = sslBundle.getOptions(); - return new DefaultClientTlsStrategy(sslBundle.createSslContext(), options.getEnabledProtocols(), - options.getCiphers(), null, new DefaultHostnameVerifier()); + private RequestConfig createDefaultRequestConfig() { + RequestConfig.Builder builder = RequestConfig.custom(); + this.defaultRequestConfigManagerCustomizer.accept(builder); + return builder.build(); } /** diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/http/client/HttpComponentsClientHttpRequestFactoryBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/http/client/HttpComponentsClientHttpRequestFactoryBuilderTests.java index 240da097b8e..6b5165ff82b 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/http/client/HttpComponentsClientHttpRequestFactoryBuilderTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/http/client/HttpComponentsClientHttpRequestFactoryBuilderTests.java @@ -22,12 +22,12 @@ import java.util.function.Function; import org.apache.hc.client5.http.HttpRoute; import org.apache.hc.client5.http.classic.HttpClient; +import org.apache.hc.client5.http.config.RequestConfig; import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; import org.apache.hc.client5.http.ssl.TlsSocketStrategy; import org.apache.hc.core5.function.Resolver; import org.apache.hc.core5.http.io.SocketConfig; -import org.apache.hc.core5.http.io.SocketConfig.Builder; import org.junit.jupiter.api.Test; import org.springframework.boot.ssl.SslBundle; @@ -54,17 +54,20 @@ class HttpComponentsClientHttpRequestFactoryBuilderTests TestCustomizer httpClientCustomizer1 = new TestCustomizer<>(); TestCustomizer httpClientCustomizer2 = new TestCustomizer<>(); TestCustomizer connectionManagerCustomizer = new TestCustomizer<>(); - TestCustomizer socketConfigCustomizer = new TestCustomizer<>(); + TestCustomizer socketConfigCustomizer = new TestCustomizer<>(); + TestCustomizer defaultRequestConfigManagerCustomizer = new TestCustomizer<>(); ClientHttpRequestFactoryBuilder.httpComponents() .withHttpClientCustomizer(httpClientCustomizer1) .withHttpClientCustomizer(httpClientCustomizer2) .withConnectionManagerCustomizer(connectionManagerCustomizer) .withSocketConfigCustomizer(socketConfigCustomizer) + .withDefaultRequestConfigManagerCustomizer(defaultRequestConfigManagerCustomizer) .build(); httpClientCustomizer1.assertCalled(); httpClientCustomizer2.assertCalled(); connectionManagerCustomizer.assertCalled(); socketConfigCustomizer.assertCalled(); + defaultRequestConfigManagerCustomizer.assertCalled(); } @Test