Update RestClientSsl to support ClientHttpRequestFactorySettings
Prior to this commit, RestClientSsl always used the default settings from ClientHttpRequestFactorySettings, overriding any user-defined settings (e.g., HttpClientProperties). With this commit, RestClientSsl now respects and uses ClientHttpRequestFactorySettings when they are provided. See gh-44979 Signed-off-by: Dmytro Nosan <dimanosan@gmail.com>
This commit is contained in:
committed by
Phillip Webb
parent
6746cac514
commit
af5d72b94f
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -34,11 +34,14 @@ class AutoConfiguredRestClientSsl implements RestClientSsl {
|
||||
|
||||
private final ClientHttpRequestFactoryBuilder<?> clientHttpRequestFactoryBuilder;
|
||||
|
||||
private final ClientHttpRequestFactorySettings clientHttpRequestFactorySettings;
|
||||
|
||||
private final SslBundles sslBundles;
|
||||
|
||||
AutoConfiguredRestClientSsl(ClientHttpRequestFactoryBuilder<?> clientHttpRequestFactoryBuilder,
|
||||
SslBundles sslBundles) {
|
||||
ClientHttpRequestFactorySettings clientHttpRequestFactorySettings, SslBundles sslBundles) {
|
||||
this.clientHttpRequestFactoryBuilder = clientHttpRequestFactoryBuilder;
|
||||
this.clientHttpRequestFactorySettings = clientHttpRequestFactorySettings;
|
||||
this.sslBundles = sslBundles;
|
||||
}
|
||||
|
||||
@@ -50,7 +53,7 @@ class AutoConfiguredRestClientSsl implements RestClientSsl {
|
||||
@Override
|
||||
public Consumer<RestClient.Builder> fromBundle(SslBundle bundle) {
|
||||
return (builder) -> {
|
||||
ClientHttpRequestFactorySettings settings = ClientHttpRequestFactorySettings.ofSslBundle(bundle);
|
||||
ClientHttpRequestFactorySettings settings = this.clientHttpRequestFactorySettings.withSslBundle(bundle);
|
||||
ClientHttpRequestFactory requestFactory = this.clientHttpRequestFactoryBuilder.build(settings);
|
||||
builder.requestFactory(requestFactory);
|
||||
};
|
||||
|
||||
@@ -68,9 +68,12 @@ public class RestClientAutoConfiguration {
|
||||
@ConditionalOnMissingBean(RestClientSsl.class)
|
||||
@ConditionalOnBean(SslBundles.class)
|
||||
AutoConfiguredRestClientSsl restClientSsl(
|
||||
ObjectProvider<ClientHttpRequestFactoryBuilder<?>> clientHttpRequestFactoryBuilder, SslBundles sslBundles) {
|
||||
ObjectProvider<ClientHttpRequestFactoryBuilder<?>> clientHttpRequestFactoryBuilder,
|
||||
ObjectProvider<ClientHttpRequestFactorySettings> clientHttpRequestFactorySettings, SslBundles sslBundles) {
|
||||
return new AutoConfiguredRestClientSsl(
|
||||
clientHttpRequestFactoryBuilder.getIfAvailable(ClientHttpRequestFactoryBuilder::detect), sslBundles);
|
||||
clientHttpRequestFactoryBuilder.getIfAvailable(ClientHttpRequestFactoryBuilder::detect),
|
||||
clientHttpRequestFactorySettings.getIfAvailable(ClientHttpRequestFactorySettings::defaults),
|
||||
sslBundles);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2012-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.web.client;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;
|
||||
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings;
|
||||
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings.Redirects;
|
||||
import org.springframework.boot.ssl.SslBundle;
|
||||
import org.springframework.boot.ssl.SslBundles;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.client.RestClient.Builder;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link AutoConfiguredRestClientSsl}.
|
||||
*
|
||||
* @author Dmytro Nosan
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class AutoConfiguredRestClientSslTests {
|
||||
|
||||
private final ClientHttpRequestFactorySettings clientHttpRequestFactorySettings = ClientHttpRequestFactorySettings
|
||||
.ofSslBundle(mock(SslBundle.class, "Default SslBundle"))
|
||||
.withRedirects(Redirects.DONT_FOLLOW)
|
||||
.withReadTimeout(Duration.ofSeconds(10))
|
||||
.withConnectTimeout(Duration.ofSeconds(30));
|
||||
|
||||
@Mock
|
||||
private SslBundles sslBundles;
|
||||
|
||||
@Mock
|
||||
private ClientHttpRequestFactoryBuilder<ClientHttpRequestFactory> clientHttpRequestFactoryBuilder;
|
||||
|
||||
@Mock
|
||||
private ClientHttpRequestFactory clientHttpRequestFactory;
|
||||
|
||||
@Test
|
||||
void shouldConfigureRestClientUsingBundleName() {
|
||||
String bundleName = "test";
|
||||
SslBundle sslBundle = mock(SslBundle.class, "SslBundle named '%s'".formatted(bundleName));
|
||||
|
||||
given(this.sslBundles.getBundle(bundleName)).willReturn(sslBundle);
|
||||
given(this.clientHttpRequestFactoryBuilder
|
||||
.build(this.clientHttpRequestFactorySettings.withSslBundle(sslBundle)))
|
||||
.willReturn(this.clientHttpRequestFactory);
|
||||
|
||||
assertThat(applySslBundle((restClientSsl) -> restClientSsl.fromBundle(bundleName)))
|
||||
.hasFieldOrPropertyWithValue("clientRequestFactory", this.clientHttpRequestFactory);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldConfigureRestClientUsingBundle() {
|
||||
SslBundle sslBundle = mock(SslBundle.class, "Custom SslBundle");
|
||||
|
||||
given(this.clientHttpRequestFactoryBuilder
|
||||
.build(this.clientHttpRequestFactorySettings.withSslBundle(sslBundle)))
|
||||
.willReturn(this.clientHttpRequestFactory);
|
||||
|
||||
assertThat(applySslBundle((restClientSsl) -> restClientSsl.fromBundle(sslBundle)))
|
||||
.hasFieldOrPropertyWithValue("clientRequestFactory", this.clientHttpRequestFactory);
|
||||
}
|
||||
|
||||
private RestClient applySslBundle(Function<RestClientSsl, Consumer<Builder>> applySslBundle) {
|
||||
Builder builder = RestClient.builder();
|
||||
applySslBundle.apply(getRestClientSsl()).accept(builder);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private RestClientSsl getRestClientSsl() {
|
||||
return new AutoConfiguredRestClientSsl(this.clientHttpRequestFactoryBuilder,
|
||||
this.clientHttpRequestFactorySettings, this.sslBundles);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.web.client;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -27,6 +28,7 @@ import org.springframework.boot.autoconfigure.http.client.HttpClientAutoConfigur
|
||||
import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;
|
||||
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings;
|
||||
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings.Redirects;
|
||||
import org.springframework.boot.ssl.SslBundle;
|
||||
import org.springframework.boot.ssl.SslBundles;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.web.client.RestClientCustomizer;
|
||||
@@ -66,9 +68,43 @@ class RestClientAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSupplyRestClientSslIfSslBundlesIsThere() {
|
||||
this.contextRunner.withBean(SslBundles.class, () -> mock(SslBundles.class))
|
||||
.run((context) -> assertThat(context).hasSingleBean(RestClientSsl.class));
|
||||
void shouldSupplyRestClientSslIfSslBundlesIsThereWithCustomHttpSettingsAndBuilder() {
|
||||
SslBundles sslBundles = mock(SslBundles.class);
|
||||
ClientHttpRequestFactorySettings clientHttpRequestFactorySettings = ClientHttpRequestFactorySettings.defaults()
|
||||
.withRedirects(Redirects.DONT_FOLLOW)
|
||||
.withConnectTimeout(Duration.ofHours(1))
|
||||
.withReadTimeout(Duration.ofDays(1))
|
||||
.withSslBundle(mock(SslBundle.class));
|
||||
ClientHttpRequestFactoryBuilder<?> clientHttpRequestFactoryBuilder = mock(
|
||||
ClientHttpRequestFactoryBuilder.class);
|
||||
this.contextRunner.withBean(SslBundles.class, () -> sslBundles)
|
||||
.withBean(ClientHttpRequestFactorySettings.class, () -> clientHttpRequestFactorySettings)
|
||||
.withBean(ClientHttpRequestFactoryBuilder.class, () -> clientHttpRequestFactoryBuilder)
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(RestClientSsl.class);
|
||||
RestClientSsl restClientSsl = context.getBean(RestClientSsl.class);
|
||||
assertThat(restClientSsl).hasFieldOrPropertyWithValue("sslBundles", sslBundles);
|
||||
assertThat(restClientSsl).hasFieldOrPropertyWithValue("clientHttpRequestFactoryBuilder",
|
||||
clientHttpRequestFactoryBuilder);
|
||||
assertThat(restClientSsl).hasFieldOrPropertyWithValue("clientHttpRequestFactorySettings",
|
||||
clientHttpRequestFactorySettings);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSupplyRestClientSslIfSslBundlesIsThereWithAutoConfiguredHttpSettingsAndBuilder() {
|
||||
SslBundles sslBundles = mock(SslBundles.class);
|
||||
this.contextRunner.withBean(SslBundles.class, () -> sslBundles).run((context) -> {
|
||||
assertThat(context).hasSingleBean(RestClientSsl.class)
|
||||
.hasSingleBean(ClientHttpRequestFactorySettings.class)
|
||||
.hasSingleBean(ClientHttpRequestFactoryBuilder.class);
|
||||
RestClientSsl restClientSsl = context.getBean(RestClientSsl.class);
|
||||
assertThat(restClientSsl).hasFieldOrPropertyWithValue("sslBundles", sslBundles);
|
||||
assertThat(restClientSsl).hasFieldOrPropertyWithValue("clientHttpRequestFactoryBuilder",
|
||||
context.getBean(ClientHttpRequestFactoryBuilder.class));
|
||||
assertThat(restClientSsl).hasFieldOrPropertyWithValue("clientHttpRequestFactorySettings",
|
||||
context.getBean(ClientHttpRequestFactorySettings.class));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user