1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
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);
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
141
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
210
211
212 private void quickStart(ByteBuffer buffer)
213 {
214
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
276
277 private boolean parseLine(ByteBuffer buffer)
278 {
279 boolean return_from_parse=false;
280
281
282 while (_state.ordinal()<State.HEADER.ordinal() && buffer.hasRemaining() && !return_from_parse)
283 {
284
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
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
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
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
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
657
658 private boolean parseHeaders(ByteBuffer buffer)
659 {
660 boolean return_from_parse=false;
661
662
663 while (_state.ordinal()<State.END.ordinal() && buffer.hasRemaining() && !return_from_parse)
664 {
665
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
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
706 if (_headerString!=null || _valueString!=null)
707 {
708
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
725 if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
726 {
727 consumeCRLF(ch,buffer);
728
729 _contentPosition=0;
730
731
732
733
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
741 if (_responseHandler !=null &&
742 (_responseStatus == 304 ||
743 _responseStatus == 204 ||
744 _responseStatus < 200))
745 _endOfContent=EndOfContent.NO_CONTENT;
746
747
748 else if (_endOfContent == EndOfContent.UNKNOWN_CONTENT)
749 {
750 if (_responseStatus == 0
751 || _responseStatus == 304
752 || _responseStatus == 204
753 || _responseStatus < 200)
754 _endOfContent=EndOfContent.NO_CONTENT;
755 else
756 _endOfContent=EndOfContent.EOF_CONTENT;
757 }
758
759
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
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
815 _header=HttpHeader.CACHE.getBest(buffer,-1,buffer.remaining());
816
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
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
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
1034
1035
1036 public boolean parseNext(ByteBuffer buffer)
1037 {
1038 try
1039 {
1040
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
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
1091 if (_responseStatus>0 && _headResponse)
1092 {
1093 setState(State.END);
1094 if (_handler.messageComplete())
1095 return true;
1096 }
1097
1098
1099
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
1134 if (_contentChunk.remaining() > remaining)
1135 {
1136
1137
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
1286
1287
1288
1289
1290
1291
1292
1293
1294 public boolean shutdownInput()
1295 {
1296 LOG.debug("shutdownInput {}", this);
1297
1298
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
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
1378
1379
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
1391
1392
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
1405
1406
1407
1408
1409
1410
1411 public abstract boolean startRequest(HttpMethod method, String methodString, ByteBuffer uri, HttpVersion version);
1412
1413
1414
1415
1416
1417
1418 public abstract boolean parsedHostHeader(String host,int port);
1419 }
1420
1421 public interface ResponseHandler<T> extends HttpHandler<T>
1422 {
1423
1424
1425
1426 public abstract boolean startResponse(HttpVersion version, int status, String reason);
1427 }
1428
1429
1430 }