diff --git a/core/src/main/java/feign/RequestTemplate.java b/core/src/main/java/feign/RequestTemplate.java index d1c276f7f5..86dc730698 100644 --- a/core/src/main/java/feign/RequestTemplate.java +++ b/core/src/main/java/feign/RequestTemplate.java @@ -13,11 +13,7 @@ */ package feign; -import static feign.Util.CONTENT_LENGTH; -import static feign.Util.UTF_8; -import static feign.Util.checkNotNull; import feign.Request.HttpMethod; -import feign.template.BodyTemplate; import feign.template.HeaderTemplate; import feign.template.QueryTemplate; import feign.template.UriTemplate; @@ -25,19 +21,12 @@ import java.io.Serializable; import java.nio.charset.Charset; import java.util.AbstractMap.SimpleImmutableEntry; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; +import static feign.Util.*; /** * Request Builder for an HTTP Target. @@ -51,7 +40,7 @@ public final class RequestTemplate implements Serializable { private static final Pattern QUERY_STRING_PATTERN = Pattern.compile("(? queries = new LinkedHashMap<>(); - private final Map headers = new LinkedHashMap<>(); + private final Map headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); private String target; private boolean resolved = false; private UriTemplate uriTemplate; @@ -73,7 +62,6 @@ public RequestTemplate() { * * @param target for the template. * @param uriTemplate for the template. - * @param bodyTemplate for the template. * @param method of the request. * @param charset for the request. * @param body of the request, may be null @@ -691,7 +679,7 @@ public RequestTemplate headers(Map> headers) { * @return the currently applied headers. */ public Map> headers() { - Map> headerMap = new LinkedHashMap<>(); + Map> headerMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); this.headers.forEach((key, headerTemplate) -> { List values = new ArrayList<>(headerTemplate.getValues()); diff --git a/core/src/test/java/feign/LoggerTest.java b/core/src/test/java/feign/LoggerTest.java index 6f8ac7d688..a8dcb6ca71 100644 --- a/core/src/test/java/feign/LoggerTest.java +++ b/core/src/test/java/feign/LoggerTest.java @@ -76,16 +76,16 @@ public static Iterable data() { "\\[SendsStuff#login\\] <--- HTTP/1.1 200 OK \\([0-9]+ms\\)")}, {Level.HEADERS, Arrays.asList( "\\[SendsStuff#login\\] ---> POST http://localhost:[0-9]+/ HTTP/1.1", - "\\[SendsStuff#login\\] Content-Type: application/json", "\\[SendsStuff#login\\] Content-Length: 80", + "\\[SendsStuff#login\\] Content-Type: application/json", "\\[SendsStuff#login\\] ---> END HTTP \\(80-byte body\\)", "\\[SendsStuff#login\\] <--- HTTP/1.1 200 OK \\([0-9]+ms\\)", "\\[SendsStuff#login\\] content-length: 3", "\\[SendsStuff#login\\] <--- END HTTP \\(3-byte body\\)")}, {Level.FULL, Arrays.asList( "\\[SendsStuff#login\\] ---> POST http://localhost:[0-9]+/ HTTP/1.1", - "\\[SendsStuff#login\\] Content-Type: application/json", "\\[SendsStuff#login\\] Content-Length: 80", + "\\[SendsStuff#login\\] Content-Type: application/json", "\\[SendsStuff#login\\] ", "\\[SendsStuff#login\\] \\{\"customer_name\": \"netflix\", \"user_name\": \"denominator\", \"password\": \"password\"\\}", "\\[SendsStuff#login\\] ---> END HTTP \\(80-byte body\\)", @@ -161,14 +161,14 @@ public static Iterable data() { "\\[SendsStuff#login\\] <--- ERROR SocketTimeoutException: Read timed out \\([0-9]+ms\\)")}, {Level.HEADERS, Arrays.asList( "\\[SendsStuff#login\\] ---> POST http://localhost:[0-9]+/ HTTP/1.1", - "\\[SendsStuff#login\\] Content-Type: application/json", "\\[SendsStuff#login\\] Content-Length: 80", + "\\[SendsStuff#login\\] Content-Type: application/json", "\\[SendsStuff#login\\] ---> END HTTP \\(80-byte body\\)", "\\[SendsStuff#login\\] <--- ERROR SocketTimeoutException: Read timed out \\([0-9]+ms\\)")}, {Level.FULL, Arrays.asList( "\\[SendsStuff#login\\] ---> POST http://localhost:[0-9]+/ HTTP/1.1", - "\\[SendsStuff#login\\] Content-Type: application/json", "\\[SendsStuff#login\\] Content-Length: 80", + "\\[SendsStuff#login\\] Content-Type: application/json", "\\[SendsStuff#login\\] ", "\\[SendsStuff#login\\] \\{\"customer_name\": \"netflix\", \"user_name\": \"denominator\", \"password\": \"password\"\\}", "\\[SendsStuff#login\\] ---> END HTTP \\(80-byte body\\)", @@ -223,14 +223,14 @@ public static Iterable data() { "\\[SendsStuff#login\\] <--- ERROR UnknownHostException: robofu.abc \\([0-9]+ms\\)")}, {Level.HEADERS, Arrays.asList( "\\[SendsStuff#login\\] ---> POST http://robofu.abc/ HTTP/1.1", - "\\[SendsStuff#login\\] Content-Type: application/json", "\\[SendsStuff#login\\] Content-Length: 80", + "\\[SendsStuff#login\\] Content-Type: application/json", "\\[SendsStuff#login\\] ---> END HTTP \\(80-byte body\\)", "\\[SendsStuff#login\\] <--- ERROR UnknownHostException: robofu.abc \\([0-9]+ms\\)")}, {Level.FULL, Arrays.asList( "\\[SendsStuff#login\\] ---> POST http://robofu.abc/ HTTP/1.1", - "\\[SendsStuff#login\\] Content-Type: application/json", "\\[SendsStuff#login\\] Content-Length: 80", + "\\[SendsStuff#login\\] Content-Type: application/json", "\\[SendsStuff#login\\] ", "\\[SendsStuff#login\\] \\{\"customer_name\": \"netflix\", \"user_name\": \"denominator\", \"password\": \"password\"\\}", "\\[SendsStuff#login\\] ---> END HTTP \\(80-byte body\\)", @@ -285,14 +285,14 @@ public static Iterable data() { "\\[SendsStuff#login\\] <--- ERROR UnknownHostException: sna%fu.abc \\([0-9]+ms\\)")}, {Level.HEADERS, Arrays.asList( "\\[SendsStuff#login\\] ---> POST http://sna%fu.abc/ HTTP/1.1", - "\\[SendsStuff#login\\] Content-Type: application/json", "\\[SendsStuff#login\\] Content-Length: 80", + "\\[SendsStuff#login\\] Content-Type: application/json", "\\[SendsStuff#login\\] ---> END HTTP \\(80-byte body\\)", "\\[SendsStuff#login\\] <--- ERROR UnknownHostException: sna%fu.abc \\([0-9]+ms\\)")}, {Level.FULL, Arrays.asList( "\\[SendsStuff#login\\] ---> POST http://sna%fu.abc/ HTTP/1.1", - "\\[SendsStuff#login\\] Content-Type: application/json", "\\[SendsStuff#login\\] Content-Length: 80", + "\\[SendsStuff#login\\] Content-Type: application/json", "\\[SendsStuff#login\\] ", "\\[SendsStuff#login\\] \\{\"customer_name\": \"netflix\", \"user_name\": \"denominator\", \"password\": \"password\"\\}", "\\[SendsStuff#login\\] ---> END HTTP \\(80-byte body\\)", diff --git a/core/src/test/java/feign/RequestTemplateTest.java b/core/src/test/java/feign/RequestTemplateTest.java index 220a94ef84..e7b7034084 100644 --- a/core/src/test/java/feign/RequestTemplateTest.java +++ b/core/src/test/java/feign/RequestTemplateTest.java @@ -16,13 +16,10 @@ import static feign.assertj.FeignAssertions.assertThat; import static java.util.Arrays.asList; import static org.assertj.core.data.MapEntry.entry; +import static org.junit.Assert.*; import feign.Request.HttpMethod; import feign.template.UriUtils; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.*; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -323,6 +320,27 @@ public void spaceEncodingInUrlParam() { .isEqualTo("/api/ABC%20123?key=XYZ%20123"); } + @Test + public void useCaseInsensitiveHeaderFieldNames() { + final RequestTemplate template = new RequestTemplate(); + + final String value = "value1"; + template.header("TEST", value); + + final String value2 = "value2"; + template.header("tEST", value2); + + final Collection test = template.headers().get("test"); + + final String assertionMessage = "Header field names should be case insensitive"; + + assertNotNull(assertionMessage, test); + assertTrue(assertionMessage, test.contains(value)); + assertTrue(assertionMessage, test.contains(value2)); + assertEquals(1, template.headers().size()); + assertEquals(2, template.headers().get("tesT").size()); + } + @Test public void encodeSlashTest() { RequestTemplate template = new RequestTemplate().method(HttpMethod.GET)