Merge pull request #3799 from raccoonback/encode-plus-character-query-parameter
Fix '+' character in query parameters is not encoded when remove query parameter
This commit is contained in:
@@ -45,7 +45,6 @@ import org.springframework.web.server.ResponseStatusException;
|
||||
import org.springframework.web.servlet.function.ServerRequest;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
import org.springframework.web.util.UriTemplate;
|
||||
import org.springframework.web.util.UriUtils;
|
||||
|
||||
import static org.springframework.cloud.gateway.server.mvc.common.MvcUtils.CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR;
|
||||
import static org.springframework.util.CollectionUtils.unmodifiableMultiValueMap;
|
||||
@@ -216,7 +215,7 @@ public abstract class BeforeFilterFunctions {
|
||||
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>(request.params());
|
||||
queryParams.remove(name);
|
||||
|
||||
MultiValueMap<String, String> encodedQueryParams = UriUtils.encodeQueryParams(queryParams);
|
||||
MultiValueMap<String, String> encodedQueryParams = MvcUtils.encodeQueryParams(queryParams);
|
||||
|
||||
// remove from uri
|
||||
URI newUri = UriComponentsBuilder.fromUri(request.uri())
|
||||
|
||||
@@ -119,6 +119,7 @@ class BeforeFilterFunctionsTests {
|
||||
MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/path")
|
||||
.queryParam("foo", "bar")
|
||||
.queryParam("baz[]", "qux[]")
|
||||
.queryParam("quux", "corge+")
|
||||
.buildRequest(null);
|
||||
|
||||
ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList());
|
||||
@@ -127,7 +128,8 @@ class BeforeFilterFunctionsTests {
|
||||
|
||||
assertThat(result.param("foo")).isEmpty();
|
||||
assertThat(result.param("baz[]")).isPresent().hasValue("qux[]");
|
||||
assertThat(result.uri().toString()).hasToString("http://localhost/path?baz%5B%5D=qux%5B%5D");
|
||||
assertThat(result.param("quux")).isPresent().hasValue("corge+");
|
||||
assertThat(result.uri().toString()).hasToString("http://localhost/path?baz%5B%5D=qux%5B%5D&quux=corge%2B");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -24,12 +24,12 @@ 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.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
import org.springframework.web.util.UriUtils;
|
||||
|
||||
import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;
|
||||
import static org.springframework.util.CollectionUtils.unmodifiableMultiValueMap;
|
||||
@@ -59,7 +59,8 @@ public class RemoveRequestParameterGatewayFilterFactory
|
||||
queryParams.remove(config.getName());
|
||||
|
||||
try {
|
||||
MultiValueMap<String, String> encodedQueryParams = UriUtils.encodeQueryParams(queryParams);
|
||||
MultiValueMap<String, String> encodedQueryParams = ServerWebExchangeUtils
|
||||
.encodeQueryParams(queryParams);
|
||||
URI newUri = UriComponentsBuilder.fromUri(request.getURI())
|
||||
.replaceQueryParams(unmodifiableMultiValueMap(encodedQueryParams))
|
||||
.build(true)
|
||||
|
||||
@@ -24,13 +24,13 @@ 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.Assert;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
import org.springframework.web.util.UriUtils;
|
||||
|
||||
import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;
|
||||
import static org.springframework.util.CollectionUtils.unmodifiableMultiValueMap;
|
||||
@@ -71,7 +71,8 @@ public class RewriteRequestParameterGatewayFilterFactory
|
||||
}
|
||||
|
||||
try {
|
||||
MultiValueMap<String, String> encodedQueryParams = UriUtils.encodeQueryParams(queryParams);
|
||||
MultiValueMap<String, String> encodedQueryParams = ServerWebExchangeUtils
|
||||
.encodeQueryParams(queryParams);
|
||||
URI uri = uriComponentsBuilder.replaceQueryParams(unmodifiableMultiValueMap(encodedQueryParams))
|
||||
.build(true)
|
||||
.toUri();
|
||||
|
||||
@@ -17,9 +17,11 @@
|
||||
package org.springframework.cloud.gateway.support;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -48,9 +50,13 @@ import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.reactive.DispatcherHandler;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
import org.springframework.web.util.UriUtils;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
@@ -260,6 +266,17 @@ public final class ServerWebExchangeUtils {
|
||||
return encoded;
|
||||
}
|
||||
|
||||
public static MultiValueMap<String, String> encodeQueryParams(MultiValueMap<String, String> params) {
|
||||
MultiValueMap<String, String> encodedQueryParams = new LinkedMultiValueMap<>(params.size());
|
||||
for (Map.Entry<String, List<String>> entry : params.entrySet()) {
|
||||
for (String value : entry.getValue()) {
|
||||
encodedQueryParams.add(UriUtils.encode(entry.getKey(), StandardCharsets.UTF_8),
|
||||
UriUtils.encode(value, StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
return CollectionUtils.unmodifiableMultiValueMap(encodedQueryParams);
|
||||
}
|
||||
|
||||
public static HttpStatus parse(String statusString) {
|
||||
HttpStatus httpStatus;
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.cloud.gateway.filter.factory;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
@@ -24,6 +26,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.filter.factory.AbstractGatewayFilterFactory.NameConfig;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
|
||||
import org.springframework.mock.web.server.MockServerWebExchange;
|
||||
@@ -123,6 +126,23 @@ class RemoveRequestParameterGatewayFilterFactoryTests {
|
||||
assertThat(actualRequest.getQueryParams()).containsEntry("ccc", singletonList(",xyz"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void removeRequestParameterFilterShouldHandleRemainingPlusSignParams() {
|
||||
MockServerHttpRequest request = MockServerHttpRequest
|
||||
.method(HttpMethod.GET, URI.create("http://localhost?foo=bar&aaa=%2Bxyz"))
|
||||
.build();
|
||||
exchange = MockServerWebExchange.from(request);
|
||||
NameConfig config = new NameConfig();
|
||||
config.setName("foo");
|
||||
GatewayFilter filter = new RemoveRequestParameterGatewayFilterFactory().apply(config);
|
||||
|
||||
filter.filter(exchange, filterChain);
|
||||
|
||||
ServerHttpRequest actualRequest = captor.getValue().getRequest();
|
||||
assertThat(actualRequest.getQueryParams()).doesNotContainKey("foo");
|
||||
assertThat(actualRequest.getQueryParams()).containsEntry("aaa", singletonList("+xyz"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void removeRequestParameterFilterShouldHandleEncodedParameterName() {
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("http://localhost")
|
||||
|
||||
@@ -88,6 +88,12 @@ class RewriteRequestParameterGatewayFilterFactoryTests {
|
||||
Map.of("campaign[]", List.of("blue"), "color", List.of("white")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void rewriteRequestParameterFilterWithPlusSign() {
|
||||
testRewriteRequestParameterFilter("color", "white+", "campaign=blue%2B&color=green",
|
||||
Map.of("campaign", List.of("blue+"), "color", List.of("white+")));
|
||||
}
|
||||
|
||||
private void testRewriteRequestParameterFilter(String name, String replacement, String query,
|
||||
Map<String, List<String>> expectedQueryParams) {
|
||||
GatewayFilter filter = new RewriteRequestParameterGatewayFilterFactory()
|
||||
|
||||
Reference in New Issue
Block a user