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