Support encoded query string in reactive requests
In addition to the updates from PR#1297 this commit adds an integration test and fixes for the resulting failures with RxNetty, Reactor Netty, and Undertow. Also replaced use of URLDecoder which is not for decoding URIs with use of UriUtils for decoding query parameters. Issue: SPR-15140
This commit is contained in:
@@ -16,9 +16,7 @@
|
||||
|
||||
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;
|
||||
@@ -29,6 +27,7 @@ import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.util.UriUtils;
|
||||
|
||||
/**
|
||||
* Common base class for {@link ServerHttpRequest} implementations.
|
||||
@@ -79,22 +78,6 @@ public abstract class AbstractServerHttpRequest implements ServerHttpRequest {
|
||||
return this.queryParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* A method for decoding name and value string in a name-value pair.
|
||||
* <p>Note that the plus sign "+" is converted into a space character " ".</p>
|
||||
* @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.
|
||||
@@ -113,13 +96,16 @@ 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(decodeQueryParam(name),
|
||||
value != null ? decodeQueryParam(value) : null);
|
||||
queryParams.add(decodeQueryParam(name), decodeQueryParam(value));
|
||||
}
|
||||
}
|
||||
return queryParams;
|
||||
}
|
||||
|
||||
private static String decodeQueryParam(String value) {
|
||||
return (value != null ? UriUtils.decode(value, StandardCharsets.UTF_8) : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiValueMap<String, HttpCookie> getCookies() {
|
||||
if (this.cookies == null) {
|
||||
|
||||
@@ -56,20 +56,17 @@ public class ReactorServerHttpRequest extends AbstractServerHttpRequest {
|
||||
|
||||
private static URI initUri(HttpServerRequest channel) {
|
||||
Assert.notNull("'channel' must not be null");
|
||||
InetSocketAddress address = channel.remoteAddress();
|
||||
return (address == null ? URI.create(channel.uri()) : getBaseUrl(address).resolve(channel.uri()));
|
||||
}
|
||||
|
||||
private static URI getBaseUrl(InetSocketAddress address) {
|
||||
try {
|
||||
URI uri = new URI(channel.uri());
|
||||
InetSocketAddress remoteAddress = channel.remoteAddress();
|
||||
return new URI(
|
||||
uri.getScheme(),
|
||||
uri.getUserInfo(),
|
||||
(remoteAddress != null ? remoteAddress.getHostString() : null),
|
||||
(remoteAddress != null ? remoteAddress.getPort() : -1),
|
||||
uri.getPath(),
|
||||
uri.getQuery(),
|
||||
uri.getFragment());
|
||||
return new URI(null, null, address.getHostString(), address.getPort(), null, null, null);
|
||||
}
|
||||
catch (URISyntaxException ex) {
|
||||
throw new IllegalStateException("Could not get URI: " + ex.getMessage(), ex);
|
||||
// Should not happen...
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,25 +63,20 @@ public class RxNettyServerHttpRequest extends AbstractServerHttpRequest {
|
||||
|
||||
private static URI initUri(HttpServerRequest<ByteBuf> request) {
|
||||
Assert.notNull("'request', request must not be null");
|
||||
return StringUtils.isEmpty(request.getHostHeader()) ?
|
||||
URI.create(request.getUri()) : getBaseUrl(request).resolve(request.getUri());
|
||||
}
|
||||
|
||||
private static URI getBaseUrl(HttpServerRequest<ByteBuf> request) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("Host", request.getHostHeader());
|
||||
InetSocketAddress address = headers.getHost();
|
||||
try {
|
||||
URI uri = new URI(request.getUri());
|
||||
InetSocketAddress remoteAddress = null;
|
||||
if (!StringUtils.isEmpty(request.getHostHeader())) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("Host", request.getHostHeader());
|
||||
remoteAddress = headers.getHost();
|
||||
}
|
||||
return new URI(
|
||||
uri.getScheme(),
|
||||
uri.getUserInfo(),
|
||||
(remoteAddress != null ? remoteAddress.getHostString() : null),
|
||||
(remoteAddress != null ? remoteAddress.getPort() : -1),
|
||||
uri.getPath(),
|
||||
uri.getQuery(),
|
||||
uri.getFragment());
|
||||
return new URI(null, null, address.getHostString(), address.getPort(), null, null, null);
|
||||
}
|
||||
catch (URISyntaxException ex) {
|
||||
throw new IllegalStateException("Could not get URI: " + ex.getMessage(), ex);
|
||||
// Should not happen...
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,11 +63,19 @@ public class UndertowServerHttpRequest extends AbstractServerHttpRequest {
|
||||
|
||||
private static URI initUri(HttpServerExchange exchange) {
|
||||
Assert.notNull(exchange, "HttpServerExchange is required.");
|
||||
String requestURI = exchange.getRequestURI();
|
||||
String query = exchange.getQueryString();
|
||||
String requestUriAndQuery = StringUtils.isEmpty(query) ? requestURI : requestURI + "?" + query;
|
||||
return (exchange.isHostIncludedInRequestURI()) ?
|
||||
URI.create(requestUriAndQuery) : getBaseUri(exchange).resolve(requestUriAndQuery);
|
||||
}
|
||||
|
||||
private static URI getBaseUri(HttpServerExchange exchange) {
|
||||
try {
|
||||
String query = exchange.getQueryString();
|
||||
return new URI(exchange.getRequestScheme(), null,
|
||||
exchange.getHostName(), exchange.getHostPort(),
|
||||
exchange.getRequestURI(), StringUtils.hasText(query) ? query : null, null);
|
||||
String scheme = exchange.getRequestScheme();
|
||||
String host = exchange.getHostName();
|
||||
int port = exchange.getHostPort();
|
||||
return new URI(scheme, null, host, port, null, null, null);
|
||||
}
|
||||
catch (URISyntaxException ex) {
|
||||
throw new IllegalStateException("Could not get URI: " + ex.getMessage(), ex);
|
||||
|
||||
Reference in New Issue
Block a user