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