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