diff --git a/spring-cloud-gateway-webflux/pom.xml b/spring-cloud-gateway-webflux/pom.xml index 5859d52d..c74106d3 100644 --- a/spring-cloud-gateway-webflux/pom.xml +++ b/spring-cloud-gateway-webflux/pom.xml @@ -30,6 +30,11 @@ spring-boot-starter-actuator test + + org.springframework.boot + spring-boot-properties-migrator + test + org.springframework.boot spring-boot-configuration-processor diff --git a/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyExchangeWebfluxProperties.java b/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyExchangeWebfluxProperties.java new file mode 100644 index 00000000..3c83cceb --- /dev/null +++ b/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyExchangeWebfluxProperties.java @@ -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 + * @RequestMapping 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 DEFAULT_SENSITIVE = Set.of("cookie", "authorization"); + + /** + * Contains headers that are skipped by default. + */ + public static Set DEFAULT_SKIPPED = Set.of("content-length", "host"); + + /** + * Fixed header values that will be added to all downstream requests. + */ + private Map headers = new LinkedHashMap<>(); + + /** + * A set of header names that should be sent downstream by default. + */ + private Set autoForward = new HashSet<>(); + + /** + * A set of sensitive header names that will not be sent downstream by default. + */ + private Set sensitive = DEFAULT_SENSITIVE; + + /** + * A set of header names that will not be sent downstream because they could be + * problematic. + */ + private Set skipped = DEFAULT_SKIPPED; + + public Map getHeaders() { + return headers; + } + + public void setHeaders(Map headers) { + this.headers = headers; + } + + public Set getAutoForward() { + return autoForward; + } + + public void setAutoForward(Set autoForward) { + this.autoForward = autoForward; + } + + public Set getSensitive() { + return sensitive; + } + + public void setSensitive(Set sensitive) { + this.sensitive = sensitive; + } + + public Set getSkipped() { + return skipped; + } + + public void setSkipped(Set 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; + } + +} diff --git a/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyProperties.java b/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyProperties.java index 38e000d5..0c7184ca 100644 --- a/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyProperties.java +++ b/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyProperties.java @@ -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 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 autoForward = new HashSet<>(); @@ -68,6 +71,7 @@ public class ProxyProperties { */ private Set skipped = DEFAULT_SKIPPED; + @DeprecatedConfigurationProperty(replacement = ProxyExchangeWebfluxProperties.PREFIX + ".headers", since = "4.3.0") public Map 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 getAutoForward() { return autoForward; } @@ -84,6 +90,8 @@ public class ProxyProperties { this.autoForward = autoForward; } + @DeprecatedConfigurationProperty(replacement = ProxyExchangeWebfluxProperties.PREFIX + ".sensitive", + since = "4.3.0") public Set getSensitive() { return sensitive; } @@ -92,6 +100,7 @@ public class ProxyProperties { this.sensitive = sensitive; } + @DeprecatedConfigurationProperty(replacement = ProxyExchangeWebfluxProperties.PREFIX + ".skipped", since = "4.3.0") public Set getSkipped() { return skipped; } diff --git a/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyResponseAutoConfiguration.java b/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyResponseAutoConfiguration.java index 20ff720d..116f0b10 100644 --- a/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyResponseAutoConfiguration.java +++ b/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyResponseAutoConfiguration.java @@ -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 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 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; diff --git a/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/ProductionConfigurationTests.java b/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/ProductionConfigurationTests.java index 62b26201..732f71f8 100644 --- a/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/ProductionConfigurationTests.java +++ b/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/ProductionConfigurationTests.java @@ -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) diff --git a/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/config/ProxyExchangeWebfluxPropertiesMigrationTests.java b/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/config/ProxyExchangeWebfluxPropertiesMigrationTests.java new file mode 100644 index 00000000..b86058a8 --- /dev/null +++ b/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/config/ProxyExchangeWebfluxPropertiesMigrationTests.java @@ -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 { + + } + +} diff --git a/spring-cloud-gateway-webflux/src/test/resources/application-propertiesmigrationtests.yml b/spring-cloud-gateway-webflux/src/test/resources/application-propertiesmigrationtests.yml new file mode 100644 index 00000000..3d9b1d93 --- /dev/null +++ b/spring-cloud-gateway-webflux/src/test/resources/application-propertiesmigrationtests.yml @@ -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