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