mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-17 08:24:13 +00:00
Consistent adaptation of HTTP headers on Servlet responses
Closes gh-36345
This commit is contained in:
+2
-3
@@ -187,10 +187,10 @@ public class ServletServerHttpRequest implements ServerHttpRequest {
|
||||
if (contentType != null && contentType.getCharset() == null) {
|
||||
String requestEncoding = this.servletRequest.getCharacterEncoding();
|
||||
if (StringUtils.hasLength(requestEncoding)) {
|
||||
Charset charSet = Charset.forName(requestEncoding);
|
||||
Charset charset = Charset.forName(requestEncoding);
|
||||
Map<String, String> params = new LinkedCaseInsensitiveMap<>();
|
||||
params.putAll(contentType.getParameters());
|
||||
params.put("charset", charSet.toString());
|
||||
params.put("charset", charset.toString());
|
||||
MediaType mediaType = new MediaType(contentType.getType(), contentType.getSubtype(), params);
|
||||
this.headers.setContentType(mediaType);
|
||||
}
|
||||
@@ -207,7 +207,6 @@ public class ServletServerHttpRequest implements ServerHttpRequest {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.headers;
|
||||
}
|
||||
|
||||
|
||||
+20
-7
@@ -18,6 +18,7 @@ package org.springframework.http.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -118,19 +119,31 @@ public class ServletServerHttpResponse implements ServerHttpResponse {
|
||||
this.servletResponse.addHeader(headerName, headerValue);
|
||||
}
|
||||
});
|
||||
|
||||
// HttpServletResponse exposes some headers as properties: we should include those if not already present
|
||||
MediaType contentTypeHeader = this.headers.getContentType();
|
||||
if (this.servletResponse.getContentType() == null && contentTypeHeader != null) {
|
||||
this.servletResponse.setContentType(contentTypeHeader.toString());
|
||||
if (this.servletResponse.getContentType() == null && this.headers.containsKey(HttpHeaders.CONTENT_TYPE)) {
|
||||
this.servletResponse.setContentType(this.headers.getFirst(HttpHeaders.CONTENT_TYPE));
|
||||
}
|
||||
if (this.servletResponse.getCharacterEncoding() == null && contentTypeHeader != null &&
|
||||
contentTypeHeader.getCharset() != null) {
|
||||
this.servletResponse.setCharacterEncoding(contentTypeHeader.getCharset().name());
|
||||
if (this.servletResponse.getCharacterEncoding() == null && this.headers.containsKey(HttpHeaders.CONTENT_TYPE)) {
|
||||
try {
|
||||
// Lazy parsing into MediaType
|
||||
MediaType contentType = this.headers.getContentType();
|
||||
if (contentType != null) {
|
||||
Charset charset = contentType.getCharset();
|
||||
if (charset != null) {
|
||||
this.servletResponse.setCharacterEncoding(charset.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// Leave character encoding unspecified
|
||||
}
|
||||
}
|
||||
long contentLength = getHeaders().getContentLength();
|
||||
long contentLength = this.headers.getContentLength();
|
||||
if (contentLength != -1) {
|
||||
this.servletResponse.setContentLengthLong(contentLength);
|
||||
}
|
||||
|
||||
this.headersWritten = true;
|
||||
}
|
||||
}
|
||||
|
||||
+26
-21
@@ -50,7 +50,9 @@ import org.springframework.util.ReflectionUtils;
|
||||
*/
|
||||
class ServletServerHttpResponse extends AbstractListenerServerHttpResponse {
|
||||
|
||||
private static final boolean IS_SERVLET61 = ReflectionUtils.findField(HttpServletResponse.class, "SC_PERMANENT_REDIRECT") != null;
|
||||
private static final boolean SERVLET61 =
|
||||
(ReflectionUtils.findField(HttpServletResponse.class, "SC_PERMANENT_REDIRECT") != null);
|
||||
|
||||
|
||||
private final HttpServletResponse response;
|
||||
|
||||
@@ -138,31 +140,35 @@ class ServletServerHttpResponse extends AbstractListenerServerHttpResponse {
|
||||
}
|
||||
|
||||
protected void adaptHeaders(boolean removeAdaptedHeaders) {
|
||||
MediaType contentType = null;
|
||||
try {
|
||||
contentType = getHeaders().getContentType();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
String rawContentType = getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
|
||||
this.response.setContentType(rawContentType);
|
||||
}
|
||||
if (this.response.getContentType() == null && contentType != null) {
|
||||
this.response.setContentType(contentType.toString());
|
||||
}
|
||||
HttpHeaders headers = getHeaders();
|
||||
|
||||
Charset charset = (contentType != null ? contentType.getCharset() : null);
|
||||
if (this.response.getCharacterEncoding() == null && charset != null) {
|
||||
this.response.setCharacterEncoding(charset.name());
|
||||
// HttpServletResponse exposes some headers as properties: we should include those if not already present
|
||||
if (this.response.getContentType() == null && headers.containsKey(HttpHeaders.CONTENT_TYPE)) {
|
||||
this.response.setContentType(headers.getFirst(HttpHeaders.CONTENT_TYPE));
|
||||
}
|
||||
|
||||
long contentLength = getHeaders().getContentLength();
|
||||
if (this.response.getCharacterEncoding() == null && headers.containsKey(HttpHeaders.CONTENT_TYPE)) {
|
||||
try {
|
||||
// Lazy parsing into MediaType
|
||||
MediaType contentType = headers.getContentType();
|
||||
if (contentType != null) {
|
||||
Charset charset = contentType.getCharset();
|
||||
if (charset != null) {
|
||||
this.response.setCharacterEncoding(charset.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// Leave character encoding unspecified
|
||||
}
|
||||
}
|
||||
long contentLength = headers.getContentLength();
|
||||
if (contentLength != -1) {
|
||||
this.response.setContentLengthLong(contentLength);
|
||||
}
|
||||
|
||||
if (removeAdaptedHeaders) {
|
||||
getHeaders().remove(HttpHeaders.CONTENT_TYPE);
|
||||
getHeaders().remove(HttpHeaders.CONTENT_LENGTH);
|
||||
headers.remove(HttpHeaders.CONTENT_TYPE);
|
||||
headers.remove(HttpHeaders.CONTENT_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,7 +192,7 @@ class ServletServerHttpResponse extends AbstractListenerServerHttpResponse {
|
||||
cookie.setSecure(httpCookie.isSecure());
|
||||
cookie.setHttpOnly(httpCookie.isHttpOnly());
|
||||
if (httpCookie.isPartitioned()) {
|
||||
if (IS_SERVLET61) {
|
||||
if (SERVLET61) {
|
||||
cookie.setAttribute("Partitioned", "");
|
||||
}
|
||||
else {
|
||||
@@ -373,7 +379,6 @@ class ServletServerHttpResponse extends AbstractListenerServerHttpResponse {
|
||||
|
||||
private class ResponseBodyProcessor extends AbstractListenerWriteProcessor<DataBuffer> {
|
||||
|
||||
|
||||
public ResponseBodyProcessor() {
|
||||
super(request.getLogPrefix());
|
||||
}
|
||||
|
||||
+25
-6
@@ -17,6 +17,7 @@
|
||||
package org.springframework.web.servlet.function;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -28,6 +29,7 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatusCode;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
@@ -51,6 +53,7 @@ abstract class AbstractServerResponse extends ErrorHandlingServerResponse {
|
||||
|
||||
private final MultiValueMap<String, Cookie> cookies;
|
||||
|
||||
|
||||
protected AbstractServerResponse(
|
||||
HttpStatusCode statusCode, HttpHeaders headers, MultiValueMap<String, Cookie> cookies) {
|
||||
|
||||
@@ -60,6 +63,7 @@ abstract class AbstractServerResponse extends ErrorHandlingServerResponse {
|
||||
CollectionUtils.unmodifiableMultiValueMap(new LinkedMultiValueMap<>(cookies));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final HttpStatusCode statusCode() {
|
||||
return this.statusCode;
|
||||
@@ -118,14 +122,29 @@ abstract class AbstractServerResponse extends ErrorHandlingServerResponse {
|
||||
servletResponse.addHeader(headerName, headerValue);
|
||||
}
|
||||
});
|
||||
|
||||
// HttpServletResponse exposes some headers as properties: we should include those if not already present
|
||||
if (servletResponse.getContentType() == null && this.headers.getContentType() != null) {
|
||||
servletResponse.setContentType(this.headers.getContentType().toString());
|
||||
if (servletResponse.getContentType() == null && this.headers.containsKey(HttpHeaders.CONTENT_TYPE)) {
|
||||
servletResponse.setContentType(this.headers.getFirst(HttpHeaders.CONTENT_TYPE));
|
||||
}
|
||||
if (servletResponse.getCharacterEncoding() == null &&
|
||||
this.headers.getContentType() != null &&
|
||||
this.headers.getContentType().getCharset() != null) {
|
||||
servletResponse.setCharacterEncoding(this.headers.getContentType().getCharset().name());
|
||||
if (servletResponse.getCharacterEncoding() == null && this.headers.containsKey(HttpHeaders.CONTENT_TYPE)) {
|
||||
try {
|
||||
// Lazy parsing into MediaType
|
||||
MediaType contentType = this.headers.getContentType();
|
||||
if (contentType != null) {
|
||||
Charset charset = contentType.getCharset();
|
||||
if (charset != null) {
|
||||
servletResponse.setCharacterEncoding(charset.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// Leave character encoding unspecified
|
||||
}
|
||||
}
|
||||
long contentLength = this.headers.getContentLength();
|
||||
if (contentLength != -1) {
|
||||
servletResponse.setContentLengthLong(contentLength);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
@@ -459,6 +459,11 @@ public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodRetur
|
||||
// ignore
|
||||
}
|
||||
|
||||
// @Override - on Servlet 6.1
|
||||
public void setCharacterEncoding(Charset encoding) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentLength(int len) {
|
||||
// ignore
|
||||
|
||||
Reference in New Issue
Block a user