Skip to content

Commit c1ca2a8

Browse files
committed
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. Signed-off-by: Dmytro Nosan <[email protected]>
1 parent 05a9521 commit c1ca2a8

File tree

4 files changed

+157
-10
lines changed

4 files changed

+157
-10
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/client/AutoConfiguredRestClientSsl.java

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2024 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -34,11 +34,14 @@ class AutoConfiguredRestClientSsl implements RestClientSsl {
3434

3535
private final ClientHttpRequestFactoryBuilder<?> clientHttpRequestFactoryBuilder;
3636

37+
private final ClientHttpRequestFactorySettings clientHttpRequestFactorySettings;
38+
3739
private final SslBundles sslBundles;
3840

3941
AutoConfiguredRestClientSsl(ClientHttpRequestFactoryBuilder<?> clientHttpRequestFactoryBuilder,
40-
SslBundles sslBundles) {
42+
ClientHttpRequestFactorySettings clientHttpRequestFactorySettings, SslBundles sslBundles) {
4143
this.clientHttpRequestFactoryBuilder = clientHttpRequestFactoryBuilder;
44+
this.clientHttpRequestFactorySettings = clientHttpRequestFactorySettings;
4245
this.sslBundles = sslBundles;
4346
}
4447

@@ -50,7 +53,7 @@ public Consumer<RestClient.Builder> fromBundle(String bundleName) {
5053
@Override
5154
public Consumer<RestClient.Builder> fromBundle(SslBundle bundle) {
5255
return (builder) -> {
53-
ClientHttpRequestFactorySettings settings = ClientHttpRequestFactorySettings.ofSslBundle(bundle);
56+
ClientHttpRequestFactorySettings settings = this.clientHttpRequestFactorySettings.withSslBundle(bundle);
5457
ClientHttpRequestFactory requestFactory = this.clientHttpRequestFactoryBuilder.build(settings);
5558
builder.requestFactory(requestFactory);
5659
};

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/client/RestClientAutoConfiguration.java

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2024 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -68,9 +68,12 @@ HttpMessageConvertersRestClientCustomizer httpMessageConvertersRestClientCustomi
6868
@ConditionalOnMissingBean(RestClientSsl.class)
6969
@ConditionalOnBean(SslBundles.class)
7070
AutoConfiguredRestClientSsl restClientSsl(
71-
ObjectProvider<ClientHttpRequestFactoryBuilder<?>> clientHttpRequestFactoryBuilder, SslBundles sslBundles) {
71+
ObjectProvider<ClientHttpRequestFactoryBuilder<?>> clientHttpRequestFactoryBuilder,
72+
ObjectProvider<ClientHttpRequestFactorySettings> clientHttpRequestFactorySettings, SslBundles sslBundles) {
7273
return new AutoConfiguredRestClientSsl(
73-
clientHttpRequestFactoryBuilder.getIfAvailable(ClientHttpRequestFactoryBuilder::detect), sslBundles);
74+
clientHttpRequestFactoryBuilder.getIfAvailable(ClientHttpRequestFactoryBuilder::detect),
75+
clientHttpRequestFactorySettings.getIfAvailable(ClientHttpRequestFactorySettings::defaults),
76+
sslBundles);
7477
}
7578

7679
@Bean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Copyright 2012-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.web.client;
18+
19+
import java.time.Duration;
20+
import java.util.function.Consumer;
21+
import java.util.function.Function;
22+
23+
import org.junit.jupiter.api.Test;
24+
import org.junit.jupiter.api.extension.ExtendWith;
25+
import org.mockito.Mock;
26+
import org.mockito.junit.jupiter.MockitoExtension;
27+
28+
import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;
29+
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings;
30+
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings.Redirects;
31+
import org.springframework.boot.ssl.SslBundle;
32+
import org.springframework.boot.ssl.SslBundles;
33+
import org.springframework.http.client.ClientHttpRequestFactory;
34+
import org.springframework.web.client.RestClient;
35+
import org.springframework.web.client.RestClient.Builder;
36+
37+
import static org.assertj.core.api.Assertions.assertThat;
38+
import static org.mockito.BDDMockito.given;
39+
import static org.mockito.Mockito.mock;
40+
41+
/**
42+
* Tests for {@link AutoConfiguredRestClientSsl}.
43+
*
44+
* @author Dmytro Nosan
45+
*/
46+
@ExtendWith(MockitoExtension.class)
47+
class AutoConfiguredRestClientSslTests {
48+
49+
private final ClientHttpRequestFactorySettings clientHttpRequestFactorySettings = ClientHttpRequestFactorySettings
50+
.ofSslBundle(mock(SslBundle.class, "Default SslBundle"))
51+
.withRedirects(Redirects.DONT_FOLLOW)
52+
.withReadTimeout(Duration.ofSeconds(10))
53+
.withConnectTimeout(Duration.ofSeconds(30));
54+
55+
@Mock
56+
private SslBundles sslBundles;
57+
58+
@Mock
59+
private ClientHttpRequestFactoryBuilder<ClientHttpRequestFactory> clientHttpRequestFactoryBuilder;
60+
61+
@Mock
62+
private ClientHttpRequestFactory clientHttpRequestFactory;
63+
64+
@Test
65+
void shouldConfigureRestClientUsingBundleName() {
66+
String bundleName = "test";
67+
SslBundle sslBundle = mock(SslBundle.class, "SslBundle named '%s'".formatted(bundleName));
68+
69+
given(this.sslBundles.getBundle(bundleName)).willReturn(sslBundle);
70+
given(this.clientHttpRequestFactoryBuilder
71+
.build(this.clientHttpRequestFactorySettings.withSslBundle(sslBundle)))
72+
.willReturn(this.clientHttpRequestFactory);
73+
74+
assertThat(applySslBundle((restClientSsl) -> restClientSsl.fromBundle(bundleName)))
75+
.hasFieldOrPropertyWithValue("clientRequestFactory", this.clientHttpRequestFactory);
76+
77+
}
78+
79+
@Test
80+
void shouldConfigureRestClientUsingBundle() {
81+
SslBundle sslBundle = mock(SslBundle.class, "Custom SslBundle");
82+
83+
given(this.clientHttpRequestFactoryBuilder
84+
.build(this.clientHttpRequestFactorySettings.withSslBundle(sslBundle)))
85+
.willReturn(this.clientHttpRequestFactory);
86+
87+
assertThat(applySslBundle((restClientSsl) -> restClientSsl.fromBundle(sslBundle)))
88+
.hasFieldOrPropertyWithValue("clientRequestFactory", this.clientHttpRequestFactory);
89+
}
90+
91+
private RestClient applySslBundle(Function<RestClientSsl, Consumer<Builder>> applySslBundle) {
92+
Builder builder = RestClient.builder();
93+
applySslBundle.apply(getRestClientSsl()).accept(builder);
94+
return builder.build();
95+
}
96+
97+
private RestClientSsl getRestClientSsl() {
98+
return new AutoConfiguredRestClientSsl(this.clientHttpRequestFactoryBuilder,
99+
this.clientHttpRequestFactorySettings, this.sslBundles);
100+
}
101+
102+
}

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/client/RestClientAutoConfigurationTests.java

+43-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2024 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.boot.autoconfigure.web.client;
1818

19+
import java.time.Duration;
1920
import java.util.List;
2021

2122
import org.junit.jupiter.api.Test;
@@ -24,6 +25,10 @@
2425
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
2526
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
2627
import org.springframework.boot.autoconfigure.http.client.HttpClientAutoConfiguration;
28+
import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;
29+
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings;
30+
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings.Redirects;
31+
import org.springframework.boot.ssl.SslBundle;
2732
import org.springframework.boot.ssl.SslBundles;
2833
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
2934
import org.springframework.boot.web.client.RestClientCustomizer;
@@ -63,9 +68,43 @@ void shouldSupplyBeans() {
6368
}
6469

6570
@Test
66-
void shouldSupplyRestClientSslIfSslBundlesIsThere() {
67-
this.contextRunner.withBean(SslBundles.class, () -> mock(SslBundles.class))
68-
.run((context) -> assertThat(context).hasSingleBean(RestClientSsl.class));
71+
void shouldSupplyRestClientSslIfSslBundlesIsThereWithCustomHttpSettingsAndBuilder() {
72+
SslBundles sslBundles = mock(SslBundles.class);
73+
ClientHttpRequestFactorySettings clientHttpRequestFactorySettings = ClientHttpRequestFactorySettings.defaults()
74+
.withRedirects(Redirects.DONT_FOLLOW)
75+
.withConnectTimeout(Duration.ofHours(1))
76+
.withReadTimeout(Duration.ofDays(1))
77+
.withSslBundle(mock(SslBundle.class));
78+
ClientHttpRequestFactoryBuilder<?> clientHttpRequestFactoryBuilder = mock(
79+
ClientHttpRequestFactoryBuilder.class);
80+
this.contextRunner.withBean(SslBundles.class, () -> sslBundles)
81+
.withBean(ClientHttpRequestFactorySettings.class, () -> clientHttpRequestFactorySettings)
82+
.withBean(ClientHttpRequestFactoryBuilder.class, () -> clientHttpRequestFactoryBuilder)
83+
.run((context) -> {
84+
assertThat(context).hasSingleBean(RestClientSsl.class);
85+
RestClientSsl restClientSsl = context.getBean(RestClientSsl.class);
86+
assertThat(restClientSsl).hasFieldOrPropertyWithValue("sslBundles", sslBundles);
87+
assertThat(restClientSsl).hasFieldOrPropertyWithValue("clientHttpRequestFactoryBuilder",
88+
clientHttpRequestFactoryBuilder);
89+
assertThat(restClientSsl).hasFieldOrPropertyWithValue("clientHttpRequestFactorySettings",
90+
clientHttpRequestFactorySettings);
91+
});
92+
}
93+
94+
@Test
95+
void shouldSupplyRestClientSslIfSslBundlesIsThereWithAutoConfiguredHttpSettingsAndBuilder() {
96+
SslBundles sslBundles = mock(SslBundles.class);
97+
this.contextRunner.withBean(SslBundles.class, () -> sslBundles).run((context) -> {
98+
assertThat(context).hasSingleBean(RestClientSsl.class)
99+
.hasSingleBean(ClientHttpRequestFactorySettings.class)
100+
.hasSingleBean(ClientHttpRequestFactoryBuilder.class);
101+
RestClientSsl restClientSsl = context.getBean(RestClientSsl.class);
102+
assertThat(restClientSsl).hasFieldOrPropertyWithValue("sslBundles", sslBundles);
103+
assertThat(restClientSsl).hasFieldOrPropertyWithValue("clientHttpRequestFactoryBuilder",
104+
context.getBean(ClientHttpRequestFactoryBuilder.class));
105+
assertThat(restClientSsl).hasFieldOrPropertyWithValue("clientHttpRequestFactorySettings",
106+
context.getBean(ClientHttpRequestFactorySettings.class));
107+
});
69108
}
70109

71110
@Test

0 commit comments

Comments
 (0)