LibWeb: Avoid re-encoding response headers

isomorphic encoding a value that has already been encoded will
result in garbage data. `response_headers` is already encoded in
ISO-8859-1/latin1, we cannot use `from_string_pair`, as it triggers
ISO-8859-1/latin1 encoding.

Follow-up of https://github.com/LadybirdBrowser/ladybird/pull/1893
This commit is contained in:
Feng Yu 2024-12-12 10:26:41 -08:00 committed by Jelle Raaijmakers
commit e0c0668f3d
Notes: github-actions[bot] 2024-12-17 12:45:04 +00:00
6 changed files with 22 additions and 7 deletions

View file

@ -2330,7 +2330,7 @@ WebIDL::ExceptionOr<GC::Ref<PendingResponse>> nonstandard_resource_loader_file_o
} }
for (auto const& [name, value] : response_headers.headers()) { for (auto const& [name, value] : response_headers.headers()) {
auto header = Infrastructure::Header::from_string_pair(name, value); auto header = Infrastructure::Header::from_latin1_pair(name, value);
response->header_list()->append(move(header)); response->header_list()->append(move(header));
} }
@ -2396,7 +2396,7 @@ WebIDL::ExceptionOr<GC::Ref<PendingResponse>> nonstandard_resource_loader_file_o
response->set_status(status_code.value_or(200)); response->set_status(status_code.value_or(200));
response->set_body(move(body)); response->set_body(move(body));
for (auto const& [name, value] : response_headers.headers()) { for (auto const& [name, value] : response_headers.headers()) {
auto header = Infrastructure::Header::from_string_pair(name, value); auto header = Infrastructure::Header::from_latin1_pair(name, value);
response->header_list()->append(move(header)); response->header_list()->append(move(header));
} }
@ -2421,7 +2421,7 @@ WebIDL::ExceptionOr<GC::Ref<PendingResponse>> nonstandard_resource_loader_file_o
auto [body, _] = TRY_OR_IGNORE(extract_body(realm, data)); auto [body, _] = TRY_OR_IGNORE(extract_body(realm, data));
response->set_body(move(body)); response->set_body(move(body));
for (auto const& [name, value] : response_headers.headers()) { for (auto const& [name, value] : response_headers.headers()) {
auto header = Infrastructure::Header::from_string_pair(name, value); auto header = Infrastructure::Header::from_latin1_pair(name, value);
response->header_list()->append(move(header)); response->header_list()->append(move(header));
} }

View file

@ -58,6 +58,14 @@ Header Header::from_string_pair(StringView name, StringView value)
}; };
} }
Header Header::from_latin1_pair(StringView name, StringView value)
{
return Header {
.name = MUST(ByteBuffer::copy(name.bytes())),
.value = MUST(ByteBuffer::copy(value.bytes())),
};
}
GC::Ref<HeaderList> HeaderList::create(JS::VM& vm) GC::Ref<HeaderList> HeaderList::create(JS::VM& vm)
{ {
return vm.heap().allocate<HeaderList>(); return vm.heap().allocate<HeaderList>();

View file

@ -29,6 +29,7 @@ struct Header {
[[nodiscard]] static Header copy(Header const&); [[nodiscard]] static Header copy(Header const&);
[[nodiscard]] static Header from_string_pair(StringView, StringView); [[nodiscard]] static Header from_string_pair(StringView, StringView);
[[nodiscard]] static Header from_latin1_pair(StringView, StringView);
}; };
// https://fetch.spec.whatwg.org/#concept-header-list // https://fetch.spec.whatwg.org/#concept-header-list

View file

@ -147,11 +147,12 @@ ErrorOr<String> to_ascii_uppercase(StringView string)
// https://infra.spec.whatwg.org/#isomorphic-encode // https://infra.spec.whatwg.org/#isomorphic-encode
ByteBuffer isomorphic_encode(StringView input) ByteBuffer isomorphic_encode(StringView input)
{ {
// To isomorphic encode an isomorphic string input: return a byte sequence whose length is equal to inputs code
// point length and whose bytes have the same values as the values of inputs code points, in the same order.
// NOTE: This is essentially spec-speak for "Encode as ISO-8859-1 / Latin-1".
ByteBuffer buf = {}; ByteBuffer buf = {};
for (auto code_point : Utf8View { input }) { for (auto code_point : Utf8View { input }) {
// VERIFY(code_point <= 0xFF); VERIFY(code_point <= 0xFF);
if (code_point > 0xFF)
dbgln("FIXME: Trying to isomorphic encode a string with code points > U+00FF.");
buf.append((u8)code_point); buf.append((u8)code_point);
} }
return buf; return buf;
@ -160,6 +161,9 @@ ByteBuffer isomorphic_encode(StringView input)
// https://infra.spec.whatwg.org/#isomorphic-decode // https://infra.spec.whatwg.org/#isomorphic-decode
String isomorphic_decode(ReadonlyBytes input) String isomorphic_decode(ReadonlyBytes input)
{ {
// To isomorphic decode a byte sequence input, return a string whose code point length is equal
// to inputs length and whose code points have the same values as the values of inputs bytes, in the same order.
// NOTE: This is essentially spec-speak for "Decode as ISO-8859-1 / Latin-1".
StringBuilder builder(input.size()); StringBuilder builder(input.size());
for (u8 code_point : input) { for (u8 code_point : input) {
builder.append_code_point(code_point); builder.append_code_point(code_point);

View file

@ -1 +1,2 @@
Content-Type:text/html;test=ÿ;charset=gbk
PASS (didn't crash) PASS (didn't crash)

View file

@ -12,7 +12,8 @@
}, },
}); });
const blob = await fetch(url).then((response) => response.blob()); const headers = await fetch(url).then((response) => response.headers);
println("Content-Type:" + headers.get("Content-Type"));
println("PASS (didn't crash)"); println("PASS (didn't crash)");
} catch (err) { } catch (err) {
println("FAIL - " + err); println("FAIL - " + err);