1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.mortbay.jetty;
17
18 import java.io.IOException;
19 import java.io.OutputStreamWriter;
20 import java.io.Writer;
21 import java.lang.reflect.Field;
22 import java.lang.reflect.Modifier;
23
24 import javax.servlet.ServletOutputStream;
25 import javax.servlet.http.HttpServletResponse;
26
27 import org.mortbay.io.Buffer;
28 import org.mortbay.io.Buffers;
29 import org.mortbay.io.ByteArrayBuffer;
30 import org.mortbay.io.EndPoint;
31 import org.mortbay.io.View;
32 import org.mortbay.log.Log;
33 import org.mortbay.util.ByteArrayOutputStream2;
34 import org.mortbay.util.StringUtil;
35 import org.mortbay.util.TypeUtil;
36
37
38
39
40
41
42
43
44
45
46
47
48 public abstract class AbstractGenerator implements Generator
49 {
50
51 public final static int STATE_HEADER = 0;
52 public final static int STATE_CONTENT = 2;
53 public final static int STATE_FLUSHING = 3;
54 public final static int STATE_END = 4;
55
56 private static final byte[] NO_BYTES = {};
57 private static int MAX_OUTPUT_CHARS = 512;
58
59 private static Buffer[] __reasons = new Buffer[505];
60 static
61 {
62 Field[] fields = HttpServletResponse.class.getDeclaredFields();
63 for (int i=0;i<fields.length;i++)
64 {
65 if ((fields[i].getModifiers()&Modifier.STATIC)!=0 &&
66 fields[i].getName().startsWith("SC_"))
67 {
68 try
69 {
70 int code = fields[i].getInt(null);
71 if (code<__reasons.length)
72 __reasons[code]=new ByteArrayBuffer(fields[i].getName().substring(3));
73 }
74 catch(IllegalAccessException e)
75 {}
76 }
77 }
78 }
79
80 protected static Buffer getReasonBuffer(int code)
81 {
82 Buffer reason=(code<__reasons.length)?__reasons[code]:null;
83 return reason==null?null:reason;
84 }
85
86 public static String getReason(int code)
87 {
88 Buffer reason=(code<__reasons.length)?__reasons[code]:null;
89 return reason==null?TypeUtil.toString(code):reason.toString();
90 }
91
92
93 protected int _state = STATE_HEADER;
94
95 protected int _status = 0;
96 protected int _version = HttpVersions.HTTP_1_1_ORDINAL;
97 protected Buffer _reason;
98 protected Buffer _method;
99 protected String _uri;
100
101 protected long _contentWritten = 0;
102 protected long _contentLength = HttpTokens.UNKNOWN_CONTENT;
103 protected boolean _last = false;
104 protected boolean _head = false;
105 protected boolean _noContent = false;
106 protected boolean _close = false;
107
108 protected Buffers _buffers;
109 protected EndPoint _endp;
110
111 protected int _headerBufferSize;
112 protected int _contentBufferSize;
113
114 protected Buffer _header;
115 protected Buffer _buffer;
116 protected Buffer _content;
117
118 private boolean _sendServerVersion;
119
120
121
122
123
124
125
126
127
128
129 public AbstractGenerator(Buffers buffers, EndPoint io, int headerBufferSize, int contentBufferSize)
130 {
131 this._buffers = buffers;
132 this._endp = io;
133 _headerBufferSize=headerBufferSize;
134 _contentBufferSize=contentBufferSize;
135 }
136
137
138 public void reset(boolean returnBuffers)
139 {
140 _state = STATE_HEADER;
141 _status = 0;
142 _version = HttpVersions.HTTP_1_1_ORDINAL;
143 _reason = null;
144 _last = false;
145 _head = false;
146 _noContent=false;
147 _close = false;
148 _contentWritten = 0;
149 _contentLength = HttpTokens.UNKNOWN_CONTENT;
150
151 synchronized(this)
152 {
153 if (returnBuffers)
154 {
155 if (_header != null)
156 _buffers.returnBuffer(_header);
157 _header = null;
158 if (_buffer != null)
159 _buffers.returnBuffer(_buffer);
160 _buffer = null;
161 }
162 else
163 {
164 if (_header != null)
165 _header.clear();
166
167 if (_buffer != null)
168 {
169 _buffers.returnBuffer(_buffer);
170 _buffer = null;
171 }
172 }
173 }
174 _content = null;
175 _method=null;
176 }
177
178
179 public void resetBuffer()
180 {
181 if(_state>=STATE_FLUSHING)
182 throw new IllegalStateException("Flushed");
183
184 _last = false;
185 _close = false;
186 _contentWritten = 0;
187 _contentLength = HttpTokens.UNKNOWN_CONTENT;
188 _content=null;
189 if (_buffer!=null)
190 _buffer.clear();
191 }
192
193
194
195
196
197 public int getContentBufferSize()
198 {
199 return _contentBufferSize;
200 }
201
202
203
204
205
206 public void increaseContentBufferSize(int contentBufferSize)
207 {
208 if (contentBufferSize > _contentBufferSize)
209 {
210 _contentBufferSize = contentBufferSize;
211 if (_buffer != null)
212 {
213 Buffer nb = _buffers.getBuffer(_contentBufferSize);
214 nb.put(_buffer);
215 _buffers.returnBuffer(_buffer);
216 _buffer = nb;
217 }
218 }
219 }
220
221
222 public Buffer getUncheckedBuffer()
223 {
224 return _buffer;
225 }
226
227
228 public boolean getSendServerVersion ()
229 {
230 return _sendServerVersion;
231 }
232
233
234 public void setSendServerVersion (boolean sendServerVersion)
235 {
236 _sendServerVersion = sendServerVersion;
237 }
238
239
240 public int getState()
241 {
242 return _state;
243 }
244
245
246 public boolean isState(int state)
247 {
248 return _state == state;
249 }
250
251
252 public boolean isComplete()
253 {
254 return _state == STATE_END;
255 }
256
257
258 public boolean isIdle()
259 {
260 return _state == STATE_HEADER && _method==null && _status==0;
261 }
262
263
264 public boolean isCommitted()
265 {
266 return _state != STATE_HEADER;
267 }
268
269
270
271
272
273 public boolean isHead()
274 {
275 return _head;
276 }
277
278
279 public void setContentLength(long value)
280 {
281 if (value<0)
282 _contentLength=HttpTokens.UNKNOWN_CONTENT;
283 else
284 _contentLength=value;
285 }
286
287
288
289
290
291 public void setHead(boolean head)
292 {
293 _head = head;
294 }
295
296
297
298
299
300
301 public boolean isPersistent()
302 {
303 return !_close;
304 }
305
306
307 public void setPersistent(boolean persistent)
308 {
309 _close=!persistent;
310 }
311
312
313
314
315
316
317 public void setVersion(int version)
318 {
319 if (_state != STATE_HEADER) throw new IllegalStateException("STATE!=START");
320 _version = version;
321 if (_version==HttpVersions.HTTP_0_9_ORDINAL && _method!=null)
322 _noContent=true;
323 }
324
325
326 public int getVersion()
327 {
328 return _version;
329 }
330
331
332
333
334 public void setRequest(String method, String uri)
335 {
336 if (method==null || HttpMethods.GET.equals(method) )
337 _method=HttpMethods.GET_BUFFER;
338 else
339 _method=HttpMethods.CACHE.lookup(method);
340 _uri=uri;
341 if (_version==HttpVersions.HTTP_0_9_ORDINAL)
342 _noContent=true;
343 }
344
345
346
347
348
349
350 public void setResponse(int status, String reason)
351 {
352 if (_state != STATE_HEADER) throw new IllegalStateException("STATE!=START");
353
354 _status = status;
355 if (reason!=null)
356 {
357 int len=reason.length();
358 if (len>_headerBufferSize/2)
359 len=_headerBufferSize/2;
360 _reason=new ByteArrayBuffer(len);
361 for (int i=0;i<len;i++)
362 {
363 char ch = reason.charAt(i);
364 if (ch!='\r'&&ch!='\n')
365 _reason.put((byte)ch);
366 else
367 _reason.put((byte)' ');
368 }
369 }
370 }
371
372
373
374
375
376
377
378 protected abstract int prepareUncheckedAddContent() throws IOException;
379
380
381 void uncheckedAddContent(int b)
382 {
383 _buffer.put((byte)b);
384 }
385
386
387 void completeUncheckedAddContent()
388 {
389 if (_noContent)
390 {
391 if(_buffer!=null)
392 _buffer.clear();
393 return;
394 }
395 else
396 {
397 _contentWritten+=_buffer.length();
398 if (_head)
399 _buffer.clear();
400 }
401 }
402
403
404 public boolean isBufferFull()
405 {
406 if (_buffer != null && _buffer.space()==0)
407 {
408 if (_buffer.length()==0 && !_buffer.isImmutable())
409 _buffer.compact();
410 return _buffer.space()==0;
411 }
412
413 return _content!=null && _content.length()>0;
414 }
415
416
417 public boolean isContentWritten()
418 {
419 return _contentLength>=0 && _contentWritten>=_contentLength;
420 }
421
422
423 public abstract void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException;
424
425
426
427
428
429
430
431 public void complete() throws IOException
432 {
433 if (_state == STATE_HEADER)
434 {
435 throw new IllegalStateException("State==HEADER");
436 }
437
438 if (_contentLength >= 0 && _contentLength != _contentWritten && !_head)
439 {
440 if (Log.isDebugEnabled())
441 Log.debug("ContentLength written=="+_contentWritten+" != contentLength=="+_contentLength);
442 _close = true;
443 }
444 }
445
446
447 public abstract long flush() throws IOException;
448
449
450
451
452
453
454
455
456
457
458
459
460
461 public void sendError(int code, String reason, String content, boolean close) throws IOException
462 {
463 if (close)
464 _close = close;
465 if (!isCommitted())
466 {
467 setResponse(code, reason);
468 completeHeader(null, false);
469 if (content != null)
470 addContent(new View(new ByteArrayBuffer(content)), Generator.LAST);
471 complete();
472 }
473 }
474
475
476
477
478
479 public long getContentWritten()
480 {
481 return _contentWritten;
482 }
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498 public static class Output extends ServletOutputStream
499 {
500 protected AbstractGenerator _generator;
501 protected long _maxIdleTime;
502 protected ByteArrayBuffer _buf = new ByteArrayBuffer(NO_BYTES);
503 protected boolean _closed;
504
505
506 String _characterEncoding;
507 Writer _converter;
508 char[] _chars;
509 ByteArrayOutputStream2 _bytes;
510
511
512
513 public Output(AbstractGenerator generator, long maxIdleTime)
514 {
515 _generator=generator;
516 _maxIdleTime=maxIdleTime;
517 }
518
519
520
521
522
523 public void close() throws IOException
524 {
525 _closed=true;
526 }
527
528
529 void blockForOutput() throws IOException
530 {
531 if (_generator._endp.isBlocking())
532 {
533 try
534 {
535 flush();
536 }
537 catch(IOException e)
538 {
539 _generator._endp.close();
540 throw e;
541 }
542 }
543 else
544 {
545 if (!_generator._endp.blockWritable(_maxIdleTime))
546 {
547 _generator._endp.close();
548 throw new EofException("timeout");
549 }
550
551 _generator.flush();
552 }
553 }
554
555
556 void reopen()
557 {
558 _closed=false;
559 }
560
561
562 public void flush() throws IOException
563 {
564
565 Buffer content = _generator._content;
566 Buffer buffer = _generator._buffer;
567 if (content!=null && content.length()>0 || buffer!=null && buffer.length()>0 || _generator.isBufferFull())
568 {
569 _generator.flush();
570
571 while ((content!=null && content.length()>0 ||buffer!=null && buffer.length()>0) && _generator._endp.isOpen())
572 blockForOutput();
573 }
574 }
575
576
577 public void write(byte[] b, int off, int len) throws IOException
578 {
579 _buf.wrap(b, off, len);
580 write(_buf);
581 _buf.wrap(NO_BYTES);
582 }
583
584
585
586
587
588 public void write(byte[] b) throws IOException
589 {
590 _buf.wrap(b);
591 write(_buf);
592 _buf.wrap(NO_BYTES);
593 }
594
595
596
597
598
599 public void write(int b) throws IOException
600 {
601 if (_closed)
602 throw new IOException("Closed");
603 if (!_generator._endp.isOpen())
604 throw new EofException();
605
606
607 while (_generator.isBufferFull())
608 {
609 blockForOutput();
610 if (_closed)
611 throw new IOException("Closed");
612 if (!_generator._endp.isOpen())
613 throw new EofException();
614 }
615
616
617 if (_generator.addContent((byte)b))
618
619 flush();
620
621 if (_generator.isContentWritten())
622 {
623 flush();
624 close();
625 }
626 }
627
628
629 private void write(Buffer buffer) throws IOException
630 {
631 if (_closed)
632 throw new IOException("Closed");
633 if (!_generator._endp.isOpen())
634 throw new EofException();
635
636
637 while (_generator.isBufferFull())
638 {
639 blockForOutput();
640 if (_closed)
641 throw new IOException("Closed");
642 if (!_generator._endp.isOpen())
643 throw new EofException();
644 }
645
646
647 _generator.addContent(buffer, Generator.MORE);
648
649
650 if (_generator.isBufferFull())
651 flush();
652
653 if (_generator.isContentWritten())
654 {
655 flush();
656 close();
657 }
658
659
660 while (buffer.length() > 0 && _generator._endp.isOpen())
661 blockForOutput();
662 }
663
664
665
666
667
668 public void print(String s) throws IOException
669 {
670 write(s.getBytes());
671 }
672 }
673
674
675
676
677
678
679
680
681
682
683
684
685 public static class OutputWriter extends Writer
686 {
687 private static final int WRITE_CONV = 0;
688 private static final int WRITE_ISO1 = 1;
689 private static final int WRITE_UTF8 = 2;
690
691 Output _out;
692 AbstractGenerator _generator;
693 int _writeMode;
694 int _surrogate;
695
696
697 public OutputWriter(Output out)
698 {
699 _out=out;
700 _generator=_out._generator;
701
702 }
703
704
705 public void setCharacterEncoding(String encoding)
706 {
707 if (encoding == null || StringUtil.__ISO_8859_1.equalsIgnoreCase(encoding))
708 {
709 _writeMode = WRITE_ISO1;
710 }
711 else if (StringUtil.__UTF8.equalsIgnoreCase(encoding))
712 {
713 _writeMode = WRITE_UTF8;
714 }
715 else
716 {
717 _writeMode = WRITE_CONV;
718 if (_out._characterEncoding == null || !_out._characterEncoding.equalsIgnoreCase(encoding))
719 _out._converter = null;
720 }
721
722 _out._characterEncoding = encoding;
723 if (_out._bytes==null)
724 _out._bytes = new ByteArrayOutputStream2(MAX_OUTPUT_CHARS);
725 }
726
727
728 public void close() throws IOException
729 {
730 _out.close();
731 }
732
733
734 public void flush() throws IOException
735 {
736 _out.flush();
737 }
738
739
740 public void write (String s,int offset, int length) throws IOException
741 {
742 while (length > MAX_OUTPUT_CHARS)
743 {
744 write(s, offset, MAX_OUTPUT_CHARS);
745 offset += MAX_OUTPUT_CHARS;
746 length -= MAX_OUTPUT_CHARS;
747 }
748
749 if (_out._chars==null)
750 {
751 _out._chars = new char[MAX_OUTPUT_CHARS];
752 }
753 char[] chars = _out._chars;
754 s.getChars(offset, offset + length, chars, 0);
755 write(chars, 0, length);
756 }
757
758
759 public void write (char[] s,int offset, int length) throws IOException
760 {
761 Output out = _out;
762
763 while (length > 0)
764 {
765 out._bytes.reset();
766 int chars = length>MAX_OUTPUT_CHARS?MAX_OUTPUT_CHARS:length;
767
768 switch (_writeMode)
769 {
770 case WRITE_CONV:
771 {
772 Writer converter=getConverter();
773 converter.write(s, offset, chars);
774 converter.flush();
775 }
776 break;
777
778 case WRITE_ISO1:
779 {
780 byte[] buffer=out._bytes.getBuf();
781 int bytes=out._bytes.getCount();
782
783 if (chars>buffer.length-bytes)
784 chars=buffer.length-bytes;
785
786 for (int i = 0; i < chars; i++)
787 {
788 int c = s[offset+i];
789 buffer[bytes++]=(byte)(c<256?c:'?');
790 }
791 if (bytes>=0)
792 out._bytes.setCount(bytes);
793
794 break;
795 }
796
797 case WRITE_UTF8:
798 {
799 byte[] buffer=out._bytes.getBuf();
800 int bytes=out._bytes.getCount();
801
802 if (bytes+chars>buffer.length)
803 chars=buffer.length-bytes;
804
805 for (int i = 0; i < chars; i++)
806 {
807 int code = s[offset+i];
808
809 if ((code & 0xffffff80) == 0)
810 {
811
812 if (bytes+1>buffer.length)
813 {
814 chars=i;
815 break;
816 }
817 buffer[bytes++]=(byte)(code);
818 }
819 else
820 {
821 if((code&0xfffff800)==0)
822 {
823
824 if (bytes+2>buffer.length)
825 {
826 chars=i;
827 break;
828 }
829 buffer[bytes++]=(byte)(0xc0|(code>>6));
830 buffer[bytes++]=(byte)(0x80|(code&0x3f));
831 }
832 else if((code&0xffff0000)==0)
833 {
834
835 if (bytes+3>buffer.length)
836 {
837 chars=i;
838 break;
839 }
840 buffer[bytes++]=(byte)(0xe0|(code>>12));
841 buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f));
842 buffer[bytes++]=(byte)(0x80|(code&0x3f));
843 }
844 else if((code&0xff200000)==0)
845 {
846
847 if (bytes+4>buffer.length)
848 {
849 chars=i;
850 break;
851 }
852 buffer[bytes++]=(byte)(0xf0|(code>>18));
853 buffer[bytes++]=(byte)(0x80|((code>>12)&0x3f));
854 buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f));
855 buffer[bytes++]=(byte)(0x80|(code&0x3f));
856 }
857 else if((code&0xf4000000)==0)
858 {
859
860 if (bytes+5>buffer.length)
861 {
862 chars=i;
863 break;
864 }
865 buffer[bytes++]=(byte)(0xf8|(code>>24));
866 buffer[bytes++]=(byte)(0x80|((code>>18)&0x3f));
867 buffer[bytes++]=(byte)(0x80|((code>>12)&0x3f));
868 buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f));
869 buffer[bytes++]=(byte)(0x80|(code&0x3f));
870 }
871 else if((code&0x80000000)==0)
872 {
873
874 if (bytes+6>buffer.length)
875 {
876 chars=i;
877 break;
878 }
879 buffer[bytes++]=(byte)(0xfc|(code>>30));
880 buffer[bytes++]=(byte)(0x80|((code>>24)&0x3f));
881 buffer[bytes++]=(byte)(0x80|((code>>18)&0x3f));
882 buffer[bytes++]=(byte)(0x80|((code>>12)&0x3f));
883 buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f));
884 buffer[bytes++]=(byte)(0x80|(code&0x3f));
885 }
886 else
887 {
888 buffer[bytes++]=(byte)('?');
889 }
890 if (bytes==buffer.length)
891 {
892 chars=i+1;
893 break;
894 }
895 }
896 }
897 out._bytes.setCount(bytes);
898 break;
899 }
900 default:
901 throw new IllegalStateException();
902 }
903
904 out._bytes.writeTo(out);
905 length-=chars;
906 offset+=chars;
907 }
908 }
909
910
911 private Writer getConverter() throws IOException
912 {
913 if (_out._converter == null)
914 _out._converter = new OutputStreamWriter(_out._bytes, _out._characterEncoding);
915 return _out._converter;
916 }
917 }
918 }