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 throw e;
641 }
642 }
643 if (last)
644 _generator.complete();
645 }
646
647
648 public void completeResponse() throws IOException
649 {
650 if (!_generator.isCommitted())
651 {
652 _generator.setResponse(_response.getStatus(),_response.getReason());
653 try
654 {
655 _generator.completeHeader(_responseFields,HttpGenerator.LAST);
656 }
657 catch(IOException io)
658 {
659 throw io;
660 }
661 catch(RuntimeException e)
662 {
663 Log.warn("header full: "+e);
664 Log.debug(e);
665
666 _response.reset();
667 _generator.reset(true);
668 _generator.setResponse(HttpStatus.ORDINAL_500_Internal_Server_Error,null);
669 _generator.completeHeader(_responseFields,HttpGenerator.LAST);
670 throw e;
671 }
672 }
673
674 _generator.complete();
675 }
676
677
678 public void flushResponse() throws IOException
679 {
680 try
681 {
682 commitResponse(HttpGenerator.MORE);
683 _generator.flush();
684 }
685 catch (IOException e)
686 {
687 throw (e instanceof EofException)?e:new EofException(e);
688 }
689 }
690
691
692 public Generator getGenerator()
693 {
694 return _generator;
695 }
696
697
698 public boolean isIncluding()
699 {
700 return _include > 0;
701 }
702
703
704 public void include()
705 {
706 _include++;
707 }
708
709
710 public void included()
711 {
712 _include--;
713 if (_out != null)
714 _out.reopen();
715 }
716
717
718 public boolean isIdle()
719 {
720 return _generator.isIdle() && (_parser.isIdle() || _delayedHandling);
721 }
722
723
724
725
726 private class RequestHandler extends HttpParser.EventHandler
727 {
728 private String _charset;
729
730
731
732
733
734
735
736 public void startRequest(Buffer method, Buffer uri, Buffer version) throws IOException
737 {
738 _host = false;
739 _expect = UNKNOWN;
740 _delayedHandling = false;
741 _charset = null;
742
743 if (_request.getTimeStamp() == 0)
744 _request.setTimeStamp(System.currentTimeMillis());
745 _request.setMethod(method.toString());
746
747 try
748 {
749 _uri.parse(uri.array(),uri.getIndex(),uri.length());
750 _request.setUri(_uri);
751
752 if (version == null)
753 {
754 _request.setProtocol(HttpVersions.HTTP_0_9);
755 _version = HttpVersions.HTTP_0_9_ORDINAL;
756 }
757 else
758 {
759 version = HttpVersions.CACHE.get(version);
760 _version = HttpVersions.CACHE.getOrdinal(version);
761 if (_version <= 0)
762 _version = HttpVersions.HTTP_1_0_ORDINAL;
763 _request.setProtocol(version.toString());
764 }
765
766 _head = method == HttpMethods.HEAD_BUFFER;
767
768 }
769 catch (Exception e)
770 {
771 throw new HttpException(HttpStatus.ORDINAL_400_Bad_Request,null,e);
772 }
773 }
774
775
776
777
778
779
780 public void parsedHeader(Buffer name, Buffer value)
781 {
782 int ho = HttpHeaders.CACHE.getOrdinal(name);
783 switch (ho)
784 {
785 case HttpHeaders.HOST_ORDINAL:
786
787 _host = true;
788 break;
789
790 case HttpHeaders.EXPECT_ORDINAL:
791 value = HttpHeaderValues.CACHE.lookup(value);
792 _expect = HttpHeaderValues.CACHE.getOrdinal(value);
793 break;
794
795 case HttpHeaders.ACCEPT_ENCODING_ORDINAL:
796 case HttpHeaders.USER_AGENT_ORDINAL:
797 value = HttpHeaderValues.CACHE.lookup(value);
798 break;
799
800 case HttpHeaders.CONTENT_TYPE_ORDINAL:
801 value = MimeTypes.CACHE.lookup(value);
802 _charset = MimeTypes.getCharsetFromContentType(value);
803 break;
804
805 case HttpHeaders.CONNECTION_ORDINAL:
806
807
808 int ordinal = HttpHeaderValues.CACHE.getOrdinal(value);
809 switch (ordinal)
810 {
811 case -1:
812 {
813 String[] values = value.toString().split(",");
814 for (int i = 0; values != null && i < values.length; i++)
815 {
816 CachedBuffer cb = HttpHeaderValues.CACHE.get(values[i].trim());
817
818 if (cb != null)
819 {
820 switch (cb.getOrdinal())
821 {
822 case HttpHeaderValues.CLOSE_ORDINAL:
823 _responseFields.add(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.CLOSE_BUFFER);
824 _generator.setPersistent(false);
825 break;
826
827 case HttpHeaderValues.KEEP_ALIVE_ORDINAL:
828 if (_version == HttpVersions.HTTP_1_0_ORDINAL)
829 _responseFields.add(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.KEEP_ALIVE_BUFFER);
830 break;
831 }
832 }
833 }
834 break;
835 }
836 case HttpHeaderValues.CLOSE_ORDINAL:
837 _responseFields.put(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.CLOSE_BUFFER);
838 _generator.setPersistent(false);
839 break;
840
841 case HttpHeaderValues.KEEP_ALIVE_ORDINAL:
842 if (_version == HttpVersions.HTTP_1_0_ORDINAL)
843 _responseFields.put(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.KEEP_ALIVE_BUFFER);
844 break;
845 }
846 }
847
848 _requestFields.add(name,value);
849 }
850
851
852
853
854 public void headerComplete() throws IOException
855 {
856 _requests++;
857 _generator.setVersion(_version);
858 switch (_version)
859 {
860 case HttpVersions.HTTP_0_9_ORDINAL:
861 break;
862 case HttpVersions.HTTP_1_0_ORDINAL:
863 _generator.setHead(_head);
864 break;
865 case HttpVersions.HTTP_1_1_ORDINAL:
866 _generator.setHead(_head);
867
868 if (_server.getSendDateHeader())
869 _responseFields.put(HttpHeaders.DATE_BUFFER,_request.getTimeStampBuffer(),_request.getTimeStamp());
870
871 if (!_host)
872 {
873 _generator.setResponse(HttpStatus.ORDINAL_400_Bad_Request,null);
874 _responseFields.put(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.CLOSE_BUFFER);
875 _generator.completeHeader(_responseFields,true);
876 _generator.complete();
877 return;
878 }
879
880 if (_expect != UNKNOWN)
881 {
882 if (_expect == HttpHeaderValues.CONTINUE_ORDINAL)
883 {
884
885
886 if (((HttpParser)_parser).getHeaderBuffer() == null || ((HttpParser)_parser).getHeaderBuffer().length() < 2)
887 {
888 _generator.setResponse(HttpStatus.ORDINAL_100_Continue,null);
889 _generator.completeHeader(null,true);
890 _generator.complete();
891 _generator.reset(false);
892 }
893 }
894 else if (_expect == HttpHeaderValues.PROCESSING_ORDINAL)
895 {
896 }
897 else
898 {
899 _generator.sendError(HttpStatus.ORDINAL_417_Expectation_Failed,null,null,true);
900 return;
901 }
902 }
903
904 break;
905 default:
906 }
907
908 if (_charset != null)
909 _request.setCharacterEncodingUnchecked(_charset);
910
911
912 if (((HttpParser)_parser).getContentLength() <= 0 && !((HttpParser)_parser).isChunking())
913 handleRequest();
914 else
915 _delayedHandling = true;
916 }
917
918
919
920
921
922
923 public void content(Buffer ref) throws IOException
924 {
925 if (_delayedHandling)
926 {
927 _delayedHandling = false;
928 handleRequest();
929 }
930 }
931
932
933
934
935
936
937 public void messageComplete(long contentLength) throws IOException
938 {
939 if (_delayedHandling)
940 {
941 _delayedHandling = false;
942 handleRequest();
943 }
944 }
945
946
947
948
949
950
951
952
953 public void startResponse(Buffer version, int status, Buffer reason)
954 {
955 Log.debug("Bad request!: " + version + " " + status + " " + reason);
956 }
957
958 }
959
960
961
962
963 public class Output extends AbstractGenerator.Output
964 {
965 Output()
966 {
967 super((AbstractGenerator)HttpConnection.this._generator,_connector.getMaxIdleTime());
968 }
969
970
971
972
973
974 public void close() throws IOException
975 {
976 if (_closed)
977 return;
978
979 if (!isIncluding() && !_generator.isCommitted())
980 commitResponse(HttpGenerator.LAST);
981 else
982 flushResponse();
983
984 super.close();
985 }
986
987
988
989
990
991 public void flush() throws IOException
992 {
993 if (!_generator.isCommitted())
994 commitResponse(HttpGenerator.MORE);
995 super.flush();
996 }
997
998
999
1000
1001
1002 public void print(String s) throws IOException
1003 {
1004 if (_closed)
1005 throw new IOException("Closed");
1006 PrintWriter writer = getPrintWriter(null);
1007 writer.print(s);
1008 }
1009
1010
1011 public void sendResponse(Buffer response) throws IOException
1012 {
1013 ((HttpGenerator)_generator).sendResponse(response);
1014 }
1015
1016
1017 public void sendContent(Object content) throws IOException
1018 {
1019 Resource resource = null;
1020
1021 if (_closed)
1022 throw new IOException("Closed");
1023
1024 if (_generator.getContentWritten() > 0)
1025 throw new IllegalStateException("!empty");
1026
1027 if (content instanceof HttpContent)
1028 {
1029 HttpContent c = (HttpContent)content;
1030 Buffer contentType = c.getContentType();
1031 if (contentType != null && !_responseFields.containsKey(HttpHeaders.CONTENT_TYPE_BUFFER))
1032 {
1033 String enc = _response.getSetCharacterEncoding();
1034 if(enc==null)
1035 _responseFields.add(HttpHeaders.CONTENT_TYPE_BUFFER, contentType);
1036 else
1037 {
1038 if(contentType instanceof CachedBuffer)
1039 {
1040 CachedBuffer content_type = ((CachedBuffer)contentType).getAssociate(enc);
1041 if(content_type!=null)
1042 _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER, content_type);
1043 else
1044 {
1045 _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER,
1046 contentType+";charset="+QuotedStringTokenizer.quote(enc,";= "));
1047 }
1048 }
1049 else
1050 {
1051 _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER,
1052 contentType+";charset="+QuotedStringTokenizer.quote(enc,";= "));
1053 }
1054 }
1055 }
1056 if (c.getContentLength() > 0)
1057 _responseFields.putLongField(HttpHeaders.CONTENT_LENGTH_BUFFER,c.getContentLength());
1058 Buffer lm = c.getLastModified();
1059 long lml = c.getResource().lastModified();
1060 if (lm != null)
1061 _responseFields.put(HttpHeaders.LAST_MODIFIED_BUFFER,lm,lml);
1062 else if (c.getResource() != null)
1063 {
1064 if (lml != -1)
1065 _responseFields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER,lml);
1066 }
1067
1068 content = c.getBuffer();
1069 if (content == null)
1070 content = c.getInputStream();
1071 }
1072 else if (content instanceof Resource)
1073 {
1074 resource = (Resource)content;
1075 _responseFields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER,resource.lastModified());
1076 content = resource.getInputStream();
1077 }
1078
1079 if (content instanceof Buffer)
1080 {
1081 _generator.addContent((Buffer)content,HttpGenerator.LAST);
1082 commitResponse(HttpGenerator.LAST);
1083 }
1084 else if (content instanceof InputStream)
1085 {
1086 InputStream in = (InputStream)content;
1087
1088 try
1089 {
1090 int max = _generator.prepareUncheckedAddContent();
1091 Buffer buffer = _generator.getUncheckedBuffer();
1092
1093 int len = buffer.readFrom(in,max);
1094
1095 while (len >= 0)
1096 {
1097 _generator.completeUncheckedAddContent();
1098 _out.flush();
1099
1100 max = _generator.prepareUncheckedAddContent();
1101 buffer = _generator.getUncheckedBuffer();
1102 len = buffer.readFrom(in,max);
1103 }
1104 _generator.completeUncheckedAddContent();
1105 _out.flush();
1106 }
1107 finally
1108 {
1109 if (resource != null)
1110 resource.release();
1111 else
1112 in.close();
1113
1114 }
1115 }
1116 else
1117 throw new IllegalArgumentException("unknown content type?");
1118
1119 }
1120 }
1121
1122
1123
1124
1125 public class OutputWriter extends AbstractGenerator.OutputWriter
1126 {
1127 OutputWriter()
1128 {
1129 super(HttpConnection.this._out);
1130 }
1131 }
1132
1133 }