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
417 final Buffer method = HttpMethods.CACHE.lookup(_tok0);
418 if (method==_tok0 && _tok1.length()==3 && Character.isDigit((char)_tok1.peek()))
419 {
420 _responseStatus = BufferUtil.toInt(_tok1);
421 _handler.startResponse(HttpVersions.CACHE.lookup(_tok0), _responseStatus,_buffer.sliceFromMark());
422 }
423 else
424 _handler.startRequest(method, _tok1,HttpVersions.CACHE.lookup(_buffer.sliceFromMark()));
425 _eol=ch;
426 _state=STATE_HEADER;
427 _tok0.setPutIndex(_tok0.getIndex());
428 _tok1.setPutIndex(_tok1.getIndex());
429 _multiLineValue=null;
430 continue;
431
432 }
433 break;
434
435 case STATE_HEADER:
436 switch(ch)
437 {
438 case HttpTokens.COLON:
439 case HttpTokens.SPACE:
440 case HttpTokens.TAB:
441 {
442
443 _length=-1;
444 _state=STATE_HEADER_VALUE;
445 break;
446 }
447
448 default:
449 {
450
451 if (_cached!=null || _tok0.length() > 0 || _tok1.length() > 0 || _multiLineValue != null)
452 {
453
454 Buffer header=_cached!=null?_cached:HttpHeaders.CACHE.lookup(_tok0);
455 _cached=null;
456 Buffer value=_multiLineValue == null ? (Buffer) _tok1 : (Buffer) new ByteArrayBuffer(_multiLineValue);
457
458 int ho=HttpHeaders.CACHE.getOrdinal(header);
459 if (ho >= 0)
460 {
461 int vo=-1;
462
463 switch (ho)
464 {
465 case HttpHeaders.CONTENT_LENGTH_ORDINAL:
466 if (_contentLength != HttpTokens.CHUNKED_CONTENT)
467 {
468 _contentLength=BufferUtil.toLong(value);
469 if (_contentLength <= 0)
470 _contentLength=HttpTokens.NO_CONTENT;
471 }
472 break;
473
474 case HttpHeaders.TRANSFER_ENCODING_ORDINAL:
475 value=HttpHeaderValues.CACHE.lookup(value);
476 vo=HttpHeaderValues.CACHE.getOrdinal(value);
477 if (HttpHeaderValues.CHUNKED_ORDINAL == vo)
478 _contentLength=HttpTokens.CHUNKED_CONTENT;
479 else
480 {
481 String c=value.toString();
482 if (c.endsWith(HttpHeaderValues.CHUNKED))
483 _contentLength=HttpTokens.CHUNKED_CONTENT;
484
485 else if (c.indexOf(HttpHeaderValues.CHUNKED) >= 0)
486 throw new HttpException(400,null);
487 }
488 break;
489 }
490 }
491
492 _handler.parsedHeader(header, value);
493 _tok0.setPutIndex(_tok0.getIndex());
494 _tok1.setPutIndex(_tok1.getIndex());
495 _multiLineValue=null;
496 }
497
498
499
500 if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
501 {
502
503
504
505 if (_contentLength == HttpTokens.UNKNOWN_CONTENT)
506 {
507 if (_responseStatus == 0
508 || _responseStatus == 304
509 || _responseStatus == 204
510 || _responseStatus < 200)
511 _contentLength=HttpTokens.NO_CONTENT;
512 else
513 _contentLength=HttpTokens.EOF_CONTENT;
514 }
515
516 _contentPosition=0;
517 _eol=ch;
518
519
520 switch (_contentLength > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) _contentLength)
521 {
522 case HttpTokens.EOF_CONTENT:
523 _state=STATE_EOF_CONTENT;
524 if(_body==null && _buffers!=null)
525 _body=_buffers.getBuffer(_contentBufferSize);
526
527 _handler.headerComplete();
528 break;
529
530 case HttpTokens.CHUNKED_CONTENT:
531 _state=STATE_CHUNKED_CONTENT;
532 if (_body==null && _buffers!=null)
533 _body=_buffers.getBuffer(_contentBufferSize);
534 _handler.headerComplete();
535 break;
536
537 case HttpTokens.NO_CONTENT:
538 _state=STATE_END;
539 _handler.headerComplete();
540 _handler.messageComplete(_contentPosition);
541 break;
542
543 default:
544 _state=STATE_CONTENT;
545 if(_forceContentBuffer ||
546 (_buffers!=null && _body==null && _buffer==_header && _contentLength>=(_header.capacity()-_header.getIndex())))
547 _body=_buffers.getBuffer(_contentBufferSize);
548 _handler.headerComplete();
549 break;
550 }
551 return total_filled;
552 }
553 else
554 {
555
556 _length=1;
557 _buffer.mark();
558 _state=STATE_HEADER_NAME;
559
560
561 if (array!=null)
562 {
563 _cached=HttpHeaders.CACHE.getBest(array, _buffer.markIndex(), length+1);
564
565 if (_cached!=null)
566 {
567 _length=_cached.length();
568 _buffer.setGetIndex(_buffer.markIndex()+_length);
569 length=_buffer.length();
570 }
571 }
572 }
573 }
574 }
575
576 break;
577
578 case STATE_HEADER_NAME:
579 switch(ch)
580 {
581 case HttpTokens.CARRIAGE_RETURN:
582 case HttpTokens.LINE_FEED:
583 if (_length > 0)
584 _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length);
585 _eol=ch;
586 _state=STATE_HEADER;
587 break;
588 case HttpTokens.COLON:
589 if (_length > 0 && _cached==null)
590 _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length);
591 _length=-1;
592 _state=STATE_HEADER_VALUE;
593 break;
594 case HttpTokens.SPACE:
595 case HttpTokens.TAB:
596 break;
597 default:
598 {
599 _cached=null;
600 if (_length == -1)
601 _buffer.mark();
602 _length=_buffer.getIndex() - _buffer.markIndex();
603 _state=STATE_HEADER_IN_NAME;
604 }
605 }
606
607 break;
608
609 case STATE_HEADER_IN_NAME:
610 switch(ch)
611 {
612 case HttpTokens.CARRIAGE_RETURN:
613 case HttpTokens.LINE_FEED:
614 if (_length > 0)
615 _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length);
616 _eol=ch;
617 _state=STATE_HEADER;
618 break;
619 case HttpTokens.COLON:
620 if (_length > 0 && _cached==null)
621 _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length);
622 _length=-1;
623 _state=STATE_HEADER_VALUE;
624 break;
625 case HttpTokens.SPACE:
626 case HttpTokens.TAB:
627 _state=STATE_HEADER_NAME;
628 break;
629 default:
630 {
631 _cached=null;
632 _length++;
633 }
634 }
635 break;
636
637 case STATE_HEADER_VALUE:
638 switch(ch)
639 {
640 case HttpTokens.CARRIAGE_RETURN:
641 case HttpTokens.LINE_FEED:
642 if (_length > 0)
643 {
644 if (_tok1.length() == 0)
645 _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length);
646 else
647 {
648
649 if (_multiLineValue == null) _multiLineValue=_tok1.toString();
650 _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length);
651 _multiLineValue += " " + _tok1.toString();
652 }
653 }
654 _eol=ch;
655 _state=STATE_HEADER;
656 break;
657 case HttpTokens.SPACE:
658 case HttpTokens.TAB:
659 break;
660 default:
661 {
662 if (_length == -1)
663 _buffer.mark();
664 _length=_buffer.getIndex() - _buffer.markIndex();
665 _state=STATE_HEADER_IN_VALUE;
666 }
667 }
668 break;
669
670 case STATE_HEADER_IN_VALUE:
671 switch(ch)
672 {
673 case HttpTokens.CARRIAGE_RETURN:
674 case HttpTokens.LINE_FEED:
675 if (_length > 0)
676 {
677 if (_tok1.length() == 0)
678 _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length);
679 else
680 {
681
682 if (_multiLineValue == null) _multiLineValue=_tok1.toString();
683 _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length);
684 _multiLineValue += " " + _tok1.toString();
685 }
686 }
687 _eol=ch;
688 _state=STATE_HEADER;
689 break;
690 case HttpTokens.SPACE:
691 case HttpTokens.TAB:
692 _state=STATE_HEADER_VALUE;
693 break;
694 default:
695 _length++;
696 }
697 break;
698 }
699 }
700
701
702
703
704 length=_buffer.length();
705 if (_input!=null)
706 _input._contentView=_contentView;
707 Buffer chunk;
708 while (_state > STATE_END && length > 0)
709 {
710 if (_eol == HttpTokens.CARRIAGE_RETURN && _buffer.peek() == HttpTokens.LINE_FEED)
711 {
712 _eol=_buffer.get();
713 length=_buffer.length();
714 continue;
715 }
716 _eol=0;
717 switch (_state)
718 {
719 case STATE_EOF_CONTENT:
720 chunk=_buffer.get(_buffer.length());
721 _contentPosition += chunk.length();
722 _contentView.update(chunk);
723 _handler.content(chunk);
724
725 return total_filled;
726
727 case STATE_CONTENT:
728 {
729 long remaining=_contentLength - _contentPosition;
730 if (remaining == 0)
731 {
732 _state=STATE_END;
733 _handler.messageComplete(_contentPosition);
734 return total_filled;
735 }
736
737 if (length > remaining)
738 {
739
740
741 length=(int)remaining;
742 }
743
744 chunk=_buffer.get(length);
745 _contentPosition += chunk.length();
746 _contentView.update(chunk);
747 _handler.content(chunk);
748
749 if(_contentPosition == _contentLength)
750 {
751 _state=STATE_END;
752 _handler.messageComplete(_contentPosition);
753 }
754
755 return total_filled;
756 }
757
758 case STATE_CHUNKED_CONTENT:
759 {
760 ch=_buffer.peek();
761 if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
762 _eol=_buffer.get();
763 else if (ch <= HttpTokens.SPACE)
764 _buffer.get();
765 else
766 {
767 _chunkLength=0;
768 _chunkPosition=0;
769 _state=STATE_CHUNK_SIZE;
770 }
771 break;
772 }
773
774 case STATE_CHUNK_SIZE:
775 {
776 ch=_buffer.get();
777 if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
778 {
779 _eol=ch;
780 if (_chunkLength == 0)
781 {
782 _state=STATE_END;
783 _handler.messageComplete(_contentPosition);
784 return total_filled;
785 }
786 else
787 _state=STATE_CHUNK;
788 }
789 else if (ch <= HttpTokens.SPACE || ch == HttpTokens.SEMI_COLON)
790 _state=STATE_CHUNK_PARAMS;
791 else if (ch >= '0' && ch <= '9')
792 _chunkLength=_chunkLength * 16 + (ch - '0');
793 else if (ch >= 'a' && ch <= 'f')
794 _chunkLength=_chunkLength * 16 + (10 + ch - 'a');
795 else if (ch >= 'A' && ch <= 'F')
796 _chunkLength=_chunkLength * 16 + (10 + ch - 'A');
797 else
798 throw new IOException("bad chunk char: " + ch);
799 break;
800 }
801
802 case STATE_CHUNK_PARAMS:
803 {
804 ch=_buffer.get();
805 if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
806 {
807 _eol=ch;
808 if (_chunkLength == 0)
809 {
810 _state=STATE_END;
811 _handler.messageComplete(_contentPosition);
812 return total_filled;
813 }
814 else
815 _state=STATE_CHUNK;
816 }
817 break;
818 }
819
820 case STATE_CHUNK:
821 {
822 int remaining=_chunkLength - _chunkPosition;
823 if (remaining == 0)
824 {
825 _state=STATE_CHUNKED_CONTENT;
826 break;
827 }
828 else if (length > remaining)
829 length=remaining;
830 chunk=_buffer.get(length);
831 _contentPosition += chunk.length();
832 _chunkPosition += chunk.length();
833 _contentView.update(chunk);
834 _handler.content(chunk);
835
836 return total_filled;
837 }
838 }
839
840 length=_buffer.length();
841 }
842 return total_filled;
843 }
844
845
846
847
848
849 public long fill() throws IOException
850 {
851 if (_buffer==null)
852 {
853 _buffer=_header=getHeaderBuffer();
854 _tok0=new View.CaseInsensitive(_buffer);
855 _tok1=new View.CaseInsensitive(_buffer);
856 }
857 if (_body!=null && _buffer!=_body)
858 _buffer=_body;
859 if (_buffer == _body)
860 _buffer.compact();
861
862 int space=_buffer.space();
863
864
865 if (space == 0)
866 throw new HttpException(HttpStatus.ORDINAL_413_Request_Entity_Too_Large, "FULL "+(_buffer==_body?"body":"head"));
867 else
868 {
869 int filled=-1;
870
871 if (_endp != null )
872 {
873 try
874 {
875 filled=_endp.fill(_buffer);
876 }
877 catch(IOException e)
878 {
879 Log.debug(e);
880 reset(true);
881 throw (e instanceof EofException) ? e:new EofException(e);
882 }
883 }
884
885 return filled;
886 }
887 }
888
889
890
891
892
893 public void skipCRLF()
894 {
895
896 while (_header!=null && _header.length()>0)
897 {
898 byte ch = _header.peek();
899 if (ch==HttpTokens.CARRIAGE_RETURN || ch==HttpTokens.LINE_FEED)
900 {
901 _eol=ch;
902 _header.skip(1);
903 }
904 else
905 break;
906 }
907
908 while (_body!=null && _body.length()>0)
909 {
910 byte ch = _body.peek();
911 if (ch==HttpTokens.CARRIAGE_RETURN || ch==HttpTokens.LINE_FEED)
912 {
913 _eol=ch;
914 _body.skip(1);
915 }
916 else
917 break;
918 }
919
920 }
921
922 public void reset(boolean returnBuffers)
923 {
924 synchronized (this)
925 {
926 if (_input!=null && _contentView.length()>0)
927 _input._contentView=_contentView.duplicate(Buffer.READWRITE);
928
929 _state=STATE_START;
930 _contentLength=HttpTokens.UNKNOWN_CONTENT;
931 _contentPosition=0;
932 _length=0;
933 _responseStatus=0;
934
935 if (_buffer!=null && _buffer.length()>0 && _eol == HttpTokens.CARRIAGE_RETURN && _buffer.peek() == HttpTokens.LINE_FEED)
936 {
937 _buffer.skip(1);
938 _eol=HttpTokens.LINE_FEED;
939 }
940
941 if (_body!=null)
942 {
943 if (_body.hasContent())
944 {
945
946
947
948 _header.setMarkIndex(-1);
949 _header.compact();
950 int take=_header.space();
951 if (take>_body.length())
952 take=_body.length();
953 _body.peek(_body.getIndex(),take);
954 _body.skip(_header.put(_body.peek(_body.getIndex(),take)));
955 }
956
957 if (_body.length()==0)
958 {
959 if (_buffers!=null && returnBuffers)
960 _buffers.returnBuffer(_body);
961 _body=null;
962 }
963 else
964 {
965 _body.setMarkIndex(-1);
966 _body.compact();
967 }
968 }
969
970
971 if (_header!=null)
972 {
973 _header.setMarkIndex(-1);
974 if (!_header.hasContent() && _buffers!=null && returnBuffers)
975 {
976 _buffers.returnBuffer(_header);
977 _header=null;
978 _buffer=null;
979 }
980 else
981 {
982 _header.compact();
983 _tok0.update(_header);
984 _tok0.update(0,0);
985 _tok1.update(_header);
986 _tok1.update(0,0);
987 }
988 }
989
990 _buffer=_header;
991 }
992 }
993
994
995 public void setState(int state)
996 {
997 this._state=state;
998 _contentLength=HttpTokens.UNKNOWN_CONTENT;
999 }
1000
1001
1002 public String toString(Buffer buf)
1003 {
1004 return "state=" + _state + " length=" + _length + " buf=" + buf.hashCode();
1005 }
1006
1007
1008 public String toString()
1009 {
1010 return "state=" + _state + " length=" + _length + " len=" + _contentLength;
1011 }
1012
1013
1014 public Buffer getHeaderBuffer()
1015 {
1016 if (_header == null)
1017 {
1018 _header=_buffers.getBuffer(_headerBufferSize);
1019 }
1020 return _header;
1021 }
1022
1023
1024 public Buffer getBodyBuffer()
1025 {
1026 return _body;
1027 }
1028
1029
1030
1031
1032
1033 public void setForceContentBuffer(boolean force)
1034 {
1035 _forceContentBuffer=force;
1036 }
1037
1038
1039
1040
1041 public static abstract class EventHandler
1042 {
1043 public abstract void content(Buffer ref) throws IOException;
1044
1045 public void headerComplete() throws IOException
1046 {
1047 }
1048
1049 public void messageComplete(long contentLength) throws IOException
1050 {
1051 }
1052
1053
1054
1055
1056 public void parsedHeader(Buffer name, Buffer value) throws IOException
1057 {
1058 }
1059
1060
1061
1062
1063 public abstract void startRequest(Buffer method, Buffer url, Buffer version)
1064 throws IOException;
1065
1066
1067
1068
1069 public abstract void startResponse(Buffer version, int status, Buffer reason)
1070 throws IOException;
1071 }
1072
1073
1074
1075
1076
1077
1078 public static class Input extends ServletInputStream
1079 {
1080 protected HttpParser _parser;
1081 protected EndPoint _endp;
1082 protected long _maxIdleTime;
1083 protected Buffer _contentView;
1084
1085
1086 public Input(HttpParser parser, long maxIdleTime)
1087 {
1088 _parser=parser;
1089 _endp=parser._endp;
1090 _maxIdleTime=maxIdleTime;
1091 _contentView=_parser._contentView;
1092 _parser._input=this;
1093 }
1094
1095
1096
1097
1098
1099 public int read() throws IOException
1100 {
1101 int c=-1;
1102 if (blockForContent())
1103 c= 0xff & _contentView.get();
1104 return c;
1105 }
1106
1107
1108
1109
1110
1111 public int read(byte[] b, int off, int len) throws IOException
1112 {
1113 int l=-1;
1114 if (blockForContent())
1115 l= _contentView.get(b, off, len);
1116 return l;
1117 }
1118
1119
1120 private boolean blockForContent() throws IOException
1121 {
1122 if (_contentView.length()>0)
1123 return true;
1124 if (_parser.getState() <= HttpParser.STATE_END)
1125 return false;
1126
1127
1128 if (_endp==null)
1129 _parser.parseNext();
1130
1131
1132 else if (_endp.isBlocking())
1133 {
1134 try
1135 {
1136 _parser.parseNext();
1137
1138
1139 while(_contentView.length() == 0 && !_parser.isState(HttpParser.STATE_END) && _endp.isOpen())
1140 {
1141
1142 _parser.parseNext();
1143 }
1144 }
1145 catch(IOException e)
1146 {
1147 _endp.close();
1148 throw e;
1149 }
1150 }
1151 else
1152 {
1153 _parser.parseNext();
1154
1155
1156 while(_contentView.length() == 0 && !_parser.isState(HttpParser.STATE_END) && _endp.isOpen())
1157 {
1158 if (_endp.isBufferingInput() && _parser.parseNext()>0)
1159 continue;
1160
1161 if (!_endp.blockReadable(_maxIdleTime))
1162 {
1163 _endp.close();
1164 throw new EofException("timeout");
1165 }
1166
1167
1168 _parser.parseNext();
1169 }
1170 }
1171
1172 return _contentView.length()>0;
1173 }
1174
1175
1176
1177
1178
1179 public int available() throws IOException
1180 {
1181 if (_contentView!=null && _contentView.length()>0)
1182 return _contentView.length();
1183 if (!_endp.isBlocking())
1184 _parser.parseNext();
1185
1186 return _contentView==null?0:_contentView.length();
1187 }
1188 }
1189
1190
1191
1192
1193 }