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