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