1 29 30 package com.caucho.server.connection; 31 32 import com.caucho.log.Log; 33 import com.caucho.server.cache.AbstractCacheEntry; 34 import com.caucho.server.cache.AbstractCacheFilterChain; 35 import com.caucho.server.dispatch.BadRequestException; 36 import com.caucho.server.dispatch.InvocationDecoder; 37 import com.caucho.server.session.CookieImpl; 38 import com.caucho.server.session.SessionImpl; 39 import com.caucho.server.session.SessionManager; 40 import com.caucho.server.util.CauchoSystem; 41 import com.caucho.server.webapp.ErrorPageManager; 42 import com.caucho.server.webapp.WebApp; 43 import com.caucho.util.Alarm; 44 import com.caucho.util.CaseInsensitiveIntMap; 45 import com.caucho.util.CharBuffer; 46 import com.caucho.util.HTTPUtil; 47 import com.caucho.util.L10N; 48 import com.caucho.util.QDate; 49 import com.caucho.vfs.ClientDisconnectException; 50 import com.caucho.vfs.FlushBuffer; 51 import com.caucho.vfs.TempBuffer; 52 import com.caucho.vfs.WriteStream; 53 import com.caucho.xml.XmlChar; 54 55 import javax.servlet.ServletOutputStream ; 56 import javax.servlet.ServletResponse ; 57 import javax.servlet.http.Cookie ; 58 import javax.servlet.http.HttpServletResponse ; 59 import javax.servlet.http.HttpSession ; 60 import java.io.IOException ; 61 import java.io.OutputStream ; 62 import java.io.PrintWriter ; 63 import java.io.Writer ; 64 import java.util.ArrayList ; 65 import java.util.HashMap ; 66 import java.util.Locale ; 67 import java.util.logging.Level ; 68 import java.util.logging.Logger ; 69 70 74 abstract public class AbstractHttpResponse implements CauchoResponse { 75 static final protected Logger log = Log.open(AbstractHttpResponse.class); 76 static final L10N L = new L10N(AbstractHttpResponse.class); 77 78 static final HashMap <String ,String > _errors; 79 80 protected static final CaseInsensitiveIntMap _headerCodes; 81 protected static final int HEADER_CACHE_CONTROL = 1; 82 protected static final int HEADER_CONTENT_TYPE = HEADER_CACHE_CONTROL + 1; 83 protected static final int HEADER_CONTENT_LENGTH = HEADER_CONTENT_TYPE + 1; 84 protected static final int HEADER_DATE = HEADER_CONTENT_LENGTH + 1; 85 protected static final int HEADER_SERVER = HEADER_DATE + 1; 86 87 protected CauchoRequest _originalRequest; 88 protected CauchoRequest _request; 89 90 protected int _statusCode; 91 protected String _statusMessage; 92 93 protected String _contentType; 94 protected String _contentPrefix; 95 protected String _charEncoding; 96 protected boolean _hasCharEncoding; 97 98 protected final ArrayList <String > _headerKeys = new ArrayList <String >(); 99 protected final ArrayList <String > _headerValues = new ArrayList <String >(); 100 101 protected final ArrayList <Cookie > _cookiesOut = new ArrayList <Cookie >(); 102 103 private final AbstractResponseStream _originalResponseStream; 104 105 private final ServletOutputStreamImpl _responseOutputStream; 106 private final ResponseWriter _responsePrintWriter; 107 108 private AbstractResponseStream _responseStream; 109 110 protected WriteStream _rawWrite; 112 113 private FlushBuffer _flushBuffer; 115 116 private boolean _isHeaderWritten; 117 private boolean _isChunked; 118 protected final QDate _calendar = new QDate(false); 119 120 protected final CharBuffer _cb = new CharBuffer(); 121 protected final char [] _headerBuffer = new char[256]; 122 123 private String _sessionId; 124 private boolean _hasSessionCookie; 125 126 private Locale _locale; 127 protected boolean _disableHeaders; 128 protected boolean _disableCaching; 129 protected long _contentLength; 130 protected boolean _isClosed; 131 protected boolean _hasSentLog; 132 133 protected boolean _hasWriter; 134 protected boolean _hasOutputStream; 135 136 private AbstractCacheFilterChain _cacheInvocation; 137 private AbstractCacheEntry _cacheEntry; 138 private OutputStream _cacheStream; 139 private Writer _cacheWriter; 140 141 protected boolean _isNoCache; 142 private boolean _allowCache; 143 private boolean _isPrivateCache; 144 private boolean _hasCacheControl; 145 146 protected boolean _isTopCache; 147 148 protected boolean _forbidForward; 149 protected boolean _hasError; 150 151 private final TempBuffer _tempBuffer = TempBuffer.allocate(); 152 153 protected AbstractHttpResponse() 154 { 155 _originalResponseStream = createResponseStream(); 156 157 _responseOutputStream = new ServletOutputStreamImpl(); 158 _responsePrintWriter = new ResponseWriter(); 159 160 _responseOutputStream.init(_originalResponseStream); 161 _responsePrintWriter.init(_originalResponseStream); 162 } 163 164 protected AbstractResponseStream createResponseStream() 165 { 166 return new ResponseStream(this); 167 } 168 169 protected AbstractHttpResponse(CauchoRequest request) 170 { 171 this(); 172 173 _request = request; 174 _originalRequest = request; 175 176 _responseOutputStream.init(_originalResponseStream); 177 _responsePrintWriter.init(_originalResponseStream); 178 } 179 180 184 public boolean isIgnoreClientDisconnect() 185 { 186 if (! (_originalRequest instanceof AbstractHttpRequest)) 187 return true; 188 else { 189 return ((AbstractHttpRequest) _originalRequest).isIgnoreClientDisconnect(); 190 } 191 } 192 193 196 public boolean isTop() 197 { 198 if (! (_request instanceof AbstractHttpRequest)) 199 return false; 200 else { 201 return ((AbstractHttpRequest) _request).isTop(); 202 } 203 } 204 205 208 public ServletResponse getResponse() 209 { 210 return null; 211 } 212 213 218 public void init(WriteStream stream) 219 { 220 _rawWrite = stream; 221 if (_originalResponseStream instanceof ResponseStream) 222 ((ResponseStream) _originalResponseStream).init(_rawWrite); 223 } 224 225 230 public void init(CauchoRequest request) 231 { 232 _request = request; 233 _originalRequest = request; 234 } 235 236 239 public CauchoRequest getRequest() 240 { 241 return _request; 242 } 243 244 247 public void setRequest(CauchoRequest req) 248 { 249 _request = req; 250 } 251 252 255 public CauchoRequest getOriginalRequest() 256 { 257 return _originalRequest; 258 } 259 260 263 public void close() 264 throws IOException 265 { 266 finish(true); 267 } 269 270 273 public boolean isClosed() 274 { 275 return _isClosed; 276 } 277 278 281 public void start() 282 throws IOException 283 { 284 _statusCode = 200; 285 _statusMessage = "OK"; 286 287 _headerKeys.clear(); 288 _headerValues.clear(); 289 290 _hasSessionCookie = false; 291 _cookiesOut.clear(); 292 293 _isHeaderWritten = false; 294 _isChunked = false; 295 _charEncoding = null; 296 _hasCharEncoding = false; 297 _contentType = null; 298 _contentPrefix = null; 299 _locale = null; 300 if (_originalResponseStream instanceof ResponseStream) 301 ((ResponseStream) _originalResponseStream).init(_rawWrite); 302 _flushBuffer = null; 303 304 _contentLength = -1; 305 _disableHeaders = false; 306 _disableCaching = false; 307 _isClosed = false; 308 _hasSentLog = false; 309 310 _hasWriter = false; 311 _hasOutputStream = false; 312 313 _cacheInvocation = null; 314 _cacheEntry = null; 315 _cacheStream = null; 316 _cacheWriter = null; 317 _isPrivateCache = false; 318 _hasCacheControl = false; 319 _allowCache = true; 320 _isNoCache = false; 321 _isTopCache = false; 322 323 _sessionId = null; 324 325 _forbidForward = false; 326 327 _originalResponseStream.start(); 328 329 _responseStream = _originalResponseStream; 330 331 _responseOutputStream.init(_responseStream); 332 _responsePrintWriter.init(_responseStream); 333 } 334 335 338 void setHead() 339 { 340 _originalResponseStream.setHead(); 341 } 342 343 346 protected final boolean isHead() 347 { 348 return _originalResponseStream.isHead(); 349 } 350 351 355 public void setForbidForward(boolean forbid) 356 { 357 _forbidForward = forbid; 358 } 359 360 364 public boolean getForbidForward() 365 { 366 return _forbidForward; 367 } 368 369 372 public void setHasError(boolean hasError) 373 { 374 _hasError = hasError; 375 } 376 377 380 public boolean hasError() 381 { 382 return _hasError; 383 } 384 385 391 public void setCacheEntry(AbstractCacheEntry entry) 392 { 393 _cacheEntry = entry; 394 } 395 396 400 public void setCacheInvocation(AbstractCacheFilterChain cacheInvocation) 401 { 402 _cacheInvocation = cacheInvocation; 403 } 404 405 public void setTopCache(boolean isTopCache) 406 { 407 _isTopCache = isTopCache; 408 } 409 410 public void setStatus(int code) 411 { 412 setStatus(code, null); 413 } 414 415 public void setStatus(int code, String message) 416 { 417 if (code < 0) 418 code = 500; 419 420 if (message != null) { 421 } 422 else if (code == SC_OK) 423 message = "OK"; 424 425 else if (code == SC_NOT_MODIFIED) 426 message = "Not Modified"; 427 428 else if (message == null) { 429 message = (String ) _errors.get(String.valueOf(code)); 430 431 if (message == null) 432 message = L.l("Internal Server Error"); 433 } 434 435 _statusCode = code; 436 _statusMessage = message; 437 } 438 439 public int getStatusCode() 440 { 441 return _statusCode; 442 } 443 444 public void sendError(int code) 445 throws IOException 446 { 447 sendError(code, null); 448 } 449 450 456 public void sendError(int code, String value) 457 throws IOException 458 { 459 if (isCommitted()) 460 throw new IllegalStateException (L.l("sendError() forbidden after buffer has been committed.")); 461 462 if (code == SC_NOT_MODIFIED && _cacheEntry != null) { 463 setStatus(code, value); 464 if (handleNotModified(_isTopCache)) 465 return; 466 } 467 468 resetBuffer(); 471 472 if (code != SC_NOT_MODIFIED) 473 killCache(); 474 475 479 480 WebApp app = getRequest().getWebApp(); 481 482 ErrorPageManager errorManager = null; 483 if (app != null) 484 errorManager = app.getErrorPageManager(); 485 486 setStatus(code, value); 487 try { 488 if (code == SC_NOT_MODIFIED || code == SC_NO_CONTENT) { 489 finish(); 490 return; 491 } 492 else if (errorManager != null) { 493 errorManager.sendError(getRequest(), this, code, _statusMessage); 494 finish(); 498 return; 499 } 500 501 setContentType("text/html"); 502 ServletOutputStream s = getOutputStream(); 503 504 s.println("<html>"); 505 if (! isCommitted()) { 506 s.print("<head><title>"); 507 s.print(code); 508 s.print(" "); 509 s.print(_statusMessage); 510 s.println("</title></head>"); 511 } 512 s.println("<body>"); 513 514 s.print("<h1>"); 515 s.print(code); 516 s.print(" "); 517 s.print(_statusMessage); 518 s.println("</h1>"); 519 520 if (code == HttpServletResponse.SC_NOT_FOUND) { 521 s.println(L.l("{0} was not found on this server.", 522 HTTPUtil.encodeString(getRequest().getPageURI()))); 523 } 524 else if (code == HttpServletResponse.SC_SERVICE_UNAVAILABLE) { 525 s.println(L.l("The server is temporarily unavailable due to maintenance downtime or excessive load.")); 526 } 527 528 if (CauchoSystem.isTesting() || app == null) { 529 } 530 else { 531 s.println("<p /><hr />"); 532 s.println("<small>"); 533 534 if (app.getServer() != null 535 && app.getServer().getServerHeader() != null) { 536 s.println(app.getServer().getServerHeader()); 537 } 538 else 539 s.println(com.caucho.Version.FULL_VERSION); 540 541 s.println("</small>"); 542 } 543 544 s.println("</body></html>"); 545 } catch (Exception e) { 546 log.log(Level.FINE, e.toString(), e); 547 } 548 549 _request.killKeepalive(); 550 finish(); 552 } 553 554 560 public void sendRedirect(String url) 561 throws IOException 562 { 563 if (url == null) 564 throw new NullPointerException (); 565 566 if (_originalResponseStream.isCommitted()) 567 throw new IllegalStateException (L.l("Can't sendRedirect() after data has committed to the client.")); 568 569 _responseStream.clearBuffer(); 570 _originalResponseStream.clearBuffer(); 571 572 _responseStream = _originalResponseStream; 573 resetBuffer(); 574 575 setStatus(SC_MOVED_TEMPORARILY); 576 String path = getAbsolutePath(url); 577 578 CharBuffer cb = new CharBuffer(); 579 580 for (int i = 0; i < path.length(); i++) { 581 char ch = path.charAt(i); 582 583 if (ch == '<') 584 cb.append("%3c"); 585 else 586 cb.append(ch); 587 } 588 589 path = cb.toString(); 590 591 setHeader("Location", path); 592 593 ServletOutputStream out = getOutputStream(); 596 out.println("The URL has moved <a HREF=\"" + path + "\">here</a>"); 597 599 if (_request instanceof AbstractHttpRequest) { 600 AbstractHttpRequest request = (AbstractHttpRequest) _request; 601 602 request.saveSession(); } 604 605 close(); 606 } 607 608 611 public void switchToRaw() 612 throws IOException 613 { 614 throw new UnsupportedOperationException (L.l("raw mode is not supported in this configuration")); 615 } 616 617 620 public WriteStream getRawOutput() 621 throws IOException 622 { 623 throw new UnsupportedOperationException (L.l("raw mode is not supported in this configuration")); 624 } 625 626 631 private String getAbsolutePath(String path) 632 { 633 int slash = path.indexOf('/'); 634 635 int len = path.length(); 636 637 for (int i = 0; i < len; i++) { 638 char ch = path.charAt(i); 639 640 if (ch == ':') 641 return path; 642 else if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z') 643 continue; 644 else 645 break; 646 } 647 648 WebApp app = getRequest().getWebApp(); 649 650 String hostPrefix = null; 651 String host = _request.getHeader("Host"); 652 String serverName = app.getHostName(); 653 654 if (serverName == null || serverName.equals("")) 655 serverName = _request.getServerName(); 656 657 int port = _request.getServerPort(); 658 659 if (hostPrefix != null && ! hostPrefix.equals("")) { 660 } 661 else if (serverName.startsWith("http:") || 662 serverName.startsWith("https:")) 663 hostPrefix = serverName; 664 else if (host != null) { 665 hostPrefix = _request.getScheme() + "://" + host; 666 } 667 else { 668 hostPrefix = _request.getScheme() + "://" + serverName; 669 670 if (serverName.indexOf(':') < 0 && 671 port != 0 && port != 80 && port != 443) 672 hostPrefix += ":" + port; 673 } 674 675 if (slash == 0) 676 return hostPrefix + path; 677 678 String uri = _request.getRequestURI(); 679 String queryString = null; 680 681 int p = path.indexOf('?'); 682 if (p > 0) { 683 queryString = path.substring(p + 1); 684 path = path.substring(0, p); 685 } 686 687 p = uri.lastIndexOf('/'); 688 689 if (p >= 0) 690 path = uri.substring(0, p + 1) + path; 691 692 try { 693 if (queryString != null) 694 return hostPrefix + InvocationDecoder.normalizeUri(path) + '?' + queryString; 695 else 696 return hostPrefix + InvocationDecoder.normalizeUri(path); 697 } catch (IOException e) { 698 throw new RuntimeException (e); 699 } 700 } 701 702 707 public boolean containsHeader(String name) 708 { 709 for (int i = 0; i < _headerKeys.size(); i++) { 710 String oldKey = _headerKeys.get(i); 711 712 if (oldKey.equalsIgnoreCase(name)) 713 return true; 714 } 715 716 if (name.equalsIgnoreCase("content-type")) 717 return _contentType != null; 718 719 if (name.equalsIgnoreCase("content-length")) 720 return _contentLength >= 0; 721 722 return false; 723 } 724 725 730 public String getHeader(String name) 731 { 732 for (int i = 0; i < _headerKeys.size(); i++) { 733 String oldKey = (String ) _headerKeys.get(i); 734 735 if (oldKey.equalsIgnoreCase(name)) 736 return (String ) _headerValues.get(i); 737 } 738 739 if (name.equalsIgnoreCase("content-type")) 740 return _contentType; 741 742 if (name.equalsIgnoreCase("content-length")) 743 return _contentLength >= 0 ? String.valueOf(_contentLength) : null; 744 745 return null; 746 } 747 748 754 public void setHeader(String key, String value) 755 { 756 if (_disableHeaders) 757 return; 758 else if (value == null) 759 throw new NullPointerException (); 760 761 if (setSpecial(key, value)) 762 return; 763 764 int i = 0; 765 boolean hasHeader = false; 766 767 for (i = _headerKeys.size() - 1; i >= 0; i--) { 768 String oldKey = _headerKeys.get(i); 769 770 if (oldKey.equalsIgnoreCase(key)) { 771 if (hasHeader) { 772 _headerKeys.remove(i); 773 _headerValues.remove(i); 774 } 775 else { 776 hasHeader = true; 777 778 _headerValues.set(i, value); 779 } 780 } 781 } 782 783 if (! hasHeader) { 784 _headerKeys.add(key); 785 _headerValues.add(value); 786 } 787 } 788 789 796 public void addHeader(String key, String value) 797 { 798 if (_disableHeaders) 799 return; 800 801 if (setSpecial(key, value)) 802 return; 803 804 _headerKeys.add(key); 805 _headerValues.add(value); 806 } 807 808 811 protected boolean setSpecial(String key, String value) 812 { 813 int length = key.length(); 814 if (256 <= length) 815 return false; 816 817 key.getChars(0, length, _headerBuffer, 0); 818 819 switch (_headerCodes.get(_headerBuffer, length)) { 820 case HEADER_CACHE_CONTROL: 821 if (value.startsWith("max-age")) { 822 } 823 else if (value.equals("x-anonymous")) { 824 } 825 else 826 _hasCacheControl = true; 827 return false; 828 829 case HEADER_CONTENT_TYPE: 830 setContentType(value); 831 return true; 832 833 case HEADER_CONTENT_LENGTH: 834 _contentLength = Long.parseLong(value); 835 return true; 836 837 case HEADER_DATE: 838 return true; 839 840 case HEADER_SERVER: 841 return false; 842 843 default: 844 return false; 845 } 846 } 847 848 public void removeHeader(String key) 849 { 850 if (_disableHeaders) 851 return; 852 853 for (int i = _headerKeys.size() - 1; i >= 0; i--) { 854 String oldKey = (String ) _headerKeys.get(i); 855 856 if (oldKey.equalsIgnoreCase(key)) { 857 _headerKeys.remove(i); 858 _headerValues.remove(i); 859 return; 860 } 861 } 862 } 863 864 871 public void setIntHeader(String name, int value) 872 { 873 _cb.clear(); 874 _cb.append(value); 875 setHeader(name, _cb.toString()); 876 } 877 878 885 public void addIntHeader(String key, int value) 886 { 887 _cb.clear(); 888 _cb.append(value); 889 addHeader(key, _cb.toString()); 890 } 891 892 899 public void setDateHeader(String name, long value) 900 { 901 _calendar.setGMTTime(value); 902 903 setHeader(name, _calendar.printDate()); 904 } 905 906 907 914 public void addDateHeader(String key, long value) 915 { 916 _calendar.setGMTTime(value); 917 918 addHeader(key, _calendar.printDate()); 919 } 920 921 928 public void setContentLength(int length) 929 { 930 _contentLength = length; 931 } 932 933 936 public long getContentLengthHeader() 937 { 938 return _contentLength; 939 } 940 941 951 public void setContentType(String value) 952 { 953 if (isCommitted()) 954 return; 955 if (_disableHeaders || value == null) { 956 _contentType = null; 957 return; 958 } 959 else if (value == "text/html" || value.equals("text/html")) { 960 _contentType = "text/html"; 961 return; 962 } 963 964 _contentType = value; 965 966 int length = value.length(); 967 int i; 968 int ch; 969 970 for (i = 0; 971 i < length && value.charAt(i) != ';' && 972 ! Character.isWhitespace(value.charAt(i)); 973 i++) { 974 } 975 976 if (i < length) 977 _contentPrefix = _contentType.substring(0, i); 978 else 979 _contentPrefix = _contentType; 980 981 while ((i = value.indexOf(';', i)) > 0) { 982 int semicolon = i; 983 for (i++; i < length && XmlChar.isWhitespace(value.charAt(i)); i++) { 984 } 985 986 int j; 987 for (j = i + 1; 988 j < length && ! XmlChar.isWhitespace((ch = value.charAt(j))) && 989 ch != '='; 990 j++) { 991 } 992 993 if (length <= j) 994 break; 995 else if ((ch = value.charAt(i)) != 'c' && ch != 'C') { 996 } 997 else if (value.substring(i, j).equalsIgnoreCase("charset")) { 998 for (; j < length && XmlChar.isWhitespace(value.charAt(j)); j++) { 999 } 1000 1001 if (length <= j || value.charAt(j) != '=') 1002 continue; 1003 1004 for (j++; j < length && XmlChar.isWhitespace(value.charAt(j)); j++) { 1005 } 1006 1007 String encoding; 1008 1009 if (j < length && value.charAt(j) == '"') { 1010 int k = ++j; 1011 1012 for (; j < length && value.charAt(j) != '"'; j++) { 1013 } 1014 1015 encoding = value.substring(k, j); 1016 } 1017 else { 1018 int k = j; 1019 for (k = j; 1020 j < length && ! XmlChar.isWhitespace(ch = value.charAt(j)) && ch != ';'; 1021 j++) { 1022 } 1023 1024 encoding = value.substring(k, j); 1025 } 1026 1027 int tail = value.indexOf(';', semicolon + 1); 1028 1029 StringBuilder sb = new StringBuilder (); 1030 sb.append(value, 0, semicolon); 1031 if (tail > 0) 1032 sb.append(value, tail, value.length()); 1033 1034 _contentType = sb.toString(); 1035 1036 if (! _hasWriter) { 1037 _hasCharEncoding = true; 1038 _charEncoding = encoding; 1039 } 1040 break; 1041 } 1042 else 1043 i = j; 1044 } 1045 1046 try { 1048 _responseStream.setEncoding(_charEncoding); 1049 } catch (Exception e) { 1050 log.log(Level.WARNING, e.toString(), e); 1051 } 1052 } 1053 1054 1057 public String getContentType() 1058 { 1059 if (_contentType == null) 1060 return null; 1061 else 1062 return _contentType + "; charset=" + getCharacterEncoding(); 1063 } 1064 1065 1068 public String getCharacterEncoding() 1069 { 1070 return _charEncoding == null ? "ISO-8859-1" : _charEncoding; 1071 } 1072 1073 1076 public void setCharacterEncoding(String encoding) 1077 { 1078 if (isCommitted()) 1079 return; 1080 if (_hasWriter) 1081 return; 1082 1083 _hasCharEncoding = true; 1084 1085 if (encoding == null || 1086 encoding.equals("ISO-8859-1") || 1087 encoding.equals("")) { 1088 encoding = null; 1089 _charEncoding = "iso-8859-1"; 1090 } 1091 else 1092 _charEncoding = encoding; 1093 1094 try { 1095 _responseStream.setEncoding(encoding); 1096 } catch (Exception e) { 1097 log.log(Level.WARNING, e.toString(), e); 1098 } 1099 } 1100 1101 String getRealCharacterEncoding() 1102 { 1103 return _charEncoding; 1104 } 1105 1106 1111 public void addCookie(Cookie cookie) 1112 { 1113 _request.setHasCookie(); 1114 1115 if (_disableHeaders) 1116 return; 1117 1118 if (cookie == null) 1119 return; 1120 1121 _cookiesOut.add(cookie); 1122 } 1123 1124 public Cookie getCookie(String name) 1125 { 1126 if (_cookiesOut == null) 1127 return null; 1128 1129 for (int i = _cookiesOut.size() - 1; i >= 0; i--) { 1130 Cookie cookie = (Cookie ) _cookiesOut.get(i); 1131 1132 if (cookie.getName().equals(name)) 1133 return cookie; 1134 } 1135 1136 return null; 1137 } 1138 1139 public ArrayList getCookies() 1140 { 1141 return _cookiesOut; 1142 } 1143 1144 public void setSessionId(String id) 1145 { 1146 _sessionId = id; 1147 1148 setPrivateOrResinCache(true); 1151 } 1152 1153 1156 public void setResponseStream(AbstractResponseStream responseStream) 1157 { 1158 _responseStream = responseStream; 1159 1160 _responseOutputStream.init(responseStream); 1161 _responsePrintWriter.init(responseStream); 1162 } 1163 1164 1167 public AbstractResponseStream getResponseStream() 1168 { 1169 return _responseStream; 1170 } 1171 1172 1175 public AbstractResponseStream getOriginalStream() 1176 { 1177 return _originalResponseStream; 1178 } 1179 1180 1183 public boolean isCauchoResponseStream() 1184 { 1185 return _responseStream.isCauchoResponseStream(); 1186 } 1187 1188 1191 public ServletOutputStream getOutputStream() throws IOException 1192 { 1193 1197 1198 _hasOutputStream = true; 1199 1200 return _responseOutputStream; 1201 } 1202 1203 1206 public void setFlushBuffer(FlushBuffer flushBuffer) 1207 { 1208 _flushBuffer = flushBuffer; 1209 } 1210 1211 1214 public FlushBuffer getFlushBuffer() 1215 { 1216 return _flushBuffer; 1217 } 1218 1219 1222 public PrintWriter getWriter() throws IOException 1223 { 1224 1228 1229 if (! _hasWriter) { 1230 _hasWriter = true; 1231 1232 if (_charEncoding != null) 1233 _responseStream.setEncoding(_charEncoding); 1234 } 1235 1236 return _responsePrintWriter; 1237 } 1238 1239 1242 public PrintWriter getNextWriter() 1243 { 1244 return null; 1245 } 1246 1247 1254 public String encodeURL(String string) 1255 { 1256 CauchoRequest request = getRequest(); 1257 1258 WebApp app = request.getWebApp(); 1259 1260 if (app == null) 1261 return string; 1262 1263 if (request.isRequestedSessionIdFromCookie()) 1264 return string; 1265 1266 HttpSession session = request.getSession(false); 1267 if (session == null) 1268 return string; 1269 1270 SessionManager sessionManager = app.getSessionManager(); 1271 if (! sessionManager.enableSessionUrls()) 1272 return string; 1273 1274 CharBuffer cb = _cb; 1275 cb.clear(); 1276 1277 String altPrefix = sessionManager.getAlternateSessionPrefix(); 1278 1279 if (altPrefix == null) { 1280 int p = string.indexOf('?'); 1282 1283 if (p == 0) { 1284 cb.append(string); 1285 } 1286 else if (p > 0) { 1287 cb.append(string, 0, p); 1288 cb.append(sessionManager.getSessionPrefix()); 1289 cb.append(session.getId()); 1290 cb.append(string, p, string.length() - p); 1291 } 1292 else if ((p = string.indexOf('#')) >= 0) { 1293 cb.append(string, 0, p); 1294 cb.append(sessionManager.getSessionPrefix()); 1295 cb.append(session.getId()); 1296 cb.append(string, p, string.length() - p); 1297 } 1298 else { 1299 cb.append(string); 1300 cb.append(sessionManager.getSessionPrefix()); 1301 cb.append(session.getId()); 1302 } 1303 } 1304 else { 1305 int p = string.indexOf("://"); 1306 1307 if (p < 0) { 1308 cb.append(altPrefix); 1309 cb.append(session.getId()); 1310 1311 if (! string.startsWith("/")) { 1312 cb.append(_request.getContextPath()); 1313 cb.append('/'); 1314 } 1315 cb.append(string); 1316 } 1317 else { 1318 int q = string.indexOf('/', p + 3); 1319 1320 if (q < 0) { 1321 cb.append(string); 1322 cb.append(altPrefix); 1323 cb.append(session.getId()); 1324 } 1325 else { 1326 cb.append(string.substring(0, q)); 1327 cb.append(altPrefix); 1328 cb.append(session.getId()); 1329 cb.append(string.substring(q)); 1330 } 1331 } 1332 } 1333 1334 return cb.toString(); 1335 } 1336 1337 public String encodeRedirectURL(String string) 1338 { 1339 return encodeURL(string); 1340 } 1341 1342 1345 public String encodeRedirectUrl(String string) 1346 { 1347 return encodeRedirectURL(string); 1348 } 1349 1350 1353 public String encodeUrl(String string) 1354 { 1355 return encodeURL(string); 1356 } 1357 1358 1361 1362 public void setBufferSize(int size) 1363 { 1364 _responseStream.setBufferSize(size); 1365 } 1366 1367 public int getBufferSize() 1368 { 1369 return _responseStream.getBufferSize(); 1370 } 1371 1372 public void flushBuffer() 1373 throws IOException 1374 { 1375 _responseStream.flush(); 1377 } 1378 1379 public void flushHeader() 1380 throws IOException 1381 { 1382 _responseStream.flushBuffer(); 1383 } 1384 1385 public void setDisableAutoFlush(boolean disable) 1386 { 1387 } 1389 1390 1393 public boolean isCommitted() 1394 { 1395 return _originalResponseStream.isCommitted(); 1396 } 1397 1398 public void reset() 1399 { 1400 reset(false); 1401 } 1402 1403 public void resetBuffer() 1404 { 1405 _responseStream.clearBuffer(); 1406 1410 } 1411 1412 1418 void reset(boolean force) 1419 { 1420 if (! force && _originalResponseStream.isCommitted()) 1421 throw new IllegalStateException (L.l("response cannot be reset() after committed")); 1422 1423 _responseStream.clearBuffer(); 1424 1428 _statusCode = 200; 1429 _statusMessage = "OK"; 1430 1431 _headerKeys.clear(); 1432 _headerValues.clear(); 1433 1434 1436 _contentLength = -1; 1437 1440 _charEncoding = null; 1441 _locale = null; 1442 1443 _hasOutputStream = false; 1444 _hasWriter = false; 1445 try { 1446 _responseStream.setLocale(null); 1447 _responseStream.setEncoding(null); 1448 } catch (Exception e) { 1449 } 1450 } 1451 1452 public void clearBuffer() 1454 { 1455 _responseStream.clearBuffer(); 1456 } 1457 1458 public void setLocale(Locale locale) 1459 { 1460 _locale = locale; 1461 1462 if (! _hasCharEncoding && ! isCommitted()) { 1463 _charEncoding = getRequest().getWebApp().getLocaleEncoding(locale); 1464 1465 try { 1466 if (_charEncoding != null) { 1467 _responseStream.setEncoding(_charEncoding); 1469 } 1470 } catch (IOException e) { 1471 } 1472 } 1473 1474 CharBuffer cb = _cb; 1475 cb.clear(); 1476 cb.append(locale.getLanguage()); 1477 if (locale.getCountry() != null && ! "".equals(locale.getCountry())) { 1478 cb.append("-"); 1479 cb.append(locale.getCountry()); 1480 if (locale.getVariant() != null && ! "".equals(locale.getVariant())) { 1481 cb.append("-"); 1482 cb.append(locale.getVariant()); 1483 } 1484 } 1485 1486 setHeader("Content-Language", cb.toString()); 1487 } 1488 1489 public Locale getLocale() 1490 { 1491 if (_locale != null) 1492 return _locale; 1493 else 1494 return Locale.getDefault(); 1495 } 1496 1497 1499 public int getRemaining() 1500 { 1501 return _responseStream.getRemaining(); 1502 } 1503 1504 1507 public int getContentLength() 1508 { 1509 return _originalResponseStream.getContentLength(); 1510 } 1511 1512 public boolean disableHeaders(boolean disable) 1513 { 1514 boolean old = _disableHeaders; 1515 _disableHeaders = disable; 1516 return old; 1517 } 1518 1519 public boolean disableCaching(boolean disable) 1520 { 1521 boolean old = _disableCaching; 1522 _disableCaching = disable; 1523 return old; 1524 } 1525 1526 1529 final public boolean isHeaderWritten() 1530 { 1531 return _isHeaderWritten; 1532 } 1533 1534 1537 final public void setHeaderWritten(boolean isWritten) 1538 { 1539 _isHeaderWritten = isWritten; 1540 } 1541 1542 1545 final void writeContinue() 1546 throws IOException 1547 { 1548 if (! _isHeaderWritten) { 1549 writeContinueInt(_rawWrite); 1550 _rawWrite.flush(); 1551 } 1552 } 1553 1554 1557 protected void writeContinueInt(WriteStream os) 1558 throws IOException 1559 { 1560 } 1561 1562 1570 protected boolean writeHeaders(WriteStream os, int length) 1571 throws IOException 1572 { 1573 if (_isHeaderWritten) 1574 return _isChunked; 1575 1576 boolean canCache = startCaching(true); 1578 _isHeaderWritten = true; 1579 1580 1596 1597 if (_request.getMethod().equals("HEAD")) { 1598 _originalResponseStream.setHead(); 1599 } 1600 1601 SessionImpl session = (SessionImpl) _originalRequest.getSession(false); 1602 if (session != null) 1603 session.saveBeforeHeaders(); 1604 1605 if (_sessionId != null && ! _hasSessionCookie) { 1606 _hasSessionCookie = true; 1607 1608 SessionManager manager = _request.getWebApp().getSessionManager(); 1609 1610 String cookieName; 1611 1612 if (_request.isSecure()) 1613 cookieName = manager.getSSLCookieName(); 1614 else 1615 cookieName = manager.getCookieName(); 1616 1617 CookieImpl cookie = new CookieImpl(cookieName, _sessionId); 1618 cookie.setVersion(manager.getCookieVersion()); 1619 String domain = manager.getCookieDomain(); 1620 if (domain != null) 1621 cookie.setDomain(domain); 1622 long maxAge = manager.getCookieMaxAge(); 1623 if (maxAge > 0) 1624 cookie.setMaxAge((int) (maxAge / 1000)); 1625 cookie.setPath("/"); 1626 1627 cookie.setPort(manager.getCookiePort()); 1628 if (manager.getCookieSecure()) { 1629 cookie.setSecure(_request.isSecure()); 1630 1634 } 1635 1636 addCookie(cookie); 1637 } 1638 1639 _isChunked = writeHeadersInt(os, length); 1640 1641 return _isChunked; 1642 } 1643 1644 1647 protected boolean startCaching(boolean isByte) 1648 { 1649 if (_isHeaderWritten) 1650 return false; 1651 _isHeaderWritten = true; 1652 1653 if (_statusCode == SC_OK && ! _disableCaching) return startCaching(_headerKeys, _headerValues, 1655 _contentType, _charEncoding, isByte); 1656 else 1657 return false; 1658 } 1659 1660 1670 boolean startCaching(ArrayList <String > keys, ArrayList <String > values, 1671 String contentType, String charEncoding, 1672 boolean isByte) 1673 { 1674 if (_cacheInvocation == null) 1675 return false; 1676 1682 else if (! isCauchoResponseStream()) { 1683 return false; 1684 } 1685 else if (! (_originalRequest instanceof CauchoRequest)) { 1686 return false; 1687 } 1688 else if (! _allowCache) { 1689 return false; 1690 } 1691 else if (isByte) { 1692 CauchoRequest request = (CauchoRequest) _originalRequest; 1693 1694 _cacheStream = _cacheInvocation.startByteCaching(request, 1695 this, keys, values, 1696 contentType, 1697 charEncoding, 1698 _contentLength); 1699 1700 if (_cacheStream != null) 1701 _originalResponseStream.setByteCacheStream(_cacheStream); 1702 1703 return _cacheStream != null; 1704 } 1705 else { 1706 CauchoRequest request = (CauchoRequest) _originalRequest; 1707 1708 _cacheWriter = _cacheInvocation.startCharCaching(request, 1709 this, keys, values, 1710 contentType, 1711 charEncoding, 1712 _contentLength); 1713 1714 if (_cacheWriter != null) 1715 _originalResponseStream.setCharCacheStream(_cacheWriter); 1716 1717 return _cacheWriter != null; 1718 } 1719 } 1720 1721 1722 1730 private boolean handleNotModified(boolean isTop) 1731 throws IOException 1732 { 1733 if (_statusCode != SC_NOT_MODIFIED) { 1734 return false; 1735 } 1736 else if (_cacheEntry != null) { 1737 if (_originalResponseStream.isCommitted()) 1738 return false; 1739 1740 _originalResponseStream.clearClosed(); 1743 _isClosed = false; 1744 1745 1746 if (_cacheInvocation != null && 1747 _cacheInvocation.fillFromCache((CauchoRequest) _originalRequest, 1748 this, _cacheEntry, isTop)) { 1749 _cacheEntry.updateExpiresDate(); 1750 _cacheInvocation = null; 1751 _cacheEntry = null; 1752 1753 finish(); 1755 return true; 1756 } 1757 } 1758 else if (_cacheInvocation != null) { 1760 CauchoRequest req = (CauchoRequest) _originalRequest; 1761 WebApp app = req.getWebApp(); 1762 1763 long maxAge = app.getMaxAge(req.getRequestURI()); 1764 1765 if (maxAge > 0 && ! containsHeader("Expires")) { 1766 setDateHeader("Expires", maxAge + Alarm.getCurrentTime()); 1767 } 1768 } 1769 1770 return false; 1771 } 1772 1773 abstract protected boolean writeHeadersInt(WriteStream os, int length) 1774 throws IOException ; 1775 1776 1788 public void setPrivateCache(boolean isPrivate) 1789 { 1790 _isPrivateCache = isPrivate; 1792 1793 _allowCache = false; 1795 } 1796 1797 1801 public void setPrivateOrResinCache(boolean isPrivate) 1802 { 1803 1805 _isPrivateCache = isPrivate; 1806 } 1807 1808 1811 public boolean getPrivateCache() 1812 { 1813 return _isPrivateCache; 1814 } 1815 1816 1819 protected boolean isPrivateCache() 1820 { 1821 return ! _hasCacheControl && _isPrivateCache; 1822 } 1823 1824 1827 public void setNoCache(boolean isNoCache) 1828 { 1829 _isNoCache = isNoCache; 1830 } 1831 1832 1835 public boolean isNoCache() 1836 { 1837 return _isNoCache; 1838 } 1839 1840 1843 public void killCache() 1844 { 1845 _allowCache = false; 1846 1847 } 1850 1851 1859 public boolean fillCookie(CharBuffer cb, Cookie cookie, 1860 long date, int version, 1861 boolean isCookie2) 1862 { 1863 1866 cb.clear(); 1867 cb.append(cookie.getName()); 1868 if (isCookie2) { 1869 cb.append("=\""); 1870 cb.append(cookie.getValue()); 1871 cb.append("\""); 1872 } 1873 else { 1874 cb.append("="); 1875 cb.append(cookie.getValue()); 1876 } 1877 1878 String domain = cookie.getDomain(); 1879 if (domain != null && ! domain.equals("")) { 1880 if (isCookie2) { 1881 cb.append("; Domain="); 1882 1883 cb.append('"'); 1884 cb.append(domain); 1885 cb.append('"'); 1886 } 1887 else { 1888 cb.append("; domain="); 1889 cb.append(domain); 1890 } 1891 } 1892 1893 String path = cookie.getPath(); 1894 if (path != null && ! path.equals("")) { 1895 if (isCookie2) { 1896 cb.append("; Path="); 1897 1898 cb.append('"'); 1899 cb.append(path); 1900 cb.append('"'); 1901 } 1902 else { 1903 if (version > 0) 1905 cb.append("; Path="); 1906 else 1907 cb.append("; path="); 1908 cb.append(path); 1909 } 1910 } 1911 1912 if (cookie.getSecure()) { 1913 if (version > 0) 1914 cb.append("; Secure"); 1915 else 1916 cb.append("; secure"); 1917 } 1918 1919 int maxAge = cookie.getMaxAge(); 1920 if (version > 0) { 1921 if (maxAge >= 0) { 1922 cb.append("; Max-Age="); 1923 cb.append(maxAge); 1924 } 1925 1926 cb.append("; Version="); 1927 cb.append(version); 1928 1929 if (cookie.getComment() != null) { 1930 cb.append("; Comment=\""); 1931 cb.append(cookie.getComment()); 1932 cb.append("\""); 1933 } 1934 1935 if (cookie instanceof CookieImpl) { 1936 CookieImpl extCookie = (CookieImpl) cookie; 1937 String port = extCookie.getPort(); 1938 1939 if (port != null && isCookie2) { 1940 cb.append("; Port=\""); 1941 cb.append(port); 1942 cb.append("\""); 1943 } 1944 } 1945 } 1946 1947 if (isCookie2) { 1948 } 1949 else if (maxAge == 0) { 1950 cb.append("; expires=Thu, 01-Dec-1994 16:00:00 GMT"); 1951 } 1952 else if (maxAge >= 0) { 1953 _calendar.setGMTTime(date + 1000L * (long) maxAge); 1954 cb.append("; expires="); 1955 cb.append(_calendar.format("%a, %d-%b-%Y %H:%M:%S GMT")); 1956 } 1957 1958 WebApp app = _request.getWebApp(); 1959 if (app.getCookieHttpOnly()) { 1960 cb.append("; HttpOnly"); 1961 } 1962 1963 return true; 1964 } 1965 1966 1970 public void finish() throws IOException 1971 { 1972 finish(false); 1973 } 1974 1975 1981 private void finish(boolean isClose) throws IOException 1982 { 1983 if (_isClosed) 1984 return; 1985 1986 try { 1987 if (_originalRequest instanceof AbstractHttpRequest) { 1988 AbstractHttpRequest request = (AbstractHttpRequest) _originalRequest; 1989 1990 try { 1991 request.skip(); 1992 } catch (BadRequestException e) { 1993 log.warning(e.toString()); 1994 log.log(Level.FINE, e.toString(), e); 1995 } catch (Exception e) { 1996 log.log(Level.WARNING, e.toString(), e); 1997 } 1998 } 1999 2000 if (_statusCode == SC_NOT_MODIFIED) { 2001 handleNotModified(_isTopCache); 2002 } 2003 2004 if (isClose) 2008 _responseStream.close(); 2009 else 2010 _responseStream.finish(); 2011 2012 if (_responseStream != _originalResponseStream) { 2013 if (isClose) 2014 _originalResponseStream.close(); 2015 else 2016 _originalResponseStream.finish(); 2017 } 2018 2019 _isClosed = true; 2020 2021 if (_rawWrite == null) { 2022 } 2023 else 2027 _rawWrite.flushBuffer(); 2028 2029 if (_cacheInvocation == null) { 2030 } 2031 else if (_cacheStream != null || _cacheWriter != null) { 2032 _cacheStream = null; 2033 _cacheWriter = null; 2034 AbstractCacheFilterChain cache = _cacheInvocation; 2035 _cacheInvocation = null; 2036 2037 cache.finishCaching(_statusCode == 200 && _allowCache); 2038 } 2039 } catch (ClientDisconnectException e) { 2040 _request.killKeepalive(); 2041 2042 if (isIgnoreClientDisconnect()) 2043 log.fine(e.toString()); 2044 else 2045 throw e; 2046 } catch (IOException e) { 2047 _request.killKeepalive(); 2048 2049 throw e; 2050 } finally { 2051 _isClosed = true; 2052 _cacheStream = null; 2053 _cacheWriter = null; 2054 _cacheInvocation = null; 2055 _cacheEntry = null; 2056 } 2057 } 2058 2059 TempBuffer getBuffer() 2060 { 2061 return _tempBuffer; 2062 } 2063 2064 protected final QDate getCalendar() 2065 { 2066 return _calendar; 2067 } 2068 2069 protected void free() 2070 { 2071 _request = null; 2072 _originalRequest = null; 2073 _cacheInvocation = null; 2074 _cacheEntry = null; 2075 _cacheStream = null; 2076 _cacheWriter = null; 2077 } 2078 2079 static { 2080 _errors = new HashMap <String ,String >(); 2081 _errors.put("100", "Continue"); 2082 _errors.put("101", "Switching Protocols"); 2083 _errors.put("200", "OK"); 2084 _errors.put("201", "Created"); 2085 _errors.put("202", "Accepted"); 2086 _errors.put("203", "Non-Authoritative Information"); 2087 _errors.put("204", "No Content"); 2088 _errors.put("205", "Reset Content"); 2089 _errors.put("206", "Partial Content"); 2090 _errors.put("300", "Multiple Choices"); 2091 _errors.put("301", "Moved Permanently"); 2092 _errors.put("302", "Found"); 2093 _errors.put("303", "See Other"); 2094 _errors.put("304", "Not Modified"); 2095 _errors.put("305", "Use Proxy"); 2096 _errors.put("307", "Temporary Redirect"); 2097 _errors.put("400", "Bad Request"); 2098 _errors.put("401", "Unauthorized"); 2099 _errors.put("402", "Payment Required"); 2100 _errors.put("403", "Forbidden"); 2101 _errors.put("404", "Not Found"); 2102 _errors.put("405", "Method Not Allowed"); 2103 _errors.put("406", "Not Acceptable"); 2104 _errors.put("407", "Proxy Authentication Required"); 2105 _errors.put("408", "Request Timeout"); 2106 _errors.put("409", "Conflict"); 2107 _errors.put("410", "Gone"); 2108 _errors.put("411", "Length Required"); 2109 _errors.put("412", "Precondition Failed"); 2110 _errors.put("413", "Request Entity Too Large"); 2111 _errors.put("414", "Request-URI Too Long"); 2112 _errors.put("415", "Unsupported Media Type"); 2113 _errors.put("416", "Requested Range Not Satisfiable"); 2114 _errors.put("417", "Expectation Failed"); 2115 _errors.put("500", "Internal Server Error"); 2116 _errors.put("501", "Not Implemented"); 2117 _errors.put("502", "Bad Gateway"); 2118 _errors.put("503", "Service Temporarily Unavailable"); 2119 _errors.put("504", "Gateway Timeout"); 2120 _errors.put("505", "Http Version Not Supported"); 2121 2122 _headerCodes = new CaseInsensitiveIntMap(); 2123 _headerCodes.put("cache-control", HEADER_CACHE_CONTROL); 2124 _headerCodes.put("content-type", HEADER_CONTENT_TYPE); 2125 _headerCodes.put("content-length", HEADER_CONTENT_LENGTH); 2126 _headerCodes.put("date", HEADER_DATE); 2127 _headerCodes.put("server", HEADER_SERVER); 2128 } 2129} 2130 | Popular Tags |