Created attachment 34189 [details] Test webapp compile with JDK 1.6 for Tomcat 6 The following exception occurs when users try to access AVI video playback on IE11. My analysis is that it's a bad behavior of Tomcat when using HttpServletResponseWrapper. ClientAbortException: java.io.IOException at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:370) at org.apache.tomcat.util.buf.ByteChunk.append(ByteChunk.java:368) at org.apache.catalina.connector.OutputBuffer.writeBytes(OutputBuffer.java:393) at org.apache.catalina.connector.OutputBuffer.write(OutputBuffer.java:382) at org.apache.catalina.connector.CoyoteOutputStream.write(CoyoteOutputStream.java:89) at org.apache.catalina.servlets.DefaultServlet.copy(DefaultServlet.java:1994) at org.apache.catalina.servlets.DefaultServlet.serveResource(DefaultServlet.java:954) at org.apache.catalina.servlets.DefaultServlet.doGet(DefaultServlet.java:420) at javax.servlet.http.HttpServlet.service(HttpServlet.java:617) at javax.servlet.http.HttpServlet.service(HttpServlet.java:723) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at com.example.BasicFilter.doFilter(BasicFilter.java:35) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293) at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:879) at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:610) at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1777) at java.lang.Thread.run(Thread.java:662) Caused by: java.io.IOException at org.apache.coyote.http11.InternalAprOutputBuffer.flushBuffer(InternalAprOutputBuffer.java:717) at org.apache.coyote.http11.InternalAprOutputBuffer$SocketOutputBuffer.doWrite(InternalAprOutputBuffer.java:747) at org.apache.coyote.http11.filters.IdentityOutputFilter.doWrite(IdentityOutputFilter.java:118) at org.apache.coyote.http11.InternalAprOutputBuffer.doWrite(InternalAprOutputBuffer.java:557) at org.apache.coyote.Response.doWrite(Response.java:533) at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:365) ... 24 more I have setup a very simple reproduction webapp (2 nearly empty class, one html, one video) attach to this issue. (test-t6.war for Tomcat 6, test.war for Tomcat 7+) This webapp is configured with a simple servlet filter, doing nothing special but wrapping the response using a simple HttpServletResponseWrapper (not doing anything at all) and logging request information on exception. To help demonstrate the cause of the problem, the filter expose an init parameter "wrap-response" in web.xml which quickly allows the webapp to be tested with 2 behavior : response wrapped (to exhibit the bug) or not (to behave properly). The home page contains a video player with a very small AVI file. The reproduction steps : * Start Tomcat (any version) with the webapp above * Access the index page using IE 11 on Windows 7 (very important : clear browser cache between each test) --> The exception above occurs. * Edit web.xml, set "wrap-response" init parameter to false * Repeat the test with IE (don't forget to clear cache!) --> No exception. The problem may be workaround by modifying Tomcat's web.xml by disabling Accept-Ranges support. <init-param> <param-name>useAcceptRanges</param-name> <param-value>false</param-value> </init-param> Because the ClientAbortException/IOException does not occurs if the response is not wrapped, and does not occurs either if acceptRange is disabled, it really make me think that is a bug in Tomcat (and not a behavior of the client contrary to what ClientAbortException implies). Bug verified to exist in all following version of tomcat (with a default install) (using JDK 1.6.0_45-b06 on Win7 SP1): Apache Tomcat/7.0.45 (using JDK 1.8.0_102-b14 on Win7 SP1): Apache Tomcat/7.0.70 Apache Tomcat/8.0.36 Apache Tomcat/8.5.4 Apache Tomcat/9.0.0.M9 Bug initially discussed on tomcat users ML http://mail-archives.apache.org/mod_mbox/tomcat-users/201608.mbox/%3C6be06ed8-64da-4f3d-4204-0e89b40617de%40jalios.com%3E
Created attachment 34190 [details] Test webapp compilee with JDK 1.8 for Tomcat 7+
I've looked at a WireShark trace with and without the wrapper. There is no Tomcat bug here. The client drops the connection for no obvious reason on multiple occasions without and without the wrapper. It just so happens that with the wrapper the timing is such that the Exception gets caught by the Filter. I'll add that the client makes multiple requests for the same parts of the avi file. Ignoring the requests it makes and then aborts, it still ends up downloading over 500K of data.
Thank you Mark for this analysis. I am completely ok to accept that IE behaves like sh%t, this would not be the first time. However, how do you explain the fact that without using the HttpServletResponseWrapper the exception does not occur ? It really seems to me that there is a change in Tomcat behavior somewhere, otherwise exception would occur everytime, don't you think ?
(In reply to Olivier Jaquemet from comment #3) > It really seems to me that there is a change in Tomcat behavior somewhere, > otherwise exception would occur everytime, don't you think ? There is a change. I dug into it a little more. With the wrapper, the Default Servlet writes the content and you see the exception when the client aborts the connection. Without the wrapper, Tomcat uses sendFile so the write is handled by a separate thread so the app never sees the exception. This is all entirely as expected.
OKay, everything is now much clearer to me. Thank you Mark for the taking the time to analyze this issue.