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