View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 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.io.IOException;
22  import java.nio.ByteBuffer;
23  
24  import org.eclipse.jetty.http.HttpTokens.EndOfContent;
25  import org.eclipse.jetty.util.ArrayTernaryTrie;
26  import org.eclipse.jetty.util.ArrayTrie;
27  import org.eclipse.jetty.util.BufferUtil;
28  import org.eclipse.jetty.util.StringUtil;
29  import org.eclipse.jetty.util.TreeTrie;
30  import org.eclipse.jetty.util.Trie;
31  import org.eclipse.jetty.util.log.Log;
32  import org.eclipse.jetty.util.log.Logger;
33  
34  public class HttpParser
35  {
36      public static final Logger LOG = Log.getLogger(HttpParser.class);
37  
38      // States
39      public enum State
40      {
41          START,
42          METHOD,
43          RESPONSE_VERSION,
44          SPACE1,
45          STATUS,
46          URI,
47          SPACE2,
48          REQUEST_VERSION,
49          REASON,
50          HEADER,
51          HEADER_NAME,
52          HEADER_IN_NAME,
53          HEADER_VALUE,
54          HEADER_IN_VALUE,
55          END,
56          EOF_CONTENT,
57          CONTENT,
58          CHUNKED_CONTENT,
59          CHUNK_SIZE,
60          CHUNK_PARAMS,
61          CHUNK,
62          CLOSED
63      };
64  
65      private final HttpHandler<ByteBuffer> _handler;
66      private final RequestHandler<ByteBuffer> _requestHandler;
67      private final ResponseHandler<ByteBuffer> _responseHandler;
68      private final int _maxHeaderBytes;
69      private HttpField _field;
70      private HttpHeader _header;
71      private String _headerString;
72      private HttpHeaderValue _value;
73      private String _valueString;
74      private int _responseStatus;
75      private int _headerBytes;
76      private boolean _host;
77  
78      /* ------------------------------------------------------------------------------- */
79      private volatile State _state=State.START;
80      private HttpMethod _method;
81      private String _methodString;
82      private HttpVersion _version;
83      private ByteBuffer _uri=ByteBuffer.allocate(256); // Tune?
84      private byte _eol;
85      private EndOfContent _endOfContent;
86      private long _contentLength;
87      private long _contentPosition;
88      private int _chunkLength;
89      private int _chunkPosition;
90      private boolean _headResponse;
91      private ByteBuffer _contentChunk;
92      private final Trie<HttpField> _connectionFields=new ArrayTernaryTrie<>(256);
93  
94      private int _length;
95      private final StringBuilder _string=new StringBuilder();
96  
97      /* ------------------------------------------------------------------------------- */
98      public HttpParser(RequestHandler<ByteBuffer> handler)
99      {
100         this(handler,-1);
101     }
102 
103     /* ------------------------------------------------------------------------------- */
104     public HttpParser(ResponseHandler<ByteBuffer> handler)
105     {
106         this(handler,-1);
107     }
108 
109     /* ------------------------------------------------------------------------------- */
110     public HttpParser(RequestHandler<ByteBuffer> handler,int maxHeaderBytes)
111     {
112         _handler=handler;
113         _requestHandler=handler;
114         _responseHandler=null;
115         _maxHeaderBytes=maxHeaderBytes;
116     }
117 
118     /* ------------------------------------------------------------------------------- */
119     public HttpParser(ResponseHandler<ByteBuffer> handler,int maxHeaderBytes)
120     {
121         _handler=handler;
122         _requestHandler=null;
123         _responseHandler=handler;
124         _maxHeaderBytes=maxHeaderBytes;
125     }
126 
127     /* ------------------------------------------------------------------------------- */
128     public long getContentLength()
129     {
130         return _contentLength;
131     }
132 
133     /* ------------------------------------------------------------ */
134     public long getContentRead()
135     {
136         return _contentPosition;
137     }
138 
139     /* ------------------------------------------------------------ */
140     /** Set if a HEAD response is expected
141      * @param head
142      */
143     public void setHeadResponse(boolean head)
144     {
145         _headResponse=head;
146     }
147 
148     /* ------------------------------------------------------------------------------- */
149     public State getState()
150     {
151         return _state;
152     }
153 
154     /* ------------------------------------------------------------------------------- */
155     public boolean inContentState()
156     {
157         return _state.ordinal() > State.END.ordinal();
158     }
159 
160     /* ------------------------------------------------------------------------------- */
161     public boolean inHeaderState()
162     {
163         return _state.ordinal() < State.END.ordinal();
164     }
165 
166     /* ------------------------------------------------------------------------------- */
167     public boolean isInContent()
168     {
169         return _state.ordinal()>State.END.ordinal() && _state.ordinal()<State.CLOSED.ordinal();
170     }
171 
172     /* ------------------------------------------------------------------------------- */
173     public boolean isChunking()
174     {
175         return _endOfContent==EndOfContent.CHUNKED_CONTENT;
176     }
177 
178     /* ------------------------------------------------------------ */
179     public boolean isStart()
180     {
181         return isState(State.START);
182     }
183 
184     /* ------------------------------------------------------------ */
185     public boolean isClosed()
186     {
187         return isState(State.CLOSED);
188     }
189 
190     /* ------------------------------------------------------------ */
191     public boolean isIdle()
192     {
193         return isState(State.START)||isState(State.END)||isState(State.CLOSED);
194     }
195 
196     /* ------------------------------------------------------------ */
197     public boolean isComplete()
198     {
199         return isState(State.END)||isState(State.CLOSED);
200     }
201 
202     /* ------------------------------------------------------------------------------- */
203     public boolean isState(State state)
204     {
205         return _state == state;
206     }
207 
208     /* ------------------------------------------------------------------------------- */
209     /* Quick lookahead for the start state looking for a request method or a HTTP version,
210      * otherwise skip white space until something else to parse.
211      */
212     private void quickStart(ByteBuffer buffer)
213     {
214         // Quick start look
215         while (_state==State.START && buffer.hasRemaining())
216         {
217             if (_requestHandler!=null)
218             {
219                 _method = HttpMethod.lookAheadGet(buffer);
220                 if (_method!=null)
221                 {
222                     _methodString = _method.asString();
223                     buffer.position(buffer.position()+_methodString.length()+1);
224                     setState(State.SPACE1);
225                     return;
226                 }
227             }
228             else if (_responseHandler!=null)
229             {
230                 _version = HttpVersion.lookAheadGet(buffer);
231                 if (_version!=null)
232                 {
233                     buffer.position(buffer.position()+_version.asString().length()+1);
234                     setState(State.SPACE1);
235                     return;
236                 }
237             }
238 
239             byte ch=buffer.get();
240 
241             if (_eol == HttpTokens.CARRIAGE_RETURN && ch == HttpTokens.LINE_FEED)
242             {
243                 _eol=HttpTokens.LINE_FEED;
244                 continue;
245             }
246             _eol=0;
247 
248             if (ch > HttpTokens.SPACE || ch<0)
249             {
250                 _string.setLength(0);
251                 _string.append((char)ch);
252                 setState(_requestHandler!=null?State.METHOD:State.RESPONSE_VERSION);
253                 return;
254             }
255         }
256     }
257 
258     private String takeString()
259     {
260         String s =_string.toString();
261         _string.setLength(0);
262         return s;
263     }
264 
265     private String takeLengthString()
266     {
267         _string.setLength(_length);
268         String s =_string.toString();
269         _string.setLength(0);
270         _length=-1;
271         return s;
272     }
273 
274     /* ------------------------------------------------------------------------------- */
275     /* Parse a request or response line
276      */
277     private boolean parseLine(ByteBuffer buffer)
278     {
279         boolean return_from_parse=false;
280 
281         // Process headers
282         while (_state.ordinal()<State.HEADER.ordinal() && buffer.hasRemaining() && !return_from_parse)
283         {
284             // process each character
285             byte ch=buffer.get();
286 
287             if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes)
288             {
289                 if (_state==State.URI)
290                 {
291                     LOG.warn("URI is too large >"+_maxHeaderBytes);
292                     badMessage(buffer,HttpStatus.REQUEST_URI_TOO_LONG_414,null);
293                 }
294                 else
295                 {
296                     if (_requestHandler!=null)
297                         LOG.warn("request is too large >"+_maxHeaderBytes);
298                     else
299                         LOG.warn("response is too large >"+_maxHeaderBytes);
300                     badMessage(buffer,HttpStatus.REQUEST_ENTITY_TOO_LARGE_413,null);
301                 }
302                 return true;
303             }
304 
305             if (_eol == HttpTokens.CARRIAGE_RETURN && ch == HttpTokens.LINE_FEED)
306             {
307                 _eol=HttpTokens.LINE_FEED;
308                 continue;
309             }
310             _eol=0;
311 
312             switch (_state)
313             {
314                 case METHOD:
315                     if (ch == HttpTokens.SPACE)
316                     {
317                         _methodString=takeString();
318                         HttpMethod method=HttpMethod.CACHE.get(_methodString);
319                         if (method!=null)
320                             _methodString=method.asString();
321                         setState(State.SPACE1);
322                     }
323                     else if (ch < HttpTokens.SPACE && ch>=0)
324                     {
325                         badMessage(buffer,HttpStatus.BAD_REQUEST_400,"No URI");
326                         return true;
327                     }
328                     else
329                         _string.append((char)ch);
330                     break;
331 
332                 case RESPONSE_VERSION:
333                     if (ch == HttpTokens.SPACE)
334                     {
335                         String version=takeString();
336                         _version=HttpVersion.CACHE.get(version);
337                         if (_version==null)
338                         {
339                             badMessage(buffer,HttpStatus.BAD_REQUEST_400,"Unknown Version");
340                             return true;
341                         }
342                         setState(State.SPACE1);
343                     }
344                     else if (ch < HttpTokens.SPACE && ch>=0)
345                     {
346                         badMessage(buffer,HttpStatus.BAD_REQUEST_400,"No Status");
347                         return true;
348                     }
349                     else
350                         _string.append((char)ch);
351                     break;
352 
353                 case SPACE1:
354                     if (ch > HttpTokens.SPACE || ch<0)
355                     {
356                         if (_responseHandler!=null)
357                         {
358                             setState(State.STATUS);
359                             _responseStatus=ch-'0';
360                         }
361                         else
362                         {
363                             _uri.clear();
364                             setState(State.URI);
365                             // quick scan for space or EoBuffer
366                             if (buffer.hasArray())
367                             {
368                                 byte[] array=buffer.array();
369                                 int p=buffer.arrayOffset()+buffer.position();
370                                 int l=buffer.arrayOffset()+buffer.limit();
371                                 int i=p;
372                                 while (i<l && array[i]>HttpTokens.SPACE)
373                                     i++;
374 
375                                 int len=i-p;
376                                 _headerBytes+=len;
377                                 
378                                 if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes)
379                                 {
380                                     LOG.warn("URI is too large >"+_maxHeaderBytes);
381                                     badMessage(buffer,HttpStatus.REQUEST_URI_TOO_LONG_414,null);
382                                     return true;
383                                 }
384                                 if (_uri.remaining()<len)
385                                 {
386                                     ByteBuffer uri = ByteBuffer.allocate(_uri.capacity()+2*len);
387                                     _uri.flip();
388                                     uri.put(_uri);
389                                     _uri=uri;
390                                 }
391                                 _uri.put(array,p-1,len+1);
392                                 buffer.position(i-buffer.arrayOffset());
393                             }
394                             else
395                                 _uri.put(ch);
396                         }
397                     }
398                     else if (ch < HttpTokens.SPACE)
399                     {
400                         badMessage(buffer,HttpStatus.BAD_REQUEST_400,_requestHandler!=null?"No URI":"No Status");
401                         return true;
402                     }
403                     break;
404 
405                 case STATUS:
406                     if (ch == HttpTokens.SPACE)
407                     {
408                         setState(State.SPACE2);
409                     }
410                     else if (ch>='0' && ch<='9')
411                     {
412                         _responseStatus=_responseStatus*10+(ch-'0');
413                     }
414                     else if (ch < HttpTokens.SPACE && ch>=0)
415                     {
416                         return_from_parse|=_responseHandler.startResponse(_version, _responseStatus, null);
417                         _eol=ch;
418                         setState(State.HEADER);
419                     }
420                     else
421                     {
422                         throw new IllegalStateException();
423                     }
424                     break;
425 
426                 case URI:
427                     if (ch == HttpTokens.SPACE)
428                     {
429                         setState(State.SPACE2);
430                     }
431                     else if (ch < HttpTokens.SPACE && ch>=0)
432                     {
433                         // HTTP/0.9
434                         _uri.flip();
435                         return_from_parse|=_requestHandler.startRequest(_method,_methodString,_uri,null);
436                         setState(State.END);
437                         BufferUtil.clear(buffer);
438                         return_from_parse|=_handler.headerComplete();
439                         return_from_parse|=_handler.messageComplete();
440                     }
441                     else
442                     {
443                         if (!_uri.hasRemaining())
444                         {
445                             ByteBuffer uri = ByteBuffer.allocate(_uri.capacity()*2);
446                             _uri.flip();
447                             uri.put(_uri);
448                             _uri=uri;
449                         }
450                         _uri.put(ch);
451                     }
452                     break;
453 
454                 case SPACE2:
455                     if (ch > HttpTokens.SPACE || ch<0)
456                     {
457                         _string.setLength(0);
458                         _string.append((char)ch);
459                         if (_responseHandler!=null)
460                         {
461                             _length=1;
462                             setState(State.REASON);
463                         }
464                         else
465                         {
466                             setState(State.REQUEST_VERSION);
467 
468                             // try quick look ahead
469                             if (buffer.position()>0 && buffer.hasArray())
470                             {
471                                 _version=HttpVersion.lookAheadGet(buffer.array(),buffer.arrayOffset()+buffer.position()-1,buffer.arrayOffset()+buffer.limit());
472                                 if (_version!=null)
473                                 {
474                                     _string.setLength(0);
475                                     buffer.position(buffer.position()+_version.asString().length()-1);
476                                     _eol=buffer.get();
477                                     setState(State.HEADER);
478                                     _uri.flip();
479                                     return_from_parse|=_requestHandler.startRequest(_method,_methodString,_uri, _version);
480                                 }
481                             }
482                         }
483                     }
484                     else if (ch < HttpTokens.SPACE)
485                     {
486                         if (_responseHandler!=null)
487                         {
488                             return_from_parse|=_responseHandler.startResponse(_version, _responseStatus, null);
489                             _eol=ch;
490                             setState(State.HEADER);
491                         }
492                         else
493                         {
494                             // HTTP/0.9
495                             _uri.flip();
496                             return_from_parse|=_requestHandler.startRequest(_method,_methodString,_uri, null);
497                             setState(State.END);
498                             BufferUtil.clear(buffer);
499                             return_from_parse|=_handler.headerComplete();
500                             return_from_parse|=_handler.messageComplete();
501                         }
502                     }
503                     break;
504 
505                 case REQUEST_VERSION:
506                     if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
507                     {
508                         String version = takeString();
509                         _version=HttpVersion.CACHE.get(version);
510                         if (_version==null)
511                         {
512                             badMessage(buffer,HttpStatus.BAD_REQUEST_400,"Unknown Version");
513                             return true;
514                         }
515 
516                         _eol=ch;
517                         setState(State.HEADER);
518                         _uri.flip();
519                         return_from_parse|=_requestHandler.startRequest(_method,_methodString,_uri, _version);
520                         continue;
521                     }
522                     else
523                         _string.append((char)ch);
524 
525                     break;
526 
527                 case REASON:
528                     if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
529                     {
530                         String reason=takeLengthString();
531 
532                         _eol=ch;
533                         setState(State.HEADER);
534                         return_from_parse|=_responseHandler.startResponse(_version, _responseStatus, reason);
535                         continue;
536                     }
537                     else
538                     {
539                         _string.append((char)ch);
540                         if (ch!=' '&&ch!='\t')
541                             _length=_string.length();
542                     }
543                     break;
544 
545                 default:
546                     throw new IllegalStateException(_state.toString());
547 
548             }
549         }
550 
551         return return_from_parse;
552     }
553 
554     private boolean handleKnownHeaders(ByteBuffer buffer)
555     {
556         boolean add_to_connection_trie=false;
557         switch (_header)
558         {
559             case CONTENT_LENGTH:
560                 if (_endOfContent != EndOfContent.CHUNKED_CONTENT)
561                 {
562                     try
563                     {
564                         _contentLength=Long.parseLong(_valueString);
565                     }
566                     catch(NumberFormatException e)
567                     {
568                         LOG.ignore(e);
569                         badMessage(buffer,HttpStatus.BAD_REQUEST_400,"Bad Content-Length");
570                         return true;
571                     }
572                     if (_contentLength <= 0)
573                         _endOfContent=EndOfContent.NO_CONTENT;
574                     else
575                         _endOfContent=EndOfContent.CONTENT_LENGTH;
576                 }
577                 break;
578 
579             case TRANSFER_ENCODING:
580                 if (_value==HttpHeaderValue.CHUNKED)
581                     _endOfContent=EndOfContent.CHUNKED_CONTENT;
582                 else
583                 {
584                     if (_valueString.endsWith(HttpHeaderValue.CHUNKED.toString()))
585                         _endOfContent=EndOfContent.CHUNKED_CONTENT;
586                     else if (_valueString.indexOf(HttpHeaderValue.CHUNKED.toString()) >= 0)
587                     {
588                         badMessage(buffer,HttpStatus.BAD_REQUEST_400,"Bad chunking");
589                         return true;
590                     }
591                 }
592                 break;
593 
594             case HOST:
595                 add_to_connection_trie=_field==null;
596                 _host=true;
597                 String host=_valueString;
598                 int port=0;
599                 if (host==null || host.length()==0)
600                 {
601                     badMessage(buffer,HttpStatus.BAD_REQUEST_400,"Bad Host header");
602                     return true;
603                 }
604 
605                 loop: for (int i = host.length(); i-- > 0;)
606                 {
607                     char c2 = (char)(0xff & host.charAt(i));
608                     switch (c2)
609                     {
610                         case ']':
611                             break loop;
612 
613                         case ':':
614                             try
615                             {
616                                 port = StringUtil.toInt(host.substring(i+1));
617                             }
618                             catch (NumberFormatException e)
619                             {
620                                 LOG.debug(e);
621                                 badMessage(buffer,HttpStatus.BAD_REQUEST_400,"Bad Host header");
622                                 return true;
623                             }
624                             host = host.substring(0,i);
625                             break loop;
626                     }
627                 }
628                 if (_requestHandler!=null)
629                     _requestHandler.parsedHostHeader(host,port);
630                 
631               break;
632 
633             case AUTHORIZATION:
634             case ACCEPT:
635             case ACCEPT_CHARSET:
636             case ACCEPT_ENCODING:
637             case ACCEPT_LANGUAGE:
638             case COOKIE:
639             case CACHE_CONTROL:
640             case USER_AGENT:
641                 add_to_connection_trie=_field==null;
642         }
643     
644         if (add_to_connection_trie && !_connectionFields.isFull() && _header!=null && _valueString!=null)
645         {
646             _field=new HttpField.CachedHttpField(_header,_valueString);
647             _connectionFields.put(_field);
648         }
649         
650         return false;
651     }
652     
653     
654     /* ------------------------------------------------------------------------------- */
655     /*
656      * Parse the message headers and return true if the handler has signaled for a return
657      */
658     private boolean parseHeaders(ByteBuffer buffer)
659     {
660         boolean return_from_parse=false;
661 
662         // Process headers
663         while (_state.ordinal()<State.END.ordinal() && buffer.hasRemaining() && !return_from_parse)
664         {
665             // process each character
666             byte ch=buffer.get();
667             if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes)
668             {
669                 LOG.warn("Header is too large >"+_maxHeaderBytes);
670                 badMessage(buffer,HttpStatus.REQUEST_ENTITY_TOO_LARGE_413,null);
671                 return true;
672             }
673 
674             if (_eol == HttpTokens.CARRIAGE_RETURN && ch == HttpTokens.LINE_FEED)
675             {
676                 _eol=HttpTokens.LINE_FEED;
677                 continue;
678             }
679             _eol=0;
680 
681             switch (_state)
682             {
683                 case HEADER:
684                     switch(ch)
685                     {
686                         case HttpTokens.COLON:
687                         case HttpTokens.SPACE:
688                         case HttpTokens.TAB:
689                         {
690                             // header value without name - continuation?
691                             _string.setLength(0);
692                             if (_valueString!=null)
693                             {
694                                 _string.append(_valueString);
695                                 _string.append(' ');
696                             }
697                             _length=_string.length();
698                             _valueString=null;
699                             setState(State.HEADER_VALUE);
700                             break;
701                         }
702 
703                         default:
704                         {
705                             // handler last header if any.  Delayed to here just in case there was a continuation line (above)
706                             if (_headerString!=null || _valueString!=null)
707                             {
708                                 // Handle known headers
709                                 if (_header!=null && handleKnownHeaders(buffer))
710                                 {
711                                     _headerString=_valueString=null;
712                                     _header=null;
713                                     _value=null;
714                                     _field=null;
715                                     return true;
716                                 }
717                                 return_from_parse|=_handler.parsedHeader(_field!=null?_field:new HttpField(_header,_headerString,_valueString));
718                             }
719                             _headerString=_valueString=null;
720                             _header=null;
721                             _value=null;
722                             _field=null;
723 
724                             // now handle the ch
725                             if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
726                             {
727                                 consumeCRLF(ch,buffer);
728 
729                                 _contentPosition=0;
730 
731                                 // End of headers!
732 
733                                 // Was there a required host header?
734                                 if (!_host && _version!=HttpVersion.HTTP_1_0 && _requestHandler!=null)
735                                 {
736                                     badMessage(buffer,HttpStatus.BAD_REQUEST_400,"No Host");
737                                     return true;
738                                 }
739 
740                                 // is it a response that cannot have a body?
741                                 if (_responseHandler !=null  && // response  
742                                     (_responseStatus == 304  || // not-modified response
743                                     _responseStatus == 204 || // no-content response
744                                     _responseStatus < 200)) // 1xx response
745                                     _endOfContent=EndOfContent.NO_CONTENT; // ignore any other headers set
746                                 
747                                 // else if we don't know framing
748                                 else if (_endOfContent == EndOfContent.UNKNOWN_CONTENT)
749                                 {
750                                     if (_responseStatus == 0  // request
751                                             || _responseStatus == 304 // not-modified response
752                                             || _responseStatus == 204 // no-content response
753                                             || _responseStatus < 200) // 1xx response
754                                         _endOfContent=EndOfContent.NO_CONTENT;
755                                     else
756                                         _endOfContent=EndOfContent.EOF_CONTENT;
757                                 }
758 
759                                 // How is the message ended?
760                                 switch (_endOfContent)
761                                 {
762                                     case EOF_CONTENT:
763                                         setState(State.EOF_CONTENT);
764                                         return_from_parse|=_handler.headerComplete();
765                                         break;
766 
767                                     case CHUNKED_CONTENT:
768                                         setState(State.CHUNKED_CONTENT);
769                                         return_from_parse|=_handler.headerComplete();
770                                         break;
771 
772                                     case NO_CONTENT:
773                                         return_from_parse|=_handler.headerComplete();
774                                         setState(State.END);
775                                         return_from_parse|=_handler.messageComplete();
776                                         break;
777 
778                                     default:
779                                         setState(State.CONTENT);
780                                         return_from_parse|=_handler.headerComplete();
781                                         break;
782                                 }
783                             }
784                             else
785                             {
786                                 if (buffer.remaining()>6)
787                                 {
788                                     // Try a look ahead for the known header name and value.
789                                     _field=_connectionFields.getBest(buffer,-1,buffer.remaining());
790                                     if (_field==null)
791                                         _field=HttpField.CACHE.getBest(buffer,-1,buffer.remaining());
792                                         
793                                     if (_field!=null)
794                                     {
795                                         _header=_field.getHeader();
796                                         _headerString=_field.getName();
797                                         _valueString=_field.getValue();
798                                         if (_valueString==null)
799                                         {
800                                             setState(State.HEADER_VALUE);
801                                             buffer.position(buffer.position()+_headerString.length()+1);
802                                             _string.setLength(0);
803                                             _length=0;
804                                             _field=null;
805                                         }
806                                         else
807                                         {
808                                             setState(State.HEADER_IN_VALUE);
809                                             buffer.position(buffer.position()+_headerString.length()+_valueString.length()+1);
810                                         }
811                                         break;
812                                     }
813 
814                                     // Try a look ahead for the known header name.
815                                     _header=HttpHeader.CACHE.getBest(buffer,-1,buffer.remaining());
816                                     //_header=HttpHeader.CACHE.getBest(buffer.array(),buffer.arrayOffset()+buffer.position()-1,buffer.remaining()+1);
817                                     if (_header!=null)
818                                     {
819                                         _headerString=_header.asString();
820                                         _string.setLength(0);
821                                         setState(State.HEADER_IN_NAME);
822                                         buffer.position(buffer.position()+_headerString.length()-1);
823                                         break;
824                                     }
825                                 }
826 
827                                 // New header
828                                 setState(State.HEADER_NAME);
829                                 _string.setLength(0);
830                                 _string.append((char)ch);
831                                 _length=1;
832                             }
833                         }
834                     }
835 
836                     break;
837 
838                 case HEADER_NAME:
839                     switch(ch)
840                     {
841                         case HttpTokens.CARRIAGE_RETURN:
842                         case HttpTokens.LINE_FEED:
843                             consumeCRLF(ch,buffer);
844                             if (_headerString==null)
845                             {
846                                 _headerString=takeLengthString();
847                                 _header=HttpHeader.CACHE.get(_headerString);
848                             }
849                             setState(State.HEADER);
850 
851                             break;
852 
853                         case HttpTokens.COLON:
854                             if (_headerString==null)
855                             {
856                                 _headerString=takeLengthString();
857                                 _header=HttpHeader.CACHE.get(_headerString); 
858                             }
859                             setState(State.HEADER_VALUE);
860                             break;
861                         case HttpTokens.SPACE:
862                         case HttpTokens.TAB:
863                             _string.append((char)ch);
864                             break;
865                         default:
866                         {
867                             _string.append((char)ch);
868                             _length=_string.length();
869                             setState(State.HEADER_IN_NAME);
870                         }
871                     }
872 
873                     break;
874 
875                 case HEADER_IN_NAME:
876                     switch(ch)
877                     {
878                         case HttpTokens.CARRIAGE_RETURN:
879                         case HttpTokens.LINE_FEED:
880                             consumeCRLF(ch,buffer);
881                             _headerString=takeString();
882                             _length=-1;
883                             _header=HttpHeader.CACHE.get(_headerString);
884                             setState(State.HEADER);
885                             break;
886 
887                         case HttpTokens.COLON:
888                             if (_headerString==null)
889                             {
890                                 _headerString=takeString();
891                                 _header=HttpHeader.CACHE.get(_headerString);
892                             }
893                             _length=-1;
894                             setState(State.HEADER_VALUE);
895                             break;
896                         case HttpTokens.SPACE:
897                         case HttpTokens.TAB:
898                             if (_header!=null)
899                             {
900                                 _string.setLength(0);
901                                 _string.append(_header.asString());
902                                 _length=_string.length();
903                                 _header=null;
904                                 _headerString=null;
905                             }
906                             setState(State.HEADER_NAME);
907                             _string.append((char)ch);
908                             break;
909                         default:
910                             if (_header!=null)
911                             {
912                                 _string.setLength(0);
913                                 _string.append(_header.asString());
914                                 _length=_string.length();
915                                 _header=null;
916                                 _headerString=null;
917                             }
918                             _string.append((char)ch);
919                             _length++;
920                     }
921                     break;
922 
923                 case HEADER_VALUE:
924                     switch(ch)
925                     {
926                         case HttpTokens.CARRIAGE_RETURN:
927                         case HttpTokens.LINE_FEED:
928                             consumeCRLF(ch,buffer);
929                             if (_length > 0)
930                             {
931                                 if (_valueString!=null)
932                                 {
933                                     // multi line value!
934                                     _value=null;
935                                     _valueString+=" "+takeLengthString();
936                                 }
937                                 else if (HttpHeaderValue.hasKnownValues(_header))
938                                 {
939                                     _valueString=takeLengthString();
940                                     _value=HttpHeaderValue.CACHE.get(_valueString);
941                                 }
942                                 else
943                                 {
944                                     _value=null;
945                                     _valueString=takeLengthString();
946                                 }
947                             }
948                             setState(State.HEADER);
949                             break;
950                         case HttpTokens.SPACE:
951                         case HttpTokens.TAB:
952                             break;
953                         default:
954                         {
955                             _string.append((char)ch);
956                             _length=_string.length();
957                             setState(State.HEADER_IN_VALUE);
958                         }
959                     }
960                     break;
961 
962                 case HEADER_IN_VALUE:
963                     switch(ch)
964                     {
965                         case HttpTokens.CARRIAGE_RETURN:
966                         case HttpTokens.LINE_FEED:
967                             consumeCRLF(ch,buffer);
968                             if (_length > 0)
969                             {
970                                 if (HttpHeaderValue.hasKnownValues(_header))
971                                 {
972                                     _valueString=takeString();
973                                     _value=HttpHeaderValue.CACHE.get(_valueString);
974                                 }
975                                 else
976                                 {
977                                     _value=null;
978                                     _valueString=takeString();
979                                 }
980                                 _length=-1;
981                             }
982                             setState(State.HEADER);
983                             break;
984                         case HttpTokens.SPACE:
985                         case HttpTokens.TAB:
986                             if (_valueString!=null)
987                             {
988                                 _string.setLength(0);
989                                 _string.append(_valueString);
990                                 _length=_valueString.length();
991                                 _valueString=null;
992                                 _field=null;
993                             }
994                             _string.append((char)ch);
995                             setState(State.HEADER_VALUE);
996                             break;
997                         default:
998                             if (_valueString!=null)
999                             {
1000                                 _string.setLength(0);
1001                                 _string.append(_valueString);
1002                                 _length=_valueString.length();
1003                                 _valueString=null;
1004                                 _field=null;
1005                             }
1006                             _string.append((char)ch);
1007                             _length++;
1008                     }
1009                     break;
1010 
1011                 default:
1012                     throw new IllegalStateException(_state.toString());
1013 
1014             }
1015         }
1016 
1017         return return_from_parse;
1018     }
1019 
1020     /* ------------------------------------------------------------------------------- */
1021     private void consumeCRLF(byte ch, ByteBuffer buffer)
1022     {
1023         _eol=ch;
1024         if (_eol==HttpTokens.CARRIAGE_RETURN && buffer.hasRemaining() && buffer.get(buffer.position())==HttpTokens.LINE_FEED)
1025         {
1026             buffer.get();
1027             _eol=0;
1028         }
1029     }
1030 
1031     /* ------------------------------------------------------------------------------- */
1032     /**
1033      * Parse until next Event.
1034      * @return True if an {@link RequestHandler} method was called and it returned true;
1035      */
1036     public boolean parseNext(ByteBuffer buffer)
1037     {
1038         try
1039         {
1040             // handle initial state
1041             switch(_state)
1042             {
1043                 case START:
1044                     _version=null;
1045                     _method=null;
1046                     _methodString=null;
1047                     _endOfContent=EndOfContent.UNKNOWN_CONTENT;
1048                     _header=null;
1049                     quickStart(buffer);
1050                     break;
1051 
1052                 case CONTENT:
1053                     if (_contentPosition==_contentLength)
1054                     {
1055                         setState(State.END);
1056                         if(_handler.messageComplete())
1057                             return true;
1058                     }
1059                     break;
1060 
1061                 case END:
1062                     return false;
1063 
1064                 case CLOSED:
1065                     if (BufferUtil.hasContent(buffer))
1066                     {
1067                         int len=buffer.remaining();
1068                         _headerBytes+=len;
1069                         if (_headerBytes>_maxHeaderBytes)
1070                         {
1071                             Thread.sleep(100);
1072                             String chars = BufferUtil.toDetailString(buffer);
1073                             BufferUtil.clear(buffer);
1074                             throw new IllegalStateException(String.format("%s %d/%d>%d data when CLOSED:%s",this,len,_headerBytes,_maxHeaderBytes,chars));
1075                         }
1076                         BufferUtil.clear(buffer);
1077                     }
1078                     return false;
1079             }
1080 
1081             // Request/response line
1082             if (_state.ordinal()<State.HEADER.ordinal())
1083                 if (parseLine(buffer))
1084                     return true;
1085 
1086             if (_state.ordinal()<State.END.ordinal())
1087                 if (parseHeaders(buffer))
1088                     return true;
1089 
1090             // Handle HEAD response
1091             if (_responseStatus>0 && _headResponse)
1092             {
1093                 setState(State.END);
1094                 if (_handler.messageComplete())
1095                     return true;
1096             }
1097 
1098 
1099             // Handle _content
1100             byte ch;
1101             while (_state.ordinal() > State.END.ordinal() && buffer.hasRemaining())
1102             {
1103                 if (_eol == HttpTokens.CARRIAGE_RETURN && buffer.get(buffer.position()) == HttpTokens.LINE_FEED)
1104                 {
1105                     _eol=buffer.get();
1106                     continue;
1107                 }
1108                 _eol=0;
1109 
1110                 switch (_state)
1111                 {
1112                     case EOF_CONTENT:
1113                         _contentChunk=buffer.asReadOnlyBuffer();
1114                         _contentPosition += _contentChunk.remaining();
1115                         buffer.position(buffer.position()+_contentChunk.remaining());
1116                         if (_handler.content(_contentChunk))
1117                             return true;
1118                         break;
1119 
1120                     case CONTENT:
1121                     {
1122                         long remaining=_contentLength - _contentPosition;
1123                         if (remaining == 0)
1124                         {
1125                             setState(State.END);
1126                             if (_handler.messageComplete())
1127                                 return true;
1128                         }
1129                         else
1130                         {
1131                             _contentChunk=buffer.asReadOnlyBuffer();
1132 
1133                             // limit content by expected size
1134                             if (_contentChunk.remaining() > remaining)
1135                             {
1136                                 // We can cast remaining to an int as we know that it is smaller than
1137                                 // or equal to length which is already an int.
1138                                 _contentChunk.limit(_contentChunk.position()+(int)remaining);
1139                             }
1140 
1141                             _contentPosition += _contentChunk.remaining();
1142                             buffer.position(buffer.position()+_contentChunk.remaining());
1143 
1144                             if (_handler.content(_contentChunk))
1145                                 return true;
1146 
1147                             if(_contentPosition == _contentLength)
1148                             {
1149                                 setState(State.END);
1150                                 if (_handler.messageComplete())
1151                                     return true;
1152                             }
1153                         }
1154                         break;
1155                     }
1156 
1157                     case CHUNKED_CONTENT:
1158                     {
1159                         ch=buffer.get(buffer.position());
1160                         if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
1161                             _eol=buffer.get();
1162                         else if (ch <= HttpTokens.SPACE)
1163                             buffer.get();
1164                         else
1165                         {
1166                             _chunkLength=0;
1167                             _chunkPosition=0;
1168                             setState(State.CHUNK_SIZE);
1169                         }
1170                         break;
1171                     }
1172 
1173                     case CHUNK_SIZE:
1174                     {
1175                         ch=buffer.get();
1176                         if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
1177                         {
1178                             _eol=ch;
1179 
1180                             if (_chunkLength == 0)
1181                             {
1182                                 if (_eol==HttpTokens.CARRIAGE_RETURN && buffer.hasRemaining() && buffer.get(buffer.position())==HttpTokens.LINE_FEED)
1183                                     _eol=buffer.get();
1184                                 setState(State.END);
1185                                 if (_handler.messageComplete())
1186                                     return true;
1187                             }
1188                             else
1189                                 setState(State.CHUNK);
1190                         }
1191                         else if (ch <= HttpTokens.SPACE || ch == HttpTokens.SEMI_COLON)
1192                             setState(State.CHUNK_PARAMS);
1193                         else if (ch >= '0' && ch <= '9')
1194                             _chunkLength=_chunkLength * 16 + (ch - '0');
1195                         else if (ch >= 'a' && ch <= 'f')
1196                             _chunkLength=_chunkLength * 16 + (10 + ch - 'a');
1197                         else if (ch >= 'A' && ch <= 'F')
1198                             _chunkLength=_chunkLength * 16 + (10 + ch - 'A');
1199                         else
1200                             throw new IOException("bad chunk char: " + ch);
1201                         break;
1202                     }
1203 
1204                     case CHUNK_PARAMS:
1205                     {
1206                         ch=buffer.get();
1207                         if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
1208                         {
1209                             _eol=ch;
1210                             if (_chunkLength == 0)
1211                             {
1212                                 if (_eol==HttpTokens.CARRIAGE_RETURN && buffer.hasRemaining() && buffer.get(buffer.position())==HttpTokens.LINE_FEED)
1213                                     _eol=buffer.get();
1214                                 setState(State.END);
1215                                 if (_handler.messageComplete())
1216                                     return true;
1217                             }
1218                             else
1219                                 setState(State.CHUNK);
1220                         }
1221                         break;
1222                     }
1223 
1224                     case CHUNK:
1225                     {
1226                         int remaining=_chunkLength - _chunkPosition;
1227                         if (remaining == 0)
1228                         {
1229                             setState(State.CHUNKED_CONTENT);
1230                         }
1231                         else
1232                         {
1233                             _contentChunk=buffer.asReadOnlyBuffer();
1234 
1235                             if (_contentChunk.remaining() > remaining)
1236                                 _contentChunk.limit(_contentChunk.position()+remaining);
1237                             remaining=_contentChunk.remaining();
1238 
1239                             _contentPosition += remaining;
1240                             _chunkPosition += remaining;
1241                             buffer.position(buffer.position()+remaining);
1242                             if (_handler.content(_contentChunk))
1243                                 return true;
1244                         }
1245                         break;
1246                     }
1247                     case CLOSED:
1248                     {
1249                         BufferUtil.clear(buffer);
1250                         return false;
1251                     }
1252                 }
1253             }
1254 
1255             return false;
1256         }
1257         catch(Exception e)
1258         {
1259             BufferUtil.clear(buffer);
1260             if (isClosed())
1261             {
1262                 LOG.debug(e);
1263                 if (e instanceof IllegalStateException)
1264                     throw (IllegalStateException)e;
1265                 throw new IllegalStateException(e);
1266             }
1267 
1268             LOG.warn("badMessage: "+e.toString()+" for "+_handler);
1269             e.printStackTrace();
1270             LOG.debug(e);
1271             badMessage(buffer,HttpStatus.BAD_REQUEST_400,null);
1272             return true;
1273         }
1274     }
1275 
1276     /* ------------------------------------------------------------------------------- */
1277     private void badMessage(ByteBuffer buffer, int status, String reason)
1278     {
1279         BufferUtil.clear(buffer);
1280         setState(State.CLOSED);
1281         _handler.badMessage(status, reason);
1282     }
1283 
1284     /**
1285      * Notifies this parser that I/O code read a -1 and therefore no more data will arrive to be parsed.
1286      * Calling this method may result in an invocation to {@link HttpHandler#messageComplete()}, for
1287      * example when the content is delimited by the close of the connection.
1288      * If the parser is already in a state that does not need data (for example, it is idle waiting for
1289      * a request/response to be parsed), then calling this method is a no-operation.
1290      *
1291      * @return the result of the invocation to {@link HttpHandler#messageComplete()} if there has been
1292      * one, or false otherwise.
1293      */
1294     public boolean shutdownInput()
1295     {
1296         LOG.debug("shutdownInput {}", this);
1297 
1298         // was this unexpected?
1299         switch(_state)
1300         {
1301             case START:
1302             case END:
1303                 break;
1304 
1305             case EOF_CONTENT:
1306                 setState(State.END);
1307                 return _handler.messageComplete();
1308 
1309             case CLOSED:
1310                 break;
1311 
1312             default:
1313                 setState(State.END);
1314                 if (!_headResponse)
1315                     _handler.earlyEOF();
1316                 return _handler.messageComplete();
1317         }
1318 
1319         return false;
1320     }
1321 
1322     /* ------------------------------------------------------------------------------- */
1323     public void close()
1324     {
1325         switch(_state)
1326         {
1327             case START:
1328             case CLOSED:
1329             case END:
1330                 break;
1331             default:
1332                 LOG.warn("Closing {}",this);
1333         }
1334         setState(State.CLOSED);
1335         _endOfContent=EndOfContent.UNKNOWN_CONTENT;
1336         _contentLength=-1;
1337         _contentPosition=0;
1338         _responseStatus=0;
1339         _headerBytes=0;
1340         _contentChunk=null;
1341     }
1342 
1343     /* ------------------------------------------------------------------------------- */
1344     public void reset()
1345     {
1346         // reset state
1347         setState(State.START);
1348         _endOfContent=EndOfContent.UNKNOWN_CONTENT;
1349         _contentLength=-1;
1350         _contentPosition=0;
1351         _responseStatus=0;
1352         _contentChunk=null;
1353         _headerBytes=0;
1354         _host=false;
1355     }
1356 
1357     /* ------------------------------------------------------------------------------- */
1358     private void setState(State state)
1359     {
1360         _state=state;
1361     }
1362 
1363     /* ------------------------------------------------------------------------------- */
1364     @Override
1365     public String toString()
1366     {
1367         return String.format("%s{s=%s,%d of %d}",
1368                 getClass().getSimpleName(),
1369                 _state,
1370                 _contentPosition,
1371                 _contentLength);
1372     }
1373 
1374     /* ------------------------------------------------------------ */
1375     /* ------------------------------------------------------------ */
1376     /* ------------------------------------------------------------ */
1377     /* Event Handler interface
1378      * These methods return true if they want parsing to return to
1379      * the caller.
1380      */
1381     public interface HttpHandler<T>
1382     {
1383         public boolean content(T item);
1384 
1385         public boolean headerComplete();
1386 
1387         public boolean messageComplete();
1388 
1389         /**
1390          * This is the method called by parser when a HTTP Header name and value is found
1391          * @param field The field parsed
1392          * @return True if the parser should return to its caller
1393          */
1394         public boolean parsedHeader(HttpField field);
1395 
1396         public boolean earlyEOF();
1397 
1398         public void badMessage(int status, String reason);
1399     }
1400 
1401     public interface RequestHandler<T> extends HttpHandler<T>
1402     {
1403         /**
1404          * This is the method called by parser when the HTTP request line is parsed
1405          * @param method The method as enum if of a known type
1406          * @param methodString The method as a string
1407          * @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.
1408          * @param version
1409          * @return true if handling parsing should return.
1410          */
1411         public abstract boolean startRequest(HttpMethod method, String methodString, ByteBuffer uri, HttpVersion version);
1412 
1413         /**
1414          * This is the method called by the parser after it has parsed the host header (and checked it's format). This is
1415          * called after the {@link HttpHandler#parsedHeader(HttpField) methods and before
1416          * HttpHandler#headerComplete();
1417          */
1418         public abstract boolean parsedHostHeader(String host,int port);
1419     }
1420 
1421     public interface ResponseHandler<T> extends HttpHandler<T>
1422     {
1423         /**
1424          * This is the method called by parser when the HTTP request line is parsed
1425          */
1426         public abstract boolean startResponse(HttpVersion version, int status, String reason);
1427     }
1428 
1429 
1430 }