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(((HttpParser)_parser),_connector.getMaxIdleTime());
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 _request.setHandled(true);
459 error=true;
460 }
461 catch (UncheckedIOException e)
462 {
463 async_exception=e;
464 LOG.debug(e);
465 _request.setHandled(true);
466 error=true;
467 }
468 catch (HttpException e)
469 {
470 LOG.debug(e);
471 _request.setHandled(true);
472 _response.sendError(e.getStatus(), e.getReason());
473 error=true;
474 }
475 catch (Throwable e)
476 {
477 if (e instanceof ThreadDeath)
478 throw (ThreadDeath)e;
479
480 async_exception=e;
481
482 error=true;
483 LOG.warn(String.valueOf(_uri),e);
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
501 _request._async.doComplete(async_exception);
502
503 if (_expect100Continue)
504 {
505 LOG.debug("100 continues not sent");
506
507
508
509
510 _expect100Continue = false;
511 if (!_response.isCommitted())
512 _generator.setPersistent(false);
513 }
514
515 if(_endp.isOpen())
516 {
517 if (error)
518 _endp.shutdownOutput();
519 else
520 {
521 if (!_response.isCommitted() && !_request.isHandled())
522 _response.sendError(HttpServletResponse.SC_NOT_FOUND);
523 _response.complete();
524 if (_generator.isPersistent())
525 _connector.persist(_endp);
526 }
527 }
528 else
529 {
530 _response.complete();
531 }
532
533 _request.setHandled(true);
534 }
535 }
536 }
537
538
539 public abstract Connection handle() throws IOException;
540
541
542 public void commitResponse(boolean last) throws IOException
543 {
544 if (!_generator.isCommitted())
545 {
546 _generator.setResponse(_response.getStatus(), _response.getReason());
547 try
548 {
549
550
551 if (_expect100Continue && _response.getStatus()!=100)
552 _generator.setPersistent(false);
553 _generator.completeHeader(_responseFields, last);
554 }
555 catch(IOException io)
556 {
557 throw io;
558 }
559 catch(RuntimeException e)
560 {
561 LOG.warn("header full: "+e);
562
563 _response.reset();
564 _generator.reset(true);
565 _generator.setResponse(HttpStatus.INTERNAL_SERVER_ERROR_500,null);
566 _generator.completeHeader(_responseFields,Generator.LAST);
567 _generator.complete();
568 throw new HttpException(HttpStatus.INTERNAL_SERVER_ERROR_500);
569 }
570
571 }
572 if (last)
573 _generator.complete();
574 }
575
576
577 public void completeResponse() throws IOException
578 {
579 if (!_generator.isCommitted())
580 {
581 _generator.setResponse(_response.getStatus(), _response.getReason());
582 try
583 {
584 _generator.completeHeader(_responseFields, Generator.LAST);
585 }
586 catch(IOException io)
587 {
588 throw io;
589 }
590 catch(RuntimeException e)
591 {
592 LOG.warn("header full: "+e);
593 LOG.debug(e);
594
595 _response.reset();
596 _generator.reset(true);
597 _generator.setResponse(HttpStatus.INTERNAL_SERVER_ERROR_500,null);
598 _generator.completeHeader(_responseFields,Generator.LAST);
599 _generator.complete();
600 throw new HttpException(HttpStatus.INTERNAL_SERVER_ERROR_500);
601 }
602 }
603
604 _generator.complete();
605 }
606
607
608 public void flushResponse() throws IOException
609 {
610 try
611 {
612 commitResponse(Generator.MORE);
613 _generator.flushBuffer();
614 }
615 catch(IOException e)
616 {
617 throw (e instanceof EofException) ? e:new EofException(e);
618 }
619 }
620
621
622 public Generator getGenerator()
623 {
624 return _generator;
625 }
626
627
628 public boolean isIncluding()
629 {
630 return _include>0;
631 }
632
633
634 public void include()
635 {
636 _include++;
637 }
638
639
640 public void included()
641 {
642 _include--;
643 if (_out!=null)
644 _out.reopen();
645 }
646
647
648 public boolean isIdle()
649 {
650 return _generator.isIdle() && (_parser.isIdle() || _delayedHandling);
651 }
652
653
654
655
656
657 public boolean isSuspended()
658 {
659 return _request.getAsyncContinuation().isSuspended();
660 }
661
662
663 public void closed()
664 {
665 LOG.debug("closed {}",this);
666 }
667
668
669 public boolean isExpecting100Continues()
670 {
671 return _expect100Continue;
672 }
673
674
675 public boolean isExpecting102Processing()
676 {
677 return _expect102Processing;
678 }
679
680
681
682
683 private class RequestHandler extends HttpParser.EventHandler
684 {
685 private String _charset;
686
687
688
689
690
691
692 @Override
693 public void startRequest(Buffer method, Buffer uri, Buffer version) throws IOException
694 {
695 uri=uri.asImmutableBuffer();
696
697 _host = false;
698 _expect = false;
699 _expect100Continue=false;
700 _expect102Processing=false;
701 _delayedHandling=false;
702 _charset=null;
703
704 if(_request.getTimeStamp()==0)
705 _request.setTimeStamp(System.currentTimeMillis());
706 _request.setMethod(method.toString());
707
708 try
709 {
710 _head=false;
711 switch (HttpMethods.CACHE.getOrdinal(method))
712 {
713 case HttpMethods.CONNECT_ORDINAL:
714 _uri.parseConnect(uri.array(), uri.getIndex(), uri.length());
715 break;
716
717 case HttpMethods.HEAD_ORDINAL:
718 _head=true;
719
720
721 default:
722 _uri.parse(uri.array(), uri.getIndex(), uri.length());
723 }
724
725 _request.setUri(_uri);
726
727 if (version==null)
728 {
729 _request.setProtocol(HttpVersions.HTTP_0_9);
730 _version=HttpVersions.HTTP_0_9_ORDINAL;
731 }
732 else
733 {
734 version= HttpVersions.CACHE.get(version);
735 if (version==null)
736 throw new HttpException(HttpStatus.BAD_REQUEST_400,null);
737 _version = HttpVersions.CACHE.getOrdinal(version);
738 if (_version <= 0) _version = HttpVersions.HTTP_1_0_ORDINAL;
739 _request.setProtocol(version.toString());
740 }
741 }
742 catch (Exception e)
743 {
744 LOG.debug(e);
745 if (e instanceof HttpException)
746 throw (HttpException)e;
747 throw new HttpException(HttpStatus.BAD_REQUEST_400,null,e);
748 }
749 }
750
751
752
753
754 @Override
755 public void parsedHeader(Buffer name, Buffer value)
756 {
757 int ho = HttpHeaders.CACHE.getOrdinal(name);
758 switch (ho)
759 {
760 case HttpHeaders.HOST_ORDINAL:
761
762 _host = true;
763 break;
764
765 case HttpHeaders.EXPECT_ORDINAL:
766 value = HttpHeaderValues.CACHE.lookup(value);
767 switch(HttpHeaderValues.CACHE.getOrdinal(value))
768 {
769 case HttpHeaderValues.CONTINUE_ORDINAL:
770 _expect100Continue=_generator instanceof HttpGenerator;
771 break;
772
773 case HttpHeaderValues.PROCESSING_ORDINAL:
774 _expect102Processing=_generator instanceof HttpGenerator;
775 break;
776
777 default:
778 String[] values = value.toString().split(",");
779 for (int i=0;values!=null && i<values.length;i++)
780 {
781 CachedBuffer cb=HttpHeaderValues.CACHE.get(values[i].trim());
782 if (cb==null)
783 _expect=true;
784 else
785 {
786 switch(cb.getOrdinal())
787 {
788 case HttpHeaderValues.CONTINUE_ORDINAL:
789 _expect100Continue=_generator instanceof HttpGenerator;
790 break;
791 case HttpHeaderValues.PROCESSING_ORDINAL:
792 _expect102Processing=_generator instanceof HttpGenerator;
793 break;
794 default:
795 _expect=true;
796 }
797 }
798 }
799 }
800 break;
801
802 case HttpHeaders.ACCEPT_ENCODING_ORDINAL:
803 case HttpHeaders.USER_AGENT_ORDINAL:
804 value = HttpHeaderValues.CACHE.lookup(value);
805 break;
806
807 case HttpHeaders.CONTENT_TYPE_ORDINAL:
808 value = MimeTypes.CACHE.lookup(value);
809 _charset=MimeTypes.getCharsetFromContentType(value);
810 break;
811
812 case HttpHeaders.CONNECTION_ORDINAL:
813
814 switch(HttpHeaderValues.CACHE.getOrdinal(value))
815 {
816 case -1:
817 {
818 String[] values = value.toString().split(",");
819 for (int i=0;values!=null && i<values.length;i++)
820 {
821 CachedBuffer cb = HttpHeaderValues.CACHE.get(values[i].trim());
822
823 if (cb!=null)
824 {
825 switch(cb.getOrdinal())
826 {
827 case HttpHeaderValues.CLOSE_ORDINAL:
828 _responseFields.add(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.CLOSE_BUFFER);
829 _generator.setPersistent(false);
830 break;
831
832 case HttpHeaderValues.KEEP_ALIVE_ORDINAL:
833 if (_version==HttpVersions.HTTP_1_0_ORDINAL)
834 _responseFields.add(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.KEEP_ALIVE_BUFFER);
835 break;
836 }
837 }
838 }
839 break;
840 }
841 case HttpHeaderValues.CLOSE_ORDINAL:
842 _responseFields.put(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.put(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.KEEP_ALIVE_BUFFER);
849 break;
850 }
851 }
852
853 _requestFields.add(name, value);
854 }
855
856
857
858
859 @Override
860 public void headerComplete() throws IOException
861 {
862 if (_endp instanceof AsyncEndPoint)
863 ((AsyncEndPoint)_endp).scheduleIdle();
864 _requests++;
865 _generator.setVersion(_version);
866 switch (_version)
867 {
868 case HttpVersions.HTTP_0_9_ORDINAL:
869 break;
870 case HttpVersions.HTTP_1_0_ORDINAL:
871 _generator.setHead(_head);
872
873 if (_server.getSendDateHeader())
874 _generator.setDate(_request.getTimeStampBuffer());
875
876 break;
877 case HttpVersions.HTTP_1_1_ORDINAL:
878 _generator.setHead(_head);
879
880 if (_server.getSendDateHeader())
881 _generator.setDate(_request.getTimeStampBuffer());
882
883 if (!_host)
884 {
885 _generator.setResponse(HttpStatus.BAD_REQUEST_400, null);
886 _responseFields.put(HttpHeaders.CONNECTION_BUFFER, HttpHeaderValues.CLOSE_BUFFER);
887 _generator.completeHeader(_responseFields, true);
888 _generator.complete();
889 return;
890 }
891
892 if (_expect)
893 {
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 (_endp instanceof AsyncEndPoint)
923 ((AsyncEndPoint)_endp).scheduleIdle();
924 if (_delayedHandling)
925 {
926 _delayedHandling=false;
927 handleRequest();
928 }
929 }
930
931
932
933
934
935
936
937 @Override
938 public void messageComplete(long contentLength) throws IOException
939 {
940 if (_delayedHandling)
941 {
942 _delayedHandling=false;
943 handleRequest();
944 }
945 }
946
947
948
949
950
951
952
953
954 @Override
955 public void startResponse(Buffer version, int status, Buffer reason)
956 {
957 LOG.debug("Bad request!: "+version+" "+status+" "+reason);
958 }
959 }
960
961
962
963
964
965 public class Output extends HttpOutput
966 {
967 Output()
968 {
969 super((AbstractGenerator)HttpConnection.this._generator,
970 _connector.isLowResources()?_connector.getLowResourceMaxIdleTime():_connector.getMaxIdleTime());
971 }
972
973
974
975
976
977 @Override
978 public void close() throws IOException
979 {
980 if (isClosed())
981 return;
982
983 if (!isIncluding() && !super._generator.isCommitted())
984 commitResponse(Generator.LAST);
985 else
986 flushResponse();
987
988 super.close();
989 }
990
991
992
993
994
995
996 @Override
997 public void flush() throws IOException
998 {
999 if (!super._generator.isCommitted())
1000 commitResponse(Generator.MORE);
1001 super.flush();
1002 }
1003
1004
1005
1006
1007
1008 @Override
1009 public void print(String s) throws IOException
1010 {
1011 if (isClosed())
1012 throw new IOException("Closed");
1013 PrintWriter writer=getPrintWriter(null);
1014 writer.print(s);
1015 }
1016
1017
1018 public void sendResponse(Buffer response) throws IOException
1019 {
1020 ((HttpGenerator)super._generator).sendResponse(response);
1021 }
1022
1023
1024 public void sendContent(Object content) throws IOException
1025 {
1026 Resource resource=null;
1027
1028 if (isClosed())
1029 throw new IOException("Closed");
1030
1031 if (super._generator.isWritten())
1032 throw new IllegalStateException("!empty");
1033
1034
1035 if (content instanceof HttpContent)
1036 {
1037 HttpContent httpContent = (HttpContent) content;
1038 Buffer contentType = httpContent.getContentType();
1039 if (contentType != null && !_responseFields.containsKey(HttpHeaders.CONTENT_TYPE_BUFFER))
1040 {
1041 String enc = _response.getSetCharacterEncoding();
1042 if(enc==null)
1043 _responseFields.add(HttpHeaders.CONTENT_TYPE_BUFFER, contentType);
1044 else
1045 {
1046 if(contentType instanceof CachedBuffer)
1047 {
1048 CachedBuffer content_type = ((CachedBuffer)contentType).getAssociate(enc);
1049 if(content_type!=null)
1050 _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER, content_type);
1051 else
1052 {
1053 _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER,
1054 contentType+";charset="+QuotedStringTokenizer.quoteIfNeeded(enc,";= "));
1055 }
1056 }
1057 else
1058 {
1059 _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER,
1060 contentType+";charset="+QuotedStringTokenizer.quoteIfNeeded(enc,";= "));
1061 }
1062 }
1063 }
1064 if (httpContent.getContentLength() > 0)
1065 _responseFields.putLongField(HttpHeaders.CONTENT_LENGTH_BUFFER, httpContent.getContentLength());
1066 Buffer lm = httpContent.getLastModified();
1067 long lml=httpContent.getResource().lastModified();
1068 if (lm != null)
1069 _responseFields.put(HttpHeaders.LAST_MODIFIED_BUFFER, lm);
1070 else if (httpContent.getResource()!=null)
1071 {
1072 if (lml!=-1)
1073 _responseFields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER, lml);
1074 }
1075
1076 boolean direct=_connector instanceof NIOConnector && ((NIOConnector)_connector).getUseDirectBuffers() && !(_connector instanceof SslConnector);
1077 content = direct?httpContent.getDirectBuffer():httpContent.getIndirectBuffer();
1078 if (content==null)
1079 content=httpContent.getInputStream();
1080 }
1081 else if (content instanceof Resource)
1082 {
1083 resource=(Resource)content;
1084 _responseFields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER, resource.lastModified());
1085 content=resource.getInputStream();
1086 }
1087
1088
1089 if (content instanceof Buffer)
1090 {
1091 super._generator.addContent((Buffer) content, Generator.LAST);
1092 commitResponse(Generator.LAST);
1093 }
1094 else if (content instanceof InputStream)
1095 {
1096 InputStream in = (InputStream)content;
1097
1098 try
1099 {
1100 int max = super._generator.prepareUncheckedAddContent();
1101 Buffer buffer = super._generator.getUncheckedBuffer();
1102
1103 int len=buffer.readFrom(in,max);
1104
1105 while (len>=0)
1106 {
1107 super._generator.completeUncheckedAddContent();
1108 _out.flush();
1109
1110 max = super._generator.prepareUncheckedAddContent();
1111 buffer = super._generator.getUncheckedBuffer();
1112 len=buffer.readFrom(in,max);
1113 }
1114 super._generator.completeUncheckedAddContent();
1115 _out.flush();
1116 }
1117 finally
1118 {
1119 if (resource!=null)
1120 resource.release();
1121 else
1122 in.close();
1123
1124 }
1125 }
1126 else
1127 throw new IllegalArgumentException("unknown content type?");
1128
1129
1130 }
1131 }
1132
1133
1134
1135
1136 public class OutputWriter extends HttpWriter
1137 {
1138 OutputWriter()
1139 {
1140 super(HttpConnection.this._out);
1141 }
1142 }
1143
1144
1145 }