Browse Source

Add SetPath filter

pull/41/head
Spencer Gibb 8 years ago
parent
commit
030798f746
No known key found for this signature in database
GPG Key ID: 7788A47380690861
  1. 6
      src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java
  2. 2
      src/main/java/org/springframework/cloud/gateway/filter/GatewayFilter.java
  3. 2
      src/main/java/org/springframework/cloud/gateway/filter/RouteToRequestUrlFilter.java
  4. 37
      src/main/java/org/springframework/cloud/gateway/filter/factory/SetPathFilterFactory.java
  5. 10
      src/main/java/org/springframework/cloud/gateway/handler/predicate/UrlPredicateFactory.java
  6. 60
      src/test/java/org/springframework/cloud/gateway/filter/factory/SetPathFilterFactoryTests.java
  7. 28
      src/test/java/org/springframework/cloud/gateway/test/GatewayIntegrationTests.java
  8. 21
      src/test/resources/application.yml

6
src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java

@ -16,6 +16,7 @@ import org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter; @@ -16,6 +16,7 @@ import org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter;
import org.springframework.cloud.gateway.filter.factory.RemoveRequestHeaderFilterFactory;
import org.springframework.cloud.gateway.filter.factory.RemoveResponseHeaderFilterFactory;
import org.springframework.cloud.gateway.filter.factory.RewritePathFilterFactory;
import org.springframework.cloud.gateway.filter.factory.SetPathFilterFactory;
import org.springframework.cloud.gateway.filter.factory.SetResponseHeaderFilterFactory;
import org.springframework.cloud.gateway.filter.factory.SetStatusFilterFactory;
import org.springframework.cloud.gateway.handler.GatewayFilteringWebHandler;
@ -140,6 +141,11 @@ public class GatewayAutoConfiguration { @@ -140,6 +141,11 @@ public class GatewayAutoConfiguration {
return new RewritePathFilterFactory();
}
@Bean
public SetPathFilterFactory setPathFilterFactory() {
return new SetPathFilterFactory();
}
@Bean
public SetResponseHeaderFilterFactory setResponseHeaderFilterFactory() {
return new SetResponseHeaderFilterFactory();

2
src/main/java/org/springframework/cloud/gateway/filter/GatewayFilter.java

@ -44,7 +44,7 @@ public interface GatewayFilter { @@ -44,7 +44,7 @@ public interface GatewayFilter {
*/
Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain);
default <T> T getAttribute(ServerWebExchange exchange, String attributeName, Class<T> type) {
static <T> T getAttribute(ServerWebExchange exchange, String attributeName, Class<T> type) {
if (exchange.getAttributes().containsKey(attributeName)) {
Object attr = exchange.getAttributes().get(attributeName);
if (type.isAssignableFrom(attr.getClass())) {

2
src/main/java/org/springframework/cloud/gateway/filter/RouteToRequestUrlFilter.java

@ -10,6 +10,8 @@ import org.springframework.web.server.ServerWebExchange; @@ -10,6 +10,8 @@ import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilterChain;
import org.springframework.web.util.UriComponentsBuilder;
import static org.springframework.cloud.gateway.filter.GatewayFilter.getAttribute;
import reactor.core.publisher.Mono;
/**

37
src/main/java/org/springframework/cloud/gateway/filter/factory/SetPathFilterFactory.java

@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
package org.springframework.cloud.gateway.filter.factory;
import java.net.URI;
import java.util.Map;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.util.UriTemplate;
import static org.springframework.cloud.gateway.filter.GatewayFilter.getAttribute;
import static org.springframework.cloud.gateway.handler.predicate.UrlPredicateFactory.URL_PREDICATE_VARS_ATTR;
/**
* @author Spencer Gibb
*/
public class SetPathFilterFactory implements FilterFactory {
@Override
@SuppressWarnings("unchecked")
public GatewayFilter apply(String template, String[] args) {
UriTemplate uriTemplate = new UriTemplate(template);
//TODO: caching can happen here
return (exchange, chain) -> {
Map<String, String> variables = getAttribute(exchange, URL_PREDICATE_VARS_ATTR, Map.class);
ServerHttpRequest req = exchange.getRequest();
URI uri = uriTemplate.expand(variables);
String newPath = uri.getPath();
ServerHttpRequest request = req.mutate()
.path(newPath)
.build();
return chain.filter(exchange.mutate().request(request).build());
};
}
}

10
src/main/java/org/springframework/cloud/gateway/handler/predicate/UrlPredicateFactory.java

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
package org.springframework.cloud.gateway.handler.predicate;
import java.util.Map;
import java.util.function.Predicate;
import org.springframework.util.AntPathMatcher;
@ -12,6 +13,8 @@ import org.springframework.web.server.support.HttpRequestPathHelper; @@ -12,6 +13,8 @@ import org.springframework.web.server.support.HttpRequestPathHelper;
*/
public class UrlPredicateFactory implements PredicateFactory {
public static final String URL_PREDICATE_VARS_ATTR = "urlPredicateVars";
private PathMatcher pathMatcher = new AntPathMatcher();
private HttpRequestPathHelper pathHelper = new HttpRequestPathHelper();
@ -40,7 +43,12 @@ public class UrlPredicateFactory implements PredicateFactory { @@ -40,7 +43,12 @@ public class UrlPredicateFactory implements PredicateFactory {
public Predicate<ServerWebExchange> apply(String pattern, String[] args) {
return exchange -> {
String lookupPath = getPathHelper().getLookupPathForRequest(exchange);
return getPathMatcher().match(pattern, lookupPath);
boolean match = getPathMatcher().match(pattern, lookupPath);
if (match) {
Map<String, String> variables = getPathMatcher().extractUriTemplateVariables(pattern, lookupPath);
exchange.getAttributes().put(URL_PREDICATE_VARS_ATTR, variables);
}
return match;
//TODO: support trailingSlashMatch
};
}

60
src/test/java/org/springframework/cloud/gateway/filter/factory/SetPathFilterFactoryTests.java

@ -0,0 +1,60 @@ @@ -0,0 +1,60 @@
package org.springframework.cloud.gateway.filter.factory;
import org.assertj.core.api.Assertions;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.handler.predicate.UrlPredicateFactory;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.MockServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilterChain;
import org.springframework.web.server.adapter.DefaultServerWebExchange;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import reactor.core.publisher.Mono;
import java.util.HashMap;
/**
* @author Spencer Gibb
*/
public class SetPathFilterFactoryTests {
@Test
public void rewritePathFilterWorks() {
HashMap<String, String> variables = new HashMap<>();
testRewriteFilter("/baz/bar", "/foo/bar", "/baz/bar", variables);
}
@Test
public void setPathFilterWithTemplateVarsWorks() {
HashMap<String, String> variables = new HashMap<>();
variables.put("id", "123");
testRewriteFilter("/bar/baz/{id}", "/foo/123", "/bar/baz/123", variables);
}
private void testRewriteFilter(String template, String actualPath, String expectedPath, HashMap<String, String> variables) {
GatewayFilter filter = new SetPathFilterFactory().apply(template, new String[]{});
MockServerHttpRequest request = MockServerHttpRequest
.get("http://localhost"+ actualPath)
.build();
DefaultServerWebExchange exchange = new DefaultServerWebExchange(request, new MockServerHttpResponse());
exchange.getAttributes().put(UrlPredicateFactory.URL_PREDICATE_VARS_ATTR, variables);
WebFilterChain filterChain = mock(WebFilterChain.class);
ArgumentCaptor<ServerWebExchange> captor = ArgumentCaptor.forClass(ServerWebExchange.class);
when(filterChain.filter(captor.capture())).thenReturn(Mono.empty());
filter.filter(exchange, filterChain);
ServerWebExchange webExchange = captor.getValue();
Assertions.assertThat(webExchange.getRequest().getURI().getPath()).isEqualTo(expectedPath);
}
}

28
src/test/java/org/springframework/cloud/gateway/test/GatewayIntegrationTests.java

@ -258,6 +258,26 @@ public class GatewayIntegrationTests { @@ -258,6 +258,26 @@ public class GatewayIntegrationTests {
);
}
@Test
public void setPathFilterWorks() {
Mono<ClientResponse> result = webClient.exchange(
GET("http://localhost:" + port + "/foo/get")
.header("Host", "www.setpath.org")
.build()
);
verify( () ->
StepVerifier.create(result)
.consumeNextWith(
response -> {
HttpStatus statusCode = response.statusCode();
assertThat(statusCode).isEqualTo(HttpStatus.OK);
})
.expectComplete()
.verify(Duration.ofSeconds(3))
);
}
@Test
public void setResponseHeaderFilterWorks() {
Mono<ClientResponse> result = webClient.exchange(
@ -281,14 +301,14 @@ public class GatewayIntegrationTests { @@ -281,14 +301,14 @@ public class GatewayIntegrationTests {
@Test
@Ignore("TODO: figure out how to set the status before response committed")
public void setStatusStringWorks() {
setStatusStringTest("www.setstatusstring.org", HttpStatus.BAD_REQUEST);
public void setStatusIntWorks() {
setStatusStringTest("www.setstatusint.org", HttpStatus.UNAUTHORIZED);
}
@Test
@Ignore("TODO: figure out how to set the status before response committed")
public void setStatusIntWorks() {
setStatusStringTest("www.setstatusint.org", HttpStatus.UNAUTHORIZED);
public void setStatusStringWorks() {
setStatusStringTest("www.setstatusstring.org", HttpStatus.BAD_REQUEST);
}
private void setStatusStringTest(String host, HttpStatus status) {

21
src/test/resources/application.yml

@ -57,6 +57,15 @@ spring: @@ -57,6 +57,15 @@ spring:
- AddResponseHeader=X-Request-Foo, Bar
- RemoveResponseHeader=X-Request-Foo
# =====================================
- id: set_path_test
uri: http://httpbin.org:80
predicates:
- Host=**.setpath.org
- Url=/foo/{segment}
filters:
- SetPath=/{segment}
# =====================================
- id: set_response_header_test
uri: http://httpbin.org:80
@ -69,22 +78,22 @@ spring: @@ -69,22 +78,22 @@ spring:
- SetResponseHeader=X-Request-Foo, Bar
# =====================================
- id: set_status_string_test
- id: set_status_int_test
uri: http://httpbin.org:80
predicates:
- Host=**.setstatusstring.org
- Host=**.setstatusint.org
- Url=/headers
filters:
- SetStatus=BAD_REQUEST
- SetStatus=401
# =====================================
- id: set_status_int_test
- id: set_status_string_test
uri: http://httpbin.org:80
predicates:
- Host=**.setstatusint.org
- Host=**.setstatusstring.org
- Url=/headers
filters:
- SetStatus=401
- SetStatus=BAD_REQUEST
# =====================================
- id: rewrite_path_test

Loading…
Cancel
Save