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.ServletInputStream;
20 import javax.servlet.ServletOutputStream;
21 import javax.servlet.http.HttpServletResponse;
22
23 import org.eclipse.jetty.continuation.ContinuationThrowable;
24 import org.eclipse.jetty.http.EncodedHttpURI;
25 import org.eclipse.jetty.http.Generator;
26 import org.eclipse.jetty.http.HttpBuffers;
27 import org.eclipse.jetty.http.HttpContent;
28 import org.eclipse.jetty.http.HttpException;
29 import org.eclipse.jetty.http.HttpFields;
30 import org.eclipse.jetty.http.HttpGenerator;
31 import org.eclipse.jetty.http.HttpHeaderValues;
32 import org.eclipse.jetty.http.HttpHeaders;
33 import org.eclipse.jetty.http.HttpMethods;
34 import org.eclipse.jetty.http.HttpParser;
35 import org.eclipse.jetty.http.HttpStatus;
36 import org.eclipse.jetty.http.HttpURI;
37 import org.eclipse.jetty.http.HttpVersions;
38 import org.eclipse.jetty.http.MimeTypes;
39 import org.eclipse.jetty.http.Parser;
40 import org.eclipse.jetty.io.AbstractConnection;
41 import org.eclipse.jetty.io.Buffer;
42 import org.eclipse.jetty.io.BufferCache.CachedBuffer;
43 import org.eclipse.jetty.io.Buffers;
44 import org.eclipse.jetty.io.Connection;
45 import org.eclipse.jetty.io.EndPoint;
46 import org.eclipse.jetty.io.EofException;
47 import org.eclipse.jetty.io.RuntimeIOException;
48 import org.eclipse.jetty.io.UncheckedPrintWriter;
49 import org.eclipse.jetty.server.nio.NIOConnector;
50 import org.eclipse.jetty.server.ssl.SslConnector;
51 import org.eclipse.jetty.util.QuotedStringTokenizer;
52 import org.eclipse.jetty.util.StringUtil;
53 import org.eclipse.jetty.util.URIUtil;
54 import org.eclipse.jetty.util.log.Log;
55 import org.eclipse.jetty.util.log.Logger;
56 import org.eclipse.jetty.util.resource.Resource;
57
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 public abstract class AbstractHttpConnection extends AbstractConnection
90 {
91 private static final Logger LOG = Log.getLogger(AbstractHttpConnection.class);
92
93 private static final int UNKNOWN = -2;
94 private static final ThreadLocal<AbstractHttpConnection> __currentConnection = new ThreadLocal<AbstractHttpConnection>();
95
96 private int _requests;
97
98 protected final Connector _connector;
99 protected final Server _server;
100 protected final HttpURI _uri;
101
102 protected final Parser _parser;
103 protected final HttpFields _requestFields;
104 protected final Request _request;
105 protected ServletInputStream _in;
106
107 protected final Generator _generator;
108 protected final HttpFields _responseFields;
109 protected final Response _response;
110 protected Output _out;
111 protected OutputWriter _writer;
112 protected PrintWriter _printWriter;
113
114 int _include;
115
116 private Object _associatedObject;
117
118 private int _version = UNKNOWN;
119
120 private boolean _expect = false;
121 private boolean _expect100Continue = false;
122 private boolean _expect102Processing = false;
123 private boolean _head = false;
124 private boolean _host = false;
125 private boolean _delayedHandling=false;
126
127
128 public static AbstractHttpConnection getCurrentConnection()
129 {
130 return __currentConnection.get();
131 }
132
133
134 protected static void setCurrentConnection(AbstractHttpConnection connection)
135 {
136 __currentConnection.set(connection);
137 }
138
139
140
141
142
143 public AbstractHttpConnection(Connector connector, EndPoint endpoint, Server server)
144 {
145 super(endpoint);
146 _uri = StringUtil.__UTF8.equals(URIUtil.__CHARSET)?new HttpURI():new EncodedHttpURI(URIUtil.__CHARSET);
147 _connector = connector;
148 HttpBuffers ab = (HttpBuffers)_connector;
149 _parser = newHttpParser(ab.getRequestBuffers(), endpoint, new RequestHandler());
150 _requestFields = new HttpFields();
151 _responseFields = new HttpFields(server.getMaxCookieVersion());
152 _request = new Request(this);
153 _response = new Response(this);
154 _generator = new HttpGenerator(ab.getResponseBuffers(), _endp);
155 _generator.setSendServerVersion(server.getSendServerVersion());
156 _server = server;
157 }
158
159
160 protected AbstractHttpConnection(Connector connector, EndPoint endpoint, Server server,
161 Parser parser, Generator generator, Request request)
162 {
163 super(endpoint);
164
165 _uri = URIUtil.__CHARSET.equals(StringUtil.__UTF8)?new HttpURI():new EncodedHttpURI(URIUtil.__CHARSET);
166 _connector = connector;
167 _parser = parser;
168 _requestFields = new HttpFields();
169 _responseFields = new HttpFields(server.getMaxCookieVersion());
170 _request = request;
171 _response = new Response(this);
172 _generator = generator;
173 _generator.setSendServerVersion(server.getSendServerVersion());
174 _server = server;
175 }
176
177 protected HttpParser newHttpParser(Buffers requestBuffers, EndPoint endpoint, HttpParser.EventHandler requestHandler)
178 {
179 return new HttpParser(requestBuffers, endpoint, requestHandler);
180 }
181
182
183
184
185
186 public Parser getParser()
187 {
188 return _parser;
189 }
190
191
192
193
194
195 public int getRequests()
196 {
197 return _requests;
198 }
199
200
201 public Server getServer()
202 {
203 return _server;
204 }
205
206
207
208
209
210 public Object getAssociatedObject()
211 {
212 return _associatedObject;
213 }
214
215
216
217
218
219 public void setAssociatedObject(Object associatedObject)
220 {
221 _associatedObject = associatedObject;
222 }
223
224
225
226
227
228 public Connector getConnector()
229 {
230 return _connector;
231 }
232
233
234
235
236
237 public HttpFields getRequestFields()
238 {
239 return _requestFields;
240 }
241
242
243
244
245
246 public HttpFields getResponseFields()
247 {
248 return _responseFields;
249 }
250
251
252
253
254
255
256 public boolean isConfidential(Request request)
257 {
258 if (_connector!=null)
259 return _connector.isConfidential(request);
260 return false;
261 }
262
263
264
265
266
267
268
269
270 public boolean isIntegral(Request request)
271 {
272 if (_connector!=null)
273 return _connector.isIntegral(request);
274 return false;
275 }
276
277
278
279
280
281 public boolean getResolveNames()
282 {
283 return _connector.getResolveNames();
284 }
285
286
287
288
289
290 public Request getRequest()
291 {
292 return _request;
293 }
294
295
296
297
298
299 public Response getResponse()
300 {
301 return _response;
302 }
303
304
305
306
307
308
309
310
311
312
313
314
315 public ServletInputStream getInputStream() throws IOException
316 {
317
318 if (_expect100Continue)
319 {
320
321 if (((HttpParser)_parser).getHeaderBuffer()==null || ((HttpParser)_parser).getHeaderBuffer().length()<2)
322 {
323 if (_generator.isCommitted())
324 throw new IllegalStateException("Committed before 100 Continues");
325
326 ((HttpGenerator)_generator).send1xx(HttpStatus.CONTINUE_100);
327 }
328 _expect100Continue=false;
329 }
330
331 if (_in == null)
332 _in = new HttpInput(AbstractHttpConnection.this);
333 return _in;
334 }
335
336
337
338
339
340 public ServletOutputStream getOutputStream()
341 {
342 if (_out == null)
343 _out = new Output();
344 return _out;
345 }
346
347
348
349
350
351
352 public PrintWriter getPrintWriter(String encoding)
353 {
354 getOutputStream();
355 if (_writer==null)
356 {
357 _writer=new OutputWriter();
358 if (_server.isUncheckedPrintWriter())
359 _printWriter=new UncheckedPrintWriter(_writer);
360 else
361 _printWriter = new PrintWriter(_writer)
362 {
363 public void close()
364 {
365 synchronized (lock)
366 {
367 try
368 {
369 out.close();
370 }
371 catch (IOException e)
372 {
373 setError();
374 }
375 }
376 }
377 };
378
379 }
380 _writer.setCharacterEncoding(encoding);
381 return _printWriter;
382 }
383
384
385 public boolean isResponseCommitted()
386 {
387 return _generator.isCommitted();
388 }
389
390
391 public void reset()
392 {
393 _parser.reset();
394 _parser.returnBuffers();
395 _requestFields.clear();
396 _request.recycle();
397 _generator.reset();
398 _generator.returnBuffers();
399 _responseFields.clear();
400 _response.recycle();
401 _uri.clear();
402 }
403
404
405 protected void handleRequest() throws IOException
406 {
407 boolean error = false;
408
409 String threadName=null;
410 try
411 {
412 if (LOG.isDebugEnabled())
413 {
414 threadName=Thread.currentThread().getName();
415 Thread.currentThread().setName(threadName+" - "+_uri);
416 }
417
418
419
420
421
422
423
424
425
426
427 final Server server=_server;
428 boolean handling=_request._async.handling() && server!=null && server.isRunning();
429 while (handling)
430 {
431 _request.setHandled(false);
432
433 String info=null;
434 try
435 {
436 _uri.getPort();
437 info=URIUtil.canonicalPath(_uri.getDecodedPath());
438 if (info==null && !_request.getMethod().equals(HttpMethods.CONNECT))
439 throw new HttpException(400);
440 _request.setPathInfo(info);
441
442 if (_out!=null)
443 _out.reopen();
444
445 if (_request._async.isInitial())
446 {
447 _request.setDispatcherType(DispatcherType.REQUEST);
448 _connector.customize(_endp, _request);
449 server.handle(this);
450 }
451 else
452 {
453 _request.setDispatcherType(DispatcherType.ASYNC);
454 server.handleAsync(this);
455 }
456 }
457 catch (ContinuationThrowable e)
458 {
459 LOG.ignore(e);
460 }
461 catch (EofException e)
462 {
463 LOG.debug(e);
464 error=true;
465 _request.setHandled(true);
466 }
467 catch (RuntimeIOException e)
468 {
469 LOG.debug(e);
470 error=true;
471 _request.setHandled(true);
472 }
473 catch (HttpException e)
474 {
475 LOG.debug(e);
476 error=true;
477 _request.setHandled(true);
478 _response.sendError(e.getStatus(), e.getReason());
479 }
480 catch (Throwable e)
481 {
482 LOG.warn(String.valueOf(_uri),e);
483 error=true;
484 _request.setHandled(true);
485 _generator.sendError(info==null?400:500, null, null, true);
486 }
487 finally
488 {
489 handling = !_request._async.unhandle() && server.isRunning() && _server!=null;
490 }
491 }
492 }
493 finally
494 {
495 if (threadName!=null)
496 Thread.currentThread().setName(threadName);
497
498 if (_request._async.isUncompleted())
499 {
500 _request._async.doComplete();
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();
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();
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 onClose()
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 public String toString()
696 {
697 return String.format("%s,g=%s,p=%s,r=%d",
698 super.toString(),
699 _generator,
700 _parser,
701 _requests);
702 }
703
704
705
706
707 private class RequestHandler extends HttpParser.EventHandler
708 {
709 private String _charset;
710
711
712
713
714
715
716 @Override
717 public void startRequest(Buffer method, Buffer uri, Buffer version) throws IOException
718 {
719 uri=uri.asImmutableBuffer();
720
721 _host = false;
722 _expect = false;
723 _expect100Continue=false;
724 _expect102Processing=false;
725 _delayedHandling=false;
726 _charset=null;
727
728 if(_request.getTimeStamp()==0)
729 _request.setTimeStamp(System.currentTimeMillis());
730 _request.setMethod(method.toString());
731
732 try
733 {
734 _head=false;
735 switch (HttpMethods.CACHE.getOrdinal(method))
736 {
737 case HttpMethods.CONNECT_ORDINAL:
738 _uri.parseConnect(uri.array(), uri.getIndex(), uri.length());
739 break;
740
741 case HttpMethods.HEAD_ORDINAL:
742 _head=true;
743 _uri.parse(uri.array(), uri.getIndex(), uri.length());
744 break;
745
746 default:
747 _uri.parse(uri.array(), uri.getIndex(), uri.length());
748 }
749
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 if (version==null)
761 throw new HttpException(HttpStatus.BAD_REQUEST_400,null);
762 _version = HttpVersions.CACHE.getOrdinal(version);
763 if (_version <= 0) _version = HttpVersions.HTTP_1_0_ORDINAL;
764 _request.setProtocol(version.toString());
765 }
766 }
767 catch (Exception e)
768 {
769 LOG.debug(e);
770 if (e instanceof HttpException)
771 throw (HttpException)e;
772 throw new HttpException(HttpStatus.BAD_REQUEST_400,null,e);
773 }
774 }
775
776
777
778
779 @Override
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 switch(HttpHeaderValues.CACHE.getOrdinal(value))
793 {
794 case HttpHeaderValues.CONTINUE_ORDINAL:
795 _expect100Continue=_generator instanceof HttpGenerator;
796 break;
797
798 case HttpHeaderValues.PROCESSING_ORDINAL:
799 _expect102Processing=_generator instanceof HttpGenerator;
800 break;
801
802 default:
803 String[] values = value.toString().split(",");
804 for (int i=0;values!=null && i<values.length;i++)
805 {
806 CachedBuffer cb=HttpHeaderValues.CACHE.get(values[i].trim());
807 if (cb==null)
808 _expect=true;
809 else
810 {
811 switch(cb.getOrdinal())
812 {
813 case HttpHeaderValues.CONTINUE_ORDINAL:
814 _expect100Continue=_generator instanceof HttpGenerator;
815 break;
816 case HttpHeaderValues.PROCESSING_ORDINAL:
817 _expect102Processing=_generator instanceof HttpGenerator;
818 break;
819 default:
820 _expect=true;
821 }
822 }
823 }
824 }
825 break;
826
827 case HttpHeaders.ACCEPT_ENCODING_ORDINAL:
828 case HttpHeaders.USER_AGENT_ORDINAL:
829 value = HttpHeaderValues.CACHE.lookup(value);
830 break;
831
832 case HttpHeaders.CONTENT_TYPE_ORDINAL:
833 value = MimeTypes.CACHE.lookup(value);
834 _charset=MimeTypes.getCharsetFromContentType(value);
835 break;
836 }
837
838 _requestFields.add(name, value);
839 }
840
841
842
843
844 @Override
845 public void headerComplete() throws IOException
846 {
847 _requests++;
848 _generator.setVersion(_version);
849 switch (_version)
850 {
851 case HttpVersions.HTTP_0_9_ORDINAL:
852 break;
853 case HttpVersions.HTTP_1_0_ORDINAL:
854 _generator.setHead(_head);
855 if (_parser.isPersistent())
856 {
857 _responseFields.add(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.KEEP_ALIVE_BUFFER);
858 _generator.setPersistent(true);
859 }
860 else if (HttpMethods.CONNECT.equals(_request.getMethod()))
861 {
862 _generator.setPersistent(true);
863 _parser.setPersistent(true);
864 }
865
866 if (_server.getSendDateHeader())
867 _generator.setDate(_request.getTimeStampBuffer());
868 break;
869
870 case HttpVersions.HTTP_1_1_ORDINAL:
871 _generator.setHead(_head);
872
873 if (!_parser.isPersistent())
874 {
875 _responseFields.add(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.CLOSE_BUFFER);
876 _generator.setPersistent(false);
877 }
878 if (_server.getSendDateHeader())
879 _generator.setDate(_request.getTimeStampBuffer());
880
881 if (!_host)
882 {
883 LOG.debug("!host {}",this);
884 _generator.setResponse(HttpStatus.BAD_REQUEST_400, null);
885 _responseFields.put(HttpHeaders.CONNECTION_BUFFER, HttpHeaderValues.CLOSE_BUFFER);
886 _generator.completeHeader(_responseFields, true);
887 _generator.complete();
888 return;
889 }
890
891 if (_expect)
892 {
893 LOG.debug("!expectation {}",this);
894 _generator.setResponse(HttpStatus.EXPECTATION_FAILED_417, null);
895 _responseFields.put(HttpHeaders.CONNECTION_BUFFER, HttpHeaderValues.CLOSE_BUFFER);
896 _generator.completeHeader(_responseFields, true);
897 _generator.complete();
898 return;
899 }
900
901 break;
902 default:
903 }
904
905 if(_charset!=null)
906 _request.setCharacterEncodingUnchecked(_charset);
907
908
909 if ((((HttpParser)_parser).getContentLength()<=0 && !((HttpParser)_parser).isChunking())||_expect100Continue)
910 handleRequest();
911 else
912 _delayedHandling=true;
913 }
914
915
916
917
918
919 @Override
920 public void content(Buffer ref) throws IOException
921 {
922 if (_delayedHandling)
923 {
924 _delayedHandling=false;
925 handleRequest();
926 }
927 }
928
929
930
931
932
933
934
935 @Override
936 public void messageComplete(long contentLength) throws IOException
937 {
938 if (_delayedHandling)
939 {
940 _delayedHandling=false;
941 handleRequest();
942 }
943 }
944
945
946
947
948
949
950
951
952 @Override
953 public void startResponse(Buffer version, int status, Buffer reason)
954 {
955 if (LOG.isDebugEnabled())
956 LOG.debug("Bad request!: "+version+" "+status+" "+reason);
957 }
958
959 }
960
961
962
963
964
965 public class Output extends HttpOutput
966 {
967 Output()
968 {
969 super(AbstractHttpConnection.this);
970 }
971
972
973
974
975
976 @Override
977 public void close() throws IOException
978 {
979 if (isClosed())
980 return;
981
982 if (!isIncluding() && !super._generator.isCommitted())
983 commitResponse(Generator.LAST);
984 else
985 flushResponse();
986
987 super.close();
988 }
989
990
991
992
993
994
995 @Override
996 public void flush() throws IOException
997 {
998 if (!super._generator.isCommitted())
999 commitResponse(Generator.MORE);
1000 super.flush();
1001 }
1002
1003
1004
1005
1006
1007 @Override
1008 public void print(String s) throws IOException
1009 {
1010 if (isClosed())
1011 throw new IOException("Closed");
1012 PrintWriter writer=getPrintWriter(null);
1013 writer.print(s);
1014 }
1015
1016
1017 public void sendResponse(Buffer response) throws IOException
1018 {
1019 ((HttpGenerator)super._generator).sendResponse(response);
1020 }
1021
1022
1023 public void sendContent(Object content) throws IOException
1024 {
1025 Resource resource=null;
1026
1027 if (isClosed())
1028 throw new IOException("Closed");
1029
1030 if (super._generator.isWritten())
1031 throw new IllegalStateException("!empty");
1032
1033
1034 if (content instanceof HttpContent)
1035 {
1036 HttpContent httpContent = (HttpContent) content;
1037 Buffer contentType = httpContent.getContentType();
1038 if (contentType != null && !_responseFields.containsKey(HttpHeaders.CONTENT_TYPE_BUFFER))
1039 {
1040 String enc = _response.getSetCharacterEncoding();
1041 if(enc==null)
1042 _responseFields.add(HttpHeaders.CONTENT_TYPE_BUFFER, contentType);
1043 else
1044 {
1045 if(contentType instanceof CachedBuffer)
1046 {
1047 CachedBuffer content_type = ((CachedBuffer)contentType).getAssociate(enc);
1048 if(content_type!=null)
1049 _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER, content_type);
1050 else
1051 {
1052 _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER,
1053 contentType+";charset="+QuotedStringTokenizer.quoteIfNeeded(enc,";= "));
1054 }
1055 }
1056 else
1057 {
1058 _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER,
1059 contentType+";charset="+QuotedStringTokenizer.quoteIfNeeded(enc,";= "));
1060 }
1061 }
1062 }
1063 if (httpContent.getContentLength() > 0)
1064 _responseFields.putLongField(HttpHeaders.CONTENT_LENGTH_BUFFER, httpContent.getContentLength());
1065 Buffer lm = httpContent.getLastModified();
1066 long lml=httpContent.getResource().lastModified();
1067 if (lm != null)
1068 _responseFields.put(HttpHeaders.LAST_MODIFIED_BUFFER, lm);
1069 else if (httpContent.getResource()!=null)
1070 {
1071 if (lml!=-1)
1072 _responseFields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER, lml);
1073 }
1074
1075 boolean direct=_connector instanceof NIOConnector && ((NIOConnector)_connector).getUseDirectBuffers() && !(_connector instanceof SslConnector);
1076 content = direct?httpContent.getDirectBuffer():httpContent.getIndirectBuffer();
1077 if (content==null)
1078 content=httpContent.getInputStream();
1079 }
1080 else if (content instanceof Resource)
1081 {
1082 resource=(Resource)content;
1083 _responseFields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER, resource.lastModified());
1084 content=resource.getInputStream();
1085 }
1086
1087
1088 if (content instanceof Buffer)
1089 {
1090 super._generator.addContent((Buffer) content, Generator.LAST);
1091 commitResponse(Generator.LAST);
1092 }
1093 else if (content instanceof InputStream)
1094 {
1095 InputStream in = (InputStream)content;
1096
1097 try
1098 {
1099 int max = super._generator.prepareUncheckedAddContent();
1100 Buffer buffer = super._generator.getUncheckedBuffer();
1101
1102 int len=buffer.readFrom(in,max);
1103
1104 while (len>=0)
1105 {
1106 super._generator.completeUncheckedAddContent();
1107 _out.flush();
1108
1109 max = super._generator.prepareUncheckedAddContent();
1110 buffer = super._generator.getUncheckedBuffer();
1111 len=buffer.readFrom(in,max);
1112 }
1113 super._generator.completeUncheckedAddContent();
1114 _out.flush();
1115 }
1116 finally
1117 {
1118 if (resource!=null)
1119 resource.release();
1120 else
1121 in.close();
1122
1123 }
1124 }
1125 else
1126 throw new IllegalArgumentException("unknown content type?");
1127
1128
1129 }
1130 }
1131
1132
1133
1134
1135 public class OutputWriter extends HttpWriter
1136 {
1137 OutputWriter()
1138 {
1139 super(AbstractHttpConnection.this._out);
1140 }
1141 }
1142
1143
1144 }