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