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