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