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