From 3e1b3c32e3dfae52c2537fe9249ec3e509417d60 Mon Sep 17 00:00:00 2001 From: Gemini Kim Date: Mon, 11 Feb 2019 13:00:44 +0100 Subject: [PATCH] Avoid duplicate Accept header values in RestTemplate Prior to this commit, the various `HttpMessageConverter` instances configured for a given `RestTemplate` instance could all contribute `MediaType` values to the "Accept:" request header. This could lead to duplicate media types in that request header, cluttering for the HTTP request for no reason. This commit ensures that only distinct values are added to the request. Issue: SPR-16690 Closes gh-22320 Closes gh-21231 --- .../web/client/RestTemplate.java | 10 ++++--- .../web/client/RestTemplateTests.java | 26 ++++++++++++++++++- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java b/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java index d439b7cc20a..4e717f0a5a1 100644 --- a/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java +++ b/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import java.io.IOException; import java.lang.reflect.Type; import java.net.URI; import java.util.ArrayList; +import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -767,7 +768,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat if (this.responseType instanceof Class) { responseClass = (Class) this.responseType; } - List allSupportedMediaTypes = new ArrayList(); + Set allSupportedMediaTypes = new LinkedHashSet(); for (HttpMessageConverter converter : getMessageConverters()) { if (responseClass != null) { if (converter.canRead(responseClass, null)) { @@ -782,11 +783,12 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat } } if (!allSupportedMediaTypes.isEmpty()) { - MediaType.sortBySpecificity(allSupportedMediaTypes); + List result = new ArrayList(allSupportedMediaTypes); + MediaType.sortBySpecificity(result); if (logger.isDebugEnabled()) { logger.debug("Setting request Accept header to " + allSupportedMediaTypes); } - request.getHeaders().setAccept(allSupportedMediaTypes); + request.getHeaders().setAccept(result); } } } diff --git a/spring-web/src/test/java/org/springframework/web/client/RestTemplateTests.java b/spring-web/src/test/java/org/springframework/web/client/RestTemplateTests.java index 6f4798af57d..c1a8bdfb80d 100644 --- a/spring-web/src/test/java/org/springframework/web/client/RestTemplateTests.java +++ b/spring-web/src/test/java/org/springframework/web/client/RestTemplateTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,8 @@ package org.springframework.web.client; import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; @@ -43,6 +45,8 @@ import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.converter.GenericHttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.util.StringUtils; import org.springframework.web.util.DefaultUriTemplateHandler; import static org.hamcrest.MatcherAssert.assertThat; @@ -878,4 +882,24 @@ public class RestTemplateTests { verify(response).close(); } + @Test + public void acceptHeaderValueShouldBeNotDuplicated() throws Exception { + final StringHttpMessageConverter utf8HttpMessageConverter = new StringHttpMessageConverter(StandardCharsets.UTF_8); + final StringHttpMessageConverter iso88591HttpMessageConverter = new StringHttpMessageConverter(StandardCharsets.ISO_8859_1); + + final RestTemplate multipleEncodingTemplate = new RestTemplate(Arrays.asList(utf8HttpMessageConverter, iso88591HttpMessageConverter)); + multipleEncodingTemplate.setRequestFactory(requestFactory); + given(requestFactory.createRequest(new URI("http://example.com"), GET)).willReturn(request); + + final HttpHeaders requestHeaders = new HttpHeaders(); + given(request.getHeaders()).willReturn(requestHeaders); + given(request.execute()).willReturn(response); + + final HttpHeaders responseHeaders = new HttpHeaders(); + given(response.getHeaders()).willReturn(responseHeaders); + + multipleEncodingTemplate.getForObject("http://example.com", String.class); + assertEquals("text/plain, */*", StringUtils.collectionToDelimitedString(request.getHeaders().get("accept"), ",")); + } + }