1616
1717package org .springframework .cloud .gateway .server .mvc ;
1818
19+ import java .util .Map ;
20+
1921import org .springframework .beans .factory .ObjectProvider ;
22+ import org .springframework .boot .SpringApplication ;
2023import org .springframework .boot .autoconfigure .AutoConfiguration ;
2124import org .springframework .boot .autoconfigure .condition .ConditionalOnMissingBean ;
2225import org .springframework .boot .autoconfigure .condition .ConditionalOnProperty ;
2326import org .springframework .boot .autoconfigure .http .client .HttpClientAutoConfiguration ;
24- import org .springframework .boot .autoconfigure .http .client .HttpClientProperties ;
27+ import org .springframework .boot .autoconfigure .http .client .HttpClientProperties . Factory ;
2528import org .springframework .boot .autoconfigure .web .client .RestClientAutoConfiguration ;
2629import org .springframework .boot .autoconfigure .web .client .RestTemplateAutoConfiguration ;
27- import org .springframework .boot .http .client .ClientHttpRequestFactoryBuilder ;
28- import org .springframework .boot .http .client .ClientHttpRequestFactorySettings ;
29- import org .springframework .boot .http .client .JdkClientHttpRequestFactoryBuilder ;
30- import org .springframework .boot .ssl .SslBundle ;
31- import org .springframework .boot .ssl .SslBundles ;
30+ import org .springframework .boot .env .EnvironmentPostProcessor ;
31+ import org .springframework .boot .http .client .ClientHttpRequestFactorySettings .Redirects ;
3232import org .springframework .boot .web .client .RestClientCustomizer ;
3333import org .springframework .cloud .gateway .server .mvc .common .ArgumentSupplierBeanPostProcessor ;
3434import org .springframework .cloud .gateway .server .mvc .config .GatewayMvcAotRuntimeHintsRegistrar ;
5555import org .springframework .context .annotation .Bean ;
5656import org .springframework .context .annotation .Import ;
5757import org .springframework .context .annotation .ImportRuntimeHints ;
58+ import org .springframework .core .env .ConfigurableEnvironment ;
5859import org .springframework .core .env .Environment ;
60+ import org .springframework .core .env .MapPropertySource ;
5961import org .springframework .http .client .ClientHttpRequestFactory ;
62+ import org .springframework .util .ClassUtils ;
6063import org .springframework .util .StringUtils ;
6164import org .springframework .web .client .RestClient ;
6265
@@ -85,8 +88,12 @@ public RouterFunctionHolderFactory routerFunctionHolderFactory(Environment env)
8588 }
8689
8790 @ Bean
88- public RestClientCustomizer gatewayRestClientCustomizer (ClientHttpRequestFactory requestFactory ) {
89- return restClientBuilder -> restClientBuilder .requestFactory (requestFactory );
91+ public RestClientCustomizer gatewayRestClientCustomizer (
92+ ObjectProvider <ClientHttpRequestFactory > requestFactoryProvider ) {
93+ return restClientBuilder -> {
94+ // for backwards compatibility if user overrode
95+ requestFactoryProvider .ifAvailable (restClientBuilder ::requestFactory );
96+ };
9097 }
9198
9299 @ Bean
@@ -111,36 +118,6 @@ public ForwardedRequestHeadersFilter forwardedRequestHeadersFilter() {
111118 return new ForwardedRequestHeadersFilter ();
112119 }
113120
114- @ Bean
115- @ ConditionalOnMissingBean
116- public ClientHttpRequestFactory gatewayClientHttpRequestFactory (HttpClientProperties properties ,
117- SslBundles sslBundles ) {
118-
119- SslBundle sslBundle = null ;
120- if (StringUtils .hasText (properties .getSsl ().getBundle ())) {
121- sslBundle = sslBundles .getBundle (properties .getSsl ().getBundle ());
122- }
123- ClientHttpRequestFactorySettings settings = ClientHttpRequestFactorySettings .ofSslBundle (sslBundle )
124- .withConnectTimeout (properties .getConnectTimeout ())
125- .withReadTimeout (properties .getReadTimeout ())
126- .withRedirects (ClientHttpRequestFactorySettings .Redirects .DONT_FOLLOW );
127-
128- ClientHttpRequestFactoryBuilder <?> builder = ClientHttpRequestFactoryBuilder .detect ();
129- if (builder instanceof JdkClientHttpRequestFactoryBuilder ) {
130- // TODO: customize restricted headers
131- String restrictedHeaders = System .getProperty ("jdk.httpclient.allowRestrictedHeaders" );
132- if (!StringUtils .hasText (restrictedHeaders )) {
133- System .setProperty ("jdk.httpclient.allowRestrictedHeaders" , "host" );
134- }
135- else if (StringUtils .hasText (restrictedHeaders ) && !restrictedHeaders .contains ("host" )) {
136- System .setProperty ("jdk.httpclient.allowRestrictedHeaders" , restrictedHeaders + ",host" );
137- }
138- }
139-
140- // Autodetect
141- return builder .build (settings );
142- }
143-
144121 @ Bean
145122 @ ConditionalOnMissingBean
146123 public GatewayMvcProperties gatewayMvcProperties () {
@@ -222,4 +199,46 @@ public XForwardedRequestHeadersFilterProperties xForwardedRequestHeadersFilterPr
222199 return new XForwardedRequestHeadersFilterProperties ();
223200 }
224201
202+ static class GatewayHttpClientEnvironmentPostProcessor implements EnvironmentPostProcessor {
203+
204+ static final boolean APACHE = ClassUtils .isPresent ("org.apache.hc.client5.http.impl.classic.HttpClients" , null );
205+ static final boolean JETTY = ClassUtils .isPresent ("org.eclipse.jetty.client.HttpClient" , null );
206+ static final boolean REACTOR_NETTY = ClassUtils .isPresent ("reactor.netty.http.client.HttpClient" , null );
207+ static final boolean JDK = ClassUtils .isPresent ("java.net.http.HttpClient" , null );
208+ static final boolean HIGHER_PRIORITY = APACHE || JETTY || REACTOR_NETTY ;
209+
210+ @ Override
211+ public void postProcessEnvironment (ConfigurableEnvironment environment , SpringApplication application ) {
212+ Redirects redirects = environment .getProperty ("spring.http.client.redirects" , Redirects .class );
213+ if (redirects == null ) {
214+ // the user hasn't set anything, change the default
215+ environment .getPropertySources ()
216+ .addFirst (new MapPropertySource ("gatewayHttpClientProperties" ,
217+ Map .of ("spring.http.client.redirects" , Redirects .DONT_FOLLOW )));
218+ }
219+ Factory factory = environment .getProperty ("spring.http.client.factory" , Factory .class );
220+ boolean setJdkHttpClientProperties = false ;
221+
222+ if (factory == null && !HIGHER_PRIORITY ) {
223+ // autodetect
224+ setJdkHttpClientProperties = JDK ;
225+ }
226+ else if (factory == Factory .JDK ) {
227+ setJdkHttpClientProperties = JDK ;
228+ }
229+
230+ if (setJdkHttpClientProperties ) {
231+ // TODO: customize restricted headers
232+ String restrictedHeaders = System .getProperty ("jdk.httpclient.allowRestrictedHeaders" );
233+ if (!StringUtils .hasText (restrictedHeaders )) {
234+ System .setProperty ("jdk.httpclient.allowRestrictedHeaders" , "host" );
235+ }
236+ else if (StringUtils .hasText (restrictedHeaders ) && !restrictedHeaders .contains ("host" )) {
237+ System .setProperty ("jdk.httpclient.allowRestrictedHeaders" , restrictedHeaders + ",host" );
238+ }
239+ }
240+ }
241+
242+ }
243+
225244}
0 commit comments