Skip to content

Commit cb036e4

Browse files
tworoguevelo
authored andcommitted
Fixes an issue with http-headers duplication when using RequestTemplate (OpenFeign#832)
* Fixes an issue with http-headers duplication when using RequestTemplate Fixes OpenFeign#570 * Changes imports formatting (upon running 'clean install')
1 parent d436ca1 commit cb036e4

3 files changed

Lines changed: 35 additions & 29 deletions

File tree

core/src/main/java/feign/RequestTemplate.java

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,31 +13,20 @@
1313
*/
1414
package feign;
1515

16-
import static feign.Util.CONTENT_LENGTH;
17-
import static feign.Util.UTF_8;
18-
import static feign.Util.checkNotNull;
1916
import feign.Request.HttpMethod;
20-
import feign.template.BodyTemplate;
2117
import feign.template.HeaderTemplate;
2218
import feign.template.QueryTemplate;
2319
import feign.template.UriTemplate;
2420
import feign.template.UriUtils;
2521
import java.io.Serializable;
2622
import java.nio.charset.Charset;
2723
import java.util.AbstractMap.SimpleImmutableEntry;
28-
import java.util.ArrayList;
29-
import java.util.Arrays;
30-
import java.util.Collection;
31-
import java.util.Collections;
32-
import java.util.Iterator;
33-
import java.util.LinkedHashMap;
34-
import java.util.LinkedHashSet;
35-
import java.util.List;
36-
import java.util.Map;
24+
import java.util.*;
3725
import java.util.Map.Entry;
3826
import java.util.regex.Matcher;
3927
import java.util.regex.Pattern;
4028
import java.util.stream.Collectors;
29+
import static feign.Util.*;
4130

4231
/**
4332
* Request Builder for an HTTP Target.
@@ -51,7 +40,7 @@ public final class RequestTemplate implements Serializable {
5140

5241
private static final Pattern QUERY_STRING_PATTERN = Pattern.compile("(?<!\\{)\\?");
5342
private final Map<String, QueryTemplate> queries = new LinkedHashMap<>();
54-
private final Map<String, HeaderTemplate> headers = new LinkedHashMap<>();
43+
private final Map<String, HeaderTemplate> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
5544
private String target;
5645
private boolean resolved = false;
5746
private UriTemplate uriTemplate;
@@ -73,7 +62,6 @@ public RequestTemplate() {
7362
*
7463
* @param target for the template.
7564
* @param uriTemplate for the template.
76-
* @param bodyTemplate for the template.
7765
* @param method of the request.
7866
* @param charset for the request.
7967
* @param body of the request, may be null
@@ -691,7 +679,7 @@ public RequestTemplate headers(Map<String, Collection<String>> headers) {
691679
* @return the currently applied headers.
692680
*/
693681
public Map<String, Collection<String>> headers() {
694-
Map<String, Collection<String>> headerMap = new LinkedHashMap<>();
682+
Map<String, Collection<String>> headerMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
695683
this.headers.forEach((key, headerTemplate) -> {
696684
List<String> values = new ArrayList<>(headerTemplate.getValues());
697685

core/src/test/java/feign/LoggerTest.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,16 +76,16 @@ public static Iterable<Object[]> data() {
7676
"\\[SendsStuff#login\\] <--- HTTP/1.1 200 OK \\([0-9]+ms\\)")},
7777
{Level.HEADERS, Arrays.asList(
7878
"\\[SendsStuff#login\\] ---> POST http://localhost:[0-9]+/ HTTP/1.1",
79-
"\\[SendsStuff#login\\] Content-Type: application/json",
8079
"\\[SendsStuff#login\\] Content-Length: 80",
80+
"\\[SendsStuff#login\\] Content-Type: application/json",
8181
"\\[SendsStuff#login\\] ---> END HTTP \\(80-byte body\\)",
8282
"\\[SendsStuff#login\\] <--- HTTP/1.1 200 OK \\([0-9]+ms\\)",
8383
"\\[SendsStuff#login\\] content-length: 3",
8484
"\\[SendsStuff#login\\] <--- END HTTP \\(3-byte body\\)")},
8585
{Level.FULL, Arrays.asList(
8686
"\\[SendsStuff#login\\] ---> POST http://localhost:[0-9]+/ HTTP/1.1",
87-
"\\[SendsStuff#login\\] Content-Type: application/json",
8887
"\\[SendsStuff#login\\] Content-Length: 80",
88+
"\\[SendsStuff#login\\] Content-Type: application/json",
8989
"\\[SendsStuff#login\\] ",
9090
"\\[SendsStuff#login\\] \\{\"customer_name\": \"netflix\", \"user_name\": \"denominator\", \"password\": \"password\"\\}",
9191
"\\[SendsStuff#login\\] ---> END HTTP \\(80-byte body\\)",
@@ -161,14 +161,14 @@ public static Iterable<Object[]> data() {
161161
"\\[SendsStuff#login\\] <--- ERROR SocketTimeoutException: Read timed out \\([0-9]+ms\\)")},
162162
{Level.HEADERS, Arrays.asList(
163163
"\\[SendsStuff#login\\] ---> POST http://localhost:[0-9]+/ HTTP/1.1",
164-
"\\[SendsStuff#login\\] Content-Type: application/json",
165164
"\\[SendsStuff#login\\] Content-Length: 80",
165+
"\\[SendsStuff#login\\] Content-Type: application/json",
166166
"\\[SendsStuff#login\\] ---> END HTTP \\(80-byte body\\)",
167167
"\\[SendsStuff#login\\] <--- ERROR SocketTimeoutException: Read timed out \\([0-9]+ms\\)")},
168168
{Level.FULL, Arrays.asList(
169169
"\\[SendsStuff#login\\] ---> POST http://localhost:[0-9]+/ HTTP/1.1",
170-
"\\[SendsStuff#login\\] Content-Type: application/json",
171170
"\\[SendsStuff#login\\] Content-Length: 80",
171+
"\\[SendsStuff#login\\] Content-Type: application/json",
172172
"\\[SendsStuff#login\\] ",
173173
"\\[SendsStuff#login\\] \\{\"customer_name\": \"netflix\", \"user_name\": \"denominator\", \"password\": \"password\"\\}",
174174
"\\[SendsStuff#login\\] ---> END HTTP \\(80-byte body\\)",
@@ -223,14 +223,14 @@ public static Iterable<Object[]> data() {
223223
"\\[SendsStuff#login\\] <--- ERROR UnknownHostException: robofu.abc \\([0-9]+ms\\)")},
224224
{Level.HEADERS, Arrays.asList(
225225
"\\[SendsStuff#login\\] ---> POST http://robofu.abc/ HTTP/1.1",
226-
"\\[SendsStuff#login\\] Content-Type: application/json",
227226
"\\[SendsStuff#login\\] Content-Length: 80",
227+
"\\[SendsStuff#login\\] Content-Type: application/json",
228228
"\\[SendsStuff#login\\] ---> END HTTP \\(80-byte body\\)",
229229
"\\[SendsStuff#login\\] <--- ERROR UnknownHostException: robofu.abc \\([0-9]+ms\\)")},
230230
{Level.FULL, Arrays.asList(
231231
"\\[SendsStuff#login\\] ---> POST http://robofu.abc/ HTTP/1.1",
232-
"\\[SendsStuff#login\\] Content-Type: application/json",
233232
"\\[SendsStuff#login\\] Content-Length: 80",
233+
"\\[SendsStuff#login\\] Content-Type: application/json",
234234
"\\[SendsStuff#login\\] ",
235235
"\\[SendsStuff#login\\] \\{\"customer_name\": \"netflix\", \"user_name\": \"denominator\", \"password\": \"password\"\\}",
236236
"\\[SendsStuff#login\\] ---> END HTTP \\(80-byte body\\)",
@@ -285,14 +285,14 @@ public static Iterable<Object[]> data() {
285285
"\\[SendsStuff#login\\] <--- ERROR UnknownHostException: sna%fu.abc \\([0-9]+ms\\)")},
286286
{Level.HEADERS, Arrays.asList(
287287
"\\[SendsStuff#login\\] ---> POST http://sna%fu.abc/ HTTP/1.1",
288-
"\\[SendsStuff#login\\] Content-Type: application/json",
289288
"\\[SendsStuff#login\\] Content-Length: 80",
289+
"\\[SendsStuff#login\\] Content-Type: application/json",
290290
"\\[SendsStuff#login\\] ---> END HTTP \\(80-byte body\\)",
291291
"\\[SendsStuff#login\\] <--- ERROR UnknownHostException: sna%fu.abc \\([0-9]+ms\\)")},
292292
{Level.FULL, Arrays.asList(
293293
"\\[SendsStuff#login\\] ---> POST http://sna%fu.abc/ HTTP/1.1",
294-
"\\[SendsStuff#login\\] Content-Type: application/json",
295294
"\\[SendsStuff#login\\] Content-Length: 80",
295+
"\\[SendsStuff#login\\] Content-Type: application/json",
296296
"\\[SendsStuff#login\\] ",
297297
"\\[SendsStuff#login\\] \\{\"customer_name\": \"netflix\", \"user_name\": \"denominator\", \"password\": \"password\"\\}",
298298
"\\[SendsStuff#login\\] ---> END HTTP \\(80-byte body\\)",

core/src/test/java/feign/RequestTemplateTest.java

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,10 @@
1616
import static feign.assertj.FeignAssertions.assertThat;
1717
import static java.util.Arrays.asList;
1818
import static org.assertj.core.data.MapEntry.entry;
19+
import static org.junit.Assert.*;
1920
import feign.Request.HttpMethod;
2021
import feign.template.UriUtils;
21-
import java.util.Arrays;
22-
import java.util.Collection;
23-
import java.util.Collections;
24-
import java.util.LinkedHashMap;
25-
import java.util.Map;
22+
import java.util.*;
2623
import org.junit.Rule;
2724
import org.junit.Test;
2825
import org.junit.rules.ExpectedException;
@@ -323,6 +320,27 @@ public void spaceEncodingInUrlParam() {
323320
.isEqualTo("/api/ABC%20123?key=XYZ%20123");
324321
}
325322

323+
@Test
324+
public void useCaseInsensitiveHeaderFieldNames() {
325+
final RequestTemplate template = new RequestTemplate();
326+
327+
final String value = "value1";
328+
template.header("TEST", value);
329+
330+
final String value2 = "value2";
331+
template.header("tEST", value2);
332+
333+
final Collection<String> test = template.headers().get("test");
334+
335+
final String assertionMessage = "Header field names should be case insensitive";
336+
337+
assertNotNull(assertionMessage, test);
338+
assertTrue(assertionMessage, test.contains(value));
339+
assertTrue(assertionMessage, test.contains(value2));
340+
assertEquals(1, template.headers().size());
341+
assertEquals(2, template.headers().get("tesT").size());
342+
}
343+
326344
@Test
327345
public void encodeSlashTest() {
328346
RequestTemplate template = new RequestTemplate().method(HttpMethod.GET)

0 commit comments

Comments
 (0)