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