diff --git a/spring-web/src/main/java/org/springframework/web/util/ContentCachingResponseWrapper.java b/spring-web/src/main/java/org/springframework/web/util/ContentCachingResponseWrapper.java index 4223a673976c..017c0f635628 100644 --- a/spring-web/src/main/java/org/springframework/web/util/ContentCachingResponseWrapper.java +++ b/spring-web/src/main/java/org/springframework/web/util/ContentCachingResponseWrapper.java @@ -38,7 +38,7 @@ /** * {@link jakarta.servlet.http.HttpServletResponse} wrapper that caches all content written to * the {@linkplain #getOutputStream() output stream} and {@linkplain #getWriter() writer}, - * and allows this content to be retrieved via a {@link #getContentAsByteArray() byte array}. + * and allows this content to be retrieved via a {@linkplain #getContentAsByteArray() byte array}. * *
Used e.g. by {@link org.springframework.web.filter.ShallowEtagHeaderFilter}. * @@ -120,9 +120,16 @@ public PrintWriter getWriter() throws IOException { return this.writer; } + /** + * This method neither flushes content to the client nor commits the underlying + * response, since the content has not yet been copied to the response. + *
Invoke {@link #copyBodyToResponse()} to copy the cached body content to + * the wrapped response object and flush its buffer. + * @see jakarta.servlet.ServletResponseWrapper#flushBuffer() + */ @Override public void flushBuffer() throws IOException { - // do not flush the underlying response as the content has not been copied to it yet + // no-op } @Override @@ -139,15 +146,11 @@ public void setContentLengthLong(long len) { throw new IllegalArgumentException("Content-Length exceeds ContentCachingResponseWrapper's maximum (" + Integer.MAX_VALUE + "): " + len); } - int lenInt = (int) len; - if (lenInt > this.content.size()) { - this.content.resize(lenInt); - } - this.contentLength = lenInt; + setContentLength((int) len); } @Override - public void setContentType(String type) { + public void setContentType(@Nullable String type) { this.contentType = type; } diff --git a/spring-web/src/test/java/org/springframework/web/filter/ContentCachingResponseWrapperTests.java b/spring-web/src/test/java/org/springframework/web/filter/ContentCachingResponseWrapperTests.java index eab4aaa0812c..1c11b5a969b1 100644 --- a/spring-web/src/test/java/org/springframework/web/filter/ContentCachingResponseWrapperTests.java +++ b/spring-web/src/test/java/org/springframework/web/filter/ContentCachingResponseWrapperTests.java @@ -16,17 +16,17 @@ package org.springframework.web.filter; -import java.nio.charset.StandardCharsets; - import jakarta.servlet.http.HttpServletResponse; import org.junit.jupiter.api.Test; -import org.springframework.http.HttpHeaders; import org.springframework.util.FileCopyUtils; import org.springframework.web.testfixture.servlet.MockHttpServletResponse; import org.springframework.web.util.ContentCachingResponseWrapper; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.http.HttpHeaders.CONTENT_LENGTH; +import static org.springframework.http.HttpHeaders.TRANSFER_ENCODING; /** * Unit tests for {@link ContentCachingResponseWrapper}. @@ -36,34 +36,47 @@ public class ContentCachingResponseWrapperTests { @Test void copyBodyToResponse() throws Exception { - byte[] responseBody = "Hello World".getBytes(StandardCharsets.UTF_8); + byte[] responseBody = "Hello World".getBytes(UTF_8); MockHttpServletResponse response = new MockHttpServletResponse(); ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response); - responseWrapper.setStatus(HttpServletResponse.SC_OK); + responseWrapper.setStatus(HttpServletResponse.SC_CREATED); FileCopyUtils.copy(responseBody, responseWrapper.getOutputStream()); responseWrapper.copyBodyToResponse(); - assertThat(response.getStatus()).isEqualTo(200); + assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_CREATED); assertThat(response.getContentLength()).isGreaterThan(0); assertThat(response.getContentAsByteArray()).isEqualTo(responseBody); } @Test void copyBodyToResponseWithTransferEncoding() throws Exception { - byte[] responseBody = "6\r\nHello 5\r\nWorld0\r\n\r\n".getBytes(StandardCharsets.UTF_8); + byte[] responseBody = "6\r\nHello 5\r\nWorld0\r\n\r\n".getBytes(UTF_8); MockHttpServletResponse response = new MockHttpServletResponse(); ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response); - responseWrapper.setStatus(HttpServletResponse.SC_OK); - responseWrapper.setHeader(HttpHeaders.TRANSFER_ENCODING, "chunked"); + responseWrapper.setStatus(HttpServletResponse.SC_CREATED); + responseWrapper.setHeader(TRANSFER_ENCODING, "chunked"); FileCopyUtils.copy(responseBody, responseWrapper.getOutputStream()); responseWrapper.copyBodyToResponse(); - assertThat(response.getStatus()).isEqualTo(200); - assertThat(response.getHeader(HttpHeaders.TRANSFER_ENCODING)).isEqualTo("chunked"); - assertThat(response.getHeader(HttpHeaders.CONTENT_LENGTH)).isNull(); + assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_CREATED); + assertHeader(response, TRANSFER_ENCODING, "chunked"); + assertHeader(response, CONTENT_LENGTH, null); assertThat(response.getContentAsByteArray()).isEqualTo(responseBody); } + private void assertHeader(HttpServletResponse response, String header, String value) { + if (value == null) { + assertThat(response.containsHeader(header)).as(header).isFalse(); + assertThat(response.getHeader(header)).as(header).isNull(); + assertThat(response.getHeaders(header)).as(header).isEmpty(); + } + else { + assertThat(response.containsHeader(header)).as(header).isTrue(); + assertThat(response.getHeader(header)).as(header).isEqualTo(value); + assertThat(response.getHeaders(header)).as(header).containsExactly(value); + } + } + }