From 1dae9aa459436e0bb1a95701ed0d31e12be7788a Mon Sep 17 00:00:00 2001 From: Robert Winch <362503+rwinch@users.noreply.github.com> Date: Tue, 24 Feb 2026 19:43:37 -0600 Subject: [PATCH] Add Missing OnCommitedResponseWrapper Header Overrides Spring Security's `OnCommitedResponseWrapper` does not override the `setHeader`, `setIntHeader`, `addIntHeader` methods. This means that if the `Content-Length` response header is specified using any of those methods then the response body length is not tracked and can be committed before the response headers are written. Spring Security should override the missing methods and track `Content-Length` as is already done for `addHeader`. This issue is the underlying problem for spring-projects/spring-framework#36381 Closes gh-18797 --- .../web/util/OnCommittedResponseWrapper.java | 30 ++++++++++++++++++- .../util/OnCommittedResponseWrapperTests.java | 27 +++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/web/src/main/java/org/springframework/security/web/util/OnCommittedResponseWrapper.java b/web/src/main/java/org/springframework/security/web/util/OnCommittedResponseWrapper.java index 9aeb3c5aec..6d0f576d76 100644 --- a/web/src/main/java/org/springframework/security/web/util/OnCommittedResponseWrapper.java +++ b/web/src/main/java/org/springframework/security/web/util/OnCommittedResponseWrapper.java @@ -58,10 +58,38 @@ public abstract class OnCommittedResponseWrapper extends HttpServletResponseWrap @Override public void addHeader(String name, String value) { + checkContentLengthHeader(name, value); + super.addHeader(name, value); + } + + @Override + public void addIntHeader(String name, int value) { + checkContentLengthHeader(name, value); + super.addIntHeader(name, value); + } + + @Override + public void setHeader(String name, String value) { + checkContentLengthHeader(name, value); + super.setHeader(name, value); + } + + @Override + public void setIntHeader(String name, int value) { + checkContentLengthHeader(name, value); + super.setIntHeader(name, value); + } + + private void checkContentLengthHeader(String name, int value) { + if ("Content-Length".equalsIgnoreCase(name)) { + setContentLength(value); + } + } + + private void checkContentLengthHeader(String name, String value) { if ("Content-Length".equalsIgnoreCase(name)) { setContentLength(Long.parseLong(value)); } - super.addHeader(name, value); } @Override diff --git a/web/src/test/java/org/springframework/security/web/util/OnCommittedResponseWrapperTests.java b/web/src/test/java/org/springframework/security/web/util/OnCommittedResponseWrapperTests.java index 485d8ac4b9..bbdb50b20c 100644 --- a/web/src/test/java/org/springframework/security/web/util/OnCommittedResponseWrapperTests.java +++ b/web/src/test/java/org/springframework/security/web/util/OnCommittedResponseWrapperTests.java @@ -1006,6 +1006,33 @@ public class OnCommittedResponseWrapperTests { assertThat(this.committed).isTrue(); } + @Test + public void addIntHeaderContentLengthPrintWriterWriteStringCommits() throws Exception { + givenGetWriterThenReturn(); + int expected = 1234; + this.response.addIntHeader("Content-Length", String.valueOf(expected).length()); + this.response.getWriter().write(expected); + assertThat(this.committed).isTrue(); + } + + @Test + public void setHeaderContentLengthPrintWriterWriteStringCommits() throws Exception { + givenGetWriterThenReturn(); + int expected = 1234; + this.response.setHeader("Content-Length", String.valueOf(String.valueOf(expected).length())); + this.response.getWriter().write(expected); + assertThat(this.committed).isTrue(); + } + + @Test + public void setIntHeaderContentLengthPrintWriterWriteStringCommits() throws Exception { + givenGetWriterThenReturn(); + int expected = 1234; + this.response.setIntHeader("Content-Length", String.valueOf(expected).length()); + this.response.getWriter().write(expected); + assertThat(this.committed).isTrue(); + } + @Test public void bufferSizePrintWriterWriteCommits() throws Exception { givenGetWriterThenReturn();