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.InputStream;
20 import java.io.PrintWriter;
21
22 import javax.servlet.ServletInputStream;
23 import javax.servlet.ServletOutputStream;
24 import javax.servlet.http.HttpServletResponse;
25
26 import org.mortbay.io.Buffer;
27 import org.mortbay.io.Connection;
28 import org.mortbay.io.EndPoint;
29 import org.mortbay.io.RuntimeIOException;
30 import org.mortbay.io.BufferCache.CachedBuffer;
31 import org.mortbay.io.nio.SelectChannelEndPoint;
32 import org.mortbay.log.Log;
33 import org.mortbay.resource.Resource;
34 import org.mortbay.util.QuotedStringTokenizer;
35 import org.mortbay.util.StringUtil;
36 import org.mortbay.util.URIUtil;
37 import org.mortbay.util.ajax.Continuation;
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58 public class HttpConnection implements Connection
59 {
60 private static int UNKNOWN = -2;
61 private static ThreadLocal __currentConnection = new ThreadLocal();
62
63 private long _timeStamp = System.currentTimeMillis();
64 private int _requests;
65 private boolean _handling;
66 private boolean _destroy;
67
68 protected final Connector _connector;
69 protected final EndPoint _endp;
70 protected final Server _server;
71 protected final HttpURI _uri;
72
73 protected final Parser _parser;
74 protected final HttpFields _requestFields;
75 protected final Request _request;
76 protected ServletInputStream _in;
77
78 protected final Generator _generator;
79 protected final HttpFields _responseFields;
80 protected final Response _response;
81 protected Output _out;
82 protected OutputWriter _writer;
83 protected PrintWriter _printWriter;
84
85 int _include;
86
87 private Object _associatedObject;
88
89 private transient int _expect = UNKNOWN;
90 private transient int _version = UNKNOWN;
91 private transient boolean _head = false;
92 private transient boolean _host = false;
93 private transient boolean _delayedHandling = false;
94
95
96 public static HttpConnection getCurrentConnection()
97 {
98 return (HttpConnection)__currentConnection.get();
99 }
100
101
102 protected static void setCurrentConnection(HttpConnection connection)
103 {
104 __currentConnection.set(connection);
105 }
106
107
108
109
110
111
112 public HttpConnection(Connector connector, EndPoint endpoint, Server server)
113 {
114 _uri = URIUtil.__CHARSET==StringUtil.__UTF8?new HttpURI():new EncodedHttpURI(URIUtil.__CHARSET);
115 _connector = connector;
116 _endp = endpoint;
117 _parser = new HttpParser(_connector,endpoint,new RequestHandler(),_connector.getHeaderBufferSize(),_connector.getRequestBufferSize());
118 _requestFields = new HttpFields();
119 _responseFields = new HttpFields();
120 _request = new Request(this);
121 _response = new Response(this);
122 _generator = new HttpGenerator(_connector,_endp,_connector.getHeaderBufferSize(),_connector.getResponseBufferSize());
123 _generator.setSendServerVersion(server.getSendServerVersion());
124 _server = server;
125 }
126
127 protected HttpConnection(Connector connector, EndPoint endpoint, Server server,
128 Parser parser, Generator generator, Request request)
129 {
130 _uri = URIUtil.__CHARSET==StringUtil.__UTF8?new HttpURI():new EncodedHttpURI(URIUtil.__CHARSET);
131 _connector = connector;
132 _endp = endpoint;
133 _parser = parser;
134 _requestFields = new HttpFields();
135 _responseFields = new HttpFields();
136 _request = request;
137 _response = new Response(this);
138 _generator = generator;
139 _generator.setSendServerVersion(server.getSendServerVersion());
140 _server = server;
141 }
142
143
144 public void destroy()
145 {
146 synchronized (this)
147 {
148 _destroy = true;
149 if (!_handling)
150 {
151 if (_parser != null)
152 _parser.reset(true);
153
154 if (_generator != null)
155 _generator.reset(true);
156
157 if (_requestFields != null)
158 _requestFields.destroy();
159
160 if (_responseFields != null)
161 _responseFields.destroy();
162
163 }
164 }
165 }
166
167
168
169
170
171 public Parser getParser()
172 {
173 return _parser;
174 }
175
176
177
178
179
180 public int getRequests()
181 {
182 return _requests;
183 }
184
185
186
187
188
189 public long getTimeStamp()
190 {
191 return _timeStamp;
192 }
193
194
195
196
197
198 public Object getAssociatedObject()
199 {
200 return _associatedObject;
201 }
202
203
204
205
206
207
208 public void setAssociatedObject(Object associatedObject)
209 {
210 _associatedObject = associatedObject;
211 }
212
213
214
215
216
217 public Connector getConnector()
218 {
219 return _connector;
220 }
221
222
223
224
225
226 public HttpFields getRequestFields()
227 {
228 return _requestFields;
229 }
230
231
232
233
234
235 public HttpFields getResponseFields()
236 {
237 return _responseFields;
238 }
239
240
241
242
243
244
245
246 public boolean isConfidential(Request request)
247 {
248 if (_connector != null)
249 return _connector.isConfidential(request);
250 return false;
251 }
252
253
254
255
256
257
258
259
260
261
262 public boolean isIntegral(Request request)
263 {
264 if (_connector != null)
265 return _connector.isIntegral(request);
266 return false;
267 }
268
269
270
271
272
273 public EndPoint getEndPoint()
274 {
275 return _endp;
276 }
277
278
279
280
281
282 public boolean getResolveNames()
283 {
284 return _connector.getResolveNames();
285 }
286
287
288
289
290
291 public Request getRequest()
292 {
293 return _request;
294 }
295
296
297
298
299
300 public Response getResponse()
301 {
302 return _response;
303 }
304
305
306
307
308
309
310 public ServletInputStream getInputStream()
311 {
312 if (_in == null)
313 _in = new HttpParser.Input(((HttpParser)_parser),_connector.getMaxIdleTime());
314 return _in;
315 }
316
317
318
319
320
321
322 public ServletOutputStream getOutputStream()
323 {
324 if (_out == null)
325 _out = new Output();
326 return _out;
327 }
328
329
330
331
332
333
334 public PrintWriter getPrintWriter(String encoding)
335 {
336 getOutputStream();
337 if (_writer == null)
338 {
339 _writer = new OutputWriter();
340 _printWriter = new PrintWriter(_writer)
341 {
342
343
344
345
346 public void close()
347 {
348 try
349 {
350 out.close();
351 }
352 catch (IOException e)
353 {
354 Log.debug(e);
355 setError();
356 }
357 }
358
359 };
360 }
361 _writer.setCharacterEncoding(encoding);
362 return _printWriter;
363 }
364
365
366 public boolean isResponseCommitted()
367 {
368 return _generator.isCommitted();
369 }
370
371
372 public void handle() throws IOException
373 {
374
375 boolean more_in_buffer = true;
376 int no_progress = 0;
377
378 while (more_in_buffer)
379 {
380 try
381 {
382 synchronized (this)
383 {
384 if (_handling)
385 throw new IllegalStateException();
386
387 _handling = true;
388 }
389
390 setCurrentConnection(this);
391 long io = 0;
392
393 Continuation continuation = _request.getContinuation();
394 if (continuation != null && continuation.isPending())
395 {
396 Log.debug("resume continuation {}",continuation);
397 if (_request.getMethod() == null)
398 throw new IllegalStateException();
399 handleRequest();
400 }
401 else
402 {
403
404 if (!_parser.isComplete())
405 io = _parser.parseAvailable();
406
407
408
409
410
411
412 while (_generator.isCommitted() && !_generator.isComplete())
413 {
414 long written = _generator.flush();
415 io += written;
416 if (written <= 0)
417 break;
418 if (_endp.isBufferingOutput())
419 _endp.flush();
420 }
421
422
423 if (_endp.isBufferingOutput())
424 {
425 _endp.flush();
426 if (!_endp.isBufferingOutput())
427 no_progress = 0;
428 }
429
430 if (io > 0)
431 no_progress = 0;
432 else if (no_progress++ >= 2)
433 return;
434 }
435 }
436 catch (HttpException e)
437 {
438 if (Log.isDebugEnabled())
439 {
440 Log.debug("uri=" + _uri);
441 Log.debug("fields=" + _requestFields);
442 Log.debug(e);
443 }
444 _generator.sendError(e.getStatus(),e.getReason(),null,true);
445
446 _parser.reset(true);
447 _endp.close();
448 throw e;
449 }
450 finally
451 {
452 setCurrentConnection(null);
453
454 more_in_buffer = _parser.isMoreInBuffer() || _endp.isBufferingInput();
455
456 synchronized (this)
457 {
458 _handling = false;
459
460 if (_destroy)
461 {
462 destroy();
463 return;
464 }
465 }
466
467 if (_parser.isComplete() && _generator.isComplete() && !_endp.isBufferingOutput())
468 {
469 if (!_generator.isPersistent())
470 {
471 _parser.reset(true);
472 more_in_buffer = false;
473 }
474
475 reset(!more_in_buffer);
476 no_progress = 0;
477 }
478
479 Continuation continuation = _request.getContinuation();
480 if (continuation != null && continuation.isPending())
481 {
482 break;
483 }
484 else if (_generator.isCommitted() && !_generator.isComplete() && _endp instanceof SelectChannelEndPoint)
485
486
487
488 ((SelectChannelEndPoint)_endp).setWritable(false);
489 }
490 }
491 }
492
493
494 public void reset(boolean returnBuffers)
495 {
496 _parser.reset(returnBuffers);
497
498 _requestFields.clear();
499 _request.recycle();
500
501 _generator.reset(returnBuffers);
502
503 _responseFields.clear();
504 _response.recycle();
505
506 _uri.clear();
507 }
508
509
510 protected void handleRequest() throws IOException
511 {
512 if (_server.isRunning())
513 {
514 boolean retrying = false;
515 boolean error = false;
516 String threadName = null;
517 String info=null;
518 try
519 {
520 info = URIUtil.canonicalPath(_uri.getDecodedPath());
521 if (info == null)
522 throw new HttpException(400);
523 _request.setPathInfo(info);
524
525 if (_out != null)
526 _out.reopen();
527
528 if (Log.isDebugEnabled())
529 {
530 threadName = Thread.currentThread().getName();
531 Thread.currentThread().setName(threadName + " - " + _uri);
532 }
533
534 _connector.customize(_endp,_request);
535
536 _server.handle(this);
537 }
538 catch (RetryRequest r)
539 {
540 if (Log.isDebugEnabled())
541 Log.ignore(r);
542 retrying = true;
543 }
544 catch (EofException e)
545 {
546 Log.ignore(e);
547 error = true;
548 }
549 catch (HttpException e)
550 {
551 Log.debug(e);
552 _request.setHandled(true);
553 _response.sendError(e.getStatus(),e.getReason());
554 error = true;
555 }
556 catch (RuntimeIOException e)
557 {
558 Log.debug(e);
559 _request.setHandled(true);
560 error = true;
561 }
562 catch (Throwable e)
563 {
564 if (e instanceof ThreadDeath)
565 throw (ThreadDeath)e;
566
567 if (info==null)
568 {
569 Log.warn(_uri+": "+e);
570 Log.debug(e);
571 _request.setHandled(true);
572 _generator.sendError(400,null,null,true);
573 }
574 else
575 {
576 Log.warn(""+_uri,e);
577 _request.setHandled(true);
578 _generator.sendError(500,null,null,true);
579 }
580 error = true;
581 }
582 finally
583 {
584 if (threadName != null)
585 Thread.currentThread().setName(threadName);
586
587 if (!retrying)
588 {
589 if (_request.getContinuation() != null)
590 {
591 Log.debug("continuation still pending {}");
592 _request.getContinuation().reset();
593 }
594
595 if (_endp.isOpen())
596 {
597 if (_generator.isPersistent())
598 _connector.persist(_endp);
599
600 if (error)
601 _endp.close();
602 else
603 {
604 if (!_response.isCommitted() && !_request.isHandled())
605 _response.sendError(HttpServletResponse.SC_NOT_FOUND);
606 _response.complete();
607 }
608 }
609 else
610 {
611 _response.complete();
612 }
613 }
614 }
615 }
616 }
617
618
619 public void commitResponse(boolean last) throws IOException
620 {
621 if (!_generator.isCommitted())
622 {
623 _generator.setResponse(_response.getStatus(),_response.getReason());
624 try
625 {
626 _generator.completeHeader(_responseFields,last);
627 }
628 catch(IOException io)
629 {
630 throw io;
631 }
632 catch(RuntimeException e)
633 {
634 Log.warn("header full: "+e);
635 Log.debug(e);
636 _response.reset();
637 _generator.reset(true);
638 _generator.setResponse(HttpStatus.ORDINAL_500_Internal_Server_Error,null);
639 _generator.completeHeader(_responseFields,HttpGenerator.LAST);
640 _generator.complete();
641 throw e;
642 }
643 }
644 if (last)
645 _generator.complete();
646 }
647
648
649 public void completeResponse() throws IOException
650 {
651 if (!_generator.isCommitted())
652 {
653 _generator.setResponse(_response.getStatus(),_response.getReason());
654 try
655 {
656 _generator.completeHeader(_responseFields,HttpGenerator.LAST);
657 }
658 catch(IOException io)
659 {
660 throw io;
661 }
662 catch(RuntimeException e)
663 {
664 Log.warn("header full: "+e);
665 Log.debug(e);
666
667 _response.reset();
668 _generator.reset(true);
669 _generator.setResponse(HttpStatus.ORDINAL_500_Internal_Server_Error,null);
670 _generator.completeHeader(_responseFields,HttpGenerator.LAST);
671 _generator.complete();
672 throw e;
673 }
674 }
675
676 _generator.complete();
677 }
678
679
680 public void flushResponse() throws IOException
681 {
682 try
683 {
684 commitResponse(HttpGenerator.MORE);
685 _generator.flush();
686 }
687 catch (IOException e)
688 {
689 throw (e instanceof EofException)?e:new EofException(e);
690 }
691 }
692
693
694 public Generator getGenerator()
695 {
696 return _generator;
697 }
698
699
700 public boolean isIncluding()
701 {
702 return _include > 0;
703 }
704
705
706 public void include()
707 {
708 _include++;
709 }
710
711
712 public void included()
713 {
714 _include--;
715 if (_out != null)
716 _out.reopen();
717 }
718
719
720 public boolean isIdle()
721 {
722 return _generator.isIdle() && (_parser.isIdle() || _delayedHandling);
723 }
724
725
726
727
728 private class RequestHandler extends HttpParser.EventHandler
729 {
730 private String _charset;
731
732
733
734
735
736
737
738 public void startRequest(Buffer method, Buffer uri, Buffer version) throws IOException
739 {
740 _host = false;
741 _expect = UNKNOWN;
742 _delayedHandling = false;
743 _charset = null;
744
745 if (_request.getTimeStamp() == 0)
746 _request.setTimeStamp(System.currentTimeMillis());
747 _request.setMethod(method.toString());
748
749 try
750 {
751 _uri.parse(uri.array(),uri.getIndex(),uri.length());
752 _request.setUri(_uri);
753
754 if (version == null)
755 {
756 _request.setProtocol(HttpVersions.HTTP_0_9);
757 _version = HttpVersions.HTTP_0_9_ORDINAL;
758 }
759 else
760 {
761 version = HttpVersions.CACHE.get(version);
762 _version = HttpVersions.CACHE.getOrdinal(version);
763 if (_version <= 0)
764 _version = HttpVersions.HTTP_1_0_ORDINAL;
765 _request.setProtocol(version.toString());
766 }
767
768 _head = method == HttpMethods.HEAD_BUFFER;
769
770 }
771 catch (Exception e)
772 {
773 throw new HttpException(HttpStatus.ORDINAL_400_Bad_Request,null,e);
774 }
775 }
776
777
778
779
780
781
782 public void parsedHeader(Buffer name, Buffer value)
783 {
784 int ho = HttpHeaders.CACHE.getOrdinal(name);
785 switch (ho)
786 {
787 case HttpHeaders.HOST_ORDINAL:
788
789 _host = true;
790 break;
791
792 case HttpHeaders.EXPECT_ORDINAL:
793 value = HttpHeaderValues.CACHE.lookup(value);
794 _expect = HttpHeaderValues.CACHE.getOrdinal(value);
795 break;
796
797 case HttpHeaders.ACCEPT_ENCODING_ORDINAL:
798 case HttpHeaders.USER_AGENT_ORDINAL:
799 value = HttpHeaderValues.CACHE.lookup(value);
800 break;
801
802 case HttpHeaders.CONTENT_TYPE_ORDINAL:
803 value = MimeTypes.CACHE.lookup(value);
804 _charset = MimeTypes.getCharsetFromContentType(value);
805 break;
806
807 case HttpHeaders.CONNECTION_ORDINAL:
808
809
810 int ordinal = HttpHeaderValues.CACHE.getOrdinal(value);
811 switch (ordinal)
812 {
813 case -1:
814 {
815 String[] values = value.toString().split(",");
816 for (int i = 0; values != null && i < values.length; i++)
817 {
818 CachedBuffer cb = HttpHeaderValues.CACHE.get(values[i].trim());
819
820 if (cb != null)
821 {
822 switch (cb.getOrdinal())
823 {
824 case HttpHeaderValues.CLOSE_ORDINAL:
825 _responseFields.add(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.CLOSE_BUFFER);
826 _generator.setPersistent(false);
827 break;
828
829 case HttpHeaderValues.KEEP_ALIVE_ORDINAL:
830 if (_version == HttpVersions.HTTP_1_0_ORDINAL)
831 _responseFields.add(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.KEEP_ALIVE_BUFFER);
832 break;
833 }
834 }
835 }
836 break;
837 }
838 case HttpHeaderValues.CLOSE_ORDINAL:
839 _responseFields.put(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.CLOSE_BUFFER);
840 _generator.setPersistent(false);
841 break;
842
843 case HttpHeaderValues.KEEP_ALIVE_ORDINAL:
844 if (_version == HttpVersions.HTTP_1_0_ORDINAL)
845 _responseFields.put(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.KEEP_ALIVE_BUFFER);
846 break;
847 }
848 }
849
850 _requestFields.add(name,value);
851 }
852
853
854
855
856 public void headerComplete() throws IOException
857 {
858 _requests++;
859 _generator.setVersion(_version);
860 switch (_version)
861 {
862 case HttpVersions.HTTP_0_9_ORDINAL:
863 break;
864 case HttpVersions.HTTP_1_0_ORDINAL:
865 _generator.setHead(_head);
866 break;
867 case HttpVersions.HTTP_1_1_ORDINAL:
868 _generator.setHead(_head);
869
870 if (_server.getSendDateHeader())
871 _responseFields.put(HttpHeaders.DATE_BUFFER,_request.getTimeStampBuffer(),_request.getTimeStamp());
872
873 if (!_host)
874 {
875 _generator.setResponse(HttpStatus.ORDINAL_400_Bad_Request,null);
876 _responseFields.put(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.CLOSE_BUFFER);
877 _generator.completeHeader(_responseFields,true);
878 _generator.complete();
879 return;
880 }
881
882 if (_expect != UNKNOWN)
883 {
884 if (_expect == HttpHeaderValues.CONTINUE_ORDINAL)
885 {
886
887
888 if (((HttpParser)_parser).getHeaderBuffer() == null || ((HttpParser)_parser).getHeaderBuffer().length() < 2)
889 {
890 _generator.setResponse(HttpStatus.ORDINAL_100_Continue,null);
891 _generator.completeHeader(null,true);
892 _generator.complete();
893 _generator.reset(false);
894 }
895 }
896 else if (_expect == HttpHeaderValues.PROCESSING_ORDINAL)
897 {
898 }
899 else
900 {
901 _generator.sendError(HttpStatus.ORDINAL_417_Expectation_Failed,null,null,true);
902 return;
903 }
904 }
905
906 break;
907 default:
908 }
909
910 if (_charset != null)
911 _request.setCharacterEncodingUnchecked(_charset);
912
913
914 if (((HttpParser)_parser).getContentLength() <= 0 && !((HttpParser)_parser).isChunking())
915 handleRequest();
916 else
917 _delayedHandling = true;
918 }
919
920
921
922
923
924
925 public void content(Buffer ref) throws IOException
926 {
927 if (_delayedHandling)
928 {
929 _delayedHandling = false;
930 handleRequest();
931 }
932 }
933
934
935
936
937
938
939 public void messageComplete(long contentLength) throws IOException
940 {
941 if (_delayedHandling)
942 {
943 _delayedHandling = false;
944 handleRequest();
945 }
946 }
947
948
949
950
951
952
953
954
955 public void startResponse(Buffer version, int status, Buffer reason)
956 {
957 Log.debug("Bad request!: " + version + " " + status + " " + reason);
958 }
959
960 }
961
962
963
964
965 public class Output extends AbstractGenerator.Output
966 {
967 Output()
968 {
969 super((AbstractGenerator)HttpConnection.this._generator,_connector.getMaxIdleTime());
970 }
971
972
973
974
975
976 public void close() throws IOException
977 {
978 if (_closed)
979 return;
980
981 if (!isIncluding() && !_generator.isCommitted())
982 commitResponse(HttpGenerator.LAST);
983 else
984 flushResponse();
985
986 super.close();
987 }
988
989
990
991
992
993 public void flush() throws IOException
994 {
995 if (!_generator.isCommitted())
996 commitResponse(HttpGenerator.MORE);
997 super.flush();
998 }
999
1000
1001
1002
1003
1004 public void print(String s) throws IOException
1005 {
1006 if (_closed)
1007 throw new IOException("Closed");
1008 PrintWriter writer = getPrintWriter(null);
1009 writer.print(s);
1010 }
1011
1012
1013 public void sendResponse(Buffer response) throws IOException
1014 {
1015 ((HttpGenerator)_generator).sendResponse(response);
1016 }
1017
1018
1019 public void sendContent(Object content) throws IOException
1020 {
1021 Resource resource = null;
1022
1023 if (_closed)
1024 throw new IOException("Closed");
1025
1026 if (_generator.getContentWritten() > 0)
1027 throw new IllegalStateException("!empty");
1028
1029 if (content instanceof HttpContent)
1030 {
1031 HttpContent c = (HttpContent)content;
1032 Buffer contentType = c.getContentType();
1033 if (contentType != null && !_responseFields.containsKey(HttpHeaders.CONTENT_TYPE_BUFFER))
1034 {
1035 String enc = _response.getSetCharacterEncoding();
1036 if(enc==null)
1037 _responseFields.add(HttpHeaders.CONTENT_TYPE_BUFFER, contentType);
1038 else
1039 {
1040 if(contentType instanceof CachedBuffer)
1041 {
1042 CachedBuffer content_type = ((CachedBuffer)contentType).getAssociate(enc);
1043 if(content_type!=null)
1044 _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER, content_type);
1045 else
1046 {
1047 _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER,
1048 contentType+";charset="+QuotedStringTokenizer.quote(enc,";= "));
1049 }
1050 }
1051 else
1052 {
1053 _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER,
1054 contentType+";charset="+QuotedStringTokenizer.quote(enc,";= "));
1055 }
1056 }
1057 }
1058 if (c.getContentLength() > 0)
1059 _responseFields.putLongField(HttpHeaders.CONTENT_LENGTH_BUFFER,c.getContentLength());
1060 Buffer lm = c.getLastModified();
1061 long lml = c.getResource().lastModified();
1062 if (lm != null)
1063 _responseFields.put(HttpHeaders.LAST_MODIFIED_BUFFER,lm,lml);
1064 else if (c.getResource() != null)
1065 {
1066 if (lml != -1)
1067 _responseFields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER,lml);
1068 }
1069
1070 content = c.getBuffer();
1071 if (content == null)
1072 content = c.getInputStream();
1073 }
1074 else if (content instanceof Resource)
1075 {
1076 resource = (Resource)content;
1077 _responseFields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER,resource.lastModified());
1078 content = resource.getInputStream();
1079 }
1080
1081 if (content instanceof Buffer)
1082 {
1083 _generator.addContent((Buffer)content,HttpGenerator.LAST);
1084 commitResponse(HttpGenerator.LAST);
1085 }
1086 else if (content instanceof InputStream)
1087 {
1088 InputStream in = (InputStream)content;
1089
1090 try
1091 {
1092 int max = _generator.prepareUncheckedAddContent();
1093 Buffer buffer = _generator.getUncheckedBuffer();
1094
1095 int len = buffer.readFrom(in,max);
1096
1097 while (len >= 0)
1098 {
1099 _generator.completeUncheckedAddContent();
1100 _out.flush();
1101
1102 max = _generator.prepareUncheckedAddContent();
1103 buffer = _generator.getUncheckedBuffer();
1104 len = buffer.readFrom(in,max);
1105 }
1106 _generator.completeUncheckedAddContent();
1107 _out.flush();
1108 }
1109 finally
1110 {
1111 if (resource != null)
1112 resource.release();
1113 else
1114 in.close();
1115
1116 }
1117 }
1118 else
1119 throw new IllegalArgumentException("unknown content type?");
1120
1121 }
1122 }
1123
1124
1125
1126
1127 public class OutputWriter extends AbstractGenerator.OutputWriter
1128 {
1129 OutputWriter()
1130 {
1131 super(HttpConnection.this._out);
1132 }
1133 }
1134
1135 }