From f1dbcdc0fec4f53b448398507312a5033712e166 Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Tue, 23 Jul 2019 12:48:25 -0400 Subject: [PATCH] Adds ability to expand uri variables for other filters. (#711) Currently only SetPath can use the uri variables from the path and host predicates. Now, other filters can use them thru the ServerWebExchangeUtils.expand() method. fixes gh-704 --- .../main/asciidoc/spring-cloud-gateway.adoc | 103 ++++++++++++++++++ .../AddRequestHeaderGatewayFilterFactory.java | 4 +- ...dRequestParameterGatewayFilterFactory.java | 4 +- ...AddResponseHeaderGatewayFilterFactory.java | 5 +- .../SetRequestHeaderGatewayFilterFactory.java | 5 +- ...SetResponseHeaderGatewayFilterFactory.java | 4 +- .../support/ServerWebExchangeUtils.java | 13 +++ ...equestHeaderGatewayFilterFactoryTests.java | 6 +- ...estParameterGatewayFilterFactoryTests.java | 6 +- ...sponseHeaderGatewayFilterFactoryTests.java | 8 +- ...equestHeaderGatewayFilterFactoryTests.java | 8 +- ...sponseHeaderGatewayFilterFactoryTests.java | 27 ++++- .../support/ServerWebExchangeUtilsTests.java | 67 ++++++++++++ .../src/test/resources/application.yml | 6 +- 14 files changed, 242 insertions(+), 24 deletions(-) create mode 100644 spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/support/ServerWebExchangeUtilsTests.java diff --git a/docs/src/main/asciidoc/spring-cloud-gateway.adoc b/docs/src/main/asciidoc/spring-cloud-gateway.adoc index b1c805b4..4099a2c1 100644 --- a/docs/src/main/asciidoc/spring-cloud-gateway.adoc +++ b/docs/src/main/asciidoc/spring-cloud-gateway.adoc @@ -341,6 +341,23 @@ spring: This will add `X-Request-Foo:Bar` header to the downstream request's headers for all matching requests. +AddRequestHeader is aware of URI variables used to match a path or host. URI variables may be used in the value and will be expanded at runtime. + +.application.yml +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: add_request_header_route + uri: https://example.org + predicates: + - Path=/foo/{segment} + filters: + - AddRequestHeader=X-Request-Foo, Bar-{segment} +---- + === AddRequestParameter GatewayFilter Factory The AddRequestParameter GatewayFilter Factory takes a name and value parameter. @@ -359,6 +376,23 @@ spring: This will add `foo=bar` to the downstream request's query string for all matching requests. +AddRequestParameter is aware of URI variables used to match a path or host. URI variables may be used in the value and will be expanded at runtime. + +.application.yml +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: add_request_parameter_route + uri: https://example.org + predicates: + - Host: {segment}.myhost.org + filters: + - AddRequestParameter=foo, bar-{segment} +---- + === AddResponseHeader GatewayFilter Factory The AddResponseHeader GatewayFilter Factory takes a name and value parameter. @@ -377,6 +411,23 @@ spring: This will add `X-Response-Foo:Bar` header to the downstream response's headers for all matching requests. +AddResponseHeader is aware of URI variables used to match a path or host. URI variables may be used in the value and will be expanded at runtime. + +.application.yml +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: add_response_header_route + uri: https://example.org + predicates: + - Host: {segment}.myhost.org + filters: + - AddResponseHeader=foo, bar-{segment} +---- + === DedupeResponseHeader GatewayFilter Factory The DedupeResponseHeader GatewayFilter Factory takes a `name` parameter and an optional `strategy` parameter. `name` can contain a list of header names, space separated. @@ -839,6 +890,41 @@ spring: For a request path of `/foo/bar`, this will set the path to `/bar` before making the downstream request. +=== SetRequestHeader GatewayFilter Factory +The SetRequestHeader GatewayFilter Factory takes `name` and `value` parameters. + +.application.yml +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: setrequestheader_route + uri: https://example.org + filters: + - SetRequestHeader=X-Request-Foo, Bar +---- + +This GatewayFilter replaces all headers with the given name, rather than adding. So if the downstream server responded with a `X-Request-Foo:1234`, this would be replaced with `X-Request-Foo:Bar`, which is what the downstream service would receive. + +SetRequestHeader is aware of URI variables used to match a path or host. URI variables may be used in the value and will be expanded at runtime. + +.application.yml +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: setrequestheader_route + uri: https://example.org + predicates: + - Host: {segment}.myhost.org + filters: + - SetRequestHeader=foo, bar-{segment} +---- + === SetResponseHeader GatewayFilter Factory The SetResponseHeader GatewayFilter Factory takes `name` and `value` parameters. @@ -857,6 +943,23 @@ spring: This GatewayFilter replaces all headers with the given name, rather than adding. So if the downstream server responded with a `X-Response-Foo:1234`, this would be replaced with `X-Response-Foo:Bar`, which is what the gateway client would receive. +SetResponseHeader is aware of URI variables used to match a path or host. URI variables may be used in the value and will be expanded at runtime. + +.application.yml +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: setresponseheader_route + uri: https://example.org + predicates: + - Host: {segment}.myhost.org + filters: + - SetResponseHeader=foo, bar-{segment} +---- + === SetStatus GatewayFilter Factory The SetStatus GatewayFilter Factory takes a single `status` parameter. It must be a valid Spring `HttpStatus`. It may be the integer value `404` or the string representation of the enumeration `NOT_FOUND`. diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/AddRequestHeaderGatewayFilterFactory.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/AddRequestHeaderGatewayFilterFactory.java index e224c558..4194926f 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/AddRequestHeaderGatewayFilterFactory.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/AddRequestHeaderGatewayFilterFactory.java @@ -20,6 +20,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.support.ServerWebExchangeUtils; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.web.server.ServerWebExchange; @@ -37,8 +38,9 @@ public class AddRequestHeaderGatewayFilterFactory @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + String value = ServerWebExchangeUtils.expand(exchange, config.getValue()); ServerHttpRequest request = exchange.getRequest().mutate() - .header(config.getName(), config.getValue()).build(); + .header(config.getName(), value).build(); return chain.filter(exchange.mutate().request(request).build()); } diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/AddRequestParameterGatewayFilterFactory.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/AddRequestParameterGatewayFilterFactory.java index 95f2acbd..944a9b1a 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/AddRequestParameterGatewayFilterFactory.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/AddRequestParameterGatewayFilterFactory.java @@ -22,6 +22,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.support.ServerWebExchangeUtils; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebExchange; @@ -52,10 +53,11 @@ public class AddRequestParameterGatewayFilterFactory } } + String value = ServerWebExchangeUtils.expand(exchange, config.getValue()); // TODO urlencode? query.append(config.getName()); query.append('='); - query.append(config.getValue()); + query.append(value); try { URI newUri = UriComponentsBuilder.fromUri(uri) diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactory.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactory.java index 9f262999..8298a9e1 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactory.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactory.java @@ -20,6 +20,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.support.ServerWebExchangeUtils; import org.springframework.web.server.ServerWebExchange; import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator; @@ -36,8 +37,8 @@ public class AddResponseHeaderGatewayFilterFactory @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { - exchange.getResponse().getHeaders().add(config.getName(), - config.getValue()); + String value = ServerWebExchangeUtils.expand(exchange, config.getValue()); + exchange.getResponse().getHeaders().add(config.getName(), value); return chain.filter(exchange); } diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestHeaderGatewayFilterFactory.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestHeaderGatewayFilterFactory.java index 71a743f8..923e1ea1 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestHeaderGatewayFilterFactory.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestHeaderGatewayFilterFactory.java @@ -20,6 +20,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.support.ServerWebExchangeUtils; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.web.server.ServerWebExchange; @@ -37,9 +38,9 @@ public class SetRequestHeaderGatewayFilterFactory @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + String value = ServerWebExchangeUtils.expand(exchange, config.getValue()); ServerHttpRequest request = exchange.getRequest().mutate() - .headers( - httpHeaders -> httpHeaders.set(config.name, config.value)) + .headers(httpHeaders -> httpHeaders.set(config.name, value)) .build(); return chain.filter(exchange.mutate().request(request).build()); diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/SetResponseHeaderGatewayFilterFactory.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/SetResponseHeaderGatewayFilterFactory.java index ea09569e..0ddb25e4 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/SetResponseHeaderGatewayFilterFactory.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/SetResponseHeaderGatewayFilterFactory.java @@ -20,6 +20,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.support.ServerWebExchangeUtils; import org.springframework.web.server.ServerWebExchange; import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator; @@ -36,8 +37,9 @@ public class SetResponseHeaderGatewayFilterFactory @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + String value = ServerWebExchangeUtils.expand(exchange, config.getValue()); return chain.filter(exchange).then(Mono.fromRunnable(() -> exchange - .getResponse().getHeaders().set(config.name, config.value))); + .getResponse().getHeaders().set(config.name, value))); } @Override diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/support/ServerWebExchangeUtils.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/support/ServerWebExchangeUtils.java index 74957c8a..4682de80 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/support/ServerWebExchangeUtils.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/support/ServerWebExchangeUtils.java @@ -249,6 +249,19 @@ public final class ServerWebExchangeUtils { return AsyncPredicate.from(predicate); } + public static String expand(ServerWebExchange exchange, String template) { + Assert.notNull(exchange, "exchange may not be null"); + Assert.notNull(template, "template may not be null"); + + if (template.indexOf('{') == -1) { // short circuit + return template; + } + + Map variables = getUriTemplateVariables(exchange); + return UriComponentsBuilder.fromPath(template).build().expand(variables) + .getPath(); + } + @SuppressWarnings("unchecked") public static void putUriTemplateVariables(ServerWebExchange exchange, Map uriVariables) { diff --git a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/AddRequestHeaderGatewayFilterFactoryTests.java b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/AddRequestHeaderGatewayFilterFactoryTests.java index 74b20fae..369e9eac 100644 --- a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/AddRequestHeaderGatewayFilterFactoryTests.java +++ b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/AddRequestHeaderGatewayFilterFactoryTests.java @@ -66,7 +66,7 @@ public class AddRequestHeaderGatewayFilterFactoryTests extends BaseWebClientTest .exchange().expectBody(Map.class).consumeWith(result -> { Map headers = getMap(result.getResponseBody(), "headers"); - assertThat(headers).containsEntry("X-Request-Acme", "ValueB"); + assertThat(headers).containsEntry("X-Request-Acme", "ValueB-www"); }); } @@ -89,9 +89,9 @@ public class AddRequestHeaderGatewayFilterFactoryTests extends BaseWebClientTest @Bean public RouteLocator testRouteLocator(RouteLocatorBuilder builder) { return builder.routes().route("add_request_header_java_test", - r -> r.path("/headers").and().host("**.addrequestheaderjava.org") + r -> r.path("/headers").and().host("{sub}.addrequestheaderjava.org") .filters(f -> f.prefixPath("/httpbin") - .addRequestHeader("X-Request-Acme", "ValueB")) + .addRequestHeader("X-Request-Acme", "ValueB-{sub}")) .uri(uri)) .build(); } diff --git a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/AddRequestParameterGatewayFilterFactoryTests.java b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/AddRequestParameterGatewayFilterFactoryTests.java index 03d247fd..a42fb65f 100644 --- a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/AddRequestParameterGatewayFilterFactoryTests.java +++ b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/AddRequestParameterGatewayFilterFactoryTests.java @@ -68,7 +68,7 @@ public class AddRequestParameterGatewayFilterFactoryTests extends BaseWebClientT @Test public void addRequestParameterFilterWorksEncodedQueryJavaDsl() { - testRequestParameterFilter("www.addreqparamjava.org", "ValueB", "javaname", + testRequestParameterFilter("www.addreqparamjava.org", "ValueB-www", "javaname", "%E6%89%8E%E6%A0%B9"); } @@ -129,9 +129,9 @@ public class AddRequestParameterGatewayFilterFactoryTests extends BaseWebClientT @Bean public RouteLocator testRouteLocator(RouteLocatorBuilder builder) { return builder.routes().route("add_request_param_java_test", - r -> r.path("/get").and().host("**.addreqparamjava.org") + r -> r.path("/get").and().host("{sub}.addreqparamjava.org") .filters(f -> f.prefixPath("/httpbin") - .addRequestParameter("example", "ValueB")) + .addRequestParameter("example", "ValueB-{sub}")) .uri(uri)) .build(); } diff --git a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactoryTests.java b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactoryTests.java index be476d83..939d5ac5 100644 --- a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactoryTests.java +++ b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactoryTests.java @@ -59,7 +59,7 @@ public class AddResponseHeaderGatewayFilterFactoryTests extends BaseWebClientTes URI uri = UriComponentsBuilder.fromUriString(this.baseUri + "/get").build(true) .toUri(); String host = "www.addresponseheaderjava.org"; - String expectedValue = "myresponsevalue"; + String expectedValue = "myresponsevalue-www"; testClient.get().uri(uri).header("Host", host).exchange().expectHeader() .valueEquals("example", expectedValue); } @@ -83,9 +83,9 @@ public class AddResponseHeaderGatewayFilterFactoryTests extends BaseWebClientTes @Bean public RouteLocator testRouteLocator(RouteLocatorBuilder builder) { return builder.routes().route("add_response_header_java_test", - r -> r.path("/get").and().host("**.addresponseheaderjava.org") - .filters(f -> f.prefixPath("/httpbin") - .addResponseHeader("example", "myresponsevalue")) + r -> r.path("/get").and().host("{sub}.addresponseheaderjava.org") + .filters(f -> f.prefixPath("/httpbin").addResponseHeader( + "example", "myresponsevalue-{sub}")) .uri(uri)) .build(); } diff --git a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/SetRequestHeaderGatewayFilterFactoryTests.java b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/SetRequestHeaderGatewayFilterFactoryTests.java index e1e089b0..6cdffa9e 100644 --- a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/SetRequestHeaderGatewayFilterFactoryTests.java +++ b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/SetRequestHeaderGatewayFilterFactoryTests.java @@ -55,7 +55,9 @@ public class SetRequestHeaderGatewayFilterFactoryTests extends BaseWebClientTest .consumeWith(result -> { Map headers = getMap(result.getResponseBody(), "headers"); - assertThat(headers).containsEntry("X-Req-Foo", "Second"); + // add was called first, so sets will overwrite + assertThat(headers).doesNotContainEntry("X-Req-Foo", "First"); + assertThat(headers).containsEntry("X-Req-Foo", "Second-www"); }); } @@ -78,10 +80,10 @@ public class SetRequestHeaderGatewayFilterFactoryTests extends BaseWebClientTest @Bean public RouteLocator testRouteLocator(RouteLocatorBuilder builder) { return builder.routes().route("test_set_request_header", - r -> r.order(-1).host("**.setrequestheader.org") + r -> r.order(-1).host("{sub}.setrequestheader.org") .filters(f -> f.prefixPath("/httpbin") .addRequestHeader("X-Req-Foo", "First") - .setRequestHeader("X-Req-Foo", "Second")) + .setRequestHeader("X-Req-Foo", "Second-{sub}")) .uri(uri)) .build(); } diff --git a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/SetResponseHeaderGatewayFilterFactoryTests.java b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/SetResponseHeaderGatewayFilterFactoryTests.java index 3eb1835d..66dbfee4 100644 --- a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/SetResponseHeaderGatewayFilterFactoryTests.java +++ b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/SetResponseHeaderGatewayFilterFactoryTests.java @@ -19,12 +19,16 @@ package org.springframework.cloud.gateway.filter.factory; import org.junit.Test; import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.factory.AbstractNameValueGatewayFilterFactory.NameValueConfig; +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 org.springframework.test.context.junit4.SpringRunner; @@ -41,7 +45,14 @@ public class SetResponseHeaderGatewayFilterFactoryTests extends BaseWebClientTes public void setResponseHeaderFilterWorks() { testClient.get().uri("/headers").header("Host", "www.setreresponseheader.org") .exchange().expectStatus().isOk().expectHeader() - .valueEquals("X-Request-Foo", "Bar"); + .valueEquals("X-Response-Foo", "Bar"); + } + + @Test + public void setResponseHeaderFilterWorksJavaDsl() { + testClient.get().uri("/headers").header("Host", "www.setresponseheaderdsl.org") + .exchange().expectStatus().isOk().expectHeader() + .valueEquals("X-Res-Foo", "Second-www"); } @Test @@ -57,6 +68,20 @@ public class SetResponseHeaderGatewayFilterFactoryTests extends BaseWebClientTes @Import(DefaultTestConfig.class) public static class TestConfig { + @Value("${test.uri}") + String uri; + + @Bean + public RouteLocator testRouteLocator(RouteLocatorBuilder builder) { + return builder.routes().route("test_set_response_header_dsl", + r -> r.order(-1).host("{sub}.setresponseheaderdsl.org") + .filters(f -> f.prefixPath("/httpbin") + .addResponseHeader("X-Res-Foo", "First") + .setResponseHeader("X-Res-Foo", "Second-{sub}")) + .uri(uri)) + .build(); + } + } } diff --git a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/support/ServerWebExchangeUtilsTests.java b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/support/ServerWebExchangeUtilsTests.java new file mode 100644 index 00000000..47793364 --- /dev/null +++ b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/support/ServerWebExchangeUtilsTests.java @@ -0,0 +1,67 @@ +/* + * Copyright 2013-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.support; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +import org.springframework.mock.web.server.MockServerWebExchange; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.expand; + +public class ServerWebExchangeUtilsTests { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void expandWorks() { + HashMap vars = new HashMap<>(); + vars.put("foo", "bar"); + vars.put("baz", "bam"); + + MockServerWebExchange exchange = mockExchange(vars); + + String expanded = expand(exchange, "my-{foo}-{baz}"); + assertThat(expanded).isEqualTo("my-bar-bam"); + + expanded = expand(exchange, "my-noop"); + assertThat(expanded).isEqualTo("my-noop"); + } + + @Test + public void missingVarThrowsException() { + MockServerWebExchange exchange = mockExchange(Collections.emptyMap()); + thrown.expect(IllegalArgumentException.class); + expand(exchange, "my-{foo}-{baz}"); + } + + private MockServerWebExchange mockExchange(Map vars) { + MockServerHttpRequest request = MockServerHttpRequest.get("/get").build(); + MockServerWebExchange exchange = MockServerWebExchange.from(request); + ServerWebExchangeUtils.putUriTemplateVariables(exchange, vars); + return exchange; + } + +} diff --git a/spring-cloud-gateway-core/src/test/resources/application.yml b/spring-cloud-gateway-core/src/test/resources/application.yml index 7840337a..7929ca31 100644 --- a/spring-cloud-gateway-core/src/test/resources/application.yml +++ b/spring-cloud-gateway-core/src/test/resources/application.yml @@ -303,9 +303,9 @@ spring: - Host=**.setreresponseheader.org - Path=/headers filters: - - AddResponseHeader=X-Request-Foo, Bar1 - - AddResponseHeader=X-Request-Foo, Bar2 - - SetResponseHeader=X-Request-Foo, Bar + - AddResponseHeader=X-Response-Foo, Bar1 + - AddResponseHeader=X-Response-Foo, Bar2 + - SetResponseHeader=X-Response-Foo, Bar # ===================================== - id: set_status_int_test