From 237df9df5c471edb8db44b96bb8a9f51418824c2 Mon Sep 17 00:00:00 2001 From: Luke Wilde Date: Wed, 8 Feb 2023 23:32:44 +0000 Subject: LibWeb: Make extract_header_list_values differentiate parsing failures Previously, parsing failures and the header not existing made extract_header_list_values return an empty Optional, making it impossible to differentiate between the two. Required for implementing CORS-preflight, where parsing failures for the headers makes it fail, but not having them doesn't make it fail in all cases. --- .../Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.cpp | 8 +++----- Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.h | 5 ++++- .../Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.cpp | 10 +++++++--- 3 files changed, 14 insertions(+), 9 deletions(-) (limited to 'Userland/Libraries') diff --git a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.cpp b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.cpp index 9dd59d8996..e12604921a 100644 --- a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.cpp +++ b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.cpp @@ -685,11 +685,11 @@ ErrorOr>> extract_header_values(Header const& header } // https://fetch.spec.whatwg.org/#extract-header-list-values -ErrorOr>> extract_header_list_values(ReadonlyBytes name, HeaderList const& list) +ErrorOr, ExtractHeaderParseFailure, Empty>> 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> {}; + return Empty {}; // 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. @@ -706,10 +706,8 @@ ErrorOr>> extract_header_list_values(ReadonlyBytes n 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> {}; + return ExtractHeaderParseFailure {}; // 3. Append each value in extract, in order, to values. values.extend(extract.release_value()); diff --git a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.h b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.h index 00192f9a72..7e5b31b7f7 100644 --- a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.h +++ b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.h @@ -59,6 +59,9 @@ struct RangeHeaderValue { Optional end; }; +struct ExtractHeaderParseFailure { +}; + [[nodiscard]] ErrorOr>> get_decode_and_split_header_value(ReadonlyBytes); [[nodiscard]] ErrorOr> convert_header_names_to_a_sorted_lowercase_set(Span); [[nodiscard]] bool is_header_name(ReadonlyBytes); @@ -76,7 +79,7 @@ struct RangeHeaderValue { [[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]] ErrorOr, ExtractHeaderParseFailure, Empty>> extract_header_list_values(ReadonlyBytes, HeaderList const&); [[nodiscard]] Optional parse_single_range_header_value(ReadonlyBytes); [[nodiscard]] ErrorOr default_user_agent_value(); diff --git a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.cpp b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.cpp index 0fad48ad08..237bdd1b63 100644 --- a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.cpp +++ b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.cpp @@ -104,13 +104,17 @@ ErrorOr> Response::location_url(Optional con return Optional {}; // 2. Let location be the result of extracting header list values given `Location` and response’s header list. - auto location_values = TRY(extract_header_list_values("Location"sv.bytes(), m_header_list)); - if (!location_values.has_value() || location_values->size() != 1) + auto location_values_or_failure = TRY(extract_header_list_values("Location"sv.bytes(), m_header_list)); + if (location_values_or_failure.has() || location_values_or_failure.has()) + return Optional {}; + + auto const& location_values = location_values_or_failure.get>(); + if (location_values.size() != 1) return Optional {}; // 3. If location is a header value, then set location to the result of parsing location with response’s URL. auto base_url = *url(); - auto location = AK::URLParser::parse(location_values->first(), &base_url); + auto location = AK::URLParser::parse(location_values.first(), &base_url); if (!location.is_valid()) return Error::from_string_view("Invalid 'Location' header URL"sv); -- cgit v1.2.3