mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-30 04:39:06 +00:00
LibWeb/XHR: Isomorphic decode accessing XMLHttpRequest response headers
Fixes a crash on: https://wpt.live/html/browsers/browsing-the-web/navigating-across-documents/refresh/subresource.any.html
This commit is contained in:
parent
731c2365b6
commit
e74ca82083
Notes:
github-actions[bot]
2025-01-15 12:36:55 +00:00
Author: https://github.com/shannonbooth
Commit: e74ca82083
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3111
Reviewed-by: https://github.com/AtkinsSJ ✅
4 changed files with 47 additions and 14 deletions
|
@ -972,13 +972,15 @@ void XMLHttpRequest::set_onreadystatechange(WebIDL::CallbackType* value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://xhr.spec.whatwg.org/#dom-xmlhttprequest-getresponseheader
|
// https://xhr.spec.whatwg.org/#dom-xmlhttprequest-getresponseheader
|
||||||
WebIDL::ExceptionOr<Optional<String>> XMLHttpRequest::get_response_header(String const& name) const
|
Optional<String> XMLHttpRequest::get_response_header(String const& name) const
|
||||||
{
|
{
|
||||||
auto& vm = this->vm();
|
|
||||||
|
|
||||||
// The getResponseHeader(name) method steps are to return the result of getting name from this’s response’s header list.
|
// The getResponseHeader(name) method steps are to return the result of getting name from this’s response’s header list.
|
||||||
auto header_bytes = m_response->header_list()->get(name.bytes());
|
auto header_bytes = m_response->header_list()->get(name.bytes());
|
||||||
return header_bytes.has_value() ? TRY_OR_THROW_OOM(vm, String::from_utf8(*header_bytes)) : Optional<String> {};
|
if (!header_bytes.has_value())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
// FIXME: The spec doesn't mention isomorphic decode. Spec bug?
|
||||||
|
return Infra::isomorphic_decode(header_bytes->bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://xhr.spec.whatwg.org/#legacy-uppercased-byte-less-than
|
// https://xhr.spec.whatwg.org/#legacy-uppercased-byte-less-than
|
||||||
|
@ -997,12 +999,10 @@ static ErrorOr<bool> is_legacy_uppercased_byte_less_than(ReadonlyBytes a, Readon
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://xhr.spec.whatwg.org/#dom-xmlhttprequest-getallresponseheaders
|
// https://xhr.spec.whatwg.org/#dom-xmlhttprequest-getallresponseheaders
|
||||||
WebIDL::ExceptionOr<String> XMLHttpRequest::get_all_response_headers() const
|
String XMLHttpRequest::get_all_response_headers() const
|
||||||
{
|
{
|
||||||
auto& vm = this->vm();
|
|
||||||
|
|
||||||
// 1. Let output be an empty byte sequence.
|
// 1. Let output be an empty byte sequence.
|
||||||
ByteBuffer output;
|
StringBuilder output;
|
||||||
|
|
||||||
// 2. Let initialHeaders be the result of running sort and combine with this’s response’s header list.
|
// 2. Let initialHeaders be the result of running sort and combine with this’s response’s header list.
|
||||||
auto initial_headers = m_response->header_list()->sort_and_combine();
|
auto initial_headers = m_response->header_list()->sort_and_combine();
|
||||||
|
@ -1011,8 +1011,7 @@ WebIDL::ExceptionOr<String> XMLHttpRequest::get_all_response_headers() const
|
||||||
// Spec Note: Unfortunately, this is needed for compatibility with deployed content.
|
// Spec Note: Unfortunately, this is needed for compatibility with deployed content.
|
||||||
// NOTE: quick_sort mutates the collection instead of returning a sorted copy.
|
// NOTE: quick_sort mutates the collection instead of returning a sorted copy.
|
||||||
quick_sort(initial_headers, [](Fetch::Infrastructure::Header const& a, Fetch::Infrastructure::Header const& b) {
|
quick_sort(initial_headers, [](Fetch::Infrastructure::Header const& a, Fetch::Infrastructure::Header const& b) {
|
||||||
// FIXME: We are not in a context where we can throw from OOM.
|
return MUST(is_legacy_uppercased_byte_less_than(a.name, b.name));
|
||||||
return is_legacy_uppercased_byte_less_than(a.name, b.name).release_value_but_fixme_should_propagate_errors();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 4. For each header in headers, append header’s name, followed by a 0x3A 0x20 byte pair, followed by header’s value, followed by a 0x0D 0x0A byte pair, to output.
|
// 4. For each header in headers, append header’s name, followed by a 0x3A 0x20 byte pair, followed by header’s value, followed by a 0x0D 0x0A byte pair, to output.
|
||||||
|
@ -1020,13 +1019,14 @@ WebIDL::ExceptionOr<String> XMLHttpRequest::get_all_response_headers() const
|
||||||
output.append(header.name);
|
output.append(header.name);
|
||||||
output.append(0x3A); // ':'
|
output.append(0x3A); // ':'
|
||||||
output.append(0x20); // ' '
|
output.append(0x20); // ' '
|
||||||
output.append(header.value);
|
// FIXME: The spec does not mention isomorphic decode. Spec bug?
|
||||||
|
output.append(Infra::isomorphic_decode(header.value).bytes());
|
||||||
output.append(0x0D); // '\r'
|
output.append(0x0D); // '\r'
|
||||||
output.append(0x0A); // '\n'
|
output.append(0x0A); // '\n'
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Return output.
|
// 5. Return output.
|
||||||
return TRY_OR_THROW_OOM(vm, String::from_utf8(output));
|
return MUST(output.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://xhr.spec.whatwg.org/#dom-xmlhttprequest-overridemimetype
|
// https://xhr.spec.whatwg.org/#dom-xmlhttprequest-overridemimetype
|
||||||
|
|
|
@ -61,8 +61,8 @@ public:
|
||||||
WebIDL::ExceptionOr<void> set_request_header(String const& header, String const& value);
|
WebIDL::ExceptionOr<void> set_request_header(String const& header, String const& value);
|
||||||
WebIDL::ExceptionOr<void> set_response_type(Bindings::XMLHttpRequestResponseType);
|
WebIDL::ExceptionOr<void> set_response_type(Bindings::XMLHttpRequestResponseType);
|
||||||
|
|
||||||
WebIDL::ExceptionOr<Optional<String>> get_response_header(String const& name) const;
|
Optional<String> get_response_header(String const& name) const;
|
||||||
WebIDL::ExceptionOr<String> get_all_response_headers() const;
|
String get_all_response_headers() const;
|
||||||
|
|
||||||
WebIDL::CallbackType* onreadystatechange();
|
WebIDL::CallbackType* onreadystatechange();
|
||||||
void set_onreadystatechange(WebIDL::CallbackType*);
|
void set_onreadystatechange(WebIDL::CallbackType*);
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
getAllResponseHeaders()
|
||||||
|
refresh: 0;./refreshed.txt?ÿ
|
||||||
|
|
||||||
|
getResponseHeader("Refresh") => '0;./refreshed.txt?ÿ'
|
|
@ -0,0 +1,29 @@
|
||||||
|
<script src="../include.js"></script>
|
||||||
|
<script>
|
||||||
|
asyncTest(async (done) => {
|
||||||
|
try {
|
||||||
|
const httpServer = httpTestServer();
|
||||||
|
const url = await httpServer.createEcho("GET", "/xml-http-request-response-header-decoding", {
|
||||||
|
status: 200,
|
||||||
|
headers: {
|
||||||
|
"Access-Control-Allow-Origin": "*",
|
||||||
|
"Access-Control-Expose-Headers": "Refresh",
|
||||||
|
"Refresh": "0;./refreshed.txt?\u0080\u00FF",
|
||||||
|
},
|
||||||
|
body: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
xhr.open("GET", url);
|
||||||
|
|
||||||
|
xhr.addEventListener("load", () => {
|
||||||
|
println(`getAllResponseHeaders()\n${xhr.getAllResponseHeaders().replace('\r','')}`);
|
||||||
|
println(`getResponseHeader("Refresh") => '${xhr.getResponseHeader("Refresh")}'`);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
xhr.send();
|
||||||
|
} catch (err) {
|
||||||
|
console.log("FAIL - " + err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
Loading…
Add table
Add a link
Reference in a new issue