From 09ecf0a245e243daf012006eddf0de002045c86c Mon Sep 17 00:00:00 2001 From: sgibb Date: Thu, 21 Dec 2023 11:17:03 -0500 Subject: [PATCH] Make host ignoring port opt in. This makes gh-3037 opt in by setting spring.cloud.gateway.predicate.host.include-port=false Fixes gh-3190 --- .../config/GatewayAutoConfiguration.java | 5 +- .../predicate/HostRoutePredicateFactory.java | 57 +++++++++++++------ ...itional-spring-configuration-metadata.json | 6 ++ .../HostRoutePredicateFactoryTests.java | 10 +++- .../src/test/resources/application.yml | 10 +++- 5 files changed, 66 insertions(+), 22 deletions(-) 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 2da24fe6..abcc7d1f 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 @@ -442,8 +442,9 @@ public class GatewayAutoConfiguration { @Bean @ConditionalOnEnabledPredicate - public HostRoutePredicateFactory hostRoutePredicateFactory() { - return new HostRoutePredicateFactory(); + public HostRoutePredicateFactory hostRoutePredicateFactory(Environment env) { + boolean includePort = env.getProperty("spring.cloud.gateway.predicate.host.include-port", Boolean.class, true); + return new HostRoutePredicateFactory(includePort); } @Bean diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/HostRoutePredicateFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/HostRoutePredicateFactory.java index 9cf82025..a2a07a99 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/HostRoutePredicateFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/HostRoutePredicateFactory.java @@ -35,16 +35,27 @@ import org.springframework.web.server.ServerWebExchange; */ public class HostRoutePredicateFactory extends AbstractRoutePredicateFactory { + private boolean includePort = true; + private PathMatcher pathMatcher = new AntPathMatcher("."); public HostRoutePredicateFactory() { + this(true); + } + + public HostRoutePredicateFactory(boolean includePort) { super(Config.class); + this.includePort = includePort; } public void setPathMatcher(PathMatcher pathMatcher) { this.pathMatcher = pathMatcher; } + /* for testing */ void setIncludePort(boolean includePort) { + this.includePort = includePort; + } + @Override public List shortcutFieldOrder() { return Collections.singletonList("patterns"); @@ -60,25 +71,35 @@ public class HostRoutePredicateFactory extends AbstractRoutePredicateFactory variables = pathMatcher.extractUriTemplateVariables(match, host); - ServerWebExchangeUtils.putUriTemplateVariables(exchange, variables); - return true; - } - + String host; + if (includePort) { + host = exchange.getRequest().getHeaders().getFirst("Host"); } + else { + InetSocketAddress address = exchange.getRequest().getHeaders().getHost(); + if (address != null) { + host = address.getHostString(); + } + else { + return false; + } + } + + String match = null; + for (int i = 0; i < config.getPatterns().size(); i++) { + String pattern = config.getPatterns().get(i); + if (pathMatcher.match(pattern, host)) { + match = pattern; + break; + } + } + + if (match != null) { + Map variables = pathMatcher.extractUriTemplateVariables(match, host); + ServerWebExchangeUtils.putUriTemplateVariables(exchange, variables); + return true; + } + return false; } 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 79d80429..d4fc0a54 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 @@ -418,6 +418,12 @@ "type": "java.lang.Boolean", "description": "If Micrometer Observability support should be turned on.", "defaultValue": "true" + }, + { + "name": "spring.cloud.gateway.predicate.host.include-port", + "type": "java.lang.Boolean", + "description": "Include the port in matching the host name.", + "defaultValue": "true" } ] } diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/HostRoutePredicateFactoryTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/HostRoutePredicateFactoryTests.java index b6a528d1..e70b34dd 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/HostRoutePredicateFactoryTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/HostRoutePredicateFactoryTests.java @@ -21,6 +21,7 @@ import java.util.function.Predicate; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -41,6 +42,9 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen @DirtiesContext public class HostRoutePredicateFactoryTests extends BaseWebClientTests { + @Autowired + private HostRoutePredicateFactory hostPredicate; + @Test public void hostRouteWorks() { expectHostRoute("www.example.org", "host_example_to_httpbin"); @@ -76,7 +80,11 @@ public class HostRoutePredicateFactoryTests extends BaseWebClientTests { @Test public void sameHostWithPort() { - expectHostRoute("hostpatternarg.org:8080", "without_pattern"); + expectHostRoute("hostpatternarg.org:8080", "host_with_port_pattern"); + + hostPredicate.setIncludePort(false); + expectHostRoute("hostpatternarg.org:8080", "host_without_port_pattern"); + hostPredicate.setIncludePort(true); } @Test diff --git a/spring-cloud-gateway-server/src/test/resources/application.yml b/spring-cloud-gateway-server/src/test/resources/application.yml index 5e62bd4b..2b1fde13 100644 --- a/spring-cloud-gateway-server/src/test/resources/application.yml +++ b/spring-cloud-gateway-server/src/test/resources/application.yml @@ -216,7 +216,15 @@ spring: # ===================================== - - id: without_pattern + - id: host_with_port_pattern + uri: ${test.uri} + predicates: + - name: Host + args: + pattern: 'hostpatternarg.org:8080' + + # ===================================== + - id: host_without_port_pattern uri: ${test.uri} predicates: - name: Host