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