remm 02/03/07 14:43:29 Modified: coyote/src/java/org/apache/coyote Response.java coyote/src/java/org/apache/coyote/tomcat4 CoyoteResponse.java OutputBuffer.java Log: - Add a new 'message' field in the response. - Implement the Catalina response object. Revision Changes Path 1.5 +27 -2 jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/Response.java Index: Response.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/Response.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- Response.java 31 Jan 2002 18:42:29 -0000 1.4 +++ Response.java 7 Mar 2002 22:43:29 -0000 1.5 @@ -100,6 +100,12 @@ /** + * Status message. + */ + protected String message = null; + + + /** * Response headers. */ protected MimeHeaders headers = new MimeHeaders(); @@ -215,6 +221,22 @@ } + /** + * Get the status message. + */ + public String getMessage() { + return message; + } + + + /** + * Set the status message. + */ + public void setMessage(String message) { + this.message = message; + } + + public boolean isCommitted() { return commited; } @@ -279,7 +301,9 @@ locale = Constants.DEFAULT_LOCALE; characterEncoding = Constants.DEFAULT_CHARACTER_ENCODING; contentLength = -1; + status = 200; + message = null; headers.clear(); // Force the PrintWriter to flush its data to the output @@ -388,7 +412,7 @@ contentLanguage = locale.getLanguage(); // only one header ! - headers.setValue("Content-Language").setString( contentLanguage); + headers.setValue("Content-Language").setString(contentLanguage); } public String getCharacterEncoding() { @@ -401,7 +425,7 @@ if (encoding != null) { characterEncoding = encoding; } - headers.setValue("Content-Type").setString( contentType); + headers.setValue("Content-Type").setString(contentType); } public String getContentType() { @@ -437,6 +461,7 @@ characterEncoding = Constants.DEFAULT_CHARACTER_ENCODING; contentLength = -1; status = 200; + message = null; commited = false; errorException = null; errorURI = null; 1.3 +471 -27 jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteResponse.java Index: CoyoteResponse.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteResponse.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- CoyoteResponse.java 1 Feb 2002 17:13:48 -0000 1.2 +++ CoyoteResponse.java 7 Mar 2002 22:43:29 -0000 1.3 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteResponse.java,v 1.2 2002/02/01 17:13:48 remm Exp $ - * $Revision: 1.2 $ - * $Date: 2002/02/01 17:13:48 $ + * $Header: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteResponse.java,v 1.3 2002/03/07 22:43:29 remm Exp $ + * $Revision: 1.3 $ + * $Date: 2002/03/07 22:43:29 $ * * ==================================================================== * @@ -68,6 +68,8 @@ import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; +import java.net.MalformedURLException; +import java.net.URL; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; @@ -82,7 +84,12 @@ import javax.servlet.ServletOutputStream; import javax.servlet.ServletResponse; import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpUtils; + +import org.apache.tomcat.util.http.MimeHeaders; import org.apache.coyote.Response; @@ -104,7 +111,7 @@ * Wrapper object for the Coyote response. * * @author Remy Maucherat - * @version $Revision: 1.2 $ $Date: 2002/02/01 17:13:48 $ + * @version $Revision: 1.3 $ $Date: 2002/03/07 22:43:29 $ */ public class CoyoteResponse @@ -170,8 +177,9 @@ * * @param response The Coyote response */ - public void setCoyoteResponse(Response response) { + public void setCoyoteResponse(Response coyoteResponse) { this.coyoteResponse = coyoteResponse; + outputBuffer.setResponse(coyoteResponse); } /** @@ -207,6 +215,49 @@ } + /** + * The associated output buffer. + */ + protected OutputBuffer outputBuffer = new OutputBuffer(); + + + /** + * The associated output stream. + */ + protected CoyoteOutputStream outputStream = + new CoyoteOutputStream(outputBuffer); + + + /** + * The associated writer. + */ + protected CoyoteWriter writer = new CoyoteWriter(outputBuffer); + + + /** + * The application commit flag. + */ + protected boolean appCommitted = false; + + + /** + * The included flag. + */ + protected boolean included = false; + + + /** + * The error flag. + */ + protected boolean error = false; + + + /** + * The set of Cookies associated with this Response. + */ + protected ArrayList cookies = new ArrayList(); + + // --------------------------------------------------------- Public Methods @@ -215,6 +266,11 @@ * preparation for reuse of this object. */ public void recycle() { + outputBuffer.recycle(); + appCommitted = false; + included = false; + error = false; + cookies.clear(); } @@ -225,7 +281,7 @@ * Return the number of bytes actually written to the output stream. */ public int getContentCount() { - return 0; + return outputBuffer.getBytesWritten(); } @@ -235,6 +291,7 @@ * @param appCommitted The new application committed flag value */ public void setAppCommitted(boolean appCommitted) { + this.appCommitted = appCommitted; } @@ -242,7 +299,7 @@ * Application commit flag accessor. */ public boolean isAppCommitted() { - return false; + return (this.appCommitted || isCommitted()); } @@ -250,7 +307,7 @@ * Return the "processing inside an include" flag. */ public boolean getIncluded() { - return false; + return included; } @@ -261,6 +318,7 @@ * RequestDispatcher.include(), else <code>false</code> */ public void setIncluded(boolean included) { + this.included = included; } @@ -314,7 +372,7 @@ * Return the output stream associated with this Response. */ public OutputStream getStream() { - return null; + return outputStream; } @@ -324,6 +382,7 @@ * @param stream The new output stream */ public void setStream(OutputStream stream) { + // This method is evil } @@ -333,6 +392,7 @@ * @param suspended The new suspended flag value */ public void setSuspended(boolean suspended) { + outputBuffer.setSuspended(suspended); } @@ -340,7 +400,7 @@ * Suspended flag accessor. */ public boolean isSuspended() { - return false; + return outputBuffer.isSuspended(); } @@ -348,6 +408,7 @@ * Set the error flag. */ public void setError() { + error = true; } @@ -355,7 +416,7 @@ * Error flag accessor. */ public boolean isError() { - return false; + return error; } @@ -367,7 +428,8 @@ */ public ServletOutputStream createOutputStream() throws IOException { - return null; + // Probably useless + return outputStream; } @@ -379,6 +441,10 @@ */ public void finishResponse() throws IOException { + // Writing leftover bytes + outputBuffer.close(); + // Finishing response + coyoteResponse.finish(); } @@ -410,7 +476,11 @@ * has already been used. */ public PrintWriter getReporter() { - return null; + if (outputBuffer.isNew()) { + return writer; + } else { + return null; + } } @@ -424,6 +494,7 @@ */ public void flushBuffer() throws IOException { + outputBuffer.flush(); } @@ -431,7 +502,7 @@ * Return the actual buffer size used for this Response. */ public int getBufferSize() { - return 0; + return outputBuffer.getBufferSize(); } @@ -452,7 +523,13 @@ */ public ServletOutputStream getOutputStream() throws IOException { - return null; + + if (writer != null) + throw new IllegalStateException + (sm.getString("coyoteResponse.getOutputStream.ise")); + + return outputStream; + } @@ -473,7 +550,13 @@ */ public PrintWriter getWriter() throws IOException { - return null; + + if (outputStream != null) + throw new IllegalStateException + (sm.getString("coyoteResponse.getWriter.ise")); + + return writer; + } @@ -481,7 +564,7 @@ * Has the output of this response already been committed? */ public boolean isCommitted() { - return false; + return (coyoteResponse.isCommitted()); } @@ -492,6 +575,13 @@ * been committed */ public void reset() { + + if (included) + return; // Ignore any call from an included servlet + + coyoteResponse.reset(); + outputBuffer.reset(); + } @@ -502,6 +592,13 @@ * been committed */ public void resetBuffer() { + + if (isCommitted()) + throw new IllegalStateException + (sm.getString("coyoteResponse.resetBuffer.ise")); + + outputBuffer.reset(); + } @@ -514,6 +611,13 @@ * output has been committed for this response */ public void setBufferSize(int size) { + + if (isCommitted() || !outputBuffer.isNew()) + throw new IllegalStateException + (sm.getString("coyoteResponse.setBufferSize.ise")); + + outputBuffer.setBufferSize(size); + } @@ -523,7 +627,16 @@ * @param length The new content length */ public void setContentLength(int length) { - + + if (isCommitted()) + return; + + // Ignore any call from an included servlet + if (included) + return; + + coyoteResponse.setContentLength(length); + } @@ -533,6 +646,16 @@ * @param type The new content type */ public void setContentType(String type) { + + if (isCommitted()) + return; + + // Ignore any call from an included servlet + if (included) + return; + + coyoteResponse.setContentType(type); + } @@ -543,6 +666,16 @@ * @param locale The new locale */ public void setLocale(Locale locale) { + + if (isCommitted()) + return; + + // Ignore any call from an included servlet + if (included) + return; + + coyoteResponse.setLocale(locale); + } @@ -554,7 +687,7 @@ * a zero-length array if no cookies have been set. */ public Cookie[] getCookies() { - return null; + return ((Cookie[]) cookies.toArray(new Cookie[cookies.size()])); } @@ -567,7 +700,7 @@ * @param name Header name to look up */ public String getHeader(String name) { - return null; + return coyoteResponse.getMimeHeaders().getHeader(name); } @@ -576,7 +709,15 @@ * a zero-length array if no headers have been set. */ public String[] getHeaderNames() { - return null; + + MimeHeaders headers = coyoteResponse.getMimeHeaders(); + int n = headers.size(); + String[] result = new String[n]; + for (int i = 0; i < n; i++) { + result[i] = headers.getName(i).toString(); + } + return result; + } @@ -588,7 +729,15 @@ * @param name Header name to look up */ public String[] getHeaderValues(String name) { - return null; + + MimeHeaders headers = coyoteResponse.getMimeHeaders(); + int n = headers.size(); + String[] result = new String[n]; + for (int i = 0; i < n; i++) { + result[i] = headers.getValue(i).toString(); + } + return result; + } @@ -597,7 +746,7 @@ * for this Response. */ public String getMessage() { - return null; + return coyoteResponse.getMessage(); } @@ -605,7 +754,7 @@ * Return the HTTP status code associated with this Response. */ public int getStatus() { - return 0; + return coyoteResponse.getStatus(); } @@ -617,6 +766,8 @@ * committed */ public void reset(int status, String message) { + reset(); + setStatus(status, message); } @@ -630,6 +781,16 @@ * @param cookie Cookie to be added */ public void addCookie(Cookie cookie) { + + if (isCommitted()) + return; + + // Ignore any call from an included servlet + if (included) + return; + + cookies.add(cookie); + } @@ -640,6 +801,16 @@ * @param value Date value to be set */ public void addDateHeader(String name, long value) { + + if (isCommitted()) + return; + + // Ignore any call from an included servlet + if (included) + return; + + addHeader(name, format.format(new Date(value))); + } @@ -650,6 +821,16 @@ * @param value Value to be set */ public void addHeader(String name, String value) { + + if (isCommitted()) + return; + + // Ignore any call from an included servlet + if (included) + return; + + coyoteResponse.addHeader(name, value); + } @@ -660,6 +841,16 @@ * @param value Integer value to be set */ public void addIntHeader(String name, int value) { + + if (isCommitted()) + return; + + // Ignore any call from an included servlet + if (included) + return; + + addHeader(name, "" + value); + } @@ -669,7 +860,7 @@ * @param name Name of the header to check */ public boolean containsHeader(String name) { - return false; + return coyoteResponse.containsHeader(name); } @@ -680,7 +871,15 @@ * @param url URL to be encoded */ public String encodeRedirectURL(String url) { - return null; + + if (isEncodeable(toAbsolute(url))) { + HttpServletRequest hreq = + (HttpServletRequest) request.getRequest(); + return (toEncoded(url, hreq.getSession().getId())); + } else { + return (url); + } + } @@ -705,7 +904,15 @@ * @param url URL to be encoded */ public String encodeURL(String url) { - return null; + + if (isEncodeable(toAbsolute(url))) { + HttpServletRequest hreq = + (HttpServletRequest) request.getRequest(); + return (toEncoded(url, hreq.getSession().getId())); + } else { + return (url); + } + } @@ -735,6 +942,7 @@ */ public void sendError(int status) throws IOException { + sendError(status, null); } @@ -750,6 +958,26 @@ */ public void sendError(int status, String message) throws IOException { + + if (isCommitted()) + throw new IllegalStateException + (sm.getString("coyoteResponse.sendError.ise")); + + // Ignore any call from an included servlet + if (included) + return; + + setError(); + + coyoteResponse.setStatus(status); + coyoteResponse.setMessage(message); + + // Clear any data content that has been buffered + resetBuffer(); + + // Cause the response to be finished (from the application perspective) + setSuspended(true); + } @@ -764,6 +992,30 @@ */ public void sendRedirect(String location) throws IOException { + + if (isCommitted()) + throw new IllegalStateException + (sm.getString("coyoteResponse.sendRedirect.ise")); + + // Ignore any call from an included servlet + if (included) + return; + + // Clear any data content that has been buffered + resetBuffer(); + + // Generate a temporary redirect to the specified location + try { + String absolute = toAbsolute(location); + setStatus(SC_MOVED_TEMPORARILY); + setHeader("Location", absolute); + } catch (IllegalArgumentException e) { + setStatus(SC_NOT_FOUND); + } + + // Cause the response to be finished (from the application perspective) + setSuspended(true); + } @@ -774,6 +1026,16 @@ * @param value Date value to be set */ public void setDateHeader(String name, long value) { + + if (isCommitted()) + return; + + // Ignore any call from an included servlet + if (included) + return; + + setHeader(name, format.format(new Date(value))); + } @@ -784,6 +1046,16 @@ * @param value Value to be set */ public void setHeader(String name, String value) { + + if (isCommitted()) + return; + + // Ignore any call from an included servlet + if (included) + return; + + coyoteResponse.setHeader(name, value); + } @@ -794,6 +1066,16 @@ * @param value Integer value to be set */ public void setIntHeader(String name, int value) { + + if (isCommitted()) + return; + + // Ignore any call from an included servlet + if (included) + return; + + setHeader(name, "" + value); + } @@ -803,6 +1085,7 @@ * @param status The new HTTP status */ public void setStatus(int status) { + setStatus(status, null); } @@ -817,6 +1100,167 @@ * parameter. */ public void setStatus(int status, String message) { + + if (isCommitted()) + return; + + // Ignore any call from an included servlet + if (included) + return; + + coyoteResponse.setStatus(status); + coyoteResponse.setMessage(message); + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Return <code>true</code> if the specified URL should be encoded with + * a session identifier. This will be true if all of the following + * conditions are met: + * <ul> + * <li>The request we are responding to asked for a valid session + * <li>The requested session ID was not received via a cookie + * <li>The specified URL points back to somewhere within the web + * application that is responding to this request + * </ul> + * + * @param location Absolute URL to be validated + */ + protected boolean isEncodeable(String location) { + + if (location == null) + return (false); + + // Is this an intra-document reference? + if (location.startsWith("#")) + return (false); + + // Are we in a valid session that is not using cookies? + HttpServletRequest hreq = (HttpServletRequest) request.getRequest(); + HttpSession session = hreq.getSession(false); + if (session == null) + return (false); + if (!hreq.isRequestedSessionIdFromURL()) + return (false); + + // Is this a valid absolute URL? + URL url = null; + try { + url = new URL(location); + } catch (MalformedURLException e) { + return (false); + } + + // Does this URL match down to (and including) the context path? + if (!hreq.getScheme().equalsIgnoreCase(url.getProtocol())) + return (false); + if (!hreq.getServerName().equalsIgnoreCase(url.getHost())) + return (false); + int serverPort = hreq.getServerPort(); + if (serverPort == -1) { + if ("https".equals(hreq.getScheme())) + serverPort = 443; + else + serverPort = 80; + } + int urlPort = url.getPort(); + if (urlPort == -1) { + if ("https".equals(url.getProtocol())) + urlPort = 443; + else + urlPort = 80; + } + if (serverPort != urlPort) + return (false); + + String contextPath = getContext().getPath(); + if ((contextPath != null) && (contextPath.length() > 0)) { + String file = url.getFile(); + if ((file == null) || !file.startsWith(contextPath)) + return (false); + if( file.indexOf(";jsessionid=" + session.getId()) >= 0 ) + return (false); + } + + // This URL belongs to our web application, so it is encodeable + return (true); + + } + + + /** + * Convert (if necessary) and return the absolute URL that represents the + * resource referenced by this possibly relative URL. If this URL is + * already absolute, return it unchanged. + * + * @param location URL to be (possibly) converted and then returned + * + * @exception IllegalArgumentException if a MalformedURLException is + * thrown when converting the relative URL to an absolute one + */ + private String toAbsolute(String location) { + + if (location == null) + return (location); + + // Construct a new absolute URL if possible (cribbed from + // the DefaultErrorPage servlet) + URL url = null; + try { + url = new URL(location); + } catch (MalformedURLException e1) { + HttpServletRequest hreq = + (HttpServletRequest) request.getRequest(); + String requrl = HttpUtils.getRequestURL(hreq).toString(); + try { + url = new URL(new URL(requrl), location); + } catch (MalformedURLException e2) { + throw new IllegalArgumentException(location); + } + } + return (url.toExternalForm()); + + } + + + /** + * Return the specified URL with the specified session identifier + * suitably encoded. + * + * @param url URL to be encoded with the session id + * @param sessionId Session id to be included in the encoded URL + */ + private String toEncoded(String url, String sessionId) { + + if ((url == null) || (sessionId == null)) + return (url); + + String path = url; + String query = ""; + String anchor = ""; + int question = url.indexOf('?'); + if (question >= 0) { + path = url.substring(0, question); + query = url.substring(question); + } + int pound = path.indexOf('#'); + if (pound >= 0) { + anchor = path.substring(pound); + path = path.substring(0, pound); + } + StringBuffer sb = new StringBuffer(path); + if( sb.length() > 0 ) { // jsessionid can't be first. + sb.append(";jsessionid="); + sb.append(sessionId); + } + sb.append(anchor); + sb.append(query); + return (sb.toString()); + } 1.2 +24 -3 jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat4/OutputBuffer.java Index: OutputBuffer.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat4/OutputBuffer.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- OutputBuffer.java 7 Mar 2002 04:27:23 -0000 1.1 +++ OutputBuffer.java 7 Mar 2002 22:43:29 -0000 1.2 @@ -135,6 +135,8 @@ private Response coyoteResponse; + private boolean suspended = false; + // ----------------------------------------------------------- Constructors @@ -180,6 +182,22 @@ } + /** + * Is the response output suspended ? + */ + public boolean isSuspended() { + return this.suspended; + } + + + /** + * Set the suspended flag. + */ + public void setSuspended(boolean suspended) { + this.suspended = suspended; + } + + // --------------------------------------------------------- Public Methods @@ -198,6 +216,7 @@ cb.recycle(); bb.recycle(); closed = false; + suspended = false; if (conv!= null) { conv.recycle(); @@ -248,6 +267,8 @@ if (debug > 2) log("realWrite(b, " + off + ", " + cnt + ") " + coyoteResponse); + if (suspended) + return; if (closed) return; if (coyoteResponse == null) @@ -452,7 +473,7 @@ conv = (C2BConverter) encoders.get(enc); if (conv == null) { try { - conv = new C2BConverter(bb,enc); + conv = new C2BConverter(bb, enc); encoders.put(enc, conv); } catch (IOException e) { conv = (C2BConverter) encoders.get(DEFAULT_ENCODING); @@ -506,7 +527,7 @@ public void setBufferSize(int size) { if (size > bb.getLimit()) {// ?????? - bb.setLimit( size ); + bb.setLimit(size); } } @@ -531,7 +552,7 @@ protected void log( String s ) { - System.out.println("OutputBuffer: " + s ); + System.out.println("OutputBuffer: " + s); }
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>