1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 12:38:12 +00:00

LibWeb: Update workarounds for fetching CORS cross-origin responses

Now that the processResponseConsumeBody algorithm receives the internal
response body of the fetched object, we do not need to go out of our way
to read its body from outside of fetch.

However, several elements do still need to manually inspect the internal
response for other data, such as response headers and status. Note that
HTMLScriptElement already does the new workaround as a proper spec step.
This commit is contained in:
Timothy Flynn 2023-05-26 09:51:53 -04:00 committed by Andreas Kling
parent 6406a561ef
commit 8ff8309202
4 changed files with 65 additions and 164 deletions

View file

@ -279,72 +279,30 @@ void HTMLLinkElement::default_fetch_and_process_linked_resource()
}
// 7. Fetch request with processResponseConsumeBody set to the following steps given response response and null, failure, or a byte sequence bodyBytes:
Fetch::Fetching::fetch(
realm(), *request,
Fetch::Infrastructure::FetchAlgorithms::create(vm(),
{ .process_request_body_chunk_length = {},
.process_request_end_of_body = {},
.process_early_hints_response = {},
.process_response = {},
.process_response_end_of_body = {},
.process_response_consume_body = [this, hr = options](auto response, auto body_bytes) {
// 1. Let success be true.
bool success = true;
Fetch::Infrastructure::FetchAlgorithms::Input fetch_algorithms_input {};
fetch_algorithms_input.process_response_consume_body = [this, hr = options](auto response, auto body_bytes) {
// FIXME: If the response is CORS cross-origin, we must use its internal response to query any of its data. See:
// https://github.com/whatwg/html/issues/9355
response = response->unsafe_response();
// 2. If either of the following conditions are met:
// - bodyBytes is null or failure; or
// - response's status is not an ok status,
// then set success to false.
// NOTE: content-specific errors, e.g., CSS parse errors or PNG decoding errors, do not affect success.
if (body_bytes.template has<Empty>()) {
// CORS cross-origin responses in the No CORS request mode provide an opaque filtered response, which is the original response
// with certain attributes removed/changed.
// 1. Let success be true.
bool success = true;
// The relevant effect it has is setting the body to `null`, which means `body_bytes` has `Empty` here. This effectively
// disables cross-origin linked resources (e.g. stylesheets).
// 2. If either of the following conditions are met:
// - bodyBytes is null or failure; or
// - response's status is not an ok status,
if (body_bytes.template has<Empty>() || body_bytes.template has<Fetch::Infrastructure::FetchAlgorithms::ConsumeBodyFailureTag>() || !Fetch::Infrastructure::is_ok_status(response->status())) {
// then set success to false.
success = false;
}
// However, the web actually depends on this, especially for stylesheets retrieved from a cross-origin CDN. For example,
// Shopify websites request stylesheets from `cdn.shopify.com` and Substack websites request stylesheets from `substackcdn.com`.
// FIXME: 3. Otherwise, wait for the link resource's critical subresources to finish loading.
// This makes this a specification bug, as this code was written from it.
// 4. Process the linked resource given el, success, response, and bodyBytes.
process_linked_resource(success, response, body_bytes);
};
// The workaround is to read the actual body from the unfiltered response and then call `process_linked_resource` from there.
// This _should_ be safe to do, as linked resource fetches do not include credentials (i.e. cookies and the Authorization
// header), so it cannot provide personalized responses.
// FIXME: Replace this workaround with a proper fix that has landed in the specification.
// See: https://github.com/whatwg/html/issues/9066
if (is<Fetch::Infrastructure::OpaqueFilteredResponse>(response.ptr())) {
auto unsafe_response = static_cast<Fetch::Infrastructure::OpaqueFilteredResponse const&>(*response).internal_response();
if (unsafe_response->body().has_value()) {
// NOTE: `this` and `unsafe_response` are protected by `fully_read` using JS::SafeFunction.
auto process_body = [this, unsafe_response](ByteBuffer bytes) {
process_linked_resource(true, unsafe_response, bytes);
};
// NOTE: `this` and `unsafe_response` are protected by `fully_read` using JS::SafeFunction.
auto process_body_error = [this, unsafe_response](auto) {
process_linked_resource(false, unsafe_response, Fetch::Infrastructure::FetchAlgorithms::ConsumeBodyFailureTag {});
};
unsafe_response->body()->fully_read(realm(), move(process_body), move(process_body_error), JS::NonnullGCPtr { realm().global_object() }).release_value_but_fixme_should_propagate_errors();
return;
} else {
success = false;
}
} else {
success = false;
}
} else if (body_bytes.template has<Fetch::Infrastructure::FetchAlgorithms::ConsumeBodyFailureTag>() || !Fetch::Infrastructure::is_ok_status(response->status())) {
success = false;
}
// FIXME: 3. Otherwise, wait for the link resource's critical subresources to finish loading.
// 4. Process the linked resource given el, success, response, and bodyBytes.
process_linked_resource(success, response, body_bytes);
} }))
.release_value_but_fixme_should_propagate_errors();
Fetch::Fetching::fetch(realm(), *request, Fetch::Infrastructure::FetchAlgorithms::create(vm(), move(fetch_algorithms_input))).release_value_but_fixme_should_propagate_errors();
}
// https://html.spec.whatwg.org/multipage/links.html#link-type-stylesheet:process-the-linked-resource