Merge branch '4.0.x'

This commit is contained in:
Ryan Baxter
2023-12-05 11:18:06 -05:00
5 changed files with 134 additions and 10 deletions

View File

@@ -309,7 +309,6 @@
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>

View File

@@ -30,6 +30,7 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.Assert;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;
import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.setResponseStatus;
@@ -50,40 +51,66 @@ public class RedirectToGatewayFilterFactory
*/
public static final String URL_KEY = "url";
/**
* IncludeRequestParams key.
*/
public static final String INCLUDE_REQUEST_PARAMS_KEY = "includeRequestParams";
public RedirectToGatewayFilterFactory() {
super(Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList(STATUS_KEY, URL_KEY);
return Arrays.asList(STATUS_KEY, URL_KEY, INCLUDE_REQUEST_PARAMS_KEY);
}
@Override
public GatewayFilter apply(Config config) {
return apply(config.status, config.url);
return apply(config.status, config.url, config.includeRequestParams);
}
public GatewayFilter apply(String statusString, String urlString) {
return apply(statusString, urlString, false);
}
public GatewayFilter apply(String statusString, String urlString, boolean includeRequestParams) {
HttpStatusHolder httpStatus = HttpStatusHolder.parse(statusString);
Assert.isTrue(httpStatus.is3xxRedirection(), "status must be a 3xx code, but was " + statusString);
final URI url = URI.create(urlString);
return apply(httpStatus, url);
return apply(httpStatus, url, includeRequestParams);
}
public GatewayFilter apply(HttpStatus httpStatus, URI uri) {
return apply(new HttpStatusHolder(httpStatus, null), uri);
return apply(new HttpStatusHolder(httpStatus, null), uri, false);
}
public GatewayFilter apply(HttpStatus httpStatus, URI uri, boolean includeRequestParams) {
return apply(new HttpStatusHolder(httpStatus, null), uri, includeRequestParams);
}
public GatewayFilter apply(HttpStatusHolder httpStatus, URI uri) {
return apply(httpStatus, uri, false);
}
public GatewayFilter apply(HttpStatusHolder httpStatus, URI uri, boolean includeRequestParams) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
if (!exchange.getResponse().isCommitted()) {
setResponseStatus(exchange, httpStatus);
String location;
if (includeRequestParams) {
location = UriComponentsBuilder.fromUri(uri).queryParams(exchange.getRequest().getQueryParams())
.build().toUri().toString();
}
else {
location = uri.toString();
}
final ServerHttpResponse response = exchange.getResponse();
response.getHeaders().set(HttpHeaders.LOCATION, uri.toString());
response.getHeaders().set(HttpHeaders.LOCATION, location);
return response.setComplete();
}
return Mono.empty();
@@ -98,7 +125,8 @@ public class RedirectToGatewayFilterFactory
else {
status = httpStatus.getStatus().toString();
}
return filterToStringCreator(RedirectToGatewayFilterFactory.this).append(status, uri).toString();
return filterToStringCreator(RedirectToGatewayFilterFactory.this).append(status, uri)
.append(INCLUDE_REQUEST_PARAMS_KEY, includeRequestParams).toString();
}
};
}
@@ -109,6 +137,8 @@ public class RedirectToGatewayFilterFactory
String url;
boolean includeRequestParams;
public String getStatus() {
return status;
}
@@ -125,6 +155,14 @@ public class RedirectToGatewayFilterFactory
this.url = url;
}
public boolean isIncludeRequestParams() {
return includeRequestParams;
}
public void setIncludeRequestParams(boolean includeRequestParams) {
this.includeRequestParams = includeRequestParams;
}
}
}

View File

@@ -471,6 +471,18 @@ public class GatewayFilterSpec extends UriSpec {
return redirect(String.valueOf(status), url.toString());
}
/**
* A filter that will return a redirect response back to the client.
* @param status an HTTP status code, should be a {@code 300} series redirect
* @param url the URL to redirect to. This URL will be set in the {@code location}
* header
* @param includeRequestParams if true, query params will be passed to the url
* @return a {@link GatewayFilterSpec} that can be used to apply additional filters
*/
public GatewayFilterSpec redirect(int status, URI url, boolean includeRequestParams) {
return redirect(String.valueOf(status), url.toString(), includeRequestParams);
}
/**
* A filter that will return a redirect response back to the client.
* @param status an HTTP status code, should be a {@code 300} series redirect
@@ -482,6 +494,18 @@ public class GatewayFilterSpec extends UriSpec {
return redirect(String.valueOf(status), url);
}
/**
* A filter that will return a redirect response back to the client.
* @param status an HTTP status code, should be a {@code 300} series redirect
* @param url the URL to redirect to. This URL will be set in the {@code location}
* header
* @param includeRequestParams if true, query params will be passed to the url
* @return a {@link GatewayFilterSpec} that can be used to apply additional filters
*/
public GatewayFilterSpec redirect(int status, String url, boolean includeRequestParams) {
return redirect(String.valueOf(status), url, includeRequestParams);
}
/**
* A filter that will return a redirect response back to the client.
* @param status an HTTP status code, should be a {@code 300} series redirect
@@ -490,7 +514,19 @@ public class GatewayFilterSpec extends UriSpec {
* @return a {@link GatewayFilterSpec} that can be used to apply additional filters
*/
public GatewayFilterSpec redirect(String status, URI url) {
return redirect(status, url.toString());
return redirect(status, url.toString(), false);
}
/**
* A filter that will return a redirect response back to the client.
* @param status an HTTP status code, should be a {@code 300} series redirect
* @param url the URL to redirect to. This URL will be set in the {@code location}
* header
* @param includeRequestParams if true, query params will be passed to the url
* @return a {@link GatewayFilterSpec} that can be used to apply additional filters
*/
public GatewayFilterSpec redirect(String status, String url, boolean includeRequestParams) {
return filter(getBean(RedirectToGatewayFilterFactory.class).apply(status, url, includeRequestParams));
}
/**
@@ -512,8 +548,21 @@ public class GatewayFilterSpec extends UriSpec {
* @return a {@link GatewayFilterSpec} that can be used to apply additional filters
*/
public GatewayFilterSpec redirect(HttpStatus status, URL url) {
return redirect(status, url, false);
}
/**
* A filter that will return a redirect response back to the client.
* @param status an HTTP status code, should be a {@code 300} series redirect
* @param url the URL to redirect to. This URL will be set in the {@code location}
* header
* @param includeRequestParams if true, query params will be passed to the url
* @return a {@link GatewayFilterSpec} that can be used to apply additional filters
*/
public GatewayFilterSpec redirect(HttpStatus status, URL url, boolean includeRequestParams) {
try {
return filter(getBean(RedirectToGatewayFilterFactory.class).apply(status, url.toURI()));
return filter(
getBean(RedirectToGatewayFilterFactory.class).apply(status, url.toURI(), includeRequestParams));
}
catch (URISyntaxException e) {
throw new IllegalArgumentException("Invalid URL", e);

View File

@@ -47,6 +47,19 @@ public class RedirectToGatewayFilterFactoryTests extends BaseWebClientTests {
.isEqualTo(HttpStatus.FOUND).expectHeader().valueEquals(HttpHeaders.LOCATION, "https://example.org");
}
@Test
public void redirectToUrlDoesNotPassQueryParametersByDefault() {
testClient.get().uri("/?membership=gold").header("Host", "www.redirectto.org").exchange().expectStatus()
.isEqualTo(HttpStatus.FOUND).expectHeader().valueEquals(HttpHeaders.LOCATION, "https://example.org");
}
@Test
public void redirectToUrlAddsQueryParametersWhenEnabledOnFilter() {
testClient.get().uri("/?membership=gold").header("Host", "queryparams.redirectto.org").exchange().expectStatus()
.isEqualTo(HttpStatus.FOUND).expectHeader()
.valueEquals(HttpHeaders.LOCATION, "https://example.org?membership=gold");
}
@Test
public void redirectToRelativeUrlFilterWorks() {
testClient.get().uri("/").header("Host", "www.relativeredirect.org").exchange().expectStatus()
@@ -59,13 +72,27 @@ public class RedirectToGatewayFilterFactoryTests extends BaseWebClientTests {
.isEqualTo(HttpStatus.FOUND).expectHeader().valueEquals(HttpHeaders.LOCATION, "/index.html#/customers");
}
@Test
public void redirectToRelativeUrlDoesNotPassQueryParametersByDefault() {
testClient.get().uri("/?membership=gold").header("Host", "www.relativeredirect.org").exchange().expectStatus()
.isEqualTo(HttpStatus.FOUND).expectHeader().valueEquals(HttpHeaders.LOCATION, "/index.html#/customers");
}
@Test
public void redirectToRelativeUrlAddsQueryParametersWhenEnabledOnFilter() {
testClient.get().uri("/?membership=gold").header("Host", "queryparams.relativeredirect.org").exchange()
.expectStatus().isEqualTo(HttpStatus.FOUND).expectHeader()
.valueEquals(HttpHeaders.LOCATION, "/index.html?membership=gold#/customers");
}
@Test
public void toStringFormat() {
Config config = new Config();
config.setStatus("301");
config.setUrl("http://newurl");
config.setIncludeRequestParams(true);
GatewayFilter filter = new RedirectToGatewayFilterFactory().apply(config);
assertThat(filter.toString()).contains("301").contains("http://newurl");
assertThat(filter.toString()).contains("301").contains("http://newurl").contains("true");
}
@EnableAutoConfiguration
@@ -78,6 +105,9 @@ public class RedirectToGatewayFilterFactoryTests extends BaseWebClientTests {
return builder.routes()
.route("relative_redirect_uri_object", r -> r.host("strcode.relativeredirect.org")
.filters(f -> f.redirect("302", URI.create("/index.html#/customers"))).uri("no://op"))
.route("relative_redirect_with_query_params",
r -> r.host("queryparams.relativeredirect.org")
.filters(f -> f.redirect(302, "/index.html#/customers", true)).uri("no://op"))
.route("relative_redirect", r -> r.host("**.relativeredirect.org")
.filters(f -> f.redirect(302, "/index.html#/customers")).uri("no://op"))
.build();

View File

@@ -296,6 +296,14 @@ spring:
filters:
- SetPath=/anything/{digits}
# =====================================
- id: redirect_to_include_query_params_test
uri: ${test.uri}
predicates:
- Host=queryparams.redirectto.org
filters:
- RedirectTo=302, https://example.org, true
# =====================================
- id: redirect_to_test
uri: ${test.uri}