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