Bug 62258 - getOutputStream() has already been called for this response with caught IOException and jsp error page
Summary: getOutputStream() has already been called for this response with caught IOExc...
Status: RESOLVED FIXED
Alias: None
Product: Tomcat 9
Classification: Unclassified
Component: Catalina (show other bugs)
Version: 9.0.6
Hardware: PC Linux
: P2 normal (vote)
Target Milestone: -----
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2018-04-05 02:29 UTC by clement
Modified: 2018-07-02 21:05 UTC (History)
0 users



Attachments
log of the Exception (6.63 KB, text/x-log)
2018-04-05 02:29 UTC, clement
Details

Note You need to log in before you can comment on or make changes to this bug.
Description clement 2018-04-05 02:29:43 UTC
Created attachment 35839 [details]
log of the Exception

When an IOException that occurred while writing the response doesn't bubble up the through the Servlet.service and a jsp error page is specified, the following Exception will happen when tomcat tries to render the jsp:

2018-04-04 18:33:04 SEVERE org.apache.catalina.core.ApplicationDispatcher invoke Servlet.service() for servlet [jsp] threw exception
java.lang.IllegalStateException: getOutputStream() has already been called for this response
[...]
2018-04-04 18:33:04 SEVERE org.apache.catalina.core.StandardHostValve custom Exception Processing ErrorPage[errorCode=0, location=/error.jsp]
org.apache.jasper.JasperException: java.lang.IllegalStateException: getOutputStream() has already been called for this response


It's reproductible with a ClientAbortException: call a page that take long time to write the response and interrupt that call (ctr+c on curl). See this project for example: https://github.com/guillaumecle/tomcat-error-page

This doesn't happen in 9.0.5, only 9.0.6. I beleive it's related to bug 41007
Comment 1 Remy Maucherat 2018-04-05 09:14:10 UTC
I don't see what the refactoring could have changed here at this point. The problem is the response is committed (really, as you wrote data) and so that's why there's an include (which fails as you saw). This behavior to try to report an error despite possible problems could be made optional, it's rather weird IMO in a more "modern" website setting.
Comment 2 Mark Thomas 2018-04-07 20:03:27 UTC
There are multiple things going on here.

1. The sample application doesn't reproduce the issue described here. An ISE is thrown but it is thrown because the error JSP tries to create a session. Once:
<%@ page session="false" %>
is added to the JSP error page, then the sample application reproduces the error described here.

2. The ISE is thrown because JSPs always use writers. This makes them a poor choice for error pages where pages that may experience errors use OutputStreams and may have committed the response before the error occurs. Static error pages are generally better as the DefaultServlet has code to handle the OutputStream or Writer case.

3. There is little point producing an error page after an error has occurred that has closed the connection to the client.

1 & 2 represent common problems with using JSPs as error pages. A likely side effect of the changes in bug 41007 - that caused more errors to be passed to the error handling mechanism - is that we will probably see more reports as a result of using JSP error pages inappropriately.

3 is something that we can address. I have committed an enhancement for this to 9.0.x.
Comment 3 clement 2018-04-07 20:34:25 UTC
>3 is something that we can address. I have committed an enhancement for this to 9.0.x.

This is awesome. I'll test it when the next version is released.
Comment 4 clement 2018-07-02 21:05:59 UTC
I confirmed the bug is fixed.