103928aee4356845252ac6b662d5c72c29903813eJake Slack//
203928aee4356845252ac6b662d5c72c29903813eJake Slack//  ========================================================================
303928aee4356845252ac6b662d5c72c29903813eJake Slack//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
403928aee4356845252ac6b662d5c72c29903813eJake Slack//  ------------------------------------------------------------------------
503928aee4356845252ac6b662d5c72c29903813eJake Slack//  All rights reserved. This program and the accompanying materials
603928aee4356845252ac6b662d5c72c29903813eJake Slack//  are made available under the terms of the Eclipse Public License v1.0
703928aee4356845252ac6b662d5c72c29903813eJake Slack//  and Apache License v2.0 which accompanies this distribution.
803928aee4356845252ac6b662d5c72c29903813eJake Slack//
903928aee4356845252ac6b662d5c72c29903813eJake Slack//      The Eclipse Public License is available at
1003928aee4356845252ac6b662d5c72c29903813eJake Slack//      http://www.eclipse.org/legal/epl-v10.html
1103928aee4356845252ac6b662d5c72c29903813eJake Slack//
1203928aee4356845252ac6b662d5c72c29903813eJake Slack//      The Apache License v2.0 is available at
1303928aee4356845252ac6b662d5c72c29903813eJake Slack//      http://www.opensource.org/licenses/apache2.0.php
1403928aee4356845252ac6b662d5c72c29903813eJake Slack//
1503928aee4356845252ac6b662d5c72c29903813eJake Slack//  You may elect to redistribute this code under either of these licenses.
1603928aee4356845252ac6b662d5c72c29903813eJake Slack//  ========================================================================
1703928aee4356845252ac6b662d5c72c29903813eJake Slack//
1803928aee4356845252ac6b662d5c72c29903813eJake Slack
1903928aee4356845252ac6b662d5c72c29903813eJake Slackpackage org.eclipse.jetty.http;
2003928aee4356845252ac6b662d5c72c29903813eJake Slack
2103928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.io.IOException;
2203928aee4356845252ac6b662d5c72c29903813eJake Slack
2303928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.Buffer;
2403928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.BufferCache.CachedBuffer;
2503928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.BufferUtil;
2603928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.Buffers;
2703928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.ByteArrayBuffer;
2803928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.EndPoint;
2903928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.EofException;
3003928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.View;
3103928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.bio.StreamEndPoint;
3203928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.StringUtil;
3303928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.log.Log;
3403928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.log.Logger;
3503928aee4356845252ac6b662d5c72c29903813eJake Slack
3603928aee4356845252ac6b662d5c72c29903813eJake Slackpublic class HttpParser implements Parser
3703928aee4356845252ac6b662d5c72c29903813eJake Slack{
3803928aee4356845252ac6b662d5c72c29903813eJake Slack    private static final Logger LOG = Log.getLogger(HttpParser.class);
3903928aee4356845252ac6b662d5c72c29903813eJake Slack
4003928aee4356845252ac6b662d5c72c29903813eJake Slack    // States
4103928aee4356845252ac6b662d5c72c29903813eJake Slack    public static final int STATE_START=-14;
4203928aee4356845252ac6b662d5c72c29903813eJake Slack    public static final int STATE_FIELD0=-13;
4303928aee4356845252ac6b662d5c72c29903813eJake Slack    public static final int STATE_SPACE1=-12;
4403928aee4356845252ac6b662d5c72c29903813eJake Slack    public static final int STATE_STATUS=-11;
4503928aee4356845252ac6b662d5c72c29903813eJake Slack    public static final int STATE_URI=-10;
4603928aee4356845252ac6b662d5c72c29903813eJake Slack    public static final int STATE_SPACE2=-9;
4703928aee4356845252ac6b662d5c72c29903813eJake Slack    public static final int STATE_END0=-8;
4803928aee4356845252ac6b662d5c72c29903813eJake Slack    public static final int STATE_END1=-7;
4903928aee4356845252ac6b662d5c72c29903813eJake Slack    public static final int STATE_FIELD2=-6;
5003928aee4356845252ac6b662d5c72c29903813eJake Slack    public static final int STATE_HEADER=-5;
5103928aee4356845252ac6b662d5c72c29903813eJake Slack    public static final int STATE_HEADER_NAME=-4;
5203928aee4356845252ac6b662d5c72c29903813eJake Slack    public static final int STATE_HEADER_IN_NAME=-3;
5303928aee4356845252ac6b662d5c72c29903813eJake Slack    public static final int STATE_HEADER_VALUE=-2;
5403928aee4356845252ac6b662d5c72c29903813eJake Slack    public static final int STATE_HEADER_IN_VALUE=-1;
5503928aee4356845252ac6b662d5c72c29903813eJake Slack    public static final int STATE_END=0;
5603928aee4356845252ac6b662d5c72c29903813eJake Slack    public static final int STATE_EOF_CONTENT=1;
5703928aee4356845252ac6b662d5c72c29903813eJake Slack    public static final int STATE_CONTENT=2;
5803928aee4356845252ac6b662d5c72c29903813eJake Slack    public static final int STATE_CHUNKED_CONTENT=3;
5903928aee4356845252ac6b662d5c72c29903813eJake Slack    public static final int STATE_CHUNK_SIZE=4;
6003928aee4356845252ac6b662d5c72c29903813eJake Slack    public static final int STATE_CHUNK_PARAMS=5;
6103928aee4356845252ac6b662d5c72c29903813eJake Slack    public static final int STATE_CHUNK=6;
6203928aee4356845252ac6b662d5c72c29903813eJake Slack    public static final int STATE_SEEKING_EOF=7;
6303928aee4356845252ac6b662d5c72c29903813eJake Slack
6403928aee4356845252ac6b662d5c72c29903813eJake Slack    private final EventHandler _handler;
6503928aee4356845252ac6b662d5c72c29903813eJake Slack    private final Buffers _buffers; // source of buffers
6603928aee4356845252ac6b662d5c72c29903813eJake Slack    private final EndPoint _endp;
6703928aee4356845252ac6b662d5c72c29903813eJake Slack    private Buffer _header; // Buffer for header data (and small _content)
6803928aee4356845252ac6b662d5c72c29903813eJake Slack    private Buffer _body; // Buffer for large content
6903928aee4356845252ac6b662d5c72c29903813eJake Slack    private Buffer _buffer; // The current buffer in use (either _header or _content)
7003928aee4356845252ac6b662d5c72c29903813eJake Slack    private CachedBuffer _cached;
7103928aee4356845252ac6b662d5c72c29903813eJake Slack    private final View.CaseInsensitive _tok0; // Saved token: header name, request method or response version
7203928aee4356845252ac6b662d5c72c29903813eJake Slack    private final View.CaseInsensitive _tok1; // Saved token: header value, request URI or response code
7303928aee4356845252ac6b662d5c72c29903813eJake Slack    private String _multiLineValue;
7403928aee4356845252ac6b662d5c72c29903813eJake Slack    private int _responseStatus; // If >0 then we are parsing a response
7503928aee4356845252ac6b662d5c72c29903813eJake Slack    private boolean _forceContentBuffer;
7603928aee4356845252ac6b662d5c72c29903813eJake Slack    private boolean _persistent;
7703928aee4356845252ac6b662d5c72c29903813eJake Slack
7803928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------------------------- */
7903928aee4356845252ac6b662d5c72c29903813eJake Slack    protected final View  _contentView=new View(); // View of the content in the buffer for {@link Input}
8003928aee4356845252ac6b662d5c72c29903813eJake Slack    protected int _state=STATE_START;
8103928aee4356845252ac6b662d5c72c29903813eJake Slack    protected byte _eol;
8203928aee4356845252ac6b662d5c72c29903813eJake Slack    protected int _length;
8303928aee4356845252ac6b662d5c72c29903813eJake Slack    protected long _contentLength;
8403928aee4356845252ac6b662d5c72c29903813eJake Slack    protected long _contentPosition;
8503928aee4356845252ac6b662d5c72c29903813eJake Slack    protected int _chunkLength;
8603928aee4356845252ac6b662d5c72c29903813eJake Slack    protected int _chunkPosition;
8703928aee4356845252ac6b662d5c72c29903813eJake Slack    private boolean _headResponse;
8803928aee4356845252ac6b662d5c72c29903813eJake Slack
8903928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------------------------- */
9003928aee4356845252ac6b662d5c72c29903813eJake Slack    /**
9103928aee4356845252ac6b662d5c72c29903813eJake Slack     * Constructor.
9203928aee4356845252ac6b662d5c72c29903813eJake Slack     */
9303928aee4356845252ac6b662d5c72c29903813eJake Slack    public HttpParser(Buffer buffer, EventHandler handler)
9403928aee4356845252ac6b662d5c72c29903813eJake Slack    {
9503928aee4356845252ac6b662d5c72c29903813eJake Slack        _endp=null;
9603928aee4356845252ac6b662d5c72c29903813eJake Slack        _buffers=null;
9703928aee4356845252ac6b662d5c72c29903813eJake Slack        _header=buffer;
9803928aee4356845252ac6b662d5c72c29903813eJake Slack        _buffer=buffer;
9903928aee4356845252ac6b662d5c72c29903813eJake Slack        _handler=handler;
10003928aee4356845252ac6b662d5c72c29903813eJake Slack
10103928aee4356845252ac6b662d5c72c29903813eJake Slack        _tok0=new View.CaseInsensitive(_header);
10203928aee4356845252ac6b662d5c72c29903813eJake Slack        _tok1=new View.CaseInsensitive(_header);
10303928aee4356845252ac6b662d5c72c29903813eJake Slack    }
10403928aee4356845252ac6b662d5c72c29903813eJake Slack
10503928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------------------------- */
10603928aee4356845252ac6b662d5c72c29903813eJake Slack    /**
10703928aee4356845252ac6b662d5c72c29903813eJake Slack     * Constructor.
10803928aee4356845252ac6b662d5c72c29903813eJake Slack     * @param buffers the buffers to use
10903928aee4356845252ac6b662d5c72c29903813eJake Slack     * @param endp the endpoint
11003928aee4356845252ac6b662d5c72c29903813eJake Slack     * @param handler the even handler
11103928aee4356845252ac6b662d5c72c29903813eJake Slack     */
11203928aee4356845252ac6b662d5c72c29903813eJake Slack    public HttpParser(Buffers buffers, EndPoint endp, EventHandler handler)
11303928aee4356845252ac6b662d5c72c29903813eJake Slack    {
11403928aee4356845252ac6b662d5c72c29903813eJake Slack        _buffers=buffers;
11503928aee4356845252ac6b662d5c72c29903813eJake Slack        _endp=endp;
11603928aee4356845252ac6b662d5c72c29903813eJake Slack        _handler=handler;
11703928aee4356845252ac6b662d5c72c29903813eJake Slack        _tok0=new View.CaseInsensitive();
11803928aee4356845252ac6b662d5c72c29903813eJake Slack        _tok1=new View.CaseInsensitive();
11903928aee4356845252ac6b662d5c72c29903813eJake Slack    }
12003928aee4356845252ac6b662d5c72c29903813eJake Slack
12103928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------------------------- */
12203928aee4356845252ac6b662d5c72c29903813eJake Slack    public long getContentLength()
12303928aee4356845252ac6b662d5c72c29903813eJake Slack    {
12403928aee4356845252ac6b662d5c72c29903813eJake Slack        return _contentLength;
12503928aee4356845252ac6b662d5c72c29903813eJake Slack    }
12603928aee4356845252ac6b662d5c72c29903813eJake Slack
12703928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
12803928aee4356845252ac6b662d5c72c29903813eJake Slack    public long getContentRead()
12903928aee4356845252ac6b662d5c72c29903813eJake Slack    {
13003928aee4356845252ac6b662d5c72c29903813eJake Slack        return _contentPosition;
13103928aee4356845252ac6b662d5c72c29903813eJake Slack    }
13203928aee4356845252ac6b662d5c72c29903813eJake Slack
13303928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
13403928aee4356845252ac6b662d5c72c29903813eJake Slack    /** Set if a HEAD response is expected
13503928aee4356845252ac6b662d5c72c29903813eJake Slack     * @param head
13603928aee4356845252ac6b662d5c72c29903813eJake Slack     */
13703928aee4356845252ac6b662d5c72c29903813eJake Slack    public void setHeadResponse(boolean head)
13803928aee4356845252ac6b662d5c72c29903813eJake Slack    {
13903928aee4356845252ac6b662d5c72c29903813eJake Slack        _headResponse=head;
14003928aee4356845252ac6b662d5c72c29903813eJake Slack    }
14103928aee4356845252ac6b662d5c72c29903813eJake Slack
14203928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------------------------- */
14303928aee4356845252ac6b662d5c72c29903813eJake Slack    public int getState()
14403928aee4356845252ac6b662d5c72c29903813eJake Slack    {
14503928aee4356845252ac6b662d5c72c29903813eJake Slack        return _state;
14603928aee4356845252ac6b662d5c72c29903813eJake Slack    }
14703928aee4356845252ac6b662d5c72c29903813eJake Slack
14803928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------------------------- */
14903928aee4356845252ac6b662d5c72c29903813eJake Slack    public boolean inContentState()
15003928aee4356845252ac6b662d5c72c29903813eJake Slack    {
15103928aee4356845252ac6b662d5c72c29903813eJake Slack        return _state > 0;
15203928aee4356845252ac6b662d5c72c29903813eJake Slack    }
15303928aee4356845252ac6b662d5c72c29903813eJake Slack
15403928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------------------------- */
15503928aee4356845252ac6b662d5c72c29903813eJake Slack    public boolean inHeaderState()
15603928aee4356845252ac6b662d5c72c29903813eJake Slack    {
15703928aee4356845252ac6b662d5c72c29903813eJake Slack        return _state < 0;
15803928aee4356845252ac6b662d5c72c29903813eJake Slack    }
15903928aee4356845252ac6b662d5c72c29903813eJake Slack
16003928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------------------------- */
16103928aee4356845252ac6b662d5c72c29903813eJake Slack    public boolean isChunking()
16203928aee4356845252ac6b662d5c72c29903813eJake Slack    {
16303928aee4356845252ac6b662d5c72c29903813eJake Slack        return _contentLength==HttpTokens.CHUNKED_CONTENT;
16403928aee4356845252ac6b662d5c72c29903813eJake Slack    }
16503928aee4356845252ac6b662d5c72c29903813eJake Slack
16603928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
16703928aee4356845252ac6b662d5c72c29903813eJake Slack    public boolean isIdle()
16803928aee4356845252ac6b662d5c72c29903813eJake Slack    {
16903928aee4356845252ac6b662d5c72c29903813eJake Slack        return isState(STATE_START);
17003928aee4356845252ac6b662d5c72c29903813eJake Slack    }
17103928aee4356845252ac6b662d5c72c29903813eJake Slack
17203928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
17303928aee4356845252ac6b662d5c72c29903813eJake Slack    public boolean isComplete()
17403928aee4356845252ac6b662d5c72c29903813eJake Slack    {
17503928aee4356845252ac6b662d5c72c29903813eJake Slack        return isState(STATE_END);
17603928aee4356845252ac6b662d5c72c29903813eJake Slack    }
17703928aee4356845252ac6b662d5c72c29903813eJake Slack
17803928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
17903928aee4356845252ac6b662d5c72c29903813eJake Slack    public boolean isMoreInBuffer()
18003928aee4356845252ac6b662d5c72c29903813eJake Slack    throws IOException
18103928aee4356845252ac6b662d5c72c29903813eJake Slack    {
18203928aee4356845252ac6b662d5c72c29903813eJake Slack        return ( _header!=null && _header.hasContent() ||
18303928aee4356845252ac6b662d5c72c29903813eJake Slack             _body!=null && _body.hasContent());
18403928aee4356845252ac6b662d5c72c29903813eJake Slack    }
18503928aee4356845252ac6b662d5c72c29903813eJake Slack
18603928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------------------------- */
18703928aee4356845252ac6b662d5c72c29903813eJake Slack    public boolean isState(int state)
18803928aee4356845252ac6b662d5c72c29903813eJake Slack    {
18903928aee4356845252ac6b662d5c72c29903813eJake Slack        return _state == state;
19003928aee4356845252ac6b662d5c72c29903813eJake Slack    }
19103928aee4356845252ac6b662d5c72c29903813eJake Slack
19203928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------------------------- */
19303928aee4356845252ac6b662d5c72c29903813eJake Slack    public boolean isPersistent()
19403928aee4356845252ac6b662d5c72c29903813eJake Slack    {
19503928aee4356845252ac6b662d5c72c29903813eJake Slack        return _persistent;
19603928aee4356845252ac6b662d5c72c29903813eJake Slack    }
19703928aee4356845252ac6b662d5c72c29903813eJake Slack
19803928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------------------------- */
19903928aee4356845252ac6b662d5c72c29903813eJake Slack    public void setPersistent(boolean persistent)
20003928aee4356845252ac6b662d5c72c29903813eJake Slack    {
20103928aee4356845252ac6b662d5c72c29903813eJake Slack        _persistent = persistent;
20203928aee4356845252ac6b662d5c72c29903813eJake Slack        if (!_persistent &&(_state==STATE_END || _state==STATE_START))
20303928aee4356845252ac6b662d5c72c29903813eJake Slack            _state=STATE_SEEKING_EOF;
20403928aee4356845252ac6b662d5c72c29903813eJake Slack    }
20503928aee4356845252ac6b662d5c72c29903813eJake Slack
20603928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------------------------- */
20703928aee4356845252ac6b662d5c72c29903813eJake Slack    /**
20803928aee4356845252ac6b662d5c72c29903813eJake Slack     * Parse until {@link #STATE_END END} state.
20903928aee4356845252ac6b662d5c72c29903813eJake Slack     * If the parser is already in the END state, then it is {@link #reset reset} and re-parsed.
21003928aee4356845252ac6b662d5c72c29903813eJake Slack     * @throws IllegalStateException If the buffers have already been partially parsed.
21103928aee4356845252ac6b662d5c72c29903813eJake Slack     */
21203928aee4356845252ac6b662d5c72c29903813eJake Slack    public void parse() throws IOException
21303928aee4356845252ac6b662d5c72c29903813eJake Slack    {
21403928aee4356845252ac6b662d5c72c29903813eJake Slack        if (_state==STATE_END)
21503928aee4356845252ac6b662d5c72c29903813eJake Slack            reset();
21603928aee4356845252ac6b662d5c72c29903813eJake Slack        if (_state!=STATE_START)
21703928aee4356845252ac6b662d5c72c29903813eJake Slack            throw new IllegalStateException("!START");
21803928aee4356845252ac6b662d5c72c29903813eJake Slack
21903928aee4356845252ac6b662d5c72c29903813eJake Slack        // continue parsing
22003928aee4356845252ac6b662d5c72c29903813eJake Slack        while (_state != STATE_END)
22103928aee4356845252ac6b662d5c72c29903813eJake Slack            if (parseNext()<0)
22203928aee4356845252ac6b662d5c72c29903813eJake Slack                return;
22303928aee4356845252ac6b662d5c72c29903813eJake Slack    }
22403928aee4356845252ac6b662d5c72c29903813eJake Slack
22503928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------------------------- */
22603928aee4356845252ac6b662d5c72c29903813eJake Slack    /**
22703928aee4356845252ac6b662d5c72c29903813eJake Slack     * Parse until END state.
22803928aee4356845252ac6b662d5c72c29903813eJake Slack     * This method will parse any remaining content in the current buffer as long as there is
22903928aee4356845252ac6b662d5c72c29903813eJake Slack     * no unconsumed content. It does not care about the {@link #getState current state} of the parser.
23003928aee4356845252ac6b662d5c72c29903813eJake Slack     * @see #parse
23103928aee4356845252ac6b662d5c72c29903813eJake Slack     * @see #parseNext
23203928aee4356845252ac6b662d5c72c29903813eJake Slack     */
23303928aee4356845252ac6b662d5c72c29903813eJake Slack    public boolean parseAvailable() throws IOException
23403928aee4356845252ac6b662d5c72c29903813eJake Slack    {
23503928aee4356845252ac6b662d5c72c29903813eJake Slack        boolean progress=parseNext()>0;
23603928aee4356845252ac6b662d5c72c29903813eJake Slack
23703928aee4356845252ac6b662d5c72c29903813eJake Slack        // continue parsing
23803928aee4356845252ac6b662d5c72c29903813eJake Slack        while (!isComplete() && _buffer!=null && _buffer.length()>0 && !_contentView.hasContent())
23903928aee4356845252ac6b662d5c72c29903813eJake Slack        {
24003928aee4356845252ac6b662d5c72c29903813eJake Slack            progress |= parseNext()>0;
24103928aee4356845252ac6b662d5c72c29903813eJake Slack        }
24203928aee4356845252ac6b662d5c72c29903813eJake Slack        return progress;
24303928aee4356845252ac6b662d5c72c29903813eJake Slack    }
24403928aee4356845252ac6b662d5c72c29903813eJake Slack
24503928aee4356845252ac6b662d5c72c29903813eJake Slack
24603928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------------------------- */
24703928aee4356845252ac6b662d5c72c29903813eJake Slack    /**
24803928aee4356845252ac6b662d5c72c29903813eJake Slack     * Parse until next Event.
24903928aee4356845252ac6b662d5c72c29903813eJake Slack     * @return an indication of progress <0 EOF, 0 no progress, >0 progress.
25003928aee4356845252ac6b662d5c72c29903813eJake Slack     */
25103928aee4356845252ac6b662d5c72c29903813eJake Slack    public int parseNext() throws IOException
25203928aee4356845252ac6b662d5c72c29903813eJake Slack    {
25303928aee4356845252ac6b662d5c72c29903813eJake Slack        try
25403928aee4356845252ac6b662d5c72c29903813eJake Slack        {
25503928aee4356845252ac6b662d5c72c29903813eJake Slack            int progress=0;
25603928aee4356845252ac6b662d5c72c29903813eJake Slack
25703928aee4356845252ac6b662d5c72c29903813eJake Slack            if (_state == STATE_END)
25803928aee4356845252ac6b662d5c72c29903813eJake Slack                return 0;
25903928aee4356845252ac6b662d5c72c29903813eJake Slack
26003928aee4356845252ac6b662d5c72c29903813eJake Slack            if (_buffer==null)
26103928aee4356845252ac6b662d5c72c29903813eJake Slack                _buffer=getHeaderBuffer();
26203928aee4356845252ac6b662d5c72c29903813eJake Slack
26303928aee4356845252ac6b662d5c72c29903813eJake Slack
26403928aee4356845252ac6b662d5c72c29903813eJake Slack            if (_state == STATE_CONTENT && _contentPosition == _contentLength)
26503928aee4356845252ac6b662d5c72c29903813eJake Slack            {
26603928aee4356845252ac6b662d5c72c29903813eJake Slack                _state=STATE_END;
26703928aee4356845252ac6b662d5c72c29903813eJake Slack                _handler.messageComplete(_contentPosition);
26803928aee4356845252ac6b662d5c72c29903813eJake Slack                return 1;
26903928aee4356845252ac6b662d5c72c29903813eJake Slack            }
27003928aee4356845252ac6b662d5c72c29903813eJake Slack
27103928aee4356845252ac6b662d5c72c29903813eJake Slack            int length=_buffer.length();
27203928aee4356845252ac6b662d5c72c29903813eJake Slack
27303928aee4356845252ac6b662d5c72c29903813eJake Slack            // Fill buffer if we can
27403928aee4356845252ac6b662d5c72c29903813eJake Slack            if (length == 0)
27503928aee4356845252ac6b662d5c72c29903813eJake Slack            {
27603928aee4356845252ac6b662d5c72c29903813eJake Slack                int filled=-1;
27703928aee4356845252ac6b662d5c72c29903813eJake Slack                IOException ex=null;
27803928aee4356845252ac6b662d5c72c29903813eJake Slack                try
27903928aee4356845252ac6b662d5c72c29903813eJake Slack                {
28003928aee4356845252ac6b662d5c72c29903813eJake Slack                    filled=fill();
28103928aee4356845252ac6b662d5c72c29903813eJake Slack                    LOG.debug("filled {}/{}",filled,_buffer.length());
28203928aee4356845252ac6b662d5c72c29903813eJake Slack                }
28303928aee4356845252ac6b662d5c72c29903813eJake Slack                catch(IOException e)
28403928aee4356845252ac6b662d5c72c29903813eJake Slack                {
28503928aee4356845252ac6b662d5c72c29903813eJake Slack                    LOG.debug(this.toString(),e);
28603928aee4356845252ac6b662d5c72c29903813eJake Slack                    ex=e;
28703928aee4356845252ac6b662d5c72c29903813eJake Slack                }
28803928aee4356845252ac6b662d5c72c29903813eJake Slack
28903928aee4356845252ac6b662d5c72c29903813eJake Slack                if (filled > 0 )
29003928aee4356845252ac6b662d5c72c29903813eJake Slack                    progress++;
29103928aee4356845252ac6b662d5c72c29903813eJake Slack                else if (filled < 0 )
29203928aee4356845252ac6b662d5c72c29903813eJake Slack                {
29303928aee4356845252ac6b662d5c72c29903813eJake Slack                    _persistent=false;
29403928aee4356845252ac6b662d5c72c29903813eJake Slack
29503928aee4356845252ac6b662d5c72c29903813eJake Slack                    // do we have content to deliver?
29603928aee4356845252ac6b662d5c72c29903813eJake Slack                    if (_state>STATE_END)
29703928aee4356845252ac6b662d5c72c29903813eJake Slack                    {
29803928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (_buffer.length()>0 && !_headResponse)
29903928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
30003928aee4356845252ac6b662d5c72c29903813eJake Slack                            Buffer chunk=_buffer.get(_buffer.length());
30103928aee4356845252ac6b662d5c72c29903813eJake Slack                            _contentPosition += chunk.length();
30203928aee4356845252ac6b662d5c72c29903813eJake Slack                            _contentView.update(chunk);
30303928aee4356845252ac6b662d5c72c29903813eJake Slack                            _handler.content(chunk); // May recurse here
30403928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
30503928aee4356845252ac6b662d5c72c29903813eJake Slack                    }
30603928aee4356845252ac6b662d5c72c29903813eJake Slack
30703928aee4356845252ac6b662d5c72c29903813eJake Slack                    // was this unexpected?
30803928aee4356845252ac6b662d5c72c29903813eJake Slack                    switch(_state)
30903928aee4356845252ac6b662d5c72c29903813eJake Slack                    {
31003928aee4356845252ac6b662d5c72c29903813eJake Slack                        case STATE_END:
31103928aee4356845252ac6b662d5c72c29903813eJake Slack                        case STATE_SEEKING_EOF:
31203928aee4356845252ac6b662d5c72c29903813eJake Slack                            _state=STATE_END;
31303928aee4356845252ac6b662d5c72c29903813eJake Slack                            break;
31403928aee4356845252ac6b662d5c72c29903813eJake Slack
31503928aee4356845252ac6b662d5c72c29903813eJake Slack                        case STATE_EOF_CONTENT:
31603928aee4356845252ac6b662d5c72c29903813eJake Slack                            _state=STATE_END;
31703928aee4356845252ac6b662d5c72c29903813eJake Slack                            _handler.messageComplete(_contentPosition);
31803928aee4356845252ac6b662d5c72c29903813eJake Slack                            break;
31903928aee4356845252ac6b662d5c72c29903813eJake Slack
32003928aee4356845252ac6b662d5c72c29903813eJake Slack                        default:
32103928aee4356845252ac6b662d5c72c29903813eJake Slack                            _state=STATE_END;
32203928aee4356845252ac6b662d5c72c29903813eJake Slack                            if (!_headResponse)
32303928aee4356845252ac6b662d5c72c29903813eJake Slack                                _handler.earlyEOF();
32403928aee4356845252ac6b662d5c72c29903813eJake Slack                            _handler.messageComplete(_contentPosition);
32503928aee4356845252ac6b662d5c72c29903813eJake Slack                    }
32603928aee4356845252ac6b662d5c72c29903813eJake Slack
32703928aee4356845252ac6b662d5c72c29903813eJake Slack                    if (ex!=null)
32803928aee4356845252ac6b662d5c72c29903813eJake Slack                        throw ex;
32903928aee4356845252ac6b662d5c72c29903813eJake Slack
33003928aee4356845252ac6b662d5c72c29903813eJake Slack                    if (!isComplete() && !isIdle())
33103928aee4356845252ac6b662d5c72c29903813eJake Slack                        throw new EofException();
33203928aee4356845252ac6b662d5c72c29903813eJake Slack
33303928aee4356845252ac6b662d5c72c29903813eJake Slack                    return -1;
33403928aee4356845252ac6b662d5c72c29903813eJake Slack                }
33503928aee4356845252ac6b662d5c72c29903813eJake Slack                length=_buffer.length();
33603928aee4356845252ac6b662d5c72c29903813eJake Slack            }
33703928aee4356845252ac6b662d5c72c29903813eJake Slack
33803928aee4356845252ac6b662d5c72c29903813eJake Slack
33903928aee4356845252ac6b662d5c72c29903813eJake Slack            // Handle header states
34003928aee4356845252ac6b662d5c72c29903813eJake Slack            byte ch;
34103928aee4356845252ac6b662d5c72c29903813eJake Slack            byte[] array=_buffer.array();
34203928aee4356845252ac6b662d5c72c29903813eJake Slack            int last=_state;
34303928aee4356845252ac6b662d5c72c29903813eJake Slack            while (_state<STATE_END && length-->0)
34403928aee4356845252ac6b662d5c72c29903813eJake Slack            {
34503928aee4356845252ac6b662d5c72c29903813eJake Slack                if (last!=_state)
34603928aee4356845252ac6b662d5c72c29903813eJake Slack                {
34703928aee4356845252ac6b662d5c72c29903813eJake Slack                    progress++;
34803928aee4356845252ac6b662d5c72c29903813eJake Slack                    last=_state;
34903928aee4356845252ac6b662d5c72c29903813eJake Slack                }
35003928aee4356845252ac6b662d5c72c29903813eJake Slack
35103928aee4356845252ac6b662d5c72c29903813eJake Slack                ch=_buffer.get();
35203928aee4356845252ac6b662d5c72c29903813eJake Slack
35303928aee4356845252ac6b662d5c72c29903813eJake Slack                if (_eol == HttpTokens.CARRIAGE_RETURN)
35403928aee4356845252ac6b662d5c72c29903813eJake Slack                {
35503928aee4356845252ac6b662d5c72c29903813eJake Slack                    if (ch == HttpTokens.LINE_FEED)
35603928aee4356845252ac6b662d5c72c29903813eJake Slack                    {
35703928aee4356845252ac6b662d5c72c29903813eJake Slack                        _eol=HttpTokens.LINE_FEED;
35803928aee4356845252ac6b662d5c72c29903813eJake Slack                        continue;
35903928aee4356845252ac6b662d5c72c29903813eJake Slack                    }
36003928aee4356845252ac6b662d5c72c29903813eJake Slack                    throw new HttpException(HttpStatus.BAD_REQUEST_400);
36103928aee4356845252ac6b662d5c72c29903813eJake Slack                }
36203928aee4356845252ac6b662d5c72c29903813eJake Slack                _eol=0;
36303928aee4356845252ac6b662d5c72c29903813eJake Slack
36403928aee4356845252ac6b662d5c72c29903813eJake Slack                switch (_state)
36503928aee4356845252ac6b662d5c72c29903813eJake Slack                {
36603928aee4356845252ac6b662d5c72c29903813eJake Slack                    case STATE_START:
36703928aee4356845252ac6b662d5c72c29903813eJake Slack                        _contentLength=HttpTokens.UNKNOWN_CONTENT;
36803928aee4356845252ac6b662d5c72c29903813eJake Slack                        _cached=null;
36903928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (ch > HttpTokens.SPACE || ch<0)
37003928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
37103928aee4356845252ac6b662d5c72c29903813eJake Slack                            _buffer.mark();
37203928aee4356845252ac6b662d5c72c29903813eJake Slack                            _state=STATE_FIELD0;
37303928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
37403928aee4356845252ac6b662d5c72c29903813eJake Slack                        break;
37503928aee4356845252ac6b662d5c72c29903813eJake Slack
37603928aee4356845252ac6b662d5c72c29903813eJake Slack                    case STATE_FIELD0:
37703928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (ch == HttpTokens.SPACE)
37803928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
37903928aee4356845252ac6b662d5c72c29903813eJake Slack                            _tok0.update(_buffer.markIndex(), _buffer.getIndex() - 1);
38003928aee4356845252ac6b662d5c72c29903813eJake Slack                            _responseStatus=HttpVersions.CACHE.get(_tok0)==null?-1:0;
38103928aee4356845252ac6b662d5c72c29903813eJake Slack                            _state=STATE_SPACE1;
38203928aee4356845252ac6b662d5c72c29903813eJake Slack                            continue;
38303928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
38403928aee4356845252ac6b662d5c72c29903813eJake Slack                        else if (ch < HttpTokens.SPACE && ch>=0)
38503928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
38603928aee4356845252ac6b662d5c72c29903813eJake Slack                            throw new HttpException(HttpStatus.BAD_REQUEST_400);
38703928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
38803928aee4356845252ac6b662d5c72c29903813eJake Slack                        break;
38903928aee4356845252ac6b662d5c72c29903813eJake Slack
39003928aee4356845252ac6b662d5c72c29903813eJake Slack                    case STATE_SPACE1:
39103928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (ch > HttpTokens.SPACE || ch<0)
39203928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
39303928aee4356845252ac6b662d5c72c29903813eJake Slack                            _buffer.mark();
39403928aee4356845252ac6b662d5c72c29903813eJake Slack                            if (_responseStatus>=0)
39503928aee4356845252ac6b662d5c72c29903813eJake Slack                            {
39603928aee4356845252ac6b662d5c72c29903813eJake Slack                                _state=STATE_STATUS;
39703928aee4356845252ac6b662d5c72c29903813eJake Slack                                _responseStatus=ch-'0';
39803928aee4356845252ac6b662d5c72c29903813eJake Slack                            }
39903928aee4356845252ac6b662d5c72c29903813eJake Slack                            else
40003928aee4356845252ac6b662d5c72c29903813eJake Slack                                _state=STATE_URI;
40103928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
40203928aee4356845252ac6b662d5c72c29903813eJake Slack                        else if (ch < HttpTokens.SPACE)
40303928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
40403928aee4356845252ac6b662d5c72c29903813eJake Slack                            throw new HttpException(HttpStatus.BAD_REQUEST_400);
40503928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
40603928aee4356845252ac6b662d5c72c29903813eJake Slack                        break;
40703928aee4356845252ac6b662d5c72c29903813eJake Slack
40803928aee4356845252ac6b662d5c72c29903813eJake Slack                    case STATE_STATUS:
40903928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (ch == HttpTokens.SPACE)
41003928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
41103928aee4356845252ac6b662d5c72c29903813eJake Slack                            _tok1.update(_buffer.markIndex(), _buffer.getIndex() - 1);
41203928aee4356845252ac6b662d5c72c29903813eJake Slack                            _state=STATE_SPACE2;
41303928aee4356845252ac6b662d5c72c29903813eJake Slack                            continue;
41403928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
41503928aee4356845252ac6b662d5c72c29903813eJake Slack                        else if (ch>='0' && ch<='9')
41603928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
41703928aee4356845252ac6b662d5c72c29903813eJake Slack                            _responseStatus=_responseStatus*10+(ch-'0');
41803928aee4356845252ac6b662d5c72c29903813eJake Slack                            continue;
41903928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
42003928aee4356845252ac6b662d5c72c29903813eJake Slack                        else if (ch < HttpTokens.SPACE && ch>=0)
42103928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
42203928aee4356845252ac6b662d5c72c29903813eJake Slack                            _handler.startResponse(HttpMethods.CACHE.lookup(_tok0), _responseStatus, null);
42303928aee4356845252ac6b662d5c72c29903813eJake Slack                            _eol=ch;
42403928aee4356845252ac6b662d5c72c29903813eJake Slack                            _state=STATE_HEADER;
42503928aee4356845252ac6b662d5c72c29903813eJake Slack                            _tok0.setPutIndex(_tok0.getIndex());
42603928aee4356845252ac6b662d5c72c29903813eJake Slack                            _tok1.setPutIndex(_tok1.getIndex());
42703928aee4356845252ac6b662d5c72c29903813eJake Slack                            _multiLineValue=null;
42803928aee4356845252ac6b662d5c72c29903813eJake Slack                            continue;
42903928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
43003928aee4356845252ac6b662d5c72c29903813eJake Slack                        // not a digit, so must be a URI
43103928aee4356845252ac6b662d5c72c29903813eJake Slack                        _state=STATE_URI;
43203928aee4356845252ac6b662d5c72c29903813eJake Slack                        _responseStatus=-1;
43303928aee4356845252ac6b662d5c72c29903813eJake Slack                        break;
43403928aee4356845252ac6b662d5c72c29903813eJake Slack
43503928aee4356845252ac6b662d5c72c29903813eJake Slack                    case STATE_URI:
43603928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (ch == HttpTokens.SPACE)
43703928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
43803928aee4356845252ac6b662d5c72c29903813eJake Slack                            _tok1.update(_buffer.markIndex(), _buffer.getIndex() - 1);
43903928aee4356845252ac6b662d5c72c29903813eJake Slack                            _state=STATE_SPACE2;
44003928aee4356845252ac6b662d5c72c29903813eJake Slack                            continue;
44103928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
44203928aee4356845252ac6b662d5c72c29903813eJake Slack                        else if (ch < HttpTokens.SPACE && ch>=0)
44303928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
44403928aee4356845252ac6b662d5c72c29903813eJake Slack                            // HTTP/0.9
44503928aee4356845252ac6b662d5c72c29903813eJake Slack                            _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _buffer.sliceFromMark(), null);
44603928aee4356845252ac6b662d5c72c29903813eJake Slack                            _persistent=false;
44703928aee4356845252ac6b662d5c72c29903813eJake Slack                            _state=STATE_SEEKING_EOF;
44803928aee4356845252ac6b662d5c72c29903813eJake Slack                            _handler.headerComplete();
44903928aee4356845252ac6b662d5c72c29903813eJake Slack                            _handler.messageComplete(_contentPosition);
45003928aee4356845252ac6b662d5c72c29903813eJake Slack                            return 1;
45103928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
45203928aee4356845252ac6b662d5c72c29903813eJake Slack                        break;
45303928aee4356845252ac6b662d5c72c29903813eJake Slack
45403928aee4356845252ac6b662d5c72c29903813eJake Slack                    case STATE_SPACE2:
45503928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (ch > HttpTokens.SPACE || ch<0)
45603928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
45703928aee4356845252ac6b662d5c72c29903813eJake Slack                            _buffer.mark();
45803928aee4356845252ac6b662d5c72c29903813eJake Slack                            _state=STATE_FIELD2;
45903928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
46003928aee4356845252ac6b662d5c72c29903813eJake Slack                        else if (ch < HttpTokens.SPACE)
46103928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
46203928aee4356845252ac6b662d5c72c29903813eJake Slack                            if (_responseStatus>0)
46303928aee4356845252ac6b662d5c72c29903813eJake Slack                            {
46403928aee4356845252ac6b662d5c72c29903813eJake Slack                                _handler.startResponse(HttpMethods.CACHE.lookup(_tok0), _responseStatus, null);
46503928aee4356845252ac6b662d5c72c29903813eJake Slack                                _eol=ch;
46603928aee4356845252ac6b662d5c72c29903813eJake Slack                                _state=STATE_HEADER;
46703928aee4356845252ac6b662d5c72c29903813eJake Slack                                _tok0.setPutIndex(_tok0.getIndex());
46803928aee4356845252ac6b662d5c72c29903813eJake Slack                                _tok1.setPutIndex(_tok1.getIndex());
46903928aee4356845252ac6b662d5c72c29903813eJake Slack                                _multiLineValue=null;
47003928aee4356845252ac6b662d5c72c29903813eJake Slack                            }
47103928aee4356845252ac6b662d5c72c29903813eJake Slack                            else
47203928aee4356845252ac6b662d5c72c29903813eJake Slack                            {
47303928aee4356845252ac6b662d5c72c29903813eJake Slack                                // HTTP/0.9
47403928aee4356845252ac6b662d5c72c29903813eJake Slack                                _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _tok1, null);
47503928aee4356845252ac6b662d5c72c29903813eJake Slack                                _persistent=false;
47603928aee4356845252ac6b662d5c72c29903813eJake Slack                                _state=STATE_SEEKING_EOF;
47703928aee4356845252ac6b662d5c72c29903813eJake Slack                                _handler.headerComplete();
47803928aee4356845252ac6b662d5c72c29903813eJake Slack                                _handler.messageComplete(_contentPosition);
47903928aee4356845252ac6b662d5c72c29903813eJake Slack                                return 1;
48003928aee4356845252ac6b662d5c72c29903813eJake Slack                            }
48103928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
48203928aee4356845252ac6b662d5c72c29903813eJake Slack                        break;
48303928aee4356845252ac6b662d5c72c29903813eJake Slack
48403928aee4356845252ac6b662d5c72c29903813eJake Slack                    case STATE_FIELD2:
48503928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
48603928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
48703928aee4356845252ac6b662d5c72c29903813eJake Slack                            Buffer version;
48803928aee4356845252ac6b662d5c72c29903813eJake Slack                            if (_responseStatus>0)
48903928aee4356845252ac6b662d5c72c29903813eJake Slack                                _handler.startResponse(version=HttpVersions.CACHE.lookup(_tok0), _responseStatus,_buffer.sliceFromMark());
49003928aee4356845252ac6b662d5c72c29903813eJake Slack                            else
49103928aee4356845252ac6b662d5c72c29903813eJake Slack                                _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _tok1, version=HttpVersions.CACHE.lookup(_buffer.sliceFromMark()));
49203928aee4356845252ac6b662d5c72c29903813eJake Slack                            _eol=ch;
49303928aee4356845252ac6b662d5c72c29903813eJake Slack                            _persistent=HttpVersions.CACHE.getOrdinal(version)>=HttpVersions.HTTP_1_1_ORDINAL;
49403928aee4356845252ac6b662d5c72c29903813eJake Slack                            _state=STATE_HEADER;
49503928aee4356845252ac6b662d5c72c29903813eJake Slack                            _tok0.setPutIndex(_tok0.getIndex());
49603928aee4356845252ac6b662d5c72c29903813eJake Slack                            _tok1.setPutIndex(_tok1.getIndex());
49703928aee4356845252ac6b662d5c72c29903813eJake Slack                            _multiLineValue=null;
49803928aee4356845252ac6b662d5c72c29903813eJake Slack                            continue;
49903928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
50003928aee4356845252ac6b662d5c72c29903813eJake Slack                        break;
50103928aee4356845252ac6b662d5c72c29903813eJake Slack
50203928aee4356845252ac6b662d5c72c29903813eJake Slack                    case STATE_HEADER:
50303928aee4356845252ac6b662d5c72c29903813eJake Slack                        switch(ch)
50403928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
50503928aee4356845252ac6b662d5c72c29903813eJake Slack                            case HttpTokens.COLON:
50603928aee4356845252ac6b662d5c72c29903813eJake Slack                            case HttpTokens.SPACE:
50703928aee4356845252ac6b662d5c72c29903813eJake Slack                            case HttpTokens.TAB:
50803928aee4356845252ac6b662d5c72c29903813eJake Slack                            {
50903928aee4356845252ac6b662d5c72c29903813eJake Slack                                // header value without name - continuation?
51003928aee4356845252ac6b662d5c72c29903813eJake Slack                                _length=-1;
51103928aee4356845252ac6b662d5c72c29903813eJake Slack                                _state=STATE_HEADER_VALUE;
51203928aee4356845252ac6b662d5c72c29903813eJake Slack                                break;
51303928aee4356845252ac6b662d5c72c29903813eJake Slack                            }
51403928aee4356845252ac6b662d5c72c29903813eJake Slack
51503928aee4356845252ac6b662d5c72c29903813eJake Slack                            default:
51603928aee4356845252ac6b662d5c72c29903813eJake Slack                            {
51703928aee4356845252ac6b662d5c72c29903813eJake Slack                                // handler last header if any
51803928aee4356845252ac6b662d5c72c29903813eJake Slack                                if (_cached!=null || _tok0.length() > 0 || _tok1.length() > 0 || _multiLineValue != null)
51903928aee4356845252ac6b662d5c72c29903813eJake Slack                                {
52003928aee4356845252ac6b662d5c72c29903813eJake Slack                                    Buffer header=_cached!=null?_cached:HttpHeaders.CACHE.lookup(_tok0);
52103928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _cached=null;
52203928aee4356845252ac6b662d5c72c29903813eJake Slack                                    Buffer value=_multiLineValue == null ? _tok1 : new ByteArrayBuffer(_multiLineValue);
52303928aee4356845252ac6b662d5c72c29903813eJake Slack
52403928aee4356845252ac6b662d5c72c29903813eJake Slack                                    int ho=HttpHeaders.CACHE.getOrdinal(header);
52503928aee4356845252ac6b662d5c72c29903813eJake Slack                                    if (ho >= 0)
52603928aee4356845252ac6b662d5c72c29903813eJake Slack                                    {
52703928aee4356845252ac6b662d5c72c29903813eJake Slack                                        int vo;
52803928aee4356845252ac6b662d5c72c29903813eJake Slack
52903928aee4356845252ac6b662d5c72c29903813eJake Slack                                        switch (ho)
53003928aee4356845252ac6b662d5c72c29903813eJake Slack                                        {
53103928aee4356845252ac6b662d5c72c29903813eJake Slack                                            case HttpHeaders.CONTENT_LENGTH_ORDINAL:
53203928aee4356845252ac6b662d5c72c29903813eJake Slack                                                if (_contentLength != HttpTokens.CHUNKED_CONTENT )
53303928aee4356845252ac6b662d5c72c29903813eJake Slack                                                {
53403928aee4356845252ac6b662d5c72c29903813eJake Slack                                                    try
53503928aee4356845252ac6b662d5c72c29903813eJake Slack                                                    {
53603928aee4356845252ac6b662d5c72c29903813eJake Slack                                                        _contentLength=BufferUtil.toLong(value);
53703928aee4356845252ac6b662d5c72c29903813eJake Slack                                                    }
53803928aee4356845252ac6b662d5c72c29903813eJake Slack                                                    catch(NumberFormatException e)
53903928aee4356845252ac6b662d5c72c29903813eJake Slack                                                    {
54003928aee4356845252ac6b662d5c72c29903813eJake Slack                                                        LOG.ignore(e);
54103928aee4356845252ac6b662d5c72c29903813eJake Slack                                                        throw new HttpException(HttpStatus.BAD_REQUEST_400);
54203928aee4356845252ac6b662d5c72c29903813eJake Slack                                                    }
54303928aee4356845252ac6b662d5c72c29903813eJake Slack                                                    if (_contentLength <= 0)
54403928aee4356845252ac6b662d5c72c29903813eJake Slack                                                        _contentLength=HttpTokens.NO_CONTENT;
54503928aee4356845252ac6b662d5c72c29903813eJake Slack                                                }
54603928aee4356845252ac6b662d5c72c29903813eJake Slack                                                break;
54703928aee4356845252ac6b662d5c72c29903813eJake Slack
54803928aee4356845252ac6b662d5c72c29903813eJake Slack                                            case HttpHeaders.TRANSFER_ENCODING_ORDINAL:
54903928aee4356845252ac6b662d5c72c29903813eJake Slack                                                value=HttpHeaderValues.CACHE.lookup(value);
55003928aee4356845252ac6b662d5c72c29903813eJake Slack                                                vo=HttpHeaderValues.CACHE.getOrdinal(value);
55103928aee4356845252ac6b662d5c72c29903813eJake Slack                                                if (HttpHeaderValues.CHUNKED_ORDINAL == vo)
55203928aee4356845252ac6b662d5c72c29903813eJake Slack                                                    _contentLength=HttpTokens.CHUNKED_CONTENT;
55303928aee4356845252ac6b662d5c72c29903813eJake Slack                                                else
55403928aee4356845252ac6b662d5c72c29903813eJake Slack                                                {
55503928aee4356845252ac6b662d5c72c29903813eJake Slack                                                    String c=value.toString(StringUtil.__ISO_8859_1);
55603928aee4356845252ac6b662d5c72c29903813eJake Slack                                                    if (c.endsWith(HttpHeaderValues.CHUNKED))
55703928aee4356845252ac6b662d5c72c29903813eJake Slack                                                        _contentLength=HttpTokens.CHUNKED_CONTENT;
55803928aee4356845252ac6b662d5c72c29903813eJake Slack
55903928aee4356845252ac6b662d5c72c29903813eJake Slack                                                    else if (c.indexOf(HttpHeaderValues.CHUNKED) >= 0)
56003928aee4356845252ac6b662d5c72c29903813eJake Slack                                                        throw new HttpException(400,null);
56103928aee4356845252ac6b662d5c72c29903813eJake Slack                                                }
56203928aee4356845252ac6b662d5c72c29903813eJake Slack                                                break;
56303928aee4356845252ac6b662d5c72c29903813eJake Slack
56403928aee4356845252ac6b662d5c72c29903813eJake Slack                                            case HttpHeaders.CONNECTION_ORDINAL:
56503928aee4356845252ac6b662d5c72c29903813eJake Slack                                                switch(HttpHeaderValues.CACHE.getOrdinal(value))
56603928aee4356845252ac6b662d5c72c29903813eJake Slack                                                {
56703928aee4356845252ac6b662d5c72c29903813eJake Slack                                                    case HttpHeaderValues.CLOSE_ORDINAL:
56803928aee4356845252ac6b662d5c72c29903813eJake Slack                                                        _persistent=false;
56903928aee4356845252ac6b662d5c72c29903813eJake Slack                                                        break;
57003928aee4356845252ac6b662d5c72c29903813eJake Slack
57103928aee4356845252ac6b662d5c72c29903813eJake Slack                                                    case HttpHeaderValues.KEEP_ALIVE_ORDINAL:
57203928aee4356845252ac6b662d5c72c29903813eJake Slack                                                        _persistent=true;
57303928aee4356845252ac6b662d5c72c29903813eJake Slack                                                        break;
57403928aee4356845252ac6b662d5c72c29903813eJake Slack
57503928aee4356845252ac6b662d5c72c29903813eJake Slack                                                    case -1: // No match, may be multi valued
57603928aee4356845252ac6b662d5c72c29903813eJake Slack                                                    {
57703928aee4356845252ac6b662d5c72c29903813eJake Slack                                                        for (String v : value.toString().split(","))
57803928aee4356845252ac6b662d5c72c29903813eJake Slack                                                        {
57903928aee4356845252ac6b662d5c72c29903813eJake Slack                                                            switch(HttpHeaderValues.CACHE.getOrdinal(v.trim()))
58003928aee4356845252ac6b662d5c72c29903813eJake Slack                                                            {
58103928aee4356845252ac6b662d5c72c29903813eJake Slack                                                                case HttpHeaderValues.CLOSE_ORDINAL:
58203928aee4356845252ac6b662d5c72c29903813eJake Slack                                                                    _persistent=false;
58303928aee4356845252ac6b662d5c72c29903813eJake Slack                                                                    break;
58403928aee4356845252ac6b662d5c72c29903813eJake Slack
58503928aee4356845252ac6b662d5c72c29903813eJake Slack                                                                case HttpHeaderValues.KEEP_ALIVE_ORDINAL:
58603928aee4356845252ac6b662d5c72c29903813eJake Slack                                                                    _persistent=true;
58703928aee4356845252ac6b662d5c72c29903813eJake Slack                                                                    break;
58803928aee4356845252ac6b662d5c72c29903813eJake Slack                                                            }
58903928aee4356845252ac6b662d5c72c29903813eJake Slack                                                        }
59003928aee4356845252ac6b662d5c72c29903813eJake Slack                                                        break;
59103928aee4356845252ac6b662d5c72c29903813eJake Slack                                                    }
59203928aee4356845252ac6b662d5c72c29903813eJake Slack                                                }
59303928aee4356845252ac6b662d5c72c29903813eJake Slack                                        }
59403928aee4356845252ac6b662d5c72c29903813eJake Slack                                    }
59503928aee4356845252ac6b662d5c72c29903813eJake Slack
59603928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _handler.parsedHeader(header, value);
59703928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _tok0.setPutIndex(_tok0.getIndex());
59803928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _tok1.setPutIndex(_tok1.getIndex());
59903928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _multiLineValue=null;
60003928aee4356845252ac6b662d5c72c29903813eJake Slack                                }
60103928aee4356845252ac6b662d5c72c29903813eJake Slack                                _buffer.setMarkIndex(-1);
60203928aee4356845252ac6b662d5c72c29903813eJake Slack
60303928aee4356845252ac6b662d5c72c29903813eJake Slack                                // now handle ch
60403928aee4356845252ac6b662d5c72c29903813eJake Slack                                if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
60503928aee4356845252ac6b662d5c72c29903813eJake Slack                                {
60603928aee4356845252ac6b662d5c72c29903813eJake Slack                                    // is it a response that cannot have a body?
60703928aee4356845252ac6b662d5c72c29903813eJake Slack                                    if (_responseStatus > 0  && // response
60803928aee4356845252ac6b662d5c72c29903813eJake Slack                                       (_responseStatus == 304  || // not-modified response
60903928aee4356845252ac6b662d5c72c29903813eJake Slack                                        _responseStatus == 204 || // no-content response
61003928aee4356845252ac6b662d5c72c29903813eJake Slack                                        _responseStatus < 200)) // 1xx response
61103928aee4356845252ac6b662d5c72c29903813eJake Slack                                        _contentLength=HttpTokens.NO_CONTENT; // ignore any other headers set
61203928aee4356845252ac6b662d5c72c29903813eJake Slack                                    // else if we don't know framing
61303928aee4356845252ac6b662d5c72c29903813eJake Slack                                    else if (_contentLength == HttpTokens.UNKNOWN_CONTENT)
61403928aee4356845252ac6b662d5c72c29903813eJake Slack                                    {
61503928aee4356845252ac6b662d5c72c29903813eJake Slack                                        if (_responseStatus == 0  // request
61603928aee4356845252ac6b662d5c72c29903813eJake Slack                                                || _responseStatus == 304 // not-modified response
61703928aee4356845252ac6b662d5c72c29903813eJake Slack                                                || _responseStatus == 204 // no-content response
61803928aee4356845252ac6b662d5c72c29903813eJake Slack                                                || _responseStatus < 200) // 1xx response
61903928aee4356845252ac6b662d5c72c29903813eJake Slack                                            _contentLength=HttpTokens.NO_CONTENT;
62003928aee4356845252ac6b662d5c72c29903813eJake Slack                                        else
62103928aee4356845252ac6b662d5c72c29903813eJake Slack                                            _contentLength=HttpTokens.EOF_CONTENT;
62203928aee4356845252ac6b662d5c72c29903813eJake Slack                                    }
62303928aee4356845252ac6b662d5c72c29903813eJake Slack
62403928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _contentPosition=0;
62503928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _eol=ch;
62603928aee4356845252ac6b662d5c72c29903813eJake Slack                                    if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED)
62703928aee4356845252ac6b662d5c72c29903813eJake Slack                                        _eol=_buffer.get();
62803928aee4356845252ac6b662d5c72c29903813eJake Slack
62903928aee4356845252ac6b662d5c72c29903813eJake Slack                                    // We convert _contentLength to an int for this switch statement because
63003928aee4356845252ac6b662d5c72c29903813eJake Slack                                    // we don't care about the amount of data available just whether there is some.
63103928aee4356845252ac6b662d5c72c29903813eJake Slack                                    switch (_contentLength > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) _contentLength)
63203928aee4356845252ac6b662d5c72c29903813eJake Slack                                    {
63303928aee4356845252ac6b662d5c72c29903813eJake Slack                                        case HttpTokens.EOF_CONTENT:
63403928aee4356845252ac6b662d5c72c29903813eJake Slack                                            _state=STATE_EOF_CONTENT;
63503928aee4356845252ac6b662d5c72c29903813eJake Slack                                            _handler.headerComplete(); // May recurse here !
63603928aee4356845252ac6b662d5c72c29903813eJake Slack                                            break;
63703928aee4356845252ac6b662d5c72c29903813eJake Slack
63803928aee4356845252ac6b662d5c72c29903813eJake Slack                                        case HttpTokens.CHUNKED_CONTENT:
63903928aee4356845252ac6b662d5c72c29903813eJake Slack                                            _state=STATE_CHUNKED_CONTENT;
64003928aee4356845252ac6b662d5c72c29903813eJake Slack                                            _handler.headerComplete(); // May recurse here !
64103928aee4356845252ac6b662d5c72c29903813eJake Slack                                            break;
64203928aee4356845252ac6b662d5c72c29903813eJake Slack
64303928aee4356845252ac6b662d5c72c29903813eJake Slack                                        case HttpTokens.NO_CONTENT:
64403928aee4356845252ac6b662d5c72c29903813eJake Slack                                            _handler.headerComplete();
64503928aee4356845252ac6b662d5c72c29903813eJake Slack                                            _state=_persistent||(_responseStatus>=100&&_responseStatus<200)?STATE_END:STATE_SEEKING_EOF;
64603928aee4356845252ac6b662d5c72c29903813eJake Slack                                            _handler.messageComplete(_contentPosition);
64703928aee4356845252ac6b662d5c72c29903813eJake Slack                                            return 1;
64803928aee4356845252ac6b662d5c72c29903813eJake Slack
64903928aee4356845252ac6b662d5c72c29903813eJake Slack                                        default:
65003928aee4356845252ac6b662d5c72c29903813eJake Slack                                            _state=STATE_CONTENT;
65103928aee4356845252ac6b662d5c72c29903813eJake Slack                                            _handler.headerComplete(); // May recurse here !
65203928aee4356845252ac6b662d5c72c29903813eJake Slack                                            break;
65303928aee4356845252ac6b662d5c72c29903813eJake Slack                                    }
65403928aee4356845252ac6b662d5c72c29903813eJake Slack                                    return 1;
65503928aee4356845252ac6b662d5c72c29903813eJake Slack                                }
65603928aee4356845252ac6b662d5c72c29903813eJake Slack                                else
65703928aee4356845252ac6b662d5c72c29903813eJake Slack                                {
65803928aee4356845252ac6b662d5c72c29903813eJake Slack                                    // New header
65903928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _length=1;
66003928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _buffer.mark();
66103928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _state=STATE_HEADER_NAME;
66203928aee4356845252ac6b662d5c72c29903813eJake Slack
66303928aee4356845252ac6b662d5c72c29903813eJake Slack                                    // try cached name!
66403928aee4356845252ac6b662d5c72c29903813eJake Slack                                    if (array!=null)
66503928aee4356845252ac6b662d5c72c29903813eJake Slack                                    {
66603928aee4356845252ac6b662d5c72c29903813eJake Slack                                        _cached=HttpHeaders.CACHE.getBest(array, _buffer.markIndex(), length+1);
66703928aee4356845252ac6b662d5c72c29903813eJake Slack
66803928aee4356845252ac6b662d5c72c29903813eJake Slack                                        if (_cached!=null)
66903928aee4356845252ac6b662d5c72c29903813eJake Slack                                        {
67003928aee4356845252ac6b662d5c72c29903813eJake Slack                                            _length=_cached.length();
67103928aee4356845252ac6b662d5c72c29903813eJake Slack                                            _buffer.setGetIndex(_buffer.markIndex()+_length);
67203928aee4356845252ac6b662d5c72c29903813eJake Slack                                            length=_buffer.length();
67303928aee4356845252ac6b662d5c72c29903813eJake Slack                                        }
67403928aee4356845252ac6b662d5c72c29903813eJake Slack                                    }
67503928aee4356845252ac6b662d5c72c29903813eJake Slack                                }
67603928aee4356845252ac6b662d5c72c29903813eJake Slack                            }
67703928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
67803928aee4356845252ac6b662d5c72c29903813eJake Slack
67903928aee4356845252ac6b662d5c72c29903813eJake Slack                        break;
68003928aee4356845252ac6b662d5c72c29903813eJake Slack
68103928aee4356845252ac6b662d5c72c29903813eJake Slack                    case STATE_HEADER_NAME:
68203928aee4356845252ac6b662d5c72c29903813eJake Slack                        switch(ch)
68303928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
68403928aee4356845252ac6b662d5c72c29903813eJake Slack                            case HttpTokens.CARRIAGE_RETURN:
68503928aee4356845252ac6b662d5c72c29903813eJake Slack                            case HttpTokens.LINE_FEED:
68603928aee4356845252ac6b662d5c72c29903813eJake Slack                                if (_length > 0)
68703928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length);
68803928aee4356845252ac6b662d5c72c29903813eJake Slack                                _eol=ch;
68903928aee4356845252ac6b662d5c72c29903813eJake Slack                                _state=STATE_HEADER;
69003928aee4356845252ac6b662d5c72c29903813eJake Slack                                break;
69103928aee4356845252ac6b662d5c72c29903813eJake Slack                            case HttpTokens.COLON:
69203928aee4356845252ac6b662d5c72c29903813eJake Slack                                if (_length > 0 && _cached==null)
69303928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length);
69403928aee4356845252ac6b662d5c72c29903813eJake Slack                                _length=-1;
69503928aee4356845252ac6b662d5c72c29903813eJake Slack                                _state=STATE_HEADER_VALUE;
69603928aee4356845252ac6b662d5c72c29903813eJake Slack                                break;
69703928aee4356845252ac6b662d5c72c29903813eJake Slack                            case HttpTokens.SPACE:
69803928aee4356845252ac6b662d5c72c29903813eJake Slack                            case HttpTokens.TAB:
69903928aee4356845252ac6b662d5c72c29903813eJake Slack                                break;
70003928aee4356845252ac6b662d5c72c29903813eJake Slack                            default:
70103928aee4356845252ac6b662d5c72c29903813eJake Slack                            {
70203928aee4356845252ac6b662d5c72c29903813eJake Slack                                _cached=null;
70303928aee4356845252ac6b662d5c72c29903813eJake Slack                                if (_length == -1)
70403928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _buffer.mark();
70503928aee4356845252ac6b662d5c72c29903813eJake Slack                                _length=_buffer.getIndex() - _buffer.markIndex();
70603928aee4356845252ac6b662d5c72c29903813eJake Slack                                _state=STATE_HEADER_IN_NAME;
70703928aee4356845252ac6b662d5c72c29903813eJake Slack                            }
70803928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
70903928aee4356845252ac6b662d5c72c29903813eJake Slack
71003928aee4356845252ac6b662d5c72c29903813eJake Slack                        break;
71103928aee4356845252ac6b662d5c72c29903813eJake Slack
71203928aee4356845252ac6b662d5c72c29903813eJake Slack                    case STATE_HEADER_IN_NAME:
71303928aee4356845252ac6b662d5c72c29903813eJake Slack                        switch(ch)
71403928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
71503928aee4356845252ac6b662d5c72c29903813eJake Slack                            case HttpTokens.CARRIAGE_RETURN:
71603928aee4356845252ac6b662d5c72c29903813eJake Slack                            case HttpTokens.LINE_FEED:
71703928aee4356845252ac6b662d5c72c29903813eJake Slack                                if (_length > 0)
71803928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length);
71903928aee4356845252ac6b662d5c72c29903813eJake Slack                                _eol=ch;
72003928aee4356845252ac6b662d5c72c29903813eJake Slack                                _state=STATE_HEADER;
72103928aee4356845252ac6b662d5c72c29903813eJake Slack                                break;
72203928aee4356845252ac6b662d5c72c29903813eJake Slack                            case HttpTokens.COLON:
72303928aee4356845252ac6b662d5c72c29903813eJake Slack                                if (_length > 0 && _cached==null)
72403928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length);
72503928aee4356845252ac6b662d5c72c29903813eJake Slack                                _length=-1;
72603928aee4356845252ac6b662d5c72c29903813eJake Slack                                _state=STATE_HEADER_VALUE;
72703928aee4356845252ac6b662d5c72c29903813eJake Slack                                break;
72803928aee4356845252ac6b662d5c72c29903813eJake Slack                            case HttpTokens.SPACE:
72903928aee4356845252ac6b662d5c72c29903813eJake Slack                            case HttpTokens.TAB:
73003928aee4356845252ac6b662d5c72c29903813eJake Slack                                _state=STATE_HEADER_NAME;
73103928aee4356845252ac6b662d5c72c29903813eJake Slack                                break;
73203928aee4356845252ac6b662d5c72c29903813eJake Slack                            default:
73303928aee4356845252ac6b662d5c72c29903813eJake Slack                            {
73403928aee4356845252ac6b662d5c72c29903813eJake Slack                                _cached=null;
73503928aee4356845252ac6b662d5c72c29903813eJake Slack                                _length++;
73603928aee4356845252ac6b662d5c72c29903813eJake Slack                            }
73703928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
73803928aee4356845252ac6b662d5c72c29903813eJake Slack                        break;
73903928aee4356845252ac6b662d5c72c29903813eJake Slack
74003928aee4356845252ac6b662d5c72c29903813eJake Slack                    case STATE_HEADER_VALUE:
74103928aee4356845252ac6b662d5c72c29903813eJake Slack                        switch(ch)
74203928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
74303928aee4356845252ac6b662d5c72c29903813eJake Slack                            case HttpTokens.CARRIAGE_RETURN:
74403928aee4356845252ac6b662d5c72c29903813eJake Slack                            case HttpTokens.LINE_FEED:
74503928aee4356845252ac6b662d5c72c29903813eJake Slack                                if (_length > 0)
74603928aee4356845252ac6b662d5c72c29903813eJake Slack                                {
74703928aee4356845252ac6b662d5c72c29903813eJake Slack                                    if (_tok1.length() == 0)
74803928aee4356845252ac6b662d5c72c29903813eJake Slack                                        _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length);
74903928aee4356845252ac6b662d5c72c29903813eJake Slack                                    else
75003928aee4356845252ac6b662d5c72c29903813eJake Slack                                    {
75103928aee4356845252ac6b662d5c72c29903813eJake Slack                                        // Continuation line!
75203928aee4356845252ac6b662d5c72c29903813eJake Slack                                        if (_multiLineValue == null) _multiLineValue=_tok1.toString(StringUtil.__ISO_8859_1);
75303928aee4356845252ac6b662d5c72c29903813eJake Slack                                        _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length);
75403928aee4356845252ac6b662d5c72c29903813eJake Slack                                        _multiLineValue += " " + _tok1.toString(StringUtil.__ISO_8859_1);
75503928aee4356845252ac6b662d5c72c29903813eJake Slack                                    }
75603928aee4356845252ac6b662d5c72c29903813eJake Slack                                }
75703928aee4356845252ac6b662d5c72c29903813eJake Slack                                _eol=ch;
75803928aee4356845252ac6b662d5c72c29903813eJake Slack                                _state=STATE_HEADER;
75903928aee4356845252ac6b662d5c72c29903813eJake Slack                                break;
76003928aee4356845252ac6b662d5c72c29903813eJake Slack                            case HttpTokens.SPACE:
76103928aee4356845252ac6b662d5c72c29903813eJake Slack                            case HttpTokens.TAB:
76203928aee4356845252ac6b662d5c72c29903813eJake Slack                                break;
76303928aee4356845252ac6b662d5c72c29903813eJake Slack                            default:
76403928aee4356845252ac6b662d5c72c29903813eJake Slack                            {
76503928aee4356845252ac6b662d5c72c29903813eJake Slack                                if (_length == -1)
76603928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _buffer.mark();
76703928aee4356845252ac6b662d5c72c29903813eJake Slack                                _length=_buffer.getIndex() - _buffer.markIndex();
76803928aee4356845252ac6b662d5c72c29903813eJake Slack                                _state=STATE_HEADER_IN_VALUE;
76903928aee4356845252ac6b662d5c72c29903813eJake Slack                            }
77003928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
77103928aee4356845252ac6b662d5c72c29903813eJake Slack                        break;
77203928aee4356845252ac6b662d5c72c29903813eJake Slack
77303928aee4356845252ac6b662d5c72c29903813eJake Slack                    case STATE_HEADER_IN_VALUE:
77403928aee4356845252ac6b662d5c72c29903813eJake Slack                        switch(ch)
77503928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
77603928aee4356845252ac6b662d5c72c29903813eJake Slack                            case HttpTokens.CARRIAGE_RETURN:
77703928aee4356845252ac6b662d5c72c29903813eJake Slack                            case HttpTokens.LINE_FEED:
77803928aee4356845252ac6b662d5c72c29903813eJake Slack                                if (_length > 0)
77903928aee4356845252ac6b662d5c72c29903813eJake Slack                                {
78003928aee4356845252ac6b662d5c72c29903813eJake Slack                                    if (_tok1.length() == 0)
78103928aee4356845252ac6b662d5c72c29903813eJake Slack                                        _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length);
78203928aee4356845252ac6b662d5c72c29903813eJake Slack                                    else
78303928aee4356845252ac6b662d5c72c29903813eJake Slack                                    {
78403928aee4356845252ac6b662d5c72c29903813eJake Slack                                        // Continuation line!
78503928aee4356845252ac6b662d5c72c29903813eJake Slack                                        if (_multiLineValue == null) _multiLineValue=_tok1.toString(StringUtil.__ISO_8859_1);
78603928aee4356845252ac6b662d5c72c29903813eJake Slack                                        _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length);
78703928aee4356845252ac6b662d5c72c29903813eJake Slack                                        _multiLineValue += " " + _tok1.toString(StringUtil.__ISO_8859_1);
78803928aee4356845252ac6b662d5c72c29903813eJake Slack                                    }
78903928aee4356845252ac6b662d5c72c29903813eJake Slack                                }
79003928aee4356845252ac6b662d5c72c29903813eJake Slack                                _eol=ch;
79103928aee4356845252ac6b662d5c72c29903813eJake Slack                                _state=STATE_HEADER;
79203928aee4356845252ac6b662d5c72c29903813eJake Slack                                break;
79303928aee4356845252ac6b662d5c72c29903813eJake Slack                            case HttpTokens.SPACE:
79403928aee4356845252ac6b662d5c72c29903813eJake Slack                            case HttpTokens.TAB:
79503928aee4356845252ac6b662d5c72c29903813eJake Slack                                _state=STATE_HEADER_VALUE;
79603928aee4356845252ac6b662d5c72c29903813eJake Slack                                break;
79703928aee4356845252ac6b662d5c72c29903813eJake Slack                            default:
79803928aee4356845252ac6b662d5c72c29903813eJake Slack                                _length++;
79903928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
80003928aee4356845252ac6b662d5c72c29903813eJake Slack                        break;
80103928aee4356845252ac6b662d5c72c29903813eJake Slack                }
80203928aee4356845252ac6b662d5c72c29903813eJake Slack            } // end of HEADER states loop
80303928aee4356845252ac6b662d5c72c29903813eJake Slack
80403928aee4356845252ac6b662d5c72c29903813eJake Slack            // ==========================
80503928aee4356845252ac6b662d5c72c29903813eJake Slack
80603928aee4356845252ac6b662d5c72c29903813eJake Slack            // Handle HEAD response
80703928aee4356845252ac6b662d5c72c29903813eJake Slack            if (_responseStatus>0 && _headResponse)
80803928aee4356845252ac6b662d5c72c29903813eJake Slack            {
80903928aee4356845252ac6b662d5c72c29903813eJake Slack                _state=_persistent||(_responseStatus>=100&&_responseStatus<200)?STATE_END:STATE_SEEKING_EOF;
81003928aee4356845252ac6b662d5c72c29903813eJake Slack                _handler.messageComplete(_contentLength);
81103928aee4356845252ac6b662d5c72c29903813eJake Slack            }
81203928aee4356845252ac6b662d5c72c29903813eJake Slack
81303928aee4356845252ac6b662d5c72c29903813eJake Slack
81403928aee4356845252ac6b662d5c72c29903813eJake Slack            // ==========================
81503928aee4356845252ac6b662d5c72c29903813eJake Slack
81603928aee4356845252ac6b662d5c72c29903813eJake Slack            // Handle _content
81703928aee4356845252ac6b662d5c72c29903813eJake Slack            length=_buffer.length();
81803928aee4356845252ac6b662d5c72c29903813eJake Slack            Buffer chunk;
81903928aee4356845252ac6b662d5c72c29903813eJake Slack            last=_state;
82003928aee4356845252ac6b662d5c72c29903813eJake Slack            while (_state > STATE_END && length > 0)
82103928aee4356845252ac6b662d5c72c29903813eJake Slack            {
82203928aee4356845252ac6b662d5c72c29903813eJake Slack                if (last!=_state)
82303928aee4356845252ac6b662d5c72c29903813eJake Slack                {
82403928aee4356845252ac6b662d5c72c29903813eJake Slack                    progress++;
82503928aee4356845252ac6b662d5c72c29903813eJake Slack                    last=_state;
82603928aee4356845252ac6b662d5c72c29903813eJake Slack                }
82703928aee4356845252ac6b662d5c72c29903813eJake Slack
82803928aee4356845252ac6b662d5c72c29903813eJake Slack                if (_eol == HttpTokens.CARRIAGE_RETURN && _buffer.peek() == HttpTokens.LINE_FEED)
82903928aee4356845252ac6b662d5c72c29903813eJake Slack                {
83003928aee4356845252ac6b662d5c72c29903813eJake Slack                    _eol=_buffer.get();
83103928aee4356845252ac6b662d5c72c29903813eJake Slack                    length=_buffer.length();
83203928aee4356845252ac6b662d5c72c29903813eJake Slack                    continue;
83303928aee4356845252ac6b662d5c72c29903813eJake Slack                }
83403928aee4356845252ac6b662d5c72c29903813eJake Slack                _eol=0;
83503928aee4356845252ac6b662d5c72c29903813eJake Slack                switch (_state)
83603928aee4356845252ac6b662d5c72c29903813eJake Slack                {
83703928aee4356845252ac6b662d5c72c29903813eJake Slack                    case STATE_EOF_CONTENT:
83803928aee4356845252ac6b662d5c72c29903813eJake Slack                        chunk=_buffer.get(_buffer.length());
83903928aee4356845252ac6b662d5c72c29903813eJake Slack                        _contentPosition += chunk.length();
84003928aee4356845252ac6b662d5c72c29903813eJake Slack                        _contentView.update(chunk);
84103928aee4356845252ac6b662d5c72c29903813eJake Slack                        _handler.content(chunk); // May recurse here
84203928aee4356845252ac6b662d5c72c29903813eJake Slack                        // TODO adjust the _buffer to keep unconsumed content
84303928aee4356845252ac6b662d5c72c29903813eJake Slack                        return 1;
84403928aee4356845252ac6b662d5c72c29903813eJake Slack
84503928aee4356845252ac6b662d5c72c29903813eJake Slack                    case STATE_CONTENT:
84603928aee4356845252ac6b662d5c72c29903813eJake Slack                    {
84703928aee4356845252ac6b662d5c72c29903813eJake Slack                        long remaining=_contentLength - _contentPosition;
84803928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (remaining == 0)
84903928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
85003928aee4356845252ac6b662d5c72c29903813eJake Slack                            _state=_persistent?STATE_END:STATE_SEEKING_EOF;
85103928aee4356845252ac6b662d5c72c29903813eJake Slack                            _handler.messageComplete(_contentPosition);
85203928aee4356845252ac6b662d5c72c29903813eJake Slack                            return 1;
85303928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
85403928aee4356845252ac6b662d5c72c29903813eJake Slack
85503928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (length > remaining)
85603928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
85703928aee4356845252ac6b662d5c72c29903813eJake Slack                            // We can cast reamining to an int as we know that it is smaller than
85803928aee4356845252ac6b662d5c72c29903813eJake Slack                            // or equal to length which is already an int.
85903928aee4356845252ac6b662d5c72c29903813eJake Slack                            length=(int)remaining;
86003928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
86103928aee4356845252ac6b662d5c72c29903813eJake Slack
86203928aee4356845252ac6b662d5c72c29903813eJake Slack                        chunk=_buffer.get(length);
86303928aee4356845252ac6b662d5c72c29903813eJake Slack                        _contentPosition += chunk.length();
86403928aee4356845252ac6b662d5c72c29903813eJake Slack                        _contentView.update(chunk);
86503928aee4356845252ac6b662d5c72c29903813eJake Slack                        _handler.content(chunk); // May recurse here
86603928aee4356845252ac6b662d5c72c29903813eJake Slack
86703928aee4356845252ac6b662d5c72c29903813eJake Slack                        if(_contentPosition == _contentLength)
86803928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
86903928aee4356845252ac6b662d5c72c29903813eJake Slack                            _state=_persistent?STATE_END:STATE_SEEKING_EOF;
87003928aee4356845252ac6b662d5c72c29903813eJake Slack                            _handler.messageComplete(_contentPosition);
87103928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
87203928aee4356845252ac6b662d5c72c29903813eJake Slack                        // TODO adjust the _buffer to keep unconsumed content
87303928aee4356845252ac6b662d5c72c29903813eJake Slack                        return 1;
87403928aee4356845252ac6b662d5c72c29903813eJake Slack                    }
87503928aee4356845252ac6b662d5c72c29903813eJake Slack
87603928aee4356845252ac6b662d5c72c29903813eJake Slack                    case STATE_CHUNKED_CONTENT:
87703928aee4356845252ac6b662d5c72c29903813eJake Slack                    {
87803928aee4356845252ac6b662d5c72c29903813eJake Slack                        ch=_buffer.peek();
87903928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
88003928aee4356845252ac6b662d5c72c29903813eJake Slack                            _eol=_buffer.get();
88103928aee4356845252ac6b662d5c72c29903813eJake Slack                        else if (ch <= HttpTokens.SPACE)
88203928aee4356845252ac6b662d5c72c29903813eJake Slack                            _buffer.get();
88303928aee4356845252ac6b662d5c72c29903813eJake Slack                        else
88403928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
88503928aee4356845252ac6b662d5c72c29903813eJake Slack                            _chunkLength=0;
88603928aee4356845252ac6b662d5c72c29903813eJake Slack                            _chunkPosition=0;
88703928aee4356845252ac6b662d5c72c29903813eJake Slack                            _state=STATE_CHUNK_SIZE;
88803928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
88903928aee4356845252ac6b662d5c72c29903813eJake Slack                        break;
89003928aee4356845252ac6b662d5c72c29903813eJake Slack                    }
89103928aee4356845252ac6b662d5c72c29903813eJake Slack
89203928aee4356845252ac6b662d5c72c29903813eJake Slack                    case STATE_CHUNK_SIZE:
89303928aee4356845252ac6b662d5c72c29903813eJake Slack                    {
89403928aee4356845252ac6b662d5c72c29903813eJake Slack                        ch=_buffer.get();
89503928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
89603928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
89703928aee4356845252ac6b662d5c72c29903813eJake Slack                            _eol=ch;
89803928aee4356845252ac6b662d5c72c29903813eJake Slack
89903928aee4356845252ac6b662d5c72c29903813eJake Slack                            if (_chunkLength == 0)
90003928aee4356845252ac6b662d5c72c29903813eJake Slack                            {
90103928aee4356845252ac6b662d5c72c29903813eJake Slack                                if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED)
90203928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _eol=_buffer.get();
90303928aee4356845252ac6b662d5c72c29903813eJake Slack                                _state=_persistent?STATE_END:STATE_SEEKING_EOF;
90403928aee4356845252ac6b662d5c72c29903813eJake Slack                                _handler.messageComplete(_contentPosition);
90503928aee4356845252ac6b662d5c72c29903813eJake Slack                                return 1;
90603928aee4356845252ac6b662d5c72c29903813eJake Slack                            }
90703928aee4356845252ac6b662d5c72c29903813eJake Slack                            else
90803928aee4356845252ac6b662d5c72c29903813eJake Slack                                _state=STATE_CHUNK;
90903928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
91003928aee4356845252ac6b662d5c72c29903813eJake Slack                        else if (ch <= HttpTokens.SPACE || ch == HttpTokens.SEMI_COLON)
91103928aee4356845252ac6b662d5c72c29903813eJake Slack                            _state=STATE_CHUNK_PARAMS;
91203928aee4356845252ac6b662d5c72c29903813eJake Slack                        else if (ch >= '0' && ch <= '9')
91303928aee4356845252ac6b662d5c72c29903813eJake Slack                            _chunkLength=_chunkLength * 16 + (ch - '0');
91403928aee4356845252ac6b662d5c72c29903813eJake Slack                        else if (ch >= 'a' && ch <= 'f')
91503928aee4356845252ac6b662d5c72c29903813eJake Slack                            _chunkLength=_chunkLength * 16 + (10 + ch - 'a');
91603928aee4356845252ac6b662d5c72c29903813eJake Slack                        else if (ch >= 'A' && ch <= 'F')
91703928aee4356845252ac6b662d5c72c29903813eJake Slack                            _chunkLength=_chunkLength * 16 + (10 + ch - 'A');
91803928aee4356845252ac6b662d5c72c29903813eJake Slack                        else
91903928aee4356845252ac6b662d5c72c29903813eJake Slack                            throw new IOException("bad chunk char: " + ch);
92003928aee4356845252ac6b662d5c72c29903813eJake Slack                        break;
92103928aee4356845252ac6b662d5c72c29903813eJake Slack                    }
92203928aee4356845252ac6b662d5c72c29903813eJake Slack
92303928aee4356845252ac6b662d5c72c29903813eJake Slack                    case STATE_CHUNK_PARAMS:
92403928aee4356845252ac6b662d5c72c29903813eJake Slack                    {
92503928aee4356845252ac6b662d5c72c29903813eJake Slack                        ch=_buffer.get();
92603928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
92703928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
92803928aee4356845252ac6b662d5c72c29903813eJake Slack                            _eol=ch;
92903928aee4356845252ac6b662d5c72c29903813eJake Slack                            if (_chunkLength == 0)
93003928aee4356845252ac6b662d5c72c29903813eJake Slack                            {
93103928aee4356845252ac6b662d5c72c29903813eJake Slack                                if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED)
93203928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _eol=_buffer.get();
93303928aee4356845252ac6b662d5c72c29903813eJake Slack                                _state=_persistent?STATE_END:STATE_SEEKING_EOF;
93403928aee4356845252ac6b662d5c72c29903813eJake Slack                                _handler.messageComplete(_contentPosition);
93503928aee4356845252ac6b662d5c72c29903813eJake Slack                                return 1;
93603928aee4356845252ac6b662d5c72c29903813eJake Slack                            }
93703928aee4356845252ac6b662d5c72c29903813eJake Slack                            else
93803928aee4356845252ac6b662d5c72c29903813eJake Slack                                _state=STATE_CHUNK;
93903928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
94003928aee4356845252ac6b662d5c72c29903813eJake Slack                        break;
94103928aee4356845252ac6b662d5c72c29903813eJake Slack                    }
94203928aee4356845252ac6b662d5c72c29903813eJake Slack
94303928aee4356845252ac6b662d5c72c29903813eJake Slack                    case STATE_CHUNK:
94403928aee4356845252ac6b662d5c72c29903813eJake Slack                    {
94503928aee4356845252ac6b662d5c72c29903813eJake Slack                        int remaining=_chunkLength - _chunkPosition;
94603928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (remaining == 0)
94703928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
94803928aee4356845252ac6b662d5c72c29903813eJake Slack                            _state=STATE_CHUNKED_CONTENT;
94903928aee4356845252ac6b662d5c72c29903813eJake Slack                            break;
95003928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
95103928aee4356845252ac6b662d5c72c29903813eJake Slack                        else if (length > remaining)
95203928aee4356845252ac6b662d5c72c29903813eJake Slack                            length=remaining;
95303928aee4356845252ac6b662d5c72c29903813eJake Slack                        chunk=_buffer.get(length);
95403928aee4356845252ac6b662d5c72c29903813eJake Slack                        _contentPosition += chunk.length();
95503928aee4356845252ac6b662d5c72c29903813eJake Slack                        _chunkPosition += chunk.length();
95603928aee4356845252ac6b662d5c72c29903813eJake Slack                        _contentView.update(chunk);
95703928aee4356845252ac6b662d5c72c29903813eJake Slack                        _handler.content(chunk); // May recurse here
95803928aee4356845252ac6b662d5c72c29903813eJake Slack                        // TODO adjust the _buffer to keep unconsumed content
95903928aee4356845252ac6b662d5c72c29903813eJake Slack                        return 1;
96003928aee4356845252ac6b662d5c72c29903813eJake Slack                    }
96103928aee4356845252ac6b662d5c72c29903813eJake Slack
96203928aee4356845252ac6b662d5c72c29903813eJake Slack                    case STATE_SEEKING_EOF:
96303928aee4356845252ac6b662d5c72c29903813eJake Slack                    {
96403928aee4356845252ac6b662d5c72c29903813eJake Slack                        // Close if there is more data than CRLF
96503928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (_buffer.length()>2)
96603928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
96703928aee4356845252ac6b662d5c72c29903813eJake Slack                            _state=STATE_END;
96803928aee4356845252ac6b662d5c72c29903813eJake Slack                            _endp.close();
96903928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
97003928aee4356845252ac6b662d5c72c29903813eJake Slack                        else
97103928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
97203928aee4356845252ac6b662d5c72c29903813eJake Slack                            // or if the data is not white space
97303928aee4356845252ac6b662d5c72c29903813eJake Slack                            while (_buffer.length()>0)
97403928aee4356845252ac6b662d5c72c29903813eJake Slack                                if (!Character.isWhitespace(_buffer.get()))
97503928aee4356845252ac6b662d5c72c29903813eJake Slack                                {
97603928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _state=STATE_END;
97703928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _endp.close();
97803928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _buffer.clear();
97903928aee4356845252ac6b662d5c72c29903813eJake Slack                                }
98003928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
98103928aee4356845252ac6b662d5c72c29903813eJake Slack
98203928aee4356845252ac6b662d5c72c29903813eJake Slack                        _buffer.clear();
98303928aee4356845252ac6b662d5c72c29903813eJake Slack                        break;
98403928aee4356845252ac6b662d5c72c29903813eJake Slack                    }
98503928aee4356845252ac6b662d5c72c29903813eJake Slack                }
98603928aee4356845252ac6b662d5c72c29903813eJake Slack
98703928aee4356845252ac6b662d5c72c29903813eJake Slack                length=_buffer.length();
98803928aee4356845252ac6b662d5c72c29903813eJake Slack            }
98903928aee4356845252ac6b662d5c72c29903813eJake Slack
99003928aee4356845252ac6b662d5c72c29903813eJake Slack            return progress;
99103928aee4356845252ac6b662d5c72c29903813eJake Slack        }
99203928aee4356845252ac6b662d5c72c29903813eJake Slack        catch(HttpException e)
99303928aee4356845252ac6b662d5c72c29903813eJake Slack        {
99403928aee4356845252ac6b662d5c72c29903813eJake Slack            _persistent=false;
99503928aee4356845252ac6b662d5c72c29903813eJake Slack            _state=STATE_SEEKING_EOF;
99603928aee4356845252ac6b662d5c72c29903813eJake Slack            throw e;
99703928aee4356845252ac6b662d5c72c29903813eJake Slack        }
99803928aee4356845252ac6b662d5c72c29903813eJake Slack    }
99903928aee4356845252ac6b662d5c72c29903813eJake Slack
100003928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------------------------- */
100103928aee4356845252ac6b662d5c72c29903813eJake Slack    /** fill the buffers from the endpoint
100203928aee4356845252ac6b662d5c72c29903813eJake Slack     *
100303928aee4356845252ac6b662d5c72c29903813eJake Slack     */
100403928aee4356845252ac6b662d5c72c29903813eJake Slack    protected int fill() throws IOException
100503928aee4356845252ac6b662d5c72c29903813eJake Slack    {
100603928aee4356845252ac6b662d5c72c29903813eJake Slack        // Do we have a buffer?
100703928aee4356845252ac6b662d5c72c29903813eJake Slack        if (_buffer==null)
100803928aee4356845252ac6b662d5c72c29903813eJake Slack            _buffer=getHeaderBuffer();
100903928aee4356845252ac6b662d5c72c29903813eJake Slack
101003928aee4356845252ac6b662d5c72c29903813eJake Slack        // Is there unconsumed content in body buffer
101103928aee4356845252ac6b662d5c72c29903813eJake Slack        if (_state>STATE_END && _buffer==_header && _header!=null && !_header.hasContent() && _body!=null && _body.hasContent())
101203928aee4356845252ac6b662d5c72c29903813eJake Slack        {
101303928aee4356845252ac6b662d5c72c29903813eJake Slack            _buffer=_body;
101403928aee4356845252ac6b662d5c72c29903813eJake Slack            return _buffer.length();
101503928aee4356845252ac6b662d5c72c29903813eJake Slack        }
101603928aee4356845252ac6b662d5c72c29903813eJake Slack
101703928aee4356845252ac6b662d5c72c29903813eJake Slack        // Shall we switch to a body buffer?
101803928aee4356845252ac6b662d5c72c29903813eJake Slack        if (_buffer==_header && _state>STATE_END && _header.length()==0 && (_forceContentBuffer || (_contentLength-_contentPosition)>_header.capacity()) && (_body!=null||_buffers!=null))
101903928aee4356845252ac6b662d5c72c29903813eJake Slack        {
102003928aee4356845252ac6b662d5c72c29903813eJake Slack            if (_body==null)
102103928aee4356845252ac6b662d5c72c29903813eJake Slack                _body=_buffers.getBuffer();
102203928aee4356845252ac6b662d5c72c29903813eJake Slack            _buffer=_body;
102303928aee4356845252ac6b662d5c72c29903813eJake Slack        }
102403928aee4356845252ac6b662d5c72c29903813eJake Slack
102503928aee4356845252ac6b662d5c72c29903813eJake Slack        // Do we have somewhere to fill from?
102603928aee4356845252ac6b662d5c72c29903813eJake Slack        if (_endp != null )
102703928aee4356845252ac6b662d5c72c29903813eJake Slack        {
102803928aee4356845252ac6b662d5c72c29903813eJake Slack            // Shall we compact the body?
102903928aee4356845252ac6b662d5c72c29903813eJake Slack            if (_buffer==_body || _state>STATE_END)
103003928aee4356845252ac6b662d5c72c29903813eJake Slack            {
103103928aee4356845252ac6b662d5c72c29903813eJake Slack                _buffer.compact();
103203928aee4356845252ac6b662d5c72c29903813eJake Slack            }
103303928aee4356845252ac6b662d5c72c29903813eJake Slack
103403928aee4356845252ac6b662d5c72c29903813eJake Slack            // Are we full?
103503928aee4356845252ac6b662d5c72c29903813eJake Slack            if (_buffer.space() == 0)
103603928aee4356845252ac6b662d5c72c29903813eJake Slack            {
103703928aee4356845252ac6b662d5c72c29903813eJake Slack                LOG.warn("HttpParser Full for {} ",_endp);
103803928aee4356845252ac6b662d5c72c29903813eJake Slack                _buffer.clear();
103903928aee4356845252ac6b662d5c72c29903813eJake Slack                throw new HttpException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413, "Request Entity Too Large: "+(_buffer==_body?"body":"head"));
104003928aee4356845252ac6b662d5c72c29903813eJake Slack            }
104103928aee4356845252ac6b662d5c72c29903813eJake Slack
104203928aee4356845252ac6b662d5c72c29903813eJake Slack            try
104303928aee4356845252ac6b662d5c72c29903813eJake Slack            {
104403928aee4356845252ac6b662d5c72c29903813eJake Slack                int filled = _endp.fill(_buffer);
104503928aee4356845252ac6b662d5c72c29903813eJake Slack                return filled;
104603928aee4356845252ac6b662d5c72c29903813eJake Slack            }
104703928aee4356845252ac6b662d5c72c29903813eJake Slack            catch(IOException e)
104803928aee4356845252ac6b662d5c72c29903813eJake Slack            {
104903928aee4356845252ac6b662d5c72c29903813eJake Slack                LOG.debug(e);
105003928aee4356845252ac6b662d5c72c29903813eJake Slack                throw (e instanceof EofException) ? e:new EofException(e);
105103928aee4356845252ac6b662d5c72c29903813eJake Slack            }
105203928aee4356845252ac6b662d5c72c29903813eJake Slack        }
105303928aee4356845252ac6b662d5c72c29903813eJake Slack
105403928aee4356845252ac6b662d5c72c29903813eJake Slack        return -1;
105503928aee4356845252ac6b662d5c72c29903813eJake Slack    }
105603928aee4356845252ac6b662d5c72c29903813eJake Slack
105703928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------------------------- */
105803928aee4356845252ac6b662d5c72c29903813eJake Slack    public void reset()
105903928aee4356845252ac6b662d5c72c29903813eJake Slack    {
106003928aee4356845252ac6b662d5c72c29903813eJake Slack        // reset state
106103928aee4356845252ac6b662d5c72c29903813eJake Slack        _contentView.setGetIndex(_contentView.putIndex());
106203928aee4356845252ac6b662d5c72c29903813eJake Slack        _state=_persistent?STATE_START:(_endp.isInputShutdown()?STATE_END:STATE_SEEKING_EOF);
106303928aee4356845252ac6b662d5c72c29903813eJake Slack        _contentLength=HttpTokens.UNKNOWN_CONTENT;
106403928aee4356845252ac6b662d5c72c29903813eJake Slack        _contentPosition=0;
106503928aee4356845252ac6b662d5c72c29903813eJake Slack        _length=0;
106603928aee4356845252ac6b662d5c72c29903813eJake Slack        _responseStatus=0;
106703928aee4356845252ac6b662d5c72c29903813eJake Slack
106803928aee4356845252ac6b662d5c72c29903813eJake Slack        // Consume LF if CRLF
106903928aee4356845252ac6b662d5c72c29903813eJake Slack        if (_eol == HttpTokens.CARRIAGE_RETURN && _buffer!=null && _buffer.hasContent() && _buffer.peek() == HttpTokens.LINE_FEED)
107003928aee4356845252ac6b662d5c72c29903813eJake Slack            _eol=_buffer.get();
107103928aee4356845252ac6b662d5c72c29903813eJake Slack
107203928aee4356845252ac6b662d5c72c29903813eJake Slack        if (_body!=null && _body.hasContent())
107303928aee4356845252ac6b662d5c72c29903813eJake Slack        {
107403928aee4356845252ac6b662d5c72c29903813eJake Slack            // There is content in the body after the end of the request.
107503928aee4356845252ac6b662d5c72c29903813eJake Slack            // This is probably a pipelined header of the next request, so we need to
107603928aee4356845252ac6b662d5c72c29903813eJake Slack            // copy it to the header buffer.
107703928aee4356845252ac6b662d5c72c29903813eJake Slack            if (_header==null)
107803928aee4356845252ac6b662d5c72c29903813eJake Slack                getHeaderBuffer();
107903928aee4356845252ac6b662d5c72c29903813eJake Slack            else
108003928aee4356845252ac6b662d5c72c29903813eJake Slack            {
108103928aee4356845252ac6b662d5c72c29903813eJake Slack                _header.setMarkIndex(-1);
108203928aee4356845252ac6b662d5c72c29903813eJake Slack                _header.compact();
108303928aee4356845252ac6b662d5c72c29903813eJake Slack            }
108403928aee4356845252ac6b662d5c72c29903813eJake Slack            int take=_header.space();
108503928aee4356845252ac6b662d5c72c29903813eJake Slack            if (take>_body.length())
108603928aee4356845252ac6b662d5c72c29903813eJake Slack                take=_body.length();
108703928aee4356845252ac6b662d5c72c29903813eJake Slack            _body.peek(_body.getIndex(),take);
108803928aee4356845252ac6b662d5c72c29903813eJake Slack            _body.skip(_header.put(_body.peek(_body.getIndex(),take)));
108903928aee4356845252ac6b662d5c72c29903813eJake Slack        }
109003928aee4356845252ac6b662d5c72c29903813eJake Slack
109103928aee4356845252ac6b662d5c72c29903813eJake Slack        if (_header!=null)
109203928aee4356845252ac6b662d5c72c29903813eJake Slack        {
109303928aee4356845252ac6b662d5c72c29903813eJake Slack            _header.setMarkIndex(-1);
109403928aee4356845252ac6b662d5c72c29903813eJake Slack            _header.compact();
109503928aee4356845252ac6b662d5c72c29903813eJake Slack        }
109603928aee4356845252ac6b662d5c72c29903813eJake Slack        if (_body!=null)
109703928aee4356845252ac6b662d5c72c29903813eJake Slack            _body.setMarkIndex(-1);
109803928aee4356845252ac6b662d5c72c29903813eJake Slack
109903928aee4356845252ac6b662d5c72c29903813eJake Slack        _buffer=_header;
110003928aee4356845252ac6b662d5c72c29903813eJake Slack        returnBuffers();
110103928aee4356845252ac6b662d5c72c29903813eJake Slack    }
110203928aee4356845252ac6b662d5c72c29903813eJake Slack
110303928aee4356845252ac6b662d5c72c29903813eJake Slack
110403928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------------------------- */
110503928aee4356845252ac6b662d5c72c29903813eJake Slack    public void returnBuffers()
110603928aee4356845252ac6b662d5c72c29903813eJake Slack    {
110703928aee4356845252ac6b662d5c72c29903813eJake Slack        if (_body!=null && !_body.hasContent() && _body.markIndex()==-1 && _buffers!=null)
110803928aee4356845252ac6b662d5c72c29903813eJake Slack        {
110903928aee4356845252ac6b662d5c72c29903813eJake Slack            if (_buffer==_body)
111003928aee4356845252ac6b662d5c72c29903813eJake Slack                _buffer=_header;
111103928aee4356845252ac6b662d5c72c29903813eJake Slack            if (_buffers!=null)
111203928aee4356845252ac6b662d5c72c29903813eJake Slack                _buffers.returnBuffer(_body);
111303928aee4356845252ac6b662d5c72c29903813eJake Slack            _body=null;
111403928aee4356845252ac6b662d5c72c29903813eJake Slack        }
111503928aee4356845252ac6b662d5c72c29903813eJake Slack
111603928aee4356845252ac6b662d5c72c29903813eJake Slack        if (_header!=null && !_header.hasContent() && _header.markIndex()==-1 && _buffers!=null)
111703928aee4356845252ac6b662d5c72c29903813eJake Slack        {
111803928aee4356845252ac6b662d5c72c29903813eJake Slack            if (_buffer==_header)
111903928aee4356845252ac6b662d5c72c29903813eJake Slack                _buffer=null;
112003928aee4356845252ac6b662d5c72c29903813eJake Slack            _buffers.returnBuffer(_header);
112103928aee4356845252ac6b662d5c72c29903813eJake Slack            _header=null;
112203928aee4356845252ac6b662d5c72c29903813eJake Slack        }
112303928aee4356845252ac6b662d5c72c29903813eJake Slack    }
112403928aee4356845252ac6b662d5c72c29903813eJake Slack
112503928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------------------------- */
112603928aee4356845252ac6b662d5c72c29903813eJake Slack    public void setState(int state)
112703928aee4356845252ac6b662d5c72c29903813eJake Slack    {
112803928aee4356845252ac6b662d5c72c29903813eJake Slack        this._state=state;
112903928aee4356845252ac6b662d5c72c29903813eJake Slack        _contentLength=HttpTokens.UNKNOWN_CONTENT;
113003928aee4356845252ac6b662d5c72c29903813eJake Slack    }
113103928aee4356845252ac6b662d5c72c29903813eJake Slack
113203928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------------------------- */
113303928aee4356845252ac6b662d5c72c29903813eJake Slack    public String toString(Buffer buf)
113403928aee4356845252ac6b662d5c72c29903813eJake Slack    {
113503928aee4356845252ac6b662d5c72c29903813eJake Slack        return "state=" + _state + " length=" + _length + " buf=" + buf.hashCode();
113603928aee4356845252ac6b662d5c72c29903813eJake Slack    }
113703928aee4356845252ac6b662d5c72c29903813eJake Slack
113803928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------------------------- */
113903928aee4356845252ac6b662d5c72c29903813eJake Slack    @Override
114003928aee4356845252ac6b662d5c72c29903813eJake Slack    public String toString()
114103928aee4356845252ac6b662d5c72c29903813eJake Slack    {
114203928aee4356845252ac6b662d5c72c29903813eJake Slack        return String.format("%s{s=%d,l=%d,c=%d}",
114303928aee4356845252ac6b662d5c72c29903813eJake Slack                getClass().getSimpleName(),
114403928aee4356845252ac6b662d5c72c29903813eJake Slack                _state,
114503928aee4356845252ac6b662d5c72c29903813eJake Slack                _length,
114603928aee4356845252ac6b662d5c72c29903813eJake Slack                _contentLength);
114703928aee4356845252ac6b662d5c72c29903813eJake Slack    }
114803928aee4356845252ac6b662d5c72c29903813eJake Slack
114903928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
115003928aee4356845252ac6b662d5c72c29903813eJake Slack    public Buffer getHeaderBuffer()
115103928aee4356845252ac6b662d5c72c29903813eJake Slack    {
115203928aee4356845252ac6b662d5c72c29903813eJake Slack        if (_header == null)
115303928aee4356845252ac6b662d5c72c29903813eJake Slack        {
115403928aee4356845252ac6b662d5c72c29903813eJake Slack            _header=_buffers.getHeader();
115503928aee4356845252ac6b662d5c72c29903813eJake Slack            _tok0.update(_header);
115603928aee4356845252ac6b662d5c72c29903813eJake Slack            _tok1.update(_header);
115703928aee4356845252ac6b662d5c72c29903813eJake Slack        }
115803928aee4356845252ac6b662d5c72c29903813eJake Slack        return _header;
115903928aee4356845252ac6b662d5c72c29903813eJake Slack    }
116003928aee4356845252ac6b662d5c72c29903813eJake Slack
116103928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
116203928aee4356845252ac6b662d5c72c29903813eJake Slack    public Buffer getBodyBuffer()
116303928aee4356845252ac6b662d5c72c29903813eJake Slack    {
116403928aee4356845252ac6b662d5c72c29903813eJake Slack        return _body;
116503928aee4356845252ac6b662d5c72c29903813eJake Slack    }
116603928aee4356845252ac6b662d5c72c29903813eJake Slack
116703928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
116803928aee4356845252ac6b662d5c72c29903813eJake Slack    /**
116903928aee4356845252ac6b662d5c72c29903813eJake Slack     * @param force True if a new buffer will be forced to be used for content and the header buffer will not be used.
117003928aee4356845252ac6b662d5c72c29903813eJake Slack     */
117103928aee4356845252ac6b662d5c72c29903813eJake Slack    public void setForceContentBuffer(boolean force)
117203928aee4356845252ac6b662d5c72c29903813eJake Slack    {
117303928aee4356845252ac6b662d5c72c29903813eJake Slack        _forceContentBuffer=force;
117403928aee4356845252ac6b662d5c72c29903813eJake Slack    }
117503928aee4356845252ac6b662d5c72c29903813eJake Slack
117603928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
117703928aee4356845252ac6b662d5c72c29903813eJake Slack    public Buffer blockForContent(long maxIdleTime) throws IOException
117803928aee4356845252ac6b662d5c72c29903813eJake Slack    {
117903928aee4356845252ac6b662d5c72c29903813eJake Slack        if (_contentView.length()>0)
118003928aee4356845252ac6b662d5c72c29903813eJake Slack            return _contentView;
118103928aee4356845252ac6b662d5c72c29903813eJake Slack
118203928aee4356845252ac6b662d5c72c29903813eJake Slack        if (getState() <= STATE_END || isState(STATE_SEEKING_EOF))
118303928aee4356845252ac6b662d5c72c29903813eJake Slack            return null;
118403928aee4356845252ac6b662d5c72c29903813eJake Slack
118503928aee4356845252ac6b662d5c72c29903813eJake Slack        try
118603928aee4356845252ac6b662d5c72c29903813eJake Slack        {
118703928aee4356845252ac6b662d5c72c29903813eJake Slack            parseNext();
118803928aee4356845252ac6b662d5c72c29903813eJake Slack
118903928aee4356845252ac6b662d5c72c29903813eJake Slack            // parse until some progress is made (or IOException thrown for timeout)
119003928aee4356845252ac6b662d5c72c29903813eJake Slack            while(_contentView.length() == 0 && !(isState(HttpParser.STATE_END)||isState(HttpParser.STATE_SEEKING_EOF)) && _endp!=null && _endp.isOpen())
119103928aee4356845252ac6b662d5c72c29903813eJake Slack            {
119203928aee4356845252ac6b662d5c72c29903813eJake Slack                if (!_endp.isBlocking())
119303928aee4356845252ac6b662d5c72c29903813eJake Slack                {
119403928aee4356845252ac6b662d5c72c29903813eJake Slack                    if (parseNext()>0)
119503928aee4356845252ac6b662d5c72c29903813eJake Slack                        continue;
119603928aee4356845252ac6b662d5c72c29903813eJake Slack
119703928aee4356845252ac6b662d5c72c29903813eJake Slack                    if (!_endp.blockReadable(maxIdleTime))
119803928aee4356845252ac6b662d5c72c29903813eJake Slack                    {
119903928aee4356845252ac6b662d5c72c29903813eJake Slack                        _endp.close();
120003928aee4356845252ac6b662d5c72c29903813eJake Slack                        throw new EofException("timeout");
120103928aee4356845252ac6b662d5c72c29903813eJake Slack                    }
120203928aee4356845252ac6b662d5c72c29903813eJake Slack                }
120303928aee4356845252ac6b662d5c72c29903813eJake Slack
120403928aee4356845252ac6b662d5c72c29903813eJake Slack                parseNext();
120503928aee4356845252ac6b662d5c72c29903813eJake Slack            }
120603928aee4356845252ac6b662d5c72c29903813eJake Slack        }
120703928aee4356845252ac6b662d5c72c29903813eJake Slack        catch(IOException e)
120803928aee4356845252ac6b662d5c72c29903813eJake Slack        {
120903928aee4356845252ac6b662d5c72c29903813eJake Slack            // TODO is this needed?
121003928aee4356845252ac6b662d5c72c29903813eJake Slack            _endp.close();
121103928aee4356845252ac6b662d5c72c29903813eJake Slack            throw e;
121203928aee4356845252ac6b662d5c72c29903813eJake Slack        }
121303928aee4356845252ac6b662d5c72c29903813eJake Slack
121403928aee4356845252ac6b662d5c72c29903813eJake Slack        return _contentView.length()>0?_contentView:null;
121503928aee4356845252ac6b662d5c72c29903813eJake Slack    }
121603928aee4356845252ac6b662d5c72c29903813eJake Slack
121703928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
121803928aee4356845252ac6b662d5c72c29903813eJake Slack    /* (non-Javadoc)
121903928aee4356845252ac6b662d5c72c29903813eJake Slack     * @see java.io.InputStream#available()
122003928aee4356845252ac6b662d5c72c29903813eJake Slack     */
122103928aee4356845252ac6b662d5c72c29903813eJake Slack    public int available() throws IOException
122203928aee4356845252ac6b662d5c72c29903813eJake Slack    {
122303928aee4356845252ac6b662d5c72c29903813eJake Slack        if (_contentView!=null && _contentView.length()>0)
122403928aee4356845252ac6b662d5c72c29903813eJake Slack            return _contentView.length();
122503928aee4356845252ac6b662d5c72c29903813eJake Slack
122603928aee4356845252ac6b662d5c72c29903813eJake Slack        if (_endp.isBlocking())
122703928aee4356845252ac6b662d5c72c29903813eJake Slack        {
122803928aee4356845252ac6b662d5c72c29903813eJake Slack            if (_state>0 && _endp instanceof StreamEndPoint)
122903928aee4356845252ac6b662d5c72c29903813eJake Slack                return ((StreamEndPoint)_endp).getInputStream().available()>0?1:0;
123003928aee4356845252ac6b662d5c72c29903813eJake Slack
123103928aee4356845252ac6b662d5c72c29903813eJake Slack            return 0;
123203928aee4356845252ac6b662d5c72c29903813eJake Slack        }
123303928aee4356845252ac6b662d5c72c29903813eJake Slack
123403928aee4356845252ac6b662d5c72c29903813eJake Slack        parseNext();
123503928aee4356845252ac6b662d5c72c29903813eJake Slack        return _contentView==null?0:_contentView.length();
123603928aee4356845252ac6b662d5c72c29903813eJake Slack    }
123703928aee4356845252ac6b662d5c72c29903813eJake Slack
123803928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
123903928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
124003928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
124103928aee4356845252ac6b662d5c72c29903813eJake Slack    public static abstract class EventHandler
124203928aee4356845252ac6b662d5c72c29903813eJake Slack    {
124303928aee4356845252ac6b662d5c72c29903813eJake Slack        public abstract void content(Buffer ref) throws IOException;
124403928aee4356845252ac6b662d5c72c29903813eJake Slack
124503928aee4356845252ac6b662d5c72c29903813eJake Slack        public void headerComplete() throws IOException
124603928aee4356845252ac6b662d5c72c29903813eJake Slack        {
124703928aee4356845252ac6b662d5c72c29903813eJake Slack        }
124803928aee4356845252ac6b662d5c72c29903813eJake Slack
124903928aee4356845252ac6b662d5c72c29903813eJake Slack        public void messageComplete(long contentLength) throws IOException
125003928aee4356845252ac6b662d5c72c29903813eJake Slack        {
125103928aee4356845252ac6b662d5c72c29903813eJake Slack        }
125203928aee4356845252ac6b662d5c72c29903813eJake Slack
125303928aee4356845252ac6b662d5c72c29903813eJake Slack        /**
125403928aee4356845252ac6b662d5c72c29903813eJake Slack         * This is the method called by parser when a HTTP Header name and value is found
125503928aee4356845252ac6b662d5c72c29903813eJake Slack         */
125603928aee4356845252ac6b662d5c72c29903813eJake Slack        public void parsedHeader(Buffer name, Buffer value) throws IOException
125703928aee4356845252ac6b662d5c72c29903813eJake Slack        {
125803928aee4356845252ac6b662d5c72c29903813eJake Slack        }
125903928aee4356845252ac6b662d5c72c29903813eJake Slack
126003928aee4356845252ac6b662d5c72c29903813eJake Slack        /**
126103928aee4356845252ac6b662d5c72c29903813eJake Slack         * This is the method called by parser when the HTTP request line is parsed
126203928aee4356845252ac6b662d5c72c29903813eJake Slack         */
126303928aee4356845252ac6b662d5c72c29903813eJake Slack        public abstract void startRequest(Buffer method, Buffer url, Buffer version)
126403928aee4356845252ac6b662d5c72c29903813eJake Slack                throws IOException;
126503928aee4356845252ac6b662d5c72c29903813eJake Slack
126603928aee4356845252ac6b662d5c72c29903813eJake Slack        /**
126703928aee4356845252ac6b662d5c72c29903813eJake Slack         * This is the method called by parser when the HTTP request line is parsed
126803928aee4356845252ac6b662d5c72c29903813eJake Slack         */
126903928aee4356845252ac6b662d5c72c29903813eJake Slack        public abstract void startResponse(Buffer version, int status, Buffer reason)
127003928aee4356845252ac6b662d5c72c29903813eJake Slack                throws IOException;
127103928aee4356845252ac6b662d5c72c29903813eJake Slack
127203928aee4356845252ac6b662d5c72c29903813eJake Slack        public void earlyEOF()
127303928aee4356845252ac6b662d5c72c29903813eJake Slack        {}
127403928aee4356845252ac6b662d5c72c29903813eJake Slack    }
127503928aee4356845252ac6b662d5c72c29903813eJake Slack
127603928aee4356845252ac6b662d5c72c29903813eJake Slack
127703928aee4356845252ac6b662d5c72c29903813eJake Slack
127803928aee4356845252ac6b662d5c72c29903813eJake Slack
127903928aee4356845252ac6b662d5c72c29903813eJake Slack}
1280