Bug 52157 - 7.0.21 change can use undesired Writer object. Wrapper circumvention. Servlet 2.3
Summary: 7.0.21 change can use undesired Writer object. Wrapper circumvention. Servlet...
Status: RESOLVED DUPLICATE of bug 51952
Alias: None
Product: Tomcat 7
Classification: Unclassified
Component: Servlet & JSP API (show other bugs)
Version: 7.0.21
Hardware: PC All
: P2 normal (vote)
Target Milestone: ---
Assignee: Tomcat Developers Mailing List
Depends on:
Reported: 2011-11-08 20:32 UTC by Brad Plies
Modified: 2011-11-08 23:35 UTC (History)
1 user (show)


Note You need to log in before you can comment on or make changes to this bug.
Description Brad Plies 2011-11-08 20:32:59 UTC
in 7.0.21 the commit:
	"41718: Include a response body when sending a redirect. (markt)"

...catalina.connector.Response.sendRedirect() now calls getWriter() in order to write the body of the http response.  However the committed implementation will bypass any wrappers.  Note that Servlet 2.3 defines HttpServletResponseWrapper.getWriter()
which would allow someone to return an alternate Writer than the default.

line 1335 (sendRedirect()):
            String absolute = toAbsolute(location);
            setHeader("Location", absolute);
            PrintWriter writer = getWriter(); // <<<<<< circumvents wrapping by HttpServletResponseWrapper.getWriter()
	    // .. This directly commits a response to the client without allowing the Wrapper the opportunity to do something different.

So if someone calls wrapper.sendRedirect(location) it invokes the Reponse.sendRedirect().  That Reponse.sendRedirect() gets a reference to a Writer relative to itself and not the Wrapper's.  In a case where the user application desires to intercept  a redirect and do something different, the response has already been committed and will cause an IllegalStateException.

Not sure what would be the best way to fix this.

Possible areas to consider
or http://svn.apache.org/repos/asf/tomcat/tc7.0.x/trunk/java/javax/servlet/http/HttpServletResponseWrapper.java 
or http://svn.apache.org/repos/asf/tomcat/tc7.0.x/trunk/java/org/apache/catalina/connector/Response.java

Bottom line is Servlet 2.3 HttpServletResponseWrapper allows you to control what Writer to return, and the current Tomcat 7.0.21 implementation will get a reference to a default Writer which may be undesirable, commit a response to the undesired Writer, and expose a scenario for an IllegalStateException.

7.0.20 and previous did not have this problem.
Comment 1 Brad Plies 2011-11-08 20:58:17 UTC
Attempted example

// See: http://download.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponseWrapper.html
class MyWrapper extends HttpServletResponseWrapper 
	public MyWrapper(HttpServletResponse response) { super(response); }
	// This was working fine with Tomcat 7.0.20
	public void sendResponse() throws IOException
		this.pw.flush(); this.pw.close();
		ServletOutputStream realStream = super.getOutputStream(); 
		byte[] byteArray = basos.baos.toByteArray();
		realStream.write(byteArray); realStream.flush();
	// NOTE: Alternate Writer & OutputStream
	MyOutputStream basos = new MyOutputStream();
	PrintWriter pw = new PrintWriter(basos);

	// NOTE: Overriding default behavior of Wrapper, returning alternates
	public ServletOutputStream getOutputStream() throws IOException { return basos; }
	public PrintWriter getWriter() throws IOException { return pw; }

public class MyFilter implements Filter
	public void doFilter(final ServletRequest request, final ServletResponse response,
		final FilterChain chain) throws IOException, ServletException
		final HttpServletRequest httpRequest = (HttpServletRequest) request;
		final MyWrapper wrappedResponse = 
			new MyWrapper((HttpServletResponse) response);

		chain.doFilter(httpRequest, wrappedResponse);
		// ... Something down the chain called wrappedResponse.sendRedirect()
		if (someCondition) 
			// Override redirect and handle response directly or something
			response.sendErrorPage(...); // NOTE: Original response object, discarding anything written to the wrapped buffer
			// !!! Blows up in Tomcat 7.0.21 because sendRedirect() circumvented the Wrapper's Writer
			// Accept the wrapped Response as the output
			// Set response output to be same as wrappedResponse output
Comment 2 Mark Thomas 2011-11-08 23:35:49 UTC
There are a bunch of issues related to this for which no simple solution is available since application provided wrappers are unlikely to be available at the point where the redirect needs to take place.

See the duplicate for details of the fix.

*** This bug has been marked as a duplicate of bug 51952 ***