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