diff options
Diffstat (limited to 'jetty-http/src')
7 files changed, 505 insertions, 361 deletions
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessage.java b/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessage.java new file mode 100644 index 0000000000..c21beff3ce --- /dev/null +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessage.java @@ -0,0 +1,67 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.http; + +/* ------------------------------------------------------------------------------- */ +class BadMessage extends Error +{ + final int _code; + final String _reason; + + BadMessage() + { + this(400,null); + } + + BadMessage(int code) + { + this(code,null); + } + + BadMessage(String reason) + { + this(400,reason); + } + + BadMessage(int code,String reason) + { + _code=code; + _reason=reason; + } + + BadMessage(int code,String reason,Throwable cause) + { + super(cause); + _code=code; + _reason=reason; + } + + public int getCode() + { + return _code; + } + + public String getReason() + { + return _reason; + } + + +}
\ No newline at end of file diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java new file mode 100644 index 0000000000..11c233cd4f --- /dev/null +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java @@ -0,0 +1,102 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.http; + +import org.eclipse.jetty.util.StringUtil; + + + +/* ------------------------------------------------------------ */ +/** + */ +public class HostPortHttpField extends HttpField +{ + public final String _host; + public final int _port; + + public HostPortHttpField(HttpHeader header, String name, String authority) + { + super(header,name,authority); + + try + { + if (authority.charAt(0)=='[') + { + // ipv6reference + int close=authority.lastIndexOf(']'); + if (close<0) + throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad ipv6"); + _host=authority.substring(1,close); + + if (authority.length()>close+1) + { + if (authority.charAt(close+1)!=':') + throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad ipv6 port"); + _port=StringUtil.toInt(authority,close+2); + } + else + _port=0; + } + else + { + // ipv4address or hostname + int c = authority.lastIndexOf(':'); + if (c>=0) + { + _host=authority.substring(0,c); + _port=StringUtil.toInt(authority,c+1); + } + else + { + _host=authority; + _port=0; + } + } + } + catch (BadMessage bm) + { + throw bm; + } + catch(Exception e) + { + throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad HostPort",e); + } + } + + /* ------------------------------------------------------------ */ + /** Get the host. + * @return the host + */ + public String getHost() + { + return _host; + } + + /* ------------------------------------------------------------ */ + /** Get the port. + * @return the port + */ + public int getPort() + { + return _port; + } + + +} 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 f270482f3a..7cece45c30 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 @@ -18,6 +18,8 @@ package org.eclipse.jetty.http; +import org.eclipse.jetty.util.QuotedStringTokenizer; + /* ------------------------------------------------------------ */ /** A HTTP Field @@ -65,6 +67,17 @@ public class HttpField return _value; } + public String[] getValues() + { + QuotedStringTokenizer tok = new QuotedStringTokenizer(_value, ",", false, false); + tok.setSingle(false); + String[] v = new String[tok.countTokens()]; + int t=0; + while(tok.hasMoreTokens()) + v[t++]=tok.nextToken(); + return v; + } + @Override public String toString() { 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 ac50f342de..e0a7e9552c 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 @@ -33,7 +33,7 @@ import org.eclipse.jetty.util.log.Logger; /* ------------------------------------------------------------ */ -/** A Parser for 1.0 and 1.1 +/** A Parser for 1.0 and 1.1 as defined by RFC7230 * <p> * The is parser parses HTTP client and server messages from buffers * passed in the {@link #parseNext(ByteBuffer)} method. The parsed @@ -71,6 +71,8 @@ import org.eclipse.jetty.util.log.Logger; * fields. Otherwise a fast case insensitive string lookup is used that may alter the * case of the method and/or headers * </p> + * <p> + * @see http://tools.ietf.org/html/rfc7230 */ public class HttpParser { @@ -330,36 +332,6 @@ public class HttpParser } /* ------------------------------------------------------------------------------- */ - private static class BadMessage extends Error - { - private static final long serialVersionUID = 1L; - private final int _code; - private final String _message; - - BadMessage() - { - this(400,null); - } - - BadMessage(int code) - { - this(code,null); - } - - BadMessage(String message) - { - this(400,message); - } - - BadMessage(int code,String message) - { - _code=code; - _message=message; - } - - } - - /* ------------------------------------------------------------------------------- */ private byte next(ByteBuffer buffer) { byte ch = buffer.get(); @@ -781,124 +753,105 @@ public class HttpParser return handle; } - private boolean handleKnownHeaders(ByteBuffer buffer) + private void parsedHeader() { - boolean add_to_connection_trie=false; - switch (_header) + // handler last header if any. Delayed to here just in case there was a continuation line (above) + if (_headerString!=null || _valueString!=null) { - case CONTENT_LENGTH: - if (_endOfContent != EndOfContent.CHUNKED_CONTENT) - { - try - { - _contentLength=Long.parseLong(_valueString); - } - catch(NumberFormatException e) - { - LOG.ignore(e); - throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad Content-Length"); - } - if (_contentLength <= 0) - _endOfContent=EndOfContent.NO_CONTENT; - else - _endOfContent=EndOfContent.CONTENT_LENGTH; - } - break; - - case TRANSFER_ENCODING: - if (_value==HttpHeaderValue.CHUNKED) - _endOfContent=EndOfContent.CHUNKED_CONTENT; - else - { - if (_valueString.endsWith(HttpHeaderValue.CHUNKED.toString())) - _endOfContent=EndOfContent.CHUNKED_CONTENT; - else if (_valueString.contains(HttpHeaderValue.CHUNKED.toString())) - { - throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad chunking"); - } - } - break; - - case HOST: - add_to_connection_trie=_connectionFields!=null && _field==null; - _host=true; - String host=_valueString; - int port=0; - if (host==null || host.length()==0) - { - throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad Host header"); - } - - int len=host.length(); - loop: for (int i = len; i-- > 0;) + // Handle known headers + if (_header!=null) + { + boolean add_to_connection_trie=false; + switch (_header) { - char c2 = (char)(0xff & host.charAt(i)); - switch (c2) - { - case ']': - break loop; - - case ':': + case CONTENT_LENGTH: + if (_endOfContent != EndOfContent.CHUNKED_CONTENT) + { try { - len=i; - port = StringUtil.toInt(host,i+1); + _contentLength=Long.parseLong(_valueString); } - catch (NumberFormatException e) + catch(NumberFormatException e) { - if (DEBUG) - LOG.debug(e); - throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad Host header"); + LOG.ignore(e); + throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad Content-Length"); } - break loop; - } - } - if (host.charAt(0)=='[') - { - if (host.charAt(len-1)!=']') - { - throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad IPv6 Host header"); - } - host = host.substring(1,len-1); + if (_contentLength <= 0) + _endOfContent=EndOfContent.NO_CONTENT; + else + _endOfContent=EndOfContent.CONTENT_LENGTH; + } + break; + + case TRANSFER_ENCODING: + if (_value==HttpHeaderValue.CHUNKED) + _endOfContent=EndOfContent.CHUNKED_CONTENT; + else + { + if (_valueString.endsWith(HttpHeaderValue.CHUNKED.toString())) + _endOfContent=EndOfContent.CHUNKED_CONTENT; + else if (_valueString.contains(HttpHeaderValue.CHUNKED.toString())) + { + throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad chunking"); + } + } + break; + + case HOST: + _host=true; + HostPortHttpField hpfield; + if (_field!=null) + { + hpfield = (HostPortHttpField)_field; + } + else + { + _field=hpfield=new HostPortHttpField(_header,_strict?_headerString:_header.asString(),_valueString); + add_to_connection_trie=_connectionFields!=null; + } + + if (_requestHandler!=null) + _requestHandler.parsedHostHeader(hpfield.getHost(),hpfield.getPort()); + + break; + + case CONNECTION: + // Don't cache if not persistent + if (_valueString!=null && _valueString.contains("close")) + { + _closed=true; + _connectionFields=null; + } + break; + + case AUTHORIZATION: + case ACCEPT: + case ACCEPT_CHARSET: + case ACCEPT_ENCODING: + case ACCEPT_LANGUAGE: + case COOKIE: + case CACHE_CONTROL: + case USER_AGENT: + add_to_connection_trie=_connectionFields!=null && _field==null; + break; + + default: break; } - else if (len!=host.length()) - host = host.substring(0,len); - - if (_requestHandler!=null) - _requestHandler.parsedHostHeader(host,port); - - break; - - case CONNECTION: - // Don't cache if not persistent - if (_valueString!=null && _valueString.contains("close")) + + if (add_to_connection_trie && !_connectionFields.isFull() && _header!=null && _valueString!=null) { - _closed=true; - _connectionFields=null; + if (_field==null) + _field=new HttpField(_header,_strict?_headerString:_header.asString(),_valueString); + _connectionFields.put(_field); } - break; - - case AUTHORIZATION: - case ACCEPT: - case ACCEPT_CHARSET: - case ACCEPT_ENCODING: - case ACCEPT_LANGUAGE: - case COOKIE: - case CACHE_CONTROL: - case USER_AGENT: - add_to_connection_trie=_connectionFields!=null && _field==null; - break; - - default: break; - } - - if (add_to_connection_trie && !_connectionFields.isFull() && _header!=null && _valueString!=null) - { - _field=new HttpField(_header,_valueString); - _connectionFields.put(_field); + } + _handler.parsedHeader(_field!=null?_field:new HttpField(_header,_headerString,_valueString)); } - return false; + _headerString=_valueString=null; + _header=null; + _value=null; + _field=null; } @@ -932,194 +885,160 @@ public class HttpParser case HttpTokens.COLON: case HttpTokens.SPACE: case HttpTokens.TAB: + throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad Continuation"); + + case HttpTokens.LINE_FEED: { - // header value without name - continuation? - if (_valueString==null) + _contentPosition=0; + + // End of headers! + + // Was there a required host header? + if (!_host && _version!=HttpVersion.HTTP_1_0 && _requestHandler!=null) { - _string.setLength(0); - _length=0; + throw new BadMessage(HttpStatus.BAD_REQUEST_400,"No Host"); } - else + + // is it a response that cannot have a body? + if (_responseHandler !=null && // response + (_responseStatus == 304 || // not-modified response + _responseStatus == 204 || // no-content response + _responseStatus < 200)) // 1xx response + _endOfContent=EndOfContent.NO_CONTENT; // ignore any other headers set + + // else if we don't know framing + else if (_endOfContent == EndOfContent.UNKNOWN_CONTENT) { - setString(_valueString); - _string.append(' '); - _length++; - _valueString=null; + if (_responseStatus == 0 // request + || _responseStatus == 304 // not-modified response + || _responseStatus == 204 // no-content response + || _responseStatus < 200) // 1xx response + _endOfContent=EndOfContent.NO_CONTENT; + else + _endOfContent=EndOfContent.EOF_CONTENT; + } + + // How is the message ended? + switch (_endOfContent) + { + case EOF_CONTENT: + setState(State.EOF_CONTENT); + handle=_handler.headerComplete()||handle; + break; + + case CHUNKED_CONTENT: + setState(State.CHUNKED_CONTENT); + handle=_handler.headerComplete()||handle; + break; + + case NO_CONTENT: + handle=_handler.headerComplete()||handle; + setState(State.END); + handle=_handler.messageComplete()||handle; + break; + + default: + setState(State.CONTENT); + handle=_handler.headerComplete()||handle; + break; } - setState(State.HEADER_VALUE); break; } default: { - // handler last header if any. Delayed to here just in case there was a continuation line (above) - if (_headerString!=null || _valueString!=null) - { - // Handle known headers - if (_header!=null && handleKnownHeaders(buffer)) - { - _headerString=_valueString=null; - _header=null; - _value=null; - _field=null; - return true; - } - handle=_handler.parsedHeader(_field!=null?_field:new HttpField(_header,_headerString,_valueString))||handle; - } - _headerString=_valueString=null; - _header=null; - _value=null; - _field=null; - // now handle the ch - if (ch == HttpTokens.LINE_FEED) - { - _contentPosition=0; + if (ch<=HttpTokens.SPACE) + throw new BadMessage(); - // End of headers! + if (buffer.hasRemaining()) + { + // Try a look ahead for the known header name and value. + HttpField field=_connectionFields==null?null:_connectionFields.getBest(buffer,-1,buffer.remaining()); + if (field==null) + field=CACHE.getBest(buffer,-1,buffer.remaining()); - // Was there a required host header? - if (!_host && _version!=HttpVersion.HTTP_1_0 && _requestHandler!=null) + if (field!=null) { - throw new BadMessage(HttpStatus.BAD_REQUEST_400,"No Host"); - } + final String n; + final String v; - // is it a response that cannot have a body? - if (_responseHandler !=null && // response - (_responseStatus == 304 || // not-modified response - _responseStatus == 204 || // no-content response - _responseStatus < 200)) // 1xx response - _endOfContent=EndOfContent.NO_CONTENT; // ignore any other headers set - - // else if we don't know framing - else if (_endOfContent == EndOfContent.UNKNOWN_CONTENT) - { - if (_responseStatus == 0 // request - || _responseStatus == 304 // not-modified response - || _responseStatus == 204 // no-content response - || _responseStatus < 200) // 1xx response - _endOfContent=EndOfContent.NO_CONTENT; + 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(),StandardCharsets.US_ASCII); + if (fv==null) + v=null; + else + { + v=BufferUtil.toString(buffer,buffer.position()+fn.length()+1,fv.length(),StandardCharsets.ISO_8859_1); + field=new HttpField(field.getHeader(),n,v); + } + } else - _endOfContent=EndOfContent.EOF_CONTENT; - } - - // How is the message ended? - switch (_endOfContent) - { - case EOF_CONTENT: - setState(State.EOF_CONTENT); - handle=_handler.headerComplete()||handle; - break; - - case CHUNKED_CONTENT: - setState(State.CHUNKED_CONTENT); - handle=_handler.headerComplete()||handle; - break; + { + n=field.getName(); + v=field.getValue(); + } - case NO_CONTENT: - handle=_handler.headerComplete()||handle; - setState(State.END); - handle=_handler.messageComplete()||handle; - break; + _header=field.getHeader(); + _headerString=n; - default: - setState(State.CONTENT); - handle=_handler.headerComplete()||handle; + if (v==null) + { + // Header only + setState(State.HEADER_VALUE); + _string.setLength(0); + _length=0; + buffer.position(buffer.position()+n.length()+1); break; - } - } - else if (ch<=HttpTokens.SPACE) - throw new BadMessage(); - else - { - if (buffer.hasRemaining()) - { - // Try a look ahead for the known header name and value. - HttpField field=_connectionFields==null?null:_connectionFields.getBest(buffer,-1,buffer.remaining()); - if (field==null) - field=CACHE.getBest(buffer,-1,buffer.remaining()); - - if (field!=null) + } + else { - final String n; - final String v; + // Header and value + int pos=buffer.position()+n.length()+v.length()+1; + byte b=buffer.get(pos); - 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(),StandardCharsets.US_ASCII); - if (fv==null) - v=null; - else + if (b==HttpTokens.CARRIAGE_RETURN || b==HttpTokens.LINE_FEED) + { + _field=field; + _valueString=v; + setState(State.HEADER_IN_VALUE); + + if (b==HttpTokens.CARRIAGE_RETURN) { - v=BufferUtil.toString(buffer,buffer.position()+fn.length()+1,fv.length(),StandardCharsets.ISO_8859_1); - field=new HttpField(field.getHeader(),n,v); + _cr=true; + buffer.position(pos+1); } - } - else - { - n=field.getName(); - v=field.getValue(); - } - - _header=field.getHeader(); - _headerString=n; - - if (v==null) - { - // Header only - setState(State.HEADER_VALUE); - _string.setLength(0); - _length=0; - buffer.position(buffer.position()+n.length()+1); + else + buffer.position(pos); break; } else { - // Header and value - int pos=buffer.position()+n.length()+v.length()+1; - byte b=buffer.get(pos); - - if (b==HttpTokens.CARRIAGE_RETURN || b==HttpTokens.LINE_FEED) - { - _field=field; - _valueString=v; - setState(State.HEADER_IN_VALUE); - - if (b==HttpTokens.CARRIAGE_RETURN) - { - _cr=true; - buffer.position(pos+1); - } - else - buffer.position(pos); - break; - } - else - { - setState(State.HEADER_IN_VALUE); - setString(v); - buffer.position(pos); - break; - } + setState(State.HEADER_IN_VALUE); + setString(v); + buffer.position(pos); + break; } } } - - // New header - setState(State.HEADER_IN_NAME); - _string.setLength(0); - _string.append((char)ch); - _length=1; } + + // New header + setState(State.HEADER_IN_NAME); + _string.setLength(0); + _string.append((char)ch); + _length=1; + } } break; case HEADER_IN_NAME: - if (ch==HttpTokens.COLON || ch==HttpTokens.LINE_FEED) + if (ch==HttpTokens.COLON) { if (_headerString==null) { @@ -1128,11 +1047,11 @@ public class HttpParser } _length=-1; - setState(ch==HttpTokens.LINE_FEED?State.HEADER:State.HEADER_VALUE); + setState(State.HEADER_VALUE); break; } - if (ch>=HttpTokens.SPACE || ch==HttpTokens.TAB) + if (ch>HttpTokens.SPACE) { if (_header!=null) { @@ -1160,19 +1079,8 @@ public class HttpParser if (ch==HttpTokens.SPACE || ch==HttpTokens.TAB) break; - - if (ch==HttpTokens.LINE_FEED) - { - if (_length > 0) - { - _value=null; - _valueString=(_valueString==null)?takeString():(_valueString+" "+takeString()); - } - setState(State.HEADER); - break; - } - throw new BadMessage("Illegal character"); + throw new BadMessage(); case HEADER_IN_VALUE: if (ch>=HttpTokens.SPACE || ch<0 || ch==HttpTokens.TAB) @@ -1197,6 +1105,7 @@ public class HttpParser _valueString=takeString(); _length=-1; } + parsedHeader(); setState(State.HEADER); break; } @@ -1332,11 +1241,11 @@ public class HttpParser { BufferUtil.clear(buffer); - LOG.warn("badMessage: "+e._code+(e._message!=null?" "+e._message:"")+" for "+_handler); + LOG.warn("badMessage: "+e._code+(e.getReason()!=null?" "+e.getReason():"")+" for "+_handler); if (DEBUG) LOG.debug(e); setState(State.CLOSED); - _handler.badMessage(e._code, e._message); + _handler.badMessage(e.getCode(), e.getReason()); return false; } catch(Exception e) @@ -1609,10 +1518,9 @@ public class HttpParser /** * This is the method called by parser when a HTTP Header name and value is found * @param field The field parsed - * @return True if the parser should return to its caller */ - public boolean parsedHeader(HttpField field); - + public void parsedHeader(HttpField field); + /* ------------------------------------------------------------ */ /** Called to signal that an EOF was received unexpectedly * during the parsing of a HTTP message @@ -1648,14 +1556,14 @@ public class HttpParser * @param version * @return true if handling parsing should return. */ - public abstract boolean startRequest(String method, HttpURI uri, HttpVersion version); + public boolean startRequest(String method, HttpURI 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 * called after the {@link HttpHandler#parsedHeader(HttpField)} methods and before * HttpHandler#headerComplete(); */ - public abstract boolean parsedHostHeader(String host,int port); + public void parsedHostHeader(String host,int port); } public interface ResponseHandler<T> extends HttpHandler<T> @@ -1663,7 +1571,7 @@ public class HttpParser /** * This is the method called by parser when the HTTP request line is parsed */ - public abstract boolean startResponse(HttpVersion version, int status, String reason); + public boolean startResponse(HttpVersion version, int status, String reason); } public Trie<HttpField> getFieldCache() 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 0385ffcb7e..a7f081e76a 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 @@ -132,10 +132,9 @@ public class HttpTester } } @Override - public boolean parsedHeader(HttpField field) + public void parsedHeader(HttpField field) { put(field.getName(),field.getValue()); - return false; } @Override @@ -302,9 +301,8 @@ public class HttpTester } @Override - public boolean parsedHostHeader(String host,int port) + public void parsedHostHeader(String host,int port) { - return false; } } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java index 2925f3e41f..5fc8436bfb 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java @@ -247,9 +247,8 @@ public class HttpGeneratorServerHTTPTest } @Override - public boolean parsedHeader(HttpField field) + public void parsedHeader(HttpField field) { - return false; } @Override 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 12b2b38908..8b25973d8c 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 @@ -181,6 +181,73 @@ public class HttpParserTest assertEquals("close", _val[1]); assertEquals(1, _headers); } + + @Test + public void test7230NoContinuations() throws Exception + { + ByteBuffer buffer= BufferUtil.toBuffer( + "GET / HTTP/1.0\015\012" + + "Host: localhost\015\012" + + "Name: value\015\012" + + " extra\015\012" + + "\015\012"); + + HttpParser.RequestHandler<ByteBuffer> handler = new Handler(); + HttpParser parser= new HttpParser(handler); + parseAll(parser,buffer); + + Assert.assertThat(_bad,Matchers.notNullValue()); + Assert.assertThat(_bad,Matchers.containsString("Bad Continuation")); + } + + + @Test + public void test7230NoWhiteSpaceInName() throws Exception + { + ByteBuffer buffer= BufferUtil.toBuffer( + "GET / HTTP/1.0\015\012" + + "Host: localhost\015\012" + + " Name: value\015\012" + + "\015\012"); + + HttpParser.RequestHandler<ByteBuffer> handler = new Handler(); + HttpParser parser= new HttpParser(handler); + parseAll(parser,buffer); + + Assert.assertThat(_bad,Matchers.notNullValue()); + Assert.assertThat(_bad,Matchers.containsString("Bad")); + + init(); + buffer= BufferUtil.toBuffer( + "GET / HTTP/1.0\015\012" + + "Host: localhost\015\012" + + "N ame: value\015\012" + + "\015\012"); + + handler = new Handler(); + parser= new HttpParser(handler); + parseAll(parser,buffer); + + Assert.assertThat(_bad,Matchers.containsString("Illegal character")); + + + init(); + buffer= BufferUtil.toBuffer( + "GET / HTTP/1.0\015\012" + + "Host: localhost\015\012" + + "Name : value\015\012" + + "\015\012"); + + handler = new Handler(); + parser= new HttpParser(handler); + parseAll(parser,buffer); + + Assert.assertThat(_bad,Matchers.containsString("Illegal character")); + + } + + + @Test public void testHeaderParseDirect() throws Exception @@ -189,13 +256,11 @@ public class HttpParserTest "GET / HTTP/1.0\015\012" + "Host: localhost\015\012" + "Header1: value1\015\012" + - "Header 2 : value 2a \015\012" + - " value 2b \015\012" + - "Header3: \015\012" + - "Header4 \015\012" + - " value4\015\012" + - "Server5 : notServer\015\012" + - "Host Header: notHost\015\012" + + "Header2: value 2a \015\012" + + "Header3: 3\015\012" + + "Header4:value4\015\012" + + "Server5: notServer\015\012" + + "HostHeader: notHost\015\012" + "Connection: close\015\012" + "Accept-Encoding: gzip, deflated\015\012" + "Accept: unknown\015\012" + @@ -216,15 +281,15 @@ public class HttpParserTest assertEquals("localhost", _val[0]); assertEquals("Header1", _hdr[1]); assertEquals("value1", _val[1]); - assertEquals("Header 2", _hdr[2]); - assertEquals("value 2a value 2b", _val[2]); + assertEquals("Header2", _hdr[2]); + assertEquals("value 2a", _val[2]); assertEquals("Header3", _hdr[3]); - assertEquals(null, _val[3]); + assertEquals("3", _val[3]); assertEquals("Header4", _hdr[4]); assertEquals("value4", _val[4]); assertEquals("Server5", _hdr[5]); assertEquals("notServer", _val[5]); - assertEquals("Host Header", _hdr[6]); + assertEquals("HostHeader", _hdr[6]); assertEquals("notHost", _val[6]); assertEquals("Connection", _hdr[7]); assertEquals("close", _val[7]); @@ -242,13 +307,11 @@ public class HttpParserTest "GET / HTTP/1.0\015\012" + "Host: localhost\015\012" + "Header1: value1\015\012" + - "Header 2 : value 2a \015\012" + - " value 2b \015\012" + - "Header3: \015\012" + - "Header4 \015\012" + - " value4\015\012" + - "Server5 : notServer\015\012" + - "Host Header: notHost\015\012" + + "Header2: value 2a \015\012" + + "Header3: 3\015\012" + + "Header4:value4\015\012" + + "Server5: notServer\015\012" + + "HostHeader: notHost\015\012" + "Connection: close\015\012" + "Accept-Encoding: gzip, deflated\015\012" + "Accept: unknown\015\012" + @@ -264,15 +327,15 @@ public class HttpParserTest assertEquals("localhost", _val[0]); assertEquals("Header1", _hdr[1]); assertEquals("value1", _val[1]); - assertEquals("Header 2", _hdr[2]); - assertEquals("value 2a value 2b", _val[2]); + assertEquals("Header2", _hdr[2]); + assertEquals("value 2a", _val[2]); assertEquals("Header3", _hdr[3]); - assertEquals(null, _val[3]); + assertEquals("3", _val[3]); assertEquals("Header4", _hdr[4]); assertEquals("value4", _val[4]); assertEquals("Server5", _hdr[5]); assertEquals("notServer", _val[5]); - assertEquals("Host Header", _hdr[6]); + assertEquals("HostHeader", _hdr[6]); assertEquals("notHost", _val[6]); assertEquals("Connection", _hdr[7]); assertEquals("close", _val[7]); @@ -292,13 +355,11 @@ public class HttpParserTest "GET / HTTP/1.0\n" + "Host: localhost\n" + "Header1: value1\n" + - "Header 2 : value 2a \n" + - " value 2b \n" + - "Header3: \n" + - "Header4 \n" + - " value4\n" + - "Server5 : notServer\n" + - "Host Header: notHost\n" + + "Header2: value 2a value 2b \n" + + "Header3: 3\n" + + "Header4:value4\n" + + "Server5: notServer\n" + + "HostHeader: notHost\n" + "Connection: close\n" + "Accept-Encoding: gzip, deflated\n" + "Accept: unknown\n" + @@ -314,15 +375,15 @@ public class HttpParserTest assertEquals("localhost", _val[0]); assertEquals("Header1", _hdr[1]); assertEquals("value1", _val[1]); - assertEquals("Header 2", _hdr[2]); + assertEquals("Header2", _hdr[2]); assertEquals("value 2a value 2b", _val[2]); assertEquals("Header3", _hdr[3]); - assertEquals(null, _val[3]); + assertEquals("3", _val[3]); assertEquals("Header4", _hdr[4]); assertEquals("value4", _val[4]); assertEquals("Server5", _hdr[5]); assertEquals("notServer", _val[5]); - assertEquals("Host Header", _hdr[6]); + assertEquals("HostHeader", _hdr[6]); assertEquals("notHost", _val[6]); assertEquals("Connection", _hdr[7]); assertEquals("close", _val[7]); @@ -496,11 +557,9 @@ public class HttpParserTest "XXXXSPLIT / HTTP/1.0\015\012" + "Host: localhost\015\012" + "Header1: value1\015\012" + - "Header2 : value 2a \015\012" + - " value 2b \015\012" + - "Header3: \015\012" + - "Header4 \015\012" + - " value4\015\012" + + "Header2: value 2a \015\012" + + "Header3: 3\015\012" + + "Header4:value4\015\012" + "Server5: notServer\015\012" + "\015\012ZZZZ"); buffer.position(2); @@ -534,9 +593,9 @@ public class HttpParserTest assertEquals("Header1", _hdr[1]); assertEquals("value1", _val[1]); assertEquals("Header2", _hdr[2]); - assertEquals("value 2a value 2b", _val[2]); + assertEquals("value 2a", _val[2]); assertEquals("Header3", _hdr[3]); - assertEquals(null, _val[3]); + assertEquals("3", _val[3]); assertEquals("Header4", _hdr[4]); assertEquals("value4", _val[4]); assertEquals("Server5", _hdr[5]); @@ -1305,7 +1364,7 @@ public class HttpParserTest HttpParser.RequestHandler<ByteBuffer> handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); - assertEquals("Bad IPv6 Host header",_bad); + Assert.assertThat(_bad,Matchers.containsString("Bad")); } @Test @@ -1336,7 +1395,7 @@ public class HttpParserTest HttpParser.RequestHandler<ByteBuffer> handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); - assertEquals("Bad Host header",_bad); + Assert.assertThat(_bad,Matchers.containsString("Bad Host")); } @Test @@ -1517,21 +1576,19 @@ public class HttpParserTest } @Override - public boolean parsedHeader(HttpField field) + public void parsedHeader(HttpField field) { _fields.add(field); //System.err.println("header "+name+": "+value); _hdr[++_headers]= field.getName(); _val[_headers]= field.getValue(); - return false; } @Override - public boolean parsedHostHeader(String host,int port) + public void parsedHostHeader(String host,int port) { _host=host; _port=port; - return false; } @Override |