View Javadoc

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