Skip to content

Commit 0920cec

Browse files
committed
Check for chunked encoding with a new MessageHeaders.contains() method #39
We were incorrectly throwing when there were multiple Transfer-Encoding headers and we weren't matching in cases when a comma separated list was used.
1 parent 3c95c27 commit 0920cec

File tree

4 files changed

+56
-1
lines changed

4 files changed

+56
-1
lines changed

Diff for: README.md

+1
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ fields and a body. Header field names are case-insensitvie and may have multiple
207207
(String) message.contentType(); // the media type of the body
208208
(Headers) message.headers(); // the header fields
209209
(List<String>) message.headers().all("Cookie"); // all values of a header
210+
(boolean) message.headers().contains("TE", "deflate"); // tests if a value is present
210211
(Optional<String>) message.headers().first("Cookie"); // the first value of a header
211212
(Map<String,List<String>>) message.headers().map(); // views the header fields as a map
212213
(Optional<String>) message.headers().sole("Location"); // throws if header has multiple values

Diff for: src/org/netpreserve/jwarc/HttpResponse.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ private static HttpResponse parse(ReadableByteChannel channel, WritableByteChann
7373
MessageBody body;
7474
if (withoutBody) {
7575
body = MessageBody.empty();
76-
} else if (headers.sole("Transfer-Encoding").orElse("").equalsIgnoreCase("chunked")) {
76+
} else if (headers.contains("Transfer-Encoding", "chunked")) {
7777
body = new ChunkedBody(channel, buffer);
7878
} else {
7979
if (channel instanceof LengthedBody.LengthedReadableByteChannel) {

Diff for: src/org/netpreserve/jwarc/MessageHeaders.java

+18
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@
1313
import java.util.List;
1414
import java.util.Map;
1515
import java.util.Optional;
16+
import java.util.regex.Pattern;
1617

1718
import static java.util.Collections.emptyList;
1819

1920
public class MessageHeaders {
21+
private static Pattern COMMA_SEPARATOR = Pattern.compile("[ \t]*,[ \t]*");
2022
private Map<String,List<String>> map;
2123

2224
MessageHeaders(Map<String, List<String>> map) {
@@ -56,6 +58,22 @@ public Map<String,List<String>> map() {
5658
return map;
5759
}
5860

61+
/**
62+
* Returns true when the given header value is present.
63+
*
64+
* Fields are interpreted as a comma-separated list and the value is compared case-insensitively.
65+
*/
66+
public boolean contains(String name, String value) {
67+
for (String rawValue : all(name)) {
68+
for (String splitValue : COMMA_SEPARATOR.split(rawValue)) {
69+
if (splitValue.trim().equalsIgnoreCase(value)) {
70+
return true;
71+
}
72+
}
73+
}
74+
return false;
75+
}
76+
5977
@Override
6078
public String toString() {
6179
return map.toString();

Diff for: test/org/netpreserve/jwarc/MessageHeadersTest.java

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.netpreserve.jwarc;
2+
3+
import org.junit.Test;
4+
5+
import java.util.ArrayList;
6+
import java.util.List;
7+
import java.util.Map;
8+
import java.util.TreeMap;
9+
10+
import static org.junit.Assert.*;
11+
12+
public class MessageHeadersTest {
13+
@Test
14+
public void testContains() {
15+
assertFalse(headers("Z", "1")
16+
.contains("Transfer-Encoding", "chunked"));
17+
assertTrue(headers("A", "0", "Transfer-Encoding", "chunked", "Z", "1")
18+
.contains("Transfer-Encoding", "chunked"));
19+
assertFalse(headers("Transfer-Encoding", "xchunkedx")
20+
.contains("Transfer-Encoding", "chunked"));
21+
assertFalse(headers("Transfer-Encoding", "gzip chunked")
22+
.contains("Transfer-Encoding", "chunked"));
23+
assertTrue(headers("Transfer-Encoding", "gzip, chunked, chunked, gzip")
24+
.contains("Transfer-Encoding", "chunked"));
25+
assertTrue(headers("Transfer-Encoding", "gzip, \tCHUNKED,,, GZIP")
26+
.contains("Transfer-Encoding", "Chunked"));
27+
}
28+
29+
private static MessageHeaders headers(String... headers) {
30+
Map<String,List<String>> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
31+
for (int i = 0; i < headers.length; i += 2) {
32+
map.computeIfAbsent(headers[i], (k) -> new ArrayList<>()).add(headers[i + 1]);
33+
}
34+
return new MessageHeaders(map);
35+
}
36+
}

0 commit comments

Comments
 (0)