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.PrintWriter;
23 import java.nio.channels.IllegalSelectorException;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.Enumeration;
28 import java.util.Locale;
29 import java.util.concurrent.atomic.AtomicInteger;
30
31 import javax.servlet.RequestDispatcher;
32 import javax.servlet.ServletOutputStream;
33 import javax.servlet.http.Cookie;
34 import javax.servlet.http.HttpServletResponse;
35 import javax.servlet.http.HttpSession;
36
37 import org.eclipse.jetty.http.HttpCookie;
38 import org.eclipse.jetty.http.HttpField;
39 import org.eclipse.jetty.http.HttpFields;
40 import org.eclipse.jetty.http.HttpGenerator;
41 import org.eclipse.jetty.http.HttpGenerator.ResponseInfo;
42 import org.eclipse.jetty.http.HttpHeader;
43 import org.eclipse.jetty.http.HttpHeaderValue;
44 import org.eclipse.jetty.http.HttpScheme;
45 import org.eclipse.jetty.http.HttpStatus;
46 import org.eclipse.jetty.http.HttpURI;
47 import org.eclipse.jetty.http.HttpVersion;
48 import org.eclipse.jetty.http.MimeTypes;
49 import org.eclipse.jetty.io.RuntimeIOException;
50 import org.eclipse.jetty.server.handler.ContextHandler;
51 import org.eclipse.jetty.server.handler.ErrorHandler;
52 import org.eclipse.jetty.util.ByteArrayISO8859Writer;
53 import org.eclipse.jetty.util.StringUtil;
54 import org.eclipse.jetty.util.URIUtil;
55 import org.eclipse.jetty.util.log.Log;
56 import org.eclipse.jetty.util.log.Logger;
57
58
59
60
61 public class Response implements HttpServletResponse
62 {
63 private static final Logger LOG = Log.getLogger(Response.class);
64
65
66 public static Response getResponse(HttpServletResponse response)
67 {
68 if (response instanceof Response)
69 return (Response)response;
70 return HttpChannel.getCurrentHttpChannel().getResponse();
71 }
72
73
74 public enum OutputType
75 {
76 NONE, STREAM, WRITER
77 }
78
79
80
81
82
83
84 public final static String SET_INCLUDE_HEADER_PREFIX = "org.eclipse.jetty.server.include.";
85
86
87
88
89
90 public final static String HTTP_ONLY_COMMENT = "__HTTP_ONLY__";
91
92 private final HttpChannel<?> _channel;
93 private final HttpOutput _out;
94 private final HttpFields _fields = new HttpFields();
95 private final AtomicInteger _include = new AtomicInteger();
96 private int _status = HttpStatus.NOT_SET_000;
97 private String _reason;
98 private Locale _locale;
99 private MimeTypes.Type _mimeType;
100 private String _characterEncoding;
101 private String _contentType;
102 private OutputType _outputType = OutputType.NONE;
103 private ResponseWriter _writer;
104 private long _contentLength = -1;
105
106
107 public Response(HttpChannel<?> channel, HttpOutput out)
108 {
109 _channel = channel;
110 _out = out;
111 }
112
113 protected HttpChannel<?> getHttpChannel()
114 {
115 return _channel;
116 }
117
118 protected void recycle()
119 {
120 _status = HttpStatus.NOT_SET_000;
121 _reason = null;
122 _locale = null;
123 _mimeType = null;
124 _characterEncoding = null;
125 _contentType = null;
126 _outputType = OutputType.NONE;
127 _contentLength = -1;
128 _out.reset();
129 _fields.clear();
130 }
131
132 public HttpOutput getHttpOutput()
133 {
134 return _out;
135 }
136
137 public boolean isIncluding()
138 {
139 return _include.get() > 0;
140 }
141
142 public void include()
143 {
144 _include.incrementAndGet();
145 }
146
147 public void included()
148 {
149 _include.decrementAndGet();
150 _out.reopen();
151 }
152
153 public void addCookie(HttpCookie cookie)
154 {
155 _fields.addSetCookie(cookie);
156 }
157
158 @Override
159 public void addCookie(Cookie cookie)
160 {
161 String comment = cookie.getComment();
162 boolean httpOnly = false;
163
164 if (comment != null)
165 {
166 int i = comment.indexOf(HTTP_ONLY_COMMENT);
167 if (i >= 0)
168 {
169 httpOnly = true;
170 comment = comment.replace(HTTP_ONLY_COMMENT, "").trim();
171 if (comment.length() == 0)
172 comment = null;
173 }
174 }
175 _fields.addSetCookie(cookie.getName(),
176 cookie.getValue(),
177 cookie.getDomain(),
178 cookie.getPath(),
179 cookie.getMaxAge(),
180 comment,
181 cookie.getSecure(),
182 httpOnly || cookie.isHttpOnly(),
183 cookie.getVersion());
184 }
185
186 @Override
187 public boolean containsHeader(String name)
188 {
189 return _fields.containsKey(name);
190 }
191
192 @Override
193 public String encodeURL(String url)
194 {
195 final Request request = _channel.getRequest();
196 SessionManager sessionManager = request.getSessionManager();
197 if (sessionManager == null)
198 return url;
199
200 HttpURI uri = null;
201 if (sessionManager.isCheckingRemoteSessionIdEncoding() && URIUtil.hasScheme(url))
202 {
203 uri = new HttpURI(url);
204 String path = uri.getPath();
205 path = (path == null ? "" : path);
206 int port = uri.getPort();
207 if (port < 0)
208 port = HttpScheme.HTTPS.asString().equalsIgnoreCase(uri.getScheme()) ? 443 : 80;
209 if (!request.getServerName().equalsIgnoreCase(uri.getHost()) ||
210 request.getServerPort() != port ||
211 !path.startsWith(request.getContextPath()))
212 return url;
213 }
214
215 String sessionURLPrefix = sessionManager.getSessionIdPathParameterNamePrefix();
216 if (sessionURLPrefix == null)
217 return url;
218
219 if (url == null)
220 return null;
221
222
223 if (request.isRequestedSessionIdFromCookie())
224 {
225 int prefix = url.indexOf(sessionURLPrefix);
226 if (prefix != -1)
227 {
228 int suffix = url.indexOf("?", prefix);
229 if (suffix < 0)
230 suffix = url.indexOf("#", prefix);
231
232 if (suffix <= prefix)
233 return url.substring(0, prefix);
234 return url.substring(0, prefix) + url.substring(suffix);
235 }
236 return url;
237 }
238
239
240 HttpSession session = request.getSession(false);
241
242
243 if (session == null)
244 return url;
245
246
247 if (!sessionManager.isValid(session))
248 return url;
249
250 String id = sessionManager.getNodeId(session);
251
252 if (uri == null)
253 uri = new HttpURI(url);
254
255
256
257 int prefix = url.indexOf(sessionURLPrefix);
258 if (prefix != -1)
259 {
260 int suffix = url.indexOf("?", prefix);
261 if (suffix < 0)
262 suffix = url.indexOf("#", prefix);
263
264 if (suffix <= prefix)
265 return url.substring(0, prefix + sessionURLPrefix.length()) + id;
266 return url.substring(0, prefix + sessionURLPrefix.length()) + id +
267 url.substring(suffix);
268 }
269
270
271 int suffix = url.indexOf('?');
272 if (suffix < 0)
273 suffix = url.indexOf('#');
274 if (suffix < 0)
275 {
276 return url +
277 ((HttpScheme.HTTPS.is(uri.getScheme()) || HttpScheme.HTTP.is(uri.getScheme())) && uri.getPath() == null ? "/" : "") +
278 sessionURLPrefix + id;
279 }
280
281
282 return url.substring(0, suffix) +
283 ((HttpScheme.HTTPS.is(uri.getScheme()) || HttpScheme.HTTP.is(uri.getScheme())) && uri.getPath() == null ? "/" : "") +
284 sessionURLPrefix + id + url.substring(suffix);
285 }
286
287 @Override
288 public String encodeRedirectURL(String url)
289 {
290 return encodeURL(url);
291 }
292
293 @Override
294 @Deprecated
295 public String encodeUrl(String url)
296 {
297 return encodeURL(url);
298 }
299
300 @Override
301 @Deprecated
302 public String encodeRedirectUrl(String url)
303 {
304 return encodeRedirectURL(url);
305 }
306
307 @Override
308 public void sendError(int sc) throws IOException
309 {
310 if (sc == 102)
311 sendProcessing();
312 else
313 sendError(sc, null);
314 }
315
316 @Override
317 public void sendError(int code, String message) throws IOException
318 {
319 if (isIncluding())
320 return;
321
322 if (isCommitted())
323 LOG.warn("Committed before "+code+" "+message);
324
325 resetBuffer();
326 _characterEncoding=null;
327 setHeader(HttpHeader.EXPIRES,null);
328 setHeader(HttpHeader.LAST_MODIFIED,null);
329 setHeader(HttpHeader.CACHE_CONTROL,null);
330 setHeader(HttpHeader.CONTENT_TYPE,null);
331 setHeader(HttpHeader.CONTENT_LENGTH,null);
332
333 _outputType = OutputType.NONE;
334 setStatus(code);
335 _reason=message;
336
337 if (message==null)
338 message=HttpStatus.getMessage(code);
339
340
341 if (code!=SC_NO_CONTENT &&
342 code!=SC_NOT_MODIFIED &&
343 code!=SC_PARTIAL_CONTENT &&
344 code>=SC_OK)
345 {
346 Request request = _channel.getRequest();
347
348 ErrorHandler error_handler = null;
349 ContextHandler.Context context = request.getContext();
350 if (context!=null)
351 error_handler=context.getContextHandler().getErrorHandler();
352 if (error_handler==null)
353 error_handler = _channel.getServer().getBean(ErrorHandler.class);
354 if (error_handler!=null)
355 {
356 request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,new Integer(code));
357 request.setAttribute(RequestDispatcher.ERROR_MESSAGE, message);
358 request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI, request.getRequestURI());
359 request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME,request.getServletName());
360 error_handler.handle(null,_channel.getRequest(),_channel.getRequest(),this );
361 }
362 else
363 {
364 setHeader(HttpHeader.CACHE_CONTROL, "must-revalidate,no-cache,no-store");
365 setContentType(MimeTypes.Type.TEXT_HTML_8859_1.toString());
366 ByteArrayISO8859Writer writer= new ByteArrayISO8859Writer(2048);
367 if (message != null)
368 {
369 message= StringUtil.replace(message, "&", "&");
370 message= StringUtil.replace(message, "<", "<");
371 message= StringUtil.replace(message, ">", ">");
372 }
373 String uri= request.getRequestURI();
374 if (uri!=null)
375 {
376 uri= StringUtil.replace(uri, "&", "&");
377 uri= StringUtil.replace(uri, "<", "<");
378 uri= StringUtil.replace(uri, ">", ">");
379 }
380
381 writer.write("<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html;charset=ISO-8859-1\"/>\n");
382 writer.write("<title>Error ");
383 writer.write(Integer.toString(code));
384 writer.write(' ');
385 if (message==null)
386 message=HttpStatus.getMessage(code);
387 writer.write(message);
388 writer.write("</title>\n</head>\n<body>\n<h2>HTTP ERROR: ");
389 writer.write(Integer.toString(code));
390 writer.write("</h2>\n<p>Problem accessing ");
391 writer.write(uri);
392 writer.write(". Reason:\n<pre> ");
393 writer.write(message);
394 writer.write("</pre>");
395 writer.write("</p>\n<hr /><i><small>Powered by Jetty://</small></i>");
396 writer.write("\n</body>\n</html>\n");
397
398 writer.flush();
399 setContentLength(writer.size());
400 writer.writeTo(getOutputStream());
401 writer.destroy();
402 }
403 }
404 else if (code!=SC_PARTIAL_CONTENT)
405 {
406
407 _channel.getRequest().getHttpFields().remove(HttpHeader.CONTENT_TYPE);
408 _channel.getRequest().getHttpFields().remove(HttpHeader.CONTENT_LENGTH);
409 _characterEncoding=null;
410 _mimeType=null;
411 }
412
413 complete();
414 }
415
416
417
418
419
420
421
422
423
424 public void sendProcessing() throws IOException
425 {
426 if (_channel.isExpecting102Processing() && !isCommitted())
427 {
428 _channel.commitResponse(HttpGenerator.PROGRESS_102_INFO, null, true);
429 }
430 }
431
432 @Override
433 public void sendRedirect(String location) throws IOException
434 {
435 if (isIncluding())
436 return;
437
438 if (location == null)
439 throw new IllegalArgumentException();
440
441 if (!URIUtil.hasScheme(location))
442 {
443 StringBuilder buf = _channel.getRequest().getRootURL();
444 if (location.startsWith("/"))
445 buf.append(location);
446 else
447 {
448 String path = _channel.getRequest().getRequestURI();
449 String parent = (path.endsWith("/")) ? path : URIUtil.parentPath(path);
450 location = URIUtil.addPaths(parent, location);
451 if (location == null)
452 throw new IllegalStateException("path cannot be above root");
453 if (!location.startsWith("/"))
454 buf.append('/');
455 buf.append(location);
456 }
457
458 location = buf.toString();
459 HttpURI uri = new HttpURI(location);
460 String path = uri.getDecodedPath();
461 String canonical = URIUtil.canonicalPath(path);
462 if (canonical == null)
463 throw new IllegalArgumentException();
464 if (!canonical.equals(path))
465 {
466 buf = _channel.getRequest().getRootURL();
467 buf.append(URIUtil.encodePath(canonical));
468 String param=uri.getParam();
469 if (param!=null)
470 {
471 buf.append(';');
472 buf.append(param);
473 }
474 String query=uri.getQuery();
475 if (query!=null)
476 {
477 buf.append('?');
478 buf.append(query);
479 }
480 String fragment=uri.getFragment();
481 if (fragment!=null)
482 {
483 buf.append('#');
484 buf.append(fragment);
485 }
486 location = buf.toString();
487 }
488 }
489
490 resetBuffer();
491 setHeader(HttpHeader.LOCATION, location);
492 setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
493 complete();
494 }
495
496 @Override
497 public void setDateHeader(String name, long date)
498 {
499 if (!isIncluding())
500 _fields.putDateField(name, date);
501 }
502
503 @Override
504 public void addDateHeader(String name, long date)
505 {
506 if (!isIncluding())
507 _fields.addDateField(name, date);
508 }
509
510 public void setHeader(HttpHeader name, String value)
511 {
512 if (HttpHeader.CONTENT_TYPE == name)
513 setContentType(value);
514 else
515 {
516 if (isIncluding())
517 return;
518
519 _fields.put(name, value);
520
521 if (HttpHeader.CONTENT_LENGTH == name)
522 {
523 if (value == null)
524 _contentLength = -1l;
525 else
526 _contentLength = Long.parseLong(value);
527 }
528 }
529 }
530
531 @Override
532 public void setHeader(String name, String value)
533 {
534 if (HttpHeader.CONTENT_TYPE.is(name))
535 setContentType(value);
536 else
537 {
538 if (isIncluding())
539 {
540 if (name.startsWith(SET_INCLUDE_HEADER_PREFIX))
541 name = name.substring(SET_INCLUDE_HEADER_PREFIX.length());
542 else
543 return;
544 }
545 _fields.put(name, value);
546 if (HttpHeader.CONTENT_LENGTH.is(name))
547 {
548 if (value == null)
549 _contentLength = -1l;
550 else
551 _contentLength = Long.parseLong(value);
552 }
553 }
554 }
555
556 @Override
557 public Collection<String> getHeaderNames()
558 {
559 final HttpFields fields = _fields;
560 return fields.getFieldNamesCollection();
561 }
562
563 @Override
564 public String getHeader(String name)
565 {
566 return _fields.getStringField(name);
567 }
568
569 @Override
570 public Collection<String> getHeaders(String name)
571 {
572 final HttpFields fields = _fields;
573 Collection<String> i = fields.getValuesCollection(name);
574 if (i == null)
575 return Collections.emptyList();
576 return i;
577 }
578
579 @Override
580 public void addHeader(String name, String value)
581 {
582 if (isIncluding())
583 {
584 if (name.startsWith(SET_INCLUDE_HEADER_PREFIX))
585 name = name.substring(SET_INCLUDE_HEADER_PREFIX.length());
586 else
587 return;
588 }
589
590 _fields.add(name, value);
591 if (HttpHeader.CONTENT_LENGTH.is(name))
592 {
593 if (value == null)
594 _contentLength = -1l;
595 else
596 _contentLength = Long.parseLong(value);
597 }
598 }
599
600 @Override
601 public void setIntHeader(String name, int value)
602 {
603 if (!isIncluding())
604 {
605 _fields.putLongField(name, value);
606 if (HttpHeader.CONTENT_LENGTH.is(name))
607 _contentLength = value;
608 }
609 }
610
611 @Override
612 public void addIntHeader(String name, int value)
613 {
614 if (!isIncluding())
615 {
616 _fields.add(name, Integer.toString(value));
617 if (HttpHeader.CONTENT_LENGTH.is(name))
618 _contentLength = value;
619 }
620 }
621
622 @Override
623 public void setStatus(int sc)
624 {
625 if (sc <= 0)
626 throw new IllegalArgumentException();
627 if (!isIncluding())
628 _status = sc;
629 }
630
631 @Override
632 @Deprecated
633 public void setStatus(int sc, String sm)
634 {
635 if (sc <= 0)
636 throw new IllegalArgumentException();
637 if (!isIncluding())
638 {
639 _status = sc;
640 _reason = sm;
641 }
642 }
643
644 @Override
645 public String getCharacterEncoding()
646 {
647 if (_characterEncoding == null)
648 _characterEncoding = StringUtil.__ISO_8859_1;
649 return _characterEncoding;
650 }
651
652 @Override
653 public String getContentType()
654 {
655 return _contentType;
656 }
657
658 @Override
659 public ServletOutputStream getOutputStream() throws IOException
660 {
661 if (_outputType == OutputType.WRITER)
662 throw new IllegalStateException("WRITER");
663 _outputType = OutputType.STREAM;
664 return _out;
665 }
666
667 public boolean isWriting()
668 {
669 return _outputType == OutputType.WRITER;
670 }
671
672 @Override
673 public PrintWriter getWriter() throws IOException
674 {
675 if (_outputType == OutputType.STREAM)
676 throw new IllegalStateException("STREAM");
677
678 if (_outputType == OutputType.NONE)
679 {
680
681 String encoding = _characterEncoding;
682 if (encoding == null)
683 {
684 encoding = MimeTypes.inferCharsetFromContentType(_contentType);
685 if (encoding == null)
686 encoding = StringUtil.__ISO_8859_1;
687 setCharacterEncoding(encoding);
688 }
689
690 if (_writer != null && _writer.isFor(encoding))
691 _writer.reopen();
692 else
693 {
694 if (StringUtil.__ISO_8859_1.equalsIgnoreCase(encoding))
695 _writer = new ResponseWriter(new Iso88591HttpWriter(_out),encoding);
696 else if (StringUtil.__UTF8.equalsIgnoreCase(encoding))
697 _writer = new ResponseWriter(new Utf8HttpWriter(_out),encoding);
698 else
699 _writer = new ResponseWriter(new EncodingHttpWriter(_out, encoding),encoding);
700 }
701
702
703 _outputType = OutputType.WRITER;
704 }
705 return _writer;
706 }
707
708 @Override
709 public void setContentLength(int len)
710 {
711
712
713
714 if (isCommitted() || isIncluding())
715 return;
716
717 long written = _out.getWritten();
718 if (written > len)
719 throw new IllegalArgumentException("setContentLength(" + len + ") when already written " + written);
720
721 _contentLength = len;
722 _fields.putLongField(HttpHeader.CONTENT_LENGTH.toString(), len);
723
724 if (_contentLength > 0)
725 {
726 try
727 {
728 closeIfAllContentWritten(written);
729 }
730 catch(IOException e)
731 {
732 throw new RuntimeIOException(e);
733 }
734 }
735 }
736
737 public boolean closeIfAllContentWritten(long written) throws IOException
738 {
739 if (_contentLength >= 0 && written >= _contentLength)
740 {
741 switch (_outputType)
742 {
743 case WRITER:
744 _writer.close();
745 break;
746 case STREAM:
747 getOutputStream().close();
748 }
749 return true;
750 }
751 return false;
752 }
753
754 public long getLongContentLength()
755 {
756 return _contentLength;
757 }
758
759 public void setLongContentLength(long len)
760 {
761
762
763
764 if (isCommitted() || isIncluding())
765 return;
766 _contentLength = len;
767 _fields.putLongField(HttpHeader.CONTENT_LENGTH.toString(), len);
768 }
769
770 @Override
771 public void setCharacterEncoding(String encoding)
772 {
773 if (isIncluding())
774 return;
775
776 if (_outputType == OutputType.NONE && !isCommitted())
777 {
778 if (encoding == null)
779 {
780
781 if (_characterEncoding != null)
782 {
783 _characterEncoding = null;
784 if (_contentType != null)
785 {
786 _contentType = MimeTypes.getContentTypeWithoutCharset(_contentType);
787 HttpField field = HttpField.CONTENT_TYPE.get(_contentType);
788 if (field!=null)
789 _fields.put(field);
790 else
791 _fields.put(HttpHeader.CONTENT_TYPE, _contentType);
792 }
793 }
794 }
795 else
796 {
797
798 _characterEncoding = StringUtil.normalizeCharset(encoding);
799 if (_contentType != null)
800 {
801 _contentType = MimeTypes.getContentTypeWithoutCharset(_contentType) + ";charset=" + _characterEncoding;
802 HttpField field = HttpField.CONTENT_TYPE.get(_contentType);
803 if (field!=null)
804 _fields.put(field);
805 else
806 _fields.put(HttpHeader.CONTENT_TYPE, _contentType);
807 }
808 }
809 }
810 }
811
812 @Override
813 public void setContentType(String contentType)
814 {
815 if (isCommitted() || isIncluding())
816 return;
817
818 if (contentType == null)
819 {
820 if (isWriting() && _characterEncoding != null)
821 throw new IllegalSelectorException();
822
823 if (_locale == null)
824 _characterEncoding = null;
825 _mimeType = null;
826 _contentType = null;
827 _fields.remove(HttpHeader.CONTENT_TYPE);
828 }
829 else
830 {
831 _contentType = contentType;
832 _mimeType = MimeTypes.CACHE.get(contentType);
833 String charset;
834 if (_mimeType != null && _mimeType.getCharset() != null)
835 charset = _mimeType.getCharset().toString();
836 else
837 charset = MimeTypes.getCharsetFromContentType(contentType);
838
839 if (charset == null)
840 {
841 if (_characterEncoding != null)
842 {
843 _contentType = contentType + ";charset=" + _characterEncoding;
844 _mimeType = null;
845 }
846 }
847 else if (isWriting() && !charset.equals(_characterEncoding))
848 {
849
850 _mimeType = null;
851 _contentType = MimeTypes.getContentTypeWithoutCharset(_contentType);
852 if (_characterEncoding != null)
853 _contentType = _contentType + ";charset=" + _characterEncoding;
854 }
855 else
856 {
857 _characterEncoding = charset;
858 }
859
860 HttpField field = HttpField.CONTENT_TYPE.get(_contentType);
861 if (field!=null)
862 _fields.put(field);
863 else
864 _fields.put(HttpHeader.CONTENT_TYPE, _contentType);
865 }
866 }
867
868 @Override
869 public void setBufferSize(int size)
870 {
871 if (isCommitted() || getContentCount() > 0)
872 throw new IllegalStateException("Committed or content written");
873 _out.setBufferSize(size);
874 }
875
876 @Override
877 public int getBufferSize()
878 {
879 return _out.getBufferSize();
880 }
881
882 @Override
883 public void flushBuffer() throws IOException
884 {
885 if (!_out.isClosed())
886 _out.flush();
887 }
888
889 @Override
890 public void reset()
891 {
892 resetForForward();
893 _status = 200;
894 _reason = null;
895 _contentLength = -1;
896 _fields.clear();
897
898 String connection = _channel.getRequest().getHttpFields().getStringField(HttpHeader.CONNECTION);
899 if (connection != null)
900 {
901 String[] values = connection.split(",");
902 for (int i = 0; values != null && i < values.length; i++)
903 {
904 HttpHeaderValue cb = HttpHeaderValue.CACHE.get(values[0].trim());
905
906 if (cb != null)
907 {
908 switch (cb)
909 {
910 case CLOSE:
911 _fields.put(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.toString());
912 break;
913
914 case KEEP_ALIVE:
915 if (HttpVersion.HTTP_1_0.is(_channel.getRequest().getProtocol()))
916 _fields.put(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.toString());
917 break;
918 case TE:
919 _fields.put(HttpHeader.CONNECTION, HttpHeaderValue.TE.toString());
920 break;
921 }
922 }
923 }
924 }
925 }
926
927 public void reset(boolean preserveCookies)
928 {
929 if (!preserveCookies)
930 reset();
931 else
932 {
933 ArrayList<String> cookieValues = new ArrayList<String>(5);
934 Enumeration<String> vals = _fields.getValues(HttpHeader.SET_COOKIE.asString());
935 while (vals.hasMoreElements())
936 cookieValues.add(vals.nextElement());
937 reset();
938 for (String v:cookieValues)
939 _fields.add(HttpHeader.SET_COOKIE, v);
940 }
941 }
942
943 public void resetForForward()
944 {
945 resetBuffer();
946 _outputType = OutputType.NONE;
947 }
948
949 @Override
950 public void resetBuffer()
951 {
952 if (isCommitted())
953 throw new IllegalStateException("Committed");
954
955 switch (_outputType)
956 {
957 case STREAM:
958 case WRITER:
959 _out.reset();
960 }
961
962 _out.resetBuffer();
963 }
964
965 protected ResponseInfo newResponseInfo()
966 {
967 if (_status == HttpStatus.NOT_SET_000)
968 _status = HttpStatus.OK_200;
969 return new ResponseInfo(_channel.getRequest().getHttpVersion(), _fields, getLongContentLength(), getStatus(), getReason(), _channel.getRequest().isHead());
970 }
971
972 @Override
973 public boolean isCommitted()
974 {
975 return _channel.isCommitted();
976 }
977
978 @Override
979 public void setLocale(Locale locale)
980 {
981 if (locale == null || isCommitted() || isIncluding())
982 return;
983
984 _locale = locale;
985 _fields.put(HttpHeader.CONTENT_LANGUAGE, locale.toString().replace('_', '-'));
986
987 if (_outputType != OutputType.NONE)
988 return;
989
990 if (_channel.getRequest().getContext() == null)
991 return;
992
993 String charset = _channel.getRequest().getContext().getContextHandler().getLocaleEncoding(locale);
994
995 if (charset != null && charset.length() > 0 && _characterEncoding == null)
996 setCharacterEncoding(charset);
997 }
998
999 @Override
1000 public Locale getLocale()
1001 {
1002 if (_locale == null)
1003 return Locale.getDefault();
1004 return _locale;
1005 }
1006
1007 @Override
1008 public int getStatus()
1009 {
1010 return _status;
1011 }
1012
1013 public String getReason()
1014 {
1015 return _reason;
1016 }
1017
1018 public void complete() throws IOException
1019 {
1020 _out.close();
1021 }
1022
1023 public HttpFields getHttpFields()
1024 {
1025 return _fields;
1026 }
1027
1028 public long getContentCount()
1029 {
1030 return _out.getWritten();
1031 }
1032
1033 @Override
1034 public String toString()
1035 {
1036 return String.format("%s %d %s%n%s", _channel.getRequest().getHttpVersion(), _status, _reason == null ? "" : _reason, _fields);
1037 }
1038
1039
1040 private static class ResponseWriter extends PrintWriter
1041 {
1042 private final String _encoding;
1043 private final HttpWriter _httpWriter;
1044
1045 public ResponseWriter(HttpWriter httpWriter,String encoding)
1046 {
1047 super(httpWriter);
1048 _httpWriter=httpWriter;
1049 _encoding=encoding;
1050 }
1051
1052 public boolean isFor(String encoding)
1053 {
1054 return _encoding.equalsIgnoreCase(encoding);
1055 }
1056
1057 protected void reopen()
1058 {
1059 super.clearError();
1060 out=_httpWriter;
1061 }
1062 }
1063 }