LibWeb: Avoid stale delayed resource callbacks
Delayed preload and image animation callbacks can outlive the objects they notify. Incremental sweeping makes this easier to hit because stale callback state may be reclaimed before the delayed work runs. Use a weak link element when firing preload load and error events, and use a weak image style value from animated image timers instead of a raw pointer.
This commit is contained in:
parent
37117b1cb4
commit
5cf90c0d0d
3 changed files with 19 additions and 11 deletions
|
|
@ -80,7 +80,11 @@ void ImageStyleValue::load_any_resources(DOM::Document& document)
|
|||
if (image_data->is_animated() && image_data->frame_count() > 1) {
|
||||
self.m_timer = Platform::Timer::create(self.m_document->heap());
|
||||
self.m_timer->set_interval(image_data->frame_duration(0));
|
||||
self.m_timer->on_timeout = GC::create_function(self.m_document->heap(), [ptr = &self] { ptr->animate(); });
|
||||
auto weak_self = self.template make_weak_ptr<ImageStyleValue>();
|
||||
self.m_timer->on_timeout = GC::create_function(self.m_document->heap(), [weak_self] {
|
||||
if (weak_self)
|
||||
weak_self->animate();
|
||||
});
|
||||
self.m_timer->start();
|
||||
}
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -519,13 +519,16 @@ void HTMLLinkElement::fetch_and_process_linked_preload_resource()
|
|||
options->destination = destination.get<Optional<Fetch::Infrastructure::Request::Destination>>();
|
||||
|
||||
// 6. Preload options, with the following steps given a response response:
|
||||
preload(options, GC::Function<void(Fetch::Infrastructure::Response&)>::create(heap(), [this](Fetch::Infrastructure::Response& response) {
|
||||
GC::Weak weak_this { *this };
|
||||
preload(options, [weak_this](Fetch::Infrastructure::Response& response) {
|
||||
// 1. If response is a network error, fire an event named error at el. Otherwise, fire an event named load at el.
|
||||
if (response.is_network_error())
|
||||
dispatch_event(DOM::Event::create(realm(), HTML::EventNames::error));
|
||||
else
|
||||
dispatch_event(DOM::Event::create(realm(), HTML::EventNames::load));
|
||||
}));
|
||||
if (auto link_element = weak_this.ptr()) {
|
||||
if (response.is_network_error())
|
||||
link_element->dispatch_event(DOM::Event::create(link_element->realm(), HTML::EventNames::error));
|
||||
else
|
||||
link_element->dispatch_event(DOM::Event::create(link_element->realm(), HTML::EventNames::load));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/semantics.html#linked-resource-fetch-setup-steps
|
||||
|
|
@ -662,7 +665,7 @@ static bool type_matches_destination(StringView type, Optional<Fetch::Infrastruc
|
|||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/links.html#preload
|
||||
void HTMLLinkElement::preload(LinkProcessingOptions& options, GC::Ptr<GC::Function<void(Fetch::Infrastructure::Response&)>> process_response)
|
||||
void HTMLLinkElement::preload(LinkProcessingOptions& options, Function<void(Fetch::Infrastructure::Response&)> process_response)
|
||||
{
|
||||
auto& realm = this->realm();
|
||||
auto& vm = realm.vm();
|
||||
|
|
@ -707,7 +710,7 @@ void HTMLLinkElement::preload(LinkProcessingOptions& options, GC::Ptr<GC::Functi
|
|||
// 11. Set controller to the result of fetching request, with processResponseConsumeBody set to the following steps
|
||||
// given a response response and null, failure, or a byte sequence bodyBytes:
|
||||
Fetch::Infrastructure::FetchAlgorithms::Input fetch_algorithms_input {};
|
||||
fetch_algorithms_input.process_response_consume_body = [&realm, options = GC::Ref { options }, process_response, entry, report_timing](GC::Ref<Fetch::Infrastructure::Response> response, Fetch::Infrastructure::FetchAlgorithms::BodyBytes body_bytes) {
|
||||
fetch_algorithms_input.process_response_consume_body = [&realm, options = GC::Ref { options }, process_response = move(process_response), entry, report_timing](GC::Ref<Fetch::Infrastructure::Response> response, Fetch::Infrastructure::FetchAlgorithms::BodyBytes 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();
|
||||
|
|
@ -734,7 +737,7 @@ void HTMLLinkElement::preload(LinkProcessingOptions& options, GC::Ptr<GC::Functi
|
|||
|
||||
// 6. If processResponse is given, then call processResponse with response.
|
||||
if (process_response)
|
||||
process_response->function()(response);
|
||||
process_response(response);
|
||||
};
|
||||
|
||||
m_fetch_controller = Fetch::Fetching::fetch(realm, *request, Fetch::Infrastructure::FetchAlgorithms::create(vm, move(fetch_algorithms_input)));
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Function.h>
|
||||
#include <LibWeb/DOM/DocumentLoadEventDelayer.h>
|
||||
#include <LibWeb/Fetch/Infrastructure/FetchAlgorithms.h>
|
||||
#include <LibWeb/Fetch/Infrastructure/HTTP/Requests.h>
|
||||
|
|
@ -161,7 +162,7 @@ private:
|
|||
bool stylesheet_linked_resource_fetch_setup_steps(Fetch::Infrastructure::Request&);
|
||||
|
||||
void preconnect(LinkProcessingOptions const&);
|
||||
void preload(LinkProcessingOptions&, GC::Ptr<GC::Function<void(Fetch::Infrastructure::Response&)>> process_response = {});
|
||||
void preload(LinkProcessingOptions&, Function<void(Fetch::Infrastructure::Response&)> process_response = {});
|
||||
|
||||
void process_linked_resource(bool success, Fetch::Infrastructure::Response const&, ByteBuffer);
|
||||
void process_icon_resource(bool success, Fetch::Infrastructure::Response const&, ByteBuffer);
|
||||
|
|
|
|||
Loading…
Reference in a new issue