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.io.IOException;
22
23 import org.eclipse.jetty.io.Buffer;
24 import org.eclipse.jetty.io.BufferCache.CachedBuffer;
25 import org.eclipse.jetty.io.BufferUtil;
26 import org.eclipse.jetty.io.Buffers;
27 import org.eclipse.jetty.io.ByteArrayBuffer;
28 import org.eclipse.jetty.io.EndPoint;
29 import org.eclipse.jetty.io.EofException;
30 import org.eclipse.jetty.io.View;
31 import org.eclipse.jetty.io.bio.StreamEndPoint;
32 import org.eclipse.jetty.util.StringUtil;
33 import org.eclipse.jetty.util.log.Log;
34 import org.eclipse.jetty.util.log.Logger;
35
36 public class HttpParser implements Parser
37 {
38 private static final Logger LOG = Log.getLogger(HttpParser.class);
39
40
41 public static final int STATE_START=-14;
42 public static final int STATE_FIELD0=-13;
43 public static final int STATE_SPACE1=-12;
44 public static final int STATE_STATUS=-11;
45 public static final int STATE_URI=-10;
46 public static final int STATE_SPACE2=-9;
47 public static final int STATE_END0=-8;
48 public static final int STATE_END1=-7;
49 public static final int STATE_FIELD2=-6;
50 public static final int STATE_HEADER=-5;
51 public static final int STATE_HEADER_NAME=-4;
52 public static final int STATE_HEADER_IN_NAME=-3;
53 public static final int STATE_HEADER_VALUE=-2;
54 public static final int STATE_HEADER_IN_VALUE=-1;
55 public static final int STATE_END=0;
56 public static final int STATE_EOF_CONTENT=1;
57 public static final int STATE_CONTENT=2;
58 public static final int STATE_CHUNKED_CONTENT=3;
59 public static final int STATE_CHUNK_SIZE=4;
60 public static final int STATE_CHUNK_PARAMS=5;
61 public static final int STATE_CHUNK=6;
62 public static final int STATE_SEEKING_EOF=7;
63
64 private final EventHandler _handler;
65 private final Buffers _buffers;
66 private final EndPoint _endp;
67 private Buffer _header;
68 private Buffer _body;
69 private Buffer _buffer;
70 private CachedBuffer _cached;
71 private final View.CaseInsensitive _tok0;
72 private final View.CaseInsensitive _tok1;
73 private String _multiLineValue;
74 private int _responseStatus;
75 private boolean _forceContentBuffer;
76 private boolean _persistent;
77
78
79 protected final View _contentView=new View();
80 protected int _state=STATE_START;
81 protected byte _eol;
82 protected int _length;
83 protected long _contentLength;
84 protected long _contentPosition;
85 protected int _chunkLength;
86 protected int _chunkPosition;
87 private boolean _headResponse;
88
89
90
91
92
93 public HttpParser(Buffer buffer, EventHandler handler)
94 {
95 _endp=null;
96 _buffers=null;
97 _header=buffer;
98 _buffer=buffer;
99 _handler=handler;
100
101 _tok0=new View.CaseInsensitive(_header);
102 _tok1=new View.CaseInsensitive(_header);
103 }
104
105
106
107
108
109
110
111
112 public HttpParser(Buffers buffers, EndPoint endp, EventHandler handler)
113 {
114 _buffers=buffers;
115 _endp=endp;
116 _handler=handler;
117 _tok0=new View.CaseInsensitive();
118 _tok1=new View.CaseInsensitive();
119 }
120
121
122 public long getContentLength()
123 {
124 return _contentLength;
125 }
126
127
128 public long getContentRead()
129 {
130 return _contentPosition;
131 }
132
133
134
135
136
137 public void setHeadResponse(boolean head)
138 {
139 _headResponse=head;
140 }
141
142
143 public int getState()
144 {
145 return _state;
146 }
147
148
149 public boolean inContentState()
150 {
151 return _state > 0;
152 }
153
154
155 public boolean inHeaderState()
156 {
157 return _state < 0;
158 }
159
160
161 public boolean isChunking()
162 {
163 return _contentLength==HttpTokens.CHUNKED_CONTENT;
164 }
165
166
167 public boolean isIdle()
168 {
169 return isState(STATE_START);
170 }
171
172
173 public boolean isComplete()
174 {
175 return isState(STATE_END);
176 }
177
178
179 public boolean isMoreInBuffer()
180 throws IOException
181 {
182 return ( _header!=null && _header.hasContent() ||
183 _body!=null && _body.hasContent());
184 }
185
186
187 public boolean isState(int state)
188 {
189 return _state == state;
190 }
191
192
193 public boolean isPersistent()
194 {
195 return _persistent;
196 }
197
198
199 public void setPersistent(boolean persistent)
200 {
201 _persistent = persistent;
202 if (!_persistent &&(_state==STATE_END || _state==STATE_START))
203 _state=STATE_SEEKING_EOF;
204 }
205
206
207
208
209
210
211
212 public void parse() throws IOException
213 {
214 if (_state==STATE_END)
215 reset();
216 if (_state!=STATE_START)
217 throw new IllegalStateException("!START");
218
219
220 while (_state != STATE_END)
221 if (parseNext()<0)
222 return;
223 }
224
225
226
227
228
229
230
231
232
233 public boolean parseAvailable() throws IOException
234 {
235 boolean progress=parseNext()>0;
236
237
238 while (!isComplete() && _buffer!=null && _buffer.length()>0)
239 {
240 progress |= parseNext()>0;
241 }
242 return progress;
243 }
244
245
246
247
248
249
250
251 public int parseNext() throws IOException
252 {
253 try
254 {
255 int progress=0;
256
257 if (_state == STATE_END)
258 return 0;
259
260 if (_buffer==null)
261 _buffer=getHeaderBuffer();
262
263
264 if (_state == STATE_CONTENT && _contentPosition == _contentLength)
265 {
266 _state=STATE_END;
267 _handler.messageComplete(_contentPosition);
268 return 1;
269 }
270
271 int length=_buffer.length();
272
273
274 if (length == 0)
275 {
276 int filled=-1;
277 IOException ex=null;
278 try
279 {
280 filled=fill();
281 LOG.debug("filled {}/{}",filled,_buffer.length());
282 }
283 catch(IOException e)
284 {
285 LOG.debug(this.toString(),e);
286 ex=e;
287 }
288
289 if (filled > 0 )
290 progress++;
291 else if (filled < 0 )
292 {
293 _persistent=false;
294
295
296 if (_state>STATE_END)
297 {
298 if (_buffer.length()>0 && !_headResponse)
299 {
300 Buffer chunk=_buffer.get(_buffer.length());
301 _contentPosition += chunk.length();
302 _contentView.update(chunk);
303 _handler.content(chunk);
304 }
305 }
306
307
308 switch(_state)
309 {
310 case STATE_END:
311 case STATE_SEEKING_EOF:
312 _state=STATE_END;
313 break;
314
315 case STATE_EOF_CONTENT:
316 _state=STATE_END;
317 _handler.messageComplete(_contentPosition);
318 break;
319
320 default:
321 _state=STATE_END;
322 if (!_headResponse)
323 _handler.earlyEOF();
324 _handler.messageComplete(_contentPosition);
325 }
326
327 if (ex!=null)
328 throw ex;
329
330 if (!isComplete() && !isIdle())
331 throw new EofException();
332
333 return -1;
334 }
335 length=_buffer.length();
336 }
337
338
339
340 byte ch;
341 byte[] array=_buffer.array();
342 int last=_state;
343 while (_state<STATE_END && length-->0)
344 {
345 if (last!=_state)
346 {
347 progress++;
348 last=_state;
349 }
350
351 ch=_buffer.get();
352
353 if (_eol == HttpTokens.CARRIAGE_RETURN && ch == HttpTokens.LINE_FEED)
354 {
355 _eol=HttpTokens.LINE_FEED;
356 continue;
357 }
358 _eol=0;
359
360 switch (_state)
361 {
362 case STATE_START:
363 _contentLength=HttpTokens.UNKNOWN_CONTENT;
364 _cached=null;
365 if (ch > HttpTokens.SPACE || ch<0)
366 {
367 _buffer.mark();
368 _state=STATE_FIELD0;
369 }
370 break;
371
372 case STATE_FIELD0:
373 if (ch == HttpTokens.SPACE)
374 {
375 _tok0.update(_buffer.markIndex(), _buffer.getIndex() - 1);
376 _responseStatus=HttpVersions.CACHE.get(_tok0)==null?-1:0;
377 _state=STATE_SPACE1;
378 continue;
379 }
380 else if (ch < HttpTokens.SPACE && ch>=0)
381 {
382 throw new HttpException(HttpStatus.BAD_REQUEST_400);
383 }
384 break;
385
386 case STATE_SPACE1:
387 if (ch > HttpTokens.SPACE || ch<0)
388 {
389 _buffer.mark();
390 if (_responseStatus>=0)
391 {
392 _state=STATE_STATUS;
393 _responseStatus=ch-'0';
394 }
395 else
396 _state=STATE_URI;
397 }
398 else if (ch < HttpTokens.SPACE)
399 {
400 throw new HttpException(HttpStatus.BAD_REQUEST_400);
401 }
402 break;
403
404 case STATE_STATUS:
405 if (ch == HttpTokens.SPACE)
406 {
407 _tok1.update(_buffer.markIndex(), _buffer.getIndex() - 1);
408 _state=STATE_SPACE2;
409 continue;
410 }
411 else if (ch>='0' && ch<='9')
412 {
413 _responseStatus=_responseStatus*10+(ch-'0');
414 continue;
415 }
416 else if (ch < HttpTokens.SPACE && ch>=0)
417 {
418 _handler.startResponse(HttpMethods.CACHE.lookup(_tok0), _responseStatus, null);
419 _eol=ch;
420 _state=STATE_HEADER;
421 _tok0.setPutIndex(_tok0.getIndex());
422 _tok1.setPutIndex(_tok1.getIndex());
423 _multiLineValue=null;
424 continue;
425 }
426
427 _state=STATE_URI;
428 _responseStatus=-1;
429 break;
430
431 case STATE_URI:
432 if (ch == HttpTokens.SPACE)
433 {
434 _tok1.update(_buffer.markIndex(), _buffer.getIndex() - 1);
435 _state=STATE_SPACE2;
436 continue;
437 }
438 else if (ch < HttpTokens.SPACE && ch>=0)
439 {
440
441 _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _buffer.sliceFromMark(), null);
442 _persistent=false;
443 _state=STATE_SEEKING_EOF;
444 _handler.headerComplete();
445 _handler.messageComplete(_contentPosition);
446 return 1;
447 }
448 break;
449
450 case STATE_SPACE2:
451 if (ch > HttpTokens.SPACE || ch<0)
452 {
453 _buffer.mark();
454 _state=STATE_FIELD2;
455 }
456 else if (ch < HttpTokens.SPACE)
457 {
458 if (_responseStatus>0)
459 {
460 _handler.startResponse(HttpMethods.CACHE.lookup(_tok0), _responseStatus, null);
461 _eol=ch;
462 _state=STATE_HEADER;
463 _tok0.setPutIndex(_tok0.getIndex());
464 _tok1.setPutIndex(_tok1.getIndex());
465 _multiLineValue=null;
466 }
467 else
468 {
469
470 _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _tok1, null);
471 _persistent=false;
472 _state=STATE_SEEKING_EOF;
473 _handler.headerComplete();
474 _handler.messageComplete(_contentPosition);
475 return 1;
476 }
477 }
478 break;
479
480 case STATE_FIELD2:
481 if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
482 {
483 Buffer version;
484 if (_responseStatus>0)
485 _handler.startResponse(version=HttpVersions.CACHE.lookup(_tok0), _responseStatus,_buffer.sliceFromMark());
486 else
487 _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _tok1, version=HttpVersions.CACHE.lookup(_buffer.sliceFromMark()));
488 _eol=ch;
489 _persistent=HttpVersions.CACHE.getOrdinal(version)>=HttpVersions.HTTP_1_1_ORDINAL;
490 _state=STATE_HEADER;
491 _tok0.setPutIndex(_tok0.getIndex());
492 _tok1.setPutIndex(_tok1.getIndex());
493 _multiLineValue=null;
494 continue;
495 }
496 break;
497
498 case STATE_HEADER:
499 switch(ch)
500 {
501 case HttpTokens.COLON:
502 case HttpTokens.SPACE:
503 case HttpTokens.TAB:
504 {
505
506 _length=-1;
507 _state=STATE_HEADER_VALUE;
508 break;
509 }
510
511 default:
512 {
513
514 if (_cached!=null || _tok0.length() > 0 || _tok1.length() > 0 || _multiLineValue != null)
515 {
516 Buffer header=_cached!=null?_cached:HttpHeaders.CACHE.lookup(_tok0);
517 _cached=null;
518 Buffer value=_multiLineValue == null ? _tok1 : new ByteArrayBuffer(_multiLineValue);
519
520 int ho=HttpHeaders.CACHE.getOrdinal(header);
521 if (ho >= 0)
522 {
523 int vo;
524
525 switch (ho)
526 {
527 case HttpHeaders.CONTENT_LENGTH_ORDINAL:
528 if (_contentLength != HttpTokens.CHUNKED_CONTENT && _responseStatus!=304 && _responseStatus!=204 && (_responseStatus<100 || _responseStatus>=200))
529 {
530 try
531 {
532 _contentLength=BufferUtil.toLong(value);
533 }
534 catch(NumberFormatException e)
535 {
536 LOG.ignore(e);
537 throw new HttpException(HttpStatus.BAD_REQUEST_400);
538 }
539 if (_contentLength <= 0)
540 _contentLength=HttpTokens.NO_CONTENT;
541 }
542 break;
543
544 case HttpHeaders.TRANSFER_ENCODING_ORDINAL:
545 value=HttpHeaderValues.CACHE.lookup(value);
546 vo=HttpHeaderValues.CACHE.getOrdinal(value);
547 if (HttpHeaderValues.CHUNKED_ORDINAL == vo)
548 _contentLength=HttpTokens.CHUNKED_CONTENT;
549 else
550 {
551 String c=value.toString(StringUtil.__ISO_8859_1);
552 if (c.endsWith(HttpHeaderValues.CHUNKED))
553 _contentLength=HttpTokens.CHUNKED_CONTENT;
554
555 else if (c.indexOf(HttpHeaderValues.CHUNKED) >= 0)
556 throw new HttpException(400,null);
557 }
558 break;
559
560 case HttpHeaders.CONNECTION_ORDINAL:
561 switch(HttpHeaderValues.CACHE.getOrdinal(value))
562 {
563 case HttpHeaderValues.CLOSE_ORDINAL:
564 _persistent=false;
565 break;
566
567 case HttpHeaderValues.KEEP_ALIVE_ORDINAL:
568 _persistent=true;
569 break;
570
571 case -1:
572 {
573 for (String v : value.toString().split(","))
574 {
575 switch(HttpHeaderValues.CACHE.getOrdinal(v.trim()))
576 {
577 case HttpHeaderValues.CLOSE_ORDINAL:
578 _persistent=false;
579 break;
580
581 case HttpHeaderValues.KEEP_ALIVE_ORDINAL:
582 _persistent=true;
583 break;
584 }
585 }
586 break;
587 }
588 }
589 }
590 }
591
592 _handler.parsedHeader(header, value);
593 _tok0.setPutIndex(_tok0.getIndex());
594 _tok1.setPutIndex(_tok1.getIndex());
595 _multiLineValue=null;
596 }
597 _buffer.setMarkIndex(-1);
598
599
600
601 if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
602 {
603
604 if (_contentLength == HttpTokens.UNKNOWN_CONTENT)
605 {
606 if (_responseStatus == 0
607 || _responseStatus == 304
608 || _responseStatus == 204
609 || _responseStatus < 200)
610 _contentLength=HttpTokens.NO_CONTENT;
611 else
612 _contentLength=HttpTokens.EOF_CONTENT;
613 }
614
615 _contentPosition=0;
616 _eol=ch;
617 if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED)
618 _eol=_buffer.get();
619
620
621
622 switch (_contentLength > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) _contentLength)
623 {
624 case HttpTokens.EOF_CONTENT:
625 _state=STATE_EOF_CONTENT;
626 _handler.headerComplete();
627 break;
628
629 case HttpTokens.CHUNKED_CONTENT:
630 _state=STATE_CHUNKED_CONTENT;
631 _handler.headerComplete();
632 break;
633
634 case HttpTokens.NO_CONTENT:
635 _handler.headerComplete();
636 _state=_persistent||(_responseStatus>=100&&_responseStatus<200)?STATE_END:STATE_SEEKING_EOF;
637 _handler.messageComplete(_contentPosition);
638 return 1;
639
640 default:
641 _state=STATE_CONTENT;
642 _handler.headerComplete();
643 break;
644 }
645 return 1;
646 }
647 else
648 {
649
650 _length=1;
651 _buffer.mark();
652 _state=STATE_HEADER_NAME;
653
654
655 if (array!=null)
656 {
657 _cached=HttpHeaders.CACHE.getBest(array, _buffer.markIndex(), length+1);
658
659 if (_cached!=null)
660 {
661 _length=_cached.length();
662 _buffer.setGetIndex(_buffer.markIndex()+_length);
663 length=_buffer.length();
664 }
665 }
666 }
667 }
668 }
669
670 break;
671
672 case STATE_HEADER_NAME:
673 switch(ch)
674 {
675 case HttpTokens.CARRIAGE_RETURN:
676 case HttpTokens.LINE_FEED:
677 if (_length > 0)
678 _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length);
679 _eol=ch;
680 _state=STATE_HEADER;
681 break;
682 case HttpTokens.COLON:
683 if (_length > 0 && _cached==null)
684 _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length);
685 _length=-1;
686 _state=STATE_HEADER_VALUE;
687 break;
688 case HttpTokens.SPACE:
689 case HttpTokens.TAB:
690 break;
691 default:
692 {
693 _cached=null;
694 if (_length == -1)
695 _buffer.mark();
696 _length=_buffer.getIndex() - _buffer.markIndex();
697 _state=STATE_HEADER_IN_NAME;
698 }
699 }
700
701 break;
702
703 case STATE_HEADER_IN_NAME:
704 switch(ch)
705 {
706 case HttpTokens.CARRIAGE_RETURN:
707 case HttpTokens.LINE_FEED:
708 if (_length > 0)
709 _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length);
710 _eol=ch;
711 _state=STATE_HEADER;
712 break;
713 case HttpTokens.COLON:
714 if (_length > 0 && _cached==null)
715 _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length);
716 _length=-1;
717 _state=STATE_HEADER_VALUE;
718 break;
719 case HttpTokens.SPACE:
720 case HttpTokens.TAB:
721 _state=STATE_HEADER_NAME;
722 break;
723 default:
724 {
725 _cached=null;
726 _length++;
727 }
728 }
729 break;
730
731 case STATE_HEADER_VALUE:
732 switch(ch)
733 {
734 case HttpTokens.CARRIAGE_RETURN:
735 case HttpTokens.LINE_FEED:
736 if (_length > 0)
737 {
738 if (_tok1.length() == 0)
739 _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length);
740 else
741 {
742
743 if (_multiLineValue == null) _multiLineValue=_tok1.toString(StringUtil.__ISO_8859_1);
744 _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length);
745 _multiLineValue += " " + _tok1.toString(StringUtil.__ISO_8859_1);
746 }
747 }
748 _eol=ch;
749 _state=STATE_HEADER;
750 break;
751 case HttpTokens.SPACE:
752 case HttpTokens.TAB:
753 break;
754 default:
755 {
756 if (_length == -1)
757 _buffer.mark();
758 _length=_buffer.getIndex() - _buffer.markIndex();
759 _state=STATE_HEADER_IN_VALUE;
760 }
761 }
762 break;
763
764 case STATE_HEADER_IN_VALUE:
765 switch(ch)
766 {
767 case HttpTokens.CARRIAGE_RETURN:
768 case HttpTokens.LINE_FEED:
769 if (_length > 0)
770 {
771 if (_tok1.length() == 0)
772 _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length);
773 else
774 {
775
776 if (_multiLineValue == null) _multiLineValue=_tok1.toString(StringUtil.__ISO_8859_1);
777 _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length);
778 _multiLineValue += " " + _tok1.toString(StringUtil.__ISO_8859_1);
779 }
780 }
781 _eol=ch;
782 _state=STATE_HEADER;
783 break;
784 case HttpTokens.SPACE:
785 case HttpTokens.TAB:
786 _state=STATE_HEADER_VALUE;
787 break;
788 default:
789 _length++;
790 }
791 break;
792 }
793 }
794
795
796
797
798 if (_responseStatus>0 && _headResponse)
799 {
800 _state=_persistent||(_responseStatus>=100&&_responseStatus<200)?STATE_END:STATE_SEEKING_EOF;
801 _handler.messageComplete(_contentLength);
802 }
803
804
805
806
807
808 length=_buffer.length();
809 Buffer chunk;
810 last=_state;
811 while (_state > STATE_END && length > 0)
812 {
813 if (last!=_state)
814 {
815 progress++;
816 last=_state;
817 }
818
819 if (_eol == HttpTokens.CARRIAGE_RETURN && _buffer.peek() == HttpTokens.LINE_FEED)
820 {
821 _eol=_buffer.get();
822 length=_buffer.length();
823 continue;
824 }
825 _eol=0;
826 switch (_state)
827 {
828 case STATE_EOF_CONTENT:
829 chunk=_buffer.get(_buffer.length());
830 _contentPosition += chunk.length();
831 _contentView.update(chunk);
832 _handler.content(chunk);
833
834 return 1;
835
836 case STATE_CONTENT:
837 {
838 long remaining=_contentLength - _contentPosition;
839 if (remaining == 0)
840 {
841 _state=_persistent?STATE_END:STATE_SEEKING_EOF;
842 _handler.messageComplete(_contentPosition);
843 return 1;
844 }
845
846 if (length > remaining)
847 {
848
849
850 length=(int)remaining;
851 }
852
853 chunk=_buffer.get(length);
854 _contentPosition += chunk.length();
855 _contentView.update(chunk);
856 _handler.content(chunk);
857
858 if(_contentPosition == _contentLength)
859 {
860 _state=_persistent?STATE_END:STATE_SEEKING_EOF;
861 _handler.messageComplete(_contentPosition);
862 }
863
864 return 1;
865 }
866
867 case STATE_CHUNKED_CONTENT:
868 {
869 ch=_buffer.peek();
870 if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
871 _eol=_buffer.get();
872 else if (ch <= HttpTokens.SPACE)
873 _buffer.get();
874 else
875 {
876 _chunkLength=0;
877 _chunkPosition=0;
878 _state=STATE_CHUNK_SIZE;
879 }
880 break;
881 }
882
883 case STATE_CHUNK_SIZE:
884 {
885 ch=_buffer.get();
886 if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
887 {
888 _eol=ch;
889
890 if (_chunkLength == 0)
891 {
892 if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED)
893 _eol=_buffer.get();
894 _state=_persistent?STATE_END:STATE_SEEKING_EOF;
895 _handler.messageComplete(_contentPosition);
896 return 1;
897 }
898 else
899 _state=STATE_CHUNK;
900 }
901 else if (ch <= HttpTokens.SPACE || ch == HttpTokens.SEMI_COLON)
902 _state=STATE_CHUNK_PARAMS;
903 else if (ch >= '0' && ch <= '9')
904 _chunkLength=_chunkLength * 16 + (ch - '0');
905 else if (ch >= 'a' && ch <= 'f')
906 _chunkLength=_chunkLength * 16 + (10 + ch - 'a');
907 else if (ch >= 'A' && ch <= 'F')
908 _chunkLength=_chunkLength * 16 + (10 + ch - 'A');
909 else
910 throw new IOException("bad chunk char: " + ch);
911 break;
912 }
913
914 case STATE_CHUNK_PARAMS:
915 {
916 ch=_buffer.get();
917 if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
918 {
919 _eol=ch;
920 if (_chunkLength == 0)
921 {
922 if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED)
923 _eol=_buffer.get();
924 _state=_persistent?STATE_END:STATE_SEEKING_EOF;
925 _handler.messageComplete(_contentPosition);
926 return 1;
927 }
928 else
929 _state=STATE_CHUNK;
930 }
931 break;
932 }
933
934 case STATE_CHUNK:
935 {
936 int remaining=_chunkLength - _chunkPosition;
937 if (remaining == 0)
938 {
939 _state=STATE_CHUNKED_CONTENT;
940 break;
941 }
942 else if (length > remaining)
943 length=remaining;
944 chunk=_buffer.get(length);
945 _contentPosition += chunk.length();
946 _chunkPosition += chunk.length();
947 _contentView.update(chunk);
948 _handler.content(chunk);
949
950 return 1;
951 }
952
953 case STATE_SEEKING_EOF:
954 {
955
956 if (_buffer.length()>2)
957 {
958 _state=STATE_END;
959 _endp.close();
960 }
961 else
962 {
963
964 while (_buffer.length()>0)
965 if (!Character.isWhitespace(_buffer.get()))
966 {
967 _state=STATE_END;
968 _endp.close();
969 _buffer.clear();
970 }
971 }
972
973 _buffer.clear();
974 break;
975 }
976 }
977
978 length=_buffer.length();
979 }
980
981 return progress;
982 }
983 catch(HttpException e)
984 {
985 _persistent=false;
986 _state=STATE_SEEKING_EOF;
987 throw e;
988 }
989 }
990
991
992
993
994
995 protected int fill() throws IOException
996 {
997
998 if (_buffer==null)
999 _buffer=getHeaderBuffer();
1000
1001
1002 if (_state>STATE_END && _buffer==_header && _header!=null && !_header.hasContent() && _body!=null && _body.hasContent())
1003 {
1004 _buffer=_body;
1005 return _buffer.length();
1006 }
1007
1008
1009 if (_buffer==_header && _state>STATE_END && _header.length()==0 && (_forceContentBuffer || (_contentLength-_contentPosition)>_header.capacity()) && (_body!=null||_buffers!=null))
1010 {
1011 if (_body==null)
1012 _body=_buffers.getBuffer();
1013 _buffer=_body;
1014 }
1015
1016
1017 if (_endp != null )
1018 {
1019
1020 if (_buffer==_body || _state>STATE_END)
1021 {
1022 _buffer.compact();
1023 }
1024
1025
1026 if (_buffer.space() == 0)
1027 {
1028 LOG.warn("HttpParser Full for {} ",_endp);
1029 _buffer.clear();
1030 throw new HttpException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413, "FULL "+(_buffer==_body?"body":"head"));
1031 }
1032
1033 try
1034 {
1035 int filled = _endp.fill(_buffer);
1036 return filled;
1037 }
1038 catch(IOException e)
1039 {
1040 LOG.debug(e);
1041 throw (e instanceof EofException) ? e:new EofException(e);
1042 }
1043 }
1044
1045 return -1;
1046 }
1047
1048
1049 public void reset()
1050 {
1051
1052 _contentView.setGetIndex(_contentView.putIndex());
1053 _state=_persistent?STATE_START:(_endp.isInputShutdown()?STATE_END:STATE_SEEKING_EOF);
1054 _contentLength=HttpTokens.UNKNOWN_CONTENT;
1055 _contentPosition=0;
1056 _length=0;
1057 _responseStatus=0;
1058
1059
1060 if (_eol == HttpTokens.CARRIAGE_RETURN && _buffer!=null && _buffer.hasContent() && _buffer.peek() == HttpTokens.LINE_FEED)
1061 _eol=_buffer.get();
1062
1063 if (_body!=null && _body.hasContent())
1064 {
1065
1066
1067
1068 if (_header==null)
1069 getHeaderBuffer();
1070 else
1071 {
1072 _header.setMarkIndex(-1);
1073 _header.compact();
1074 }
1075 int take=_header.space();
1076 if (take>_body.length())
1077 take=_body.length();
1078 _body.peek(_body.getIndex(),take);
1079 _body.skip(_header.put(_body.peek(_body.getIndex(),take)));
1080 }
1081
1082 if (_header!=null)
1083 {
1084 _header.setMarkIndex(-1);
1085 _header.compact();
1086 }
1087 if (_body!=null)
1088 _body.setMarkIndex(-1);
1089
1090 _buffer=_header;
1091 returnBuffers();
1092 }
1093
1094
1095
1096 public void returnBuffers()
1097 {
1098 if (_body!=null && !_body.hasContent() && _body.markIndex()==-1 && _buffers!=null)
1099 {
1100 if (_buffer==_body)
1101 _buffer=_header;
1102 if (_buffers!=null)
1103 _buffers.returnBuffer(_body);
1104 _body=null;
1105 }
1106
1107 if (_header!=null && !_header.hasContent() && _header.markIndex()==-1 && _buffers!=null)
1108 {
1109 if (_buffer==_header)
1110 _buffer=null;
1111 _buffers.returnBuffer(_header);
1112 _header=null;
1113 }
1114 }
1115
1116
1117 public void setState(int state)
1118 {
1119 this._state=state;
1120 _contentLength=HttpTokens.UNKNOWN_CONTENT;
1121 }
1122
1123
1124 public String toString(Buffer buf)
1125 {
1126 return "state=" + _state + " length=" + _length + " buf=" + buf.hashCode();
1127 }
1128
1129
1130 @Override
1131 public String toString()
1132 {
1133 return String.format("%s{s=%d,l=%d,c=%d}",
1134 getClass().getSimpleName(),
1135 _state,
1136 _length,
1137 _contentLength);
1138 }
1139
1140
1141 public Buffer getHeaderBuffer()
1142 {
1143 if (_header == null)
1144 {
1145 _header=_buffers.getHeader();
1146 _tok0.update(_header);
1147 _tok1.update(_header);
1148 }
1149 return _header;
1150 }
1151
1152
1153 public Buffer getBodyBuffer()
1154 {
1155 return _body;
1156 }
1157
1158
1159
1160
1161
1162 public void setForceContentBuffer(boolean force)
1163 {
1164 _forceContentBuffer=force;
1165 }
1166
1167
1168 public Buffer blockForContent(long maxIdleTime) throws IOException
1169 {
1170 if (_contentView.length()>0)
1171 return _contentView;
1172
1173 if (getState() <= STATE_END || isState(STATE_SEEKING_EOF))
1174 return null;
1175
1176 try
1177 {
1178 parseNext();
1179
1180
1181 while(_contentView.length() == 0 && !(isState(HttpParser.STATE_END)||isState(HttpParser.STATE_SEEKING_EOF)) && _endp!=null && _endp.isOpen())
1182 {
1183 if (!_endp.isBlocking())
1184 {
1185 if (parseNext()>0)
1186 continue;
1187
1188 if (!_endp.blockReadable(maxIdleTime))
1189 {
1190 _endp.close();
1191 throw new EofException("timeout");
1192 }
1193 }
1194
1195 parseNext();
1196 }
1197 }
1198 catch(IOException e)
1199 {
1200
1201 _endp.close();
1202 throw e;
1203 }
1204
1205 return _contentView.length()>0?_contentView:null;
1206 }
1207
1208
1209
1210
1211
1212 public int available() throws IOException
1213 {
1214 if (_contentView!=null && _contentView.length()>0)
1215 return _contentView.length();
1216
1217 if (_endp.isBlocking())
1218 {
1219 if (_state>0 && _endp instanceof StreamEndPoint)
1220 return ((StreamEndPoint)_endp).getInputStream().available()>0?1:0;
1221
1222 return 0;
1223 }
1224
1225 parseNext();
1226 return _contentView==null?0:_contentView.length();
1227 }
1228
1229
1230
1231
1232 public static abstract class EventHandler
1233 {
1234 public abstract void content(Buffer ref) throws IOException;
1235
1236 public void headerComplete() throws IOException
1237 {
1238 }
1239
1240 public void messageComplete(long contentLength) throws IOException
1241 {
1242 }
1243
1244
1245
1246
1247 public void parsedHeader(Buffer name, Buffer value) throws IOException
1248 {
1249 }
1250
1251
1252
1253
1254 public abstract void startRequest(Buffer method, Buffer url, Buffer version)
1255 throws IOException;
1256
1257
1258
1259
1260 public abstract void startResponse(Buffer version, int status, Buffer reason)
1261 throws IOException;
1262
1263 public void earlyEOF()
1264 {}
1265 }
1266
1267
1268
1269
1270 }