Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Wilkins2012-12-24 08:17:00 +0000
committerGreg Wilkins2012-12-24 08:17:00 +0000
commit31def062146702f03da8d6f2e7010b7d4586439b (patch)
tree518d0cef9629b9012944f780f5ccacdaea831c86
parent73d90623c77539c0899dbfa98132e4265062c2da (diff)
downloadorg.eclipse.jetty.project-31def062146702f03da8d6f2e7010b7d4586439b.tar.gz
org.eclipse.jetty.project-31def062146702f03da8d6f2e7010b7d4586439b.tar.xz
org.eclipse.jetty.project-31def062146702f03da8d6f2e7010b7d4586439b.zip
jetty-9 URI parsing passed ByteBuffer so that strange query string encodings can be supported
-rw-r--r--jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java74
-rw-r--r--jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java4
-rw-r--r--jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java16
-rw-r--r--jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java4
-rw-r--r--jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRuleTest.java2
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java2
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java6
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/Request.java6
-rw-r--r--jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/api/ClientUsageTest.java13
-rw-r--r--jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java10
-rw-r--r--jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java5
-rw-r--r--jetty-util/src/main/java/org/eclipse/jetty/util/ByteArrayOutputStream2.java5
-rw-r--r--jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java2
-rw-r--r--jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java269
-rw-r--r--jetty-util/src/test/java/org/eclipse/jetty/util/URLEncodedTest.java31
-rw-r--r--jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java2
-rw-r--r--jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/mux/MuxAddHandler.java3
-rw-r--r--tests/test-webapps/test-jetty-webapp/src/test/java/org/eclipse/jetty/DispatchServletTest.java7
18 files changed, 252 insertions, 209 deletions
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
index d373a29184..f77012a823 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
@@ -78,7 +78,7 @@ public class HttpParser
private HttpMethod _method;
private String _methodString;
private HttpVersion _version;
- private String _uri;
+ private ByteBuffer _uri=ByteBuffer.allocate(128); // Tune?
private byte _eol;
private EndOfContent _endOfContent;
private long _contentLength;
@@ -87,12 +87,10 @@ public class HttpParser
private int _chunkPosition;
private boolean _headResponse;
private ByteBuffer _contentChunk;
- // private final Trie<HttpField> _connectionFields=(Trie<HttpField>)HttpField.CONNECTION.clone();
- private final Trie<HttpField> _connectionFields=new Trie(512);
+ private final Trie<HttpField> _connectionFields=new Trie<>(512);
private int _length;
private final StringBuilder _string=new StringBuilder();
- private final Utf8StringBuilder _utf8=new Utf8StringBuilder();
/* ------------------------------------------------------------------------------- */
public HttpParser(RequestHandler<ByteBuffer> handler)
@@ -360,9 +358,39 @@ public class HttpParser
}
else
{
+ _uri.clear();
setState(State.URI);
- _utf8.reset();
- _utf8.append(ch);
+ // quick scan for space or EoBuffer
+ if (buffer.hasArray())
+ {
+ byte[] array=buffer.array();
+ int p=buffer.arrayOffset()+buffer.position();
+ int l=buffer.arrayOffset()+buffer.limit();
+ int i=p;
+ while (i<l && array[i]>HttpTokens.SPACE)
+ i++;
+
+ int len=i-p;
+ _headerBytes+=len;
+
+ if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes)
+ {
+ LOG.warn("URI is too large >"+_maxHeaderBytes);
+ badMessage(buffer,HttpStatus.REQUEST_URI_TOO_LONG_414,null);
+ return true;
+ }
+ if (_uri.remaining()<len)
+ {
+ ByteBuffer uri = ByteBuffer.allocate(_uri.capacity()+2*len);
+ _uri.flip();
+ uri.put(_uri);
+ _uri=uri;
+ }
+ _uri.put(array,p-1,len+1);
+ buffer.position(i-buffer.arrayOffset());
+ }
+ else
+ _uri.put(ch);
}
}
else if (ch < HttpTokens.SPACE)
@@ -396,15 +424,12 @@ public class HttpParser
case URI:
if (ch == HttpTokens.SPACE)
{
- _uri=_utf8.toString();
- _utf8.reset();
setState(State.SPACE2);
}
else if (ch < HttpTokens.SPACE && ch>=0)
{
// HTTP/0.9
- _uri=_utf8.toString();
- _utf8.reset();
+ _uri.flip();
return_from_parse|=_requestHandler.startRequest(_method,_methodString,_uri,null);
setState(State.END);
BufferUtil.clear(buffer);
@@ -412,7 +437,16 @@ public class HttpParser
return_from_parse|=_handler.messageComplete();
}
else
- _utf8.append(ch);
+ {
+ if (!_uri.hasRemaining())
+ {
+ ByteBuffer uri = ByteBuffer.allocate(_uri.capacity()*2);
+ _uri.flip();
+ uri.put(_uri);
+ _uri=uri;
+ }
+ _uri.put(ch);
+ }
break;
case SPACE2:
@@ -439,7 +473,8 @@ public class HttpParser
buffer.position(buffer.position()+_version.asString().length()-1);
_eol=buffer.get();
setState(State.HEADER);
- return_from_parse|=_requestHandler.startRequest(_method,_methodString, _uri, _version);
+ _uri.flip();
+ return_from_parse|=_requestHandler.startRequest(_method,_methodString,_uri, _version);
}
}
}
@@ -455,7 +490,8 @@ public class HttpParser
else
{
// HTTP/0.9
- return_from_parse|=_requestHandler.startRequest(_method,_methodString, _uri, null);
+ _uri.flip();
+ return_from_parse|=_requestHandler.startRequest(_method,_methodString,_uri, null);
setState(State.END);
BufferUtil.clear(buffer);
return_from_parse|=_handler.headerComplete();
@@ -477,7 +513,8 @@ public class HttpParser
_eol=ch;
setState(State.HEADER);
- return_from_parse|=_requestHandler.startRequest(_method,_methodString, _uri, _version);
+ _uri.flip();
+ return_from_parse|=_requestHandler.startRequest(_method,_methodString,_uri, _version);
continue;
}
else
@@ -1001,7 +1038,6 @@ public class HttpParser
_version=null;
_method=null;
_methodString=null;
- _uri=null;
_endOfContent=EndOfContent.UNKNOWN_CONTENT;
_header=null;
quickStart(buffer);
@@ -1214,7 +1250,6 @@ public class HttpParser
}
catch(Exception e)
{
- e.printStackTrace();
BufferUtil.clear(buffer);
if (isClosed())
{
@@ -1360,8 +1395,13 @@ public class HttpParser
{
/**
* This is the method called by parser when the HTTP request line is parsed
+ * @param method The method as enum if of a known type
+ * @param methodString The method as a string
+ * @param uri The raw bytes of the URI. These are copied into a ByteBuffer that will not be changed until this parser is reset and reused.
+ * @param version
+ * @return true if handling parsing should return.
*/
- public abstract boolean startRequest(HttpMethod method, String methodString, String uri, HttpVersion version);
+ public abstract boolean startRequest(HttpMethod method, String methodString, ByteBuffer uri, HttpVersion version);
/**
* This is the method called by the parser after it has parsed the host header (and checked it's format). This is
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java
index c038ebe429..414007de35 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java
@@ -237,10 +237,10 @@ public class HttpTester
private String _uri;
@Override
- public boolean startRequest(HttpMethod method, String methodString, String uri, HttpVersion version)
+ public boolean startRequest(HttpMethod method, String methodString, ByteBuffer uri, HttpVersion version)
{
_method=methodString;
- _uri=uri;
+ _uri=BufferUtil.toUTF8String(uri);
_version=version;
return false;
}
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java
index 27d83bc516..e4593ce1da 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java
@@ -127,7 +127,7 @@ public class HttpURI
public void parse(String raw)
{
- byte[] b = StringUtil.getBytes(raw);
+ byte[] b = StringUtil.getUtf8Bytes(raw);
parse2(b,0,b.length);
_rawString=raw;
}
@@ -680,12 +680,6 @@ public class HttpURI
return StringUtil.toString(bytes,0,n,encoding);
}
-
-
-
-
-
-
public String getPathAndParam()
{
@@ -734,17 +728,17 @@ public class HttpURI
return new String(_raw,_fragment+1,_end-_fragment-1,_charset);
}
- public void decodeQueryTo(MultiMap parameters)
+ public void decodeQueryTo(MultiMap<String> parameters)
{
if (_query==_fragment)
return;
if (_charset==StringUtil.__UTF8_CHARSET)
UrlEncoded.decodeUtf8To(_raw,_query+1,_fragment-_query-1,parameters);
else
- UrlEncoded.decodeTo(StringUtil.toString(_raw,_query+1,_fragment-_query-1,_charset.toString()),parameters,_charset.toString());
+ UrlEncoded.decodeTo(StringUtil.toString(_raw,_query+1,_fragment-_query-1,_charset.toString()),parameters,_charset.toString(),-1);
}
- public void decodeQueryTo(MultiMap parameters, String encoding) throws UnsupportedEncodingException
+ public void decodeQueryTo(MultiMap<String> parameters, String encoding) throws UnsupportedEncodingException
{
if (_query==_fragment)
return;
@@ -752,7 +746,7 @@ public class HttpURI
if (encoding==null || StringUtil.isUTF8(encoding))
UrlEncoded.decodeUtf8To(_raw,_query+1,_fragment-_query-1,parameters);
else
- UrlEncoded.decodeTo(StringUtil.toString(_raw,_query+1,_fragment-_query-1,encoding),parameters,encoding);
+ UrlEncoded.decodeTo(StringUtil.toString(_raw,_query+1,_fragment-_query-1,encoding),parameters,encoding,-1);
}
public void clear()
diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java
index 3000e8d91d..3a949b6f14 100644
--- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java
+++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java
@@ -843,14 +843,14 @@ public class HttpParserTest
}
@Override
- public boolean startRequest(HttpMethod httpMethod, String method, String uri, HttpVersion version)
+ public boolean startRequest(HttpMethod httpMethod, String method, ByteBuffer uri, HttpVersion version)
{
request=true;
_h= -1;
_hdr= new String[10];
_val= new String[10];
_methodOrVersion= method;
- _uriOrStatus= uri;
+ _uriOrStatus= BufferUtil.toUTF8String(uri);
_versionOrReason= version==null?null:version.asString();
fields=new HttpFields();
diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRuleTest.java
index e847b29a98..0f9483c4f9 100644
--- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRuleTest.java
+++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRuleTest.java
@@ -87,7 +87,7 @@ public class RewriteRegexRuleTest extends AbstractRuleTestCase
if (test[5]!=null)
{
MultiMap<String> params=new MultiMap<String>();
- UrlEncoded.decodeTo(test[5],params,StringUtil.__UTF8);
+ UrlEncoded.decodeTo(test[5],params,StringUtil.__UTF8_CHARSET,-1);
for (String n:params.keySet())
assertEquals(params.getString(n),_request.getParameter(n));
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java
index 46e5cb5d86..4c5a1051fe 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java
@@ -147,7 +147,7 @@ public class Dispatcher implements RequestDispatcher
}
MultiMap<String> parameters=new MultiMap<>();
- UrlEncoded.decodeTo(query,parameters,baseRequest.getCharacterEncoding());
+ UrlEncoded.decodeTo(query,parameters,baseRequest.getCharacterEncoding(),-1);
if(old_params != null) {
// Merge parameters.
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
index 2eeab02169..92d67ed101 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
@@ -373,7 +373,7 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
}
@Override
- public boolean startRequest(HttpMethod httpMethod, String method, String uri, HttpVersion version)
+ public boolean startRequest(HttpMethod httpMethod, String method, ByteBuffer uri, HttpVersion version)
{
_expect = false;
_expect100Continue = false;
@@ -384,9 +384,9 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
_request.setMethod(httpMethod, method);
if (httpMethod == HttpMethod.CONNECT)
- _uri.parseConnect(uri);
+ _uri.parseConnect(uri.array(),uri.arrayOffset()+uri.position(),uri.remaining());
else
- _uri.parse(uri);
+ _uri.parse(uri.array(),uri.arrayOffset()+uri.position(),uri.remaining());
_request.setUri(_uri);
String path;
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java
index 6ce69d268f..31678f55be 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java
@@ -2102,7 +2102,7 @@ public class Request implements HttpServletRequest
{
// extract parameters from dispatch query
MultiMap<String> parameters = new MultiMap<>();
- UrlEncoded.decodeTo(query,parameters, StringUtil.__UTF8); //have to assume UTF-8 because we can't know otherwise
+ UrlEncoded.decodeTo(query,parameters, StringUtil.__UTF8_CHARSET,-1); //have to assume UTF-8 because we can't know otherwise
boolean merge_old_query = false;
@@ -2123,11 +2123,11 @@ public class Request implements HttpServletRequest
{
StringBuilder overridden_query_string = new StringBuilder();
MultiMap<String> overridden_old_query = new MultiMap<>();
- UrlEncoded.decodeTo(_queryString,overridden_old_query,getQueryEncoding());//decode using any queryencoding set for the request
+ UrlEncoded.decodeTo(_queryString,overridden_old_query,getQueryEncoding(),-1);//decode using any queryencoding set for the request
MultiMap<String> overridden_new_query = new MultiMap<>();
- UrlEncoded.decodeTo(query,overridden_new_query,StringUtil.__UTF8); //have to assume utf8 as we cannot know otherwise
+ UrlEncoded.decodeTo(query,overridden_new_query,StringUtil.__UTF8_CHARSET,-1); //have to assume utf8 as we cannot know otherwise
for(String name: overridden_old_query.keySet())
{
diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/api/ClientUsageTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/api/ClientUsageTest.java
index e7111b79e3..9e74f2777f 100644
--- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/api/ClientUsageTest.java
+++ b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/api/ClientUsageTest.java
@@ -136,7 +136,7 @@ public class ClientUsageTest
Session session = new StandardSession(SPDY.V2, null, null, null, null, null, null, 1, null, null, null);
session.syn(new SynInfo(new Fields(), false), new StreamFrameListener.Adapter()
- {
+ {
// The good of passing the listener to push() is that applications can safely
// accumulate info from the reply headers to be used in the data callback,
// e.g. content-type, charset, etc.
@@ -167,16 +167,11 @@ public class ClientUsageTest
{
StringBuilder builder = (StringBuilder)stream.getAttribute("builder");
builder.append(dataInfo.asString("UTF-8", true));
- if (dataInfo.isClose())
- {
- int receivedLength = builder.toString().getBytes(Charset.forName("UTF-8")).length;
- assert receivedLength == stream.getAttribute("content-length");
- }
}
- }, new Promise.Adapter<Stream>()
- {
- @Override
+ }, new Promise.Adapter<Stream>()
+ {
+ @Override
public void succeeded(Stream stream)
{
stream.data(new BytesDataInfo("wee".getBytes(Charset.forName("UTF-8")), false), new Callback.Adapter());
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java
index 54dcc66438..75acdf1a61 100644
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java
+++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java
@@ -33,6 +33,7 @@ import org.eclipse.jetty.server.HttpTransport;
import org.eclipse.jetty.spdy.api.ByteBufferDataInfo;
import org.eclipse.jetty.spdy.api.DataInfo;
import org.eclipse.jetty.spdy.api.Stream;
+import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@@ -170,10 +171,13 @@ public class HttpChannelOverSPDY extends HttpChannel<DataInfo>
HttpMethod httpMethod = HttpMethod.fromString(methodHeader.value());
HttpVersion httpVersion = HttpVersion.fromString(versionHeader.value());
- String uriString = uriHeader.value();
+
+ // TODO should handle URI as byte buffer as some bad clients send WRONG encodings in query string
+ // that we have to deal with
+ ByteBuffer uri = BufferUtil.toBuffer(uriHeader.value());
- LOG.debug("HTTP > {} {} {}", httpMethod, uriString, httpVersion);
- startRequest(httpMethod, httpMethod.asString(), uriString, httpVersion);
+ LOG.debug("HTTP > {} {} {}", httpMethod, uriHeader.value(), httpVersion);
+ startRequest(httpMethod, httpMethod.asString(), uri, httpVersion);
Fields.Field schemeHeader = headers.get(HTTPSPDYHeader.SCHEME.name(version));
if (schemeHeader != null)
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java
index b601af5108..304812327c 100644
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java
+++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java
@@ -52,6 +52,7 @@ import org.eclipse.jetty.spdy.api.Stream;
import org.eclipse.jetty.spdy.api.StreamFrameListener;
import org.eclipse.jetty.spdy.api.SynInfo;
import org.eclipse.jetty.spdy.server.http.HTTPSPDYHeader;
+import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.Promise;
@@ -80,13 +81,13 @@ public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParse
}
@Override
- public boolean startRequest(HttpMethod method, String methodString, String uri, HttpVersion httpVersion)
+ public boolean startRequest(HttpMethod method, String methodString, ByteBuffer uri, HttpVersion httpVersion)
{
Connector connector = getConnector();
String scheme = connector.getConnectionFactory(SslConnectionFactory.class) != null ? "https" : "http";
headers.put(HTTPSPDYHeader.SCHEME.name(version), scheme);
headers.put(HTTPSPDYHeader.METHOD.name(version), methodString);
- headers.put(HTTPSPDYHeader.URI.name(version), uri);
+ headers.put(HTTPSPDYHeader.URI.name(version), BufferUtil.toUTF8String(uri)); // TODO handle bad encodings
headers.put(HTTPSPDYHeader.VERSION.name(version), httpVersion.asString());
return false;
}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ByteArrayOutputStream2.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ByteArrayOutputStream2.java
index b370bfddbd..2da49421f9 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/ByteArrayOutputStream2.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ByteArrayOutputStream2.java
@@ -18,6 +18,7 @@
package org.eclipse.jetty.util;
import java.io.ByteArrayOutputStream;
+import java.nio.charset.Charset;
/* ------------------------------------------------------------ */
/** ByteArrayOutputStream with public internals
@@ -46,4 +47,8 @@ public class ByteArrayOutputStream2 extends ByteArrayOutputStream
buf[count++]=(byte)b;
}
+ public String toString(Charset charset)
+ {
+ return new String(buf, 0, count, charset);
+ }
}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java
index 2566142452..d7ca17bb2a 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java
@@ -52,11 +52,13 @@ public class StringUtil
public final static Charset __UTF8_CHARSET;
public final static Charset __ISO_8859_1_CHARSET;
+ public final static Charset __UTF16_CHARSET;
static
{
__UTF8_CHARSET=Charset.forName(__UTF8);
__ISO_8859_1_CHARSET=Charset.forName(__ISO_8859_1);
+ __UTF16_CHARSET=Charset.forName(__UTF16);
CHARSETS.put("UTF-8",__UTF8);
CHARSETS.put("UTF8",__UTF8);
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java b/jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java
index 01e0e9c145..58474f83f9 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java
@@ -25,6 +25,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;
@@ -56,31 +57,31 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
{
static final Logger LOG = Log.getLogger(UrlEncoded.class);
- public static final String ENCODING = System.getProperty("org.eclipse.jetty.util.UrlEncoding.charset",StringUtil.__UTF8);
-
- /* ----------------------------------------------------------------- */
- public UrlEncoded(UrlEncoded url)
- {
- super(url);
- }
-
- /* ----------------------------------------------------------------- */
- public UrlEncoded()
+ public static final Charset ENCODING;
+ static
{
+ Charset encoding=null;
+ try
+ {
+ encoding=Charset.forName(System.getProperty("org.eclipse.jetty.util.UrlEncoding.charset",StringUtil.__UTF8));
+ }
+ catch(Exception e)
+ {
+ LOG.warn(e);
+ encoding=StringUtil.__UTF8_CHARSET;
+ }
+ ENCODING=encoding;
}
/* ----------------------------------------------------------------- */
- public UrlEncoded(String s)
+ public UrlEncoded(UrlEncoded url)
{
- this();
- decode(s,ENCODING);
+ super(url);
}
/* ----------------------------------------------------------------- */
- public UrlEncoded(String s, String charset)
+ public UrlEncoded()
{
- this();
- decode(s,charset);
}
/* ----------------------------------------------------------------- */
@@ -90,7 +91,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
}
/* ----------------------------------------------------------------- */
- public void decode(String query,String charset)
+ public void decode(String query,Charset charset)
{
decodeTo(query,this,charset,-1);
}
@@ -106,7 +107,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
/* -------------------------------------------------------------- */
/** Encode Hashtable with % encoding.
*/
- public String encode(String charset)
+ public String encode(Charset charset)
{
return encode(charset,false);
}
@@ -116,7 +117,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
* @param equalsForNullValue if True, then an '=' is always used, even
* for parameters without a value. e.g. "blah?a=&b=&c=".
*/
- public synchronized String encode(String charset, boolean equalsForNullValue)
+ public synchronized String encode(Charset charset, boolean equalsForNullValue)
{
return encode(this,charset,equalsForNullValue);
}
@@ -126,7 +127,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
* @param equalsForNullValue if True, then an '=' is always used, even
* for parameters without a value. e.g. "blah?a=&b=&c=".
*/
- public static String encode(MultiMap<String> map, String charset, boolean equalsForNullValue)
+ public static String encode(MultiMap<String> map, Charset charset, boolean equalsForNullValue)
{
if (charset==null)
charset=ENCODING;
@@ -180,22 +181,20 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
return result.toString();
}
-
-
/* -------------------------------------------------------------- */
/** Decoded parameters to Map.
* @param content the string containing the encoded parameters
*/
- public static void decodeTo(String content, MultiMap<String> map, String charset)
+ public static void decodeTo(String content, MultiMap<String> map, String charset, int maxKeys)
{
- decodeTo(content,map,charset,-1);
+ decodeTo(content,map,charset==null?null:Charset.forName(charset),maxKeys);
}
/* -------------------------------------------------------------- */
/** Decoded parameters to Map.
* @param content the string containing the encoded parameters
*/
- public static void decodeTo(String content, MultiMap<String> map, String charset, int maxKeys)
+ public static void decodeTo(String content, MultiMap<String> map, Charset charset, int maxKeys)
{
if (charset==null)
charset=ENCODING;
@@ -570,7 +569,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
decodeTo(buf.getBuffer().toString(),map,ENCODING,maxKeys);
}
-
+
/* -------------------------------------------------------------- */
/** Decoded parameters to Map.
* @param in the stream containing the encoded parameters
@@ -578,30 +577,51 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
public static void decodeTo(InputStream in, MultiMap<String> map, String charset, int maxLength, int maxKeys)
throws IOException
{
+ if (charset==null)
+ {
+ if (ENCODING==StringUtil.__UTF8_CHARSET)
+ decodeUtf8To(in,map,maxLength,maxKeys);
+ else
+ decodeTo(in,map,ENCODING,maxLength,maxKeys);
+ }
+ else if (StringUtil.__UTF8.equalsIgnoreCase(charset))
+ decodeUtf8To(in,map,maxLength,maxKeys);
+ else if (StringUtil.__ISO_8859_1.equalsIgnoreCase(charset))
+ decode88591To(in,map,maxLength,maxKeys);
+ else if (StringUtil.__UTF16.equalsIgnoreCase(charset))
+ decodeUtf16To(in,map,maxLength,maxKeys);
+ else
+ decodeTo(in,map,Charset.forName(charset),maxLength,maxKeys);
+ }
+
+ /* -------------------------------------------------------------- */
+ /** Decoded parameters to Map.
+ * @param in the stream containing the encoded parameters
+ */
+ public static void decodeTo(InputStream in, MultiMap<String> map, Charset charset, int maxLength, int maxKeys)
+ throws IOException
+ {
//no charset present, use the configured default
if (charset==null)
- {
charset=ENCODING;
- }
- if (StringUtil.__UTF8.equalsIgnoreCase(charset))
+ if (StringUtil.__UTF8_CHARSET.equals(charset))
{
decodeUtf8To(in,map,maxLength,maxKeys);
return;
}
- if (StringUtil.__ISO_8859_1.equals(charset))
+ if (StringUtil.__ISO_8859_1_CHARSET.equals(charset))
{
decode88591To(in,map,maxLength,maxKeys);
return;
}
- if (StringUtil.__UTF16.equalsIgnoreCase(charset)) // Should be all 2 byte encodings
+ if (StringUtil.__UTF16_CHARSET.equals(charset)) // Should be all 2 byte encodings
{
decodeUtf16To(in,map,maxLength,maxKeys);
return;
}
-
synchronized(map)
{
@@ -700,9 +720,9 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
* This method makes the assumption that the majority of calls
* will need no decoding.
*/
- public static String decodeString(String encoded,int offset,int length,String charset)
+ public static String decodeString(String encoded,int offset,int length,Charset charset)
{
- if (charset==null || StringUtil.isUTF8(charset))
+ if (charset==null || StringUtil.__UTF8_CHARSET.equals(charset))
{
Utf8StringBuffer buffer=null;
@@ -786,117 +806,110 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
{
StringBuffer buffer=null;
- try
+ for (int i=0;i<length;i++)
{
- for (int i=0;i<length;i++)
+ char c = encoded.charAt(offset+i);
+ if (c<0||c>0xff)
{
- char c = encoded.charAt(offset+i);
- if (c<0||c>0xff)
+ if (buffer==null)
{
- if (buffer==null)
- {
- buffer=new StringBuffer(length);
- buffer.append(encoded,offset,offset+i+1);
- }
- else
- buffer.append(c);
+ buffer=new StringBuffer(length);
+ buffer.append(encoded,offset,offset+i+1);
}
- else if (c=='+')
+ else
+ buffer.append(c);
+ }
+ else if (c=='+')
+ {
+ if (buffer==null)
{
- if (buffer==null)
- {
- buffer=new StringBuffer(length);
- buffer.append(encoded,offset,offset+i);
- }
-
- buffer.append(' ');
+ buffer=new StringBuffer(length);
+ buffer.append(encoded,offset,offset+i);
}
- else if (c=='%')
+
+ buffer.append(' ');
+ }
+ else if (c=='%')
+ {
+ if (buffer==null)
{
- if (buffer==null)
- {
- buffer=new StringBuffer(length);
- buffer.append(encoded,offset,offset+i);
- }
+ buffer=new StringBuffer(length);
+ buffer.append(encoded,offset,offset+i);
+ }
- byte[] ba=new byte[length];
- int n=0;
- while(c>=0 && c<=0xff)
- {
- if (c=='%')
- {
- if(i+2<length)
+ byte[] ba=new byte[length];
+ int n=0;
+ while(c>=0 && c<=0xff)
+ {
+ if (c=='%')
+ {
+ if(i+2<length)
+ {
+ try
{
- try
+ if ('u'==encoded.charAt(offset+i+1))
{
- if ('u'==encoded.charAt(offset+i+1))
- {
- int o=offset+i+2;
- i+=6;
- String unicode = new String(Character.toChars(TypeUtil.parseInt(encoded,o,4,16)));
- byte[] reencoded = unicode.getBytes(charset);
- System.arraycopy(reencoded,0,ba,n,reencoded.length);
- n+=reencoded.length;
- }
- else
- {
- int o=offset+i+1;
- i+=3;
- ba[n]=(byte)TypeUtil.parseInt(encoded,o,2,16);
- n++;
- }
+ int o=offset+i+2;
+ i+=6;
+ String unicode = new String(Character.toChars(TypeUtil.parseInt(encoded,o,4,16)));
+ byte[] reencoded = unicode.getBytes(charset);
+ System.arraycopy(reencoded,0,ba,n,reencoded.length);
+ n+=reencoded.length;
}
- catch(NumberFormatException nfe)
- {
- LOG.ignore(nfe);
- ba[n++] = (byte)'?';
+ else
+ {
+ int o=offset+i+1;
+ i+=3;
+ ba[n]=(byte)TypeUtil.parseInt(encoded,o,2,16);
+ n++;
}
}
- else
- {
- ba[n++] = (byte)'%';
- i++;
+ catch(NumberFormatException nfe)
+ {
+ LOG.ignore(nfe);
+ ba[n++] = (byte)'?';
}
}
- else if (c=='+')
- {
- ba[n++]=(byte)' ';
- i++;
- }
else
{
- ba[n++]=(byte)c;
+ ba[n++] = (byte)'%';
i++;
}
-
- if (i>=length)
- break;
- c = encoded.charAt(offset+i);
+ }
+ else if (c=='+')
+ {
+ ba[n++]=(byte)' ';
+ i++;
+ }
+ else
+ {
+ ba[n++]=(byte)c;
+ i++;
}
- i--;
- buffer.append(new String(ba,0,n,charset));
-
+ if (i>=length)
+ break;
+ c = encoded.charAt(offset+i);
}
- else if (buffer!=null)
- buffer.append(c);
- }
- if (buffer==null)
- {
- if (offset==0 && encoded.length()==length)
- return encoded;
- return encoded.substring(offset,offset+length);
- }
+ i--;
+ buffer.append(new String(ba,0,n,charset));
- return buffer.toString();
+ }
+ else if (buffer!=null)
+ buffer.append(c);
}
- catch (UnsupportedEncodingException e)
+
+ if (buffer==null)
{
- throw new RuntimeException(e);
+ if (offset==0 && encoded.length()==length)
+ return encoded;
+ return encoded.substring(offset,offset+length);
}
+
+ return buffer.toString();
}
-
+
}
/* ------------------------------------------------------------ */
@@ -914,20 +927,12 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
* @param string
* @return encoded string.
*/
- public static String encodeString(String string,String charset)
+ public static String encodeString(String string,Charset charset)
{
if (charset==null)
charset=ENCODING;
byte[] bytes=null;
- try
- {
- bytes=string.getBytes(charset);
- }
- catch(UnsupportedEncodingException e)
- {
- // LOG.warn(LogSupport.EXCEPTION,e);
- bytes=string.getBytes();
- }
+ bytes=string.getBytes(charset);
int len=bytes.length;
byte[] encoded= new byte[bytes.length*3];
@@ -969,15 +974,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
if (noEncode)
return string;
- try
- {
- return new String(encoded,0,n,charset);
- }
- catch(UnsupportedEncodingException e)
- {
- // LOG.warn(LogSupport.EXCEPTION,e);
- return new String(encoded,0,n);
- }
+ return new String(encoded,0,n,charset);
}
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/URLEncodedTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/URLEncodedTest.java
index dfa5b6e3fc..f152bf65ba 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/URLEncodedTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/URLEncodedTest.java
@@ -22,6 +22,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
+import java.nio.charset.Charset;
import org.junit.Assert;
import org.junit.Test;
@@ -120,24 +121,24 @@ public class URLEncodedTest
assertEquals("encoded get", url_encoded.getString("Name8"),"xx, yy ,zz");
url_encoded.clear();
- url_encoded.decode("Name11=%u30EDxxVerdi+%C6+og+2zz", "ISO-8859-1");
+ url_encoded.decode("Name11=%u30EDxxVerdi+%C6+og+2zz", StringUtil.__ISO_8859_1_CHARSET);
assertEquals("encoded param size",1, url_encoded.size());
assertEquals("encoded get", "?xxVerdi \u00c6 og 2zz",url_encoded.getString("Name11"));
url_encoded.clear();
- url_encoded.decode("Name12=%u30EDxxVerdi+%2F+og+2zz", "UTF-8");
+ url_encoded.decode("Name12=%u30EDxxVerdi+%2F+og+2zz", StringUtil.__UTF8_CHARSET);
assertEquals("encoded param size",1, url_encoded.size());
assertEquals("encoded get", url_encoded.getString("Name12"),"\u30edxxVerdi / og 2zz");
url_encoded.clear();
- url_encoded.decode("Name14=%uXXXXa%GGb%+%c%+%d", "ISO-8859-1");
+ url_encoded.decode("Name14=%uXXXXa%GGb%+%c%+%d", StringUtil.__ISO_8859_1_CHARSET);
assertEquals("encoded param size",1, url_encoded.size());
assertEquals("encoded get","?a?b?c?d", url_encoded.getString("Name14"));
url_encoded.clear();
- url_encoded.decode("Name14=%uXXXX%GG%+%%+%", "UTF-8");
+ url_encoded.decode("Name14=%uXXXX%GG%+%%+%", StringUtil.__UTF8_CHARSET);
assertEquals("encoded param size",1, url_encoded.size());
- assertEquals("encoded get", url_encoded.getString("Name14"),"\ufffd\ufffd\ufffd\ufffd");
+ assertEquals("encoded get", "\ufffd\ufffd\ufffd\ufffd",url_encoded.getString("Name14"));
/* Not every jvm supports this encoding */
@@ -145,7 +146,7 @@ public class URLEncodedTest
if (java.nio.charset.Charset.isSupported("SJIS"))
{
url_encoded.clear();
- url_encoded.decode("Name9=%u30ED%83e%83X%83g", "SJIS"); // "Test" in Japanese Katakana
+ url_encoded.decode("Name9=%u30ED%83e%83X%83g", Charset.forName("SJIS")); // "Test" in Japanese Katakana
assertEquals("encoded param size",1, url_encoded.size());
assertEquals("encoded get", "\u30ed\u30c6\u30b9\u30c8", url_encoded.getString("Name9"));
}
@@ -159,11 +160,11 @@ public class URLEncodedTest
public void testBadEncoding()
{
UrlEncoded url_encoded = new UrlEncoded();
- url_encoded.decode("Name15=xx%zz", "UTF-8");
+ url_encoded.decode("Name15=xx%zz", StringUtil.__UTF8_CHARSET);
assertEquals("encoded param size",1, url_encoded.size());
assertEquals("encoded get", "xx\ufffd", url_encoded.getString("Name15"));
- assertEquals("xxx",UrlEncoded.decodeString("xxx%u123",0,5,"UTF-8"));
+ assertEquals("xxx",UrlEncoded.decodeString("xxx%u123",0,5,StringUtil.__UTF8_CHARSET));
}
@@ -185,12 +186,12 @@ public class URLEncodedTest
{
ByteArrayInputStream in = new ByteArrayInputStream("name\n=value+%30&name1=&name2&n\u00e3me3=value+3".getBytes(charsets[i][0]));
MultiMap<String> m = new MultiMap<>();
- UrlEncoded.decodeTo(in, m, charsets[i][1], -1,-1);
- assertEquals(i+" stream length",4,m.size());
- assertEquals(i+" stream name\\n","value 0",m.getString("name\n"));
- assertEquals(i+" stream name1","",m.getString("name1"));
- assertEquals(i+" stream name2","",m.getString("name2"));
- assertEquals(i+" stream n\u00e3me3","value 3",m.getString("n\u00e3me3"));
+ UrlEncoded.decodeTo(in, m, charsets[i][1]==null?null:Charset.forName(charsets[i][1]), -1,-1);
+ assertEquals(charsets[i][1]+" stream length",4,m.size());
+ assertEquals(charsets[i][1]+" stream name\\n","value 0",m.getString("name\n"));
+ assertEquals(charsets[i][1]+" stream name1","",m.getString("name1"));
+ assertEquals(charsets[i][1]+" stream name2","",m.getString("name2"));
+ assertEquals(charsets[i][1]+" stream n\u00e3me3","value 3",m.getString("n\u00e3me3"));
}
@@ -198,7 +199,7 @@ public class URLEncodedTest
{
ByteArrayInputStream in2 = new ByteArrayInputStream ("name=%83e%83X%83g".getBytes(StringUtil.__ISO_8859_1));
MultiMap<String> m2 = new MultiMap<>();
- UrlEncoded.decodeTo(in2, m2, "Shift_JIS", -1,-1);
+ UrlEncoded.decodeTo(in2, m2, Charset.forName("Shift_JIS"), -1,-1);
assertEquals("stream length",1,m2.size());
assertEquals("stream name","\u30c6\u30b9\u30c8",m2.getString("name"));
}
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java
index cead6208ad..95d02d4043 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java
@@ -88,7 +88,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Web
String query = requestURI.getQuery();
if (StringUtil.isNotBlank(query))
{
- UrlEncoded.decodeTo(query,params,StringUtil.__UTF8);
+ UrlEncoded.decodeTo(query,params,StringUtil.__UTF8_CHARSET,-1);
}
for (String name : params.keySet())
diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/mux/MuxAddHandler.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/mux/MuxAddHandler.java
index 306531cd0d..31cd5e0d9a 100644
--- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/mux/MuxAddHandler.java
+++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/mux/MuxAddHandler.java
@@ -27,6 +27,7 @@ import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.websocket.api.UpgradeRequest;
import org.eclipse.jetty.websocket.api.UpgradeResponse;
import org.eclipse.jetty.websocket.common.extensions.mux.MuxChannel;
@@ -89,7 +90,7 @@ public class MuxAddHandler implements MuxAddServer
HttpMethod method = HttpMethod.fromString(request.getMethod());
HttpVersion version = HttpVersion.fromString(request.getHttpVersion());
- httpChannel.startRequest(method,request.getMethod(),request.getRequestURI().toASCIIString(),version);
+ httpChannel.startRequest(method,request.getMethod(),BufferUtil.toBuffer(request.getRequestURI().toASCIIString()),version);
for (String headerName : request.getHeaders().keySet())
{
diff --git a/tests/test-webapps/test-jetty-webapp/src/test/java/org/eclipse/jetty/DispatchServletTest.java b/tests/test-webapps/test-jetty-webapp/src/test/java/org/eclipse/jetty/DispatchServletTest.java
index 6f800eb7de..8aff82d723 100644
--- a/tests/test-webapps/test-jetty-webapp/src/test/java/org/eclipse/jetty/DispatchServletTest.java
+++ b/tests/test-webapps/test-jetty-webapp/src/test/java/org/eclipse/jetty/DispatchServletTest.java
@@ -22,10 +22,14 @@ import com.acme.DispatchServlet;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlet.ServletTester;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.StdErrLog;
+import org.hamcrest.Matchers;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertThat;
/**
* Simple tests against DispatchServlet.
@@ -136,8 +140,7 @@ public class DispatchServletTest
response.startsWith("HTTP/1.1 413 "));
assertFalse(msg + " should not be code 500.", response.startsWith("HTTP/1.1 500 "));
-
- assertTrue(msg + " should return error code 403 (Forbidden)", response.startsWith("HTTP/1.1 403 "));
+ assertThat(response,Matchers.startsWith("HTTP/1.1 403 "));
}
}
}

Back to the top