mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 20:28:11 +00:00
LibWeb/Fetch: Add support for parsing a single range header value
This is a change in the Fetch spec. See: -2d080d7
-a18fb3e
This commit is contained in:
parent
b8e0cec20e
commit
60e9790a40
2 changed files with 39 additions and 27 deletions
|
@ -425,8 +425,16 @@ bool is_cors_safelisted_request_header(Header const& header)
|
|||
}
|
||||
// `range`
|
||||
else if (name.equals_ignoring_case("range"sv)) {
|
||||
// If value is not a simple range header value, then return false.
|
||||
if (!is_simple_range_header_value(value))
|
||||
// 1. Let rangeValue be the result of parsing a single range header value given value.
|
||||
auto range_value = parse_single_range_header_value(value);
|
||||
|
||||
// 2. If rangeValue is failure, then return false.
|
||||
if (!range_value.has_value())
|
||||
return false;
|
||||
|
||||
// 3. If rangeValue[0] is null, then return false.
|
||||
// NOTE: As web browsers have historically not emitted ranges such as `bytes=-500` this algorithm does not safelist them.
|
||||
if (!range_value->start.has_value())
|
||||
return false;
|
||||
}
|
||||
// Otherwise
|
||||
|
@ -616,16 +624,14 @@ bool is_request_body_header_name(ReadonlyBytes header_name)
|
|||
// TODO: https://fetch.spec.whatwg.org/#extract-header-list-values
|
||||
|
||||
// https://fetch.spec.whatwg.org/#simple-range-header-value
|
||||
bool is_simple_range_header_value(ReadonlyBytes value)
|
||||
Optional<RangeHeaderValue> parse_single_range_header_value(ReadonlyBytes value)
|
||||
{
|
||||
// To determine if a byte sequence value is a simple range header value, perform the following steps. They return a boolean.
|
||||
|
||||
// 1. Let data be the isomorphic decoding of value.
|
||||
auto data = StringView { value };
|
||||
|
||||
// 2. If data does not start with "bytes=", then return false.
|
||||
// 2. If data does not start with "bytes=", then return failure.
|
||||
if (!data.starts_with("bytes="sv))
|
||||
return false;
|
||||
return {};
|
||||
|
||||
// 3. Let position be a position variable for data, initially pointing at the 6th code point of data.
|
||||
auto lexer = GenericLexer { data };
|
||||
|
@ -634,34 +640,35 @@ bool is_simple_range_header_value(ReadonlyBytes value)
|
|||
// 4. Let rangeStart be the result of collecting a sequence of code points that are ASCII digits, from data given position.
|
||||
auto range_start = lexer.consume_while(is_ascii_digit);
|
||||
|
||||
// FIXME: I believe the case of an empty rangeStart string (`bytes=-`) is not handled,
|
||||
// and would later fail 'interpreted as decimal number'.
|
||||
if (range_start.is_empty())
|
||||
return false;
|
||||
// 5. Let rangeStartValue be rangeStart, interpreted as decimal number, if rangeStart is not the empty string; otherwise null.
|
||||
auto range_start_value = range_start.to_uint<u64>();
|
||||
|
||||
// 5. If the code point at position within data is not U+002D (-), then return false.
|
||||
// 6. Advance position by 1.
|
||||
// 6. If the code point at position within data is not U+002D (-), then return failure.
|
||||
// 7. Advance position by 1.
|
||||
if (!lexer.consume_specific('-'))
|
||||
return false;
|
||||
return {};
|
||||
|
||||
// 7. Let rangeEnd be the result of collecting a sequence of code points that are ASCII digits, from data given position.
|
||||
// 8. Let rangeEnd be the result of collecting a sequence of code points that are ASCII digits, from data given position.
|
||||
auto range_end = lexer.consume_while(is_ascii_digit);
|
||||
|
||||
// 8. If position is not past the end of data, then return false.
|
||||
// 9. Let rangeEndValue be rangeEnd, interpreted as decimal number, if rangeEnd is not the empty string; otherwise null.
|
||||
auto range_end_value = range_end.to_uint<u64>();
|
||||
|
||||
// 10. If position is not past the end of data, then return failure.
|
||||
if (!lexer.is_eof())
|
||||
return false;
|
||||
return {};
|
||||
|
||||
// 9. If rangeEnd’s length is 0, then return true.
|
||||
// NOTE: The range end can be omitted, e.g., `bytes=0-` is valid.
|
||||
if (range_end.is_empty())
|
||||
return true;
|
||||
// 11. If rangeEndValue and rangeStartValue are null, then return failure.
|
||||
if (!range_end_value.has_value() && !range_start_value.has_value())
|
||||
return {};
|
||||
|
||||
// 10. If rangeStart, interpreted as decimal number, is greater than rangeEnd, interpreted as decimal number, then return false.
|
||||
if (*range_start.to_uint<u64>() > *range_end.to_uint<u64>())
|
||||
return false;
|
||||
// 12. If rangeStartValue and rangeEndValue are numbers, and rangeStartValue is greater than rangeEndValue, then return failure.
|
||||
if (range_start_value.has_value() && range_end_value.has_value() && *range_start_value > *range_end_value)
|
||||
return {};
|
||||
|
||||
// 11. Return true.
|
||||
return true;
|
||||
// 13. Return (rangeStartValue, rangeEndValue).
|
||||
// NOTE: The range end or start can be omitted, e.g., `bytes=0-` or `bytes=-500` are valid ranges.
|
||||
return RangeHeaderValue { move(range_start_value), move(range_end_value) };
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -45,6 +45,11 @@ public:
|
|||
[[nodiscard]] Optional<MimeSniff::MimeType> extract_mime_type() const;
|
||||
};
|
||||
|
||||
struct RangeHeaderValue {
|
||||
Optional<u64> start;
|
||||
Optional<u64> end;
|
||||
};
|
||||
|
||||
[[nodiscard]] ErrorOr<OrderedHashTable<ByteBuffer>> convert_header_names_to_a_sorted_lowercase_set(Span<ReadonlyBytes>);
|
||||
[[nodiscard]] bool is_header_name(ReadonlyBytes);
|
||||
[[nodiscard]] bool is_header_value(ReadonlyBytes);
|
||||
|
@ -60,6 +65,6 @@ public:
|
|||
[[nodiscard]] bool is_forbidden_header_name(ReadonlyBytes);
|
||||
[[nodiscard]] bool is_forbidden_response_header_name(ReadonlyBytes);
|
||||
[[nodiscard]] bool is_request_body_header_name(ReadonlyBytes);
|
||||
[[nodiscard]] bool is_simple_range_header_value(ReadonlyBytes);
|
||||
[[nodiscard]] Optional<RangeHeaderValue> parse_single_range_header_value(ReadonlyBytes);
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue