0

I'm trying to handle inbound connections closed by the client as silently as possible, i. e. not spam the app log with ERROR messages and stacktraces but only log a brief WARN message.

I'm using Jetty as embedded server in my Spring Boot app. By default, a closed connection leads to this error:

java.io.IOException: Close SendCallback@7cd49aa0[PROCESSING][i=HTTP/1.1{s=200,h=16,cl=-1},cb=org.eclipse.jetty.server.HttpChannel$SendCallback@e46a817] in state PROCESSING
at org.eclipse.jetty.util.IteratingCallback.close(IteratingCallback.java:428)
at org.eclipse.jetty.server.HttpConnection.onClose(HttpConnection.java:524)
at org.eclipse.jetty.io.ssl.SslConnection.onClose(SslConnection.java:378)
at org.eclipse.jetty.io.SelectorManager.connectionClosed(SelectorManager.java:345)
at org.eclipse.jetty.io.ManagedSelector$DestroyEndPoint.run(ManagedSelector.java:1104)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034)
at java.base/java.lang.Thread.run(Unknown Source)

I can easily catch this with an @ExceptionHandler. However the response of my ExceptionHandler causes a subsequent Exception since the channel is closed already:

org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver: Failure in @ExceptionHandler com.acme.controller.CommonControllerErrorHandler#handleUncaught(Exception)
org.eclipse.jetty.io.EofException: Closed
    at org.eclipse.jetty.server.HttpOutput.checkWritable(HttpOutput.java:771)
    at org.eclipse.jetty.server.HttpOutput.write(HttpOutput.java:795)
    at org.springframework.security.web.util.OnCommittedResponseWrapper$SaveContextServletOutputStream.write(OnCommittedResponseWrapper.java:638)
    at org.springframework.util.StreamUtils$NonClosingOutputStream.write(StreamUtils.java:287)
    at com.fasterxml.jackson.core.json.UTF8JsonGenerator._flushBuffer(UTF8JsonGenerator.java:2203)
    at com.fasterxml.jackson.core.json.UTF8JsonGenerator.flush(UTF8JsonGenerator.java:1197)
    at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:1063)
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:456)
    at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:104)
    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:290)
    at org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(HttpEntityMethodProcessor.java:219)
    at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:78)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:135)
    at org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver.doResolveHandlerMethodException(ExceptionHandlerExceptionResolver.java:428)

I tried not to send a response at all, but these approaches failed:

  • Defining an ExceptionHandler with response type ResponseEntity and returning null
  • Defining an ExceptionHandler with void return type, a parameter of type HttpServletResponse and
    • doing nothing with the response
    • calling reset() on the response

Instead, Spring MVC will return HTTP-200 OK and a Cache-Control header by default.
Is there any way to stop Spring MVC from doing this? I debugged through the internals of the framework but I'm reluctant to overwrite larger parts of the logic with custom beans. The internals of the exception handling ("behind the scenes") don't seem to be have been designed for being overwritten or extended.

Peter Wippermann
  • 4,125
  • 5
  • 35
  • 48
  • you want to catch the IOExceotion(that cause by client closed), and log it with the warn message? – smileis2333 May 19 '23 at 08:47
  • @smileis2333 yes, that's exactly what I' doing in an `@ExceptionHandler` method. But that works only if that exception is thrown by my Controller. However, after that ExceptionHandler method returns/ends, Spring MVC will still write a response which causes another `IOException`. And you can't catch those within the internals of Spring MVC. Especially ExceptionHandlers are not applicable there. – Peter Wippermann May 22 '23 at 08:00
  • This https://stackoverflow.com/questions/39727912/spring-mvc-request-interrupted-hook is very similar to your question – smileis2333 May 24 '23 at 07:38
  • yes, the topic is similar. But different from that other question, I'm already being notified about the closed connection. No I want to react appropriately and stop processing in Spring MVC. – Peter Wippermann May 25 '23 at 08:22

0 Answers0