Skip to content

Commit c2ec248

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

File tree

3 files changed

+35
-28
lines changed

3 files changed

+35
-28
lines changed

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

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@
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;
16+
import static feign.Util.*;
1917

2018
import feign.Request.HttpMethod;
2119
import feign.template.HeaderTemplate;
@@ -24,16 +22,8 @@
2422
import feign.template.UriUtils;
2523
import java.io.Serializable;
2624
import java.nio.charset.Charset;
25+
import java.util.*;
2726
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;
3727
import java.util.Map.Entry;
3828
import java.util.regex.Matcher;
3929
import java.util.regex.Pattern;
@@ -50,7 +40,7 @@ public final class RequestTemplate implements Serializable {
5040

5141
private static final Pattern QUERY_STRING_PATTERN = Pattern.compile("(?<!\\{)\\?");
5242
private final Map<String, QueryTemplate> queries = new LinkedHashMap<>();
53-
private final Map<String, HeaderTemplate> headers = new LinkedHashMap<>();
43+
private final Map<String, HeaderTemplate> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
5444
private String target;
5545
private boolean resolved = false;
5646
private UriTemplate uriTemplate;
@@ -70,7 +60,6 @@ public RequestTemplate() {
7060
*
7161
* @param target for the template.
7262
* @param uriTemplate for the template.
73-
* @param bodyTemplate for the template.
7463
* @param method of the request.
7564
* @param charset for the request.
7665
* @param body of the request, may be null
@@ -694,7 +683,7 @@ public RequestTemplate headers(Map<String, Collection<String>> headers) {
694683
* @return the currently applied headers.
695684
*/
696685
public Map<String, Collection<String>> headers() {
697-
Map<String, Collection<String>> headerMap = new LinkedHashMap<>();
686+
Map<String, Collection<String>> headerMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
698687
this.headers.forEach(
699688
(key, headerTemplate) -> {
700689
List<String> values = new ArrayList<>(headerTemplate.getValues());

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ public static Iterable<Object[]> data() {
8282
Level.HEADERS,
8383
Arrays.asList(
8484
"\\[SendsStuff#login\\] ---> POST http://localhost:[0-9]+/ HTTP/1.1",
85-
"\\[SendsStuff#login\\] Content-Type: application/json",
8685
"\\[SendsStuff#login\\] Content-Length: 80",
86+
"\\[SendsStuff#login\\] Content-Type: application/json",
8787
"\\[SendsStuff#login\\] ---> END HTTP \\(80-byte body\\)",
8888
"\\[SendsStuff#login\\] <--- HTTP/1.1 200 OK \\([0-9]+ms\\)",
8989
"\\[SendsStuff#login\\] content-length: 3",
@@ -93,8 +93,8 @@ public static Iterable<Object[]> data() {
9393
Level.FULL,
9494
Arrays.asList(
9595
"\\[SendsStuff#login\\] ---> POST http://localhost:[0-9]+/ HTTP/1.1",
96-
"\\[SendsStuff#login\\] Content-Type: application/json",
9796
"\\[SendsStuff#login\\] Content-Length: 80",
97+
"\\[SendsStuff#login\\] Content-Type: application/json",
9898
"\\[SendsStuff#login\\] ",
9999
"\\[SendsStuff#login\\] \\{\"customer_name\": \"netflix\", \"user_name\":"
100100
+ " \"denominator\", \"password\": \"password\"\\}",
@@ -185,8 +185,8 @@ public static Iterable<Object[]> data() {
185185
Level.HEADERS,
186186
Arrays.asList(
187187
"\\[SendsStuff#login\\] ---> POST http://localhost:[0-9]+/ HTTP/1.1",
188-
"\\[SendsStuff#login\\] Content-Type: application/json",
189188
"\\[SendsStuff#login\\] Content-Length: 80",
189+
"\\[SendsStuff#login\\] Content-Type: application/json",
190190
"\\[SendsStuff#login\\] ---> END HTTP \\(80-byte body\\)",
191191
"\\[SendsStuff#login\\] <--- ERROR SocketTimeoutException: Read timed out"
192192
+ " \\([0-9]+ms\\)")
@@ -195,8 +195,8 @@ public static Iterable<Object[]> data() {
195195
Level.FULL,
196196
Arrays.asList(
197197
"\\[SendsStuff#login\\] ---> POST http://localhost:[0-9]+/ HTTP/1.1",
198-
"\\[SendsStuff#login\\] Content-Type: application/json",
199198
"\\[SendsStuff#login\\] Content-Length: 80",
199+
"\\[SendsStuff#login\\] Content-Type: application/json",
200200
"\\[SendsStuff#login\\] ",
201201
"\\[SendsStuff#login\\] \\{\"customer_name\": \"netflix\", \"user_name\":"
202202
+ " \"denominator\", \"password\": \"password\"\\}",
@@ -263,8 +263,8 @@ public static Iterable<Object[]> data() {
263263
Level.HEADERS,
264264
Arrays.asList(
265265
"\\[SendsStuff#login\\] ---> POST http://robofu.abc/ HTTP/1.1",
266-
"\\[SendsStuff#login\\] Content-Type: application/json",
267266
"\\[SendsStuff#login\\] Content-Length: 80",
267+
"\\[SendsStuff#login\\] Content-Type: application/json",
268268
"\\[SendsStuff#login\\] ---> END HTTP \\(80-byte body\\)",
269269
"\\[SendsStuff#login\\] <--- ERROR UnknownHostException: robofu.abc"
270270
+ " \\([0-9]+ms\\)")
@@ -273,8 +273,8 @@ public static Iterable<Object[]> data() {
273273
Level.FULL,
274274
Arrays.asList(
275275
"\\[SendsStuff#login\\] ---> POST http://robofu.abc/ HTTP/1.1",
276-
"\\[SendsStuff#login\\] Content-Type: application/json",
277276
"\\[SendsStuff#login\\] Content-Length: 80",
277+
"\\[SendsStuff#login\\] Content-Type: application/json",
278278
"\\[SendsStuff#login\\] ",
279279
"\\[SendsStuff#login\\] \\{\"customer_name\": \"netflix\", \"user_name\":"
280280
+ " \"denominator\", \"password\": \"password\"\\}",
@@ -339,8 +339,8 @@ public static Iterable<Object[]> data() {
339339
Level.HEADERS,
340340
Arrays.asList(
341341
"\\[SendsStuff#login\\] ---> POST http://sna%fu.abc/ HTTP/1.1",
342-
"\\[SendsStuff#login\\] Content-Type: application/json",
343342
"\\[SendsStuff#login\\] Content-Length: 80",
343+
"\\[SendsStuff#login\\] Content-Type: application/json",
344344
"\\[SendsStuff#login\\] ---> END HTTP \\(80-byte body\\)",
345345
"\\[SendsStuff#login\\] <--- ERROR UnknownHostException: sna%fu.abc"
346346
+ " \\([0-9]+ms\\)")
@@ -349,8 +349,8 @@ public static Iterable<Object[]> data() {
349349
Level.FULL,
350350
Arrays.asList(
351351
"\\[SendsStuff#login\\] ---> POST http://sna%fu.abc/ HTTP/1.1",
352-
"\\[SendsStuff#login\\] Content-Type: application/json",
353352
"\\[SendsStuff#login\\] Content-Length: 80",
353+
"\\[SendsStuff#login\\] Content-Type: application/json",
354354
"\\[SendsStuff#login\\] ",
355355
"\\[SendsStuff#login\\] \\{\"customer_name\": \"netflix\", \"user_name\":"
356356
+ " \"denominator\", \"password\": \"password\"\\}",

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

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,11 @@
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

2021
import feign.Request.HttpMethod;
2122
import feign.template.UriUtils;
22-
import java.util.Arrays;
23-
import java.util.Collection;
24-
import java.util.Collections;
25-
import java.util.LinkedHashMap;
26-
import java.util.Map;
23+
import java.util.*;
2724
import org.junit.Rule;
2825
import org.junit.Test;
2926
import org.junit.rules.ExpectedException;
@@ -337,6 +334,27 @@ public void spaceEncodingInUrlParam() {
337334
assertThat(template.request().url()).isEqualTo("/api/ABC%20123?key=XYZ%20123");
338335
}
339336

337+
@Test
338+
public void useCaseInsensitiveHeaderFieldNames() {
339+
final RequestTemplate template = new RequestTemplate();
340+
341+
final String value = "value1";
342+
template.header("TEST", value);
343+
344+
final String value2 = "value2";
345+
template.header("tEST", value2);
346+
347+
final Collection<String> test = template.headers().get("test");
348+
349+
final String assertionMessage = "Header field names should be case insensitive";
350+
351+
assertNotNull(assertionMessage, test);
352+
assertTrue(assertionMessage, test.contains(value));
353+
assertTrue(assertionMessage, test.contains(value2));
354+
assertEquals(1, template.headers().size());
355+
assertEquals(2, template.headers().get("tesT").size());
356+
}
357+
340358
@Test
341359
public void encodeSlashTest() {
342360
RequestTemplate template =

0 commit comments

Comments
 (0)