LibHTTP: Ignore empty list elements when extracting token headers

It turns out that the validation of header values in db5f16f042
was a bit over aggressive. extract_token_headers previously treated
empty list elements (empty or whitespace-only after trimming) as parse
failures. This is incorrect per RFC 9110, which specifies that
recipients must ignore empty list elements in comma-separated header
values.

> A recipient MUST parse and ignore a reasonable number of empty
> list elements
This commit is contained in:
Shannon Booth 2026-03-15 19:39:29 +01:00 committed by Shannon Booth
parent cc711a6060
commit d76330645a
2 changed files with 29 additions and 10 deletions

View file

@ -24,17 +24,19 @@ Header Header::isomorphic_encode(StringView name, StringView value)
return { TextCodec::isomorphic_encode(name), TextCodec::isomorphic_encode(value) };
}
// https://www.rfc-editor.org/rfc/rfc9110.html#name-recipient-requirements
static Optional<Vector<ByteString>> extract_token_headers(ByteString const& value)
{
auto parts = value.split(',', SplitBehavior::Nothing);
for (auto& part : parts) {
part = part.trim(HTTP_WHITESPACE, TrimMode::Both);
if (part.is_empty())
return {};
if (!is_header_name(part))
Vector<ByteString> result;
for (auto& part : value.split(',', SplitBehavior::Nothing)) {
auto trimmed = part.trim(HTTP_WHITESPACE, TrimMode::Both);
if (trimmed.is_empty())
continue;
if (!is_header_name(trimmed))
return {};
result.append(move(trimmed));
}
return parts;
return result;
}
// https://fetch.spec.whatwg.org/#extract-header-values

View file

@ -172,13 +172,30 @@ TEST_CASE(extract_header_values)
EXPECT_EQ(result, (Vector<ByteString> {}));
}
result = HTTP::Header { header, ",,,"sv }.extract_header_values();
// Two commas and some spaces.
result = HTTP::Header { header, ", ,"sv }.extract_header_values();
if (requires_at_least_one) {
EXPECT_EQ(result, OptionalNone {});
} else {
EXPECT_EQ(result, (Vector<ByteString> {}));
}
// Only a comma.
result = HTTP::Header { header, ","sv }.extract_header_values();
if (requires_at_least_one) {
EXPECT_EQ(result, OptionalNone {});
} else {
EXPECT_EQ(result, (Vector<ByteString> {}));
}
// Empty list element ignored.
result = HTTP::Header { header, "foo , ,bar,charlie"sv }.extract_header_values();
EXPECT_EQ(result, (Vector<ByteString> { "foo", "bar", "charlie" }));
// Leading empty list component.
result = HTTP::Header { header, ",foo,bar"sv }.extract_header_values();
EXPECT_EQ(result, (Vector<ByteString> { "foo", "bar" }));
// Space inside a token is invalid.
result = HTTP::Header { header, "no no"sv }.extract_header_values();
EXPECT_EQ(result, OptionalNone {});
@ -203,9 +220,9 @@ TEST_CASE(extract_header_values)
result = HTTP::Header { header, "bb-8,no no"sv }.extract_header_values();
EXPECT_EQ(result, OptionalNone {});
// Whitespace-only item between commas fails.
// Whitespace-only item is ignored.
result = HTTP::Header { header, "bb-8, ,no"sv }.extract_header_values();
EXPECT_EQ(result, OptionalNone {});
EXPECT_EQ(result, (Vector<ByteString> { "bb-8", "no" }));
}
// Other headers: returned as a single-element list regardless of content.