0

So I get the following exception when a user cancels a request on my web application hosted on a Tomcat application server, with dependency management handled through Maven:

ClientAbortException:  java.net.SocketException: Connection reset
    at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:406)
    at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:480)
    at org.apache.tomcat.util.buf.ByteChunk.append(ByteChunk.java:366)
    at org.apache.catalina.connector.OutputBuffer.writeBytes(OutputBuffer.java:431)
    at org.apache.catalina.connector.OutputBuffer.write(OutputBuffer.java:419)
    at org.apache.catalina.connector.CoyoteOutputStream.write(CoyoteOutputStream.java:91)
    ...

I have a Spring @ControllerAdvice class that handles all exceptions, and sends an email.

@ExceptionHandler(value = Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ResponseEntity defaultErrorHandler(final HttpServletRequest request, final Principal principal, final Exception e) {

    //send email with details of error

    return ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
}

However, I do not want to send the email if it is this ClientAbortException.

I would like to do something like this:

if (!(e instanceof ClientAbortException)) {
    //send email with details of error
}

But ClientAbortException does not seem to be on my classpath, as it is an exception included in a tomcat server-level lib.

I could check if e instance of SocketException, but I might miss other SocketExceptions that I care about. My next idea was something like:

e instanceof SocketException && e.getMessage().contains("Connection reset")

But it seems like there should be a more straightforward way of doing this.

Any ideas?

Andrew Mairose
  • 10,615
  • 12
  • 60
  • 102

1 Answers1

0

I look at java doc and the ClientAbortException is child of IOException so you can't use instance of to SocketException.

On my version of tomcat the code that throws the exception is:

if (cnt > 0) {
        // real write to the adapter
        outputChunk.setBytes(buf, off, cnt);
        try {
            coyoteResponse.doWrite(outputChunk);
        } catch (IOException e) {
            // An IOException on a write is almost always due to
            // the remote client aborting the request.  Wrap this
            // so that it can be handled better by the error dispatcher.
            throw new ClientAbortException(e);
        }
    }

I think you just create a new exception handler for you client abort exception. Don't use instance on different exceptions.

@ExceptionHandler(value = ClientAbortException.class)
public ResponseEntity<ErrorResponse> handleClientAbort(Exception ex, HttpServletRequest req) {
    //YOUR HANDLER IMPLEMENTATION

}

You can use the @Order annotation to configure the precedence of exceptions.

Community
  • 1
  • 1