388675 Non utf8 encoded query strings not decoded to parameter map using queryEncoding

This commit is contained in:
Jan Bartel 2012-09-13 13:35:27 +10:00
parent e7f1743dd4
commit 0035343af3
5 changed files with 193 additions and 7 deletions

View File

@ -94,7 +94,15 @@ public class HttpURI
public HttpURI(String raw)
{
_rawString=raw;
byte[] b = raw.getBytes();
byte[] b;
try
{
b = raw.getBytes(StringUtil.__UTF8);
}
catch (UnsupportedEncodingException e)
{
throw new RuntimeException(e.getMessage());
}
parse(b,0,b.length);
}
@ -700,7 +708,7 @@ public class HttpURI
if (encoding==null || StringUtil.isUTF8(encoding))
UrlEncoded.decodeUtf8To(_raw,_query+1,_fragment-_query-1,parameters);
else
UrlEncoded.decodeTo(toUtf8String(_query+1,_fragment-_query-1),parameters,encoding);
UrlEncoded.decodeTo(StringUtil.toString(_raw,_query+1,_fragment-_query-1,encoding),parameters,encoding);
}
public void clear()

View File

@ -1739,6 +1739,7 @@ public class Request implements HttpServletRequest
public void setQueryString(String queryString)
{
_queryString = queryString;
_queryEncoding = null; //assume utf-8
}
/* ------------------------------------------------------------ */
@ -1922,7 +1923,7 @@ public class Request implements HttpServletRequest
{
// extract parameters from dispatch query
MultiMap<String> parameters = new MultiMap<String>();
UrlEncoded.decodeTo(query,parameters,getCharacterEncoding());
UrlEncoded.decodeTo(query,parameters, StringUtil.__UTF8); //have to assume UTF-8 because we can't know otherwise
boolean merge_old_query = false;
@ -1957,10 +1958,11 @@ public class Request implements HttpServletRequest
{
StringBuilder overridden_query_string = new StringBuilder();
MultiMap<String> overridden_old_query = new MultiMap<String>();
UrlEncoded.decodeTo(_queryString,overridden_old_query,getCharacterEncoding());
UrlEncoded.decodeTo(_queryString,overridden_old_query,getQueryEncoding());//decode using any queryencoding set for the request
MultiMap<String> overridden_new_query = new MultiMap<String>();
UrlEncoded.decodeTo(query,overridden_new_query,getCharacterEncoding());
UrlEncoded.decodeTo(query,overridden_new_query,StringUtil.__UTF8); //have to assume utf8 as we cannot know otherwise
Iterator<Entry<String, Object>> iter = overridden_old_query.entrySet().iterator();
while (iter.hasNext())

View File

@ -386,7 +386,7 @@ public class Server extends HandlerWrapper implements Attributes
baseRequest.setRequestURI(null);
baseRequest.setPathInfo(baseRequest.getRequestURI());
if (uri.getQuery()!=null)
baseRequest.mergeQueryString(uri.getQuery());
baseRequest.mergeQueryString(uri.getQuery()); //we have to assume dispatch path and query are UTF8
}
final String target=baseRequest.getPathInfo();

View File

@ -19,6 +19,7 @@
package org.eclipse.jetty.server;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@ -26,12 +27,16 @@ import static org.junit.Assert.fail;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.Set;
import junit.framework.Assert;
import org.eclipse.jetty.http.EncodedHttpURI;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.io.ByteArrayBuffer;
import org.eclipse.jetty.util.MultiMap;
import org.eclipse.jetty.util.TypeUtil;
import org.junit.Test;
public class HttpURITest
@ -205,6 +210,106 @@ public class HttpURITest
}
}
@Test
public void testNoPercentEncodingOfQueryUsingNonUTF8() throws Exception
{
byte[] utf8_bytes = "/%D0%A1%D1%82%D1%80%D0%BE%D0%BD%D0%B3-%D1%84%D0%B8%D0%BB%D1%8C%D1%82%D1%80/%D0%BA%D0%B0%D1%82%D0%B0%D0%BB%D0%BE%D0%B3?".getBytes("UTF-8");
byte[] cp1251_bytes = TypeUtil.fromHexString("e2fbe1f0e0edee3dd2e5ecefe5f0e0f2f3f0e0");
String expectedCP1251String = new String(cp1251_bytes, "cp1251");
String expectedCP1251Key = new String(cp1251_bytes, 0, 7, "cp1251");
String expectedCP1251Value = new String(cp1251_bytes, 8, cp1251_bytes.length-8, "cp1251");
//paste both byte arrays together to form the uri
byte[] allbytes = new byte[utf8_bytes.length+cp1251_bytes.length];
int i=0;
for (;i<utf8_bytes.length;i++) {
allbytes[i] = utf8_bytes[i];
}
for (int j=0; j< cp1251_bytes.length;j++)
allbytes[i+j] = cp1251_bytes[j];
//Test using a HttpUri that expects a particular charset encoding. See URIUtil.__CHARSET
EncodedHttpURI uri = new EncodedHttpURI("cp1251");
uri.parse(allbytes, 0, allbytes.length);
assertEquals(expectedCP1251String, uri.getQuery("cp1251"));
//Test params decoded correctly
MultiMap params = new MultiMap();
uri.decodeQueryTo(params);
String val = params.getString(expectedCP1251Key);
assertNotNull(val);
assertEquals(expectedCP1251Value, val);
//Test using HttpURI where you pass in the charset encoding.
HttpURI httpuri = new HttpURI();
httpuri.parse(allbytes,0,allbytes.length);
assertNotNull(httpuri.getQuery("UTF-8")); //still get back a query string, just incorrectly encoded
assertEquals(expectedCP1251String, httpuri.getQuery("cp1251"));
//Test params decoded correctly
params.clear();
httpuri.decodeQueryTo(params, "cp1251");
val = params.getString(expectedCP1251Key);
assertNotNull(val);
assertEquals(expectedCP1251Value, val);
//test able to set the query encoding and call getQueryString multiple times
Request request = new Request();
request.setUri(httpuri);
request.setAttribute("org.eclipse.jetty.server.Request.queryEncoding", "ISO-8859-1");
assertNotNull (request.getQueryString()); //will be incorrect encoding but not null
request.setAttribute("org.eclipse.jetty.server.Request.queryEncoding", "cp1251");
assertEquals(expectedCP1251String, request.getQueryString());
}
@Test
public void testPercentEncodingOfQueryStringUsingNonUTF8() throws UnsupportedEncodingException
{
byte[] utf8_bytes = "/%D0%A1%D1%82%D1%80%D0%BE%D0%BD%D0%B3-%D1%84%D0%B8%D0%BB%D1%8C%D1%82%D1%80/%D0%BA%D0%B0%D1%82%D0%B0%D0%BB%D0%BE%D0%B3?".getBytes("UTF-8");
byte[] cp1251_bytes = "%e2%fb%e1%f0%e0%ed%ee=%d2%e5%ec%ef%e5%f0%e0%f2%f3%f0%e0".getBytes("cp1251");
byte[] key_bytes = TypeUtil.fromHexString("e2fbe1f0e0edee");
byte[] val_bytes = TypeUtil.fromHexString("d2e5ecefe5f0e0f2f3f0e0");
String expectedCP1251String = new String(cp1251_bytes, "cp1251");
String expectedCP1251Key = new String(key_bytes, "cp1251");
String expectedCP1251Value = new String(val_bytes, "cp1251");
byte[] allbytes = new byte[utf8_bytes.length+cp1251_bytes.length];
//stick both arrays together to form uri
int i=0;
for (;i<utf8_bytes.length;i++) {
allbytes[i] = utf8_bytes[i];
}
for (int j=0; j< cp1251_bytes.length;j++)
allbytes[i+j] = cp1251_bytes[j];
HttpURI httpuri = new HttpURI();
httpuri.parse(allbytes,0,allbytes.length);
assertNotNull(httpuri.getQuery("UTF-8")); //will be incorrectly encoded, but no errors
assertEquals(expectedCP1251String, httpuri.getQuery("cp1251"));
//test params decoded correctly
MultiMap params = new MultiMap();
httpuri.decodeQueryTo(params, "cp1251");
String val = params.getString(expectedCP1251Key);
assertNotNull(val);
assertEquals(expectedCP1251Value, val);
//test able to set the query encoding and call getQueryString multiple times
Request request = new Request();
request.setUri(httpuri);
request.setAttribute("org.eclipse.jetty.server.Request.queryEncoding", "ISO-8859-1");
assertNotNull (request.getQueryString()); //will be incorrect encoding but not null
request.setAttribute("org.eclipse.jetty.server.Request.queryEncoding", "cp1251");
assertEquals(expectedCP1251String, request.getQueryString());
}
@Test
public void testUnicodeErrors() throws UnsupportedEncodingException

View File

@ -24,6 +24,7 @@ import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import javax.servlet.Filter;
@ -53,6 +54,7 @@ import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.TypeUtil;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@ -111,6 +113,23 @@ public class DispatcherTest
assertEquals(expected, responses);
}
@Test public void testForwardNonUTF8() throws Exception
{
_contextHandler.addServlet(ForwardNonUTF8Servlet.class, "/ForwardServlet/*");
_contextHandler.addServlet(AssertNonUTF8ForwardServlet.class, "/AssertForwardServlet/*");
String expected=
"HTTP/1.1 200 OK\r\n"+
"Content-Type: text/html\r\n"+
"Content-Length: 0\r\n"+
"\r\n";
String responses = _connector.getResponses("GET /context/ForwardServlet?do=assertforward&foreign=%d2%e5%ec%ef%e5%f0%e0%f2%f3%f0%e0&test=1 HTTP/1.1\n" + "Host: localhost\n\n");
assertEquals(expected, responses);
}
@Test
public void testForwardWithParam() throws Exception
{
@ -303,6 +322,7 @@ public class DispatcherTest
dispatcher = getServletContext().getRequestDispatcher("/IncludeServlet/includepath?do=assertforwardinclude");
else if(request.getParameter("do").equals("assertincludeforward"))
dispatcher = getServletContext().getRequestDispatcher("/AssertIncludeForwardServlet/assertpath?do=end");
else if(request.getParameter("do").equals("assertforward"))
dispatcher = getServletContext().getRequestDispatcher("/AssertForwardServlet?do=end&do=the");
else if(request.getParameter("do").equals("ctx.echo"))
@ -313,6 +333,18 @@ public class DispatcherTest
}
}
public static class ForwardNonUTF8Servlet extends HttpServlet implements Servlet
{
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
RequestDispatcher dispatcher = null;
request.setAttribute("org.eclipse.jetty.server.Request.queryEncoding", "cp1251");
dispatcher = getServletContext().getRequestDispatcher("/AssertForwardServlet?do=end&else=%D0%B2%D1%8B%D0%B1%D1%80%D0%B0%D0%BD%D0%BE%3D%D0%A2%D0%B5%D0%BC%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D1%83%D1%80%D0%B0");
dispatcher.forward(request, response);
}
}
/*
* Forward filter works with roger, echo and reverse echo servlets to test various
* forwarding bits using filters.
@ -531,6 +563,45 @@ public class DispatcherTest
response.setStatus(HttpServletResponse.SC_OK);
}
}
public static class AssertNonUTF8ForwardServlet extends HttpServlet implements Servlet
{
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
byte[] cp1251_bytes = TypeUtil.fromHexString("d2e5ecefe5f0e0f2f3f0e0");
String expectedCP1251String = new String(cp1251_bytes, "cp1251");
assertEquals( "/context/ForwardServlet", request.getAttribute(Dispatcher.FORWARD_REQUEST_URI));
assertEquals( "/context", request.getAttribute(Dispatcher.FORWARD_CONTEXT_PATH) );
assertEquals( "/ForwardServlet", request.getAttribute(Dispatcher.FORWARD_SERVLET_PATH));
assertEquals( null, request.getAttribute(Dispatcher.FORWARD_PATH_INFO));
assertEquals( "do=assertforward&foreign=%d2%e5%ec%ef%e5%f0%e0%f2%f3%f0%e0&test=1", request.getAttribute(Dispatcher.FORWARD_QUERY_STRING) );
List<String> expectedAttributeNames = Arrays.asList(Dispatcher.FORWARD_REQUEST_URI, Dispatcher.FORWARD_CONTEXT_PATH,
Dispatcher.FORWARD_SERVLET_PATH, Dispatcher.FORWARD_QUERY_STRING);
List<String> requestAttributeNames = Collections.list(request.getAttributeNames());
assertTrue(requestAttributeNames.containsAll(expectedAttributeNames));
assertEquals(null, request.getPathInfo());
assertEquals(null, request.getPathTranslated());
assertTrue(request.getQueryString().startsWith("do=end&else=%D0%B2%D1%8B%D0%B1%D1%80%D0%B0%D0%BD%D0%BE%3D%D0%A2%D0%B5%D0%BC%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D1%83%D1%80%D0%B0&test=1&foreign="));
String[] vals = request.getParameterValues("foreign");
assertTrue(vals!=null);
assertEquals(1, vals.length);
assertEquals(expectedCP1251String, vals[0]);
assertEquals("/context/AssertForwardServlet", request.getRequestURI());
assertEquals("/context", request.getContextPath());
assertEquals("/AssertForwardServlet", request.getServletPath());
response.setContentType("text/html");
response.setStatus(HttpServletResponse.SC_OK);
}
}
public static class AssertIncludeServlet extends HttpServlet implements Servlet
{