View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 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  
19  package org.eclipse.jetty.http;
20  
21  import java.nio.ByteBuffer;
22  import java.nio.charset.StandardCharsets;
23  
24  import org.eclipse.jetty.http.HttpTokens.EndOfContent;
25  import org.eclipse.jetty.util.ArrayTernaryTrie;
26  import org.eclipse.jetty.util.ArrayTrie;
27  import org.eclipse.jetty.util.BufferUtil;
28  import org.eclipse.jetty.util.StringUtil;
29  import org.eclipse.jetty.util.Trie;
30  import org.eclipse.jetty.util.TypeUtil;
31  import org.eclipse.jetty.util.log.Log;
32  import org.eclipse.jetty.util.log.Logger;
33  
34  
35  /* ------------------------------------------------------------ */
36  /** A Parser for HTTP 0.9, 1.0 and 1.1
37   * <p>
38   * The is parser parses HTTP client and server messages from buffers
39   * passed in the {@link #parseNext(ByteBuffer)} method.  The parsed
40   * elements of the HTTP message are passed as event calls to the 
41   * {@link HttpHandler} instance the parser is constructed with.
42   * If the passed handler is a {@link RequestHandler} then server side
43   * parsing is performed and if it is a {@link ResponseHandler}, then 
44   * client side parsing is done.
45   * </p>
46   * <p>
47   * The contract of the {@link HttpHandler} API is that if a call returns 
48   * true then the call to {@link #parseNext(ByteBuffer)} will return as 
49   * soon as possible also with a true response.  Typically this indicates
50   * that the parsing has reached a stage where the caller should process 
51   * the events accumulated by the handler.    It is the preferred calling
52   * style that handling such as calling a servlet to process a request, 
53   * should be done after a true return from {@link #parseNext(ByteBuffer)}
54   * rather than from within the scope of a call like 
55   * {@link RequestHandler#messageComplete()}
56   * </p>
57   * <p>
58   * For performance, the parse is heavily dependent on the 
59   * {@link Trie#getBest(ByteBuffer, int, int)} method to look ahead in a
60   * single pass for both the structure ( : and CRLF ) and semantic (which
61   * header and value) of a header.  Specifically the static {@link HttpField#CACHE}
62   * is used to lookup common combinations of headers and values 
63   * (eg. "Connection: close"), or just header names (eg. "Connection:" ).
64   * For headers who's value is not known statically (eg. Host, COOKIE) then a
65   * per parser dynamic Trie of {@link HttpFields} from previous parsed messages
66   * is used to help the parsing of subsequent messages.
67   * </p>
68   * <p>
69   * If the system property "org.eclipse.jetty.http.HttpParser.STRICT" is set to true,
70   * then the parser will strictly pass on the exact strings received for methods and header
71   * fields.  Otherwise a fast case insensitive string lookup is used that may alter the
72   * case of the method and/or headers
73   * </p>
74   */
75  public class HttpParser
76  {
77      public static final Logger LOG = Log.getLogger(HttpParser.class);
78      public final static boolean __STRICT=Boolean.getBoolean("org.eclipse.jetty.http.HttpParser.STRICT"); 
79      public final static int INITIAL_URI_LENGTH=256;
80  
81      /**
82       * Cache of common {@link HttpField}s including: <UL>
83       * <LI>Common static combinations such as:<UL>
84       *   <li>Connection: close
85       *   <li>Accept-Encoding: gzip
86       *   <li>Content-Length: 0
87       * </ul>
88       * <li>Combinations of Content-Type header for common mime types by common charsets
89       * <li>Most common headers with null values so that a lookup will at least
90       * determine the header name even if the name:value combination is not cached
91       * </ul>
92       */
93      public final static Trie<HttpField> CACHE = new ArrayTrie<>(2048);
94      public final static Trie<HttpField> CONTENT_TYPE = new ArrayTrie<>(512);
95      
96      // States
97      public enum State
98      {
99          START,
100         METHOD,
101         RESPONSE_VERSION,
102         SPACE1,
103         STATUS,
104         URI,
105         SPACE2,
106         REQUEST_VERSION,
107         REASON,
108         HEADER,
109         HEADER_IN_NAME,
110         HEADER_VALUE,
111         HEADER_IN_VALUE,
112         CONTENT,
113         EOF_CONTENT,
114         CHUNKED_CONTENT,
115         CHUNK_SIZE,
116         CHUNK_PARAMS,
117         CHUNK,
118         END,
119         CLOSED
120     }
121 
122     private final boolean DEBUG=LOG.isDebugEnabled(); // Cache debug to help branch prediction
123     private final HttpHandler<ByteBuffer> _handler;
124     private final RequestHandler<ByteBuffer> _requestHandler;
125     private final ResponseHandler<ByteBuffer> _responseHandler;
126     private final int _maxHeaderBytes;
127     private final boolean _strict;
128     private HttpField _field;
129     private HttpHeader _header;
130     private String _headerString;
131     private HttpHeaderValue _value;
132     private String _valueString;
133     private int _responseStatus;
134     private int _headerBytes;
135     private boolean _host;
136 
137     /* ------------------------------------------------------------------------------- */
138     private volatile State _state=State.START;
139     private volatile boolean _eof;
140     private volatile boolean _closed;
141     private HttpMethod _method;
142     private String _methodString;
143     private HttpVersion _version;
144     private ByteBuffer _uri=ByteBuffer.allocate(INITIAL_URI_LENGTH); // Tune?
145     private EndOfContent _endOfContent;
146     private long _contentLength;
147     private long _contentPosition;
148     private int _chunkLength;
149     private int _chunkPosition;
150     private boolean _headResponse;
151     private boolean _cr;
152     private ByteBuffer _contentChunk;
153     private Trie<HttpField> _connectionFields;
154 
155     private int _length;
156     private final StringBuilder _string=new StringBuilder();
157 
158     static
159     {
160         CACHE.put(new HttpField(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE));
161         CACHE.put(new HttpField(HttpHeader.CONNECTION,HttpHeaderValue.KEEP_ALIVE));
162         CACHE.put(new HttpField(HttpHeader.CONNECTION,HttpHeaderValue.UPGRADE));
163         CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip"));
164         CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip, deflate"));
165         CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip,deflate,sdch"));
166         CACHE.put(new HttpField(HttpHeader.ACCEPT_LANGUAGE,"en-US,en;q=0.5"));
167         CACHE.put(new HttpField(HttpHeader.ACCEPT_LANGUAGE,"en-GB,en-US;q=0.8,en;q=0.6"));
168         CACHE.put(new HttpField(HttpHeader.ACCEPT_CHARSET,"ISO-8859-1,utf-8;q=0.7,*;q=0.3"));
169         CACHE.put(new HttpField(HttpHeader.ACCEPT,"*/*"));
170         CACHE.put(new HttpField(HttpHeader.ACCEPT,"image/png,image/*;q=0.8,*/*;q=0.5"));
171         CACHE.put(new HttpField(HttpHeader.ACCEPT,"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"));
172         CACHE.put(new HttpField(HttpHeader.PRAGMA,"no-cache"));
173         CACHE.put(new HttpField(HttpHeader.CACHE_CONTROL,"private, no-cache, no-cache=Set-Cookie, proxy-revalidate"));
174         CACHE.put(new HttpField(HttpHeader.CACHE_CONTROL,"no-cache"));
175         CACHE.put(new HttpField(HttpHeader.CONTENT_LENGTH,"0"));
176         CACHE.put(new HttpField(HttpHeader.CONTENT_ENCODING,"gzip"));
177         CACHE.put(new HttpField(HttpHeader.CONTENT_ENCODING,"deflate"));
178         CACHE.put(new HttpField(HttpHeader.TRANSFER_ENCODING,"chunked"));
179         CACHE.put(new HttpField(HttpHeader.EXPIRES,"Fri, 01 Jan 1990 00:00:00 GMT"));
180         
181         // Content types
182         for (String type : new String[]{"text/plain","text/html","text/xml","text/json","application/x-www-form-urlencoded"})
183         {
184             HttpField field=new HttpField(HttpHeader.CONTENT_TYPE,type);
185             CACHE.put(field);
186             CONTENT_TYPE.put(type,field);
187             
188             for (String charset : new String[]{"UTF-8","ISO-8859-1"})
189             {
190                 String type_charset=type+"; charset="+charset;
191                 field=new HttpField(HttpHeader.CONTENT_TYPE,type_charset);
192                 CACHE.put(field);
193                 CACHE.put(new HttpField(HttpHeader.CONTENT_TYPE,type+";charset="+charset));
194                 CONTENT_TYPE.put(type_charset,field);
195                 CONTENT_TYPE.put(type+";charset="+charset,field);
196             }
197         }
198     
199         // Add headers with null values so HttpParser can avoid looking up name again for unknown values
200         for (HttpHeader h:HttpHeader.values())
201             if (!CACHE.put(new HttpField(h,(String)null)))
202                 throw new IllegalStateException("CACHE FULL");
203         // Add some more common headers
204         CACHE.put(new HttpField(HttpHeader.REFERER,(String)null));
205         CACHE.put(new HttpField(HttpHeader.IF_MODIFIED_SINCE,(String)null));
206         CACHE.put(new HttpField(HttpHeader.IF_NONE_MATCH,(String)null));
207         CACHE.put(new HttpField(HttpHeader.AUTHORIZATION,(String)null));
208         CACHE.put(new HttpField(HttpHeader.COOKIE,(String)null));
209     }
210 
211     /* ------------------------------------------------------------------------------- */
212     public HttpParser(RequestHandler<ByteBuffer> handler)
213     {
214         this(handler,-1,__STRICT);
215     }
216 
217     /* ------------------------------------------------------------------------------- */
218     public HttpParser(ResponseHandler<ByteBuffer> handler)
219     {
220         this(handler,-1,__STRICT);
221     }
222 
223     /* ------------------------------------------------------------------------------- */
224     public HttpParser(RequestHandler<ByteBuffer> handler,int maxHeaderBytes)
225     {
226         this(handler,maxHeaderBytes,__STRICT);
227     }
228 
229     /* ------------------------------------------------------------------------------- */
230     public HttpParser(ResponseHandler<ByteBuffer> handler,int maxHeaderBytes)
231     {
232         this(handler,maxHeaderBytes,__STRICT);
233     }
234     
235     /* ------------------------------------------------------------------------------- */
236     public HttpParser(RequestHandler<ByteBuffer> handler,int maxHeaderBytes,boolean strict)
237     {
238         _handler=handler;
239         _requestHandler=handler;
240         _responseHandler=null;
241         _maxHeaderBytes=maxHeaderBytes;
242         _strict=strict;
243     }
244 
245     /* ------------------------------------------------------------------------------- */
246     public HttpParser(ResponseHandler<ByteBuffer> handler,int maxHeaderBytes,boolean strict)
247     {
248         _handler=handler;
249         _requestHandler=null;
250         _responseHandler=handler;
251         _maxHeaderBytes=maxHeaderBytes;
252         _strict=strict;
253     }
254 
255     /* ------------------------------------------------------------------------------- */
256     public long getContentLength()
257     {
258         return _contentLength;
259     }
260 
261     /* ------------------------------------------------------------ */
262     public long getContentRead()
263     {
264         return _contentPosition;
265     }
266 
267     /* ------------------------------------------------------------ */
268     /** Set if a HEAD response is expected
269      * @param head
270      */
271     public void setHeadResponse(boolean head)
272     {
273         _headResponse=head;
274     }
275 
276     /* ------------------------------------------------------------------------------- */
277     protected void setResponseStatus(int status)
278     {
279         _responseStatus=status;
280     }
281 
282     /* ------------------------------------------------------------------------------- */
283     public State getState()
284     {
285         return _state;
286     }
287 
288     /* ------------------------------------------------------------------------------- */
289     public boolean inContentState()
290     {
291         return _state.ordinal()>=State.CONTENT.ordinal() && _state.ordinal()<State.END.ordinal();
292     }
293 
294     /* ------------------------------------------------------------------------------- */
295     public boolean inHeaderState()
296     {
297         return _state.ordinal() < State.CONTENT.ordinal();
298     }
299 
300     /* ------------------------------------------------------------------------------- */
301     public boolean isChunking()
302     {
303         return _endOfContent==EndOfContent.CHUNKED_CONTENT;
304     }
305 
306     /* ------------------------------------------------------------ */
307     public boolean isStart()
308     {
309         return isState(State.START);
310     }
311 
312     /* ------------------------------------------------------------ */
313     public boolean isClosed()
314     {
315         return isState(State.CLOSED);
316     }
317 
318     /* ------------------------------------------------------------ */
319     public boolean isIdle()
320     {
321         return isState(State.START)||isState(State.END)||isState(State.CLOSED);
322     }
323 
324     /* ------------------------------------------------------------ */
325     public boolean isComplete()
326     {
327         return isState(State.END)||isState(State.CLOSED);
328     }
329 
330     /* ------------------------------------------------------------------------------- */
331     public boolean isState(State state)
332     {
333         return _state == state;
334     }
335 
336     /* ------------------------------------------------------------------------------- */
337     private static class BadMessage extends Error
338     {
339         private static final long serialVersionUID = 1L;
340         private final int _code;
341         private final String _message;
342 
343         BadMessage()
344         {
345             this(400,null);
346         }
347         
348         BadMessage(int code)
349         {
350             this(code,null);
351         }
352         
353         BadMessage(String message)
354         {
355             this(400,message);
356         }
357         
358         BadMessage(int code,String message)
359         {
360             _code=code;
361             _message=message;
362         }
363         
364     }
365     
366     /* ------------------------------------------------------------------------------- */
367     private byte next(ByteBuffer buffer)
368     {
369         byte ch = buffer.get();
370         
371         if (_cr)
372         {
373             if (ch!=HttpTokens.LINE_FEED)
374                 throw new BadMessage("Bad EOL");
375             _cr=false;
376             return ch;
377         }
378 
379         if (ch>=0 && ch<HttpTokens.SPACE)
380         {
381             if (ch==HttpTokens.CARRIAGE_RETURN)
382             {
383                 if (buffer.hasRemaining())
384                 {
385                     if(_maxHeaderBytes>0 && _state.ordinal()<State.END.ordinal())
386                         _headerBytes++;
387                     ch=buffer.get();
388                     if (ch!=HttpTokens.LINE_FEED)
389                         throw new BadMessage("Bad EOL");
390                 }
391                 else
392                 {
393                     _cr=true;
394                     // Can return 0 here to indicate the need for more characters, 
395                     // because a real 0 in the buffer would cause a BadMessage below 
396                     return 0;
397                 }
398             }
399             // Only LF or TAB acceptable special characters
400             else if (!(ch==HttpTokens.LINE_FEED || ch==HttpTokens.TAB))
401                 throw new BadMessage("Illegal character");
402         }
403         
404         return ch;
405     }
406     
407     /* ------------------------------------------------------------------------------- */
408     /* Quick lookahead for the start state looking for a request method or a HTTP version,
409      * otherwise skip white space until something else to parse.
410      */
411     private boolean quickStart(ByteBuffer buffer)
412     {
413         if (_requestHandler!=null)
414         {
415             _method = HttpMethod.lookAheadGet(buffer);
416             if (_method!=null)
417             {
418                 _methodString = _method.asString();
419                 buffer.position(buffer.position()+_methodString.length()+1);
420                 setState(State.SPACE1);
421                 return false;
422             }
423         }
424         else if (_responseHandler!=null)
425         {
426             _version = HttpVersion.lookAheadGet(buffer);
427             if (_version!=null)
428             {
429                 buffer.position(buffer.position()+_version.asString().length()+1);
430                 setState(State.SPACE1);
431                 return false;
432             }
433         }
434         
435         // Quick start look
436         while (_state==State.START && buffer.hasRemaining())
437         {
438             int ch=next(buffer);
439 
440             if (ch > HttpTokens.SPACE)
441             {
442                 _string.setLength(0);
443                 _string.append((char)ch);
444                 setState(_requestHandler!=null?State.METHOD:State.RESPONSE_VERSION);
445                 return false;
446             }
447             else if (ch==0)
448                 break;
449             else if (ch<0)
450                 throw new BadMessage();
451         }
452         return false;
453     }
454 
455     /* ------------------------------------------------------------------------------- */
456     private void setString(String s)
457     {
458         _string.setLength(0);
459         _string.append(s);
460         _length=s.length();
461     }
462     
463     /* ------------------------------------------------------------------------------- */
464     private String takeString()
465     {
466         _string.setLength(_length);
467         String s =_string.toString();
468         _string.setLength(0);
469         _length=-1;
470         return s;
471     }
472 
473     /* ------------------------------------------------------------------------------- */
474     /* Parse a request or response line
475      */
476     private boolean parseLine(ByteBuffer buffer)
477     {
478         boolean handle=false;
479 
480         // Process headers
481         while (_state.ordinal()<State.HEADER.ordinal() && buffer.hasRemaining() && !handle)
482         {
483             // process each character
484             byte ch=next(buffer);
485             if (ch==0)
486                 break;
487 
488             if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes)
489             {
490                 if (_state==State.URI)
491                 {
492                     LOG.warn("URI is too large >"+_maxHeaderBytes);
493                     throw new BadMessage(HttpStatus.REQUEST_URI_TOO_LONG_414);
494                 }
495                 else
496                 {
497                     if (_requestHandler!=null)
498                         LOG.warn("request is too large >"+_maxHeaderBytes);
499                     else
500                         LOG.warn("response is too large >"+_maxHeaderBytes);
501                     throw new BadMessage(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413);
502                 }
503             }
504 
505             switch (_state)
506             {
507                 case METHOD:
508                     if (ch == HttpTokens.SPACE)
509                     {
510                         _length=_string.length();
511                         _methodString=takeString();
512                         HttpMethod method=HttpMethod.CACHE.get(_methodString);
513                         if (method!=null && !_strict)
514                             _methodString=method.asString();
515                         setState(State.SPACE1);
516                     }
517                     else if (ch < HttpTokens.SPACE)
518                         throw new BadMessage(ch<0?"Illegal character":"No URI");
519                     else
520                         _string.append((char)ch);
521                     break;
522 
523                 case RESPONSE_VERSION:
524                     if (ch == HttpTokens.SPACE)
525                     {
526                         _length=_string.length();
527                         String version=takeString();
528                         _version=HttpVersion.CACHE.get(version);
529                         if (_version==null)
530                             throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Unknown Version");
531                         setState(State.SPACE1);
532                     }
533                     else if (ch < HttpTokens.SPACE)
534                         throw new BadMessage(ch<0?"Illegal character":"No Status");
535                     else
536                         _string.append((char)ch);
537                     break;
538 
539                 case SPACE1:
540                     if (ch > HttpTokens.SPACE || ch<0)
541                     {
542                         if (_responseHandler!=null)
543                         {
544                             setState(State.STATUS);
545                             setResponseStatus(ch-'0');
546                         }
547                         else
548                         {
549                             _uri.clear();
550                             setState(State.URI);
551                             // quick scan for space or EoBuffer
552                             if (buffer.hasArray())
553                             {
554                                 byte[] array=buffer.array();
555                                 int p=buffer.arrayOffset()+buffer.position();
556                                 int l=buffer.arrayOffset()+buffer.limit();
557                                 int i=p;
558                                 while (i<l && array[i]>HttpTokens.SPACE)
559                                     i++;
560 
561                                 int len=i-p;
562                                 _headerBytes+=len;
563                                 
564                                 if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes)
565                                 {
566                                     LOG.warn("URI is too large >"+_maxHeaderBytes);
567                                     throw new BadMessage(HttpStatus.REQUEST_URI_TOO_LONG_414);
568                                 }
569                                 if (_uri.remaining()<=len)
570                                 {
571                                     ByteBuffer uri = ByteBuffer.allocate(_uri.capacity()+2*len);
572                                     _uri.flip();
573                                     uri.put(_uri);
574                                     _uri=uri;
575                                 }
576                                 _uri.put(array,p-1,len+1);
577                                 buffer.position(i-buffer.arrayOffset());
578                             }
579                             else
580                                 _uri.put(ch);
581                         }
582                     }
583                     else if (ch < HttpTokens.SPACE)
584                     {
585                         throw new BadMessage(HttpStatus.BAD_REQUEST_400,_requestHandler!=null?"No URI":"No Status");
586                     }
587                     break;
588 
589                 case STATUS:
590                     if (ch == HttpTokens.SPACE)
591                     {
592                         setState(State.SPACE2);
593                     }
594                     else if (ch>='0' && ch<='9')
595                     {
596                         _responseStatus=_responseStatus*10+(ch-'0');
597                     }
598                     else if (ch < HttpTokens.SPACE && ch>=0)
599                     {
600                         handle=_responseHandler.startResponse(_version, _responseStatus, null)||handle;
601                         setState(State.HEADER);
602                     }
603                     else
604                     {
605                         throw new BadMessage();
606                     }
607                     break;
608 
609                 case URI:
610                     if (ch == HttpTokens.SPACE)
611                     {
612                         setState(State.SPACE2);
613                     }
614                     else if (ch < HttpTokens.SPACE && ch>=0)
615                     {
616                         // HTTP/0.9
617                         _uri.flip();
618                         handle=_requestHandler.startRequest(_method,_methodString,_uri,null)||handle;
619                         setState(State.END);
620                         BufferUtil.clear(buffer);
621                         handle=_handler.headerComplete()||handle;
622                         handle=_handler.messageComplete()||handle;
623                     }
624                     else
625                     {
626                         if (!_uri.hasRemaining())
627                         {
628                             ByteBuffer uri = ByteBuffer.allocate(_uri.capacity()*2);
629                             _uri.flip();
630                             uri.put(_uri);
631                             _uri=uri;
632                         }
633                         _uri.put(ch);
634                     }
635                     break;
636 
637                 case SPACE2:
638                     if (ch > HttpTokens.SPACE)
639                     {
640                         _string.setLength(0);
641                         _string.append((char)ch);
642                         if (_responseHandler!=null)
643                         {
644                             _length=1;
645                             setState(State.REASON);
646                         }
647                         else
648                         {
649                             setState(State.REQUEST_VERSION);
650 
651                             // try quick look ahead for HTTP Version
652                             HttpVersion version;
653                             if (buffer.position()>0 && buffer.hasArray())
654                                 version=HttpVersion.lookAheadGet(buffer.array(),buffer.arrayOffset()+buffer.position()-1,buffer.arrayOffset()+buffer.limit());
655                             else
656                                 version=HttpVersion.CACHE.getBest(buffer,0,buffer.remaining());
657                             if (version!=null) 
658                             {
659                                 int pos = buffer.position()+version.asString().length()-1;
660                                 if (pos<buffer.limit())
661                                 {
662                                     byte n=buffer.get(pos);
663                                     if (n==HttpTokens.CARRIAGE_RETURN)
664                                     {
665                                         _cr=true;
666                                         _version=version;
667                                         _string.setLength(0);
668                                         buffer.position(pos+1);
669                                     }
670                                     else if (n==HttpTokens.LINE_FEED)
671                                     {
672                                         _version=version;
673                                         _string.setLength(0);
674                                         buffer.position(pos);
675                                     }
676                                 }
677                             }
678                         }
679                     }
680                     else if (ch == HttpTokens.LINE_FEED)
681                     {
682                         if (_responseHandler!=null)
683                         {
684                             handle=_responseHandler.startResponse(_version, _responseStatus, null)||handle;
685                             setState(State.HEADER);
686                         }
687                         else
688                         {
689                             // HTTP/0.9
690                             _uri.flip();
691                             handle=_requestHandler.startRequest(_method,_methodString,_uri, null)||handle;
692                             setState(State.END);
693                             BufferUtil.clear(buffer);
694                             handle=_handler.headerComplete()||handle;
695                             handle=_handler.messageComplete()||handle;
696                         }
697                     }
698                     else if (ch<0)
699                         throw new BadMessage();
700                     break;
701 
702                 case REQUEST_VERSION:
703                     if (ch == HttpTokens.LINE_FEED)
704                     {
705                         if (_version==null)
706                         {
707                             _length=_string.length();
708                             _version=HttpVersion.CACHE.get(takeString());
709                         }
710                         if (_version==null)
711                             throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Unknown Version");
712                         
713                         // Should we try to cache header fields?
714                         if (_connectionFields==null && _version.getVersion()>=HttpVersion.HTTP_1_1.getVersion())
715                         {
716                             int header_cache = _handler.getHeaderCacheSize();
717                             if (header_cache>0)
718                                 _connectionFields=new ArrayTernaryTrie<>(header_cache);
719                         }
720 
721                         setState(State.HEADER);
722                         _uri.flip();
723                         handle=_requestHandler.startRequest(_method,_methodString,_uri, _version)||handle;
724                         continue;
725                     }
726                     else if (ch>=HttpTokens.SPACE)
727                         _string.append((char)ch);
728                     else
729                         throw new BadMessage();
730 
731                     break;
732 
733                 case REASON:
734                     if (ch == HttpTokens.LINE_FEED)
735                     {
736                         String reason=takeString();
737 
738                         setState(State.HEADER);
739                         handle=_responseHandler.startResponse(_version, _responseStatus, reason)||handle;
740                         continue;
741                     }
742                     else if (ch>=HttpTokens.SPACE)
743                     {
744                         _string.append((char)ch);
745                         if (ch!=' '&&ch!='\t')
746                             _length=_string.length();
747                     } 
748                     else
749                         throw new BadMessage();
750                     break;
751 
752                 default:
753                     throw new IllegalStateException(_state.toString());
754 
755             }
756         }
757 
758         return handle;
759     }
760 
761     private boolean handleKnownHeaders(ByteBuffer buffer)
762     {
763         boolean add_to_connection_trie=false;
764         switch (_header)
765         {
766             case CONTENT_LENGTH:
767                 if (_endOfContent != EndOfContent.CHUNKED_CONTENT)
768                 {
769                     try
770                     {
771                         _contentLength=Long.parseLong(_valueString);
772                     }
773                     catch(NumberFormatException e)
774                     {
775                         LOG.ignore(e);
776                         throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad Content-Length");
777                     }
778                     if (_contentLength <= 0)
779                         _endOfContent=EndOfContent.NO_CONTENT;
780                     else
781                         _endOfContent=EndOfContent.CONTENT_LENGTH;
782                 }
783                 break;
784 
785             case TRANSFER_ENCODING:
786                 if (_value==HttpHeaderValue.CHUNKED)
787                     _endOfContent=EndOfContent.CHUNKED_CONTENT;
788                 else
789                 {
790                     if (_valueString.endsWith(HttpHeaderValue.CHUNKED.toString()))
791                         _endOfContent=EndOfContent.CHUNKED_CONTENT;
792                     else if (_valueString.indexOf(HttpHeaderValue.CHUNKED.toString()) >= 0)
793                     {
794                         throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad chunking");
795                     }
796                 }
797                 break;
798 
799             case HOST:
800                 add_to_connection_trie=_connectionFields!=null && _field==null;
801                 _host=true;
802                 String host=_valueString;
803                 int port=0;
804                 if (host==null || host.length()==0)
805                 {
806                     throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad Host header");
807                 }
808 
809                 int len=host.length();
810                 loop: for (int i = len; i-- > 0;)
811                 {
812                     char c2 = (char)(0xff & host.charAt(i));
813                     switch (c2)
814                     {
815                         case ']':
816                             break loop;
817 
818                         case ':':
819                             try
820                             {
821                                 len=i;
822                                 port = StringUtil.toInt(host.substring(i+1));
823                             }
824                             catch (NumberFormatException e)
825                             {
826                                 if (DEBUG)
827                                     LOG.debug(e);
828                                 throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad Host header");
829                             }
830                             break loop;
831                     }
832                 }
833                 if (host.charAt(0)=='[')
834                 {
835                     if (host.charAt(len-1)!=']') 
836                     {
837                         throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad IPv6 Host header");
838                     }
839                     host = host.substring(1,len-1);
840                 }
841                 else if (len!=host.length())
842                     host = host.substring(0,len);
843                 
844                 if (_requestHandler!=null)
845                     _requestHandler.parsedHostHeader(host,port);
846                 
847               break;
848               
849             case CONNECTION:
850                 // Don't cache if not persistent
851                 if (_valueString!=null && _valueString.indexOf("close")>=0)
852                 {
853                     _closed=true;
854                     _connectionFields=null;
855                 }
856                 break;
857 
858             case AUTHORIZATION:
859             case ACCEPT:
860             case ACCEPT_CHARSET:
861             case ACCEPT_ENCODING:
862             case ACCEPT_LANGUAGE:
863             case COOKIE:
864             case CACHE_CONTROL:
865             case USER_AGENT:
866                 add_to_connection_trie=_connectionFields!=null && _field==null;
867                 break;
868                 
869             default: break;
870         }
871     
872         if (add_to_connection_trie && !_connectionFields.isFull() && _header!=null && _valueString!=null)
873         {
874             _field=new HttpField(_header,_valueString);
875             _connectionFields.put(_field);
876         }
877         
878         return false;
879     }
880     
881     
882     /* ------------------------------------------------------------------------------- */
883     /*
884      * Parse the message headers and return true if the handler has signaled for a return
885      */
886     protected boolean parseHeaders(ByteBuffer buffer)
887     {
888         boolean handle=false;
889 
890         // Process headers
891         while (_state.ordinal()<State.CONTENT.ordinal() && buffer.hasRemaining() && !handle)
892         {
893             // process each character
894             byte ch=next(buffer);
895             if (ch==0)
896                 break;
897             
898             if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes)
899             {
900                 LOG.warn("Header is too large >"+_maxHeaderBytes);
901                 throw new BadMessage(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413);
902             }
903 
904             switch (_state)
905             {
906                 case HEADER:
907                     switch(ch)
908                     {
909                         case HttpTokens.COLON:
910                         case HttpTokens.SPACE:
911                         case HttpTokens.TAB:
912                         {
913                             // header value without name - continuation?
914                             if (_valueString==null)
915                             {
916                                 _string.setLength(0);
917                                 _length=0;
918                             }
919                             else
920                             {
921                                 setString(_valueString);
922                                 _string.append(' ');
923                                 _length++;
924                                 _valueString=null;
925                             }
926                             setState(State.HEADER_VALUE);
927                             break;
928                         }
929 
930                         default:
931                         {
932                             // handler last header if any.  Delayed to here just in case there was a continuation line (above)
933                             if (_headerString!=null || _valueString!=null)
934                             {
935                                 // Handle known headers
936                                 if (_header!=null && handleKnownHeaders(buffer))
937                                 {
938                                     _headerString=_valueString=null;
939                                     _header=null;
940                                     _value=null;
941                                     _field=null;
942                                     return true;
943                                 }
944                                 handle=_handler.parsedHeader(_field!=null?_field:new HttpField(_header,_headerString,_valueString))||handle;
945                             }
946                             _headerString=_valueString=null;
947                             _header=null;
948                             _value=null;
949                             _field=null;
950 
951                             // now handle the ch
952                             if (ch == HttpTokens.LINE_FEED)
953                             {
954                                 _contentPosition=0;
955 
956                                 // End of headers!
957 
958                                 // Was there a required host header?
959                                 if (!_host && _version!=HttpVersion.HTTP_1_0 && _requestHandler!=null)
960                                 {
961                                     throw new BadMessage(HttpStatus.BAD_REQUEST_400,"No Host");
962                                 }
963 
964                                 // is it a response that cannot have a body?
965                                 if (_responseHandler !=null  && // response  
966                                     (_responseStatus == 304  || // not-modified response
967                                     _responseStatus == 204 || // no-content response
968                                     _responseStatus < 200)) // 1xx response
969                                     _endOfContent=EndOfContent.NO_CONTENT; // ignore any other headers set
970                                 
971                                 // else if we don't know framing
972                                 else if (_endOfContent == EndOfContent.UNKNOWN_CONTENT)
973                                 {
974                                     if (_responseStatus == 0  // request
975                                             || _responseStatus == 304 // not-modified response
976                                             || _responseStatus == 204 // no-content response
977                                             || _responseStatus < 200) // 1xx response
978                                         _endOfContent=EndOfContent.NO_CONTENT;
979                                     else
980                                         _endOfContent=EndOfContent.EOF_CONTENT;
981                                 }
982 
983                                 // How is the message ended?
984                                 switch (_endOfContent)
985                                 {
986                                     case EOF_CONTENT:
987                                         setState(State.EOF_CONTENT);
988                                         handle=_handler.headerComplete()||handle;
989                                         break;
990 
991                                     case CHUNKED_CONTENT:
992                                         setState(State.CHUNKED_CONTENT);
993                                         handle=_handler.headerComplete()||handle;
994                                         break;
995 
996                                     case NO_CONTENT:
997                                         handle=_handler.headerComplete()||handle;
998                                         setState(State.END);
999                                         handle=_handler.messageComplete()||handle;
1000                                         break;
1001 
1002                                     default:
1003                                         setState(State.CONTENT);
1004                                         handle=_handler.headerComplete()||handle;
1005                                         break;
1006                                 }
1007                             }
1008                             else if (ch<=HttpTokens.SPACE)
1009                                 throw new BadMessage();
1010                             else
1011                             {
1012                                 if (buffer.hasRemaining())
1013                                 {
1014                                     // Try a look ahead for the known header name and value.
1015                                     HttpField field=_connectionFields==null?null:_connectionFields.getBest(buffer,-1,buffer.remaining());
1016                                     if (field==null)
1017                                         field=CACHE.getBest(buffer,-1,buffer.remaining());
1018                                         
1019                                     if (field!=null)
1020                                     {
1021                                         final String n;
1022                                         final String v;
1023 
1024                                         if (_strict)
1025                                         {
1026                                             // Have to get the fields exactly from the buffer to match case
1027                                             String fn=field.getName();
1028                                             String fv=field.getValue();
1029                                             n=BufferUtil.toString(buffer,buffer.position()-1,fn.length(),StandardCharsets.US_ASCII);
1030                                             if (fv==null)
1031                                                 v=null;
1032                                             else
1033                                             {
1034                                                 v=BufferUtil.toString(buffer,buffer.position()+fn.length()+1,fv.length(),StandardCharsets.ISO_8859_1);
1035                                                 field=new HttpField(field.getHeader(),n,v);
1036                                             }
1037                                         }
1038                                         else
1039                                         {
1040                                             n=field.getName();
1041                                             v=field.getValue(); 
1042                                         }
1043                                         
1044                                         _header=field.getHeader();
1045                                         _headerString=n;
1046          
1047                                         if (v==null)
1048                                         {
1049                                             // Header only
1050                                             setState(State.HEADER_VALUE);
1051                                             _string.setLength(0);
1052                                             _length=0;
1053                                             buffer.position(buffer.position()+n.length()+1);
1054                                             break;
1055                                         }
1056                                         else
1057                                         {
1058                                             // Header and value
1059                                             int pos=buffer.position()+n.length()+v.length()+1;
1060                                             byte b=buffer.get(pos);
1061 
1062                                             if (b==HttpTokens.CARRIAGE_RETURN || b==HttpTokens.LINE_FEED)
1063                                             {                     
1064                                                 _field=field;
1065                                                 _valueString=v;
1066                                                 setState(State.HEADER_IN_VALUE);
1067 
1068                                                 if (b==HttpTokens.CARRIAGE_RETURN)
1069                                                 {
1070                                                     _cr=true;
1071                                                     buffer.position(pos+1);
1072                                                 }
1073                                                 else
1074                                                     buffer.position(pos);
1075                                                 break;
1076                                             }
1077                                             else
1078                                             {
1079                                                 setState(State.HEADER_IN_VALUE);
1080                                                 setString(v);
1081                                                 buffer.position(pos);
1082                                                 break;
1083                                             }
1084                                         }
1085                                     }
1086                                 }
1087 
1088                                 // New header
1089                                 setState(State.HEADER_IN_NAME);
1090                                 _string.setLength(0);
1091                                 _string.append((char)ch);
1092                                 _length=1;
1093                             }
1094                         }
1095                     }
1096                     break;
1097 
1098                 case HEADER_IN_NAME:
1099                     if (ch==HttpTokens.COLON || ch==HttpTokens.LINE_FEED)
1100                     {
1101                         if (_headerString==null)
1102                         {
1103                             _headerString=takeString();
1104                             _header=HttpHeader.CACHE.get(_headerString);
1105                         }
1106                         _length=-1;
1107 
1108                         setState(ch==HttpTokens.LINE_FEED?State.HEADER:State.HEADER_VALUE);
1109                         break;
1110                     }
1111                     
1112                     if (ch>=HttpTokens.SPACE || ch==HttpTokens.TAB)
1113                     {
1114                         if (_header!=null)
1115                         {
1116                             setString(_header.asString());
1117                             _header=null;
1118                             _headerString=null;
1119                         }
1120 
1121                         _string.append((char)ch);
1122                         if (ch>HttpTokens.SPACE)
1123                             _length=_string.length();
1124                         break;
1125                     }
1126                      
1127                     throw new BadMessage("Illegal character");
1128 
1129                 case HEADER_VALUE:
1130                     if (ch>HttpTokens.SPACE || ch<0)
1131                     {
1132                         _string.append((char)(0xff&ch));
1133                         _length=_string.length();
1134                         setState(State.HEADER_IN_VALUE);
1135                         break;
1136                     }
1137                     
1138                     if (ch==HttpTokens.SPACE || ch==HttpTokens.TAB)
1139                         break;
1140                     
1141                     if (ch==HttpTokens.LINE_FEED)
1142                     {
1143                         if (_length > 0)
1144                         {
1145                             _value=null;
1146                             _valueString=(_valueString==null)?takeString():(_valueString+" "+takeString());
1147                         }
1148                         setState(State.HEADER);
1149                         break; 
1150                     }
1151 
1152                     throw new BadMessage("Illegal character");
1153 
1154                 case HEADER_IN_VALUE:
1155                     if (ch>=HttpTokens.SPACE || ch<0)
1156                     {
1157                         if (_valueString!=null)
1158                         {
1159                             setString(_valueString);
1160                             _valueString=null;
1161                             _field=null;
1162                         }
1163                         _string.append((char)(0xff&ch));
1164                         if (ch>HttpTokens.SPACE || ch<0)
1165                             _length=_string.length();
1166                         break;
1167                     }
1168                     
1169                     if (ch==HttpTokens.LINE_FEED)
1170                     {
1171                         if (_length > 0)
1172                         {
1173                             _value=null;
1174                             _valueString=takeString();
1175                             _length=-1;
1176                         }
1177                         setState(State.HEADER);
1178                         break;
1179                     }
1180                     throw new BadMessage("Illegal character");
1181                     
1182                 default:
1183                     throw new IllegalStateException(_state.toString());
1184 
1185             }
1186         }
1187 
1188         return handle;
1189     }
1190 
1191     /* ------------------------------------------------------------------------------- */
1192     /**
1193      * Parse until next Event.
1194      * @return True if an {@link RequestHandler} method was called and it returned true;
1195      */
1196     public boolean parseNext(ByteBuffer buffer)
1197     {
1198         if (DEBUG)
1199             LOG.debug("parseNext s={} {}",_state,BufferUtil.toDetailString(buffer));
1200         try
1201         {
1202             boolean handle=false;
1203             
1204             // Start a request/response
1205             if (_state==State.START)
1206             {
1207                 _version=null;
1208                 _method=null;
1209                 _methodString=null;
1210                 _endOfContent=EndOfContent.UNKNOWN_CONTENT;
1211                 _header=null;
1212                 handle=quickStart(buffer);
1213             }
1214             
1215             // Request/response line
1216             if (!handle && _state.ordinal()>= State.START.ordinal() && _state.ordinal()<State.HEADER.ordinal())
1217                 handle=parseLine(buffer);
1218 
1219             // parse headers
1220             if (!handle && _state.ordinal()>= State.HEADER.ordinal() && _state.ordinal()<State.CONTENT.ordinal())
1221                 handle=parseHeaders(buffer);
1222             
1223             // parse content
1224             if (!handle && _state.ordinal()>= State.CONTENT.ordinal() && _state.ordinal()<State.END.ordinal())
1225             {
1226                 // Handle HEAD response
1227                 if (_responseStatus>0 && _headResponse)
1228                 {
1229                     setState(State.END);
1230                     handle=_handler.messageComplete();
1231                 }
1232                 else
1233                     handle=parseContent(buffer);
1234             }
1235             
1236             // handle end states
1237             if (_state==State.END)
1238             {
1239                 // eat white space
1240                 while (buffer.remaining()>0 && buffer.get(buffer.position())<=HttpTokens.SPACE)
1241                     buffer.get();
1242             }
1243             else if (_state==State.CLOSED)
1244             {
1245                 if (BufferUtil.hasContent(buffer))
1246                 {
1247                     // Just ignore data when closed
1248                     _headerBytes+=buffer.remaining();
1249                     BufferUtil.clear(buffer);
1250                     if (_headerBytes>_maxHeaderBytes)
1251                     {
1252                         // Don't want to waste time reading data of a closed request
1253                         throw new IllegalStateException("too much data after closed");
1254                     }
1255                 }
1256             }
1257             
1258             // Handle EOF
1259             if (_eof && !buffer.hasRemaining())
1260             {
1261                 switch(_state)
1262                 {
1263                     case CLOSED:
1264                         break;
1265                         
1266                     case START:
1267                         _handler.earlyEOF();
1268                         setState(State.CLOSED);
1269                         break;
1270                         
1271                     case END:
1272                         setState(State.CLOSED);
1273                         break;
1274                         
1275                     case EOF_CONTENT:
1276                         handle=_handler.messageComplete()||handle;
1277                         setState(State.CLOSED);
1278                         break;
1279 
1280                     case  CONTENT:
1281                     case  CHUNKED_CONTENT:
1282                     case  CHUNK_SIZE:
1283                     case  CHUNK_PARAMS:
1284                     case  CHUNK:
1285                         _handler.earlyEOF();
1286                         setState(State.CLOSED);
1287                         break;
1288 
1289                     default:
1290                         if (DEBUG)
1291                             LOG.debug("{} EOF in {}",this,_state);
1292                         _handler.badMessage(400,null);
1293                         setState(State.CLOSED);
1294                         break;
1295                 }
1296             }
1297             
1298             return handle;
1299         }
1300         catch(BadMessage e)
1301         {
1302             BufferUtil.clear(buffer);
1303 
1304             LOG.warn("badMessage: "+e._code+(e._message!=null?" "+e._message:"")+" for "+_handler);
1305             if (DEBUG)
1306                 LOG.debug(e);
1307             setState(State.CLOSED);
1308             _handler.badMessage(e._code, e._message);
1309             return false;
1310         }
1311         catch(Exception e)
1312         {
1313             BufferUtil.clear(buffer);
1314 
1315             LOG.warn("badMessage: "+e.toString()+" for "+_handler);
1316             if (DEBUG)
1317                 LOG.debug(e);
1318             
1319             if (_state.ordinal()<=State.END.ordinal())
1320             {
1321                 setState(State.CLOSED);
1322                 _handler.badMessage(400,null);
1323             }
1324             else
1325             {
1326                 _handler.earlyEOF();
1327                 setState(State.CLOSED);
1328             }
1329 
1330             return false;
1331         }
1332     }
1333 
1334     protected boolean parseContent(ByteBuffer buffer)
1335     {
1336         // Handle _content
1337         byte ch;
1338         while (_state.ordinal() < State.END.ordinal() && buffer.hasRemaining())
1339         {
1340             switch (_state)
1341             {
1342                 case EOF_CONTENT:
1343                     _contentChunk=buffer.asReadOnlyBuffer();
1344                     _contentPosition += _contentChunk.remaining();
1345                     buffer.position(buffer.position()+_contentChunk.remaining());
1346                     if (_handler.content(_contentChunk))
1347                         return true;
1348                     break;
1349 
1350                 case CONTENT:
1351                 {
1352                     long remaining=_contentLength - _contentPosition;
1353                     if (remaining == 0)
1354                     {
1355                         setState(State.END);
1356                         if (_handler.messageComplete())
1357                             return true;
1358                     }
1359                     else
1360                     {
1361                         _contentChunk=buffer.asReadOnlyBuffer();
1362 
1363                         // limit content by expected size
1364                         if (_contentChunk.remaining() > remaining)
1365                         {
1366                             // We can cast remaining to an int as we know that it is smaller than
1367                             // or equal to length which is already an int.
1368                             _contentChunk.limit(_contentChunk.position()+(int)remaining);
1369                         }
1370 
1371                         _contentPosition += _contentChunk.remaining();
1372                         buffer.position(buffer.position()+_contentChunk.remaining());
1373 
1374                         boolean handle=_handler.content(_contentChunk);
1375                         if(_contentPosition == _contentLength)
1376                         {
1377                             setState(State.END);
1378                             if (_handler.messageComplete())
1379                                 return true;
1380                         }
1381                         if (handle)
1382                             return true;
1383                     }
1384                     break;
1385                 }
1386 
1387                 case CHUNKED_CONTENT:
1388                 {
1389                     ch=next(buffer);
1390                     if (ch>HttpTokens.SPACE)
1391                     {
1392                         _chunkLength=TypeUtil.convertHexDigit(ch);
1393                         _chunkPosition=0;
1394                         setState(State.CHUNK_SIZE);
1395                     }
1396 
1397                     break;
1398                 }
1399 
1400                 case CHUNK_SIZE:
1401                 {
1402                     ch=next(buffer);
1403                     if (ch==0)
1404                         break;
1405                     if (ch == HttpTokens.LINE_FEED)
1406                     {
1407                         if (_chunkLength == 0)
1408                         {
1409                             setState(State.END);
1410                             if (_handler.messageComplete())
1411                                 return true;
1412                         }
1413                         else
1414                             setState(State.CHUNK);
1415                     }
1416                     else if (ch <= HttpTokens.SPACE || ch == HttpTokens.SEMI_COLON)
1417                         setState(State.CHUNK_PARAMS);
1418                     else
1419                         _chunkLength=_chunkLength * 16 + TypeUtil.convertHexDigit(ch);
1420                     break;
1421                 }
1422 
1423                 case CHUNK_PARAMS:
1424                 {
1425                     ch=next(buffer);
1426                     if (ch == HttpTokens.LINE_FEED)
1427                     {
1428                         if (_chunkLength == 0)
1429                         {
1430                             setState(State.END);
1431                             if (_handler.messageComplete())
1432                                 return true;
1433                         }
1434                         else
1435                             setState(State.CHUNK);
1436                     }
1437                     break;
1438                 }
1439 
1440                 case CHUNK:
1441                 {
1442                     int remaining=_chunkLength - _chunkPosition;
1443                     if (remaining == 0)
1444                     {
1445                         setState(State.CHUNKED_CONTENT);
1446                     }
1447                     else
1448                     {
1449                         _contentChunk=buffer.asReadOnlyBuffer();
1450 
1451                         if (_contentChunk.remaining() > remaining)
1452                             _contentChunk.limit(_contentChunk.position()+remaining);
1453                         remaining=_contentChunk.remaining();
1454 
1455                         _contentPosition += remaining;
1456                         _chunkPosition += remaining;
1457                         buffer.position(buffer.position()+remaining);
1458                         if (_handler.content(_contentChunk))
1459                             return true;
1460                     }
1461                     break;
1462                 }
1463                 
1464                 case CLOSED:
1465                 {
1466                     BufferUtil.clear(buffer);
1467                     return false;
1468                 }
1469 
1470                 default: 
1471                     break;
1472             }
1473         }
1474         return false;
1475     }
1476 
1477     /* ------------------------------------------------------------------------------- */
1478     public boolean isAtEOF()
1479  
1480     {
1481         return _eof;
1482     }
1483     
1484     /* ------------------------------------------------------------------------------- */
1485     public void atEOF()
1486 
1487     {        
1488         if (DEBUG)
1489             LOG.debug("atEOF {}", this);
1490         _eof=true;
1491     }
1492 
1493     /* ------------------------------------------------------------------------------- */
1494     public void close()
1495     {
1496         if (DEBUG)
1497             LOG.debug("close {}", this);
1498         setState(State.CLOSED);
1499     }
1500     
1501     /* ------------------------------------------------------------------------------- */
1502     public void reset()
1503     {
1504         if (DEBUG)
1505             LOG.debug("reset {}", this);
1506         // reset state
1507         if (_state==State.CLOSED)
1508             return;
1509         if (_closed)
1510         {
1511             setState(State.CLOSED);
1512             return;
1513         }
1514         
1515         setState(State.START);
1516         _endOfContent=EndOfContent.UNKNOWN_CONTENT;
1517         _contentLength=-1;
1518         _contentPosition=0;
1519         _responseStatus=0;
1520         _contentChunk=null;
1521         _headerBytes=0;
1522         _host=false;
1523     }
1524 
1525     /* ------------------------------------------------------------------------------- */
1526     protected void setState(State state)
1527     {
1528         if (DEBUG)
1529             LOG.debug("{} --> {}",_state,state);
1530         _state=state;
1531     }
1532 
1533     /* ------------------------------------------------------------------------------- */
1534     @Override
1535     public String toString()
1536     {
1537         return String.format("%s{s=%s,%d of %d}",
1538                 getClass().getSimpleName(),
1539                 _state,
1540                 _contentPosition,
1541                 _contentLength);
1542     }
1543 
1544     /* ------------------------------------------------------------ */
1545     /* ------------------------------------------------------------ */
1546     /* ------------------------------------------------------------ */
1547     /* Event Handler interface
1548      * These methods return true if the caller should process the events
1549      * so far received (eg return from parseNext and call HttpChannel.handle).
1550      * If multiple callbacks are called in sequence (eg 
1551      * headerComplete then messageComplete) from the same point in the parsing
1552      * then it is sufficient for the caller to process the events only once.
1553      */
1554     public interface HttpHandler<T>
1555     {
1556         public boolean content(T item);
1557 
1558         public boolean headerComplete();
1559 
1560         public boolean messageComplete();
1561 
1562         /**
1563          * This is the method called by parser when a HTTP Header name and value is found
1564          * @param field The field parsed
1565          * @return True if the parser should return to its caller
1566          */
1567         public boolean parsedHeader(HttpField field);
1568 
1569         /* ------------------------------------------------------------ */
1570         /** Called to signal that an EOF was received unexpectedly
1571          * during the parsing of a HTTP message
1572          */
1573         public void earlyEOF();
1574 
1575         /* ------------------------------------------------------------ */
1576         /** Called to signal that a bad HTTP message has been received.
1577          * @param status The bad status to send
1578          * @param reason The textual reason for badness
1579          */
1580         public void badMessage(int status, String reason);
1581         
1582         /* ------------------------------------------------------------ */
1583         /** @return the size in bytes of the per parser header cache
1584          */
1585         public int getHeaderCacheSize();
1586     }
1587 
1588     public interface RequestHandler<T> extends HttpHandler<T>
1589     {
1590         /**
1591          * This is the method called by parser when the HTTP request line is parsed
1592          * @param method The method as enum if of a known type
1593          * @param methodString The method as a string
1594          * @param uri The raw bytes of the URI.  These are copied into a ByteBuffer that will not be changed until this parser is reset and reused.
1595          * @param version
1596          * @return true if handling parsing should return.
1597          */
1598         public abstract boolean startRequest(HttpMethod method, String methodString, ByteBuffer uri, HttpVersion version);
1599 
1600         /**
1601          * This is the method called by the parser after it has parsed the host header (and checked it's format). This is
1602          * called after the {@link HttpHandler#parsedHeader(HttpField)} methods and before
1603          * HttpHandler#headerComplete();
1604          */
1605         public abstract boolean parsedHostHeader(String host,int port);
1606     }
1607 
1608     public interface ResponseHandler<T> extends HttpHandler<T>
1609     {
1610         /**
1611          * This is the method called by parser when the HTTP request line is parsed
1612          */
1613         public abstract boolean startResponse(HttpVersion version, int status, String reason);
1614     }
1615 
1616     public Trie<HttpField> getFieldCache()
1617     {
1618         return _connectionFields;
1619     }
1620 }