Migrates proxy-exchange-webflux properties to new namespace

from spring.cloud.gateway.proxy to spring.cloud.gateway.proxy-exchange.webflux

Fixes gh-3362
This commit is contained in:
spencergibb
2025-05-09 16:16:58 -04:00
parent eca63cba65
commit ebef2879a7
7 changed files with 206 additions and 10 deletions

View File

@@ -30,6 +30,11 @@
<artifactId>spring-boot-starter-actuator</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-properties-migrator</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>

View File

@@ -0,0 +1,117 @@
/*
* Copyright 2016-2019 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.cloud.gateway.webflux.config;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.gateway.webflux.ProxyExchange;
import org.springframework.http.HttpHeaders;
/**
* Configuration properties for the {@link ProxyExchange} argument handler in
* <code>@RequestMapping</code> methods.
*
* @author Dave Syer
* @author Tim Ysewyn
* @author Joris Kuipers
* @author Spencer Gibb
*
*/
@ConfigurationProperties(ProxyExchangeWebfluxProperties.PREFIX)
public class ProxyExchangeWebfluxProperties {
/**
* Properties prefix.
*/
public static final String PREFIX = "spring.cloud.gateway.proxy-exchange.webflux";
/**
* Contains headers that are considered case-sensitive by default.
*/
public static Set<String> DEFAULT_SENSITIVE = Set.of("cookie", "authorization");
/**
* Contains headers that are skipped by default.
*/
public static Set<String> DEFAULT_SKIPPED = Set.of("content-length", "host");
/**
* Fixed header values that will be added to all downstream requests.
*/
private Map<String, String> headers = new LinkedHashMap<>();
/**
* A set of header names that should be sent downstream by default.
*/
private Set<String> autoForward = new HashSet<>();
/**
* A set of sensitive header names that will not be sent downstream by default.
*/
private Set<String> sensitive = DEFAULT_SENSITIVE;
/**
* A set of header names that will not be sent downstream because they could be
* problematic.
*/
private Set<String> skipped = DEFAULT_SKIPPED;
public Map<String, String> getHeaders() {
return headers;
}
public void setHeaders(Map<String, String> headers) {
this.headers = headers;
}
public Set<String> getAutoForward() {
return autoForward;
}
public void setAutoForward(Set<String> autoForward) {
this.autoForward = autoForward;
}
public Set<String> getSensitive() {
return sensitive;
}
public void setSensitive(Set<String> sensitive) {
this.sensitive = sensitive;
}
public Set<String> getSkipped() {
return skipped;
}
public void setSkipped(Set<String> skipped) {
this.skipped = skipped;
}
public HttpHeaders convertHeaders() {
HttpHeaders headers = new HttpHeaders();
for (String key : this.headers.keySet()) {
headers.set(key, this.headers.get(key));
}
return headers;
}
}

View File

@@ -22,6 +22,7 @@ import java.util.Map;
import java.util.Set;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
import org.springframework.cloud.gateway.webflux.ProxyExchange;
import org.springframework.http.HttpHeaders;
@@ -32,8 +33,10 @@ import org.springframework.http.HttpHeaders;
* @author Dave Syer
* @author Tim Ysewyn
* @author Joris Kuipers
* @deprecated {@link ProxyExchangeWebfluxProperties}
*
*/
@Deprecated
@ConfigurationProperties("spring.cloud.gateway.proxy")
public class ProxyProperties {
@@ -53,7 +56,7 @@ public class ProxyProperties {
private Map<String, String> headers = new LinkedHashMap<>();
/**
* A set of header names that should be send downstream by default.
* A set of header names that should be sent downstream by default.
*/
private Set<String> autoForward = new HashSet<>();
@@ -68,6 +71,7 @@ public class ProxyProperties {
*/
private Set<String> skipped = DEFAULT_SKIPPED;
@DeprecatedConfigurationProperty(replacement = ProxyExchangeWebfluxProperties.PREFIX + ".headers", since = "4.3.0")
public Map<String, String> getHeaders() {
return headers;
}
@@ -76,6 +80,8 @@ public class ProxyProperties {
this.headers = headers;
}
@DeprecatedConfigurationProperty(replacement = ProxyExchangeWebfluxProperties.PREFIX + ".auto-forward",
since = "4.3.0")
public Set<String> getAutoForward() {
return autoForward;
}
@@ -84,6 +90,8 @@ public class ProxyProperties {
this.autoForward = autoForward;
}
@DeprecatedConfigurationProperty(replacement = ProxyExchangeWebfluxProperties.PREFIX + ".sensitive",
since = "4.3.0")
public Set<String> getSensitive() {
return sensitive;
}
@@ -92,6 +100,7 @@ public class ProxyProperties {
this.sensitive = sensitive;
}
@DeprecatedConfigurationProperty(replacement = ProxyExchangeWebfluxProperties.PREFIX + ".skipped", since = "4.3.0")
public Set<String> getSkipped() {
return skipped;
}

View File

@@ -48,7 +48,7 @@ import org.springframework.web.reactive.result.method.annotation.ArgumentResolve
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication
@ConditionalOnClass({ HandlerMethodReturnValueHandler.class, WebClient.class })
@EnableConfigurationProperties(ProxyProperties.class)
@EnableConfigurationProperties({ ProxyExchangeWebfluxProperties.class, ProxyProperties.class })
public class ProxyResponseAutoConfiguration implements WebFluxConfigurer {
@Autowired
@@ -57,18 +57,18 @@ public class ProxyResponseAutoConfiguration implements WebFluxConfigurer {
@Bean
@ConditionalOnMissingBean
public ProxyExchangeArgumentResolver proxyExchangeArgumentResolver(Optional<WebClient.Builder> optional,
ProxyProperties proxy) {
ProxyExchangeWebfluxProperties properties) {
WebClient.Builder builder = optional.orElse(WebClient.builder());
WebClient template = builder.build();
ProxyExchangeArgumentResolver resolver = new ProxyExchangeArgumentResolver(template);
resolver.setHeaders(proxy.convertHeaders());
resolver.setAutoForwardedHeaders(proxy.getAutoForward());
resolver.setHeaders(properties.convertHeaders());
resolver.setAutoForwardedHeaders(properties.getAutoForward());
Set<String> excludedHeaderNames = new HashSet<>();
if (proxy.getSensitive() != null) {
excludedHeaderNames.addAll(proxy.getSensitive());
if (properties.getSensitive() != null) {
excludedHeaderNames.addAll(properties.getSensitive());
}
if (proxy.getSkipped() != null) {
excludedHeaderNames.addAll(proxy.getSkipped());
if (properties.getSkipped() != null) {
excludedHeaderNames.addAll(properties.getSkipped());
}
resolver.setExcluded(excludedHeaderNames);
return resolver;

View File

@@ -62,7 +62,8 @@ import org.springframework.web.util.UriComponentsBuilder;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(properties = { "spring.cloud.gateway.proxy.skipped=host" }, webEnvironment = WebEnvironment.RANDOM_PORT)
@SpringBootTest(properties = { "spring.cloud.gateway.proxy-exchange.webflux.skipped=host" },
webEnvironment = WebEnvironment.RANDOM_PORT)
@ContextConfiguration(classes = TestApplication.class)
@DirtiesContext
@ExtendWith(OutputCaptureExtension.class)

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2013-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.cloud.gateway.webflux.config;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.context.ActiveProfiles;
import static org.assertj.core.api.Assertions.assertThat;
@SuppressWarnings("unchecked")
@SpringBootTest(properties = {}, webEnvironment = WebEnvironment.RANDOM_PORT)
@ActiveProfiles("propertiesmigrationtests")
public class ProxyExchangeWebfluxPropertiesMigrationTests {
@Autowired
ProxyProperties properties;
@Test
public void deprecatedRoutePropertiesWork() {
assertThat(properties.getHeaders()).hasSize(2);
assertThat(properties.getAutoForward()).hasSize(2);
assertThat(properties.getSensitive()).hasSize(2);
assertThat(properties.getSkipped()).hasSize(3);
}
@SpringBootConfiguration
@EnableAutoConfiguration
protected static class TestConfiguration {
}
}

View File

@@ -0,0 +1,12 @@
spring.cloud.gateway.proxy:
headers:
X-Foo: xfooval
X-Bar: xbarval
auto-forward:
- X-FWD1
- X-FWD2
sensitive: X-S1, X-S21
skipped: X-SK1, X-SK2, X-SK3
logging:
level:
org.springframework.cloud.gateway.server.mvc: TRACE