diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractServerHttpRequest.java b/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractServerHttpRequest.java index 57f35e0566a..6acf05c0d57 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractServerHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractServerHttpRequest.java @@ -16,7 +16,10 @@ package org.springframework.http.server.reactive; +import java.io.UnsupportedEncodingException; import java.net.URI; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -76,6 +79,22 @@ public abstract class AbstractServerHttpRequest implements ServerHttpRequest { return this.queryParams; } + /** + * A method for decoding name and value string in a name-value pair. + *

Note that the plus sign "+" is converted into a space character " ".

+ * @param encodedString the string to be decoded + * @return the decoded string + * @see java.net.URLDecoder#decode(String, String) + */ + private static String decodeQueryParam(final String encodedString) { + try { + return URLDecoder.decode(encodedString, StandardCharsets.UTF_8.name()); + } catch (UnsupportedEncodingException e) { + // StandardCharsets are guaranteed to be available on every implementation of the Java platform, so this should never happen. + throw new IllegalStateException(e); + } + } + /** * A method for parsing of the query into name-value pairs. The return * value is turned into an immutable map and cached. @@ -94,7 +113,8 @@ public abstract class AbstractServerHttpRequest implements ServerHttpRequest { String eq = matcher.group(2); String value = matcher.group(3); value = (value != null ? value : (StringUtils.hasLength(eq) ? "" : null)); - queryParams.add(name, value); + queryParams.add(decodeQueryParam(name), + value != null ? decodeQueryParam(value) : null); } } return queryParams; diff --git a/spring-web/src/test/java/org/springframework/http/server/reactive/ServerHttpRequestTests.java b/spring-web/src/test/java/org/springframework/http/server/reactive/ServerHttpRequestTests.java index 0ef6ba345ee..922fb503ec8 100644 --- a/spring-web/src/test/java/org/springframework/http/server/reactive/ServerHttpRequestTests.java +++ b/spring-web/src/test/java/org/springframework/http/server/reactive/ServerHttpRequestTests.java @@ -64,6 +64,13 @@ public class ServerHttpRequestTests { assertEquals(Arrays.asList("1", "2"), params.get("a")); } + @Test + public void queryParamsWithUrlEncodedValue() throws Exception { + MultiValueMap params = createHttpRequest("/path?a=%20%2B+%C3%A0").getQueryParams(); + assertEquals(1, params.size()); + assertEquals(Collections.singletonList(" + \u00e0"), params.get("a")); + } + @Test public void queryParamsWithEmptyValue() throws Exception { MultiValueMap params = createHttpRequest("/path?a=").getQueryParams();