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