Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ private QueryStringAttribute(boolean includeQuestionMark) {

@Override
public String readAttribute(final HttpServerExchange exchange) {
String qs = exchange.getQueryString();
String qs = exchange.getDecodedQueryString();
if(qs.isEmpty() || !includeQuestionMark) {
return qs;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ public String readAttribute(final HttpServerExchange exchange) {
.append(exchange.getRequestMethod().toString())
.append(' ')
.append(exchange.getRequestURI());
if (!exchange.getQueryString().isEmpty()) {
if (!exchange.getDecodedQueryString().isEmpty()) {
sb.append('?');
sb.append(exchange.getQueryString());
sb.append(exchange.getDecodedQueryString());
}
sb.append(' ')
.append(exchange.getProtocol().toString()).toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ protected URI getRedirectURI(final HttpServerExchange exchange, final int port)
}
}
uriBuilder.append(uri);
final String queryString = exchange.getQueryString();
final String queryString = exchange.getDecodedQueryString();
if (queryString != null && !queryString.isEmpty()) {
uriBuilder.append("?").append(queryString);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,17 +235,17 @@ private AuthenticationMechanismOutcome handleDigestHeader(HttpServerExchange exc
if(parsedHeader.containsKey(DigestAuthorizationToken.DIGEST_URI)) {
String uri = parsedHeader.get(DigestAuthorizationToken.DIGEST_URI);
String requestURI = exchange.getRequestURI();
if(!exchange.getQueryString().isEmpty()) {
requestURI = requestURI + "?" + exchange.getQueryString();
if(!exchange.getDecodedQueryString().isEmpty()) {
requestURI = requestURI + "?" + exchange.getDecodedQueryString();
}
if(!uri.equals(requestURI)) {
//it is possible we were given an absolute URI
//we reconstruct the URI from the host header to make sure they match up
//I am not sure if this is overly strict, however I think it is better
//to be safe than sorry
requestURI = exchange.getRequestURL();
if(!exchange.getQueryString().isEmpty()) {
requestURI = requestURI + "?" + exchange.getQueryString();
if(!exchange.getDecodedQueryString().isEmpty()) {
requestURI = requestURI + "?" + exchange.getDecodedQueryString();
}
if(!uri.equals(requestURI)) {
//just end the auth process
Expand Down
5 changes: 2 additions & 3 deletions core/src/main/java/io/undertow/server/Connectors.java
Original file line number Diff line number Diff line change
Expand Up @@ -569,10 +569,9 @@ public static void setExchangeRequestPath(final HttpServerExchange exchange, fin
}
if(requiresDecode && allowUnescapedCharactersInUrl) {
final String decodedQS = URLUtils.decode(qs, charset, decodeSlashFlag,false, decodeBuffer);
exchange.setQueryString(decodedQS);
} else {
exchange.setQueryString(qs);
exchange.setDecodedQueryString(decodedQS);
}
exchange.setQueryString(qs);

URLUtils.parseQueryString(qs, exchange, charset, decodeQueryString, maxParameters);
return;
Expand Down
74 changes: 56 additions & 18 deletions core/src/main/java/io/undertow/server/HttpServerExchange.java
Original file line number Diff line number Diff line change
Expand Up @@ -208,13 +208,14 @@ public final class HttpServerExchange extends AbstractAttachable {
private String resolvedPath = "";

/**
* the query string - percent encoded
* the unencoded query string (i.e. percent encoded), in its original form as it appears in the received request.
*/
private String queryString = "";

/**
* the non-decoded query string. Set only when query string goes through decoding
* the decoded query string, if there was any decoding done
*/
private String nonDecodedQueryString = null;
private String decodedQueryString = null;

private int requestWrapperCount = 0;
private ConduitWrapper<StreamSourceConduit>[] requestWrappers; //we don't allocate these by default, as for get requests they are not used
Expand Down Expand Up @@ -581,24 +582,25 @@ public HttpServerExchange setResolvedPath(final String resolvedPath) {
}

/**
* Returns the query string for this request.
*
* @return The query string, without the leading ?
* @return The query string as originally appeared in the request, without the leading ?
*/
public String getQueryString() {
return queryString;
return this.queryString;
}

/**
* Set query string. Leading {@code '?'} char will be removed automatically.
* Sets the query string, unencoded and in its original form as it appears in the received request.
* Leading {@code '?'} char will be removed automatically.<p>
*
* @param queryString the query string as originally contained in the request, without any decoding
* @return this http server exchange
*/
public HttpServerExchange setQueryString(final String queryString) {
// Clean leading ?
if( queryString.length() > 0 && queryString.charAt(0) == '?' ) {
this.queryString = queryString.substring(1);
} else {
this.queryString = queryString;
this.queryString = cleanQueryString(queryString);
if (this.queryString == null) {
this.queryString = "";
}
return this;
}
Expand All @@ -608,27 +610,63 @@ public HttpServerExchange setQueryString(final String queryString) {
* The returned string does not contain the leading {@code '?'} char.
*
* @return The request query string, without the leading {@code '?'}, non-decoded.
*
* @deprecated use {@link #getQueryString()} instead
*/
@Deprecated(forRemoval = true, since="2.3.20.Final")
public String getNonDecodedQueryString() {
return this.nonDecodedQueryString == null? this.queryString: this.nonDecodedQueryString;
return getQueryString();
}

/**
* Sets the non-decoded query string. Leading {@code '?'} char will be removed automatically.<p>
* Must be invoked only if the {@link #getQueryString() query string} has gone through decoding. In such case, we expect
* that both forms of the query string will be set in the exchange: {@link #setQueryString decoded} and non-decoded.
*
* @param nonDecodedQueryString the query string as originally contained in the request, without any decoding
* @param unencodedQueryString the query string as originally contained in the request, without any decoding
* @return this http server exchange
*
* @deprecated Use #setQueryString instead
*/
public HttpServerExchange setNonDecodedQueryString(String nonDecodedQueryString) {
@Deprecated(forRemoval = true, since="2.3.20.Final")
public HttpServerExchange setNonDecodedQueryString(String unencodedQueryString) {
return setQueryString(unencodedQueryString);
}

/**
* Returns the query string in its decoded form if available, which will depend on configs such as
* {@link UndertowOptions#ALLOW_UNESCAPED_CHARACTERS_IN_URL}.
* If unavailable, the decoded query string is just the same as {@link #getQueryString}
*
* @return The request query string, without the leading {@code '?'}, post parsing, decoded.
*/
public String getDecodedQueryString() {
return this.decodedQueryString != null && this.decodedQueryString.length() > 0 ? this.decodedQueryString : this.queryString;
}

/**
* Sets the decoded query string.
* Leading {@code '?'} char will be removed automatically.<p>
* Must be invoked only if the {@link #getQueryString() query string} has gone through decoding. In such case, we expect
* that both forms of the query string will be set in the exchange: decoded and {@link #setQueryString non-decoded}
*
* @param decodedQueryString the request query string, without the leading {@code '?'}, post parsing, decoded.
* @return this http server exchange
*/
public HttpServerExchange setDecodedQueryString(String decodedQueryString) {
this.decodedQueryString = cleanQueryString(decodedQueryString);
return this;
}

private String cleanQueryString(String queryString) {
// Clean leading ?
if( nonDecodedQueryString.length() > 0 && nonDecodedQueryString.charAt(0) == '?' ) {
this.nonDecodedQueryString = nonDecodedQueryString.substring(1);
if (queryString == null) {
return queryString;
} else if( queryString.length() > 0 && queryString.charAt(0) == '?' ) {
return queryString.substring(1);
} else {
this.nonDecodedQueryString = nonDecodedQueryString;
return queryString;
}
return this;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public long getProcessingTime() {
}

public String getQueryString() {
return exchange.getQueryString();
return exchange.getDecodedQueryString();
}

public String getUri() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ public void handleRequest(final HttpServerExchange exchange) throws Exception {
exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "message/http");
StringBuilder body = new StringBuilder("TRACE ");
body.append(exchange.getRequestURI());
if(!exchange.getQueryString().isEmpty()) {
if(!exchange.getDecodedQueryString().isEmpty()) {
body.append('?');
body.append(exchange.getQueryString());
body.append(exchange.getDecodedQueryString());
}
body.append(' ');
body.append(exchange.getProtocol().toString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ public void logMessage(String pattern, HttpServerExchange exchange) {
} else {
jdbcLogAttribute.user = sc.getAuthenticatedAccount().getPrincipal().getName();
}
jdbcLogAttribute.query = exchange.getQueryString();
jdbcLogAttribute.query = exchange.getDecodedQueryString();

jdbcLogAttribute.bytes = exchange.getResponseContentLength();
if (jdbcLogAttribute.bytes < 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,12 @@ public LearningPushHandler(int maxPathEtries, int maxPathAge, int maxPushEtries,
public void handleRequest(HttpServerExchange exchange) throws Exception {
String fullPath;
String requestPath;
if(exchange.getQueryString().isEmpty()) {
if(exchange.getDecodedQueryString().isEmpty()) {
fullPath = exchange.getRequestURL();
requestPath = exchange.getRequestPath();
} else{
fullPath = exchange.getRequestURL() + "?" + exchange.getQueryString();
requestPath = exchange.getRequestPath() + "?" + exchange.getQueryString();
fullPath = exchange.getRequestURL() + "?" + exchange.getDecodedQueryString();
requestPath = exchange.getRequestPath() + "?" + exchange.getDecodedQueryString();
}

doPush(exchange, fullPath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public void handleRequest(final HttpServerExchange exchange) throws Exception {
sb.append("\n");
}
sb.append(" protocol=" + exchange.getProtocol() + "\n");
sb.append(" queryString=" + exchange.getQueryString() + "\n");
sb.append(" queryString=" + exchange.getDecodedQueryString() + "\n");
sb.append(" remoteAddr=" + exchange.getSourceAddress() + "\n");
sb.append(" remoteHost=" + exchange.getSourceAddress().getHostName() + "\n");
sb.append(" scheme=" + exchange.getRequestScheme() + "\n");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ public void handleRequest(HttpServerExchange exchange) throws Exception {
// GC'ing, as the reference is removed from the Map in the finally clause

Long key = Thread.currentThread().getId();
MonitoredThread monitoredThread = new MonitoredThread(Thread.currentThread(), exchange.getRequestURI() + exchange.getQueryString());
MonitoredThread monitoredThread = new MonitoredThread(Thread.currentThread(), exchange.getRequestURI() + exchange.getDecodedQueryString());
activeThreads.put(key, monitoredThread);
if(timerKey == null) {
synchronized (this) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ private static void decodePath(HttpServerExchange exchange, String charset, Stri
}

private static void decodeQueryString(HttpServerExchange exchange, String charset, StringBuilder sb) {
if (!exchange.getQueryString().isEmpty()) {
if (!exchange.getDecodedQueryString().isEmpty()) {
final TreeMap<String, Deque<String>> newParams = new TreeMap<>();
for (Map.Entry<String, Deque<String>> param : exchange.getQueryParameters().entrySet()) {
final Deque<String> newValues = new ArrayDeque<>(param.getValue().size());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -328,15 +328,15 @@ protected ExchangeAttribute getClientToServerElement(
return new ExchangeAttribute() {
@Override
public String readAttribute(HttpServerExchange exchange) {
String query = exchange.getQueryString();
String query = exchange.getDecodedQueryString();

if (query.isEmpty()) {
return exchange.getRequestURI();
} else {
StringBuilder buf = new StringBuilder();
buf.append(exchange.getRequestURI());
buf.append('?');
buf.append(exchange.getQueryString());
buf.append(exchange.getDecodedQueryString());
return buf.toString();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ public void run() {
}
requestURI.append(targetURI);

String qs = exchange.getNonDecodedQueryString();
String qs = exchange.getQueryString();
if (qs != null && !qs.isEmpty()) {
requestURI.append('?');
requestURI.append(qs);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,12 @@ public static boolean sendRequestedBlobs(HttpServerExchange exchange) {
String type = null;
String etag = null;
String quotedEtag = null;
if ("css".equals(exchange.getQueryString())) {
if ("css".equals(exchange.getDecodedQueryString())) {
buffer = Blobs.FILE_CSS_BUFFER.duplicate();
type = "text/css";
etag = Blobs.FILE_CSS_ETAG;
quotedEtag = Blobs.FILE_CSS_ETAG_QUOTED;
} else if ("js".equals(exchange.getQueryString())) {
} else if ("js".equals(exchange.getDecodedQueryString())) {
buffer = Blobs.FILE_JS_BUFFER.duplicate();
type = "application/javascript";
etag = Blobs.FILE_JS_ETAG;
Expand Down
Loading