From dc24a87479c033940f4111012e733d21b466a023 Mon Sep 17 00:00:00 2001 From: Feng Yu Date: Fri, 6 Dec 2024 09:35:02 -0800 Subject: [PATCH] LibWeb: Ensure Headers API can handle non-ascii characters This patch ensure Headers object's associated header list is ISO-8859-1 encoded when set using `Infra::isomorphic_encode`, and correctly decoded using `Infra::isomorphic_decode`. Follow-up of https://github.com/LadybirdBrowser/ladybird/pull/1893 --- Libraries/LibWeb/Fetch/Headers.cpp | 17 ++--- Libraries/LibWeb/Fetch/HeadersIterator.cpp | 5 +- .../Fetch/fetch-headers-non-ascii.txt | 34 ++++++++++ .../input/Fetch/fetch-headers-non-ascii.html | 66 +++++++++++++++++++ 4 files changed, 109 insertions(+), 13 deletions(-) create mode 100644 Tests/LibWeb/Text/expected/Fetch/fetch-headers-non-ascii.txt create mode 100644 Tests/LibWeb/Text/input/Fetch/fetch-headers-non-ascii.html diff --git a/Libraries/LibWeb/Fetch/Headers.cpp b/Libraries/LibWeb/Fetch/Headers.cpp index 1d4dbf31a7ecf..b60503d7c270b 100644 --- a/Libraries/LibWeb/Fetch/Headers.cpp +++ b/Libraries/LibWeb/Fetch/Headers.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace Web::Fetch { @@ -56,10 +57,7 @@ void Headers::visit_edges(JS::Cell::Visitor& visitor) WebIDL::ExceptionOr Headers::append(String const& name_string, String const& value_string) { // The append(name, value) method steps are to append (name, value) to this. - auto header = Infrastructure::Header { - .name = MUST(ByteBuffer::copy(name_string.bytes())), - .value = MUST(ByteBuffer::copy(value_string.bytes())), - }; + auto header = Infrastructure::Header::from_string_pair(name_string, value_string); TRY(append(move(header))); return {}; } @@ -106,7 +104,7 @@ WebIDL::ExceptionOr> Headers::get(String const& name_string) // 2. Return the result of getting name from this’s header list. auto byte_buffer = m_header_list->get(name); - return byte_buffer.has_value() ? MUST(String::from_utf8(*byte_buffer)) : Optional {}; + return byte_buffer.has_value() ? Infra::isomorphic_decode(*byte_buffer) : Optional {}; } // https://fetch.spec.whatwg.org/#dom-headers-getsetcookie @@ -123,7 +121,7 @@ Vector Headers::get_set_cookie() // `Set-Cookie`, in order. for (auto const& header : *m_header_list) { if (StringView { header.name }.equals_ignoring_ascii_case("Set-Cookie"sv)) - values.append(MUST(String::from_utf8(header.value))); + values.append(Infra::isomorphic_decode(header.value)); } return values; } @@ -152,10 +150,7 @@ WebIDL::ExceptionOr Headers::set(String const& name_string, String const& // 1. Normalize value. auto normalized_value = Infrastructure::normalize_header_value(value); - auto header = Infrastructure::Header { - .name = MUST(ByteBuffer::copy(name)), - .value = move(normalized_value), - }; + auto header = Infrastructure::Header::from_string_pair(name, normalized_value); // 2. If validating (name, value) for headers returns false, then return. if (!TRY(validate(header))) @@ -197,7 +192,7 @@ JS::ThrowCompletionOr Headers::for_each(ForEachCallback callback) auto const& pair = pairs[i]; // 2. Invoke idlCallback with « pair’s value, pair’s key, idlObject » and with thisArg as the callback this value. - TRY(callback(MUST(String::from_utf8(pair.name)), MUST(String::from_utf8(pair.value)))); + TRY(callback(Infra::isomorphic_decode(pair.name), Infra::isomorphic_decode(pair.value))); // 3. Set pairs to idlObject’s current list of value pairs to iterate over. (It might have changed.) pairs = value_pairs_to_iterate_over(); diff --git a/Libraries/LibWeb/Fetch/HeadersIterator.cpp b/Libraries/LibWeb/Fetch/HeadersIterator.cpp index 3b25fa055b943..8279fa27cdd04 100644 --- a/Libraries/LibWeb/Fetch/HeadersIterator.cpp +++ b/Libraries/LibWeb/Fetch/HeadersIterator.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace Web::Bindings { @@ -65,8 +66,8 @@ GC::Ref HeadersIterator::next() return create_iterator_result_object(vm(), JS::js_undefined(), true); auto const& pair = pairs[m_index++]; - StringView pair_name { pair.name }; - StringView pair_value { pair.value }; + auto pair_name = Infra::isomorphic_decode(pair.name); + auto pair_value = Infra::isomorphic_decode(pair.value); switch (m_iteration_kind) { case JS::Object::PropertyKind::Key: diff --git a/Tests/LibWeb/Text/expected/Fetch/fetch-headers-non-ascii.txt b/Tests/LibWeb/Text/expected/Fetch/fetch-headers-non-ascii.txt new file mode 100644 index 0000000000000..36d42bde131d5 --- /dev/null +++ b/Tests/LibWeb/Text/expected/Fetch/fetch-headers-non-ascii.txt @@ -0,0 +1,34 @@ +-------------------------------- +Headers constructor +-------------------------------- +Accept: before-æøå-after +X-Test: before-ß-after + +-------------------------------- +Headers.append() +-------------------------------- +Accept: before-æøå-after +X-Test: before-ß-after + +-------------------------------- +Headers.set() +-------------------------------- +Accept: before-æøå-after +X-Test: before-ß-after + +-------------------------------- +Headers.getSetCookie() +-------------------------------- +Set-Cookie: before-æøå-after + +-------------------------------- +Headers iterator +-------------------------------- +accept: before-æøå-after +x-test: before-ß-after + +-------------------------------- +Headers.forEach() +-------------------------------- +accept: before-æøå-after +x-test: before-ß-after diff --git a/Tests/LibWeb/Text/input/Fetch/fetch-headers-non-ascii.html b/Tests/LibWeb/Text/input/Fetch/fetch-headers-non-ascii.html new file mode 100644 index 0000000000000..d2f066fcd820c --- /dev/null +++ b/Tests/LibWeb/Text/input/Fetch/fetch-headers-non-ascii.html @@ -0,0 +1,66 @@ + + +