0001: /*
0002: * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/HttpResponseBase.java,v 1.54 2002/04/05 18:43:12 remm Exp $
0003: * $Revision: 1.54 $
0004: * $Date: 2002/04/05 18:43:12 $
0005: *
0006: * ====================================================================
0007: *
0008: * The Apache Software License, Version 1.1
0009: *
0010: * Copyright (c) 1999 The Apache Software Foundation. All rights
0011: * reserved.
0012: *
0013: * Redistribution and use in source and binary forms, with or without
0014: * modification, are permitted provided that the following conditions
0015: * are met:
0016: *
0017: * 1. Redistributions of source code must retain the above copyright
0018: * notice, this list of conditions and the following disclaimer.
0019: *
0020: * 2. Redistributions in binary form must reproduce the above copyright
0021: * notice, this list of conditions and the following disclaimer in
0022: * the documentation and/or other materials provided with the
0023: * distribution.
0024: *
0025: * 3. The end-user documentation included with the redistribution, if
0026: * any, must include the following acknowlegement:
0027: * "This product includes software developed by the
0028: * Apache Software Foundation (http://www.apache.org/)."
0029: * Alternately, this acknowlegement may appear in the software itself,
0030: * if and wherever such third-party acknowlegements normally appear.
0031: *
0032: * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
0033: * Foundation" must not be used to endorse or promote products derived
0034: * from this software without prior written permission. For written
0035: * permission, please contact apache@apache.org.
0036: *
0037: * 5. Products derived from this software may not be called "Apache"
0038: * nor may "Apache" appear in their names without prior written
0039: * permission of the Apache Group.
0040: *
0041: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0042: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0043: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0044: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0045: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0046: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0047: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0048: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0049: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0050: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0051: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0052: * SUCH DAMAGE.
0053: * ====================================================================
0054: *
0055: * This software consists of voluntary contributions made by many
0056: * individuals on behalf of the Apache Software Foundation. For more
0057: * information on the Apache Software Foundation, please see
0058: * <http://www.apache.org/>.
0059: *
0060: * [Additional notices, if required by prior licensing conditions]
0061: *
0062: */
0063:
0064: package org.apache.catalina.connector;
0065:
0066: import java.io.IOException;
0067: import java.io.OutputStreamWriter;
0068: import java.io.PrintWriter;
0069: import java.io.UnsupportedEncodingException;
0070: import java.net.MalformedURLException; // import java.net.URL;
0071: import java.security.AccessController;
0072: import java.security.PrivilegedAction;
0073: import java.security.PrivilegedExceptionAction;
0074: import java.security.PrivilegedActionException;
0075: import java.text.SimpleDateFormat;
0076: import java.util.ArrayList;
0077: import java.util.Date;
0078: import java.util.HashMap;
0079: import java.util.Iterator;
0080: import java.util.Locale;
0081: import java.util.TimeZone;
0082: import javax.servlet.ServletResponse;
0083: import javax.servlet.http.Cookie;
0084: import javax.servlet.http.HttpServletRequest;
0085: import javax.servlet.http.HttpServletResponse;
0086: import javax.servlet.http.HttpSession;
0087: import javax.servlet.http.HttpUtils;
0088: import org.apache.catalina.HttpResponse;
0089: import org.apache.catalina.Globals;
0090: import org.apache.catalina.Logger;
0091: import org.apache.catalina.util.CookieTools;
0092: import org.apache.catalina.util.RequestUtil;
0093: import org.apache.catalina.util.URL;
0094:
0095: /**
0096: * Convenience base implementation of the <b>HttpResponse</b> interface, which
0097: * can be used for the <code>Response</code> implementation required by most
0098: * <code>Connectors</code> that deal with HTTP. Only the connector-specific
0099: * methods need to be implemented.
0100: *
0101: * @author Craig R. McClanahan
0102: * @author Remy Maucherat
0103: * @version $Revision: 1.54 $ $Date: 2002/04/05 18:43:12 $
0104: * @deprecated
0105: */
0106:
0107: public class HttpResponseBase extends ResponseBase implements
0108: HttpResponse, HttpServletResponse {
0109:
0110: protected class PrivilegedFlushBuffer implements
0111: PrivilegedExceptionAction {
0112:
0113: PrivilegedFlushBuffer() {
0114: }
0115:
0116: public Object run() throws Exception {
0117: doFlushBuffer();
0118: return null;
0119: }
0120: }
0121:
0122: // ----------------------------------------------------------- Constructors
0123:
0124: public HttpResponseBase() {
0125:
0126: format.setTimeZone(TimeZone.getTimeZone("GMT"));
0127:
0128: }
0129:
0130: // ----------------------------------------------------- Instance Variables
0131:
0132: /**
0133: * The set of Cookies associated with this Response.
0134: */
0135: protected ArrayList cookies = new ArrayList();
0136:
0137: /**
0138: * The date format we will use for creating date headers.
0139: */
0140: protected final SimpleDateFormat format = new SimpleDateFormat(
0141: "EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
0142:
0143: /**
0144: * The facade associated with this response.
0145: */
0146: protected HttpResponseFacade facade = new HttpResponseFacade(this );
0147:
0148: /**
0149: * The HTTP headers explicitly added via addHeader(), but not including
0150: * those to be added with setContentLength(), setContentType(), and so on.
0151: * This collection is keyed by the header name, and the elements are
0152: * ArrayLists containing the associated values that have been set.
0153: */
0154: protected HashMap headers = new HashMap();
0155:
0156: /**
0157: * Descriptive information about this HttpResponse implementation.
0158: */
0159: protected static final String info = "org.apache.catalina.connector.HttpResponseBase/1.0";
0160:
0161: /**
0162: * The error message set by <code>sendError()</code>.
0163: */
0164: protected String message = getStatusMessage(HttpServletResponse.SC_OK);
0165:
0166: /**
0167: * The HTTP status code associated with this Response.
0168: */
0169: protected int status = HttpServletResponse.SC_OK;
0170:
0171: /**
0172: * The time zone with which to construct date headers.
0173: */
0174: protected static final TimeZone zone = TimeZone.getTimeZone("GMT");
0175:
0176: // ------------------------------------------------------------- Properties
0177:
0178: /**
0179: * Return the <code>ServletResponse</code> for which this object
0180: * is the facade.
0181: */
0182: public ServletResponse getResponse() {
0183:
0184: return (facade);
0185:
0186: }
0187:
0188: // --------------------------------------------------------- Public Methods
0189:
0190: /**
0191: * Perform whatever actions are required to flush and close the output
0192: * stream or writer, in a single operation.
0193: *
0194: * @exception IOException if an input/output error occurs
0195: */
0196: public void finishResponse() throws IOException {
0197:
0198: // If an HTTP error >= 400 has been created with no content,
0199: // attempt to create a simple error message
0200: if (!isCommitted() && (stream == null) && (writer == null)
0201: && (status >= HttpServletResponse.SC_BAD_REQUEST)
0202: && (contentType == null) && (contentCount == 0)) {
0203: try {
0204: setContentType("text/html");
0205: PrintWriter writer = getWriter();
0206: writer.println("<html>");
0207: writer.println("<head>");
0208: writer.println("<title>Tomcat Error Report</title>");
0209: writer.println("<br><br>");
0210: writer.println("<h1>HTTP Status ");
0211: writer.print(status);
0212: writer.print(" - ");
0213: if (message != null)
0214: writer.print(message);
0215: else
0216: writer.print(getStatusMessage(status));
0217: writer.println("</h1>");
0218: writer.println("</body>");
0219: writer.println("</html>");
0220: } catch (IOException e) {
0221: throw e;
0222: } catch (Throwable e) {
0223: ; // Just eat it
0224: }
0225: }
0226:
0227: // Flush the headers and finish this response
0228: sendHeaders();
0229: super .finishResponse();
0230:
0231: }
0232:
0233: /**
0234: * Return an array of all cookies set for this response, or
0235: * a zero-length array if no cookies have been set.
0236: */
0237: public Cookie[] getCookies() {
0238:
0239: synchronized (cookies) {
0240: return ((Cookie[]) cookies.toArray(new Cookie[cookies
0241: .size()]));
0242: }
0243:
0244: }
0245:
0246: /**
0247: * Return the value for the specified header, or <code>null</code> if this
0248: * header has not been set. If more than one value was added for this
0249: * name, only the first is returned; use getHeaderValues() to retrieve all
0250: * of them.
0251: *
0252: * @param name Header name to look up
0253: */
0254: public String getHeader(String name) {
0255:
0256: ArrayList values = null;
0257: synchronized (headers) {
0258: values = (ArrayList) headers.get(name);
0259: }
0260: if (values != null)
0261: return ((String) values.get(0));
0262: else
0263: return (null);
0264:
0265: }
0266:
0267: /**
0268: * Return an array of all the header names set for this response, or
0269: * a zero-length array if no headers have been set.
0270: */
0271: public String[] getHeaderNames() {
0272:
0273: synchronized (headers) {
0274: String results[] = new String[headers.size()];
0275: return ((String[]) headers.keySet().toArray(results));
0276: }
0277:
0278: }
0279:
0280: /**
0281: * Return an array of all the header values associated with the
0282: * specified header name, or an zero-length array if there are no such
0283: * header values.
0284: *
0285: * @param name Header name to look up
0286: */
0287: public String[] getHeaderValues(String name) {
0288:
0289: ArrayList values = null;
0290: synchronized (headers) {
0291: values = (ArrayList) headers.get(name);
0292: }
0293: if (values == null)
0294: return (new String[0]);
0295: String results[] = new String[values.size()];
0296: return ((String[]) values.toArray(results));
0297:
0298: }
0299:
0300: /**
0301: * Return the error message that was set with <code>sendError()</code>
0302: * for this Response.
0303: */
0304: public String getMessage() {
0305:
0306: return (this .message);
0307:
0308: }
0309:
0310: /**
0311: * Return the HTTP status code associated with this Response.
0312: */
0313: public int getStatus() {
0314:
0315: return (this .status);
0316:
0317: }
0318:
0319: /**
0320: * Release all object references, and initialize instance variables, in
0321: * preparation for reuse of this object.
0322: */
0323: public void recycle() {
0324:
0325: super .recycle();
0326: cookies.clear();
0327: headers.clear();
0328: message = getStatusMessage(HttpServletResponse.SC_OK);
0329: status = HttpServletResponse.SC_OK;
0330:
0331: }
0332:
0333: /**
0334: * Reset this response, and specify the values for the HTTP status code
0335: * and corresponding message.
0336: *
0337: * @exception IllegalStateException if this response has already been
0338: * committed
0339: */
0340: public void reset(int status, String message) {
0341:
0342: reset();
0343: setStatus(status, message);
0344:
0345: }
0346:
0347: // ------------------------------------------------------ Protected Methods
0348:
0349: /**
0350: * Returns a default status message for the specified HTTP status code.
0351: *
0352: * @param status The status code for which a message is desired
0353: */
0354: protected String getStatusMessage(int status) {
0355:
0356: switch (status) {
0357: case SC_OK:
0358: return ("OK");
0359: case SC_ACCEPTED:
0360: return ("Accepted");
0361: case SC_BAD_GATEWAY:
0362: return ("Bad Gateway");
0363: case SC_BAD_REQUEST:
0364: return ("Bad Request");
0365: case SC_CONFLICT:
0366: return ("Conflict");
0367: case SC_CONTINUE:
0368: return ("Continue");
0369: case SC_CREATED:
0370: return ("Created");
0371: case SC_EXPECTATION_FAILED:
0372: return ("Expectation Failed");
0373: case SC_FORBIDDEN:
0374: return ("Forbidden");
0375: case SC_GATEWAY_TIMEOUT:
0376: return ("Gateway Timeout");
0377: case SC_GONE:
0378: return ("Gone");
0379: case SC_HTTP_VERSION_NOT_SUPPORTED:
0380: return ("HTTP Version Not Supported");
0381: case SC_INTERNAL_SERVER_ERROR:
0382: return ("Internal Server Error");
0383: case SC_LENGTH_REQUIRED:
0384: return ("Length Required");
0385: case SC_METHOD_NOT_ALLOWED:
0386: return ("Method Not Allowed");
0387: case SC_MOVED_PERMANENTLY:
0388: return ("Moved Permanently");
0389: case SC_MOVED_TEMPORARILY:
0390: return ("Moved Temporarily");
0391: case SC_MULTIPLE_CHOICES:
0392: return ("Multiple Choices");
0393: case SC_NO_CONTENT:
0394: return ("No Content");
0395: case SC_NON_AUTHORITATIVE_INFORMATION:
0396: return ("Non-Authoritative Information");
0397: case SC_NOT_ACCEPTABLE:
0398: return ("Not Acceptable");
0399: case SC_NOT_FOUND:
0400: return ("Not Found");
0401: case SC_NOT_IMPLEMENTED:
0402: return ("Not Implemented");
0403: case SC_NOT_MODIFIED:
0404: return ("Not Modified");
0405: case SC_PARTIAL_CONTENT:
0406: return ("Partial Content");
0407: case SC_PAYMENT_REQUIRED:
0408: return ("Payment Required");
0409: case SC_PRECONDITION_FAILED:
0410: return ("Precondition Failed");
0411: case SC_PROXY_AUTHENTICATION_REQUIRED:
0412: return ("Proxy Authentication Required");
0413: case SC_REQUEST_ENTITY_TOO_LARGE:
0414: return ("Request Entity Too Large");
0415: case SC_REQUEST_TIMEOUT:
0416: return ("Request Timeout");
0417: case SC_REQUEST_URI_TOO_LONG:
0418: return ("Request URI Too Long");
0419: case SC_REQUESTED_RANGE_NOT_SATISFIABLE:
0420: return ("Requested Range Not Satisfiable");
0421: case SC_RESET_CONTENT:
0422: return ("Reset Content");
0423: case SC_SEE_OTHER:
0424: return ("See Other");
0425: case SC_SERVICE_UNAVAILABLE:
0426: return ("Service Unavailable");
0427: case SC_SWITCHING_PROTOCOLS:
0428: return ("Switching Protocols");
0429: case SC_UNAUTHORIZED:
0430: return ("Unauthorized");
0431: case SC_UNSUPPORTED_MEDIA_TYPE:
0432: return ("Unsupported Media Type");
0433: case SC_USE_PROXY:
0434: return ("Use Proxy");
0435: case 207: // WebDAV
0436: return ("Multi-Status");
0437: case 422: // WebDAV
0438: return ("Unprocessable Entity");
0439: case 423: // WebDAV
0440: return ("Locked");
0441: case 507: // WebDAV
0442: return ("Insufficient Storage");
0443: default:
0444: return ("HTTP Response Status " + status);
0445: }
0446:
0447: }
0448:
0449: /**
0450: * Return <code>true</code> if the specified URL should be encoded with
0451: * a session identifier. This will be true if all of the following
0452: * conditions are met:
0453: * <ul>
0454: * <li>The request we are responding to asked for a valid session
0455: * <li>The requested session ID was not received via a cookie
0456: * <li>The specified URL points back to somewhere within the web
0457: * application that is responding to this request
0458: * </ul>
0459: *
0460: * @param location Absolute URL to be validated
0461: **/
0462: private boolean isEncodeable(String location) {
0463:
0464: if (location == null)
0465: return (false);
0466:
0467: // Is this an intra-document reference?
0468: if (location.startsWith("#"))
0469: return (false);
0470:
0471: // Are we in a valid session that is not using cookies?
0472: HttpServletRequest hreq = (HttpServletRequest) request
0473: .getRequest();
0474: HttpSession session = hreq.getSession(false);
0475: if (session == null)
0476: return (false);
0477: if (hreq.isRequestedSessionIdFromCookie())
0478: return (false);
0479:
0480: // Is this a valid absolute URL?
0481: URL url = null;
0482: try {
0483: url = new URL(location);
0484: } catch (MalformedURLException e) {
0485: return (false);
0486: }
0487:
0488: // Does this URL match down to (and including) the context path?
0489: if (!hreq.getScheme().equalsIgnoreCase(url.getProtocol()))
0490: return (false);
0491: if (!hreq.getServerName().equalsIgnoreCase(url.getHost()))
0492: return (false);
0493: int serverPort = hreq.getServerPort();
0494: if (serverPort == -1) {
0495: if ("https".equals(hreq.getScheme()))
0496: serverPort = 443;
0497: else
0498: serverPort = 80;
0499: }
0500: int urlPort = url.getPort();
0501: if (urlPort == -1) {
0502: if ("https".equals(url.getProtocol()))
0503: urlPort = 443;
0504: else
0505: urlPort = 80;
0506: }
0507: if (serverPort != urlPort)
0508: return (false);
0509:
0510: String contextPath = getContext().getPath();
0511: if ((contextPath != null) && (contextPath.length() > 0)) {
0512: String file = url.getFile();
0513: if ((file == null) || !file.startsWith(contextPath))
0514: return (false);
0515: if (file.indexOf(";jsessionid=" + session.getId()) >= 0)
0516: return (false);
0517: }
0518:
0519: // This URL belongs to our web application, so it is encodeable
0520: return (true);
0521:
0522: }
0523:
0524: private void log(String message) {
0525: Logger logger = context.getLogger();
0526: logger.log(message);
0527: }
0528:
0529: private void log(String message, Throwable throwable) {
0530: Logger logger = context.getLogger();
0531: logger.log(message, throwable);
0532: }
0533:
0534: /**
0535: * Return the HTTP protocol version implemented by this response
0536: * object. (This method must be overridden by subclasses of this
0537: * as to correctly return the highest HTTP version number supported
0538: * as specified in Section 3.1 of RFC-2616).
0539: *
0540: * @return A string in the form of "HTTP/1.0" ...
0541: */
0542: protected String getProtocol() {
0543: return (request.getRequest().getProtocol());
0544: }
0545:
0546: /**
0547: * Send the HTTP response headers, if this has not already occurred.
0548: */
0549: protected void sendHeaders() throws IOException {
0550:
0551: if (isCommitted())
0552: return;
0553:
0554: // Check if the request was an HTTP/0.9 request
0555: if ("HTTP/0.9".equals(request.getRequest().getProtocol())) {
0556: committed = true;
0557: return;
0558: }
0559:
0560: // Prepare a suitable output writer
0561: OutputStreamWriter osr = null;
0562: try {
0563: osr = new OutputStreamWriter(getStream(),
0564: getCharacterEncoding());
0565: } catch (UnsupportedEncodingException e) {
0566: osr = new OutputStreamWriter(getStream());
0567: }
0568: final PrintWriter outputWriter = new PrintWriter(osr);
0569:
0570: // Send the "Status:" header
0571: outputWriter.print(this .getProtocol());
0572: outputWriter.print(" ");
0573: outputWriter.print(status);
0574: if (message != null) {
0575: outputWriter.print(" ");
0576: outputWriter.print(message);
0577: }
0578: outputWriter.print("\r\n");
0579: // System.out.println("sendHeaders: " +
0580: // request.getRequest().getProtocol() +
0581: // " " + status + " " + message);
0582:
0583: // Send the content-length and content-type headers (if any)
0584: if (getContentType() != null) {
0585: outputWriter.print("Content-Type: " + getContentType()
0586: + "\r\n");
0587: // System.out.println(" Content-Type: " + getContentType());
0588: }
0589: if (getContentLength() >= 0) {
0590: outputWriter.print("Content-Length: " + getContentLength()
0591: + "\r\n");
0592: // System.out.println(" Content-Length: " + getContentLength());
0593: }
0594:
0595: // Send all specified headers (if any)
0596: synchronized (headers) {
0597: Iterator names = headers.keySet().iterator();
0598: while (names.hasNext()) {
0599: String name = (String) names.next();
0600: ArrayList values = (ArrayList) headers.get(name);
0601: Iterator items = values.iterator();
0602: while (items.hasNext()) {
0603: String value = (String) items.next();
0604: outputWriter.print(name);
0605: outputWriter.print(": ");
0606: outputWriter.print(value);
0607: outputWriter.print("\r\n");
0608: // System.out.println(" " + name + ": " + value);
0609: }
0610: }
0611: }
0612:
0613: // Add the session ID cookie if necessary
0614: HttpServletRequest hreq = (HttpServletRequest) request
0615: .getRequest();
0616: HttpSession session = hreq.getSession(false);
0617:
0618: if ((session != null) && session.isNew()
0619: && (getContext() != null) && getContext().getCookies()) {
0620: Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME,
0621: session.getId());
0622: cookie.setMaxAge(-1);
0623: String contextPath = null;
0624: if (context != null)
0625: contextPath = context.getPath();
0626: if ((contextPath != null) && (contextPath.length() > 0))
0627: cookie.setPath(contextPath);
0628: else
0629: cookie.setPath("/");
0630: if (hreq.isSecure())
0631: cookie.setSecure(true);
0632: addCookie(cookie);
0633: }
0634:
0635: // Send all specified cookies (if any)
0636: synchronized (cookies) {
0637: Iterator items = cookies.iterator();
0638: while (items.hasNext()) {
0639: Cookie cookie = (Cookie) items.next();
0640: outputWriter.print(CookieTools
0641: .getCookieHeaderName(cookie));
0642: outputWriter.print(": ");
0643: outputWriter.print(CookieTools
0644: .getCookieHeaderValue(cookie));
0645: outputWriter.print("\r\n");
0646: //System.out.println(" " +
0647: // CookieTools.getCookieHeaderName(cookie) +
0648: // ": " +
0649: // CookieTools.getCookieHeaderValue(cookie));
0650: }
0651: }
0652:
0653: // Send a terminating blank line to mark the end of the headers
0654: outputWriter.print("\r\n");
0655: outputWriter.flush();
0656: // System.out.println("----------");
0657:
0658: // The response is now committed
0659: committed = true;
0660:
0661: }
0662:
0663: /**
0664: * Convert (if necessary) and return the absolute URL that represents the
0665: * resource referenced by this possibly relative URL. If this URL is
0666: * already absolute, return it unchanged.
0667: *
0668: * @param location URL to be (possibly) converted and then returned
0669: *
0670: * @exception IllegalArgumentException if a MalformedURLException is
0671: * thrown when converting the relative URL to an absolute one
0672: */
0673: private String toAbsolute(String location) {
0674:
0675: if (location == null)
0676: return (location);
0677:
0678: // Construct a new absolute URL if possible (cribbed from
0679: // the DefaultErrorPage servlet)
0680: URL url = null;
0681: try {
0682: url = new URL(location);
0683: } catch (MalformedURLException e1) {
0684: HttpServletRequest hreq = (HttpServletRequest) request
0685: .getRequest();
0686: String requrl = HttpUtils.getRequestURL(hreq).toString();
0687: try {
0688: url = new URL(new URL(requrl), location);
0689: } catch (MalformedURLException e2) {
0690: throw new IllegalArgumentException(location);
0691: }
0692: }
0693: return (url.toExternalForm());
0694:
0695: }
0696:
0697: /**
0698: * Return the specified URL with the specified session identifier
0699: * suitably encoded.
0700: *
0701: * @param url URL to be encoded with the session id
0702: * @param sessionId Session id to be included in the encoded URL
0703: */
0704: private String toEncoded(String url, String sessionId) {
0705:
0706: if ((url == null) || (sessionId == null))
0707: return (url);
0708:
0709: String path = url;
0710: String query = "";
0711: String anchor = "";
0712: int question = url.indexOf('?');
0713: if (question >= 0) {
0714: path = url.substring(0, question);
0715: query = url.substring(question);
0716: }
0717: int pound = path.indexOf('#');
0718: if (pound >= 0) {
0719: anchor = path.substring(pound);
0720: path = path.substring(0, pound);
0721: }
0722: StringBuffer sb = new StringBuffer(path);
0723: if (sb.length() > 0) { // jsessionid can't be first.
0724: sb.append(";jsessionid=");
0725: sb.append(sessionId);
0726: }
0727: sb.append(anchor);
0728: sb.append(query);
0729: return (sb.toString());
0730:
0731: }
0732:
0733: // ------------------------------------------------ ServletResponse Methods
0734:
0735: /**
0736: * Flush the buffer and commit this response. If this is the first output,
0737: * send the HTTP headers prior to the user data.
0738: *
0739: * @exception IOException if an input/output error occurs
0740: */
0741: public void flushBuffer() throws IOException {
0742:
0743: if (System.getSecurityManager() != null) {
0744: try {
0745: PrivilegedFlushBuffer dp = new PrivilegedFlushBuffer();
0746: AccessController.doPrivileged(dp);
0747: } catch (PrivilegedActionException pe) {
0748: throw (IOException) pe.getException();
0749: }
0750: } else {
0751: doFlushBuffer();
0752: }
0753:
0754: }
0755:
0756: private void doFlushBuffer() throws IOException {
0757:
0758: if (!isCommitted())
0759: sendHeaders();
0760:
0761: super .flushBuffer();
0762:
0763: }
0764:
0765: /**
0766: * Clear any content written to the buffer. In addition, all cookies
0767: * and headers are cleared, and the status is reset.
0768: *
0769: * @exception IllegalStateException if this response has already
0770: * been committed
0771: */
0772: public void reset() {
0773:
0774: if (included)
0775: return; // Ignore any call from an included servlet
0776:
0777: super .reset();
0778: cookies.clear();
0779: headers.clear();
0780: message = null;
0781: status = HttpServletResponse.SC_OK;
0782:
0783: }
0784:
0785: /**
0786: * Set the content length (in bytes) for this Response.
0787: *
0788: * @param length The new content length
0789: */
0790: public void setContentLength(int length) {
0791:
0792: if (isCommitted())
0793: return;
0794:
0795: if (included)
0796: return; // Ignore any call from an included servlet
0797:
0798: super .setContentLength(length);
0799:
0800: }
0801:
0802: /**
0803: * Set the content type for this Response.
0804: *
0805: * @param type The new content type
0806: */
0807: public void setContentType(String type) {
0808:
0809: if (isCommitted())
0810: return;
0811:
0812: if (included)
0813: return; // Ignore any call from an included servlet
0814:
0815: super .setContentType(type);
0816:
0817: }
0818:
0819: /**
0820: * Set the Locale that is appropriate for this response, including
0821: * setting the appropriate character encoding.
0822: *
0823: * @param locale The new locale
0824: */
0825: public void setLocale(Locale locale) {
0826:
0827: if (isCommitted())
0828: return;
0829:
0830: if (included)
0831: return; // Ignore any call from an included servlet
0832:
0833: super .setLocale(locale);
0834: String language = locale.getLanguage();
0835: if ((language != null) && (language.length() > 0)) {
0836: String country = locale.getCountry();
0837: StringBuffer value = new StringBuffer(language);
0838: if ((country != null) && (country.length() > 0)) {
0839: value.append('-');
0840: value.append(country);
0841: }
0842: setHeader("Content-Language", value.toString());
0843: }
0844:
0845: }
0846:
0847: // -------------------------------------------- HttpServletResponse Methods
0848:
0849: /**
0850: * Add the specified Cookie to those that will be included with
0851: * this Response.
0852: *
0853: * @param cookie Cookie to be added
0854: */
0855: public void addCookie(Cookie cookie) {
0856:
0857: if (isCommitted())
0858: return;
0859:
0860: if (included)
0861: return; // Ignore any call from an included servlet
0862:
0863: synchronized (cookies) {
0864: cookies.add(cookie);
0865: }
0866:
0867: }
0868:
0869: /**
0870: * Add the specified date header to the specified value.
0871: *
0872: * @param name Name of the header to set
0873: * @param value Date value to be set
0874: */
0875: public void addDateHeader(String name, long value) {
0876:
0877: if (isCommitted())
0878: return;
0879:
0880: if (included)
0881: return; // Ignore any call from an included servlet
0882:
0883: addHeader(name, format.format(new Date(value)));
0884:
0885: }
0886:
0887: /**
0888: * Add the specified header to the specified value.
0889: *
0890: * @param name Name of the header to set
0891: * @param value Value to be set
0892: */
0893: public void addHeader(String name, String value) {
0894:
0895: if (isCommitted())
0896: return;
0897:
0898: if (included)
0899: return; // Ignore any call from an included servlet
0900:
0901: synchronized (headers) {
0902: ArrayList values = (ArrayList) headers.get(name);
0903: if (values == null) {
0904: values = new ArrayList();
0905: headers.put(name, values);
0906: }
0907: values.add(value);
0908: }
0909:
0910: }
0911:
0912: /**
0913: * Add the specified integer header to the specified value.
0914: *
0915: * @param name Name of the header to set
0916: * @param value Integer value to be set
0917: */
0918: public void addIntHeader(String name, int value) {
0919:
0920: if (isCommitted())
0921: return;
0922:
0923: if (included)
0924: return; // Ignore any call from an included servlet
0925:
0926: addHeader(name, "" + value);
0927:
0928: }
0929:
0930: /**
0931: * Has the specified header been set already in this response?
0932: *
0933: * @param name Name of the header to check
0934: */
0935: public boolean containsHeader(String name) {
0936:
0937: synchronized (headers) {
0938: return (headers.get(name) != null);
0939: }
0940:
0941: }
0942:
0943: /**
0944: * Encode the session identifier associated with this response
0945: * into the specified redirect URL, if necessary.
0946: *
0947: * @param url URL to be encoded
0948: */
0949: public String encodeRedirectURL(String url) {
0950:
0951: if (isEncodeable(toAbsolute(url))) {
0952: HttpServletRequest hreq = (HttpServletRequest) request
0953: .getRequest();
0954: return (toEncoded(url, hreq.getSession().getId()));
0955: } else
0956: return (url);
0957:
0958: }
0959:
0960: /**
0961: * Encode the session identifier associated with this response
0962: * into the specified redirect URL, if necessary.
0963: *
0964: * @param url URL to be encoded
0965: *
0966: * @deprecated As of Version 2.1 of the Java Servlet API, use
0967: * <code>encodeRedirectURL()</code> instead.
0968: */
0969: public String encodeRedirectUrl(String url) {
0970:
0971: return (encodeRedirectURL(url));
0972:
0973: }
0974:
0975: /**
0976: * Encode the session identifier associated with this response
0977: * into the specified URL, if necessary.
0978: *
0979: * @param url URL to be encoded
0980: */
0981: public String encodeURL(String url) {
0982: if (isEncodeable(toAbsolute(url))) {
0983: HttpServletRequest hreq = (HttpServletRequest) request
0984: .getRequest();
0985: return (toEncoded(url, hreq.getSession().getId()));
0986: } else
0987: return (url);
0988:
0989: }
0990:
0991: /**
0992: * Encode the session identifier associated with this response
0993: * into the specified URL, if necessary.
0994: *
0995: * @param url URL to be encoded
0996: *
0997: * @deprecated As of Version 2.1 of the Java Servlet API, use
0998: * <code>encodeURL()</code> instead.
0999: */
1000: public String encodeUrl(String url) {
1001:
1002: return (encodeURL(url));
1003:
1004: }
1005:
1006: /**
1007: * Send an acknowledgment of a request.
1008: *
1009: * @exception IOException if an input/output error occurs
1010: */
1011: public void sendAcknowledgement() throws IOException {
1012: }
1013:
1014: /**
1015: * Send an error response with the specified status and a
1016: * default message.
1017: *
1018: * @param status HTTP status code to send
1019: *
1020: * @exception IllegalStateException if this response has
1021: * already been committed
1022: * @exception IOException if an input/output error occurs
1023: */
1024: public void sendError(int status) throws IOException {
1025:
1026: sendError(status, getStatusMessage(status));
1027:
1028: }
1029:
1030: /**
1031: * Send an error response with the specified status and message.
1032: *
1033: * @param status HTTP status code to send
1034: * @param message Corresponding message to send
1035: *
1036: * @exception IllegalStateException if this response has
1037: * already been committed
1038: * @exception IOException if an input/output error occurs
1039: */
1040: public void sendError(int status, String message)
1041: throws IOException {
1042:
1043: if (isCommitted())
1044: throw new IllegalStateException(sm
1045: .getString("httpResponseBase.sendError.ise"));
1046:
1047: if (included)
1048: return; // Ignore any call from an included servlet
1049:
1050: setError();
1051:
1052: // Record the status code and message.
1053: this .status = status;
1054: this .message = message;
1055:
1056: // Clear any data content that has been buffered
1057: resetBuffer();
1058:
1059: // Cause the response to be finished (from the application perspective)
1060: setSuspended(true);
1061:
1062: }
1063:
1064: /**
1065: * Send a temporary redirect to the specified redirect location URL.
1066: *
1067: * @param location Location URL to redirect to
1068: *
1069: * @exception IllegalStateException if this response has
1070: * already been committed
1071: * @exception IOException if an input/output error occurs
1072: */
1073: public void sendRedirect(String location) throws IOException {
1074:
1075: if (isCommitted())
1076: throw new IllegalStateException(sm
1077: .getString("httpResponseBase.sendRedirect.ise"));
1078:
1079: if (included)
1080: return; // Ignore any call from an included servlet
1081:
1082: // Clear any data content that has been buffered
1083: resetBuffer();
1084:
1085: // Generate a temporary redirect to the specified location
1086: try {
1087: String absolute = toAbsolute(location);
1088: setStatus(SC_MOVED_TEMPORARILY);
1089: setHeader("Location", absolute);
1090: } catch (IllegalArgumentException e) {
1091: setStatus(SC_NOT_FOUND);
1092: }
1093:
1094: // Cause the response to be finished (from the application perspective)
1095: setSuspended(true);
1096:
1097: }
1098:
1099: /**
1100: * Set the specified date header to the specified value.
1101: *
1102: * @param name Name of the header to set
1103: * @param value Date value to be set
1104: */
1105: public void setDateHeader(String name, long value) {
1106:
1107: if (isCommitted())
1108: return;
1109:
1110: if (included)
1111: return; // Ignore any call from an included servlet
1112:
1113: setHeader(name, format.format(new Date(value)));
1114:
1115: }
1116:
1117: /**
1118: * Set the specified header to the specified value.
1119: *
1120: * @param name Name of the header to set
1121: * @param value Value to be set
1122: */
1123: public void setHeader(String name, String value) {
1124:
1125: if (isCommitted())
1126: return;
1127:
1128: if (included)
1129: return; // Ignore any call from an included servlet
1130:
1131: ArrayList values = new ArrayList();
1132: values.add(value);
1133: synchronized (headers) {
1134: headers.put(name, values);
1135: }
1136:
1137: String match = name.toLowerCase();
1138: if (match.equals("content-length")) {
1139: int contentLength = -1;
1140: try {
1141: contentLength = Integer.parseInt(value);
1142: } catch (NumberFormatException e) {
1143: ;
1144: }
1145: if (contentLength >= 0)
1146: setContentLength(contentLength);
1147: } else if (match.equals("content-type")) {
1148: setContentType(value);
1149: }
1150:
1151: }
1152:
1153: /**
1154: * Set the specified integer header to the specified value.
1155: *
1156: * @param name Name of the header to set
1157: * @param value Integer value to be set
1158: */
1159: public void setIntHeader(String name, int value) {
1160:
1161: if (isCommitted())
1162: return;
1163:
1164: if (included)
1165: return; // Ignore any call from an included servlet
1166:
1167: setHeader(name, "" + value);
1168:
1169: }
1170:
1171: /**
1172: * Set the HTTP status to be returned with this response.
1173: *
1174: * @param status The new HTTP status
1175: */
1176: public void setStatus(int status) {
1177:
1178: setStatus(status, getStatusMessage(status));
1179:
1180: }
1181:
1182: /**
1183: * Set the HTTP status and message to be returned with this response.
1184: *
1185: * @param status The new HTTP status
1186: * @param message The associated text message
1187: *
1188: * @deprecated As of Version 2.1 of the Java Servlet API, this method
1189: * has been deprecated due to the ambiguous meaning of the message
1190: * parameter.
1191: */
1192: public void setStatus(int status, String message) {
1193:
1194: if (included)
1195: return; // Ignore any call from an included servlet
1196:
1197: this.status = status;
1198: this.message = message;
1199:
1200: }
1201:
1202: }
|