_length=cached.length();
_length=_cached.length();
    public boolean parseNext() throws IOException    {        if (_buffer==null)        {            _header = _buffers.getBuffer(_headerBufferSize);            _buffer = _header;            _tok0 = new View(_header);            _tok1 = new View(_header);            _tok0.setPutIndex(_tok0.getIndex());            _tok1.setPutIndex(_tok1.getIndex());        }                if (_state == STATE_END) throw new IllegalStateException("STATE_END");        if (_state == STATE_CONTENT && _contentPosition == _contentLength)        {            _state = STATE_END;            _handler.messageComplete(_contentPosition);            return false;        }                int length=_buffer.length();        boolean fill_called=false;                // Fill buffer if we can        if (length == 0)        {            int filled = -1;            if (_content!=null && _buffer!=_content)            {                _buffer=_content;                filled=_buffer.length();            }                            if (_buffer.markIndex() == 0 && _buffer.putIndex() == _buffer.capacity())                    throw new IOException("FULL");            if (_endp != null && filled<=0)            {                // Compress buffer if handling _content buffer                // TODO check this is not moving data too much                if (_buffer == _content)                     _buffer.compact();                if (_buffer.space() == 0)                 {                       throw new IOException("FULL");                }                                try                {                    filled = _endp.fill(_buffer);                    fill_called=true;                }                catch(IOException ioe)                {                    Log.debug(ioe);                    reset(true);                    throw new IOException("EOF");                }            }                        if (filled < 0 && _state == STATE_EOF_CONTENT)            {                _state = STATE_END;                _handler.messageComplete(_contentPosition);                return fill_called;            }            if (filled < 0)             {                reset(true);                throw new IOException("EOF");            }            length=_buffer.length();        }                // EventHandler header        byte ch;        byte[] array = _buffer.array();        Buffer cached = null;                while (_state < STATE_END && length-->0)        {            ch = _buffer.get();                        if (_eol == CARRIAGE_RETURN && ch == LINE_FEED)            {                _eol = LINE_FEED;                continue;            }            _eol = 0;            switch (_state)            {                case STATE_START:                    _contentLength = UNKNOWN_CONTENT;                    if (ch > SPACE)                    {                        _buffer.mark();                        _state = STATE_FIELD0;                    }                    break;                case STATE_FIELD0:                    if (ch == SPACE)                    {                        _tok0.update(_buffer.markIndex(), _buffer.getIndex() - 1);                        _state = STATE_SPACE1;                        continue;                    }                    else if (ch < SPACE)                    {                        throw new IOException("BAD");                    }                    break;                case STATE_SPACE1:                    if (ch > SPACE)                    {                        _buffer.mark();                        _state = STATE_FIELD1;                        _response = ch >= '1' && ch <= '5';                    }                    else if (ch < SPACE)                    {                        throw new IOException("BAD");                    }                    break;                case STATE_FIELD1:                    if (ch == SPACE)                    {                        _tok1.update(_buffer.markIndex(), _buffer.getIndex() - 1);                        _state = STATE_SPACE2;                        continue;                    }                    else if (ch < SPACE)                    {                        // HTTP/0.9                        _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _buffer                                .sliceFromMark(), null);                        _state = STATE_END;                        _handler.headerComplete();                        _handler.messageComplete(_contentPosition);                        return  fill_called;                    }                    break;                case STATE_SPACE2:                    if (ch > SPACE)                    {                        _buffer.mark();                        _state = STATE_FIELD2;                    }                    else if (ch < SPACE)                    {                        // HTTP/0.9                        _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _tok1, null);                        _state = STATE_END;                        _handler.headerComplete();                        _handler.messageComplete(_contentPosition);                        return fill_called;                    }                    break;                case STATE_FIELD2:                    if (ch == CARRIAGE_RETURN || ch == LINE_FEED)                    {                        if (_response)                            _handler.startResponse(HttpVersions.CACHE.lookup(_tok0), BufferUtil                                    .toInt(_tok1), _buffer.sliceFromMark());                        else                            _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _tok1,                                    HttpVersions.CACHE.lookup(_buffer.sliceFromMark()));                        _eol = ch;                        _state = STATE_HEADER;                        _tok0.setPutIndex(_tok0.getIndex());                        _tok1.setPutIndex(_tok1.getIndex());                        _multiLineValue = null;                        return fill_called;                    }                    break;                case STATE_HEADER:                    if (ch == COLON || ch == SPACE || ch == TAB)                    {                        // header value without name - continuation?                        _length = -1;                        _state = STATE_HEADER_VALUE;                    }                    else                    {                        // 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 ? (Buffer) _tok1 : (Buffer) new ByteArrayBuffer(_multiLineValue);                            int ho = HttpHeaders.CACHE.getOrdinal(header);                            if (ho >= 0)                            {                                int vo = -1;                                 switch (ho)                                {                                    case HttpHeaders.CONTENT_LENGTH_ORDINAL:                                        if (_contentLength != CHUNKED_CONTENT)                                        {                                            _contentLength = BufferUtil.toInt(value);                                            if (_contentLength <= 0)                                                    _contentLength = HttpParser.NO_CONTENT;                                        }                                        break;                                    case HttpHeaders.CONNECTION_ORDINAL:                                        // TODO comma list of connections !!!                                        value = HttpHeaderValues.CACHE.lookup(value);                                        break;                                    case HttpHeaders.TRANSFER_ENCODING_ORDINAL:                                        value = HttpHeaderValues.CACHE.lookup(value);                                        vo=HttpHeaderValues.CACHE.getOrdinal(value);                                        if (HttpHeaderValues.CHUNKED_ORDINAL == vo)                                            _contentLength = CHUNKED_CONTENT;                                        else                                        {                                            // TODO avoid string conversion here                                            String c = value.toString();                                            if (c.endsWith(HttpHeaderValues.CHUNKED))                                                _contentLength = CHUNKED_CONTENT;                                            else if (c.indexOf(HttpHeaderValues.CHUNKED) >= 0)                                                throw new HttpException(400,null);                                        }                                        break;                                    case HttpHeaders.CONTENT_TYPE_ORDINAL:                                        _hasContent = true;                                        break;                                }                            }                            _handler.parsedHeader(header, value);                            _tok0.setPutIndex(_tok0.getIndex());                            _tok1.setPutIndex(_tok1.getIndex());                            _multiLineValue = null;                        }                                                // now handle ch                        if (ch == CARRIAGE_RETURN || ch == LINE_FEED)                        {                            // End of header                            // work out the _content demarcation                            if (_contentLength == UNKNOWN_CONTENT)                            {                                if (_hasContent || _response)                                    _contentLength = EOF_CONTENT;                                else                                    _contentLength = NO_CONTENT;                            }                            _contentPosition = 0;                            _eol = ch;                            switch (_contentLength)                            {                                case HttpParser.EOF_CONTENT:                                    _state = STATE_EOF_CONTENT;                                    if(_content==null && _buffers!=null)                                        _content=_buffers.getBuffer(_contentBufferSize);                                                                        _handler.headerComplete(); // May recurse here !                                    break;                                                                    case HttpParser.CHUNKED_CONTENT:                                    _state = STATE_CHUNKED_CONTENT;                                    if (_content==null && _buffers!=null)                                        _content=_buffers.getBuffer(_contentBufferSize);                                    _handler.headerComplete(); // May recurse here !                                    break;                                                                    case HttpParser.NO_CONTENT:                                    _state = STATE_END;                                    _handler.headerComplete(); // May recurse here !                                    _handler.messageComplete(_contentPosition);                                    break;                                                                    default:                                    _state = STATE_CONTENT;                                	if(_buffers!=null && _content==null && _buffer==_header && _contentLength>(_header.capacity()-_header.getIndex()))                                	    _content=_buffers.getBuffer(_contentBufferSize);                                    _handler.headerComplete(); // May recurse here !                                    break;                            }                            return fill_called;                        }                        else                        {                            // New header                            _length = 1;                            _buffer.mark();                            _state = STATE_HEADER_NAME;                                                        // try cached name!                            cached = HttpHeaders.CACHE.getBest(array, _buffer.markIndex(), length+1);                            if (cached!=null)                            {                                _length=cached.length();                                _buffer.setGetIndex(_buffer.markIndex()+_length);                                length=_buffer.length();                            }                        }                    }                    break;                case STATE_HEADER_NAME:                    if (ch == CARRIAGE_RETURN || ch == LINE_FEED)                    {                        if (_length > 0)                                _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length);                        _eol = ch;                        _state = STATE_HEADER;                    }                    else if (ch == COLON)                    {                        if (_length > 0 && cached==null)                                _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length);                        _length = -1;                        _state = STATE_HEADER_VALUE;                    }                    else if (ch != SPACE && ch != TAB)                    {                        // Drag the mark                        if (_length == -1) _buffer.mark();                        _length = _buffer.getIndex() - _buffer.markIndex();                    }                    break;                case STATE_HEADER_VALUE:                    if (ch == CARRIAGE_RETURN || ch == LINE_FEED)                    {                        if (_length > 0)                        {                            if (_tok1.length() == 0)                                _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length);                            else                            {                                // Continuation line!                                // TODO - deal with CR LF and COLON?                                if (_multiLineValue == null) _multiLineValue = _tok1.toString();                                _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length);                                _multiLineValue += " " + _tok1.toString();                            }                        }                        _eol = ch;                        _state = STATE_HEADER;                    }                    else if (ch != SPACE && ch != TAB)                    {                        if (_length == -1) _buffer.mark();                        _length = _buffer.getIndex() - _buffer.markIndex();                    }                    break;            }        } // end of HEADER states loop                        // Handle _content        Buffer chunk;        length = _buffer.length();        while (_state > STATE_END && length > 0)        {            if (_eol == CARRIAGE_RETURN && _buffer.peek() == 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();                    _handler.content(chunk);                    return fill_called;                case STATE_CONTENT:                 {                    int remaining = _contentLength - _contentPosition;                    if (remaining == 0)                    {                        _state = STATE_END;                        _handler.messageComplete(_contentPosition);                        return fill_called;                    }                    else if (length > remaining) length = remaining;                    chunk = _buffer.get(length);                    _contentPosition += chunk.length();                    _handler.content(chunk);                    return fill_called;                }                case STATE_CHUNKED_CONTENT:                {                    ch = _buffer.peek();                    if (ch == CARRIAGE_RETURN || ch == LINE_FEED)                        _eol = _buffer.get();                    else if (ch <= SPACE)                        _buffer.get();                    else                    {                        _chunkLength = 0;                        _chunkPosition = 0;                        _state = STATE_CHUNK_SIZE;                    }                    break;                }                case STATE_CHUNK_SIZE:                {                    ch = _buffer.get();                    if (ch == CARRIAGE_RETURN || ch == LINE_FEED)                    {                        _eol = ch;                        if (_chunkLength == 0)                        {                            _state = STATE_END;                            _handler.messageComplete(_contentPosition);                            return fill_called;                        }                        else                            _state = STATE_CHUNK;                    }                    else if (ch <= SPACE || ch == 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 == CARRIAGE_RETURN || ch == LINE_FEED)                    {                        _eol = ch;                        if (_chunkLength == 0)                        {                            _state = STATE_END;                            _handler.messageComplete(_contentPosition);                            return fill_called;                        }                        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();                    _handler.content(chunk);                    return fill_called;                }            }            length = _buffer.length();        }        return fill_called;    }