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