Allow ServerHttpRequest content-type mutation
Prior to this commit, `ServerHttpRequest.mutate()` would not reflect changes made on the "Accept" and "Content-Type" HTTP headers. This was due to the fact that the instantiation of a new request based on the mutated values would not use the writable HTTP headers used during the mutation, but rather a read-only view of the headers backed by `ReadOnlyHttpHeaders`. `ReadOnlyHttpHeaders` caches those values for performance reasons, so getting those from the new request would not reflect the changes made during the mutation phase. This commit ensures that the new request uses the mutated headers. Fixes gh-26615
This commit is contained in:
parent
0087578469
commit
5a11569790
|
|
@ -38,6 +38,7 @@ import org.springframework.util.StringUtils;
|
|||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sebastien Deleuze
|
||||
* @author Brian Clozel
|
||||
* @since 5.0
|
||||
*/
|
||||
class DefaultServerHttpRequestBuilder implements ServerHttpRequest.Builder {
|
||||
|
|
@ -131,7 +132,7 @@ class DefaultServerHttpRequestBuilder implements ServerHttpRequest.Builder {
|
|||
@Override
|
||||
public ServerHttpRequest build() {
|
||||
return new MutatedServerHttpRequest(getUriToUse(), this.contextPath,
|
||||
this.httpMethodValue, this.sslInfo, this.remoteAddress, this.body, this.originalRequest);
|
||||
this.httpMethodValue, this.sslInfo, this.remoteAddress, this.headers, this.body, this.originalRequest);
|
||||
}
|
||||
|
||||
private URI getUriToUse() {
|
||||
|
|
@ -190,9 +191,9 @@ class DefaultServerHttpRequestBuilder implements ServerHttpRequest.Builder {
|
|||
|
||||
public MutatedServerHttpRequest(URI uri, @Nullable String contextPath,
|
||||
String methodValue, @Nullable SslInfo sslInfo, @Nullable InetSocketAddress remoteAddress,
|
||||
Flux<DataBuffer> body, ServerHttpRequest originalRequest) {
|
||||
HttpHeaders headers, Flux<DataBuffer> body, ServerHttpRequest originalRequest) {
|
||||
|
||||
super(uri, contextPath, originalRequest.getHeaders());
|
||||
super(uri, contextPath, headers);
|
||||
this.methodValue = methodValue;
|
||||
this.remoteAddress = (remoteAddress != null ? remoteAddress : originalRequest.getRemoteAddress());
|
||||
this.sslInfo = (sslInfo != null ? sslInfo : originalRequest.getSslInfo());
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import org.junit.jupiter.api.Test;
|
|||
|
||||
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.testfixture.servlet.DelegatingServletInputStream;
|
||||
import org.springframework.web.testfixture.servlet.MockAsyncContext;
|
||||
|
|
@ -46,6 +47,7 @@ import static org.mockito.Mockito.mock;
|
|||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sam Brannen
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
public class ServerHttpRequestTests {
|
||||
|
||||
|
|
@ -166,6 +168,18 @@ public class ServerHttpRequestTests {
|
|||
assertThat(request.getHeaders().get(headerName)).containsExactly(headerValue3);
|
||||
}
|
||||
|
||||
@Test // gh-26615
|
||||
void mutateContentTypeHeaderValue() throws Exception {
|
||||
ServerHttpRequest request = createRequest("/path").mutate()
|
||||
.headers(headers -> headers.setContentType(MediaType.APPLICATION_JSON)).build();
|
||||
|
||||
assertThat(request.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON);
|
||||
|
||||
ServerHttpRequest mutated = request.mutate()
|
||||
.headers(headers -> headers.setContentType(MediaType.APPLICATION_CBOR)).build();
|
||||
assertThat(mutated.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_CBOR);
|
||||
}
|
||||
|
||||
@Test
|
||||
void mutateWithExistingContextPath() throws Exception {
|
||||
ServerHttpRequest request = createRequest("/context/path", "/context");
|
||||
|
|
|
|||
Loading…
Reference in New Issue