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