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