Mercurial Hosting > luan
diff src/org/eclipse/jetty/http/HttpParser.java @ 873:220ad4853cda
remove StreamEndPoint
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Mon, 03 Oct 2016 20:03:50 -0600 |
parents | 8e9db0bbf4f9 |
children | c8cd3e96db5f |
line wrap: on
line diff
--- a/src/org/eclipse/jetty/http/HttpParser.java Mon Oct 03 19:55:41 2016 -0600 +++ b/src/org/eclipse/jetty/http/HttpParser.java Mon Oct 03 20:03:50 2016 -0600 @@ -28,1250 +28,1246 @@ import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EofException; import org.eclipse.jetty.io.View; -import org.eclipse.jetty.io.bio.StreamEndPoint; import org.eclipse.jetty.util.StringUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class HttpParser implements Parser { - private static final Logger LOG = LoggerFactory.getLogger(HttpParser.class); + private static final Logger LOG = LoggerFactory.getLogger(HttpParser.class); - // States - public static final int STATE_START=-14; - public static final int STATE_FIELD0=-13; - public static final int STATE_SPACE1=-12; - public static final int STATE_STATUS=-11; - public static final int STATE_URI=-10; - public static final int STATE_SPACE2=-9; - public static final int STATE_END0=-8; - public static final int STATE_END1=-7; - public static final int STATE_FIELD2=-6; - public static final int STATE_HEADER=-5; - public static final int STATE_HEADER_NAME=-4; - public static final int STATE_HEADER_IN_NAME=-3; - public static final int STATE_HEADER_VALUE=-2; - public static final int STATE_HEADER_IN_VALUE=-1; - public static final int STATE_END=0; - public static final int STATE_EOF_CONTENT=1; - public static final int STATE_CONTENT=2; - public static final int STATE_CHUNKED_CONTENT=3; - public static final int STATE_CHUNK_SIZE=4; - public static final int STATE_CHUNK_PARAMS=5; - public static final int STATE_CHUNK=6; - public static final int STATE_SEEKING_EOF=7; + // States + public static final int STATE_START=-14; + public static final int STATE_FIELD0=-13; + public static final int STATE_SPACE1=-12; + public static final int STATE_STATUS=-11; + public static final int STATE_URI=-10; + public static final int STATE_SPACE2=-9; + public static final int STATE_END0=-8; + public static final int STATE_END1=-7; + public static final int STATE_FIELD2=-6; + public static final int STATE_HEADER=-5; + public static final int STATE_HEADER_NAME=-4; + public static final int STATE_HEADER_IN_NAME=-3; + public static final int STATE_HEADER_VALUE=-2; + public static final int STATE_HEADER_IN_VALUE=-1; + public static final int STATE_END=0; + public static final int STATE_EOF_CONTENT=1; + public static final int STATE_CONTENT=2; + public static final int STATE_CHUNKED_CONTENT=3; + public static final int STATE_CHUNK_SIZE=4; + public static final int STATE_CHUNK_PARAMS=5; + public static final int STATE_CHUNK=6; + public static final int STATE_SEEKING_EOF=7; - private final EventHandler _handler; - private final Buffers _buffers; // source of buffers - private final EndPoint _endp; - private Buffer _header; // Buffer for header data (and small _content) - private Buffer _body; // Buffer for large content - private Buffer _buffer; // The current buffer in use (either _header or _content) - private CachedBuffer _cached; - private final View.CaseInsensitive _tok0; // Saved token: header name, request method or response version - private final View.CaseInsensitive _tok1; // Saved token: header value, request URI or response code - private String _multiLineValue; - private int _responseStatus; // If >0 then we are parsing a response - private boolean _forceContentBuffer; - private boolean _persistent; + private final EventHandler _handler; + private final Buffers _buffers; // source of buffers + private final EndPoint _endp; + private Buffer _header; // Buffer for header data (and small _content) + private Buffer _body; // Buffer for large content + private Buffer _buffer; // The current buffer in use (either _header or _content) + private CachedBuffer _cached; + private final View.CaseInsensitive _tok0; // Saved token: header name, request method or response version + private final View.CaseInsensitive _tok1; // Saved token: header value, request URI or response code + private String _multiLineValue; + private int _responseStatus; // If >0 then we are parsing a response + private boolean _forceContentBuffer; + private boolean _persistent; - /* ------------------------------------------------------------------------------- */ - protected final View _contentView=new View(); // View of the content in the buffer for {@link Input} - protected int _state=STATE_START; - protected byte _eol; - protected int _length; - protected long _contentLength; - protected long _contentPosition; - protected int _chunkLength; - protected int _chunkPosition; - private boolean _headResponse; + /* ------------------------------------------------------------------------------- */ + protected final View _contentView=new View(); // View of the content in the buffer for {@link Input} + protected int _state=STATE_START; + protected byte _eol; + protected int _length; + protected long _contentLength; + protected long _contentPosition; + protected int _chunkLength; + protected int _chunkPosition; + private boolean _headResponse; - /* ------------------------------------------------------------------------------- */ - /** - * Constructor. - */ - public HttpParser(Buffer buffer, EventHandler handler) - { - _endp=null; - _buffers=null; - _header=buffer; - _buffer=buffer; - _handler=handler; + /* ------------------------------------------------------------------------------- */ + /** + * Constructor. + */ + public HttpParser(Buffer buffer, EventHandler handler) + { + _endp=null; + _buffers=null; + _header=buffer; + _buffer=buffer; + _handler=handler; - _tok0=new View.CaseInsensitive(_header); - _tok1=new View.CaseInsensitive(_header); - } + _tok0=new View.CaseInsensitive(_header); + _tok1=new View.CaseInsensitive(_header); + } - /* ------------------------------------------------------------------------------- */ - /** - * Constructor. - * @param buffers the buffers to use - * @param endp the endpoint - * @param handler the even handler - */ - public HttpParser(Buffers buffers, EndPoint endp, EventHandler handler) - { - _buffers=buffers; - _endp=endp; - _handler=handler; - _tok0=new View.CaseInsensitive(); - _tok1=new View.CaseInsensitive(); - } + /* ------------------------------------------------------------------------------- */ + /** + * Constructor. + * @param buffers the buffers to use + * @param endp the endpoint + * @param handler the even handler + */ + public HttpParser(Buffers buffers, EndPoint endp, EventHandler handler) + { + _buffers=buffers; + _endp=endp; + _handler=handler; + _tok0=new View.CaseInsensitive(); + _tok1=new View.CaseInsensitive(); + } - /* ------------------------------------------------------------------------------- */ - public long getContentLength() - { - return _contentLength; - } + /* ------------------------------------------------------------------------------- */ + public long getContentLength() + { + return _contentLength; + } - /* ------------------------------------------------------------ */ - public long getContentRead() - { - return _contentPosition; - } + /* ------------------------------------------------------------ */ + public long getContentRead() + { + return _contentPosition; + } - /* ------------------------------------------------------------ */ - /** Set if a HEAD response is expected - * @param head - */ - public void setHeadResponse(boolean head) - { - _headResponse=head; - } + /* ------------------------------------------------------------ */ + /** Set if a HEAD response is expected + * @param head + */ + public void setHeadResponse(boolean head) + { + _headResponse=head; + } - /* ------------------------------------------------------------------------------- */ - public int getState() - { - return _state; - } + /* ------------------------------------------------------------------------------- */ + public int getState() + { + return _state; + } - /* ------------------------------------------------------------------------------- */ - public boolean inContentState() - { - return _state > 0; - } + /* ------------------------------------------------------------------------------- */ + public boolean inContentState() + { + return _state > 0; + } - /* ------------------------------------------------------------------------------- */ - public boolean inHeaderState() - { - return _state < 0; - } + /* ------------------------------------------------------------------------------- */ + public boolean inHeaderState() + { + return _state < 0; + } - /* ------------------------------------------------------------------------------- */ - public boolean isChunking() - { - return _contentLength==HttpTokens.CHUNKED_CONTENT; - } + /* ------------------------------------------------------------------------------- */ + public boolean isChunking() + { + return _contentLength==HttpTokens.CHUNKED_CONTENT; + } - /* ------------------------------------------------------------ */ - public boolean isIdle() - { - return isState(STATE_START); - } + /* ------------------------------------------------------------ */ + public boolean isIdle() + { + return isState(STATE_START); + } - /* ------------------------------------------------------------ */ - public boolean isComplete() - { - return isState(STATE_END); - } + /* ------------------------------------------------------------ */ + public boolean isComplete() + { + return isState(STATE_END); + } - /* ------------------------------------------------------------ */ - public boolean isMoreInBuffer() - throws IOException - { - return ( _header!=null && _header.hasContent() || - _body!=null && _body.hasContent()); - } + /* ------------------------------------------------------------ */ + public boolean isMoreInBuffer() + throws IOException + { + return ( _header!=null && _header.hasContent() || + _body!=null && _body.hasContent()); + } - /* ------------------------------------------------------------------------------- */ - public boolean isState(int state) - { - return _state == state; - } + /* ------------------------------------------------------------------------------- */ + public boolean isState(int state) + { + return _state == state; + } - /* ------------------------------------------------------------------------------- */ - public boolean isPersistent() - { - return _persistent; - } + /* ------------------------------------------------------------------------------- */ + public boolean isPersistent() + { + return _persistent; + } - /* ------------------------------------------------------------------------------- */ - public void setPersistent(boolean persistent) - { - _persistent = persistent; - if (!_persistent &&(_state==STATE_END || _state==STATE_START)) - _state=STATE_SEEKING_EOF; - } + /* ------------------------------------------------------------------------------- */ + public void setPersistent(boolean persistent) + { + _persistent = persistent; + if (!_persistent &&(_state==STATE_END || _state==STATE_START)) + _state=STATE_SEEKING_EOF; + } - /* ------------------------------------------------------------------------------- */ - /** - * Parse until {@link #STATE_END END} state. - * If the parser is already in the END state, then it is {@link #reset reset} and re-parsed. - * @throws IllegalStateException If the buffers have already been partially parsed. - */ - public void parse() throws IOException - { - if (_state==STATE_END) - reset(); - if (_state!=STATE_START) - throw new IllegalStateException("!START"); + /* ------------------------------------------------------------------------------- */ + /** + * Parse until {@link #STATE_END END} state. + * If the parser is already in the END state, then it is {@link #reset reset} and re-parsed. + * @throws IllegalStateException If the buffers have already been partially parsed. + */ + public void parse() throws IOException + { + if (_state==STATE_END) + reset(); + if (_state!=STATE_START) + throw new IllegalStateException("!START"); - // continue parsing - while (_state != STATE_END) - if (parseNext()<0) - return; - } + // continue parsing + while (_state != STATE_END) + if (parseNext()<0) + return; + } - /* ------------------------------------------------------------------------------- */ - /** - * Parse until END state. - * This method will parse any remaining content in the current buffer as long as there is - * no unconsumed content. It does not care about the {@link #getState current state} of the parser. - * @see #parse - * @see #parseNext - */ - public boolean parseAvailable() throws IOException - { - boolean progress=parseNext()>0; + /* ------------------------------------------------------------------------------- */ + /** + * Parse until END state. + * This method will parse any remaining content in the current buffer as long as there is + * no unconsumed content. It does not care about the {@link #getState current state} of the parser. + * @see #parse + * @see #parseNext + */ + public boolean parseAvailable() throws IOException + { + boolean progress=parseNext()>0; - // continue parsing - while (!isComplete() && _buffer!=null && _buffer.length()>0 && !_contentView.hasContent()) - { - progress |= parseNext()>0; - } - return progress; - } + // continue parsing + while (!isComplete() && _buffer!=null && _buffer.length()>0 && !_contentView.hasContent()) + { + progress |= parseNext()>0; + } + return progress; + } - /* ------------------------------------------------------------------------------- */ - /** - * Parse until next Event. - * @return an indication of progress <0 EOF, 0 no progress, >0 progress. - */ - public int parseNext() throws IOException - { - try - { - int progress=0; + /* ------------------------------------------------------------------------------- */ + /** + * Parse until next Event. + * @return an indication of progress <0 EOF, 0 no progress, >0 progress. + */ + public int parseNext() throws IOException + { + try + { + int progress=0; - if (_state == STATE_END) - return 0; + if (_state == STATE_END) + return 0; - if (_buffer==null) - _buffer=getHeaderBuffer(); + if (_buffer==null) + _buffer=getHeaderBuffer(); - if (_state == STATE_CONTENT && _contentPosition == _contentLength) - { - _state=STATE_END; - _handler.messageComplete(_contentPosition); - return 1; - } + if (_state == STATE_CONTENT && _contentPosition == _contentLength) + { + _state=STATE_END; + _handler.messageComplete(_contentPosition); + return 1; + } - int length=_buffer.length(); + int length=_buffer.length(); - // Fill buffer if we can - if (length == 0) - { - int filled=-1; - IOException ex=null; - try - { - filled=fill(); - LOG.debug("filled {}/{}",filled,_buffer.length()); - } - catch(IOException e) - { - LOG.debug(this.toString(),e); - ex=e; - } + // Fill buffer if we can + if (length == 0) + { + int filled=-1; + IOException ex=null; + try + { + filled=fill(); + LOG.debug("filled {}/{}",filled,_buffer.length()); + } + catch(IOException e) + { + LOG.debug(this.toString(),e); + ex=e; + } - if (filled > 0 ) - progress++; - else if (filled < 0 ) - { - _persistent=false; + if (filled > 0 ) + progress++; + else if (filled < 0 ) + { + _persistent=false; - // do we have content to deliver? - if (_state>STATE_END) - { - if (_buffer.length()>0 && !_headResponse) - { - Buffer chunk=_buffer.get(_buffer.length()); - _contentPosition += chunk.length(); - _contentView.update(chunk); - _handler.content(chunk); // May recurse here - } - } + // do we have content to deliver? + if (_state>STATE_END) + { + if (_buffer.length()>0 && !_headResponse) + { + Buffer chunk=_buffer.get(_buffer.length()); + _contentPosition += chunk.length(); + _contentView.update(chunk); + _handler.content(chunk); // May recurse here + } + } - // was this unexpected? - switch(_state) - { - case STATE_END: - case STATE_SEEKING_EOF: - _state=STATE_END; - break; + // was this unexpected? + switch(_state) + { + case STATE_END: + case STATE_SEEKING_EOF: + _state=STATE_END; + break; - case STATE_EOF_CONTENT: - _state=STATE_END; - _handler.messageComplete(_contentPosition); - break; + case STATE_EOF_CONTENT: + _state=STATE_END; + _handler.messageComplete(_contentPosition); + break; - default: - _state=STATE_END; - if (!_headResponse) - _handler.earlyEOF(); - _handler.messageComplete(_contentPosition); - } + default: + _state=STATE_END; + if (!_headResponse) + _handler.earlyEOF(); + _handler.messageComplete(_contentPosition); + } - if (ex!=null) - throw ex; + if (ex!=null) + throw ex; - if (!isComplete() && !isIdle()) - throw new EofException(); + if (!isComplete() && !isIdle()) + throw new EofException(); - return -1; - } - length=_buffer.length(); - } + return -1; + } + length=_buffer.length(); + } - // Handle header states - byte ch; - byte[] array=_buffer.array(); - int last=_state; - while (_state<STATE_END && length-->0) - { - if (last!=_state) - { - progress++; - last=_state; - } + // Handle header states + byte ch; + byte[] array=_buffer.array(); + int last=_state; + while (_state<STATE_END && length-->0) + { + if (last!=_state) + { + progress++; + last=_state; + } - ch=_buffer.get(); + ch=_buffer.get(); - if (_eol == HttpTokens.CARRIAGE_RETURN) - { - if (ch == HttpTokens.LINE_FEED) - { - _eol=HttpTokens.LINE_FEED; - continue; - } - throw new HttpException(HttpStatus.BAD_REQUEST_400); - } - _eol=0; + if (_eol == HttpTokens.CARRIAGE_RETURN) + { + if (ch == HttpTokens.LINE_FEED) + { + _eol=HttpTokens.LINE_FEED; + continue; + } + throw new HttpException(HttpStatus.BAD_REQUEST_400); + } + _eol=0; - switch (_state) - { - case STATE_START: - _contentLength=HttpTokens.UNKNOWN_CONTENT; - _cached=null; - if (ch > HttpTokens.SPACE || ch<0) - { - _buffer.mark(); - _state=STATE_FIELD0; - } - break; + switch (_state) + { + case STATE_START: + _contentLength=HttpTokens.UNKNOWN_CONTENT; + _cached=null; + if (ch > HttpTokens.SPACE || ch<0) + { + _buffer.mark(); + _state=STATE_FIELD0; + } + break; - case STATE_FIELD0: - if (ch == HttpTokens.SPACE) - { - _tok0.update(_buffer.markIndex(), _buffer.getIndex() - 1); - _responseStatus=HttpVersions.CACHE.get(_tok0)==null?-1:0; - _state=STATE_SPACE1; - continue; - } - else if (ch < HttpTokens.SPACE && ch>=0) - { - throw new HttpException(HttpStatus.BAD_REQUEST_400); - } - break; + case STATE_FIELD0: + if (ch == HttpTokens.SPACE) + { + _tok0.update(_buffer.markIndex(), _buffer.getIndex() - 1); + _responseStatus=HttpVersions.CACHE.get(_tok0)==null?-1:0; + _state=STATE_SPACE1; + continue; + } + else if (ch < HttpTokens.SPACE && ch>=0) + { + throw new HttpException(HttpStatus.BAD_REQUEST_400); + } + break; - case STATE_SPACE1: - if (ch > HttpTokens.SPACE || ch<0) - { - _buffer.mark(); - if (_responseStatus>=0) - { - _state=STATE_STATUS; - _responseStatus=ch-'0'; - } - else - _state=STATE_URI; - } - else if (ch < HttpTokens.SPACE) - { - throw new HttpException(HttpStatus.BAD_REQUEST_400); - } - break; + case STATE_SPACE1: + if (ch > HttpTokens.SPACE || ch<0) + { + _buffer.mark(); + if (_responseStatus>=0) + { + _state=STATE_STATUS; + _responseStatus=ch-'0'; + } + else + _state=STATE_URI; + } + else if (ch < HttpTokens.SPACE) + { + throw new HttpException(HttpStatus.BAD_REQUEST_400); + } + break; - case STATE_STATUS: - if (ch == HttpTokens.SPACE) - { - _tok1.update(_buffer.markIndex(), _buffer.getIndex() - 1); - _state=STATE_SPACE2; - continue; - } - else if (ch>='0' && ch<='9') - { - _responseStatus=_responseStatus*10+(ch-'0'); - continue; - } - else if (ch < HttpTokens.SPACE && ch>=0) - { - _handler.startResponse(HttpMethods.CACHE.lookup(_tok0), _responseStatus, null); - _eol=ch; - _state=STATE_HEADER; - _tok0.setPutIndex(_tok0.getIndex()); - _tok1.setPutIndex(_tok1.getIndex()); - _multiLineValue=null; - continue; - } - // not a digit, so must be a URI - _state=STATE_URI; - _responseStatus=-1; - break; + case STATE_STATUS: + if (ch == HttpTokens.SPACE) + { + _tok1.update(_buffer.markIndex(), _buffer.getIndex() - 1); + _state=STATE_SPACE2; + continue; + } + else if (ch>='0' && ch<='9') + { + _responseStatus=_responseStatus*10+(ch-'0'); + continue; + } + else if (ch < HttpTokens.SPACE && ch>=0) + { + _handler.startResponse(HttpMethods.CACHE.lookup(_tok0), _responseStatus, null); + _eol=ch; + _state=STATE_HEADER; + _tok0.setPutIndex(_tok0.getIndex()); + _tok1.setPutIndex(_tok1.getIndex()); + _multiLineValue=null; + continue; + } + // not a digit, so must be a URI + _state=STATE_URI; + _responseStatus=-1; + break; - case STATE_URI: - if (ch == HttpTokens.SPACE) - { - _tok1.update(_buffer.markIndex(), _buffer.getIndex() - 1); - _state=STATE_SPACE2; - continue; - } - else if (ch < HttpTokens.SPACE && ch>=0) - { - // HTTP/0.9 - _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _buffer.sliceFromMark(), null); - _persistent=false; - _state=STATE_SEEKING_EOF; - _handler.headerComplete(); - _handler.messageComplete(_contentPosition); - return 1; - } - break; + case STATE_URI: + if (ch == HttpTokens.SPACE) + { + _tok1.update(_buffer.markIndex(), _buffer.getIndex() - 1); + _state=STATE_SPACE2; + continue; + } + else if (ch < HttpTokens.SPACE && ch>=0) + { + // HTTP/0.9 + _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _buffer.sliceFromMark(), null); + _persistent=false; + _state=STATE_SEEKING_EOF; + _handler.headerComplete(); + _handler.messageComplete(_contentPosition); + return 1; + } + break; - case STATE_SPACE2: - if (ch > HttpTokens.SPACE || ch<0) - { - _buffer.mark(); - _state=STATE_FIELD2; - } - else if (ch < HttpTokens.SPACE) - { - if (_responseStatus>0) - { - _handler.startResponse(HttpMethods.CACHE.lookup(_tok0), _responseStatus, null); - _eol=ch; - _state=STATE_HEADER; - _tok0.setPutIndex(_tok0.getIndex()); - _tok1.setPutIndex(_tok1.getIndex()); - _multiLineValue=null; - } - else - { - // HTTP/0.9 - _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _tok1, null); - _persistent=false; - _state=STATE_SEEKING_EOF; - _handler.headerComplete(); - _handler.messageComplete(_contentPosition); - return 1; - } - } - break; + case STATE_SPACE2: + if (ch > HttpTokens.SPACE || ch<0) + { + _buffer.mark(); + _state=STATE_FIELD2; + } + else if (ch < HttpTokens.SPACE) + { + if (_responseStatus>0) + { + _handler.startResponse(HttpMethods.CACHE.lookup(_tok0), _responseStatus, null); + _eol=ch; + _state=STATE_HEADER; + _tok0.setPutIndex(_tok0.getIndex()); + _tok1.setPutIndex(_tok1.getIndex()); + _multiLineValue=null; + } + else + { + // HTTP/0.9 + _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _tok1, null); + _persistent=false; + _state=STATE_SEEKING_EOF; + _handler.headerComplete(); + _handler.messageComplete(_contentPosition); + return 1; + } + } + break; - case STATE_FIELD2: - if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED) - { - Buffer version; - if (_responseStatus>0) - _handler.startResponse(version=HttpVersions.CACHE.lookup(_tok0), _responseStatus,_buffer.sliceFromMark()); - else - _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _tok1, version=HttpVersions.CACHE.lookup(_buffer.sliceFromMark())); - _eol=ch; - _persistent=HttpVersions.CACHE.getOrdinal(version)>=HttpVersions.HTTP_1_1_ORDINAL; - _state=STATE_HEADER; - _tok0.setPutIndex(_tok0.getIndex()); - _tok1.setPutIndex(_tok1.getIndex()); - _multiLineValue=null; - continue; - } - break; + case STATE_FIELD2: + if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED) + { + Buffer version; + if (_responseStatus>0) + _handler.startResponse(version=HttpVersions.CACHE.lookup(_tok0), _responseStatus,_buffer.sliceFromMark()); + else + _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _tok1, version=HttpVersions.CACHE.lookup(_buffer.sliceFromMark())); + _eol=ch; + _persistent=HttpVersions.CACHE.getOrdinal(version)>=HttpVersions.HTTP_1_1_ORDINAL; + _state=STATE_HEADER; + _tok0.setPutIndex(_tok0.getIndex()); + _tok1.setPutIndex(_tok1.getIndex()); + _multiLineValue=null; + continue; + } + break; - case STATE_HEADER: - switch(ch) - { - case HttpTokens.COLON: - case HttpTokens.SPACE: - case HttpTokens.TAB: - { - // header value without name - continuation? - _length=-1; - _state=STATE_HEADER_VALUE; - break; - } + case STATE_HEADER: + switch(ch) + { + case HttpTokens.COLON: + case HttpTokens.SPACE: + case HttpTokens.TAB: + { + // header value without name - continuation? + _length=-1; + _state=STATE_HEADER_VALUE; + break; + } - default: - { - // handler last header if any - if (_cached!=null || _tok0.length() > 0 || _tok1.length() > 0 || _multiLineValue != null) - { - Buffer header=_cached!=null?_cached:HttpHeaders.CACHE.lookup(_tok0); - _cached=null; - Buffer value=_multiLineValue == null ? _tok1 : new ByteArrayBuffer(_multiLineValue); + default: + { + // handler last header if any + if (_cached!=null || _tok0.length() > 0 || _tok1.length() > 0 || _multiLineValue != null) + { + Buffer header=_cached!=null?_cached:HttpHeaders.CACHE.lookup(_tok0); + _cached=null; + Buffer value=_multiLineValue == null ? _tok1 : new ByteArrayBuffer(_multiLineValue); - int ho=HttpHeaders.CACHE.getOrdinal(header); - if (ho >= 0) - { - int vo; + int ho=HttpHeaders.CACHE.getOrdinal(header); + if (ho >= 0) + { + int vo; - switch (ho) - { - case HttpHeaders.CONTENT_LENGTH_ORDINAL: - if (_contentLength != HttpTokens.CHUNKED_CONTENT ) - { - try - { - _contentLength=BufferUtil.toLong(value); - } - catch(NumberFormatException e) - { - LOG.trace("",e); - throw new HttpException(HttpStatus.BAD_REQUEST_400); - } - if (_contentLength <= 0) - _contentLength=HttpTokens.NO_CONTENT; - } - break; + switch (ho) + { + case HttpHeaders.CONTENT_LENGTH_ORDINAL: + if (_contentLength != HttpTokens.CHUNKED_CONTENT ) + { + try + { + _contentLength=BufferUtil.toLong(value); + } + catch(NumberFormatException e) + { + LOG.trace("",e); + throw new HttpException(HttpStatus.BAD_REQUEST_400); + } + if (_contentLength <= 0) + _contentLength=HttpTokens.NO_CONTENT; + } + break; - case HttpHeaders.TRANSFER_ENCODING_ORDINAL: - value=HttpHeaderValues.CACHE.lookup(value); - vo=HttpHeaderValues.CACHE.getOrdinal(value); - if (HttpHeaderValues.CHUNKED_ORDINAL == vo) - _contentLength=HttpTokens.CHUNKED_CONTENT; - else - { - String c=value.toString(StringUtil.__ISO_8859_1); - if (c.endsWith(HttpHeaderValues.CHUNKED)) - _contentLength=HttpTokens.CHUNKED_CONTENT; + case HttpHeaders.TRANSFER_ENCODING_ORDINAL: + value=HttpHeaderValues.CACHE.lookup(value); + vo=HttpHeaderValues.CACHE.getOrdinal(value); + if (HttpHeaderValues.CHUNKED_ORDINAL == vo) + _contentLength=HttpTokens.CHUNKED_CONTENT; + else + { + String c=value.toString(StringUtil.__ISO_8859_1); + if (c.endsWith(HttpHeaderValues.CHUNKED)) + _contentLength=HttpTokens.CHUNKED_CONTENT; - else if (c.indexOf(HttpHeaderValues.CHUNKED) >= 0) - throw new HttpException(400,null); - } - break; + else if (c.indexOf(HttpHeaderValues.CHUNKED) >= 0) + throw new HttpException(400,null); + } + break; - case HttpHeaders.CONNECTION_ORDINAL: - switch(HttpHeaderValues.CACHE.getOrdinal(value)) - { - case HttpHeaderValues.CLOSE_ORDINAL: - _persistent=false; - break; + case HttpHeaders.CONNECTION_ORDINAL: + switch(HttpHeaderValues.CACHE.getOrdinal(value)) + { + case HttpHeaderValues.CLOSE_ORDINAL: + _persistent=false; + break; - case HttpHeaderValues.KEEP_ALIVE_ORDINAL: - _persistent=true; - break; + case HttpHeaderValues.KEEP_ALIVE_ORDINAL: + _persistent=true; + break; - case -1: // No match, may be multi valued - { - for (String v : value.toString().split(",")) - { - switch(HttpHeaderValues.CACHE.getOrdinal(v.trim())) - { - case HttpHeaderValues.CLOSE_ORDINAL: - _persistent=false; - break; + case -1: // No match, may be multi valued + { + for (String v : value.toString().split(",")) + { + switch(HttpHeaderValues.CACHE.getOrdinal(v.trim())) + { + case HttpHeaderValues.CLOSE_ORDINAL: + _persistent=false; + break; - case HttpHeaderValues.KEEP_ALIVE_ORDINAL: - _persistent=true; - break; - } - } - break; - } - } - } - } + case HttpHeaderValues.KEEP_ALIVE_ORDINAL: + _persistent=true; + break; + } + } + break; + } + } + } + } - _handler.parsedHeader(header, value); - _tok0.setPutIndex(_tok0.getIndex()); - _tok1.setPutIndex(_tok1.getIndex()); - _multiLineValue=null; - } - _buffer.setMarkIndex(-1); + _handler.parsedHeader(header, value); + _tok0.setPutIndex(_tok0.getIndex()); + _tok1.setPutIndex(_tok1.getIndex()); + _multiLineValue=null; + } + _buffer.setMarkIndex(-1); - // now handle ch - if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED) - { - // is it a response that cannot have a body? - if (_responseStatus > 0 && // response - (_responseStatus == 304 || // not-modified response - _responseStatus == 204 || // no-content response - _responseStatus < 200)) // 1xx response - _contentLength=HttpTokens.NO_CONTENT; // ignore any other headers set - // else if we don't know framing - else if (_contentLength == HttpTokens.UNKNOWN_CONTENT) - { - if (_responseStatus == 0 // request - || _responseStatus == 304 // not-modified response - || _responseStatus == 204 // no-content response - || _responseStatus < 200) // 1xx response - _contentLength=HttpTokens.NO_CONTENT; - else - _contentLength=HttpTokens.EOF_CONTENT; - } + // now handle ch + if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED) + { + // is it a response that cannot have a body? + if (_responseStatus > 0 && // response + (_responseStatus == 304 || // not-modified response + _responseStatus == 204 || // no-content response + _responseStatus < 200)) // 1xx response + _contentLength=HttpTokens.NO_CONTENT; // ignore any other headers set + // else if we don't know framing + else if (_contentLength == HttpTokens.UNKNOWN_CONTENT) + { + if (_responseStatus == 0 // request + || _responseStatus == 304 // not-modified response + || _responseStatus == 204 // no-content response + || _responseStatus < 200) // 1xx response + _contentLength=HttpTokens.NO_CONTENT; + else + _contentLength=HttpTokens.EOF_CONTENT; + } - _contentPosition=0; - _eol=ch; - if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED) - _eol=_buffer.get(); + _contentPosition=0; + _eol=ch; + if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED) + _eol=_buffer.get(); - // We convert _contentLength to an int for this switch statement because - // we don't care about the amount of data available just whether there is some. - switch (_contentLength > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) _contentLength) - { - case HttpTokens.EOF_CONTENT: - _state=STATE_EOF_CONTENT; - _handler.headerComplete(); // May recurse here ! - break; + // We convert _contentLength to an int for this switch statement because + // we don't care about the amount of data available just whether there is some. + switch (_contentLength > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) _contentLength) + { + case HttpTokens.EOF_CONTENT: + _state=STATE_EOF_CONTENT; + _handler.headerComplete(); // May recurse here ! + break; - case HttpTokens.CHUNKED_CONTENT: - _state=STATE_CHUNKED_CONTENT; - _handler.headerComplete(); // May recurse here ! - break; + case HttpTokens.CHUNKED_CONTENT: + _state=STATE_CHUNKED_CONTENT; + _handler.headerComplete(); // May recurse here ! + break; - case HttpTokens.NO_CONTENT: - _handler.headerComplete(); - _state=_persistent||(_responseStatus>=100&&_responseStatus<200)?STATE_END:STATE_SEEKING_EOF; - _handler.messageComplete(_contentPosition); - return 1; + case HttpTokens.NO_CONTENT: + _handler.headerComplete(); + _state=_persistent||(_responseStatus>=100&&_responseStatus<200)?STATE_END:STATE_SEEKING_EOF; + _handler.messageComplete(_contentPosition); + return 1; - default: - _state=STATE_CONTENT; - _handler.headerComplete(); // May recurse here ! - break; - } - return 1; - } - else - { - // New header - _length=1; - _buffer.mark(); - _state=STATE_HEADER_NAME; + default: + _state=STATE_CONTENT; + _handler.headerComplete(); // May recurse here ! + break; + } + return 1; + } + else + { + // New header + _length=1; + _buffer.mark(); + _state=STATE_HEADER_NAME; - // try cached name! - if (array!=null) - { - _cached=HttpHeaders.CACHE.getBest(array, _buffer.markIndex(), length+1); + // try cached name! + if (array!=null) + { + _cached=HttpHeaders.CACHE.getBest(array, _buffer.markIndex(), length+1); - if (_cached!=null) - { - _length=_cached.length(); - _buffer.setGetIndex(_buffer.markIndex()+_length); - length=_buffer.length(); - } - } - } - } - } + if (_cached!=null) + { + _length=_cached.length(); + _buffer.setGetIndex(_buffer.markIndex()+_length); + length=_buffer.length(); + } + } + } + } + } - break; + break; - case STATE_HEADER_NAME: - switch(ch) - { - case HttpTokens.CARRIAGE_RETURN: - case HttpTokens.LINE_FEED: - if (_length > 0) - _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length); - _eol=ch; - _state=STATE_HEADER; - break; - case HttpTokens.COLON: - if (_length > 0 && _cached==null) - _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length); - _length=-1; - _state=STATE_HEADER_VALUE; - break; - case HttpTokens.SPACE: - case HttpTokens.TAB: - break; - default: - { - _cached=null; - if (_length == -1) - _buffer.mark(); - _length=_buffer.getIndex() - _buffer.markIndex(); - _state=STATE_HEADER_IN_NAME; - } - } + case STATE_HEADER_NAME: + switch(ch) + { + case HttpTokens.CARRIAGE_RETURN: + case HttpTokens.LINE_FEED: + if (_length > 0) + _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length); + _eol=ch; + _state=STATE_HEADER; + break; + case HttpTokens.COLON: + if (_length > 0 && _cached==null) + _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length); + _length=-1; + _state=STATE_HEADER_VALUE; + break; + case HttpTokens.SPACE: + case HttpTokens.TAB: + break; + default: + { + _cached=null; + if (_length == -1) + _buffer.mark(); + _length=_buffer.getIndex() - _buffer.markIndex(); + _state=STATE_HEADER_IN_NAME; + } + } - break; + break; - case STATE_HEADER_IN_NAME: - switch(ch) - { - case HttpTokens.CARRIAGE_RETURN: - case HttpTokens.LINE_FEED: - if (_length > 0) - _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length); - _eol=ch; - _state=STATE_HEADER; - break; - case HttpTokens.COLON: - if (_length > 0 && _cached==null) - _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length); - _length=-1; - _state=STATE_HEADER_VALUE; - break; - case HttpTokens.SPACE: - case HttpTokens.TAB: - _state=STATE_HEADER_NAME; - break; - default: - { - _cached=null; - _length++; - } - } - break; + case STATE_HEADER_IN_NAME: + switch(ch) + { + case HttpTokens.CARRIAGE_RETURN: + case HttpTokens.LINE_FEED: + if (_length > 0) + _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length); + _eol=ch; + _state=STATE_HEADER; + break; + case HttpTokens.COLON: + if (_length > 0 && _cached==null) + _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length); + _length=-1; + _state=STATE_HEADER_VALUE; + break; + case HttpTokens.SPACE: + case HttpTokens.TAB: + _state=STATE_HEADER_NAME; + break; + default: + { + _cached=null; + _length++; + } + } + break; - case STATE_HEADER_VALUE: - switch(ch) - { - case HttpTokens.CARRIAGE_RETURN: - case HttpTokens.LINE_FEED: - if (_length > 0) - { - if (_tok1.length() == 0) - _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length); - else - { - // Continuation line! - if (_multiLineValue == null) _multiLineValue=_tok1.toString(StringUtil.__ISO_8859_1); - _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length); - _multiLineValue += " " + _tok1.toString(StringUtil.__ISO_8859_1); - } - } - _eol=ch; - _state=STATE_HEADER; - break; - case HttpTokens.SPACE: - case HttpTokens.TAB: - break; - default: - { - if (_length == -1) - _buffer.mark(); - _length=_buffer.getIndex() - _buffer.markIndex(); - _state=STATE_HEADER_IN_VALUE; - } - } - break; + case STATE_HEADER_VALUE: + switch(ch) + { + case HttpTokens.CARRIAGE_RETURN: + case HttpTokens.LINE_FEED: + if (_length > 0) + { + if (_tok1.length() == 0) + _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length); + else + { + // Continuation line! + if (_multiLineValue == null) _multiLineValue=_tok1.toString(StringUtil.__ISO_8859_1); + _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length); + _multiLineValue += " " + _tok1.toString(StringUtil.__ISO_8859_1); + } + } + _eol=ch; + _state=STATE_HEADER; + break; + case HttpTokens.SPACE: + case HttpTokens.TAB: + break; + default: + { + if (_length == -1) + _buffer.mark(); + _length=_buffer.getIndex() - _buffer.markIndex(); + _state=STATE_HEADER_IN_VALUE; + } + } + break; - case STATE_HEADER_IN_VALUE: - switch(ch) - { - case HttpTokens.CARRIAGE_RETURN: - case HttpTokens.LINE_FEED: - if (_length > 0) - { - if (_tok1.length() == 0) - _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length); - else - { - // Continuation line! - if (_multiLineValue == null) _multiLineValue=_tok1.toString(StringUtil.__ISO_8859_1); - _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length); - _multiLineValue += " " + _tok1.toString(StringUtil.__ISO_8859_1); - } - } - _eol=ch; - _state=STATE_HEADER; - break; - case HttpTokens.SPACE: - case HttpTokens.TAB: - _state=STATE_HEADER_VALUE; - break; - default: - _length++; - } - break; - } - } // end of HEADER states loop + case STATE_HEADER_IN_VALUE: + switch(ch) + { + case HttpTokens.CARRIAGE_RETURN: + case HttpTokens.LINE_FEED: + if (_length > 0) + { + if (_tok1.length() == 0) + _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length); + else + { + // Continuation line! + if (_multiLineValue == null) _multiLineValue=_tok1.toString(StringUtil.__ISO_8859_1); + _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length); + _multiLineValue += " " + _tok1.toString(StringUtil.__ISO_8859_1); + } + } + _eol=ch; + _state=STATE_HEADER; + break; + case HttpTokens.SPACE: + case HttpTokens.TAB: + _state=STATE_HEADER_VALUE; + break; + default: + _length++; + } + break; + } + } // end of HEADER states loop - // ========================== + // ========================== - // Handle HEAD response - if (_responseStatus>0 && _headResponse) - { - _state=_persistent||(_responseStatus>=100&&_responseStatus<200)?STATE_END:STATE_SEEKING_EOF; - _handler.messageComplete(_contentLength); - } + // Handle HEAD response + if (_responseStatus>0 && _headResponse) + { + _state=_persistent||(_responseStatus>=100&&_responseStatus<200)?STATE_END:STATE_SEEKING_EOF; + _handler.messageComplete(_contentLength); + } - // ========================== + // ========================== - // Handle _content - length=_buffer.length(); - Buffer chunk; - last=_state; - while (_state > STATE_END && length > 0) - { - if (last!=_state) - { - progress++; - last=_state; - } + // Handle _content + length=_buffer.length(); + Buffer chunk; + last=_state; + while (_state > STATE_END && length > 0) + { + if (last!=_state) + { + progress++; + last=_state; + } - if (_eol == HttpTokens.CARRIAGE_RETURN && _buffer.peek() == HttpTokens.LINE_FEED) - { - _eol=_buffer.get(); - length=_buffer.length(); - continue; - } - _eol=0; - switch (_state) - { - case STATE_EOF_CONTENT: - chunk=_buffer.get(_buffer.length()); - _contentPosition += chunk.length(); - _contentView.update(chunk); - _handler.content(chunk); // May recurse here - // TODO adjust the _buffer to keep unconsumed content - return 1; + if (_eol == HttpTokens.CARRIAGE_RETURN && _buffer.peek() == HttpTokens.LINE_FEED) + { + _eol=_buffer.get(); + length=_buffer.length(); + continue; + } + _eol=0; + switch (_state) + { + case STATE_EOF_CONTENT: + chunk=_buffer.get(_buffer.length()); + _contentPosition += chunk.length(); + _contentView.update(chunk); + _handler.content(chunk); // May recurse here + // TODO adjust the _buffer to keep unconsumed content + return 1; - case STATE_CONTENT: - { - long remaining=_contentLength - _contentPosition; - if (remaining == 0) - { - _state=_persistent?STATE_END:STATE_SEEKING_EOF; - _handler.messageComplete(_contentPosition); - return 1; - } + case STATE_CONTENT: + { + long remaining=_contentLength - _contentPosition; + if (remaining == 0) + { + _state=_persistent?STATE_END:STATE_SEEKING_EOF; + _handler.messageComplete(_contentPosition); + return 1; + } - if (length > remaining) - { - // We can cast reamining to an int as we know that it is smaller than - // or equal to length which is already an int. - length=(int)remaining; - } + if (length > remaining) + { + // We can cast reamining to an int as we know that it is smaller than + // or equal to length which is already an int. + length=(int)remaining; + } - chunk=_buffer.get(length); - _contentPosition += chunk.length(); - _contentView.update(chunk); - _handler.content(chunk); // May recurse here + chunk=_buffer.get(length); + _contentPosition += chunk.length(); + _contentView.update(chunk); + _handler.content(chunk); // May recurse here - if(_contentPosition == _contentLength) - { - _state=_persistent?STATE_END:STATE_SEEKING_EOF; - _handler.messageComplete(_contentPosition); - } - // TODO adjust the _buffer to keep unconsumed content - return 1; - } + if(_contentPosition == _contentLength) + { + _state=_persistent?STATE_END:STATE_SEEKING_EOF; + _handler.messageComplete(_contentPosition); + } + // TODO adjust the _buffer to keep unconsumed content + return 1; + } - case STATE_CHUNKED_CONTENT: - { - ch=_buffer.peek(); - if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED) - _eol=_buffer.get(); - else if (ch <= HttpTokens.SPACE) - _buffer.get(); - else - { - _chunkLength=0; - _chunkPosition=0; - _state=STATE_CHUNK_SIZE; - } - break; - } + case STATE_CHUNKED_CONTENT: + { + ch=_buffer.peek(); + if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED) + _eol=_buffer.get(); + else if (ch <= HttpTokens.SPACE) + _buffer.get(); + else + { + _chunkLength=0; + _chunkPosition=0; + _state=STATE_CHUNK_SIZE; + } + break; + } - case STATE_CHUNK_SIZE: - { - ch=_buffer.get(); - if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED) - { - _eol=ch; + case STATE_CHUNK_SIZE: + { + ch=_buffer.get(); + if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED) + { + _eol=ch; - if (_chunkLength == 0) - { - if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED) - _eol=_buffer.get(); - _state=_persistent?STATE_END:STATE_SEEKING_EOF; - _handler.messageComplete(_contentPosition); - return 1; - } - else - _state=STATE_CHUNK; - } - else if (ch <= HttpTokens.SPACE || ch == HttpTokens.SEMI_COLON) - _state=STATE_CHUNK_PARAMS; - else if (ch >= '0' && ch <= '9') - _chunkLength=_chunkLength * 16 + (ch - '0'); - else if (ch >= 'a' && ch <= 'f') - _chunkLength=_chunkLength * 16 + (10 + ch - 'a'); - else if (ch >= 'A' && ch <= 'F') - _chunkLength=_chunkLength * 16 + (10 + ch - 'A'); - else - throw new IOException("bad chunk char: " + ch); - break; - } + if (_chunkLength == 0) + { + if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED) + _eol=_buffer.get(); + _state=_persistent?STATE_END:STATE_SEEKING_EOF; + _handler.messageComplete(_contentPosition); + return 1; + } + else + _state=STATE_CHUNK; + } + else if (ch <= HttpTokens.SPACE || ch == HttpTokens.SEMI_COLON) + _state=STATE_CHUNK_PARAMS; + else if (ch >= '0' && ch <= '9') + _chunkLength=_chunkLength * 16 + (ch - '0'); + else if (ch >= 'a' && ch <= 'f') + _chunkLength=_chunkLength * 16 + (10 + ch - 'a'); + else if (ch >= 'A' && ch <= 'F') + _chunkLength=_chunkLength * 16 + (10 + ch - 'A'); + else + throw new IOException("bad chunk char: " + ch); + break; + } - case STATE_CHUNK_PARAMS: - { - ch=_buffer.get(); - if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED) - { - _eol=ch; - if (_chunkLength == 0) - { - if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED) - _eol=_buffer.get(); - _state=_persistent?STATE_END:STATE_SEEKING_EOF; - _handler.messageComplete(_contentPosition); - return 1; - } - else - _state=STATE_CHUNK; - } - break; - } + case STATE_CHUNK_PARAMS: + { + ch=_buffer.get(); + if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED) + { + _eol=ch; + if (_chunkLength == 0) + { + if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED) + _eol=_buffer.get(); + _state=_persistent?STATE_END:STATE_SEEKING_EOF; + _handler.messageComplete(_contentPosition); + return 1; + } + else + _state=STATE_CHUNK; + } + break; + } - case STATE_CHUNK: - { - int remaining=_chunkLength - _chunkPosition; - if (remaining == 0) - { - _state=STATE_CHUNKED_CONTENT; - break; - } - else if (length > remaining) - length=remaining; - chunk=_buffer.get(length); - _contentPosition += chunk.length(); - _chunkPosition += chunk.length(); - _contentView.update(chunk); - _handler.content(chunk); // May recurse here - // TODO adjust the _buffer to keep unconsumed content - return 1; - } + case STATE_CHUNK: + { + int remaining=_chunkLength - _chunkPosition; + if (remaining == 0) + { + _state=STATE_CHUNKED_CONTENT; + break; + } + else if (length > remaining) + length=remaining; + chunk=_buffer.get(length); + _contentPosition += chunk.length(); + _chunkPosition += chunk.length(); + _contentView.update(chunk); + _handler.content(chunk); // May recurse here + // TODO adjust the _buffer to keep unconsumed content + return 1; + } - case STATE_SEEKING_EOF: - { - // Close if there is more data than CRLF - if (_buffer.length()>2) - { - _state=STATE_END; - _endp.close(); - } - else - { - // or if the data is not white space - while (_buffer.length()>0) - if (!Character.isWhitespace(_buffer.get())) - { - _state=STATE_END; - _endp.close(); - _buffer.clear(); - } - } - - _buffer.clear(); - break; - } - } + case STATE_SEEKING_EOF: + { + // Close if there is more data than CRLF + if (_buffer.length()>2) + { + _state=STATE_END; + _endp.close(); + } + else + { + // or if the data is not white space + while (_buffer.length()>0) + if (!Character.isWhitespace(_buffer.get())) + { + _state=STATE_END; + _endp.close(); + _buffer.clear(); + } + } + + _buffer.clear(); + break; + } + } - length=_buffer.length(); - } + length=_buffer.length(); + } - return progress; - } - catch(HttpException e) - { - _persistent=false; - _state=STATE_SEEKING_EOF; - throw e; - } - } + return progress; + } + catch(HttpException e) + { + _persistent=false; + _state=STATE_SEEKING_EOF; + throw e; + } + } - /* ------------------------------------------------------------------------------- */ - /** fill the buffers from the endpoint - * - */ - protected int fill() throws IOException - { - // Do we have a buffer? - if (_buffer==null) - _buffer=getHeaderBuffer(); + /* ------------------------------------------------------------------------------- */ + /** fill the buffers from the endpoint + * + */ + protected int fill() throws IOException + { + // Do we have a buffer? + if (_buffer==null) + _buffer=getHeaderBuffer(); - // Is there unconsumed content in body buffer - if (_state>STATE_END && _buffer==_header && _header!=null && !_header.hasContent() && _body!=null && _body.hasContent()) - { - _buffer=_body; - return _buffer.length(); - } + // Is there unconsumed content in body buffer + if (_state>STATE_END && _buffer==_header && _header!=null && !_header.hasContent() && _body!=null && _body.hasContent()) + { + _buffer=_body; + return _buffer.length(); + } - // Shall we switch to a body buffer? - if (_buffer==_header && _state>STATE_END && _header.length()==0 && (_forceContentBuffer || (_contentLength-_contentPosition)>_header.capacity()) && (_body!=null||_buffers!=null)) - { - if (_body==null) - _body=_buffers.getBuffer(); - _buffer=_body; - } + // Shall we switch to a body buffer? + if (_buffer==_header && _state>STATE_END && _header.length()==0 && (_forceContentBuffer || (_contentLength-_contentPosition)>_header.capacity()) && (_body!=null||_buffers!=null)) + { + if (_body==null) + _body=_buffers.getBuffer(); + _buffer=_body; + } - // Do we have somewhere to fill from? - if (_endp != null ) - { - // Shall we compact the body? - if (_buffer==_body || _state>STATE_END) - { - _buffer.compact(); - } + // Do we have somewhere to fill from? + if (_endp != null ) + { + // Shall we compact the body? + if (_buffer==_body || _state>STATE_END) + { + _buffer.compact(); + } - // Are we full? - if (_buffer.space() == 0) - { - LOG.warn("HttpParser Full for {} ",_endp); - _buffer.clear(); - throw new HttpException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413, "Request Entity Too Large: "+(_buffer==_body?"body":"head")); - } + // Are we full? + if (_buffer.space() == 0) + { + LOG.warn("HttpParser Full for {} ",_endp); + _buffer.clear(); + throw new HttpException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413, "Request Entity Too Large: "+(_buffer==_body?"body":"head")); + } - try - { - int filled = _endp.fill(_buffer); - return filled; - } - catch(IOException e) - { - LOG.debug("",e); - throw (e instanceof EofException) ? e:new EofException(e); - } - } + try + { + int filled = _endp.fill(_buffer); + return filled; + } + catch(IOException e) + { + LOG.debug("",e); + throw (e instanceof EofException) ? e:new EofException(e); + } + } - return -1; - } + return -1; + } - /* ------------------------------------------------------------------------------- */ - public void reset() - { - // reset state - _contentView.setGetIndex(_contentView.putIndex()); - _state=_persistent?STATE_START:(_endp.isInputShutdown()?STATE_END:STATE_SEEKING_EOF); - _contentLength=HttpTokens.UNKNOWN_CONTENT; - _contentPosition=0; - _length=0; - _responseStatus=0; + /* ------------------------------------------------------------------------------- */ + public void reset() + { + // reset state + _contentView.setGetIndex(_contentView.putIndex()); + _state=_persistent?STATE_START:(_endp.isInputShutdown()?STATE_END:STATE_SEEKING_EOF); + _contentLength=HttpTokens.UNKNOWN_CONTENT; + _contentPosition=0; + _length=0; + _responseStatus=0; - // Consume LF if CRLF - if (_eol == HttpTokens.CARRIAGE_RETURN && _buffer!=null && _buffer.hasContent() && _buffer.peek() == HttpTokens.LINE_FEED) - _eol=_buffer.get(); + // Consume LF if CRLF + if (_eol == HttpTokens.CARRIAGE_RETURN && _buffer!=null && _buffer.hasContent() && _buffer.peek() == HttpTokens.LINE_FEED) + _eol=_buffer.get(); - if (_body!=null && _body.hasContent()) - { - // There is content in the body after the end of the request. - // This is probably a pipelined header of the next request, so we need to - // copy it to the header buffer. - if (_header==null) - getHeaderBuffer(); - else - { - _header.setMarkIndex(-1); - _header.compact(); - } - int take=_header.space(); - if (take>_body.length()) - take=_body.length(); - _body.peek(_body.getIndex(),take); - _body.skip(_header.put(_body.peek(_body.getIndex(),take))); - } + if (_body!=null && _body.hasContent()) + { + // There is content in the body after the end of the request. + // This is probably a pipelined header of the next request, so we need to + // copy it to the header buffer. + if (_header==null) + getHeaderBuffer(); + else + { + _header.setMarkIndex(-1); + _header.compact(); + } + int take=_header.space(); + if (take>_body.length()) + take=_body.length(); + _body.peek(_body.getIndex(),take); + _body.skip(_header.put(_body.peek(_body.getIndex(),take))); + } - if (_header!=null) - { - _header.setMarkIndex(-1); - _header.compact(); - } - if (_body!=null) - _body.setMarkIndex(-1); + if (_header!=null) + { + _header.setMarkIndex(-1); + _header.compact(); + } + if (_body!=null) + _body.setMarkIndex(-1); - _buffer=_header; - returnBuffers(); - } + _buffer=_header; + returnBuffers(); + } - /* ------------------------------------------------------------------------------- */ - public void returnBuffers() - { - if (_body!=null && !_body.hasContent() && _body.markIndex()==-1 && _buffers!=null) - { - if (_buffer==_body) - _buffer=_header; - if (_buffers!=null) - _buffers.returnBuffer(_body); - _body=null; - } + /* ------------------------------------------------------------------------------- */ + public void returnBuffers() + { + if (_body!=null && !_body.hasContent() && _body.markIndex()==-1 && _buffers!=null) + { + if (_buffer==_body) + _buffer=_header; + if (_buffers!=null) + _buffers.returnBuffer(_body); + _body=null; + } - if (_header!=null && !_header.hasContent() && _header.markIndex()==-1 && _buffers!=null) - { - if (_buffer==_header) - _buffer=null; - _buffers.returnBuffer(_header); - _header=null; - } - } + if (_header!=null && !_header.hasContent() && _header.markIndex()==-1 && _buffers!=null) + { + if (_buffer==_header) + _buffer=null; + _buffers.returnBuffer(_header); + _header=null; + } + } - /* ------------------------------------------------------------------------------- */ - public void setState(int state) - { - this._state=state; - _contentLength=HttpTokens.UNKNOWN_CONTENT; - } + /* ------------------------------------------------------------------------------- */ + public void setState(int state) + { + this._state=state; + _contentLength=HttpTokens.UNKNOWN_CONTENT; + } - /* ------------------------------------------------------------------------------- */ - public String toString(Buffer buf) - { - return "state=" + _state + " length=" + _length + " buf=" + buf.hashCode(); - } + /* ------------------------------------------------------------------------------- */ + public String toString(Buffer buf) + { + return "state=" + _state + " length=" + _length + " buf=" + buf.hashCode(); + } - /* ------------------------------------------------------------------------------- */ - @Override - public String toString() - { - return String.format("%s{s=%d,l=%d,c=%d}", - getClass().getSimpleName(), - _state, - _length, - _contentLength); - } + /* ------------------------------------------------------------------------------- */ + @Override + public String toString() + { + return String.format("%s{s=%d,l=%d,c=%d}", + getClass().getSimpleName(), + _state, + _length, + _contentLength); + } - /* ------------------------------------------------------------ */ - public Buffer getHeaderBuffer() - { - if (_header == null) - { - _header=_buffers.getHeader(); - _tok0.update(_header); - _tok1.update(_header); - } - return _header; - } + /* ------------------------------------------------------------ */ + public Buffer getHeaderBuffer() + { + if (_header == null) + { + _header=_buffers.getHeader(); + _tok0.update(_header); + _tok1.update(_header); + } + return _header; + } - /* ------------------------------------------------------------ */ - public Buffer getBodyBuffer() - { - return _body; - } + /* ------------------------------------------------------------ */ + public Buffer getBodyBuffer() + { + return _body; + } - /* ------------------------------------------------------------ */ - /** - * @param force True if a new buffer will be forced to be used for content and the header buffer will not be used. - */ - public void setForceContentBuffer(boolean force) - { - _forceContentBuffer=force; - } + /* ------------------------------------------------------------ */ + /** + * @param force True if a new buffer will be forced to be used for content and the header buffer will not be used. + */ + public void setForceContentBuffer(boolean force) + { + _forceContentBuffer=force; + } - /* ------------------------------------------------------------ */ - public Buffer blockForContent(long maxIdleTime) throws IOException - { - if (_contentView.length()>0) - return _contentView; + /* ------------------------------------------------------------ */ + public Buffer blockForContent(long maxIdleTime) throws IOException + { + if (_contentView.length()>0) + return _contentView; - if (getState() <= STATE_END || isState(STATE_SEEKING_EOF)) - return null; - - try - { - parseNext(); + if (getState() <= STATE_END || isState(STATE_SEEKING_EOF)) + return null; - // parse until some progress is made (or IOException thrown for timeout) - while(_contentView.length() == 0 && !(isState(HttpParser.STATE_END)||isState(HttpParser.STATE_SEEKING_EOF)) && _endp!=null && _endp.isOpen()) - { - if (!_endp.isBlocking()) - { - if (parseNext()>0) - continue; + try + { + parseNext(); - if (!_endp.blockReadable(maxIdleTime)) - { - _endp.close(); - throw new EofException("timeout"); - } - } + // parse until some progress is made (or IOException thrown for timeout) + while(_contentView.length() == 0 && !(isState(HttpParser.STATE_END)||isState(HttpParser.STATE_SEEKING_EOF)) && _endp!=null && _endp.isOpen()) + { + if (!_endp.isBlocking()) + { + if (parseNext()>0) + continue; + + if (!_endp.blockReadable(maxIdleTime)) + { + _endp.close(); + throw new EofException("timeout"); + } + } - parseNext(); - } - } - catch(IOException e) - { - // TODO is this needed? - _endp.close(); - throw e; - } - - return _contentView.length()>0?_contentView:null; - } + parseNext(); + } + } + catch(IOException e) + { + // TODO is this needed? + _endp.close(); + throw e; + } - /* ------------------------------------------------------------ */ - /* (non-Javadoc) - * @see java.io.InputStream#available() - */ - public int available() throws IOException - { - if (_contentView!=null && _contentView.length()>0) - return _contentView.length(); + return _contentView.length()>0?_contentView:null; + } - if (_endp.isBlocking()) - { - if (_state>0 && _endp instanceof StreamEndPoint) - return ((StreamEndPoint)_endp).getInputStream().available()>0?1:0; + /* ------------------------------------------------------------ */ + /* (non-Javadoc) + * @see java.io.InputStream#available() + */ + public int available() throws IOException + { + if (_contentView!=null && _contentView.length()>0) + return _contentView.length(); - return 0; - } + if (_endp.isBlocking()) + { + return 0; + } - parseNext(); - return _contentView==null?0:_contentView.length(); - } + parseNext(); + return _contentView==null?0:_contentView.length(); + } - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - public static abstract class EventHandler - { - public abstract void content(Buffer ref) throws IOException; + /* ------------------------------------------------------------ */ + /* ------------------------------------------------------------ */ + /* ------------------------------------------------------------ */ + public static abstract class EventHandler + { + public abstract void content(Buffer ref) throws IOException; - public void headerComplete() throws IOException - { - } - - public void messageComplete(long contentLength) throws IOException - { - } + public void headerComplete() throws IOException + { + } - /** - * This is the method called by parser when a HTTP Header name and value is found - */ - public void parsedHeader(Buffer name, Buffer value) throws IOException - { - } + public void messageComplete(long contentLength) throws IOException + { + } + + /** + * This is the method called by parser when a HTTP Header name and value is found + */ + public void parsedHeader(Buffer name, Buffer value) throws IOException + { + } - /** - * This is the method called by parser when the HTTP request line is parsed - */ - public abstract void startRequest(Buffer method, Buffer url, Buffer version) - throws IOException; + /** + * This is the method called by parser when the HTTP request line is parsed + */ + public abstract void startRequest(Buffer method, Buffer url, Buffer version) + throws IOException; - /** - * This is the method called by parser when the HTTP request line is parsed - */ - public abstract void startResponse(Buffer version, int status, Buffer reason) - throws IOException; + /** + * This is the method called by parser when the HTTP request line is parsed + */ + public abstract void startResponse(Buffer version, int status, Buffer reason) + throws IOException; - public void earlyEOF() - {} - } + public void earlyEOF() + {} + }