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