From ce9dc19a3c6a870509105c5cedae1cd59b93917d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Deleuze?= Date: Mon, 4 Mar 2024 13:24:50 +0100 Subject: [PATCH 1/2] Optimize content type parsing This commit avoids calling HttpHeaders#getContentType multiple times in ServletServerHttpResponse#writeHeaders. Closes gh-32361 --- .../http/server/ServletServerHttpResponse.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpResponse.java b/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpResponse.java index ca28b8e0580..7ec872f05bc 100644 --- a/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpResponse.java +++ b/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpResponse.java @@ -27,6 +27,7 @@ import jakarta.servlet.http.HttpServletResponse; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatusCode; +import org.springframework.http.MediaType; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; @@ -118,12 +119,13 @@ public class ServletServerHttpResponse implements ServerHttpResponse { } }); // HttpServletResponse exposes some headers as properties: we should include those if not already present - if (this.servletResponse.getContentType() == null && this.headers.getContentType() != null) { - this.servletResponse.setContentType(this.headers.getContentType().toString()); + MediaType contentTypeHeader = this.headers.getContentType(); + if (this.servletResponse.getContentType() == null && contentTypeHeader != null) { + this.servletResponse.setContentType(contentTypeHeader.toString()); } - if (this.servletResponse.getCharacterEncoding() == null && this.headers.getContentType() != null && - this.headers.getContentType().getCharset() != null) { - this.servletResponse.setCharacterEncoding(this.headers.getContentType().getCharset().name()); + if (this.servletResponse.getCharacterEncoding() == null && contentTypeHeader != null && + contentTypeHeader.getCharset() != null) { + this.servletResponse.setCharacterEncoding(contentTypeHeader.getCharset().name()); } long contentLength = getHeaders().getContentLength(); if (contentLength != -1) { From 7493ce86b6b6014287789069d41943f5d3ac02fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Deleuze?= Date: Mon, 4 Mar 2024 14:25:51 +0100 Subject: [PATCH 2/2] Fix ServletResponseHttpHeaders#get null handling ServletResponseHttpHeaders#get should be annotated with `@Nullable` and return null instead of a singleton list containing null when there is no content type header. Closes gh-32362 --- .../http/server/ServletServerHttpResponse.java | 4 +++- .../http/server/ServletServerHttpResponseTests.java | 13 +++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpResponse.java b/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpResponse.java index 7ec872f05bc..875e5bd3127 100644 --- a/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpResponse.java +++ b/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpResponse.java @@ -171,13 +171,15 @@ public class ServletServerHttpResponse implements ServerHttpResponse { } @Override + @Nullable public List get(Object key) { Assert.isInstanceOf(String.class, key, "Key must be a String-based header name"); String headerName = (String) key; if (headerName.equalsIgnoreCase(CONTENT_TYPE)) { // Content-Type is written as an override so don't merge - return Collections.singletonList(getFirst(headerName)); + String value = getFirst(headerName); + return (value != null ? Collections.singletonList(value) : null); } Collection values1 = servletResponse.getHeaders(headerName); diff --git a/spring-web/src/test/java/org/springframework/http/server/ServletServerHttpResponseTests.java b/spring-web/src/test/java/org/springframework/http/server/ServletServerHttpResponseTests.java index efdf1bf691f..34a40016ac0 100644 --- a/spring-web/src/test/java/org/springframework/http/server/ServletServerHttpResponseTests.java +++ b/spring-web/src/test/java/org/springframework/http/server/ServletServerHttpResponseTests.java @@ -75,6 +75,19 @@ class ServletServerHttpResponseTests { assertThat(mockResponse.getCharacterEncoding()).as("Invalid Content-Type").isEqualTo("UTF-8"); } + @Test + void getHeadersWithNoContentType() { + this.response = new ServletServerHttpResponse(this.mockResponse); + assertThat(this.response.getHeaders().get(HttpHeaders.CONTENT_TYPE)).isNull(); + } + + @Test + void getHeadersWithContentType() { + this.mockResponse.setContentType(MediaType.TEXT_PLAIN_VALUE); + this.response = new ServletServerHttpResponse(this.mockResponse); + assertThat(this.response.getHeaders().get(HttpHeaders.CONTENT_TYPE)).containsExactly(MediaType.TEXT_PLAIN_VALUE); + } + @Test void preExistingHeadersFromHttpServletResponse() { String headerName = "Access-Control-Allow-Origin";