diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index be248adf..801097a0 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -19,7 +19,7 @@ jobs: - name: Set up JDK uses: actions/setup-java@v4 with: - distribution: 'temurin' + distribution: 'liberica' java-version: '17' cache: 'maven' - name: Build with Maven diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/seturi-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/seturi-factory.adoc new file mode 100644 index 00000000..2251d13b --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/seturi-factory.adoc @@ -0,0 +1,26 @@ +[[seturi-gatewayfilter-factory]] += `SetRequestUri` `GatewayFilter` Factory + +The `SetRequestUri` `GatewayFilter` factory takes a `uri` parameter. +It offers a simple way to manipulate the request uri by allowing templated segments of the path. +This uses the URI templates from Spring Framework. +Multiple matching segments are allowed. +The following listing configures a `SetRequestUri` `GatewayFilter`: + +.application.yml +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: seturi_route + uri: no://op + predicates: + - Path=/{appId}/** + filters: + - SetRequestUri=http://{appId}.example.com +---- + +For a request path of `/red-application/blue`, this sets the uri to `http://red-application.example.com` before making the downstream request and the final url, including path is going to be `http://red-application.example.com/red-application/blue` + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/starter.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/starter.adoc index 6d3b7bd8..d8f759ce 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/starter.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/starter.adoc @@ -5,7 +5,7 @@ To include Spring Cloud Gateway Server Web MVC in your project, use the starter with a group ID of `org.springframework.cloud` and an artifact ID of `spring-cloud-starter-gateway-server-webmvc`. See the https://projects.spring.io/spring-cloud/[Spring Cloud Project page] for details on setting up your build system with the current Spring Cloud Release Train. -If you include the starter, but you do not want the gateway to be enabled, set `spring.cloud.gateway.mvc.enabled=false`. +If you include the starter, but you do not want the gateway to be enabled, set `spring.cloud.gateway.server.webmvc.enabled=false`. IMPORTANT: Spring Cloud Gateway Server MVC is built on https://spring.io/projects/spring-boot#learn[Spring Boot] and https://docs.spring.io/spring-framework/reference/web/webmvc-functional.html[Spring WebMvc.fn]. As a consequence, many of the asynchronous or reactive libraries may not apply when you use Spring Cloud Gateway Server MVC. diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index ad20bf03..01c47d60 100644 --- a/spring-cloud-gateway-server-mvc/pom.xml +++ b/spring-cloud-gateway-server-mvc/pom.xml @@ -146,4 +146,30 @@ test + + + + github_actions + + + + env.GITHUB_ACTIONS + true + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + host + + + + + + + diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayMvcClassPathWarningAutoConfiguration.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayMvcClassPathWarningAutoConfiguration.java index 4fef7bc7..21173cf9 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayMvcClassPathWarningAutoConfiguration.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayMvcClassPathWarningAutoConfiguration.java @@ -22,11 +22,12 @@ import org.apache.commons.logging.LogFactory; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.gateway.server.mvc.config.GatewayMvcProperties; import org.springframework.context.annotation.Configuration; @Configuration(proxyBeanMethods = false) @AutoConfigureBefore(GatewayServerMvcAutoConfiguration.class) -@ConditionalOnProperty(name = "spring.cloud.gateway.mvc.enabled", matchIfMissing = true) +@ConditionalOnProperty(name = GatewayMvcProperties.PREFIX + ".enabled", matchIfMissing = true) public class GatewayMvcClassPathWarningAutoConfiguration { private static final Log log = LogFactory.getLog(GatewayMvcClassPathWarningAutoConfiguration.class); diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java index 37cd5245..2aecabe1 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java @@ -78,7 +78,7 @@ import org.springframework.web.client.RestClient; @AutoConfiguration(after = { HttpClientAutoConfiguration.class, RestTemplateAutoConfiguration.class, RestClientAutoConfiguration.class, FilterAutoConfiguration.class, HandlerFunctionAutoConfiguration.class, PredicateAutoConfiguration.class }) -@ConditionalOnProperty(name = "spring.cloud.gateway.mvc.enabled", matchIfMissing = true) +@ConditionalOnProperty(name = GatewayMvcProperties.PREFIX + ".enabled", matchIfMissing = true) @Import(GatewayMvcPropertiesBeanDefinitionRegistrar.class) @ImportRuntimeHints(GatewayMvcAotRuntimeHintsRegistrar.class) public class GatewayServerMvcAutoConfiguration { diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java index 80e859ac..ce2b2404 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java @@ -45,7 +45,6 @@ import org.springframework.web.server.ResponseStatusException; import org.springframework.web.servlet.function.ServerRequest; import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.UriTemplate; -import org.springframework.web.util.UriUtils; import static org.springframework.cloud.gateway.server.mvc.common.MvcUtils.CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR; import static org.springframework.util.CollectionUtils.unmodifiableMultiValueMap; @@ -216,7 +215,7 @@ public abstract class BeforeFilterFunctions { MultiValueMap queryParams = new LinkedMultiValueMap<>(request.params()); queryParams.remove(name); - MultiValueMap encodedQueryParams = UriUtils.encodeQueryParams(queryParams); + MultiValueMap encodedQueryParams = MvcUtils.encodeQueryParams(queryParams); // remove from uri URI newUri = UriComponentsBuilder.fromUri(request.uri()) diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java index 0eb0ff71..01f8f9f4 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 the original author or authors. + * 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. @@ -34,6 +34,7 @@ import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder; import org.springframework.boot.http.client.ClientHttpRequestFactorySettings; import org.springframework.boot.http.client.SimpleClientHttpRequestFactoryBuilder; +import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.cloud.gateway.server.mvc.filter.FilterAutoConfiguration; import org.springframework.cloud.gateway.server.mvc.filter.FormFilter; @@ -47,6 +48,7 @@ import org.springframework.cloud.gateway.server.mvc.filter.WeightCalculatorFilte import org.springframework.cloud.gateway.server.mvc.filter.XForwardedRequestHeadersFilter; import org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctionAutoConfiguration; import org.springframework.cloud.gateway.server.mvc.predicate.PredicateAutoConfiguration; +import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient; import org.springframework.context.ConfigurableApplicationContext; import static org.assertj.core.api.Assertions.assertThat; @@ -204,6 +206,27 @@ public class GatewayServerMvcAutoConfigurationTests { assertThat(builder).isInstanceOf(SimpleClientHttpRequestFactoryBuilder.class); } + @Test + void loadBalancerFunctionHandlerAdded() { + new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(FilterAutoConfiguration.class, PredicateAutoConfiguration.class, + HandlerFunctionAutoConfiguration.class, GatewayServerMvcAutoConfiguration.class, + HttpClientAutoConfiguration.class, RestTemplateAutoConfiguration.class, + RestClientAutoConfiguration.class)) + .run(context -> assertThat(context).hasBean("lbHandlerFunctionDefinition")); + } + + @Test + void loadBalancerFunctionHandlerNotAddedWhenNoLoadBalancerClientOnClasspath() { + new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(FilterAutoConfiguration.class, PredicateAutoConfiguration.class, + HandlerFunctionAutoConfiguration.class, GatewayServerMvcAutoConfiguration.class, + HttpClientAutoConfiguration.class, RestTemplateAutoConfiguration.class, + RestClientAutoConfiguration.class)) + .withClassLoader(new FilteredClassLoader(LoadBalancerClient.class)) + .run(context -> assertThat(context).doesNotHaveBean("lbHandlerFunctionDefinition")); + } + @SpringBootConfiguration @EnableAutoConfiguration static class TestConfig { diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcLoadBalancerIntegrationTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcLoadBalancerIntegrationTests.java new file mode 100644 index 00000000..d2e5889b --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcLoadBalancerIntegrationTests.java @@ -0,0 +1,62 @@ +/* + * 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.server.mvc; + +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.cloud.gateway.server.mvc.filter.FilterAutoConfiguration; +import org.springframework.cloud.gateway.server.mvc.test.HttpbinTestcontainers; +import org.springframework.cloud.gateway.server.mvc.test.TestLoadBalancerConfig; +import org.springframework.cloud.gateway.server.mvc.test.client.TestRestClient; +import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; + +/** + * Integration tests for {@link FilterAutoConfiguration.LoadBalancerHandlerConfiguration}. + * + * @author Olga Maciaszek-Sharma + * + */ +@SpringBootTest(classes = { ServerMvcLoadBalancerIntegrationTests.Config.class, FilterAutoConfiguration.class }, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ContextConfiguration(initializers = HttpbinTestcontainers.class) +@ActiveProfiles("lb") +public class ServerMvcLoadBalancerIntegrationTests { + + @LocalServerPort + int port; + + @Autowired + TestRestClient testRestClient; + + @Test + void shouldUseLbHandlerFunctionDefinitionToResolveHost() { + testRestClient.get().uri("http://localhost:" + port + "/test").exchange().expectStatus().isOk(); + } + + @SpringBootApplication + @LoadBalancerClient(name = "httpbin", configuration = TestLoadBalancerConfig.Httpbin.class) + static class Config { + + } + +} diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/VanillaRouterFunctionTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/VanillaRouterFunctionTests.java index fd96c938..81d1128c 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/VanillaRouterFunctionTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/VanillaRouterFunctionTests.java @@ -43,7 +43,7 @@ import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFuncti import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.host; @SuppressWarnings("unchecked") -@SpringBootTest(properties = { "spring.cloud.gateway.mvc.http-client.type=jdk" }, +@SpringBootTest(properties = { "spring.http.client.factory=jdk" }, webEnvironment = WebEnvironment.RANDOM_PORT) @ContextConfiguration(initializers = HttpbinTestcontainers.class) public class VanillaRouterFunctionTests { diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java index 1ef0b2c7..90dd5e19 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java @@ -119,6 +119,7 @@ class BeforeFilterFunctionsTests { MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/path") .param("foo[]", "bar") .param("baz", "qux") + .param("quux", "corge+") .buildRequest(null); ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList()); @@ -126,7 +127,9 @@ class BeforeFilterFunctionsTests { ServerRequest result = BeforeFilterFunctions.rewriteRequestParameter("foo[]", "replacement[]").apply(request); assertThat(result.param("foo[]")).isPresent().hasValue("replacement[]"); - assertThat(result.uri().toString()).hasToString("http://localhost/path?baz=qux&foo%5B%5D=replacement%5B%5D"); + assertThat(result.param("quux")).isPresent().hasValue("corge+"); + assertThat(result.uri().toString()) + .hasToString("http://localhost/path?quux=corge%2B&baz=qux&foo%5B%5D=replacement%5B%5D"); } @Test diff --git a/spring-cloud-gateway-server-mvc/src/test/resources/application-functionhandlerconfigtests.yml b/spring-cloud-gateway-server-mvc/src/test/resources/application-functionhandlerconfigtests.yml index c7430ca4..847e7057 100644 --- a/spring-cloud-gateway-server-mvc/src/test/resources/application-functionhandlerconfigtests.yml +++ b/spring-cloud-gateway-server-mvc/src/test/resources/application-functionhandlerconfigtests.yml @@ -1,4 +1,4 @@ -spring.cloud.gateway.mvc: +spring.cloud.gateway.server.webmvc: routesMap: testsimplefunction: uri: fn:upper diff --git a/spring-cloud-gateway-server-mvc/src/test/resources/application-lb.yml b/spring-cloud-gateway-server-mvc/src/test/resources/application-lb.yml new file mode 100644 index 00000000..9d0437b3 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/resources/application-lb.yml @@ -0,0 +1,11 @@ +spring: + cloud: + gateway: + mvc: + routes: + - id: test + uri: lb://httpbin + predicates: + - Path=/test/** + filters: + - StripPrefix=1 \ No newline at end of file diff --git a/spring-cloud-gateway-server-mvc/src/test/resources/application-propertiesbeandefinitionregistrartests.yml b/spring-cloud-gateway-server-mvc/src/test/resources/application-propertiesbeandefinitionregistrartests.yml index a91fe14d..cd55ac63 100644 --- a/spring-cloud-gateway-server-mvc/src/test/resources/application-propertiesbeandefinitionregistrartests.yml +++ b/spring-cloud-gateway-server-mvc/src/test/resources/application-propertiesbeandefinitionregistrartests.yml @@ -1,4 +1,4 @@ -spring.cloud.gateway.mvc: +spring.cloud.gateway.server.webmvc: routesMap: route1: uri: https://example1.com diff --git a/spring-cloud-gateway-server-mvc/src/test/resources/application-streamhandlerconfigtests.yml b/spring-cloud-gateway-server-mvc/src/test/resources/application-streamhandlerconfigtests.yml index 3e97fc80..00cfc6b9 100644 --- a/spring-cloud-gateway-server-mvc/src/test/resources/application-streamhandlerconfigtests.yml +++ b/spring-cloud-gateway-server-mvc/src/test/resources/application-streamhandlerconfigtests.yml @@ -1,4 +1,4 @@ -spring.cloud.gateway.mvc: +spring.cloud.gateway.server.webmvc: routesMap: testsimplestream: uri: stream:hello-out-0 diff --git a/spring-cloud-gateway-server-mvc/src/test/resources/application-stripprefixstaticport.yml b/spring-cloud-gateway-server-mvc/src/test/resources/application-stripprefixstaticport.yml index c27795c3..184cfee5 100644 --- a/spring-cloud-gateway-server-mvc/src/test/resources/application-stripprefixstaticport.yml +++ b/spring-cloud-gateway-server-mvc/src/test/resources/application-stripprefixstaticport.yml @@ -1,5 +1,5 @@ strip.prefix.static.uri: http://${httpbin.host}:${httpbin.port} -spring.cloud.gateway.mvc: +spring.cloud.gateway.server.webmvc: routes: - id: strip_prefix_static_port_config uri: ${strip.prefix.static.uri} diff --git a/spring-cloud-gateway-server-mvc/src/test/resources/application-weightrequestpredicateintegrationtests.yml b/spring-cloud-gateway-server-mvc/src/test/resources/application-weightrequestpredicateintegrationtests.yml index 69d927b8..f4dc97ad 100644 --- a/spring-cloud-gateway-server-mvc/src/test/resources/application-weightrequestpredicateintegrationtests.yml +++ b/spring-cloud-gateway-server-mvc/src/test/resources/application-weightrequestpredicateintegrationtests.yml @@ -1,4 +1,4 @@ -spring.cloud.gateway.mvc: +spring.cloud.gateway.server.webmvc: routes: - id: weight_high_test uri: https://examplel1.com diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java index 3acaa689..b5022c46 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java @@ -111,6 +111,7 @@ import org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties; import org.springframework.cloud.gateway.filter.factory.SetPathGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.SetRequestHeaderGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.SetRequestHostHeaderGatewayFilterFactory; +import org.springframework.cloud.gateway.filter.factory.SetRequestUriGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.SetResponseHeaderGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.SetStatusGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.StripPrefixGatewayFilterFactory; @@ -722,6 +723,12 @@ public class GatewayAutoConfiguration { return new RequestHeaderToRequestUriGatewayFilterFactory(); } + @Bean + @ConditionalOnEnabledFilter + public SetRequestUriGatewayFilterFactory setRequestUriGatewayFilterFactory() { + return new SetRequestUriGatewayFilterFactory(); + } + @Bean @ConditionalOnEnabledFilter public RequestSizeGatewayFilterFactory requestSizeGatewayFilterFactory() { diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveRequestParameterGatewayFilterFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveRequestParameterGatewayFilterFactory.java index 9d17f6ef..b8469337 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveRequestParameterGatewayFilterFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveRequestParameterGatewayFilterFactory.java @@ -24,12 +24,12 @@ import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.support.ServerWebExchangeUtils; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.util.UriComponentsBuilder; -import org.springframework.web.util.UriUtils; import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator; import static org.springframework.util.CollectionUtils.unmodifiableMultiValueMap; @@ -59,7 +59,8 @@ public class RemoveRequestParameterGatewayFilterFactory queryParams.remove(config.getName()); try { - MultiValueMap encodedQueryParams = UriUtils.encodeQueryParams(queryParams); + MultiValueMap encodedQueryParams = ServerWebExchangeUtils + .encodeQueryParams(queryParams); URI newUri = UriComponentsBuilder.fromUri(request.getURI()) .replaceQueryParams(unmodifiableMultiValueMap(encodedQueryParams)) .build(true) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RewriteRequestParameterGatewayFilterFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RewriteRequestParameterGatewayFilterFactory.java index 02bccdaf..18f5e588 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RewriteRequestParameterGatewayFilterFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RewriteRequestParameterGatewayFilterFactory.java @@ -24,13 +24,13 @@ import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.support.ServerWebExchangeUtils; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.util.Assert; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.util.UriComponentsBuilder; -import org.springframework.web.util.UriUtils; import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator; import static org.springframework.util.CollectionUtils.unmodifiableMultiValueMap; @@ -71,7 +71,8 @@ public class RewriteRequestParameterGatewayFilterFactory } try { - MultiValueMap encodedQueryParams = UriUtils.encodeQueryParams(queryParams); + MultiValueMap encodedQueryParams = ServerWebExchangeUtils + .encodeQueryParams(queryParams); URI uri = uriComponentsBuilder.replaceQueryParams(unmodifiableMultiValueMap(encodedQueryParams)) .build(true) .toUri(); diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactory.java new file mode 100644 index 00000000..1fbdfaed --- /dev/null +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactory.java @@ -0,0 +1,112 @@ +/* + * Copyright 2013-2020 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.filter.factory; + +import java.net.URI; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.cloud.gateway.filter.GatewayFilter; +import org.springframework.cloud.gateway.filter.OrderedGatewayFilter; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.util.UriComponentsBuilder; + +import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator; +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.getUriTemplateVariables; + +/** + * This filter changes the request uri. + * + * @author Stepan Mikhailiuk + */ +public class SetRequestUriGatewayFilterFactory + extends AbstractChangeRequestUriGatewayFilterFactory { + + private static final Logger log = LoggerFactory.getLogger(SetRequestUriGatewayFilterFactory.class); + + public SetRequestUriGatewayFilterFactory() { + super(Config.class); + } + + @Override + public List shortcutFieldOrder() { + return Arrays.asList(NAME_KEY); + } + + @Override + public GatewayFilter apply(Config config) { + // AbstractChangeRequestUriGatewayFilterFactory.apply() returns + // OrderedGatewayFilter + OrderedGatewayFilter gatewayFilter = (OrderedGatewayFilter) super.apply(config); + return new OrderedGatewayFilter(gatewayFilter, gatewayFilter.getOrder()) { + @Override + public String toString() { + return filterToStringCreator(SetRequestUriGatewayFilterFactory.this) + .append("template", config.getTemplate()) + .toString(); + } + }; + } + + String getUri(ServerWebExchange exchange, Config config) { + String template = config.getTemplate(); + + if (template.indexOf('{') == -1) { + return template; + } + + Map variables = getUriTemplateVariables(exchange); + return UriComponentsBuilder.fromUriString(template).build().expand(variables).toUriString(); + } + + @Override + protected Optional determineRequestUri(ServerWebExchange exchange, Config config) { + try { + String url = getUri(exchange, config); + URI uri = URI.create(url); + if (!uri.isAbsolute()) { + log.info("Request url is invalid: url={}, error=URI is not absolute", url); + return Optional.ofNullable(null); + } + return Optional.of(uri); + } + catch (IllegalArgumentException e) { + log.info("Request url is invalid : url={}, error={}", config.getTemplate(), e.getMessage()); + return Optional.ofNullable(null); + } + } + + public static class Config { + + private String template; + + public String getTemplate() { + return template; + } + + public void setTemplate(String template) { + this.template = template; + } + + } + +} diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java index 47723b74..8b87e45a 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java @@ -58,6 +58,7 @@ import org.springframework.cloud.gateway.filter.factory.RemoveRequestParameterGa import org.springframework.cloud.gateway.filter.factory.RemoveResponseHeaderGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.RequestHeaderSizeGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.RequestHeaderToRequestUriGatewayFilterFactory; +import org.springframework.cloud.gateway.filter.factory.SetRequestUriGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.RequestRateLimiterGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.RequestSizeGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.RetryGatewayFilterFactory; @@ -869,6 +870,16 @@ public class GatewayFilterSpec extends UriSpec { return filter(getBean(RequestHeaderToRequestUriGatewayFilterFactory.class).apply(c -> c.setName(headerName))); } + /** + * A filter which changes the URI the request will be routed to by the Gateway by + * pulling it from a header on the request. + * @param uri the URI + * @return a {@link GatewayFilterSpec} that can be used to apply additional filters + */ + public GatewayFilterSpec setRequestUri(String uri) { + return filter(getBean(SetRequestUriGatewayFilterFactory.class).apply(c -> c.setTemplate(uri))); + } + /** * A filter which change the URI the request will be routed to by the Gateway. * @param determineRequestUri a {@link Function} which takes a diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/ServerWebExchangeUtils.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/ServerWebExchangeUtils.java index 7585a182..fd185504 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/ServerWebExchangeUtils.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/ServerWebExchangeUtils.java @@ -17,9 +17,11 @@ package org.springframework.cloud.gateway.support; import java.net.URI; +import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashSet; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; @@ -48,9 +50,13 @@ import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpRequestDecorator; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; import org.springframework.web.reactive.DispatcherHandler; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.util.UriComponentsBuilder; +import org.springframework.web.util.UriUtils; /** * @author Spencer Gibb @@ -260,6 +266,17 @@ public final class ServerWebExchangeUtils { return encoded; } + public static MultiValueMap encodeQueryParams(MultiValueMap params) { + MultiValueMap encodedQueryParams = new LinkedMultiValueMap<>(params.size()); + for (Map.Entry> entry : params.entrySet()) { + for (String value : entry.getValue()) { + encodedQueryParams.add(UriUtils.encode(entry.getKey(), StandardCharsets.UTF_8), + UriUtils.encode(value, StandardCharsets.UTF_8)); + } + } + return CollectionUtils.unmodifiableMultiValueMap(encodedQueryParams); + } + public static HttpStatus parse(String statusString) { HttpStatus httpStatus; diff --git a/spring-cloud-gateway-server/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-gateway-server/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 1a646d71..13464a13 100644 --- a/spring-cloud-gateway-server/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-gateway-server/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1966,16 +1966,6 @@ "since": "4.3.0" } }, - { - "name": "spring.cloud.gateway.mvc.routes", - "type": "java.util.List", - "description": "List of Routes.", - "deprecated": true, - "deprecation": { - "replacement": "spring.cloud.gateway.server.webflux.mvc.routes", - "since": "4.3.0" - } - }, { "name": "spring.cloud.gateway.observability.enabled", "type": "java.lang.Boolean", diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/conditional/DisableBuiltInFiltersTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/conditional/DisableBuiltInFiltersTests.java index b581dfa0..66eacd76 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/conditional/DisableBuiltInFiltersTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/conditional/DisableBuiltInFiltersTests.java @@ -100,6 +100,7 @@ public class DisableBuiltInFiltersTests { "spring.cloud.gateway.server.webflux.filter.secure-headers.enabled=false", "spring.cloud.gateway.server.webflux.filter.set-request-header.enabled=false", "spring.cloud.gateway.server.webflux.filter.set-request-host-header.enabled=false", + "spring.cloud.gateway.server.webflux.filter.set-request-uri.enabled=false", "spring.cloud.gateway.server.webflux.filter.set-response-header.enabled=false", "spring.cloud.gateway.server.webflux.filter.rewrite-response-header.enabled=false", "spring.cloud.gateway.server.webflux.filter.rewrite-location-response-header.enabled=false", diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RemoveRequestParameterGatewayFilterFactoryTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RemoveRequestParameterGatewayFilterFactoryTests.java index a96aef38..2eb96bb6 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RemoveRequestParameterGatewayFilterFactoryTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RemoveRequestParameterGatewayFilterFactoryTests.java @@ -16,6 +16,8 @@ package org.springframework.cloud.gateway.filter.factory; +import java.net.URI; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; @@ -24,6 +26,7 @@ import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory.NameConfig; +import org.springframework.http.HttpMethod; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; @@ -123,6 +126,23 @@ class RemoveRequestParameterGatewayFilterFactoryTests { assertThat(actualRequest.getQueryParams()).containsEntry("ccc", singletonList(",xyz")); } + @Test + void removeRequestParameterFilterShouldHandleRemainingPlusSignParams() { + MockServerHttpRequest request = MockServerHttpRequest + .method(HttpMethod.GET, URI.create("http://localhost?foo=bar&aaa=%2Bxyz")) + .build(); + exchange = MockServerWebExchange.from(request); + NameConfig config = new NameConfig(); + config.setName("foo"); + GatewayFilter filter = new RemoveRequestParameterGatewayFilterFactory().apply(config); + + filter.filter(exchange, filterChain); + + ServerHttpRequest actualRequest = captor.getValue().getRequest(); + assertThat(actualRequest.getQueryParams()).doesNotContainKey("foo"); + assertThat(actualRequest.getQueryParams()).containsEntry("aaa", singletonList("+xyz")); + } + @Test void removeRequestParameterFilterShouldHandleEncodedParameterName() { MockServerHttpRequest request = MockServerHttpRequest.get("http://localhost") diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RewriteRequestParameterGatewayFilterFactoryTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RewriteRequestParameterGatewayFilterFactoryTests.java index f7803861..24aa900b 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RewriteRequestParameterGatewayFilterFactoryTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RewriteRequestParameterGatewayFilterFactoryTests.java @@ -88,6 +88,12 @@ class RewriteRequestParameterGatewayFilterFactoryTests { Map.of("campaign[]", List.of("blue"), "color", List.of("white"))); } + @Test + void rewriteRequestParameterFilterWithPlusSign() { + testRewriteRequestParameterFilter("color", "white+", "campaign=blue%2B&color=green", + Map.of("campaign", List.of("blue+"), "color", List.of("white+"))); + } + private void testRewriteRequestParameterFilter(String name, String replacement, String query, Map> expectedQueryParams) { GatewayFilter filter = new RewriteRequestParameterGatewayFilterFactory() diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactoryIntegrationTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactoryIntegrationTests.java new file mode 100644 index 00000000..b52a81af --- /dev/null +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactoryIntegrationTests.java @@ -0,0 +1,79 @@ +/* + * Copyright 2013-2020 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.filter.factory; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.cloud.gateway.route.RouteLocator; +import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; +import org.springframework.cloud.gateway.test.BaseWebClientTests; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; +import org.springframework.test.annotation.DirtiesContext; + +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +/** + * @author Stepan Mikhailiuk + */ +@SpringBootTest(webEnvironment = RANDOM_PORT) +@DirtiesContext +public class SetRequestUriGatewayFilterFactoryIntegrationTests extends BaseWebClientTests { + + @LocalServerPort + int port; + + @Test + public void setUriWorkWithProperties() { + testClient.get().uri("/").header("Host", "testservice.setrequesturi.org").exchange().expectStatus().isOk(); + + testClient.get() + .uri("/service/testservice") + .header("Host", "setrequesturi.org") + .exchange() + .expectStatus() + .isOk(); + } + + @EnableAutoConfiguration + @SpringBootConfiguration + @Import(DefaultTestConfig.class) + public static class TestConfig { + + @Bean + public RouteLocator routeLocator(RouteLocatorBuilder builder) { + return builder.routes() + .route("map_subdomain_to_service_name", + r -> r.host("{serviceName}.setrequesturi.org") + .filters(f -> f.prefixPath("/httpbin").setRequestUri("lb://{serviceName}")) + .uri("no://op")) + .route("map_path_to_service_name", + r -> r.host("setrequesturi.org") + .and() + .path("/service/{serviceName}") + .filters(f -> f.rewritePath("/.*", "/").setRequestUri("lb://{serviceName}")) + .uri("no://op")) + .build(); + } + + } + +} diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactoryTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactoryTests.java new file mode 100644 index 00000000..2366b0c8 --- /dev/null +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactoryTests.java @@ -0,0 +1,83 @@ +/* + * Copyright 2013-2020 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.filter.factory; + +import java.net.URI; + +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import reactor.core.publisher.Mono; + +import org.springframework.cloud.gateway.filter.GatewayFilter; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +import org.springframework.mock.web.server.MockServerWebExchange; +import org.springframework.web.server.ServerWebExchange; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR; + +/** + * @author Stepan Mikhailiuk + */ +public class SetRequestUriGatewayFilterFactoryTests { + + @Test + public void filterChangeRequestUri() { + SetRequestUriGatewayFilterFactory factory = new SetRequestUriGatewayFilterFactory(); + GatewayFilter filter = factory.apply(c -> c.setTemplate("https://example.com")); + MockServerHttpRequest request = MockServerHttpRequest.get("http://localhost").build(); + ServerWebExchange exchange = MockServerWebExchange.from(request); + exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, URI.create("http://localhost")); + GatewayFilterChain filterChain = mock(GatewayFilterChain.class); + ArgumentCaptor captor = ArgumentCaptor.forClass(ServerWebExchange.class); + when(filterChain.filter(captor.capture())).thenReturn(Mono.empty()); + filter.filter(exchange, filterChain); + ServerWebExchange webExchange = captor.getValue(); + URI uri = (URI) webExchange.getAttributes().get(GATEWAY_REQUEST_URL_ATTR); + assertThat(uri).isNotNull(); + assertThat(uri.toString()).isEqualTo("https://example.com"); + } + + @Test + public void filterDoesNotChangeRequestUriIfUriIsInvalid() throws Exception { + SetRequestUriGatewayFilterFactory factory = new SetRequestUriGatewayFilterFactory(); + GatewayFilter filter = factory.apply(c -> c.setTemplate("invalid_uri")); + MockServerHttpRequest request = MockServerHttpRequest.get("http://localhost").build(); + ServerWebExchange exchange = MockServerWebExchange.from(request); + exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, URI.create("http://localhost")); + GatewayFilterChain filterChain = mock(GatewayFilterChain.class); + ArgumentCaptor captor = ArgumentCaptor.forClass(ServerWebExchange.class); + when(filterChain.filter(captor.capture())).thenReturn(Mono.empty()); + filter.filter(exchange, filterChain); + ServerWebExchange webExchange = captor.getValue(); + URI uri = (URI) webExchange.getAttributes().get(GATEWAY_REQUEST_URL_ATTR); + assertThat(uri).isNotNull(); + assertThat(uri.toURL().toString()).isEqualTo("http://localhost"); + } + + @Test + public void toStringFormat() { + SetRequestUriGatewayFilterFactory.Config config = new SetRequestUriGatewayFilterFactory.Config(); + config.setTemplate("http://localhost:8080"); + GatewayFilter filter = new SetRequestUriGatewayFilterFactory().apply(config); + assertThat(filter.toString()).contains("http://localhost:8080"); + } + +} diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/AdhocTestSuite.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/AdhocTestSuite.java index 38041174..bba39646 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/AdhocTestSuite.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/AdhocTestSuite.java @@ -66,6 +66,8 @@ import static org.junit.Assume.assumeThat; RewriteLocationResponseHeaderGatewayFilterFactoryTests.class, org.springframework.cloud.gateway.filter.factory.RequestRateLimiterGatewayFilterFactoryTests.class, org.springframework.cloud.gateway.filter.factory.RequestHeaderToRequestUriGatewayFilterFactoryIntegrationTests.class, + org.springframework.cloud.gateway.filter.factory.SetRequestUriGatewayFilterFactoryTests.class, + org.springframework.cloud.gateway.filter.factory.SetRequestUriGatewayFilterFactoryIntegrationTests.class, org.springframework.cloud.gateway.filter.factory.RemoveResponseHeaderGatewayFilterFactoryTests.class, org.springframework.cloud.gateway.filter.factory.RewritePathGatewayFilterFactoryTests.class, org.springframework.cloud.gateway.filter.factory.StripPrefixGatewayFilterFactoryIntegrationTests.class, diff --git a/spring-cloud-starter-gateway-mvc/pom.xml b/spring-cloud-starter-gateway-mvc/pom.xml index e86d2d1f..8e66ee4e 100644 --- a/spring-cloud-starter-gateway-mvc/pom.xml +++ b/spring-cloud-starter-gateway-mvc/pom.xml @@ -34,5 +34,10 @@ org.springframework.boot spring-boot-starter-web + + + org.springframework.boot + spring-boot-properties-migrator + diff --git a/spring-cloud-starter-gateway-server-webflux/pom.xml b/spring-cloud-starter-gateway-server-webflux/pom.xml index ab94fcc5..ed3b79c4 100644 --- a/spring-cloud-starter-gateway-server-webflux/pom.xml +++ b/spring-cloud-starter-gateway-server-webflux/pom.xml @@ -33,5 +33,10 @@ org.springframework.boot spring-boot-starter-webflux + + + org.springframework.boot + spring-boot-properties-migrator + diff --git a/spring-cloud-starter-gateway-server-webmvc/pom.xml b/spring-cloud-starter-gateway-server-webmvc/pom.xml index 00420392..14b339e1 100644 --- a/spring-cloud-starter-gateway-server-webmvc/pom.xml +++ b/spring-cloud-starter-gateway-server-webmvc/pom.xml @@ -33,5 +33,10 @@ org.springframework.boot spring-boot-starter-web + + + org.springframework.boot + spring-boot-properties-migrator + diff --git a/spring-cloud-starter-gateway/pom.xml b/spring-cloud-starter-gateway/pom.xml index 8de3f70e..9705acd7 100644 --- a/spring-cloud-starter-gateway/pom.xml +++ b/spring-cloud-starter-gateway/pom.xml @@ -34,5 +34,10 @@ org.springframework.boot spring-boot-starter-webflux + + + org.springframework.boot + spring-boot-properties-migrator +