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