Skip to content

Commit ebd1f4e

Browse files
committed
backport HttpHeaderParser
1 parent 8eae9d7 commit ebd1f4e

File tree

2 files changed

+95
-0
lines changed

2 files changed

+95
-0
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package org.elasticsearch.test.fixture;
11+
12+
import java.util.regex.Matcher;
13+
import java.util.regex.Pattern;
14+
15+
public enum HttpHeaderParser {
16+
;
17+
18+
private static final Pattern RANGE_HEADER_PATTERN = Pattern.compile("bytes=([0-9]+)-([0-9]+)");
19+
20+
/**
21+
* Parse a "Range" header
22+
*
23+
* Note: only a single bounded range is supported (e.g. <code>Range: bytes={range_start}-{range_end}</code>)
24+
*
25+
* @see <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Range">MDN: Range header</a>
26+
* @param rangeHeaderValue The header value as a string
27+
* @return a {@link Range} instance representing the parsed value, or null if the header is malformed
28+
*/
29+
public static Range parseRangeHeader(String rangeHeaderValue) {
30+
final Matcher matcher = RANGE_HEADER_PATTERN.matcher(rangeHeaderValue);
31+
if (matcher.matches()) {
32+
try {
33+
return new Range(Long.parseLong(matcher.group(1)), Long.parseLong(matcher.group(2)));
34+
} catch (NumberFormatException e) {
35+
return null;
36+
}
37+
}
38+
return null;
39+
}
40+
41+
public record Range(long start, long end) {}
42+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package org.elasticsearch.http;
11+
12+
import org.elasticsearch.common.Strings;
13+
import org.elasticsearch.test.ESTestCase;
14+
import org.elasticsearch.test.fixture.HttpHeaderParser;
15+
16+
import java.math.BigInteger;
17+
18+
public class HttpHeaderParserTests extends ESTestCase {
19+
20+
public void testParseRangeHeader() {
21+
final long start = randomLongBetween(0, 10_000);
22+
final long end = randomLongBetween(start, start + 10_000);
23+
assertEquals(new HttpHeaderParser.Range(start, end), HttpHeaderParser.parseRangeHeader("bytes=" + start + "-" + end));
24+
}
25+
26+
public void testParseRangeHeaderInvalidLong() {
27+
final BigInteger longOverflow = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE).add(randomBigInteger());
28+
assertNull(HttpHeaderParser.parseRangeHeader("bytes=123-" + longOverflow));
29+
assertNull(HttpHeaderParser.parseRangeHeader("bytes=" + longOverflow + "-123"));
30+
}
31+
32+
public void testParseRangeHeaderMultipleRangesNotMatched() {
33+
assertNull(
34+
HttpHeaderParser.parseRangeHeader(
35+
Strings.format(
36+
"bytes=%d-%d,%d-%d",
37+
randomIntBetween(0, 99),
38+
randomIntBetween(100, 199),
39+
randomIntBetween(200, 299),
40+
randomIntBetween(300, 399)
41+
)
42+
)
43+
);
44+
}
45+
46+
public void testParseRangeHeaderEndlessRangeNotMatched() {
47+
assertNull(HttpHeaderParser.parseRangeHeader(Strings.format("bytes=%d-", randomLongBetween(0, Long.MAX_VALUE))));
48+
}
49+
50+
public void testParseRangeHeaderSuffixLengthNotMatched() {
51+
assertNull(HttpHeaderParser.parseRangeHeader(Strings.format("bytes=-%d", randomLongBetween(0, Long.MAX_VALUE))));
52+
}
53+
}

0 commit comments

Comments
 (0)