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