View Javadoc

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