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