This is not a bug per se. I would like to know WHY
Tomcat does something it does. I am working with spring web 2.5.5 in this application on Tomcat 7.0.
Scenario: When an exception is thrown in within my application, it is caught by the Spring DispatcherServlet.doDispatch method. That method then calls DispatcherServlet.processHandlerException. processHandlerException iterates through any HandlerExceptionResolvers to try to find a ModelAndView to render. In my case, we have a custom handler that returns a ModelAndView. If a ModelAndView is returned from one of the HandlerExceptionResolvers, processHandlerException then calls WebUtils.exposeErrorRequestAttributes. This adds a status of 200, and the exception to the request. After this, processHanderException returns to doDispatch, and the returned ModelAndView are rendered, which commits the response, directing the user to an error page as expected.
What doesn't make sense to me is what follows next. As control bubbles back up the stack from DispatcherServlet, it ultimately reaches org.apache.catalina.core.StandardContextValve.invoke which is one of Tomcat's "valves" which are executed sequentially prior to delivering a request to a
servlet. After control returns to StandardContextValve.invoke it does some checks about request.isAsync and if any errors were applied to the request. Since WebUtils.exposeErrorRequestAttributes (above) applied the exception to the request, it finds that Throwable and calls StandardContextValve.throwable. This method searches for an errorPage (which would have been defined in web.xml) and finds our catch all error page as defined in web.xml. The throwable method then calls the custom method which checks to see if the response is committed (it is in this case). Since it is committed, it calls RequestDispatcher.include. This appears to send the request back through the Dispatcher and ultimately the servlets that handle that errorPage. Even though all the processing is done for that error page, nothing is returned to the user, because the response has already been closed. This is fine, since I already delivered a custom error page to the user.
What I don't understand is: And why does tomcat fire off more processing with RequestDispatcher.include if the response is already committed when spring handled the error? I understand that it does it because it pulled the exception off the request (where Spring placed it after handling the exception). But what benefit is the additional processing after the response has been committed? This question may be better to answer from the spring side of things but I wanted to see if there was some insight on the Tomcat side.
Below is some code snippets that may help understand the problem at hand:
DispatcherServlet.processHandlerException()
WebUtils.exposeErrorRequestAttributes()
Inside StandardContextValve.invoke()
StandardContextValve.throwable()
StandardContextValve.custom()