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