Keep DefaultServerHttpRequestBuilder-mutated headers case-insensitive

This change avoids the trap of creating a copy of `HttpHeaders` using a
case-sensitive `MultiValueMap` by mistake. Since mutability is always
desirable, we make a mutable copy by using `addAll` on an empty
`HttpHeaders`.

We can't simply rely on HttpHeaders' map-based constructor to detect
read-only header in this particular case, because the container's
original headers representation might in some cases be read-only.

Closes gh-33666
This commit is contained in:
Simon Baslé
2024-10-09 11:39:03 +02:00
parent 59ef5e140f
commit ef77b4064f
2 changed files with 123 additions and 3 deletions

View File

@@ -30,7 +30,6 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
@@ -71,8 +70,12 @@ class DefaultServerHttpRequestBuilder implements ServerHttpRequest.Builder {
Assert.notNull(original, "ServerHttpRequest is required");
this.uri = original.getURI();
// original headers can be immutable, so create a copy
this.headers = new HttpHeaders(new LinkedMultiValueMap<>(original.getHeaders()));
// Some containers (including Jetty and Netty4) can have an immutable
// representation of headers. Since mutability is always desirable here,
// we always create a mutable case-insensitive copy of the original
// headers by using the basic constructor and addAll.
this.headers = new HttpHeaders();
this.headers.addAll(original.getHeaders());
this.httpMethod = original.getMethod();
this.contextPath = original.getPath().contextPath().value();
this.remoteAddress = original.getRemoteAddress();