diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java index e9001905..df8aca99 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java @@ -55,9 +55,9 @@ import org.springframework.cloud.gateway.filter.factory.RequestHeaderToRequestUr import org.springframework.cloud.gateway.filter.factory.RequestRateLimiterGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.RequestSizeGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.RetryGatewayFilterFactory; -import org.springframework.cloud.gateway.filter.factory.RewritePathGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.RewriteLocationResponseHeaderGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.RewriteLocationResponseHeaderGatewayFilterFactory.StripVersion; +import org.springframework.cloud.gateway.filter.factory.RewritePathGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.RewriteResponseHeaderGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.SaveSessionGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.SecureHeadersGatewayFilterFactory; @@ -488,7 +488,7 @@ public class GatewayFilterSpec extends UriSpec { public GatewayFilterSpec requestRateLimiter( Consumer configConsumer) { return filter(getBean(RequestRateLimiterGatewayFilterFactory.class) - .apply(configConsumer)); + .apply(this.routeBuilder.getId(), configConsumer)); } /** @@ -806,7 +806,7 @@ public class GatewayFilterSpec extends UriSpec { public GatewayFilterSpec configure( Consumer configConsumer) { - filter(this.filter.apply(configConsumer)); + filter(this.filter.apply(routeBuilder.getId(), configConsumer)); return GatewayFilterSpec.this; } diff --git a/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/ProxyExchange.java b/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/ProxyExchange.java index e0e34e1e..65541bdf 100644 --- a/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/ProxyExchange.java +++ b/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/ProxyExchange.java @@ -52,6 +52,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageNotWritableException; import org.springframework.util.ClassUtils; +import org.springframework.util.StringUtils; import org.springframework.validation.BindingResult; import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.bind.annotation.RequestBody; @@ -414,11 +415,14 @@ public class ProxyExchange { else { forwarded = ""; } - forwarded = forwarded + forwarded(uri); + forwarded = forwarded + forwarded(uri, webRequest.getHeader("host")); headers.set("forwarded", forwarded); } - private String forwarded(URI uri) { + private String forwarded(URI uri, String hostHeader) { + if (!StringUtils.isEmpty(hostHeader)) { + return "host=" + hostHeader; + } if ("http".equals(uri.getScheme())) { return "host=" + uri.getHost(); } diff --git a/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/ProductionConfigurationTests.java b/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/ProductionConfigurationTests.java index 18ecf85e..073b4bb8 100644 --- a/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/ProductionConfigurationTests.java +++ b/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/ProductionConfigurationTests.java @@ -110,7 +110,7 @@ public class ProductionConfigurationTests { @Test public void post() throws Exception { assertThat(rest.postForObject("/proxy/0", Collections.singletonMap("name", "foo"), - Bar.class).getName()).isEqualTo("host=localhost;foo"); + Bar.class).getName()).isEqualTo("host=localhost:" + port + ";foo"); } @Test @@ -190,13 +190,14 @@ public class ProductionConfigurationTests { .body(Collections .singletonList(Collections.singletonMap("name", "foo"))), new ParameterizedTypeReference>() { - }).getBody().iterator().next().getName()).isEqualTo("host=localhost;foo"); + }).getBody().iterator().next().getName()) + .isEqualTo("host=localhost:" + port + ";foo"); } @Test public void bodyless() throws Exception { assertThat(rest.postForObject("/proxy/0", Collections.singletonMap("name", "foo"), - Bar.class).getName()).isEqualTo("host=localhost;foo"); + Bar.class).getName()).isEqualTo("host=localhost:" + port + ";foo"); } @Test @@ -207,7 +208,8 @@ public class ProductionConfigurationTests { .expand("/proxy/entity")) .body(Collections.singletonMap("name", "foo")), new ParameterizedTypeReference>() { - }).getBody().iterator().next().getName()).isEqualTo("host=localhost;foo"); + }).getBody().iterator().next().getName()) + .isEqualTo("host=localhost:" + port + ";foo"); } @Test @@ -218,21 +220,22 @@ public class ProductionConfigurationTests { .expand("/proxy/type")) .body(Collections.singletonMap("name", "foo")), new ParameterizedTypeReference>() { - }).getBody().iterator().next().getName()).isEqualTo("host=localhost;foo"); + }).getBody().iterator().next().getName()) + .isEqualTo("host=localhost:" + port + ";foo"); } @Test public void single() throws Exception { assertThat(rest.postForObject("/proxy/single", Collections.singletonMap("name", "foobar"), Bar.class).getName()) - .isEqualTo("host=localhost;foobar"); + .isEqualTo("host=localhost:" + port + ";foobar"); } @Test public void converter() throws Exception { assertThat(rest.postForObject("/proxy/converter", Collections.singletonMap("name", "foobar"), Bar.class).getName()) - .isEqualTo("host=localhost;foobar"); + .isEqualTo("host=localhost:" + port + ";foobar"); } @Test @@ -255,6 +258,20 @@ public class ProductionConfigurationTests { assertThat(headers.get("abc")).containsOnly("123"); } + @Test + public void forwardedHeaderUsesHost() throws Exception { + Map> headers = rest + .exchange(RequestEntity + .get(rest.getRestTemplate().getUriTemplateHandler() + .expand("/proxy/headers")) + .header("host", "foo:1234").build(), Map.class) + .getBody(); + + assertThat(headers).containsKey("forwarded"); + assertThat(headers.get("forwarded").size()).isEqualTo(1); + assertThat(headers.get("forwarded").get(0)).isEqualTo("host=localhost:" + port); + } + @SpringBootApplication static class TestApplication { diff --git a/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/ProxyExchange.java b/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/ProxyExchange.java index 5c4e311d..21d94df6 100644 --- a/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/ProxyExchange.java +++ b/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/ProxyExchange.java @@ -35,6 +35,7 @@ import org.springframework.http.RequestEntity; import org.springframework.http.RequestEntity.BodyBuilder; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.util.StringUtils; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.ResponseBody; @@ -396,11 +397,15 @@ public class ProxyExchange { else { forwarded = ""; } - forwarded = forwarded + forwarded(uri); + forwarded = forwarded + + forwarded(uri, exchange.getRequest().getHeaders().getFirst("host")); headers.set("forwarded", forwarded); } - private String forwarded(URI uri) { + private String forwarded(URI uri, String hostHeader) { + if (!StringUtils.isEmpty(hostHeader)) { + return "host=" + hostHeader; + } if ("http".equals(uri.getScheme())) { return "host=" + uri.getHost(); } 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 c21743d1..87e1b714 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 @@ -114,7 +114,7 @@ public class ProductionConfigurationTests { @Test public void post() throws Exception { assertThat(rest.postForObject("/proxy/0", Collections.singletonMap("name", "foo"), - Bar.class).getName()).isEqualTo("host=localhost;foo"); + Bar.class).getName()).isEqualTo("host=localhost:" + port + ";foo"); } @Test @@ -130,13 +130,13 @@ public class ProductionConfigurationTests { new ParameterizedTypeReference>() { }); assertThat(result.getBody().iterator().next().getName()) - .isEqualTo("host=localhost;foo"); + .isEqualTo("host=localhost:" + port + ";foo"); } @Test public void bodyless() throws Exception { assertThat(rest.postForObject("/proxy/0", Collections.singletonMap("name", "foo"), - Bar.class).getName()).isEqualTo("host=localhost;foo"); + Bar.class).getName()).isEqualTo("host=localhost:" + port + ";foo"); } @Test @@ -147,7 +147,8 @@ public class ProductionConfigurationTests { .expand("/proxy/entity")) .body(Collections.singletonMap("name", "foo")), new ParameterizedTypeReference>() { - }).getBody().iterator().next().getName()).isEqualTo("host=localhost;foo"); + }).getBody().iterator().next().getName()) + .isEqualTo("host=localhost:" + port + ";foo"); } @Test @@ -158,21 +159,22 @@ public class ProductionConfigurationTests { .expand("/proxy/type")) .body(Collections.singletonMap("name", "foo")), new ParameterizedTypeReference>() { - }).getBody().iterator().next().getName()).isEqualTo("host=localhost;foo"); + }).getBody().iterator().next().getName()) + .isEqualTo("host=localhost:" + port + ";foo"); } @Test public void single() throws Exception { assertThat(rest.postForObject("/proxy/single", Collections.singletonMap("name", "foobar"), Bar.class).getName()) - .isEqualTo("host=localhost;foobar"); + .isEqualTo("host=localhost:" + port + ";foobar"); } @Test public void converter() throws Exception { assertThat(rest.postForObject("/proxy/converter", Collections.singletonMap("name", "foobar"), Bar.class).getName()) - .isEqualTo("host=localhost;foobar"); + .isEqualTo("host=localhost:" + port + ";foobar"); } @Test @@ -189,6 +191,20 @@ public class ProductionConfigurationTests { assertThat(headers.get("abc")).containsOnly("123"); } + @Test + public void forwardedHeaderUsesHost() throws Exception { + Map> headers = rest + .exchange(RequestEntity + .get(rest.getRestTemplate().getUriTemplateHandler() + .expand("/proxy/headers")) + .header("host", "foo:1234").build(), Map.class) + .getBody(); + + assertThat(headers).containsKey("forwarded"); + assertThat(headers.get("forwarded").size()).isEqualTo(1); + assertThat(headers.get("forwarded").get(0)).isEqualTo("host=localhost:" + port); + } + @SpringBootApplication static class TestApplication {