Search code examples
javajavascriptjettyembedded-jettywildfly-8

Java/Jetty/Wildfly: Gracefully Handle Aborted Client Connections


I have developed a web application that plays audio and video files. Users can change the currently playing track, in which case a new source is set for the HTML 5 player on the client-side. The distribution of the application uses embedded Jetty 9, and other environments run WildFly 8.

The application works correctly, however when the a user changes the track WildFly issues this stack trace:

java.io.IOException: An established connection was aborted by the software in your host machine
    at sun.nio.ch.SocketDispatcher.writev0(Native Method) [rt.jar:1.7.0_75]
    at sun.nio.ch.SocketDispatcher.writev(SocketDispatcher.java:55) [rt.jar:1.7.0_75]
    at sun.nio.ch.IOUtil.write(IOUtil.java:148) [rt.jar:1.7.0_75]
    at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:524) [rt.jar:1.7.0_75]
    at org.xnio.nio.NioSocketConduit.write(NioSocketConduit.java:161)
    at io.undertow.server.protocol.http.HttpResponseConduit.write(HttpResponseConduit.java:609) [undertow-core-1.1.0.Final.jar:1.1.0.Final]
    at io.undertow.conduits.AbstractFixedLengthStreamSinkConduit.write(AbstractFixedLengthStreamSinkConduit.java:148) [undertow-core-1.1.0.Final.jar:1.1.0.Final]
    ...

And Jetty throws a similar error:

org.eclipse.jetty.io.EofException
    at org.eclipse.jetty.io.ChannelEndPoint.flush(ChannelEndPoint.java:192)
    at org.eclipse.jetty.io.WriteFlusher.flush(WriteFlusher.java:408)
    at org.eclipse.jetty.io.WriteFlusher.write(WriteFlusher.java:302)
    at org.eclipse.jetty.io.AbstractEndPoint.write(AbstractEndPoint.java:128)
    ...
Caused by: java.io.IOException: Broken pipe
    at sun.nio.ch.FileDispatcherImpl.write0(Native Method)
    at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:47)
    at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93)
    at sun.nio.ch.IOUtil.write(IOUtil.java:65)

It makes sense - yes, the client has aborted the connection to the previous source file and issues a GET request for the next file, but this is the expected operation of the application.

Is there a way to gracefully handle this and avoid these errors?


Solution

  • If the exception is thrown from inside a call your application is making, catch the IOException and handle it how you want - probably by returning from whatever your code is doing without complaining.

    Tomcat has org.apache.catalina.connector.ClientAbortException so you can tell the difference between this and other IOExceptions, but there is no portable exception defined by the Servlet specification.

    If the exception occurs in pure container code, such as an IO worker thread, then I would file a bug arguing that clients disconnecting is expected to occur, so and exception should not be logged at anything higher than debug/trace level.