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