1//
2//  ========================================================================
3//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4//  ------------------------------------------------------------------------
5//  All rights reserved. This program and the accompanying materials
6//  are made available under the terms of the Eclipse Public License v1.0
7//  and Apache License v2.0 which accompanies this distribution.
8//
9//      The Eclipse Public License is available at
10//      http://www.eclipse.org/legal/epl-v10.html
11//
12//      The Apache License v2.0 is available at
13//      http://www.opensource.org/licenses/apache2.0.php
14//
15//  You may elect to redistribute this code under either of these licenses.
16//  ========================================================================
17//
18
19package org.eclipse.jetty.http;
20
21import java.io.IOException;
22
23import org.eclipse.jetty.io.Buffer;
24import org.eclipse.jetty.io.BufferCache.CachedBuffer;
25import org.eclipse.jetty.io.BufferUtil;
26import org.eclipse.jetty.io.Buffers;
27import org.eclipse.jetty.io.ByteArrayBuffer;
28import org.eclipse.jetty.io.EndPoint;
29import org.eclipse.jetty.io.EofException;
30import org.eclipse.jetty.io.View;
31import org.eclipse.jetty.io.bio.StreamEndPoint;
32import org.eclipse.jetty.util.StringUtil;
33import org.eclipse.jetty.util.log.Log;
34import org.eclipse.jetty.util.log.Logger;
35
36public class HttpParser implements Parser
37{
38    private static final Logger LOG = Log.getLogger(HttpParser.class);
39
40    // States
41    public static final int STATE_START=-14;
42    public static final int STATE_FIELD0=-13;
43    public static final int STATE_SPACE1=-12;
44    public static final int STATE_STATUS=-11;
45    public static final int STATE_URI=-10;
46    public static final int STATE_SPACE2=-9;
47    public static final int STATE_END0=-8;
48    public static final int STATE_END1=-7;
49    public static final int STATE_FIELD2=-6;
50    public static final int STATE_HEADER=-5;
51    public static final int STATE_HEADER_NAME=-4;
52    public static final int STATE_HEADER_IN_NAME=-3;
53    public static final int STATE_HEADER_VALUE=-2;
54    public static final int STATE_HEADER_IN_VALUE=-1;
55    public static final int STATE_END=0;
56    public static final int STATE_EOF_CONTENT=1;
57    public static final int STATE_CONTENT=2;
58    public static final int STATE_CHUNKED_CONTENT=3;
59    public static final int STATE_CHUNK_SIZE=4;
60    public static final int STATE_CHUNK_PARAMS=5;
61    public static final int STATE_CHUNK=6;
62    public static final int STATE_SEEKING_EOF=7;
63
64    private final EventHandler _handler;
65    private final Buffers _buffers; // source of buffers
66    private final EndPoint _endp;
67    private Buffer _header; // Buffer for header data (and small _content)
68    private Buffer _body; // Buffer for large content
69    private Buffer _buffer; // The current buffer in use (either _header or _content)
70    private CachedBuffer _cached;
71    private final View.CaseInsensitive _tok0; // Saved token: header name, request method or response version
72    private final View.CaseInsensitive _tok1; // Saved token: header value, request URI or response code
73    private String _multiLineValue;
74    private int _responseStatus; // If >0 then we are parsing a response
75    private boolean _forceContentBuffer;
76    private boolean _persistent;
77
78    /* ------------------------------------------------------------------------------- */
79    protected final View  _contentView=new View(); // View of the content in the buffer for {@link Input}
80    protected int _state=STATE_START;
81    protected byte _eol;
82    protected int _length;
83    protected long _contentLength;
84    protected long _contentPosition;
85    protected int _chunkLength;
86    protected int _chunkPosition;
87    private boolean _headResponse;
88
89    /* ------------------------------------------------------------------------------- */
90    /**
91     * Constructor.
92     */
93    public HttpParser(Buffer buffer, EventHandler handler)
94    {
95        _endp=null;
96        _buffers=null;
97        _header=buffer;
98        _buffer=buffer;
99        _handler=handler;
100
101        _tok0=new View.CaseInsensitive(_header);
102        _tok1=new View.CaseInsensitive(_header);
103    }
104
105    /* ------------------------------------------------------------------------------- */
106    /**
107     * Constructor.
108     * @param buffers the buffers to use
109     * @param endp the endpoint
110     * @param handler the even handler
111     */
112    public HttpParser(Buffers buffers, EndPoint endp, EventHandler handler)
113    {
114        _buffers=buffers;
115        _endp=endp;
116        _handler=handler;
117        _tok0=new View.CaseInsensitive();
118        _tok1=new View.CaseInsensitive();
119    }
120
121    /* ------------------------------------------------------------------------------- */
122    public long getContentLength()
123    {
124        return _contentLength;
125    }
126
127    /* ------------------------------------------------------------ */
128    public long getContentRead()
129    {
130        return _contentPosition;
131    }
132
133    /* ------------------------------------------------------------ */
134    /** Set if a HEAD response is expected
135     * @param head
136     */
137    public void setHeadResponse(boolean head)
138    {
139        _headResponse=head;
140    }
141
142    /* ------------------------------------------------------------------------------- */
143    public int getState()
144    {
145        return _state;
146    }
147
148    /* ------------------------------------------------------------------------------- */
149    public boolean inContentState()
150    {
151        return _state > 0;
152    }
153
154    /* ------------------------------------------------------------------------------- */
155    public boolean inHeaderState()
156    {
157        return _state < 0;
158    }
159
160    /* ------------------------------------------------------------------------------- */
161    public boolean isChunking()
162    {
163        return _contentLength==HttpTokens.CHUNKED_CONTENT;
164    }
165
166    /* ------------------------------------------------------------ */
167    public boolean isIdle()
168    {
169        return isState(STATE_START);
170    }
171
172    /* ------------------------------------------------------------ */
173    public boolean isComplete()
174    {
175        return isState(STATE_END);
176    }
177
178    /* ------------------------------------------------------------ */
179    public boolean isMoreInBuffer()
180    throws IOException
181    {
182        return ( _header!=null && _header.hasContent() ||
183             _body!=null && _body.hasContent());
184    }
185
186    /* ------------------------------------------------------------------------------- */
187    public boolean isState(int state)
188    {
189        return _state == state;
190    }
191
192    /* ------------------------------------------------------------------------------- */
193    public boolean isPersistent()
194    {
195        return _persistent;
196    }
197
198    /* ------------------------------------------------------------------------------- */
199    public void setPersistent(boolean persistent)
200    {
201        _persistent = persistent;
202        if (!_persistent &&(_state==STATE_END || _state==STATE_START))
203            _state=STATE_SEEKING_EOF;
204    }
205
206    /* ------------------------------------------------------------------------------- */
207    /**
208     * Parse until {@link #STATE_END END} state.
209     * If the parser is already in the END state, then it is {@link #reset reset} and re-parsed.
210     * @throws IllegalStateException If the buffers have already been partially parsed.
211     */
212    public void parse() throws IOException
213    {
214        if (_state==STATE_END)
215            reset();
216        if (_state!=STATE_START)
217            throw new IllegalStateException("!START");
218
219        // continue parsing
220        while (_state != STATE_END)
221            if (parseNext()<0)
222                return;
223    }
224
225    /* ------------------------------------------------------------------------------- */
226    /**
227     * Parse until END state.
228     * This method will parse any remaining content in the current buffer as long as there is
229     * no unconsumed content. It does not care about the {@link #getState current state} of the parser.
230     * @see #parse
231     * @see #parseNext
232     */
233    public boolean parseAvailable() throws IOException
234    {
235        boolean progress=parseNext()>0;
236
237        // continue parsing
238        while (!isComplete() && _buffer!=null && _buffer.length()>0 && !_contentView.hasContent())
239        {
240            progress |= parseNext()>0;
241        }
242        return progress;
243    }
244
245
246    /* ------------------------------------------------------------------------------- */
247    /**
248     * Parse until next Event.
249     * @return an indication of progress <0 EOF, 0 no progress, >0 progress.
250     */
251    public int parseNext() throws IOException
252    {
253        try
254        {
255            int progress=0;
256
257            if (_state == STATE_END)
258                return 0;
259
260            if (_buffer==null)
261                _buffer=getHeaderBuffer();
262
263
264            if (_state == STATE_CONTENT && _contentPosition == _contentLength)
265            {
266                _state=STATE_END;
267                _handler.messageComplete(_contentPosition);
268                return 1;
269            }
270
271            int length=_buffer.length();
272
273            // Fill buffer if we can
274            if (length == 0)
275            {
276                int filled=-1;
277                IOException ex=null;
278                try
279                {
280                    filled=fill();
281                    LOG.debug("filled {}/{}",filled,_buffer.length());
282                }
283                catch(IOException e)
284                {
285                    LOG.debug(this.toString(),e);
286                    ex=e;
287                }
288
289                if (filled > 0 )
290                    progress++;
291                else if (filled < 0 )
292                {
293                    _persistent=false;
294
295                    // do we have content to deliver?
296                    if (_state>STATE_END)
297                    {
298                        if (_buffer.length()>0 && !_headResponse)
299                        {
300                            Buffer chunk=_buffer.get(_buffer.length());
301                            _contentPosition += chunk.length();
302                            _contentView.update(chunk);
303                            _handler.content(chunk); // May recurse here
304                        }
305                    }
306
307                    // was this unexpected?
308                    switch(_state)
309                    {
310                        case STATE_END:
311                        case STATE_SEEKING_EOF:
312                            _state=STATE_END;
313                            break;
314
315                        case STATE_EOF_CONTENT:
316                            _state=STATE_END;
317                            _handler.messageComplete(_contentPosition);
318                            break;
319
320                        default:
321                            _state=STATE_END;
322                            if (!_headResponse)
323                                _handler.earlyEOF();
324                            _handler.messageComplete(_contentPosition);
325                    }
326
327                    if (ex!=null)
328                        throw ex;
329
330                    if (!isComplete() && !isIdle())
331                        throw new EofException();
332
333                    return -1;
334                }
335                length=_buffer.length();
336            }
337
338
339            // Handle header states
340            byte ch;
341            byte[] array=_buffer.array();
342            int last=_state;
343            while (_state<STATE_END && length-->0)
344            {
345                if (last!=_state)
346                {
347                    progress++;
348                    last=_state;
349                }
350
351                ch=_buffer.get();
352
353                if (_eol == HttpTokens.CARRIAGE_RETURN)
354                {
355                    if (ch == HttpTokens.LINE_FEED)
356                    {
357                        _eol=HttpTokens.LINE_FEED;
358                        continue;
359                    }
360                    throw new HttpException(HttpStatus.BAD_REQUEST_400);
361                }
362                _eol=0;
363
364                switch (_state)
365                {
366                    case STATE_START:
367                        _contentLength=HttpTokens.UNKNOWN_CONTENT;
368                        _cached=null;
369                        if (ch > HttpTokens.SPACE || ch<0)
370                        {
371                            _buffer.mark();
372                            _state=STATE_FIELD0;
373                        }
374                        break;
375
376                    case STATE_FIELD0:
377                        if (ch == HttpTokens.SPACE)
378                        {
379                            _tok0.update(_buffer.markIndex(), _buffer.getIndex() - 1);
380                            _responseStatus=HttpVersions.CACHE.get(_tok0)==null?-1:0;
381                            _state=STATE_SPACE1;
382                            continue;
383                        }
384                        else if (ch < HttpTokens.SPACE && ch>=0)
385                        {
386                            throw new HttpException(HttpStatus.BAD_REQUEST_400);
387                        }
388                        break;
389
390                    case STATE_SPACE1:
391                        if (ch > HttpTokens.SPACE || ch<0)
392                        {
393                            _buffer.mark();
394                            if (_responseStatus>=0)
395                            {
396                                _state=STATE_STATUS;
397                                _responseStatus=ch-'0';
398                            }
399                            else
400                                _state=STATE_URI;
401                        }
402                        else if (ch < HttpTokens.SPACE)
403                        {
404                            throw new HttpException(HttpStatus.BAD_REQUEST_400);
405                        }
406                        break;
407
408                    case STATE_STATUS:
409                        if (ch == HttpTokens.SPACE)
410                        {
411                            _tok1.update(_buffer.markIndex(), _buffer.getIndex() - 1);
412                            _state=STATE_SPACE2;
413                            continue;
414                        }
415                        else if (ch>='0' && ch<='9')
416                        {
417                            _responseStatus=_responseStatus*10+(ch-'0');
418                            continue;
419                        }
420                        else if (ch < HttpTokens.SPACE && ch>=0)
421                        {
422                            _handler.startResponse(HttpMethods.CACHE.lookup(_tok0), _responseStatus, null);
423                            _eol=ch;
424                            _state=STATE_HEADER;
425                            _tok0.setPutIndex(_tok0.getIndex());
426                            _tok1.setPutIndex(_tok1.getIndex());
427                            _multiLineValue=null;
428                            continue;
429                        }
430                        // not a digit, so must be a URI
431                        _state=STATE_URI;
432                        _responseStatus=-1;
433                        break;
434
435                    case STATE_URI:
436                        if (ch == HttpTokens.SPACE)
437                        {
438                            _tok1.update(_buffer.markIndex(), _buffer.getIndex() - 1);
439                            _state=STATE_SPACE2;
440                            continue;
441                        }
442                        else if (ch < HttpTokens.SPACE && ch>=0)
443                        {
444                            // HTTP/0.9
445                            _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _buffer.sliceFromMark(), null);
446                            _persistent=false;
447                            _state=STATE_SEEKING_EOF;
448                            _handler.headerComplete();
449                            _handler.messageComplete(_contentPosition);
450                            return 1;
451                        }
452                        break;
453
454                    case STATE_SPACE2:
455                        if (ch > HttpTokens.SPACE || ch<0)
456                        {
457                            _buffer.mark();
458                            _state=STATE_FIELD2;
459                        }
460                        else if (ch < HttpTokens.SPACE)
461                        {
462                            if (_responseStatus>0)
463                            {
464                                _handler.startResponse(HttpMethods.CACHE.lookup(_tok0), _responseStatus, null);
465                                _eol=ch;
466                                _state=STATE_HEADER;
467                                _tok0.setPutIndex(_tok0.getIndex());
468                                _tok1.setPutIndex(_tok1.getIndex());
469                                _multiLineValue=null;
470                            }
471                            else
472                            {
473                                // HTTP/0.9
474                                _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _tok1, null);
475                                _persistent=false;
476                                _state=STATE_SEEKING_EOF;
477                                _handler.headerComplete();
478                                _handler.messageComplete(_contentPosition);
479                                return 1;
480                            }
481                        }
482                        break;
483
484                    case STATE_FIELD2:
485                        if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
486                        {
487                            Buffer version;
488                            if (_responseStatus>0)
489                                _handler.startResponse(version=HttpVersions.CACHE.lookup(_tok0), _responseStatus,_buffer.sliceFromMark());
490                            else
491                                _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _tok1, version=HttpVersions.CACHE.lookup(_buffer.sliceFromMark()));
492                            _eol=ch;
493                            _persistent=HttpVersions.CACHE.getOrdinal(version)>=HttpVersions.HTTP_1_1_ORDINAL;
494                            _state=STATE_HEADER;
495                            _tok0.setPutIndex(_tok0.getIndex());
496                            _tok1.setPutIndex(_tok1.getIndex());
497                            _multiLineValue=null;
498                            continue;
499                        }
500                        break;
501
502                    case STATE_HEADER:
503                        switch(ch)
504                        {
505                            case HttpTokens.COLON:
506                            case HttpTokens.SPACE:
507                            case HttpTokens.TAB:
508                            {
509                                // header value without name - continuation?
510                                _length=-1;
511                                _state=STATE_HEADER_VALUE;
512                                break;
513                            }
514
515                            default:
516                            {
517                                // handler last header if any
518                                if (_cached!=null || _tok0.length() > 0 || _tok1.length() > 0 || _multiLineValue != null)
519                                {
520                                    Buffer header=_cached!=null?_cached:HttpHeaders.CACHE.lookup(_tok0);
521                                    _cached=null;
522                                    Buffer value=_multiLineValue == null ? _tok1 : new ByteArrayBuffer(_multiLineValue);
523
524                                    int ho=HttpHeaders.CACHE.getOrdinal(header);
525                                    if (ho >= 0)
526                                    {
527                                        int vo;
528
529                                        switch (ho)
530                                        {
531                                            case HttpHeaders.CONTENT_LENGTH_ORDINAL:
532                                                if (_contentLength != HttpTokens.CHUNKED_CONTENT )
533                                                {
534                                                    try
535                                                    {
536                                                        _contentLength=BufferUtil.toLong(value);
537                                                    }
538                                                    catch(NumberFormatException e)
539                                                    {
540                                                        LOG.ignore(e);
541                                                        throw new HttpException(HttpStatus.BAD_REQUEST_400);
542                                                    }
543                                                    if (_contentLength <= 0)
544                                                        _contentLength=HttpTokens.NO_CONTENT;
545                                                }
546                                                break;
547
548                                            case HttpHeaders.TRANSFER_ENCODING_ORDINAL:
549                                                value=HttpHeaderValues.CACHE.lookup(value);
550                                                vo=HttpHeaderValues.CACHE.getOrdinal(value);
551                                                if (HttpHeaderValues.CHUNKED_ORDINAL == vo)
552                                                    _contentLength=HttpTokens.CHUNKED_CONTENT;
553                                                else
554                                                {
555                                                    String c=value.toString(StringUtil.__ISO_8859_1);
556                                                    if (c.endsWith(HttpHeaderValues.CHUNKED))
557                                                        _contentLength=HttpTokens.CHUNKED_CONTENT;
558
559                                                    else if (c.indexOf(HttpHeaderValues.CHUNKED) >= 0)
560                                                        throw new HttpException(400,null);
561                                                }
562                                                break;
563
564                                            case HttpHeaders.CONNECTION_ORDINAL:
565                                                switch(HttpHeaderValues.CACHE.getOrdinal(value))
566                                                {
567                                                    case HttpHeaderValues.CLOSE_ORDINAL:
568                                                        _persistent=false;
569                                                        break;
570
571                                                    case HttpHeaderValues.KEEP_ALIVE_ORDINAL:
572                                                        _persistent=true;
573                                                        break;
574
575                                                    case -1: // No match, may be multi valued
576                                                    {
577                                                        for (String v : value.toString().split(","))
578                                                        {
579                                                            switch(HttpHeaderValues.CACHE.getOrdinal(v.trim()))
580                                                            {
581                                                                case HttpHeaderValues.CLOSE_ORDINAL:
582                                                                    _persistent=false;
583                                                                    break;
584
585                                                                case HttpHeaderValues.KEEP_ALIVE_ORDINAL:
586                                                                    _persistent=true;
587                                                                    break;
588                                                            }
589                                                        }
590                                                        break;
591                                                    }
592                                                }
593                                        }
594                                    }
595
596                                    _handler.parsedHeader(header, value);
597                                    _tok0.setPutIndex(_tok0.getIndex());
598                                    _tok1.setPutIndex(_tok1.getIndex());
599                                    _multiLineValue=null;
600                                }
601                                _buffer.setMarkIndex(-1);
602
603                                // now handle ch
604                                if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
605                                {
606                                    // is it a response that cannot have a body?
607                                    if (_responseStatus > 0  && // response
608                                       (_responseStatus == 304  || // not-modified response
609                                        _responseStatus == 204 || // no-content response
610                                        _responseStatus < 200)) // 1xx response
611                                        _contentLength=HttpTokens.NO_CONTENT; // ignore any other headers set
612                                    // else if we don't know framing
613                                    else if (_contentLength == HttpTokens.UNKNOWN_CONTENT)
614                                    {
615                                        if (_responseStatus == 0  // request
616                                                || _responseStatus == 304 // not-modified response
617                                                || _responseStatus == 204 // no-content response
618                                                || _responseStatus < 200) // 1xx response
619                                            _contentLength=HttpTokens.NO_CONTENT;
620                                        else
621                                            _contentLength=HttpTokens.EOF_CONTENT;
622                                    }
623
624                                    _contentPosition=0;
625                                    _eol=ch;
626                                    if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED)
627                                        _eol=_buffer.get();
628
629                                    // We convert _contentLength to an int for this switch statement because
630                                    // we don't care about the amount of data available just whether there is some.
631                                    switch (_contentLength > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) _contentLength)
632                                    {
633                                        case HttpTokens.EOF_CONTENT:
634                                            _state=STATE_EOF_CONTENT;
635                                            _handler.headerComplete(); // May recurse here !
636                                            break;
637
638                                        case HttpTokens.CHUNKED_CONTENT:
639                                            _state=STATE_CHUNKED_CONTENT;
640                                            _handler.headerComplete(); // May recurse here !
641                                            break;
642
643                                        case HttpTokens.NO_CONTENT:
644                                            _handler.headerComplete();
645                                            _state=_persistent||(_responseStatus>=100&&_responseStatus<200)?STATE_END:STATE_SEEKING_EOF;
646                                            _handler.messageComplete(_contentPosition);
647                                            return 1;
648
649                                        default:
650                                            _state=STATE_CONTENT;
651                                            _handler.headerComplete(); // May recurse here !
652                                            break;
653                                    }
654                                    return 1;
655                                }
656                                else
657                                {
658                                    // New header
659                                    _length=1;
660                                    _buffer.mark();
661                                    _state=STATE_HEADER_NAME;
662
663                                    // try cached name!
664                                    if (array!=null)
665                                    {
666                                        _cached=HttpHeaders.CACHE.getBest(array, _buffer.markIndex(), length+1);
667
668                                        if (_cached!=null)
669                                        {
670                                            _length=_cached.length();
671                                            _buffer.setGetIndex(_buffer.markIndex()+_length);
672                                            length=_buffer.length();
673                                        }
674                                    }
675                                }
676                            }
677                        }
678
679                        break;
680
681                    case STATE_HEADER_NAME:
682                        switch(ch)
683                        {
684                            case HttpTokens.CARRIAGE_RETURN:
685                            case HttpTokens.LINE_FEED:
686                                if (_length > 0)
687                                    _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length);
688                                _eol=ch;
689                                _state=STATE_HEADER;
690                                break;
691                            case HttpTokens.COLON:
692                                if (_length > 0 && _cached==null)
693                                    _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length);
694                                _length=-1;
695                                _state=STATE_HEADER_VALUE;
696                                break;
697                            case HttpTokens.SPACE:
698                            case HttpTokens.TAB:
699                                break;
700                            default:
701                            {
702                                _cached=null;
703                                if (_length == -1)
704                                    _buffer.mark();
705                                _length=_buffer.getIndex() - _buffer.markIndex();
706                                _state=STATE_HEADER_IN_NAME;
707                            }
708                        }
709
710                        break;
711
712                    case STATE_HEADER_IN_NAME:
713                        switch(ch)
714                        {
715                            case HttpTokens.CARRIAGE_RETURN:
716                            case HttpTokens.LINE_FEED:
717                                if (_length > 0)
718                                    _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length);
719                                _eol=ch;
720                                _state=STATE_HEADER;
721                                break;
722                            case HttpTokens.COLON:
723                                if (_length > 0 && _cached==null)
724                                    _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length);
725                                _length=-1;
726                                _state=STATE_HEADER_VALUE;
727                                break;
728                            case HttpTokens.SPACE:
729                            case HttpTokens.TAB:
730                                _state=STATE_HEADER_NAME;
731                                break;
732                            default:
733                            {
734                                _cached=null;
735                                _length++;
736                            }
737                        }
738                        break;
739
740                    case STATE_HEADER_VALUE:
741                        switch(ch)
742                        {
743                            case HttpTokens.CARRIAGE_RETURN:
744                            case HttpTokens.LINE_FEED:
745                                if (_length > 0)
746                                {
747                                    if (_tok1.length() == 0)
748                                        _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length);
749                                    else
750                                    {
751                                        // Continuation line!
752                                        if (_multiLineValue == null) _multiLineValue=_tok1.toString(StringUtil.__ISO_8859_1);
753                                        _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length);
754                                        _multiLineValue += " " + _tok1.toString(StringUtil.__ISO_8859_1);
755                                    }
756                                }
757                                _eol=ch;
758                                _state=STATE_HEADER;
759                                break;
760                            case HttpTokens.SPACE:
761                            case HttpTokens.TAB:
762                                break;
763                            default:
764                            {
765                                if (_length == -1)
766                                    _buffer.mark();
767                                _length=_buffer.getIndex() - _buffer.markIndex();
768                                _state=STATE_HEADER_IN_VALUE;
769                            }
770                        }
771                        break;
772
773                    case STATE_HEADER_IN_VALUE:
774                        switch(ch)
775                        {
776                            case HttpTokens.CARRIAGE_RETURN:
777                            case HttpTokens.LINE_FEED:
778                                if (_length > 0)
779                                {
780                                    if (_tok1.length() == 0)
781                                        _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length);
782                                    else
783                                    {
784                                        // Continuation line!
785                                        if (_multiLineValue == null) _multiLineValue=_tok1.toString(StringUtil.__ISO_8859_1);
786                                        _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length);
787                                        _multiLineValue += " " + _tok1.toString(StringUtil.__ISO_8859_1);
788                                    }
789                                }
790                                _eol=ch;
791                                _state=STATE_HEADER;
792                                break;
793                            case HttpTokens.SPACE:
794                            case HttpTokens.TAB:
795                                _state=STATE_HEADER_VALUE;
796                                break;
797                            default:
798                                _length++;
799                        }
800                        break;
801                }
802            } // end of HEADER states loop
803
804            // ==========================
805
806            // Handle HEAD response
807            if (_responseStatus>0 && _headResponse)
808            {
809                _state=_persistent||(_responseStatus>=100&&_responseStatus<200)?STATE_END:STATE_SEEKING_EOF;
810                _handler.messageComplete(_contentLength);
811            }
812
813
814            // ==========================
815
816            // Handle _content
817            length=_buffer.length();
818            Buffer chunk;
819            last=_state;
820            while (_state > STATE_END && length > 0)
821            {
822                if (last!=_state)
823                {
824                    progress++;
825                    last=_state;
826                }
827
828                if (_eol == HttpTokens.CARRIAGE_RETURN && _buffer.peek() == HttpTokens.LINE_FEED)
829                {
830                    _eol=_buffer.get();
831                    length=_buffer.length();
832                    continue;
833                }
834                _eol=0;
835                switch (_state)
836                {
837                    case STATE_EOF_CONTENT:
838                        chunk=_buffer.get(_buffer.length());
839                        _contentPosition += chunk.length();
840                        _contentView.update(chunk);
841                        _handler.content(chunk); // May recurse here
842                        // TODO adjust the _buffer to keep unconsumed content
843                        return 1;
844
845                    case STATE_CONTENT:
846                    {
847                        long remaining=_contentLength - _contentPosition;
848                        if (remaining == 0)
849                        {
850                            _state=_persistent?STATE_END:STATE_SEEKING_EOF;
851                            _handler.messageComplete(_contentPosition);
852                            return 1;
853                        }
854
855                        if (length > remaining)
856                        {
857                            // We can cast reamining to an int as we know that it is smaller than
858                            // or equal to length which is already an int.
859                            length=(int)remaining;
860                        }
861
862                        chunk=_buffer.get(length);
863                        _contentPosition += chunk.length();
864                        _contentView.update(chunk);
865                        _handler.content(chunk); // May recurse here
866
867                        if(_contentPosition == _contentLength)
868                        {
869                            _state=_persistent?STATE_END:STATE_SEEKING_EOF;
870                            _handler.messageComplete(_contentPosition);
871                        }
872                        // TODO adjust the _buffer to keep unconsumed content
873                        return 1;
874                    }
875
876                    case STATE_CHUNKED_CONTENT:
877                    {
878                        ch=_buffer.peek();
879                        if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
880                            _eol=_buffer.get();
881                        else if (ch <= HttpTokens.SPACE)
882                            _buffer.get();
883                        else
884                        {
885                            _chunkLength=0;
886                            _chunkPosition=0;
887                            _state=STATE_CHUNK_SIZE;
888                        }
889                        break;
890                    }
891
892                    case STATE_CHUNK_SIZE:
893                    {
894                        ch=_buffer.get();
895                        if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
896                        {
897                            _eol=ch;
898
899                            if (_chunkLength == 0)
900                            {
901                                if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED)
902                                    _eol=_buffer.get();
903                                _state=_persistent?STATE_END:STATE_SEEKING_EOF;
904                                _handler.messageComplete(_contentPosition);
905                                return 1;
906                            }
907                            else
908                                _state=STATE_CHUNK;
909                        }
910                        else if (ch <= HttpTokens.SPACE || ch == HttpTokens.SEMI_COLON)
911                            _state=STATE_CHUNK_PARAMS;
912                        else if (ch >= '0' && ch <= '9')
913                            _chunkLength=_chunkLength * 16 + (ch - '0');
914                        else if (ch >= 'a' && ch <= 'f')
915                            _chunkLength=_chunkLength * 16 + (10 + ch - 'a');
916                        else if (ch >= 'A' && ch <= 'F')
917                            _chunkLength=_chunkLength * 16 + (10 + ch - 'A');
918                        else
919                            throw new IOException("bad chunk char: " + ch);
920                        break;
921                    }
922
923                    case STATE_CHUNK_PARAMS:
924                    {
925                        ch=_buffer.get();
926                        if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
927                        {
928                            _eol=ch;
929                            if (_chunkLength == 0)
930                            {
931                                if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED)
932                                    _eol=_buffer.get();
933                                _state=_persistent?STATE_END:STATE_SEEKING_EOF;
934                                _handler.messageComplete(_contentPosition);
935                                return 1;
936                            }
937                            else
938                                _state=STATE_CHUNK;
939                        }
940                        break;
941                    }
942
943                    case STATE_CHUNK:
944                    {
945                        int remaining=_chunkLength - _chunkPosition;
946                        if (remaining == 0)
947                        {
948                            _state=STATE_CHUNKED_CONTENT;
949                            break;
950                        }
951                        else if (length > remaining)
952                            length=remaining;
953                        chunk=_buffer.get(length);
954                        _contentPosition += chunk.length();
955                        _chunkPosition += chunk.length();
956                        _contentView.update(chunk);
957                        _handler.content(chunk); // May recurse here
958                        // TODO adjust the _buffer to keep unconsumed content
959                        return 1;
960                    }
961
962                    case STATE_SEEKING_EOF:
963                    {
964                        // Close if there is more data than CRLF
965                        if (_buffer.length()>2)
966                        {
967                            _state=STATE_END;
968                            _endp.close();
969                        }
970                        else
971                        {
972                            // or if the data is not white space
973                            while (_buffer.length()>0)
974                                if (!Character.isWhitespace(_buffer.get()))
975                                {
976                                    _state=STATE_END;
977                                    _endp.close();
978                                    _buffer.clear();
979                                }
980                        }
981
982                        _buffer.clear();
983                        break;
984                    }
985                }
986
987                length=_buffer.length();
988            }
989
990            return progress;
991        }
992        catch(HttpException e)
993        {
994            _persistent=false;
995            _state=STATE_SEEKING_EOF;
996            throw e;
997        }
998    }
999
1000    /* ------------------------------------------------------------------------------- */
1001    /** fill the buffers from the endpoint
1002     *
1003     */
1004    protected int fill() throws IOException
1005    {
1006        // Do we have a buffer?
1007        if (_buffer==null)
1008            _buffer=getHeaderBuffer();
1009
1010        // Is there unconsumed content in body buffer
1011        if (_state>STATE_END && _buffer==_header && _header!=null && !_header.hasContent() && _body!=null && _body.hasContent())
1012        {
1013            _buffer=_body;
1014            return _buffer.length();
1015        }
1016
1017        // Shall we switch to a body buffer?
1018        if (_buffer==_header && _state>STATE_END && _header.length()==0 && (_forceContentBuffer || (_contentLength-_contentPosition)>_header.capacity()) && (_body!=null||_buffers!=null))
1019        {
1020            if (_body==null)
1021                _body=_buffers.getBuffer();
1022            _buffer=_body;
1023        }
1024
1025        // Do we have somewhere to fill from?
1026        if (_endp != null )
1027        {
1028            // Shall we compact the body?
1029            if (_buffer==_body || _state>STATE_END)
1030            {
1031                _buffer.compact();
1032            }
1033
1034            // Are we full?
1035            if (_buffer.space() == 0)
1036            {
1037                LOG.warn("HttpParser Full for {} ",_endp);
1038                _buffer.clear();
1039                throw new HttpException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413, "Request Entity Too Large: "+(_buffer==_body?"body":"head"));
1040            }
1041
1042            try
1043            {
1044                int filled = _endp.fill(_buffer);
1045                return filled;
1046            }
1047            catch(IOException e)
1048            {
1049                LOG.debug(e);
1050                throw (e instanceof EofException) ? e:new EofException(e);
1051            }
1052        }
1053
1054        return -1;
1055    }
1056
1057    /* ------------------------------------------------------------------------------- */
1058    public void reset()
1059    {
1060        // reset state
1061        _contentView.setGetIndex(_contentView.putIndex());
1062        _state=_persistent?STATE_START:(_endp.isInputShutdown()?STATE_END:STATE_SEEKING_EOF);
1063        _contentLength=HttpTokens.UNKNOWN_CONTENT;
1064        _contentPosition=0;
1065        _length=0;
1066        _responseStatus=0;
1067
1068        // Consume LF if CRLF
1069        if (_eol == HttpTokens.CARRIAGE_RETURN && _buffer!=null && _buffer.hasContent() && _buffer.peek() == HttpTokens.LINE_FEED)
1070            _eol=_buffer.get();
1071
1072        if (_body!=null && _body.hasContent())
1073        {
1074            // There is content in the body after the end of the request.
1075            // This is probably a pipelined header of the next request, so we need to
1076            // copy it to the header buffer.
1077            if (_header==null)
1078                getHeaderBuffer();
1079            else
1080            {
1081                _header.setMarkIndex(-1);
1082                _header.compact();
1083            }
1084            int take=_header.space();
1085            if (take>_body.length())
1086                take=_body.length();
1087            _body.peek(_body.getIndex(),take);
1088            _body.skip(_header.put(_body.peek(_body.getIndex(),take)));
1089        }
1090
1091        if (_header!=null)
1092        {
1093            _header.setMarkIndex(-1);
1094            _header.compact();
1095        }
1096        if (_body!=null)
1097            _body.setMarkIndex(-1);
1098
1099        _buffer=_header;
1100        returnBuffers();
1101    }
1102
1103
1104    /* ------------------------------------------------------------------------------- */
1105    public void returnBuffers()
1106    {
1107        if (_body!=null && !_body.hasContent() && _body.markIndex()==-1 && _buffers!=null)
1108        {
1109            if (_buffer==_body)
1110                _buffer=_header;
1111            if (_buffers!=null)
1112                _buffers.returnBuffer(_body);
1113            _body=null;
1114        }
1115
1116        if (_header!=null && !_header.hasContent() && _header.markIndex()==-1 && _buffers!=null)
1117        {
1118            if (_buffer==_header)
1119                _buffer=null;
1120            _buffers.returnBuffer(_header);
1121            _header=null;
1122        }
1123    }
1124
1125    /* ------------------------------------------------------------------------------- */
1126    public void setState(int state)
1127    {
1128        this._state=state;
1129        _contentLength=HttpTokens.UNKNOWN_CONTENT;
1130    }
1131
1132    /* ------------------------------------------------------------------------------- */
1133    public String toString(Buffer buf)
1134    {
1135        return "state=" + _state + " length=" + _length + " buf=" + buf.hashCode();
1136    }
1137
1138    /* ------------------------------------------------------------------------------- */
1139    @Override
1140    public String toString()
1141    {
1142        return String.format("%s{s=%d,l=%d,c=%d}",
1143                getClass().getSimpleName(),
1144                _state,
1145                _length,
1146                _contentLength);
1147    }
1148
1149    /* ------------------------------------------------------------ */
1150    public Buffer getHeaderBuffer()
1151    {
1152        if (_header == null)
1153        {
1154            _header=_buffers.getHeader();
1155            _tok0.update(_header);
1156            _tok1.update(_header);
1157        }
1158        return _header;
1159    }
1160
1161    /* ------------------------------------------------------------ */
1162    public Buffer getBodyBuffer()
1163    {
1164        return _body;
1165    }
1166
1167    /* ------------------------------------------------------------ */
1168    /**
1169     * @param force True if a new buffer will be forced to be used for content and the header buffer will not be used.
1170     */
1171    public void setForceContentBuffer(boolean force)
1172    {
1173        _forceContentBuffer=force;
1174    }
1175
1176    /* ------------------------------------------------------------ */
1177    public Buffer blockForContent(long maxIdleTime) throws IOException
1178    {
1179        if (_contentView.length()>0)
1180            return _contentView;
1181
1182        if (getState() <= STATE_END || isState(STATE_SEEKING_EOF))
1183            return null;
1184
1185        try
1186        {
1187            parseNext();
1188
1189            // parse until some progress is made (or IOException thrown for timeout)
1190            while(_contentView.length() == 0 && !(isState(HttpParser.STATE_END)||isState(HttpParser.STATE_SEEKING_EOF)) && _endp!=null && _endp.isOpen())
1191            {
1192                if (!_endp.isBlocking())
1193                {
1194                    if (parseNext()>0)
1195                        continue;
1196
1197                    if (!_endp.blockReadable(maxIdleTime))
1198                    {
1199                        _endp.close();
1200                        throw new EofException("timeout");
1201                    }
1202                }
1203
1204                parseNext();
1205            }
1206        }
1207        catch(IOException e)
1208        {
1209            // TODO is this needed?
1210            _endp.close();
1211            throw e;
1212        }
1213
1214        return _contentView.length()>0?_contentView:null;
1215    }
1216
1217    /* ------------------------------------------------------------ */
1218    /* (non-Javadoc)
1219     * @see java.io.InputStream#available()
1220     */
1221    public int available() throws IOException
1222    {
1223        if (_contentView!=null && _contentView.length()>0)
1224            return _contentView.length();
1225
1226        if (_endp.isBlocking())
1227        {
1228            if (_state>0 && _endp instanceof StreamEndPoint)
1229                return ((StreamEndPoint)_endp).getInputStream().available()>0?1:0;
1230
1231            return 0;
1232        }
1233
1234        parseNext();
1235        return _contentView==null?0:_contentView.length();
1236    }
1237
1238    /* ------------------------------------------------------------ */
1239    /* ------------------------------------------------------------ */
1240    /* ------------------------------------------------------------ */
1241    public static abstract class EventHandler
1242    {
1243        public abstract void content(Buffer ref) throws IOException;
1244
1245        public void headerComplete() throws IOException
1246        {
1247        }
1248
1249        public void messageComplete(long contentLength) throws IOException
1250        {
1251        }
1252
1253        /**
1254         * This is the method called by parser when a HTTP Header name and value is found
1255         */
1256        public void parsedHeader(Buffer name, Buffer value) throws IOException
1257        {
1258        }
1259
1260        /**
1261         * This is the method called by parser when the HTTP request line is parsed
1262         */
1263        public abstract void startRequest(Buffer method, Buffer url, Buffer version)
1264                throws IOException;
1265
1266        /**
1267         * This is the method called by parser when the HTTP request line is parsed
1268         */
1269        public abstract void startResponse(Buffer version, int status, Buffer reason)
1270                throws IOException;
1271
1272        public void earlyEOF()
1273        {}
1274    }
1275
1276
1277
1278
1279}
1280