From 455aa340111edd83a517e992b9fe4efac70f6886 Mon Sep 17 00:00:00 2001 From: Linus Groh Date: Tue, 25 Oct 2022 23:02:47 +0100 Subject: [PATCH] LibWeb: Partially implement 'Extract header (list) values' AOs The header-specific ABNF rules are completely ignored for now, but we can at least extract a single header value, which at least works for simple cases like `Location`-based redirects. --- .../Fetch/Infrastructure/HTTP/Headers.cpp | 45 ++++++++++++++++++- .../Fetch/Infrastructure/HTTP/Headers.h | 2 + 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.cpp b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.cpp index 5efd151b7f..d1c224138e 100644 --- a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.cpp +++ b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.cpp @@ -636,8 +636,49 @@ bool is_request_body_header_name(ReadonlyBytes header_name) "Content-Type"sv); } -// TODO: https://fetch.spec.whatwg.org/#extract-header-values -// TODO: https://fetch.spec.whatwg.org/#extract-header-list-values +// https://fetch.spec.whatwg.org/#extract-header-values +ErrorOr>> extract_header_values(Header const& header) +{ + // FIXME: 1. If parsing header’s value, per the ABNF for header’s name, fails, then return failure. + // FIXME: 2. Return one or more values resulting from parsing header’s value, per the ABNF for header’s name. + // This always ignores the ABNF rules for now and returns the header value as a single list item. + return Vector { TRY(ByteBuffer::copy(header.value)) }; +} + +// https://fetch.spec.whatwg.org/#extract-header-list-values +ErrorOr>> extract_header_list_values(ReadonlyBytes name, HeaderList const& list) +{ + // 1. If list does not contain name, then return null. + if (!list.contains(name)) + return Optional> {}; + + // FIXME: 2. If the ABNF for name allows a single header and list contains more than one, then return failure. + // NOTE: If different error handling is needed, extract the desired header first. + + // 3. Let values be an empty list. + auto values = Vector {}; + + // 4. For each header header list contains whose name is name: + for (auto const& header : list) { + if (!StringView { header.name }.equals_ignoring_case(name)) + continue; + + // 1. Let extract be the result of extracting header values from header. + auto extract = TRY(extract_header_values(header)); + + // 2. If extract is failure, then return failure. + // FIXME: Currently we treat the null return above and failure return as the same thing, + // ErrorOr already signals OOM to the caller. + if (!extract.has_value()) + return Optional> {}; + + // 3. Append each value in extract, in order, to values. + values.extend(extract.release_value()); + } + + // 5. Return values. + return values; +} // https://fetch.spec.whatwg.org/#simple-range-header-value Optional parse_single_range_header_value(ReadonlyBytes value) diff --git a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.h b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.h index 3b6515131e..e2dbb19816 100644 --- a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.h +++ b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.h @@ -73,6 +73,8 @@ struct RangeHeaderValue { [[nodiscard]] bool is_forbidden_header_name(ReadonlyBytes); [[nodiscard]] bool is_forbidden_response_header_name(ReadonlyBytes); [[nodiscard]] bool is_request_body_header_name(ReadonlyBytes); +[[nodiscard]] ErrorOr>> extract_header_values(Header const&); +[[nodiscard]] ErrorOr>> extract_header_list_values(ReadonlyBytes, HeaderList const&); [[nodiscard]] Optional parse_single_range_header_value(ReadonlyBytes); [[nodiscard]] ErrorOr default_user_agent_value();