Skip to content

Commit 4b8a937

Browse files
committed
Allow interceptors to add existing header values
Provide a fully mutable HttpHeaders to ClientHttpRequestInterceptors of a RestTemplate when headers are set using HttpEntity. This avoids UnsupportedOperationException if both HttpEntity and ClientHttpRequestInterceptor add values for the same HTTP header. Issue: SPR-15066
1 parent 55fc731 commit 4b8a937

File tree

2 files changed

+38
-13
lines changed

2 files changed

+38
-13
lines changed

spring-web/src/main/java/org/springframework/web/client/RestTemplate.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import java.lang.reflect.Type;
2121
import java.net.URI;
2222
import java.util.ArrayList;
23+
import java.util.Collections;
24+
import java.util.LinkedList;
2325
import java.util.List;
2426
import java.util.Map;
2527
import java.util.Set;
@@ -837,7 +839,9 @@ public void doWithRequest(ClientHttpRequest httpRequest) throws IOException {
837839
HttpHeaders httpHeaders = httpRequest.getHeaders();
838840
HttpHeaders requestHeaders = this.requestEntity.getHeaders();
839841
if (!requestHeaders.isEmpty()) {
840-
httpHeaders.putAll(requestHeaders);
842+
for (Map.Entry<String, List<String>> entry : requestHeaders.entrySet()) {
843+
httpHeaders.put(entry.getKey(), new LinkedList<String>(entry.getValue()));
844+
}
841845
}
842846
if (httpHeaders.getContentLength() < 0) {
843847
httpHeaders.setContentLength(0L);

spring-web/src/test/java/org/springframework/web/client/RestTemplateTests.java

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,23 +39,18 @@
3939
import org.springframework.http.ResponseEntity;
4040
import org.springframework.http.client.ClientHttpRequest;
4141
import org.springframework.http.client.ClientHttpRequestFactory;
42+
import org.springframework.http.client.ClientHttpRequestInterceptor;
4243
import org.springframework.http.client.ClientHttpResponse;
4344
import org.springframework.http.converter.GenericHttpMessageConverter;
4445
import org.springframework.http.converter.HttpMessageConverter;
4546
import org.springframework.web.util.DefaultUriTemplateHandler;
4647

47-
import static org.junit.Assert.assertEquals;
48-
import static org.junit.Assert.assertFalse;
49-
import static org.junit.Assert.assertNull;
50-
import static org.junit.Assert.assertSame;
51-
import static org.junit.Assert.fail;
52-
import static org.mockito.BDDMockito.any;
53-
import static org.mockito.BDDMockito.eq;
54-
import static org.mockito.BDDMockito.given;
55-
import static org.mockito.BDDMockito.mock;
56-
import static org.mockito.BDDMockito.verify;
57-
import static org.mockito.BDDMockito.willThrow;
58-
import static org.springframework.http.MediaType.parseMediaType;
48+
import static org.hamcrest.MatcherAssert.assertThat;
49+
import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
50+
import static org.junit.Assert.*;
51+
import static org.mockito.BDDMockito.*;
52+
import static org.springframework.http.HttpMethod.POST;
53+
import static org.springframework.http.MediaType.*;
5954

6055
/**
6156
* @author Arjen Poutsma
@@ -840,4 +835,30 @@ public void exchangeParameterizedType() throws Exception {
840835
verify(response).close();
841836
}
842837

838+
@Test // SPR-15066
839+
public void requestInterceptorCanAddExistingHeaderValue() throws Exception {
840+
ClientHttpRequestInterceptor interceptor = (request, body, execution) -> {
841+
request.getHeaders().add("MyHeader", "MyInterceptorValue");
842+
return execution.execute(request, body);
843+
};
844+
template.setInterceptors(Collections.singletonList(interceptor));
845+
846+
given(requestFactory.createRequest(new URI("http://example.com"), HttpMethod.POST)).willReturn(request);
847+
HttpHeaders requestHeaders = new HttpHeaders();
848+
given(request.getHeaders()).willReturn(requestHeaders);
849+
given(request.execute()).willReturn(response);
850+
given(errorHandler.hasError(response)).willReturn(false);
851+
HttpStatus status = HttpStatus.OK;
852+
given(response.getStatusCode()).willReturn(status);
853+
given(response.getStatusText()).willReturn(status.getReasonPhrase());
854+
855+
HttpHeaders entityHeaders = new HttpHeaders();
856+
entityHeaders.add("MyHeader", "MyEntityValue");
857+
HttpEntity<Void> entity = new HttpEntity<>(null, entityHeaders);
858+
template.exchange("http://example.com", HttpMethod.POST, entity, Void.class);
859+
assertThat(requestHeaders.get("MyHeader"), contains("MyEntityValue", "MyInterceptorValue"));
860+
861+
verify(response).close();
862+
}
863+
843864
}

0 commit comments

Comments
 (0)