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