Added support to parse and ignore HTTP/1.1 chunking trailers.
Handle an early EOF within the trailer gracefully rather than with earlyEOF.
This commit is contained in:
Greg Wilkins 2017-01-10 16:19:40 +11:00
parent 058e4658e4
commit d2b8980243
2 changed files with 117 additions and 10 deletions

View File

@ -28,8 +28,6 @@ import org.eclipse.jetty.http.HttpTokens.EndOfContent;
import org.eclipse.jetty.util.ArrayTernaryTrie;
import org.eclipse.jetty.util.ArrayTrie;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.HostPort;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.Trie;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.Utf8StringBuilder;
@ -133,6 +131,7 @@ public class HttpParser
CHUNK_SIZE,
CHUNK_PARAMS,
CHUNK,
CHUNK_TRAILER,
CHUNK_END,
END,
CLOSE, // The associated stream/endpoint should be closed
@ -682,7 +681,7 @@ public class HttpParser
if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes)
{
LOG.warn("URI is too large >"+_maxHeaderBytes);
throw new BadMessageException(HttpStatus.REQUEST_URI_TOO_LONG_414);
throw new BadMessageException(HttpStatus.URI_TOO_LONG_414);
}
_uri.append(array,p-1,len+1);
buffer.position(i-buffer.arrayOffset());
@ -1383,14 +1382,16 @@ public class HttpParser
break;
case EOF_CONTENT:
case CHUNK_END:
setState(State.CLOSED);
return _handler.messageComplete();
case CONTENT:
case CHUNKED_CONTENT:
case CHUNK_SIZE:
case CHUNK_PARAMS:
case CHUNK:
case CONTENT:
case CHUNKED_CONTENT:
case CHUNK_SIZE:
case CHUNK_PARAMS:
case CHUNK:
case CHUNK_TRAILER:
setState(State.CLOSED);
_handler.earlyEOF();
break;
@ -1592,7 +1593,6 @@ public class HttpParser
case CHUNK_END:
{
// TODO handle chunk trailer
ch=next(buffer);
if (ch==0)
break;
@ -1601,7 +1601,19 @@ public class HttpParser
setState(State.END);
return _handler.messageComplete();
}
throw new IllegalCharacterException(_state,ch,buffer);
setState(State.CHUNK_TRAILER);
break;
}
case CHUNK_TRAILER:
{
// TODO handle chunk trailer values
ch=next(buffer);
if (ch==0)
break;
if (ch == HttpTokens.LINE_FEED)
setState(State.CHUNK_END);
break;
}
case CLOSED:

View File

@ -779,6 +779,101 @@ public class HttpParserTest
Assert.assertTrue(_messageCompleted);
}
@Test
public void testChunkParseTrailer() throws Exception
{
ByteBuffer buffer = BufferUtil.toBuffer(
"GET /chunk HTTP/1.0\r\n"
+ "Header1: value1\r\n"
+ "Transfer-Encoding: chunked\r\n"
+ "\r\n"
+ "a;\r\n"
+ "0123456789\r\n"
+ "1a\r\n"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n"
+ "0\r\n"
+ "Trailer: value\r\n"
+ "\r\n");
HttpParser.RequestHandler handler = new Handler();
HttpParser parser = new HttpParser(handler);
parseAll(parser, buffer);
Assert.assertEquals("GET", _methodOrVersion);
Assert.assertEquals("/chunk", _uriOrStatus);
Assert.assertEquals("HTTP/1.0", _versionOrReason);
Assert.assertEquals(1, _headers);
Assert.assertEquals("Header1", _hdr[0]);
Assert.assertEquals("value1", _val[0]);
Assert.assertEquals("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", _content);
Assert.assertTrue(_headerCompleted);
Assert.assertTrue(_messageCompleted);
}
@Test
public void testChunkParseBadTrailer() throws Exception
{
ByteBuffer buffer = BufferUtil.toBuffer(
"GET /chunk HTTP/1.0\r\n"
+ "Header1: value1\r\n"
+ "Transfer-Encoding: chunked\r\n"
+ "\r\n"
+ "a;\r\n"
+ "0123456789\r\n"
+ "1a\r\n"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n"
+ "0\r\n"
+ "Trailer: value");
HttpParser.RequestHandler handler = new Handler();
HttpParser parser = new HttpParser(handler);
parseAll(parser, buffer);
parser.atEOF();
parser.parseNext(BufferUtil.EMPTY_BUFFER);
Assert.assertEquals("GET", _methodOrVersion);
Assert.assertEquals("/chunk", _uriOrStatus);
Assert.assertEquals("HTTP/1.0", _versionOrReason);
Assert.assertEquals(1, _headers);
Assert.assertEquals("Header1", _hdr[0]);
Assert.assertEquals("value1", _val[0]);
Assert.assertEquals("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", _content);
Assert.assertTrue(_headerCompleted);
Assert.assertTrue(_early);
}
@Test
public void testChunkParseNoTrailer() throws Exception
{
ByteBuffer buffer = BufferUtil.toBuffer(
"GET /chunk HTTP/1.0\r\n"
+ "Header1: value1\r\n"
+ "Transfer-Encoding: chunked\r\n"
+ "\r\n"
+ "a;\r\n"
+ "0123456789\r\n"
+ "1a\r\n"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n"
+ "0\r\n");
HttpParser.RequestHandler handler = new Handler();
HttpParser parser = new HttpParser(handler);
parseAll(parser, buffer);
parser.atEOF();
parser.parseNext(BufferUtil.EMPTY_BUFFER);
Assert.assertEquals("GET", _methodOrVersion);
Assert.assertEquals("/chunk", _uriOrStatus);
Assert.assertEquals("HTTP/1.0", _versionOrReason);
Assert.assertEquals(1, _headers);
Assert.assertEquals("Header1", _hdr[0]);
Assert.assertEquals("value1", _val[0]);
Assert.assertEquals("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", _content);
Assert.assertTrue(_headerCompleted);
Assert.assertTrue(_messageCompleted);
}
@Test
public void testStartEOF() throws Exception
{