From 613e65f043e36324577eed14e08da3d83b2fa520 Mon Sep 17 00:00:00 2001 From: Eiichi Sato Date: Sat, 14 Jan 2017 20:43:31 +0900 Subject: [PATCH] Fix URL decoding issue in reactive @RequestParam %-encoded strings were injected undecoded into @RequestParam variables, which does not coincide with spring-webmvc behaviour. This commit fixes AbstractServerHttpRequest.getQueryParams() to correctly return decoded name-value pairs. Issue: SPR-15140 --- .../reactive/AbstractServerHttpRequest.java | 22 ++++++++++++++++++- .../reactive/ServerHttpRequestTests.java | 7 ++++++ 2 files changed, 28 insertions(+), 1 deletion(-) 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();