Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java1
-rw-r--r--jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java332
-rw-r--r--jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java45
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java1
-rw-r--r--jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java1
-rw-r--r--jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java2
6 files changed, 199 insertions, 183 deletions
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java
index aedfd2aec2..6d835dc2d5 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java
@@ -68,6 +68,7 @@ public class HttpField
CACHE.put(new CachedHttpField(HttpHeader.CONTENT_LENGTH,"0"));
CACHE.put(new CachedHttpField(HttpHeader.CONTENT_ENCODING,"gzip"));
CACHE.put(new CachedHttpField(HttpHeader.CONTENT_ENCODING,"deflate"));
+ CACHE.put(new CachedHttpField(HttpHeader.TRANSFER_ENCODING,"chunked"));
CACHE.put(new CachedHttpField(HttpHeader.EXPIRES,"Fri, 01 Jan 1990 00:00:00 GMT"));
// Content types
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 99c2231996..db4642957d 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
@@ -63,11 +63,18 @@ import org.eclipse.jetty.util.log.Logger;
* per parser dynamic Trie of {@link HttpFields} from previous parsed messages
* is used to help the parsing of subsequent messages.
* </p>
+ * <p>
+ * If the system property "org.eclipse.jetty.http.HttpParser.STRICT" is set to true,
+ * then the parser will strictly pass on the exact strings received for methods and header
+ * fields. Otherwise a fast case insensitive string lookup is used that may alter the
+ * case of the method and/or headers
+ * </p>
*/
public class HttpParser
{
public static final Logger LOG = Log.getLogger(HttpParser.class);
- static final int INITIAL_URI_LENGTH=256;
+ public final static boolean __STRICT=Boolean.getBoolean("org.eclipse.jetty.http.HttpParser.STRICT");
+ public final static int INITIAL_URI_LENGTH=256;
// States
public enum State
@@ -82,7 +89,6 @@ public class HttpParser
REQUEST_VERSION,
REASON,
HEADER,
- HEADER_NAME,
HEADER_IN_NAME,
HEADER_VALUE,
HEADER_IN_VALUE,
@@ -101,6 +107,7 @@ public class HttpParser
private final RequestHandler<ByteBuffer> _requestHandler;
private final ResponseHandler<ByteBuffer> _responseHandler;
private final int _maxHeaderBytes;
+ private final boolean _strict;
private HttpField _field;
private HttpHeader _header;
private String _headerString;
@@ -132,31 +139,45 @@ public class HttpParser
/* ------------------------------------------------------------------------------- */
public HttpParser(RequestHandler<ByteBuffer> handler)
{
- this(handler,-1);
+ this(handler,-1,__STRICT);
}
/* ------------------------------------------------------------------------------- */
public HttpParser(ResponseHandler<ByteBuffer> handler)
{
- this(handler,-1);
+ this(handler,-1,__STRICT);
}
/* ------------------------------------------------------------------------------- */
public HttpParser(RequestHandler<ByteBuffer> handler,int maxHeaderBytes)
{
+ this(handler,maxHeaderBytes,__STRICT);
+ }
+
+ /* ------------------------------------------------------------------------------- */
+ public HttpParser(ResponseHandler<ByteBuffer> handler,int maxHeaderBytes)
+ {
+ this(handler,maxHeaderBytes,__STRICT);
+ }
+
+ /* ------------------------------------------------------------------------------- */
+ public HttpParser(RequestHandler<ByteBuffer> handler,int maxHeaderBytes,boolean strict)
+ {
_handler=handler;
_requestHandler=handler;
_responseHandler=null;
_maxHeaderBytes=maxHeaderBytes;
+ _strict=strict;
}
/* ------------------------------------------------------------------------------- */
- public HttpParser(ResponseHandler<ByteBuffer> handler,int maxHeaderBytes)
+ public HttpParser(ResponseHandler<ByteBuffer> handler,int maxHeaderBytes,boolean strict)
{
_handler=handler;
_requestHandler=null;
_responseHandler=handler;
_maxHeaderBytes=maxHeaderBytes;
+ _strict=strict;
}
/* ------------------------------------------------------------------------------- */
@@ -376,14 +397,16 @@ public class HttpParser
return false;
}
- private String takeString()
+ /* ------------------------------------------------------------------------------- */
+ private void setString(String s)
{
- String s =_string.toString();
_string.setLength(0);
- return s;
+ _string.append(s);
+ _length=s.length();
}
-
- private String takeLengthString()
+
+ /* ------------------------------------------------------------------------------- */
+ private String takeString()
{
_string.setLength(_length);
String s =_string.toString();
@@ -429,9 +452,10 @@ public class HttpParser
case METHOD:
if (ch == HttpTokens.SPACE)
{
+ _length=_string.length();
_methodString=takeString();
HttpMethod method=HttpMethod.CACHE.get(_methodString);
- if (method!=null)
+ if (method!=null && !_strict)
_methodString=method.asString();
setState(State.SPACE1);
}
@@ -444,6 +468,7 @@ public class HttpParser
case RESPONSE_VERSION:
if (ch == HttpTokens.SPACE)
{
+ _length=_string.length();
String version=takeString();
_version=HttpVersion.CACHE.get(version);
if (_version==null)
@@ -622,7 +647,10 @@ public class HttpParser
if (ch == HttpTokens.LINE_FEED)
{
if (_version==null)
+ {
+ _length=_string.length();
_version=HttpVersion.CACHE.get(takeString());
+ }
if (_version==null)
{
throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Unknown Version");
@@ -651,7 +679,7 @@ public class HttpParser
case REASON:
if (ch == HttpTokens.LINE_FEED)
{
- String reason=takeLengthString();
+ String reason=takeString();
setState(State.HEADER);
return_from_parse=_responseHandler.startResponse(_version, _responseStatus, reason)||return_from_parse;
@@ -826,14 +854,18 @@ public class HttpParser
case HttpTokens.TAB:
{
// header value without name - continuation?
- _string.setLength(0);
- if (_valueString!=null)
+ if (_valueString==null)
+ {
+ _string.setLength(0);
+ _length=0;
+ }
+ else
{
- _string.append(_valueString);
+ setString(_valueString);
_string.append(' ');
+ _length++;
+ _valueString=null;
}
- _length=_string.length();
- _valueString=null;
setState(State.HEADER_VALUE);
break;
}
@@ -929,14 +961,35 @@ public class HttpParser
if (field!=null)
{
- String n=field.getName();
- String v=field.getValue();
+ final String n;
+ final String v;
+
+ if (_strict)
+ {
+ // Have to get the fields exactly from the buffer to match case
+ String fn=field.getName();
+ String fv=field.getValue();
+ n=BufferUtil.toString(buffer,buffer.position()-1,fn.length(),StringUtil.__US_ASCII_CHARSET);
+ if (fv==null)
+ v=null;
+ else
+ {
+ v=BufferUtil.toString(buffer,buffer.position()+fn.length()+1,fv.length(),StringUtil.__ISO_8859_1_CHARSET);
+ field=new HttpField(field.getHeader(),n,v);
+ }
+ }
+ else
+ {
+ n=field.getName();
+ v=field.getValue();
+ }
+
+ _header=field.getHeader();
+ _headerString=n;
if (v==null)
{
// Header only
- _header=field.getHeader();
- _headerString=n;
setState(State.HEADER_VALUE);
_string.setLength(0);
_length=0;
@@ -952,8 +1005,6 @@ public class HttpParser
if (b==HttpTokens.CARRIAGE_RETURN || b==HttpTokens.LINE_FEED)
{
_field=field;
- _header=_field.getHeader();
- _headerString=n;
_valueString=v;
setState(State.HEADER_IN_VALUE);
@@ -966,194 +1017,111 @@ public class HttpParser
buffer.position(pos);
break;
}
+ else
+ {
+ setState(State.HEADER_IN_VALUE);
+ setString(v);
+ buffer.position(pos);
+ break;
+ }
}
}
}
// New header
- setState(State.HEADER_NAME);
+ setState(State.HEADER_IN_NAME);
_string.setLength(0);
_string.append((char)ch);
_length=1;
}
}
}
-
break;
- case HEADER_NAME:
- if (ch<0)
- throw new BadMessage();
- switch(ch)
+ case HEADER_IN_NAME:
+ if (ch==HttpTokens.COLON || ch==HttpTokens.LINE_FEED)
{
- case HttpTokens.LINE_FEED:
- if (_headerString==null)
- {
- _headerString=takeLengthString();
- _header=HttpHeader.CACHE.get(_headerString);
- }
- setState(State.HEADER);
- break;
-
- case HttpTokens.COLON:
- if (_headerString==null)
- {
- _headerString=takeLengthString();
- _header=HttpHeader.CACHE.get(_headerString);
- }
- setState(State.HEADER_VALUE);
- break;
-
- case HttpTokens.SPACE:
- case HttpTokens.TAB:
- break;
-
- default:
+ if (_headerString==null)
{
- _string.append((char)ch);
- _length=_string.length();
- setState(State.HEADER_IN_NAME);
+ _headerString=takeString();
+ _header=HttpHeader.CACHE.get(_headerString);
}
- }
-
- break;
+ _length=-1;
- case HEADER_IN_NAME:
- if (ch<HttpTokens.SPACE)
- {
-
+ setState(ch==HttpTokens.LINE_FEED?State.HEADER:State.HEADER_VALUE);
+ break;
}
- if (ch<0)
- throw new BadMessage("Illegal character");
- switch(ch)
+
+ if (ch>=HttpTokens.SPACE || ch==HttpTokens.TAB)
{
- case HttpTokens.LINE_FEED:
- _headerString=takeString();
- _length=-1;
- _header=HttpHeader.CACHE.get(_headerString);
- setState(State.HEADER);
- break;
+ if (_header!=null)
+ {
+ setString(_header.asString());
+ _header=null;
+ _headerString=null;
+ }
- case HttpTokens.COLON:
- if (_headerString==null)
- {
- _headerString=takeString();
- _header=HttpHeader.CACHE.get(_headerString);
- }
- _length=-1;
- setState(State.HEADER_VALUE);
- break;
- case HttpTokens.SPACE:
- case HttpTokens.TAB:
- if (_header!=null)
- {
- _string.setLength(0);
- _string.append(_header.asString());
- _length=_string.length();
- _header=null;
- _headerString=null;
- }
- setState(State.HEADER_NAME);
- _string.append((char)ch);
- break;
- default:
- if (_header!=null)
- {
- _string.setLength(0);
- _string.append(_header.asString());
- _length=_string.length();
- _header=null;
- _headerString=null;
- }
- _string.append((char)ch);
- _length++;
+ _string.append((char)ch);
+ if (ch>HttpTokens.SPACE)
+ _length=_string.length();
+ break;
}
- break;
+
+ throw new BadMessage("Illegal character");
case HEADER_VALUE:
- switch(ch)
+ if (ch>HttpTokens.SPACE || ch<0)
{
- case HttpTokens.LINE_FEED:
- if (_length > 0)
- {
- if (_valueString!=null)
- {
- // multi line value!
- _value=null;
- _valueString+=" "+takeLengthString();
- }
- else if (HttpHeaderValue.hasKnownValues(_header))
- {
- _valueString=takeLengthString();
- _value=HttpHeaderValue.CACHE.get(_valueString);
- }
- else
- {
- _value=null;
- _valueString=takeLengthString();
- }
- }
- setState(State.HEADER);
- break;
- case HttpTokens.SPACE:
- case HttpTokens.TAB:
- break;
- default:
+ _string.append((char)(0xff&ch));
+ _length=_string.length();
+ setState(State.HEADER_IN_VALUE);
+ break;
+ }
+
+ if (ch==HttpTokens.SPACE || ch==HttpTokens.TAB)
+ break;
+
+ if (ch==HttpTokens.LINE_FEED)
+ {
+ if (_length > 0)
{
- _string.append((char)(0xff&ch));
- _length=_string.length();
- setState(State.HEADER_IN_VALUE);
+ _value=null;
+ _valueString=(_valueString==null)?takeString():(_valueString+" "+takeString());
}
+ setState(State.HEADER);
+ break;
}
- break;
+
+ throw new BadMessage("Illegal character");
case HEADER_IN_VALUE:
- switch(ch)
+ if (ch>=HttpTokens.SPACE || ch<0)
{
- case HttpTokens.LINE_FEED:
- if (_length > 0)
- {
- if (HttpHeaderValue.hasKnownValues(_header))
- {
- _valueString=takeString();
- _value=HttpHeaderValue.CACHE.get(_valueString);
- }
- else
- {
- _value=null;
- _valueString=takeString();
- }
- _length=-1;
- }
- setState(State.HEADER);
- break;
- case HttpTokens.SPACE:
- case HttpTokens.TAB:
- if (_valueString!=null)
- {
- _string.setLength(0);
- _string.append(_valueString);
- _length=_valueString.length();
- _valueString=null;
- _field=null;
- }
- _string.append((char)ch);
- setState(State.HEADER_VALUE);
- break;
- default:
- if (_valueString!=null)
- {
- _string.setLength(0);
- _string.append(_valueString);
- _length=_valueString.length();
- _valueString=null;
- _field=null;
- }
- _string.append((char)(0xff&ch));
- _length++;
+ if (_valueString!=null)
+ {
+ setString(_valueString);
+ _valueString=null;
+ _field=null;
+ }
+ _string.append((char)(0xff&ch));
+ if (ch>HttpTokens.SPACE || ch<0)
+ _length=_string.length();
+ break;
}
- break;
-
+
+ if (ch==HttpTokens.LINE_FEED)
+ {
+ if (_length > 0)
+ {
+ _value=null;
+ _valueString=takeString();
+ _length=-1;
+ }
+ setState(State.HEADER);
+ break;
+ }
+ throw new BadMessage("Illegal character");
+
default:
throw new IllegalStateException(_state.toString());
@@ -1377,7 +1345,7 @@ public class HttpParser
{
BufferUtil.clear(buffer);
- LOG.warn("badMessage: "+e._code+(e._message!=null?" "+e._message:"")+" for "+_handler);
+ LOG.warn("BadMessage: "+e._code+(e._message!=null?" "+e._message:"")+" for "+_handler);
if (DEBUG)
LOG.debug(e);
setState(State.CLOSED);
@@ -1388,7 +1356,7 @@ public class HttpParser
{
BufferUtil.clear(buffer);
- LOG.warn("badMessage: "+e.toString()+" for "+_handler);
+ LOG.warn("Parsing Exception: "+e.toString()+" for "+_handler);
if (DEBUG)
LOG.debug(e);
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 51b0de6037..654474d726 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
@@ -379,6 +379,50 @@ public class HttpParserTest
HttpParser parser= new HttpParser(handler);
parseAll(parser,buffer);
assertThat(_bad,Matchers.notNullValue());
+ }
+
+ @Test
+ public void testNonStrict() throws Exception
+ {
+ ByteBuffer buffer= BufferUtil.toBuffer(
+ "get / http/1.0\015\012" +
+ "HOST: localhost\015\012" +
+ "cOnNeCtIoN: ClOsE\015\012"+
+ "\015\012");
+ HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
+ HttpParser parser= new HttpParser(handler,-1,false);
+ parseAll(parser,buffer);
+
+ assertEquals("GET", _methodOrVersion);
+ assertEquals("/", _uriOrStatus);
+ assertEquals("HTTP/1.0", _versionOrReason);
+ assertEquals("Host", _hdr[0]);
+ assertEquals("localhost", _val[0]);
+ assertEquals("Connection", _hdr[1]);
+ assertEquals("close", _val[1]);
+ assertEquals(1, _h);
+ }
+
+ @Test
+ public void testStrict() throws Exception
+ {
+ ByteBuffer buffer= BufferUtil.toBuffer(
+ "gEt / http/1.0\015\012" +
+ "HOST: localhost\015\012" +
+ "cOnNeCtIoN: ClOsE\015\012"+
+ "\015\012");
+ HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
+ HttpParser parser= new HttpParser(handler,-1,true);
+ parseAll(parser,buffer);
+
+ assertEquals("gEt", _methodOrVersion);
+ assertEquals("/", _uriOrStatus);
+ assertEquals("HTTP/1.0", _versionOrReason);
+ assertEquals("HOST", _hdr[0]);
+ assertEquals("localhost", _val[0]);
+ assertEquals("cOnNeCtIoN", _hdr[1]);
+ assertEquals("ClOsE", _val[1]);
+ assertEquals(1, _h);
}
@Test
@@ -494,7 +538,6 @@ public class HttpParserTest
+ "\015\012"
+ "0123456789\015\012");
-
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
HttpParser parser= new HttpParser(handler);
parser.parseNext(buffer);
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 ae280489a1..7d542303bc 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
@@ -23,6 +23,7 @@ import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
+
import javax.servlet.DispatcherType;
import javax.servlet.RequestDispatcher;
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java
index 5a5f5945e1..d98e65452b 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java
@@ -48,6 +48,7 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log;
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 29db2113ad..58ede8b0b1 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
@@ -53,12 +53,14 @@ public class StringUtil
public final static Charset __UTF8_CHARSET;
public final static Charset __ISO_8859_1_CHARSET;
public final static Charset __UTF16_CHARSET;
+ public final static Charset __US_ASCII_CHARSET;
static
{
__UTF8_CHARSET=Charset.forName(__UTF8);
__ISO_8859_1_CHARSET=Charset.forName(__ISO_8859_1);
__UTF16_CHARSET=Charset.forName(__UTF16);
+ __US_ASCII_CHARSET=Charset.forName("US-ASCII");
CHARSETS.put("UTF-8",__UTF8);
CHARSETS.put("UTF8",__UTF8);

Back to the top