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 7269fa6b2..53cb3358d 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 @@ -24,6 +24,7 @@ import java.util.function.Predicate; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.web.util.UriComponentsBuilder; import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.handler.AsyncPredicate; @@ -80,7 +81,19 @@ public class ServerWebExchangeUtils { public static boolean containsEncodedParts(URI uri) { boolean encoded = (uri.getRawQuery() != null && uri.getRawQuery().contains("%")) - || (uri.getPath() != null && uri.getRawPath().contains("%")); + || (uri.getRawPath() != null && uri.getRawPath().contains("%")); + + // Verify if it is really fully encoded. Treat partial encoded as uncoded. + if (encoded) { + try { + UriComponentsBuilder.fromUri(uri).build(true); + return true; + } catch (IllegalArgumentException ignore) { + } + + return false; + } + return encoded; } diff --git a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/RouteToRequestUrlFilterTests.java b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/RouteToRequestUrlFilterTests.java index d857f6ae3..aad78dbd6 100644 --- a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/RouteToRequestUrlFilterTests.java +++ b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/RouteToRequestUrlFilterTests.java @@ -101,6 +101,32 @@ public class RouteToRequestUrlFilterTests { assertThat(uri.getRawQuery()).isEqualTo("a=b&c=d%5B%5D"); } + @Test + public void partialEncodedParameters() { + URI url = UriComponentsBuilder.fromUriString( + "http://localhost/get?key[]=test= key&start=1533108081") + .build().toUri(); + + // prove that it is partial encoded + assertThat(url.getRawQuery()).isEqualTo("key[]=test=%20key&start=1533108081"); + + assertThat(url).hasParameter("key[]", "test= key"); + assertThat(url).hasParameter("start", "1533108081"); + + MockServerHttpRequest request = MockServerHttpRequest + .method(HttpMethod.GET, url) + .build(); + + ServerWebExchange webExchange = testFilter(request, "http://myhost"); + URI uri = webExchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR); + assertThat(uri).hasScheme("http").hasHost("myhost") + .hasParameter("key[]", "test= key") + .hasParameter("start", "1533108081"); + + // prove that it is double encoded since partial encoded uri is treated as uncoded. + assertThat(uri.getRawQuery()).isEqualTo("key[]=test=%2520key&start=1533108081"); + } + @Test public void encodedUrl() { URI url = UriComponentsBuilder.fromUriString("http://localhost/abc def/get").buildAndExpand().encode().toUri();