This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/main by this push: new 48df571e7f Implement the new sendRedirect() methods in Servlet 6.1 48df571e7f is described below commit 48df571e7f8b0f4afe0353b559b6844d637c7c56 Author: Mark Thomas <ma...@apache.org> AuthorDate: Tue Mar 14 14:15:54 2023 +0000 Implement the new sendRedirect() methods in Servlet 6.1 --- java/jakarta/servlet/http/HttpServletResponse.java | 97 +++++++++++++++++++--- .../servlet/http/HttpServletResponseWrapper.java | 30 ++++++- java/org/apache/catalina/connector/Response.java | 30 ++----- .../apache/catalina/connector/ResponseFacade.java | 4 +- .../catalina/core/ApplicationHttpResponse.java | 12 +-- .../filters/TesterHttpServletResponse.java | 2 +- webapps/docs/changelog.xml | 4 + 7 files changed, 132 insertions(+), 47 deletions(-) diff --git a/java/jakarta/servlet/http/HttpServletResponse.java b/java/jakarta/servlet/http/HttpServletResponse.java index daacbc212b..a1757dbc71 100644 --- a/java/jakarta/servlet/http/HttpServletResponse.java +++ b/java/jakarta/servlet/http/HttpServletResponse.java @@ -112,22 +112,99 @@ public interface HttpServletResponse extends ServletResponse { void sendError(int sc) throws IOException; /** - * Sends a temporary redirect response to the client using the specified redirect location URL. This method can - * accept relative URLs; the servlet container must convert the relative URL to an absolute URL before sending the - * response to the client. If the location is relative without a leading '/' the container interprets it as relative - * to the current request URI. If the location is relative with a leading '/' the container interprets it as - * relative to the servlet container root. + * Sends a redirect response to the client using the specified redirect location URL with the status code + * {@link #SC_FOUND} 302 (Found), clears the response buffer and commits the response. The response buffer will be + * replaced with a short hypertext note as per RFC 9110. + * <p> + * This method has no effect if called from an include. + * + * @param location the redirect location URL (may be absolute or relative) + * + * @exception IOException If an input or output exception occurs + * @exception IllegalArgumentException If a relative URL is given and cannot be converted into an absolute URL + * @exception IllegalStateException If the response was already committed when this method was called + * + * @see #sendRedirect(String, int, boolean) + */ + default void sendRedirect(String location) throws IOException { + sendRedirect(location, SC_FOUND, true); + } + + /** + * Sends a redirect response to the client using the specified redirect location URL with the status code + * {@link #SC_FOUND} 302 (Found), optionally clears the response buffer and commits the response. If the response + * buffer is cleared, it will be replaced with a short hypertext note as per RFC 9110. + * <p> + * This method has no effect if called from an include. + * + * @param location the redirect location URL (may be absolute or relative) + * @param clearBuffer if {@code true}, clear the buffer and replace it with the data set by this method otherwise + * retain the existing buffer + * + * @exception IOException If an input or output exception occurs + * @exception IllegalArgumentException If a relative URL is given and cannot be converted into an absolute URL + * @exception IllegalStateException If the response was already committed when this method was called + * + * @see #sendRedirect(String, int, boolean) + */ + default void sendRedirect(String location, boolean clearBuffer) throws IOException { + sendRedirect(location, SC_FOUND, clearBuffer); + } + + /** + * Sends a redirect response to the client using the specified redirect location URL and status code, clears the + * response buffer and commits the response. The response buffer will be replaced with a short hypertext note as per + * RFC 9110. + * <p> + * This method has no effect if called from an include. + * + * @param location the redirect location URL (may be absolute or relative) + * @param sc the status code to use for the redirect + * + * @exception IOException If an input or output exception occurs + * @exception IllegalArgumentException If a relative URL is given and cannot be converted into an absolute URL + * @exception IllegalStateException If the response was already committed when this method was called + * + * @see #sendRedirect(String, int, boolean) + */ + default void sendRedirect(String location, int sc) throws IOException { + sendRedirect(location, sc, true); + } + + /** + * Sends a redirect response to the client using the specified redirect location URL and status code, optionally + * clears the response buffer and commits the response. If the response buffer is cleared, it will be replaced with + * a short hypertext note as per RFC 9110. + * <p> + * This method has no effect if called from an include. + * <p> + * This method accepts both relative and absolute URLs. Absolute URLs passed to this method are used as provided as + * the redirect location URL. Relative URLs are converted to absolute URLs unless a container specific + * feature/option is provided that controls whether relative URLs passed to this method are converted to absolute + * URLs or used as provided for the redirect location URL. If converting a relative URL to an absolute URL then: + * <ul> + * <li>If the location is relative without a leading '/' the container interprets it as relative to the current + * request URI.</li> + * <li>If the location is relative with a leading '/' the container interprets it as relative to the servlet + * container root.</li> + * <li>If the location is relative with two leading '/' the container interprets it as a network-path reference (see + * <a href="http://www.ietf.org/rfc/rfc3986.txt"> RFC 3986: Uniform Resource Identifier (URI): Generic Syntax</a>, + * section 4.2 "Relative Reference").</li> + * </ul> * <p> * If the response has already been committed, this method throws an IllegalStateException. After using this method, * the response should be considered to be committed and should not be written to. * - * @param location the redirect location URL + * @param location the redirect location URL (may be absolute or relative) + * @param sc the status code to use for the redirect + * @param clearBuffer if {@code true}, clear the buffer and replace it with the data set by this method otherwise + * retain the existing buffer * - * @exception IOException If an input or output exception occurs - * @exception IllegalStateException If the response was committed or if a partial URL is given and cannot be - * converted into a valid URL + * @exception IOException If an input or output exception occurs + * @exception IllegalArgumentException If a relative URL is given and cannot be converted into an absolute URL + * @exception IllegalStateException If the response was already committed when this method was called */ - void sendRedirect(String location) throws IOException; + void sendRedirect(String location, int sc, boolean clearBuffer) throws IOException; /** * Sets a response header with the given name and date-value. The date is specified in terms of milliseconds since diff --git a/java/jakarta/servlet/http/HttpServletResponseWrapper.java b/java/jakarta/servlet/http/HttpServletResponseWrapper.java index e6c491e55b..2804d4795a 100644 --- a/java/jakarta/servlet/http/HttpServletResponseWrapper.java +++ b/java/jakarta/servlet/http/HttpServletResponseWrapper.java @@ -98,13 +98,41 @@ public class HttpServletResponseWrapper extends ServletResponseWrapper implement } /** - * The default behavior of this method is to return sendRedirect(String location) on the wrapped response object. + * The default behavior of this method is to call sendRedirect(String location) on the wrapped response object. */ @Override public void sendRedirect(String location) throws IOException { this._getHttpServletResponse().sendRedirect(location); } + /** + * The default behavior of this method is to call sendRedirect(String location, int sc) on the wrapped response + * object. + */ + @Override + public void sendRedirect(String location, int sc) throws IOException { + this._getHttpServletResponse().sendRedirect(location, sc); + } + + /** + * The default behavior of this method is to call sendRedirect(String location, boolean clearBuffer) on the wrapped + * response object. + */ + @Override + public void sendRedirect(String location, boolean clearBuffer) throws IOException { + this._getHttpServletResponse().sendRedirect(location, clearBuffer); + } + + /** + * The default behavior of this method is to call sendRedirect(String location, int sc, boolean clearBuffer) on the + * wrapped response object. + */ + @Override + public void sendRedirect(String location, int sc, boolean clearBuffer) throws IOException { + this._getHttpServletResponse().sendRedirect(location, sc, clearBuffer); + } + + /** * The default behavior of this method is to call setDateHeader(String name, long date) on the wrapped response * object. diff --git a/java/org/apache/catalina/connector/Response.java b/java/org/apache/catalina/connector/Response.java index 9ba8a399c6..e96cd9298c 100644 --- a/java/org/apache/catalina/connector/Response.java +++ b/java/org/apache/catalina/connector/Response.java @@ -1222,30 +1222,8 @@ public class Response implements HttpServletResponse { } - /** - * Send a temporary redirect to the specified redirect location URL. - * - * @param location Location URL to redirect to - * - * @exception IllegalStateException if this response has already been committed - * @exception IOException if an input/output error occurs - */ @Override - public void sendRedirect(String location) throws IOException { - sendRedirect(location, SC_FOUND); - } - - - /** - * Internal method that allows a redirect to be sent with a status other than {@link HttpServletResponse#SC_FOUND} - * (302). No attempt is made to validate the status code. - * - * @param location Location URL to redirect to - * @param status HTTP status code that will be sent - * - * @throws IOException an IO exception occurred - */ - public void sendRedirect(String location, int status) throws IOException { + public void sendRedirect(String location, int status, boolean clearBuffer) throws IOException { if (isCommitted()) { throw new IllegalStateException(sm.getString("coyoteResponse.sendRedirect.ise")); } @@ -1256,7 +1234,9 @@ public class Response implements HttpServletResponse { } // Clear any data content that has been buffered - resetBuffer(true); + if (clearBuffer) { + resetBuffer(true); + } // Generate a temporary redirect to the specified location try { @@ -1274,7 +1254,7 @@ public class Response implements HttpServletResponse { } setStatus(status); setHeader("Location", locationUri); - if (context != null && context.getSendRedirectBody()) { + if (clearBuffer && context != null && context.getSendRedirectBody()) { PrintWriter writer = getWriter(); writer.print(sm.getString("coyoteResponse.sendRedirect.note", Escape.htmlElementContent(locationUri))); flushBuffer(); diff --git a/java/org/apache/catalina/connector/ResponseFacade.java b/java/org/apache/catalina/connector/ResponseFacade.java index 1ffcdf593e..accfbbd00b 100644 --- a/java/org/apache/catalina/connector/ResponseFacade.java +++ b/java/org/apache/catalina/connector/ResponseFacade.java @@ -272,10 +272,10 @@ public class ResponseFacade implements HttpServletResponse { @Override - public void sendRedirect(String location) throws IOException { + public void sendRedirect(String location, int sc, boolean clearBuffer) throws IOException { checkCommitted("coyoteResponse.sendRedirect.ise"); response.setAppCommitted(true); - response.sendRedirect(location); + response.sendRedirect(location, sc, clearBuffer); } diff --git a/java/org/apache/catalina/core/ApplicationHttpResponse.java b/java/org/apache/catalina/core/ApplicationHttpResponse.java index 73ae1eddf6..75f882fff2 100644 --- a/java/org/apache/catalina/core/ApplicationHttpResponse.java +++ b/java/org/apache/catalina/core/ApplicationHttpResponse.java @@ -257,19 +257,15 @@ class ApplicationHttpResponse extends HttpServletResponseWrapper { /** + * {@inheritDoc} + * <p> * Disallow <code>sendRedirect()</code> calls on an included response. - * - * @param location The new location - * - * @exception IOException if an input/output error occurs */ @Override - public void sendRedirect(String location) throws IOException { - + public void sendRedirect(String location, int sc, boolean clearBuffer) throws IOException { if (!included) { - ((HttpServletResponse) getResponse()).sendRedirect(location); + ((HttpServletResponse) getResponse()).sendRedirect(location, sc, clearBuffer); } - } diff --git a/test/org/apache/catalina/filters/TesterHttpServletResponse.java b/test/org/apache/catalina/filters/TesterHttpServletResponse.java index a440da7837..aa9b00a28c 100644 --- a/test/org/apache/catalina/filters/TesterHttpServletResponse.java +++ b/test/org/apache/catalina/filters/TesterHttpServletResponse.java @@ -349,7 +349,7 @@ public class TesterHttpServletResponse implements HttpServletResponse { } @Override - public void sendRedirect(String location) throws IOException { + public void sendRedirect(String location, int sc, boolean clearBuffer) throws IOException { /* NOOP */} @Override diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 1204011225..fdaab5447c 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -133,6 +133,10 @@ <code>authenticationSessionTimeout</code> attribute of the FORM authenticator. (markt) </add> + <add> + Implement the new Servlet API methods that provide additional control + when sending a redirect to the client. (markt) + </add> </changelog> </subsection> <subsection name="Coyote"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org