Skip to content

Commit c333903

Browse files
committed
Http header field names must be case-insensitive
GitHub has started changing their headers from capitalized words to all lowercase. A recent change made the header fields querying case-senstive which broke gzip content detection. This was not caught by tests because recorded files remain unchanged. It is also possible that WireMock is auto-capitalizing. This fixes the case-sensitivity issue and also extends that funcionality to anyone consuming the headers generated by ResponseInfo. Fixes #751
1 parent dd55e8a commit c333903

File tree

2 files changed

+34
-2
lines changed

2 files changed

+34
-2
lines changed

src/main/java/org/kohsuke/github/GitHubResponse.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@
1212
import java.net.URL;
1313
import java.nio.charset.StandardCharsets;
1414
import java.util.Collections;
15-
import java.util.HashMap;
15+
import java.util.Comparator;
1616
import java.util.List;
1717
import java.util.Map;
18+
import java.util.TreeMap;
1819

1920
import javax.annotation.CheckForNull;
2021
import javax.annotation.Nonnull;
@@ -206,6 +207,9 @@ interface BodyHandler<T> {
206207
*/
207208
static abstract class ResponseInfo {
208209

210+
private static final Comparator<String> nullableCaseInsensitiveComparator = Comparator
211+
.nullsFirst(String.CASE_INSENSITIVE_ORDER);
212+
209213
private final int statusCode;
210214
@Nonnull
211215
private final GitHubRequest request;
@@ -217,7 +221,12 @@ protected ResponseInfo(@Nonnull GitHubRequest request,
217221
@Nonnull Map<String, List<String>> headers) {
218222
this.request = request;
219223
this.statusCode = statusCode;
220-
this.headers = Collections.unmodifiableMap(new HashMap<>(headers));
224+
225+
// Response header field names must be case-insensitive.
226+
TreeMap<String, List<String>> caseInsensitiveMap = new TreeMap<>(nullableCaseInsensitiveComparator);
227+
caseInsensitiveMap.putAll(headers);
228+
229+
this.headers = Collections.unmodifiableMap(caseInsensitiveMap);
221230
}
222231

223232
/**

src/test/java/org/kohsuke/github/GHObjectTest.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import org.junit.Test;
44

5+
import java.util.Objects;
6+
57
import static org.hamcrest.Matchers.*;
68

79
public class GHObjectTest extends org.kohsuke.github.AbstractGitHubWireMockTest {
@@ -16,5 +18,26 @@ public void test_toString() throws Exception {
1618
// getResponseHeaderFields is deprecated but we should not break it.
1719
assertThat(org.getResponseHeaderFields(), notNullValue());
1820
assertThat(org.getResponseHeaderFields().get("Cache-Control").get(0), is("private, max-age=60, s-maxage=60"));
21+
22+
// Header field names must be case-insensitive
23+
assertThat(org.getResponseHeaderFields().containsKey("CacHe-ContrOl"), is(true));
24+
25+
// The KeySet from header fields should also be case-insensitive
26+
assertThat(org.getResponseHeaderFields().keySet().contains("CacHe-ControL"), is(true));
27+
assertThat(org.getResponseHeaderFields().keySet().contains("CacHe-ControL"), is(true));
28+
29+
assertThat(org.getResponseHeaderFields().get("cachE-cOntrol").get(0), is("private, max-age=60, s-maxage=60"));
30+
31+
// GitHub has started changing their headers to all lowercase.
32+
// For this test we want the field names to be with mixed-case (harder to do comparison).
33+
// Ensure that it remains that way, if test resources are ever refreshed.
34+
boolean found = false;
35+
for (String key : org.getResponseHeaderFields().keySet()) {
36+
if (Objects.equals("Cache-Control", key)) {
37+
found = true;
38+
break;
39+
}
40+
}
41+
assertThat("Must have the literal expected string 'Cache-Control' for header field name", found);
1942
}
2043
}

0 commit comments

Comments
 (0)