diff options
author | Linus Groh <mail@linusgroh.de> | 2023-02-10 22:02:18 +0000 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2023-02-11 13:14:26 +0000 |
commit | ee68eba0acc380a3b52efb3ed4bddffdab2eceaa (patch) | |
tree | 7f5edaef9157cb5deffc140389fc741731203fcb /Userland/Libraries/LibWeb/Fetch | |
parent | 6bce48e99bf7bc325f4047a20828bb8099025dad (diff) | |
download | serenity-ee68eba0acc380a3b52efb3ed4bddffdab2eceaa.zip |
LibWeb: Implement Headers.getSetCookie()
This is a normative change in the Fetch spec.
See: https://github.com/whatwg/fetch/commit/e4d3480
This also implements the changes to the 'sort and combine' algorithm,
which now treats "set-cookie" headers differently, and is exposed to JS
via the Headers' iterator.
Passes all 21 WPT tests :^)
http://wpt.live/fetch/api/headers/header-setcookie.any.html
Diffstat (limited to 'Userland/Libraries/LibWeb/Fetch')
-rw-r--r-- | Userland/Libraries/LibWeb/Fetch/Headers.cpp | 22 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Fetch/Headers.h | 3 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Fetch/Headers.idl | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.cpp | 42 |
4 files changed, 54 insertions, 14 deletions
diff --git a/Userland/Libraries/LibWeb/Fetch/Headers.cpp b/Userland/Libraries/LibWeb/Fetch/Headers.cpp index 0441b5d8d8..7aae86b938 100644 --- a/Userland/Libraries/LibWeb/Fetch/Headers.cpp +++ b/Userland/Libraries/LibWeb/Fetch/Headers.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Linus Groh <linusg@serenityos.org> + * Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org> * * SPDX-License-Identifier: BSD-2-Clause */ @@ -112,6 +112,26 @@ WebIDL::ExceptionOr<DeprecatedString> Headers::get(DeprecatedString const& name_ return byte_buffer.has_value() ? DeprecatedString { byte_buffer->span() } : DeprecatedString {}; } +// https://fetch.spec.whatwg.org/#dom-headers-getsetcookie +WebIDL::ExceptionOr<Vector<DeprecatedString>> Headers::get_set_cookie() +{ + // The getSetCookie() method steps are: + auto& vm = this->vm(); + auto values = Vector<DeprecatedString> {}; + + // 1. If this’s header list does not contain `Set-Cookie`, then return « ». + if (!m_header_list->contains("Set-Cookie"sv.bytes())) + return values; + + // 2. Return the values of all headers in this’s header list whose name is a byte-case-insensitive match for + // `Set-Cookie`, in order. + for (auto const& header : *m_header_list) { + if (StringView { header.name }.equals_ignoring_case("Set-Cookie"sv)) + TRY_OR_THROW_OOM(vm, values.try_append(DeprecatedString { header.value.bytes() })); + } + return values; +} + // https://fetch.spec.whatwg.org/#dom-headers-has WebIDL::ExceptionOr<bool> Headers::has(DeprecatedString const& name_string) { diff --git a/Userland/Libraries/LibWeb/Fetch/Headers.h b/Userland/Libraries/LibWeb/Fetch/Headers.h index 683a4f7327..c366b5fcbf 100644 --- a/Userland/Libraries/LibWeb/Fetch/Headers.h +++ b/Userland/Libraries/LibWeb/Fetch/Headers.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Linus Groh <linusg@serenityos.org> + * Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org> * * SPDX-License-Identifier: BSD-2-Clause */ @@ -50,6 +50,7 @@ public: WebIDL::ExceptionOr<void> append(DeprecatedString const& name, DeprecatedString const& value); WebIDL::ExceptionOr<void> delete_(DeprecatedString const& name); WebIDL::ExceptionOr<DeprecatedString> get(DeprecatedString const& name); + WebIDL::ExceptionOr<Vector<DeprecatedString>> get_set_cookie(); WebIDL::ExceptionOr<bool> has(DeprecatedString const& name); WebIDL::ExceptionOr<void> set(DeprecatedString const& name, DeprecatedString const& value); diff --git a/Userland/Libraries/LibWeb/Fetch/Headers.idl b/Userland/Libraries/LibWeb/Fetch/Headers.idl index f2dbd9e4c0..a495339dd5 100644 --- a/Userland/Libraries/LibWeb/Fetch/Headers.idl +++ b/Userland/Libraries/LibWeb/Fetch/Headers.idl @@ -7,6 +7,7 @@ interface Headers { undefined append(ByteString name, ByteString value); undefined delete(ByteString name); ByteString? get(ByteString name); + sequence<ByteString> getSetCookie(); boolean has(ByteString name); undefined set(ByteString name, ByteString value); iterable<ByteString, ByteString>; diff --git a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.cpp b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.cpp index 2b5addf6fd..abc8d56889 100644 --- a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.cpp +++ b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Linus Groh <linusg@serenityos.org> + * Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org> * Copyright (c) 2022, Kenneth Myhra <kennethmyhra@serenityos.org> * Copyright (c) 2022, Luke Wilde <lukew@serenityos.org> * @@ -257,22 +257,40 @@ ErrorOr<Vector<Header>> HeaderList::sort_and_combine() const // 2. Let names be the result of convert header names to a sorted-lowercase set with all the names of the headers in list. Vector<ReadonlyBytes> names_list; + TRY(names_list.try_ensure_capacity(size())); for (auto const& header : *this) - names_list.append(header.name); + names_list.unchecked_append(header.name); auto names = TRY(convert_header_names_to_a_sorted_lowercase_set(names_list)); // 3. For each name of names: for (auto& name : names) { - // 1. Let value be the result of getting name from list. - // 2. Assert: value is not null. - auto value = TRY(get(name)).value(); - - // 3. Append (name, value) to headers. - auto header = Infrastructure::Header { - .name = move(name), - .value = move(value), - }; - headers.append(move(header)); + // 1. If name is `set-cookie`, then: + if (name == "set-cookie"sv.bytes()) { + // 1. Let values be a list of all values of headers in list whose name is a byte-case-insensitive match for name, in order. + // 2. For each value of values: + for (auto const& [header_name, value] : *this) { + if (StringView { header_name }.equals_ignoring_case(name)) { + // 1. Append (name, value) to headers. + auto header = TRY(Header::from_string_pair(name, value)); + TRY(headers.try_append(move(header))); + } + } + } + // 2. Otherwise: + else { + // 1. Let value be the result of getting name from list. + auto value = TRY(get(name)); + + // 2. Assert: value is not null. + VERIFY(value.has_value()); + + // 3. Append (name, value) to headers. + auto header = Header { + .name = move(name), + .value = value.release_value(), + }; + TRY(headers.try_append(move(header))); + } } // 4. Return headers. |