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 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
407 boolean full =
408 (_buffer !=null && _buffer.length()>0 && _buffer.space()==0) ||
409 (_content!=null && _content.length()>0);
410
411 return full;
412 }
413
414
415 public boolean isContentWritten()
416 {
417 return _contentLength>=0 && _contentWritten>=_contentLength;
418 }
419
420
421 public abstract void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException;
422
423
424
425
426
427
428
429 public void complete() throws IOException
430 {
431 if (_state == STATE_HEADER)
432 {
433 throw new IllegalStateException("State==HEADER");
434 }
435
436 if (_contentLength >= 0 && _contentLength != _contentWritten && !_head)
437 {
438 if (Log.isDebugEnabled())
439 Log.debug("ContentLength written=="+_contentWritten+" != contentLength=="+_contentLength);
440 _close = true;
441 }
442 }
443
444
445 public abstract long flush() throws IOException;
446
447
448
449
450
451
452
453
454
455
456
457
458
459 public void sendError(int code, String reason, String content, boolean close) throws IOException
460 {
461 if (!isCommitted())
462 {
463 setResponse(code, reason);
464 _close = close;
465 completeHeader(null, false);
466 if (content != null)
467 addContent(new View(new ByteArrayBuffer(content)), Generator.LAST);
468 complete();
469 }
470 }
471
472
473
474
475
476 public long getContentWritten()
477 {
478 return _contentWritten;
479 }
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495 public static class Output extends ServletOutputStream
496 {
497 protected AbstractGenerator _generator;
498 protected long _maxIdleTime;
499 protected ByteArrayBuffer _buf = new ByteArrayBuffer(NO_BYTES);
500 protected boolean _closed;
501
502
503 String _characterEncoding;
504 Writer _converter;
505 char[] _chars;
506 ByteArrayOutputStream2 _bytes;
507
508
509
510 public Output(AbstractGenerator generator, long maxIdleTime)
511 {
512 _generator=generator;
513 _maxIdleTime=maxIdleTime;
514 }
515
516
517
518
519
520 public void close() throws IOException
521 {
522 _closed=true;
523 }
524
525
526 void blockForOutput() throws IOException
527 {
528 if (_generator._endp.isBlocking())
529 {
530 try
531 {
532 flush();
533 }
534 catch(IOException e)
535 {
536 _generator._endp.close();
537 throw e;
538 }
539 }
540 else
541 {
542 if (!_generator._endp.blockWritable(_maxIdleTime))
543 {
544 _generator._endp.close();
545 throw new EofException("timeout");
546 }
547
548 _generator.flush();
549 }
550 }
551
552
553 void reopen()
554 {
555 _closed=false;
556 }
557
558
559 public void flush() throws IOException
560 {
561
562 Buffer content = _generator._content;
563 Buffer buffer = _generator._buffer;
564 if (content!=null && content.length()>0 ||buffer!=null && buffer.length()>0 || _generator.isBufferFull())
565 {
566 _generator.flush();
567
568 while ((content!=null && content.length()>0 ||buffer!=null && buffer.length()>0) && _generator._endp.isOpen())
569 blockForOutput();
570 }
571 }
572
573
574 public void write(byte[] b, int off, int len) throws IOException
575 {
576 _buf.wrap(b, off, len);
577 write(_buf);
578 }
579
580
581
582
583
584 public void write(byte[] b) throws IOException
585 {
586 _buf.wrap(b);
587 write(_buf);
588 }
589
590
591
592
593
594 public void write(int b) throws IOException
595 {
596 if (_closed)
597 throw new IOException("Closed");
598 if (!_generator._endp.isOpen())
599 throw new EofException();
600
601
602 while (_generator.isBufferFull())
603 {
604 blockForOutput();
605 if (_closed)
606 throw new IOException("Closed");
607 if (!_generator._endp.isOpen())
608 throw new EofException();
609 }
610
611
612 if (_generator.addContent((byte)b))
613
614 flush();
615
616 if (_generator.isContentWritten())
617 {
618 flush();
619 close();
620 }
621 }
622
623
624 private void write(Buffer buffer) throws IOException
625 {
626 if (_closed)
627 throw new IOException("Closed");
628 if (!_generator._endp.isOpen())
629 throw new EofException();
630
631
632 while (_generator.isBufferFull())
633 {
634 blockForOutput();
635 if (_closed)
636 throw new IOException("Closed");
637 if (!_generator._endp.isOpen())
638 throw new EofException();
639 }
640
641
642 _generator.addContent(buffer, Generator.MORE);
643
644
645 if (_generator.isBufferFull())
646 flush();
647
648 if (_generator.isContentWritten())
649 {
650 flush();
651 close();
652 }
653
654
655 while (buffer.length() > 0 && _generator._endp.isOpen())
656 blockForOutput();
657 }
658
659
660
661
662
663 public void print(String s) throws IOException
664 {
665 write(s.getBytes());
666 }
667 }
668
669
670
671
672
673
674
675
676
677
678
679
680 public static class OutputWriter extends Writer
681 {
682 private static final int WRITE_CONV = 0;
683 private static final int WRITE_ISO1 = 1;
684 private static final int WRITE_UTF8 = 2;
685
686 Output _out;
687 AbstractGenerator _generator;
688 int _writeMode;
689 int _surrogate;
690
691
692 public OutputWriter(Output out)
693 {
694 _out=out;
695 _generator=_out._generator;
696
697 }
698
699
700 public void setCharacterEncoding(String encoding)
701 {
702 if (encoding == null || StringUtil.__ISO_8859_1.equalsIgnoreCase(encoding))
703 {
704 _writeMode = WRITE_ISO1;
705 }
706 else if (StringUtil.__UTF8.equalsIgnoreCase(encoding))
707 {
708 _writeMode = WRITE_UTF8;
709 }
710 else
711 {
712 _writeMode = WRITE_CONV;
713 if (_out._characterEncoding == null || !_out._characterEncoding.equalsIgnoreCase(encoding))
714 _out._converter = null;
715 }
716
717 _out._characterEncoding = encoding;
718 if (_out._bytes==null)
719 _out._bytes = new ByteArrayOutputStream2(MAX_OUTPUT_CHARS);
720 }
721
722
723 public void close() throws IOException
724 {
725 _out.close();
726 }
727
728
729 public void flush() throws IOException
730 {
731 _out.flush();
732 }
733
734
735 public void write (String s,int offset, int length) throws IOException
736 {
737 while (length > MAX_OUTPUT_CHARS)
738 {
739 write(s, offset, MAX_OUTPUT_CHARS);
740 offset += MAX_OUTPUT_CHARS;
741 length -= MAX_OUTPUT_CHARS;
742 }
743
744 if (_out._chars==null)
745 {
746 _out._chars = new char[MAX_OUTPUT_CHARS];
747 }
748 char[] chars = _out._chars;
749 s.getChars(offset, offset + length, chars, 0);
750 write(chars, 0, length);
751 }
752
753
754 public void write (char[] s,int offset, int length) throws IOException
755 {
756 Output out = _out;
757
758 while (length > 0)
759 {
760 out._bytes.reset();
761 int chars = length>MAX_OUTPUT_CHARS?MAX_OUTPUT_CHARS:length;
762
763 switch (_writeMode)
764 {
765 case WRITE_CONV:
766 {
767 Writer converter=getConverter();
768 converter.write(s, offset, chars);
769 converter.flush();
770 }
771 break;
772
773 case WRITE_ISO1:
774 {
775 byte[] buffer=out._bytes.getBuf();
776 int bytes=out._bytes.getCount();
777
778 if (chars>buffer.length-bytes)
779 chars=buffer.length-bytes;
780
781 for (int i = 0; i < chars; i++)
782 {
783 int c = s[offset+i];
784 buffer[bytes++]=(byte)(c<256?c:'?');
785 }
786 if (bytes>=0)
787 out._bytes.setCount(bytes);
788
789 break;
790 }
791
792 case WRITE_UTF8:
793 {
794 byte[] buffer=out._bytes.getBuf();
795 int bytes=out._bytes.getCount();
796
797 if (bytes+chars>buffer.length)
798 chars=buffer.length-bytes;
799
800 for (int i = 0; i < chars; i++)
801 {
802 int code = s[offset+i];
803
804 if ((code & 0xffffff80) == 0)
805 {
806
807 buffer[bytes++]=(byte)(code);
808 }
809 else if((code&0xfffff800)==0)
810 {
811
812 if (bytes+2>buffer.length)
813 {
814 chars=i;
815 break;
816 }
817 buffer[bytes++]=(byte)(0xc0|(code>>6));
818 buffer[bytes++]=(byte)(0x80|(code&0x3f));
819
820 if (bytes+chars-i-1>buffer.length)
821 chars-=1;
822 }
823 else if((code&0xffff0000)==0)
824 {
825
826 if (bytes+3>buffer.length)
827 {
828 chars=i;
829 break;
830 }
831 buffer[bytes++]=(byte)(0xe0|(code>>12));
832 buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f));
833 buffer[bytes++]=(byte)(0x80|(code&0x3f));
834
835 if (bytes+chars-i-1>buffer.length)
836 chars-=2;
837 }
838 else if((code&0xff200000)==0)
839 {
840
841 if (bytes+4>buffer.length)
842 {
843 chars=i;
844 break;
845 }
846 buffer[bytes++]=(byte)(0xf0|(code>>18));
847 buffer[bytes++]=(byte)(0x80|((code>>12)&0x3f));
848 buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f));
849 buffer[bytes++]=(byte)(0x80|(code&0x3f));
850
851 if (bytes+chars-i-1>buffer.length)
852 chars-=3;
853 }
854 else if((code&0xf4000000)==0)
855 {
856
857 if (bytes+5>buffer.length)
858 {
859 chars=i;
860 break;
861 }
862 buffer[bytes++]=(byte)(0xf8|(code>>24));
863 buffer[bytes++]=(byte)(0x80|((code>>18)&0x3f));
864 buffer[bytes++]=(byte)(0x80|((code>>12)&0x3f));
865 buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f));
866 buffer[bytes++]=(byte)(0x80|(code&0x3f));
867
868 if (bytes+chars-i-1>buffer.length)
869 chars-=4;
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 if (bytes+chars-i-1>buffer.length)
887 chars-=5;
888 }
889 else
890 {
891 buffer[bytes++]=(byte)('?');
892 }
893 }
894 out._bytes.setCount(bytes);
895 break;
896 }
897 default:
898 throw new IllegalStateException();
899 }
900
901 out._bytes.writeTo(out);
902 length-=chars;
903 offset+=chars;
904 }
905 }
906
907
908 private Writer getConverter() throws IOException
909 {
910 if (_out._converter == null)
911 _out._converter = new OutputStreamWriter(_out._bytes, _out._characterEncoding);
912 return _out._converter;
913 }
914 }
915 }