Skip to content
This repository was archived by the owner on May 28, 2018. It is now read-only.

Commit b392726

Browse files
author
Adam Lindenthal
committed
JERSEY-2850 GrizzlyHttpContainer throws exception with certain chars in query
Change-Id: Ic75721e07fff6b5528fecff4b94cb6e19a9b3675
1 parent 1c5a1dd commit b392726

File tree

2 files changed

+66
-48
lines changed

2 files changed

+66
-48
lines changed

core-server/src/main/java/org/glassfish/jersey/server/internal/ContainerUtils.java

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
33
*
4-
* Copyright (c) 2010-2014 Oracle and/or its affiliates. All rights reserved.
4+
* Copyright (c) 2010-2015 Oracle and/or its affiliates. All rights reserved.
55
*
66
* The contents of this file are subject to the terms of either the GNU
77
* General Public License Version 2 only ("GPL") or the Common Development
@@ -39,36 +39,43 @@
3939
*/
4040
package org.glassfish.jersey.server.internal;
4141

42-
import javax.ws.rs.core.UriBuilder;
43-
import java.net.URI;
44-
4542
/**
4643
* Utility methods used by container implementations.
4744
*
4845
* @author Adam Lindenthal (adam.lindenthal at oracle.com)
4946
*/
5047
public class ContainerUtils {
48+
private static final String[] TOKENS = {
49+
"{", "}", "\\", "^", "|", "`"
50+
};
51+
52+
private static final String[] REPLACEMENTS = {
53+
"%7B", "%7D", "%5C", "%5E", "%7C", "%60"
54+
};
5155

5256
/**
5357
* Encodes (predefined subset of) unsafe/unwise URI characters with the percent-encoding.
54-
* <p/>
55-
* <p>Replaces the predefined set of unsafe URI characters in the query string with its percent-encoded counterparts. The
56-
* reserved characters (as defined by the RFC) are automatically encoded by browsers, but some characters are in the "gray
57-
* zone" - are not explicitly forbidden, but not recommended and known to cause issues.</p>
58-
* <p/>
59-
* <p>Currently, the method only encodes the curly brackets ({@code \{} and {@code \}}),
60-
* if any, to allow URI request parameters to contain JSON.</p>
58+
*
59+
* <p>Replaces the predefined set of unsafe URI characters in the query string with its percent-encoded
60+
* counterparts. The reserved characters (as defined by the RFC) are automatically encoded by browsers, but some
61+
* characters are in the "gray zone" - are not explicitly forbidden, but not recommended and known to cause
62+
* issues.</p>
6163
*
6264
* @param originalQueryString URI query string (the part behind the question mark character).
63-
* @return the same string with unsafe characters (currently only curly brackets) eventually percent encoded.
65+
* @return the same string with unsafe characters percent encoded.
6466
*/
65-
public static String encodeUnsafeCharacters(String originalQueryString) {
67+
public static String encodeUnsafeCharacters(final String originalQueryString) {
6668
if (originalQueryString == null) {
6769
return null;
6870
}
69-
if (originalQueryString.contains("{") || originalQueryString.contains("}")) {
70-
return originalQueryString.replace("{", "%7B").replace("}", "%7D");
71+
72+
String result = originalQueryString;
73+
for (int i = 0; i < TOKENS.length; i++) {
74+
if (originalQueryString.contains(TOKENS[i])) {
75+
result = result.replace(TOKENS[i], REPLACEMENTS[i]);
76+
}
7177
}
72-
return originalQueryString;
78+
79+
return result;
7380
}
7481
}

tests/e2e/src/test/java/org/glassfish/jersey/tests/api/JsonInUriTest.java renamed to tests/e2e/src/test/java/org/glassfish/jersey/tests/api/UnsafeCharsInUriTest.java

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
33
*
4-
* Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
4+
* Copyright (c) 2014-2015 Oracle and/or its affiliates. All rights reserved.
55
*
66
* The contents of this file are subject to the terms of either the GNU
77
* General Public License Version 2 only ("GPL") or the Common Development
@@ -39,39 +39,38 @@
3939
*/
4040
package org.glassfish.jersey.tests.api;
4141

42-
import org.glassfish.jersey.filter.LoggingFilter;
43-
import org.glassfish.jersey.server.ResourceConfig;
44-
import org.glassfish.jersey.test.JerseyTest;
45-
import org.glassfish.jersey.test.TestProperties;
46-
import org.junit.Test;
47-
48-
import javax.ws.rs.DefaultValue;
49-
import javax.ws.rs.GET;
50-
import javax.ws.rs.Path;
51-
import javax.ws.rs.QueryParam;
52-
import javax.ws.rs.core.Response;
5342
import java.io.BufferedReader;
5443
import java.io.BufferedWriter;
5544
import java.io.IOException;
5645
import java.io.InputStreamReader;
5746
import java.io.OutputStreamWriter;
5847
import java.io.PrintWriter;
5948
import java.net.Socket;
60-
import java.util.logging.Logger;
49+
import java.net.URI;
50+
51+
import javax.ws.rs.DefaultValue;
52+
import javax.ws.rs.GET;
53+
import javax.ws.rs.Path;
54+
import javax.ws.rs.QueryParam;
55+
import javax.ws.rs.core.Response;
56+
57+
import org.glassfish.jersey.server.ResourceConfig;
58+
import org.glassfish.jersey.test.JerseyTest;
59+
60+
import org.junit.Test;
61+
6162

6263
import static org.junit.Assert.assertEquals;
6364

6465
/**
65-
* Test if URI can contain a JSON in the query parameter.
66+
* Test if URI can contain unsafe characters in the query parameter, e.g. for sending JSON
6667
*
6768
* @author Adam Lindenthal (adam.lindenthal at oracle.com)
6869
*/
69-
public class JsonInUriTest extends JerseyTest {
70-
private static final Logger LOGGER = Logger.getLogger(JsonInUriTest.class.getName());
71-
70+
public class UnsafeCharsInUriTest extends JerseyTest {
7271
@Override
7372
protected ResourceConfig configure() {
74-
ResourceConfig rc = new ResourceConfig(JsonInUriTest.ResponseTest.class);
73+
ResourceConfig rc = new ResourceConfig(UnsafeCharsInUriTest.ResponseTest.class);
7574
return rc;
7675
}
7776

@@ -81,46 +80,58 @@ protected ResourceConfig configure() {
8180
@Path(value = "/app")
8281
public static class ResponseTest {
8382
/**
84-
* Test resource method returning the content of the {@code json} query parameter.
83+
* Test resource method returning the content of the {@code msg} query parameter.
8584
*
86-
* @return the {@code json} query parameter (as received)
85+
* @return the {@code msg} query parameter (as received)
8786
*/
8887
@GET
8988
@Path("test")
90-
public Response jsonQueryParamTest(@DefaultValue("") @QueryParam("json") String json) {
91-
return Response.ok().entity(json).build();
89+
public Response jsonQueryParamTest(@DefaultValue("") @QueryParam("msg") final String msg) {
90+
return Response.ok().entity(msg).build();
9291
}
9392

9493
}
9594

9695
/**
97-
* Test, that server can consume JSON sent in the query parameter
96+
* Test, that server can consume JSON (curly brackets) and other unsafe characters sent in the query parameter
9897
*
9998
* @throws IOException
10099
*/
101100
@Test
102-
public void testJsonInUriWithSockets() throws IOException {
101+
public void testSpecCharsInUriWithSockets() throws IOException {
102+
// quotes are encoded by browsers, curly brackets are not, so the quotes will be sent pre-encoded
103+
// HTTP 1.0 is used for simplicity
104+
String response = sendGetRequestOverSocket(getBaseUri(), "GET /app/test?msg={%22foo%22:%22bar%22} HTTP/1.0");
105+
assertEquals("{\"foo\":\"bar\"}", response);
106+
107+
response = sendGetRequestOverSocket(getBaseUri(),
108+
"GET /app/test?msg=Hello\\World+With+SpecChars+§*)$!±@-_=;`:\\,~| HTTP/1.0");
109+
110+
assertEquals("Hello\\World With SpecChars §*)$!±@-_=;`:\\,~|", response);
111+
}
112+
113+
private String sendGetRequestOverSocket(final URI baseUri, final String requestLine) throws IOException {
103114
// Low level approach with sockets is used, because common Java HTTP clients are using java.net.URI,
104115
// which fails when unencoded curly bracket is part of the URI
105-
Socket socket = new Socket(getBaseUri().getHost(), getBaseUri().getPort());
106-
PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())));
116+
final Socket socket = new Socket(baseUri.getHost(), baseUri.getPort());
117+
final PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())));
107118

108-
// quotes are encoded by browsers, curly brackets are not, so the quotes will be sent pre-encoded
109-
// HTTP 1.0 is used for simplicity
110-
pw.println("GET /app/test?json={%22foo%22:%22bar%22} HTTP/1.0");
111-
pw.println(); // http request should end with a blank line
119+
pw.println(requestLine);
120+
pw.println(); // http request should end with a blank line
112121
pw.flush();
113122

114-
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
123+
final BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
115124

116125
String lastLine = null;
117126
String line;
118127
while ((line = br.readLine()) != null) {
119128
// read the response and remember the last line
120129
lastLine = line;
121130
}
122-
assertEquals("{\"foo\":\"bar\"}", lastLine);
131+
pw.close();
123132
br.close();
133+
134+
return lastLine;
124135
}
125136
}
126137

0 commit comments

Comments
 (0)