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