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 9b56ea7c..a5d664b1 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; @@ -405,11 +406,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 {