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 import java.io.InterruptedIOException;
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.util.StringUtil;
27 import org.eclipse.jetty.util.log.Log;
28 import org.eclipse.jetty.util.log.Logger;
29
30
31
32
33
34
35
36
37 public class HttpGenerator extends AbstractGenerator
38 {
39 private static final Logger LOG = Log.getLogger(HttpGenerator.class);
40
41
42 private static class Status
43 {
44 Buffer _reason;
45 Buffer _schemeCode;
46 Buffer _responseLine;
47 }
48 private static final Status[] __status = new Status[HttpStatus.MAX_CODE+1];
49 static
50 {
51 int versionLength=HttpVersions.HTTP_1_1_BUFFER.length();
52
53 for (int i=0;i<__status.length;i++)
54 {
55 HttpStatus.Code code = HttpStatus.getCode(i);
56 if (code==null)
57 continue;
58 String reason=code.getMessage();
59 byte[] bytes=new byte[versionLength+5+reason.length()+2];
60 HttpVersions.HTTP_1_1_BUFFER.peek(0,bytes, 0, versionLength);
61 bytes[versionLength+0]=' ';
62 bytes[versionLength+1]=(byte)('0'+i/100);
63 bytes[versionLength+2]=(byte)('0'+(i%100)/10);
64 bytes[versionLength+3]=(byte)('0'+(i%10));
65 bytes[versionLength+4]=' ';
66 for (int j=0;j<reason.length();j++)
67 bytes[versionLength+5+j]=(byte)reason.charAt(j);
68 bytes[versionLength+5+reason.length()]=HttpTokens.CARRIAGE_RETURN;
69 bytes[versionLength+6+reason.length()]=HttpTokens.LINE_FEED;
70
71 __status[i] = new Status();
72 __status[i]._reason=new ByteArrayBuffer(bytes,versionLength+5,bytes.length-versionLength-7,Buffer.IMMUTABLE);
73 __status[i]._schemeCode=new ByteArrayBuffer(bytes,0,versionLength+5,Buffer.IMMUTABLE);
74 __status[i]._responseLine=new ByteArrayBuffer(bytes,0,bytes.length,Buffer.IMMUTABLE);
75 }
76 }
77
78
79 public static Buffer getReasonBuffer(int code)
80 {
81 Status status = code<__status.length?__status[code]:null;
82 if (status!=null)
83 return status._reason;
84 return null;
85 }
86
87
88
89 private static final byte[] LAST_CHUNK =
90 { (byte) '0', (byte) '\015', (byte) '\012', (byte) '\015', (byte) '\012'};
91 private static final byte[] CONTENT_LENGTH_0 = StringUtil.getBytes("Content-Length: 0\015\012");
92 private static final byte[] CONNECTION_KEEP_ALIVE = StringUtil.getBytes("Connection: keep-alive\015\012");
93 private static final byte[] CONNECTION_CLOSE = StringUtil.getBytes("Connection: close\015\012");
94 private static final byte[] CONNECTION_ = StringUtil.getBytes("Connection: ");
95 private static final byte[] CRLF = StringUtil.getBytes("\015\012");
96 private static final byte[] TRANSFER_ENCODING_CHUNKED = StringUtil.getBytes("Transfer-Encoding: chunked\015\012");
97 private static byte[] SERVER = StringUtil.getBytes("Server: Jetty(7.0.x)\015\012");
98
99
100 private static final int CHUNK_SPACE = 12;
101
102 public static void setServerVersion(String version)
103 {
104 SERVER=StringUtil.getBytes("Server: Jetty("+version+")\015\012");
105 }
106
107
108 private boolean _bypass = false;
109 private boolean _needCRLF = false;
110 private boolean _needEOC = false;
111 private boolean _bufferChunked = false;
112
113
114
115
116
117
118
119
120
121 public HttpGenerator(Buffers buffers, EndPoint io)
122 {
123 super(buffers,io);
124 }
125
126
127 @Override
128 public void reset()
129 {
130 if (_persistent!=null && !_persistent && _endp!=null && !_endp.isOutputShutdown())
131 {
132 try
133 {
134 _endp.shutdownOutput();
135 }
136 catch(IOException e)
137 {
138 LOG.ignore(e);
139 }
140 }
141 super.reset();
142 if (_buffer!=null)
143 _buffer.clear();
144 if (_header!=null)
145 _header.clear();
146 if (_content!=null)
147 _content=null;
148 _bypass = false;
149 _needCRLF = false;
150 _needEOC = false;
151 _bufferChunked=false;
152 _method=null;
153 _uri=null;
154 _noContent=false;
155 }
156
157
158
159
160
161
162
163
164
165
166
167
168 public void addContent(Buffer content, boolean last) throws IOException
169 {
170 if (_noContent)
171 throw new IllegalStateException("NO CONTENT");
172
173 if (_last || _state==STATE_END)
174 {
175 LOG.warn("Ignoring extra content {}",content);
176 content.clear();
177 return;
178 }
179 _last = last;
180
181
182 if (_content!=null && _content.length()>0 || _bufferChunked)
183 {
184 if (_endp.isOutputShutdown())
185 throw new EofException();
186 flushBuffer();
187 if (_content != null && _content.length()>0)
188 {
189 Buffer nc=_buffers.getBuffer(_content.length()+content.length());
190 nc.put(_content);
191 nc.put(content);
192 content=nc;
193 }
194 }
195
196 _content = content;
197 _contentWritten += content.length();
198
199
200 if (_head)
201 {
202 content.clear();
203 _content=null;
204 }
205 else if (_endp != null && (_buffer==null || _buffer.length()==0) && _content.length() > 0 && (_last || isCommitted() && _content.length()>1024))
206 {
207 _bypass = true;
208 }
209 else if (!_bufferChunked)
210 {
211
212 if (_buffer == null)
213 _buffer = _buffers.getBuffer();
214
215
216 int len=_buffer.put(_content);
217 _content.skip(len);
218 if (_content.length() == 0)
219 _content = null;
220 }
221 }
222
223
224
225
226
227
228
229 public void sendResponse(Buffer response) throws IOException
230 {
231 if (_noContent || _state!=STATE_HEADER || _content!=null && _content.length()>0 || _bufferChunked || _head )
232 throw new IllegalStateException();
233
234 _last = true;
235
236 _content = response;
237 _bypass = true;
238 _state = STATE_FLUSHING;
239
240
241 _contentLength =_contentWritten = response.length();
242
243 }
244
245
246
247
248
249
250
251
252
253 public boolean addContent(byte b) throws IOException
254 {
255 if (_noContent)
256 throw new IllegalStateException("NO CONTENT");
257
258 if (_last || _state==STATE_END)
259 {
260 LOG.warn("Ignoring extra content {}",Byte.valueOf(b));
261 return false;
262 }
263
264
265 if (_content != null && _content.length()>0 || _bufferChunked)
266 {
267 flushBuffer();
268 if (_content != null && _content.length()>0 || _bufferChunked)
269 throw new IllegalStateException("FULL");
270 }
271
272 _contentWritten++;
273
274
275 if (_head)
276 return false;
277
278
279 if (_buffer == null)
280 _buffer = _buffers.getBuffer();
281
282
283 _buffer.put(b);
284
285 return _buffer.space()<=(_contentLength == HttpTokens.CHUNKED_CONTENT?CHUNK_SPACE:0);
286 }
287
288
289
290
291
292
293
294 @Override
295 public int prepareUncheckedAddContent() throws IOException
296 {
297 if (_noContent)
298 return -1;
299
300 if (_last || _state==STATE_END)
301 return -1;
302
303
304 Buffer content = _content;
305 if (content != null && content.length()>0 || _bufferChunked)
306 {
307 flushBuffer();
308 if (content != null && content.length()>0 || _bufferChunked)
309 throw new IllegalStateException("FULL");
310 }
311
312
313 if (_buffer == null)
314 _buffer = _buffers.getBuffer();
315
316 _contentWritten-=_buffer.length();
317
318
319 if (_head)
320 return Integer.MAX_VALUE;
321
322 return _buffer.space()-(_contentLength == HttpTokens.CHUNKED_CONTENT?CHUNK_SPACE:0);
323 }
324
325
326 @Override
327 public boolean isBufferFull()
328 {
329
330 return super.isBufferFull() || _bufferChunked || _bypass || (_contentLength == HttpTokens.CHUNKED_CONTENT && _buffer != null && _buffer.space() < CHUNK_SPACE);
331 }
332
333
334 public void send1xx(int code) throws IOException
335 {
336 if (_state != STATE_HEADER)
337 return;
338
339 if (code<100||code>199)
340 throw new IllegalArgumentException("!1xx");
341 Status status=__status[code];
342 if (status==null)
343 throw new IllegalArgumentException(code+"?");
344
345
346 if (_header == null)
347 _header = _buffers.getHeader();
348
349 _header.put(status._responseLine);
350 _header.put(HttpTokens.CRLF);
351
352 try
353 {
354
355 while(_header.length()>0)
356 {
357 int len = _endp.flush(_header);
358 if (len<0)
359 throw new EofException();
360 if (len==0)
361 Thread.sleep(100);
362 }
363 }
364 catch(InterruptedException e)
365 {
366 LOG.debug(e);
367 throw new InterruptedIOException(e.toString());
368 }
369 }
370
371
372 @Override
373 public boolean isRequest()
374 {
375 return _method!=null;
376 }
377
378
379 @Override
380 public boolean isResponse()
381 {
382 return _method==null;
383 }
384
385
386 @Override
387 public void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException
388 {
389 if (_state != STATE_HEADER)
390 return;
391
392
393 if (isResponse() && _status==0)
394 throw new EofException();
395
396 if (_last && !allContentAdded)
397 throw new IllegalStateException("last?");
398 _last = _last | allContentAdded;
399
400
401 if (_header == null)
402 _header = _buffers.getHeader();
403
404 boolean has_server = false;
405
406 try
407 {
408 if (isRequest())
409 {
410 _persistent=true;
411
412 if (_version == HttpVersions.HTTP_0_9_ORDINAL)
413 {
414 _contentLength = HttpTokens.NO_CONTENT;
415 _header.put(_method);
416 _header.put((byte)' ');
417 _header.put(_uri.getBytes("UTF-8"));
418 _header.put(HttpTokens.CRLF);
419 _state = STATE_FLUSHING;
420 _noContent=true;
421 return;
422 }
423 else
424 {
425 _header.put(_method);
426 _header.put((byte)' ');
427 _header.put(_uri.getBytes("UTF-8"));
428 _header.put((byte)' ');
429 _header.put(_version==HttpVersions.HTTP_1_0_ORDINAL?HttpVersions.HTTP_1_0_BUFFER:HttpVersions.HTTP_1_1_BUFFER);
430 _header.put(HttpTokens.CRLF);
431 }
432 }
433 else
434 {
435
436 if (_version == HttpVersions.HTTP_0_9_ORDINAL)
437 {
438 _persistent = false;
439 _contentLength = HttpTokens.EOF_CONTENT;
440 _state = STATE_CONTENT;
441 return;
442 }
443 else
444 {
445 if (_persistent==null)
446 _persistent= (_version > HttpVersions.HTTP_1_0_ORDINAL);
447
448
449 Status status = _status<__status.length?__status[_status]:null;
450
451 if (status==null)
452 {
453 _header.put(HttpVersions.HTTP_1_1_BUFFER);
454 _header.put((byte) ' ');
455 _header.put((byte) ('0' + _status / 100));
456 _header.put((byte) ('0' + (_status % 100) / 10));
457 _header.put((byte) ('0' + (_status % 10)));
458 _header.put((byte) ' ');
459 if (_reason==null)
460 {
461 _header.put((byte) ('0' + _status / 100));
462 _header.put((byte) ('0' + (_status % 100) / 10));
463 _header.put((byte) ('0' + (_status % 10)));
464 }
465 else
466 _header.put(_reason);
467 _header.put(HttpTokens.CRLF);
468 }
469 else
470 {
471 if (_reason==null)
472 _header.put(status._responseLine);
473 else
474 {
475 _header.put(status._schemeCode);
476 _header.put(_reason);
477 _header.put(HttpTokens.CRLF);
478 }
479 }
480
481 if (_status<200 && _status>=100 )
482 {
483 _noContent=true;
484 _content=null;
485 if (_buffer!=null)
486 _buffer.clear();
487
488
489 if (_status!=101 )
490 {
491 _header.put(HttpTokens.CRLF);
492 _state = STATE_CONTENT;
493 return;
494 }
495 }
496 else if (_status==204 || _status==304)
497 {
498 _noContent=true;
499 _content=null;
500 if (_buffer!=null)
501 _buffer.clear();
502 }
503 }
504 }
505
506
507 if (_status>=200 && _date!=null)
508 {
509 _header.put(HttpHeaders.DATE_BUFFER);
510 _header.put((byte)':');
511 _header.put((byte)' ');
512 _header.put(_date);
513 _header.put(CRLF);
514 }
515
516
517 HttpFields.Field content_length = null;
518 HttpFields.Field transfer_encoding = null;
519 boolean keep_alive = false;
520 boolean close=false;
521 boolean content_type=false;
522 StringBuilder connection = null;
523
524 if (fields != null)
525 {
526 int s=fields.size();
527 for (int f=0;f<s;f++)
528 {
529 HttpFields.Field field = fields.getField(f);
530 if (field==null)
531 continue;
532
533 switch (field.getNameOrdinal())
534 {
535 case HttpHeaders.CONTENT_LENGTH_ORDINAL:
536 content_length = field;
537 _contentLength = field.getLongValue();
538
539 if (_contentLength < _contentWritten || _last && _contentLength != _contentWritten)
540 content_length = null;
541
542
543 field.putTo(_header);
544 break;
545
546 case HttpHeaders.CONTENT_TYPE_ORDINAL:
547 if (BufferUtil.isPrefix(MimeTypes.MULTIPART_BYTERANGES_BUFFER, field.getValueBuffer())) _contentLength = HttpTokens.SELF_DEFINING_CONTENT;
548
549
550 content_type=true;
551 field.putTo(_header);
552 break;
553
554 case HttpHeaders.TRANSFER_ENCODING_ORDINAL:
555 if (_version == HttpVersions.HTTP_1_1_ORDINAL)
556 transfer_encoding = field;
557
558 break;
559
560 case HttpHeaders.CONNECTION_ORDINAL:
561 if (isRequest())
562 field.putTo(_header);
563
564 int connection_value = field.getValueOrdinal();
565 switch (connection_value)
566 {
567 case -1:
568 {
569 String[] values = field.getValue().split(",");
570 for (int i=0;values!=null && i<values.length;i++)
571 {
572 CachedBuffer cb = HttpHeaderValues.CACHE.get(values[i].trim());
573
574 if (cb!=null)
575 {
576 switch(cb.getOrdinal())
577 {
578 case HttpHeaderValues.CLOSE_ORDINAL:
579 close=true;
580 if (isResponse())
581 _persistent=false;
582 keep_alive=false;
583 if (!_persistent && isResponse() && _contentLength == HttpTokens.UNKNOWN_CONTENT)
584 _contentLength = HttpTokens.EOF_CONTENT;
585 break;
586
587 case HttpHeaderValues.KEEP_ALIVE_ORDINAL:
588 if (_version == HttpVersions.HTTP_1_0_ORDINAL)
589 {
590 keep_alive = true;
591 if (isResponse())
592 _persistent = true;
593 }
594 break;
595
596 default:
597 if (connection==null)
598 connection=new StringBuilder();
599 else
600 connection.append(',');
601 connection.append(values[i]);
602 }
603 }
604 else
605 {
606 if (connection==null)
607 connection=new StringBuilder();
608 else
609 connection.append(',');
610 connection.append(values[i]);
611 }
612 }
613
614 break;
615 }
616 case HttpHeaderValues.UPGRADE_ORDINAL:
617 {
618
619 if (isResponse())
620 {
621 field.putTo(_header);
622 continue;
623 }
624 }
625 case HttpHeaderValues.CLOSE_ORDINAL:
626 {
627 close=true;
628 if (isResponse())
629 _persistent=false;
630 if (!_persistent && isResponse() && _contentLength == HttpTokens.UNKNOWN_CONTENT)
631 _contentLength = HttpTokens.EOF_CONTENT;
632 break;
633 }
634 case HttpHeaderValues.KEEP_ALIVE_ORDINAL:
635 {
636 if (_version == HttpVersions.HTTP_1_0_ORDINAL)
637 {
638 keep_alive = true;
639 if (isResponse())
640 _persistent=true;
641 }
642 break;
643 }
644 default:
645 {
646 if (connection==null)
647 connection=new StringBuilder();
648 else
649 connection.append(',');
650 connection.append(field.getValue());
651 }
652 }
653
654
655 break;
656
657 case HttpHeaders.SERVER_ORDINAL:
658 if (getSendServerVersion())
659 {
660 has_server=true;
661 field.putTo(_header);
662 }
663 break;
664
665 default:
666
667 field.putTo(_header);
668 }
669 }
670 }
671
672
673
674
675
676
677
678
679
680
681 switch ((int) _contentLength)
682 {
683 case HttpTokens.UNKNOWN_CONTENT:
684
685
686
687
688 if (_contentWritten == 0 && isResponse() && (_status < 200 || _status == 204 || _status == 304))
689 _contentLength = HttpTokens.NO_CONTENT;
690 else if (_last)
691 {
692
693 _contentLength = _contentWritten;
694 if (content_length == null && (isResponse() || _contentLength>0 || content_type ) && !_noContent)
695 {
696
697 _header.put(HttpHeaders.CONTENT_LENGTH_BUFFER);
698 _header.put(HttpTokens.COLON);
699 _header.put((byte) ' ');
700 BufferUtil.putDecLong(_header, _contentLength);
701 _header.put(HttpTokens.CRLF);
702 }
703 }
704 else
705 {
706
707 _contentLength = (!_persistent || _version < HttpVersions.HTTP_1_1_ORDINAL ) ? HttpTokens.EOF_CONTENT : HttpTokens.CHUNKED_CONTENT;
708 if (isRequest() && _contentLength==HttpTokens.EOF_CONTENT)
709 {
710 _contentLength=HttpTokens.NO_CONTENT;
711 _noContent=true;
712 }
713 }
714 break;
715
716 case HttpTokens.NO_CONTENT:
717 if (content_length == null && isResponse() && _status >= 200 && _status != 204 && _status != 304)
718 _header.put(CONTENT_LENGTH_0);
719 break;
720
721 case HttpTokens.EOF_CONTENT:
722 _persistent = isRequest();
723 break;
724
725 case HttpTokens.CHUNKED_CONTENT:
726 break;
727
728 default:
729
730 break;
731 }
732
733
734 if (_contentLength == HttpTokens.CHUNKED_CONTENT)
735 {
736
737 if (transfer_encoding != null && HttpHeaderValues.CHUNKED_ORDINAL != transfer_encoding.getValueOrdinal())
738 {
739 String c = transfer_encoding.getValue();
740 if (c.endsWith(HttpHeaderValues.CHUNKED))
741 transfer_encoding.putTo(_header);
742 else
743 throw new IllegalArgumentException("BAD TE");
744 }
745 else
746 _header.put(TRANSFER_ENCODING_CHUNKED);
747 }
748
749
750 if (_contentLength==HttpTokens.EOF_CONTENT)
751 {
752 keep_alive=false;
753 _persistent=false;
754 }
755
756 if (isResponse())
757 {
758 if (!_persistent && (close || _version > HttpVersions.HTTP_1_0_ORDINAL))
759 {
760 _header.put(CONNECTION_CLOSE);
761 if (connection!=null)
762 {
763 _header.setPutIndex(_header.putIndex()-2);
764 _header.put((byte)',');
765 _header.put(connection.toString().getBytes());
766 _header.put(CRLF);
767 }
768 }
769 else if (keep_alive)
770 {
771 _header.put(CONNECTION_KEEP_ALIVE);
772 if (connection!=null)
773 {
774 _header.setPutIndex(_header.putIndex()-2);
775 _header.put((byte)',');
776 _header.put(connection.toString().getBytes());
777 _header.put(CRLF);
778 }
779 }
780 else if (connection!=null)
781 {
782 _header.put(CONNECTION_);
783 _header.put(connection.toString().getBytes());
784 _header.put(CRLF);
785 }
786 }
787
788 if (!has_server && _status>199 && getSendServerVersion())
789 _header.put(SERVER);
790
791
792 _header.put(HttpTokens.CRLF);
793 _state = STATE_CONTENT;
794
795 }
796 catch(ArrayIndexOutOfBoundsException e)
797 {
798 throw new RuntimeException("Header>"+_header.capacity(),e);
799 }
800 }
801
802
803
804
805
806
807
808 @Override
809 public void complete() throws IOException
810 {
811 if (_state == STATE_END)
812 return;
813
814 super.complete();
815
816 if (_state < STATE_FLUSHING)
817 {
818 _state = STATE_FLUSHING;
819 if (_contentLength == HttpTokens.CHUNKED_CONTENT)
820 _needEOC = true;
821 }
822
823 flushBuffer();
824 }
825
826
827 @Override
828 public int flushBuffer() throws IOException
829 {
830 try
831 {
832
833 if (_state == STATE_HEADER)
834 throw new IllegalStateException("State==HEADER");
835
836 prepareBuffers();
837
838 if (_endp == null)
839 {
840 if (_needCRLF && _buffer!=null)
841 _buffer.put(HttpTokens.CRLF);
842 if (_needEOC && _buffer!=null && !_head)
843 _buffer.put(LAST_CHUNK);
844 _needCRLF=false;
845 _needEOC=false;
846 return 0;
847 }
848
849 int total= 0;
850
851 int len = -1;
852 int to_flush = flushMask();
853 int last_flush;
854
855 do
856 {
857 last_flush=to_flush;
858 switch (to_flush)
859 {
860 case 7:
861 throw new IllegalStateException();
862 case 6:
863 len = _endp.flush(_header, _buffer, null);
864 break;
865 case 5:
866 len = _endp.flush(_header, _content, null);
867 break;
868 case 4:
869 len = _endp.flush(_header);
870 break;
871 case 3:
872 len = _endp.flush(_buffer, _content, null);
873 break;
874 case 2:
875 len = _endp.flush(_buffer);
876 break;
877 case 1:
878 len = _endp.flush(_content);
879 break;
880 case 0:
881 {
882 len=0;
883
884 if (_header != null)
885 _header.clear();
886
887 _bypass = false;
888 _bufferChunked = false;
889
890 if (_buffer != null)
891 {
892 _buffer.clear();
893 if (_contentLength == HttpTokens.CHUNKED_CONTENT)
894 {
895
896 _buffer.setPutIndex(CHUNK_SPACE);
897 _buffer.setGetIndex(CHUNK_SPACE);
898
899
900
901 if (_content != null && _content.length() < _buffer.space() && _state != STATE_FLUSHING)
902 {
903 _buffer.put(_content);
904 _content.clear();
905 _content=null;
906 }
907 }
908 }
909
910
911 if (!_needCRLF && !_needEOC && (_content==null || _content.length()==0))
912 {
913 if (_state == STATE_FLUSHING)
914 _state = STATE_END;
915
916 if (_state==STATE_END && _persistent != null && !_persistent && _status!=100 && _method==null)
917 _endp.shutdownOutput();
918 }
919 else
920
921 prepareBuffers();
922 }
923
924 }
925
926 if (len > 0)
927 total+=len;
928
929 to_flush = flushMask();
930 }
931
932 while (len>0 || (to_flush!=0 && last_flush==0));
933
934 return total;
935 }
936 catch (IOException e)
937 {
938 LOG.ignore(e);
939 throw (e instanceof EofException) ? e:new EofException(e);
940 }
941 }
942
943
944 private int flushMask()
945 {
946 return ((_header != null && _header.length() > 0)?4:0)
947 | ((_buffer != null && _buffer.length() > 0)?2:0)
948 | ((_bypass && _content != null && _content.length() > 0)?1:0);
949 }
950
951
952 private void prepareBuffers()
953 {
954
955 if (!_bufferChunked)
956 {
957
958 if (!_bypass && _content != null && _content.length() > 0 && _buffer != null && _buffer.space() > 0)
959 {
960 int len = _buffer.put(_content);
961 _content.skip(len);
962 if (_content.length() == 0)
963 _content = null;
964 }
965
966
967 if (_contentLength == HttpTokens.CHUNKED_CONTENT)
968 {
969 if (_bypass && (_buffer==null||_buffer.length()==0) && _content!=null)
970 {
971
972 int size = _content.length();
973 _bufferChunked = true;
974
975 if (_header == null)
976 _header = _buffers.getHeader();
977
978
979 if (_needCRLF)
980 {
981 if (_header.length() > 0) throw new IllegalStateException("EOC");
982 _header.put(HttpTokens.CRLF);
983 _needCRLF = false;
984 }
985
986 BufferUtil.putHexInt(_header, size);
987 _header.put(HttpTokens.CRLF);
988
989
990 _needCRLF=true;
991 }
992 else if (_buffer!=null)
993 {
994 int size = _buffer.length();
995 if (size > 0)
996 {
997
998 _bufferChunked = true;
999
1000
1001
1002 if (_buffer.getIndex() == CHUNK_SPACE)
1003 {
1004
1005 _buffer.poke(_buffer.getIndex() - 2, HttpTokens.CRLF, 0, 2);
1006 _buffer.setGetIndex(_buffer.getIndex() - 2);
1007 BufferUtil.prependHexInt(_buffer, size);
1008
1009 if (_needCRLF)
1010 {
1011 _buffer.poke(_buffer.getIndex() - 2, HttpTokens.CRLF, 0, 2);
1012 _buffer.setGetIndex(_buffer.getIndex() - 2);
1013 _needCRLF = false;
1014 }
1015 }
1016 else
1017 {
1018
1019 if (_header == null)
1020 _header = _buffers.getHeader();
1021
1022 if (_needCRLF)
1023 {
1024 if (_header.length() > 0) throw new IllegalStateException("EOC");
1025 _header.put(HttpTokens.CRLF);
1026 _needCRLF = false;
1027 }
1028 BufferUtil.putHexInt(_header, size);
1029 _header.put(HttpTokens.CRLF);
1030 }
1031
1032
1033 if (_buffer.space() >= 2)
1034 _buffer.put(HttpTokens.CRLF);
1035 else
1036 _needCRLF = true;
1037 }
1038 }
1039
1040
1041 if (_needEOC && (_content == null || _content.length() == 0))
1042 {
1043 if (_needCRLF)
1044 {
1045 if (_buffer == null && _header.space() >= 2)
1046 {
1047 _header.put(HttpTokens.CRLF);
1048 _needCRLF = false;
1049 }
1050 else if (_buffer!=null && _buffer.space() >= 2)
1051 {
1052 _buffer.put(HttpTokens.CRLF);
1053 _needCRLF = false;
1054 }
1055 }
1056
1057 if (!_needCRLF && _needEOC)
1058 {
1059 if (_buffer == null && _header.space() >= LAST_CHUNK.length)
1060 {
1061 if (!_head)
1062 {
1063 _header.put(LAST_CHUNK);
1064 _bufferChunked=true;
1065 }
1066 _needEOC = false;
1067 }
1068 else if (_buffer!=null && _buffer.space() >= LAST_CHUNK.length)
1069 {
1070 if (!_head)
1071 {
1072 _buffer.put(LAST_CHUNK);
1073 _bufferChunked=true;
1074 }
1075 _needEOC = false;
1076 }
1077 }
1078 }
1079 }
1080 }
1081
1082 if (_content != null && _content.length() == 0)
1083 _content = null;
1084
1085 }
1086
1087 public int getBytesBuffered()
1088 {
1089 return(_header==null?0:_header.length())+
1090 (_buffer==null?0:_buffer.length())+
1091 (_content==null?0:_content.length());
1092 }
1093
1094 public boolean isEmpty()
1095 {
1096 return (_header==null||_header.length()==0) &&
1097 (_buffer==null||_buffer.length()==0) &&
1098 (_content==null||_content.length()==0);
1099 }
1100
1101 @Override
1102 public String toString()
1103 {
1104 return String.format("%s{s=%d,h=%d,b=%d,c=%d}",
1105 getClass().getSimpleName(),
1106 _state,
1107 _header == null ? -1 : _header.length(),
1108 _buffer == null ? -1 : _buffer.length(),
1109 _content == null ? -1 : _content.length());
1110 }
1111 }