From 5bdd36810304d053e52f3532d1cdb4deb062f733 Mon Sep 17 00:00:00 2001 From: king-407 <95581750+king-407@users.noreply.github.com> Date: Wed, 3 Jun 2026 20:28:32 +0530 Subject: [PATCH] Set 500 status for disconnected client exceptions Signed-off-by: king-407 <95581750+king-407@users.noreply.github.com> --- .../ExceptionHandlerExceptionResolver.java | 3 +++ .../DefaultHandlerExceptionResolver.java | 6 ++++- ...xceptionHandlerExceptionResolverTests.java | 24 +++++++++++++++++++ .../DefaultHandlerExceptionResolverTests.java | 10 ++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.java index 2dcb87750664..90455e675810 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.java @@ -465,6 +465,9 @@ protected boolean shouldApplyTo(HttpServletRequest request, @Nullable Object han } catch (Throwable invocationEx) { if (disconnectedClientHelper.checkAndLogClientDisconnectedException(invocationEx)) { + if (!response.isCommitted()) { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } return new ModelAndView(); } // Any other than the original exception (or a cause) is unintended here, diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolver.java index fe3ab55a7f09..1f416c046ec9 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolver.java @@ -510,7 +510,8 @@ protected ModelAndView handleAsyncRequestNotUsableException(AsyncRequestNotUsabl * typically an {@link IOException} of a specific subtype or with a message * specific to the underlying Servlet container. Those are detected through * {@link DisconnectedClientHelper#isClientDisconnectedException(Throwable)} - *
By default, do nothing since the response is not usable. + *
By default, set the response status to 500 but otherwise do nothing + * since the response may not be usable. * @param ex the {@code Exception} to be handled * @param request current HTTP request * @param response current HTTP response @@ -522,6 +523,9 @@ protected ModelAndView handleAsyncRequestNotUsableException(AsyncRequestNotUsabl protected ModelAndView handleDisconnectedClientException( Exception ex, HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) { + if (!response.isCommitted()) { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } return new ModelAndView(); } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolverTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolverTests.java index 38af2470ce5d..2da8b6afaf19 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolverTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolverTests.java @@ -436,6 +436,18 @@ void resolveExceptionAsyncRequestNotUsable() throws Exception { assertThat(mav.isEmpty()).isTrue(); } + @Test + void resolveExceptionHandlerRethrowsDisconnectedClientException() throws Exception { + IOException ex = new IOException("Broken pipe"); + HandlerMethod handlerMethod = new HandlerMethod(new RethrowingExceptionController(), "handle"); + this.resolver.afterPropertiesSet(); + ModelAndView mav = this.resolver.resolveException(this.request, this.response, handlerMethod, ex); + + assertThat(mav).isNotNull(); + assertThat(mav.isEmpty()).isTrue(); + assertThat(this.response.getStatus()).isEqualTo(500); + } + @Test void resolveExceptionJsonMediaType() throws UnsupportedEncodingException, NoSuchMethodException { IllegalArgumentException ex = new IllegalArgumentException(); @@ -550,6 +562,18 @@ public void handleException() { } + @Controller + static class RethrowingExceptionController { + + public void handle() {} + + @ExceptionHandler(IOException.class) + public void handleException(IOException ex) throws IOException { + throw ex; + } + } + + @Controller static class ModelArgumentController { diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolverTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolverTests.java index d26fbab1b56a..e17f9b332afb 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolverTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolverTests.java @@ -16,6 +16,7 @@ package org.springframework.web.servlet.mvc.support; +import java.io.IOException; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collections; @@ -171,6 +172,15 @@ void handleHttpMessageNotWritable() { assertThat(response.getStatus()).as("Invalid status code").isEqualTo(500); } + @Test + void handleDisconnectedClientException() { + Exception ex = new IOException("Broken pipe"); + ModelAndView mav = exceptionResolver.resolveException(request, response, null, ex); + assertThat(mav).as("No ModelAndView returned").isNotNull(); + assertThat(mav.isEmpty()).as("No Empty ModelAndView returned").isTrue(); + assertThat(response.getStatus()).as("Invalid status code").isEqualTo(500); + } + @Test void handleMethodArgumentNotValid() throws Exception { BeanPropertyBindingResult errors = new BeanPropertyBindingResult(new TestBean(), "testBean");