View Javadoc

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