Watcher: Ensure that HTTP headers are case insensitive in response

According to RFC 2616 HTTP headers are case insensitive.
But `HttpResponse#contentType()` only looks up for Content-Type.

This stores all header responses lower cased in the HTTP response.

Closes elastic/elasticsearch#1357

Original commit: elastic/x-pack-elasticsearch@c009be8365
This commit is contained in:
Alexander Reelsen 2016-02-05 14:59:27 +01:00
parent 166e8786ea
commit 93a3d3f570
3 changed files with 24 additions and 10 deletions

View File

@ -201,7 +201,7 @@ public class HttpClient extends AbstractLifecycleComponent<HttpClient> {
urlConnection.connect();
final int statusCode = urlConnection.getResponseCode();
Map<String, String[]> responseHeaders = new HashMap<>();
Map<String, String[]> responseHeaders = new HashMap<>(urlConnection.getHeaderFields().size());
for (Map.Entry<String, List<String>> header : urlConnection.getHeaderFields().entrySet()) {
// HttpURLConnection#getHeaderFields returns the first status line as a header
// with a `null` key (facepalm)... so we have to skip that one.
@ -209,7 +209,6 @@ public class HttpClient extends AbstractLifecycleComponent<HttpClient> {
responseHeaders.put(header.getKey(), header.getValue().toArray(new String[header.getValue().size()]));
}
}
responseHeaders = unmodifiableMap(responseHeaders);
logger.debug("http status code [{}]", statusCode);
if (statusCode < 400) {
final byte[] body;

View File

@ -11,6 +11,7 @@ import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.ParseFieldMatcher;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
@ -22,6 +23,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import static java.util.Collections.emptyMap;
@ -60,7 +62,11 @@ public class HttpResponse implements ToXContent {
public HttpResponse(int status, @Nullable BytesReference body, Map<String, String[]> headers) {
this.status = status;
this.body = body;
this.headers = headers;
MapBuilder<String, String[]> mapBuilder = MapBuilder.newMapBuilder();
for (Map.Entry<String, String[]> entry : headers.entrySet()) {
mapBuilder.put(entry.getKey().toLowerCase(Locale.ROOT), entry.getValue());
}
this.headers = mapBuilder.immutableMap();
}
public int status() {
@ -75,12 +81,12 @@ public class HttpResponse implements ToXContent {
return body;
}
public Map<String, String[]> headers() {
return headers;
public String[] header(String header) {
return headers.get(header.toLowerCase(Locale.ROOT));
}
public String contentType() {
String[] values = headers.get(HttpHeaders.Names.CONTENT_TYPE);
String[] values = header(HttpHeaders.Names.CONTENT_TYPE);
if (values == null || values.length == 0) {
return null;
}
@ -88,7 +94,7 @@ public class HttpResponse implements ToXContent {
}
public XContentType xContentType() {
String[] values = headers.get(HttpHeaders.Names.CONTENT_TYPE);
String[] values = header(HttpHeaders.Names.CONTENT_TYPE);
if (values == null || values.length == 0) {
return null;
}

View File

@ -12,6 +12,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.test.ESTestCase;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import static java.util.Collections.emptyMap;
@ -77,9 +78,17 @@ public class HttpResponseTests extends ESTestCase {
} else {
assertThat(parsedResponse.body().toUtf8(), is(body));
}
assertThat(parsedResponse.headers().size(), is(headers.size()));
for (Map.Entry<String, String[]> header : parsedResponse.headers().entrySet()) {
assertThat(header.getValue(), arrayContaining(headers.get(header.getKey())));
for (Map.Entry<String, String[]> headerEntry : headers.entrySet()) {
assertThat(headerEntry.getValue(), arrayContaining(parsedResponse.header(headerEntry.getKey())));
}
}
public void testThatHeadersAreCaseInsensitive() {
Map<String, String[]> headers = new HashMap<>();
headers.put(randomFrom("key", "keY", "KEY", "Key"), new String[] { "value" });
headers.put(randomFrom("content-type"), new String[] { "text/html" });
HttpResponse response = new HttpResponse(200, headers);
assertThat(response.header("key")[0], is("value"));
assertThat(response.contentType(), is("text/html"));
}
}