mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-26 01:35:08 +02:00
LibWeb: Fix stale image request callbacks corrupting newer requests
When img.src is changed rapidly (e.g., YouTube Music sets a GIF placeholder then swaps to a real URL via IntersectionObserver), the failure callback from the stale first request could corrupt the newer request by calling abort_the_image_request on the now-reassigned m_current_request. Fix this by using the existing m_update_the_image_data_count generation counter to detect stale fetch callbacks. This fixes thumbnail loading on YouTube Music.
This commit is contained in:
committed by
Alexander Kalenik
parent
a7b70b0042
commit
b49c243abd
Notes:
github-actions[bot]
2026-03-03 13:13:51 +00:00
Author: https://github.com/kalenikaliaksandr Commit: https://github.com/LadybirdBrowser/ladybird/commit/b49c243abd8 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/8237 Reviewed-by: https://github.com/gmta
@@ -838,7 +838,7 @@ after_step_7:
|
||||
if (delay_load_event)
|
||||
m_load_event_delayer.emplace(document());
|
||||
|
||||
add_callbacks_to_image_request(*image_request, maybe_omit_events, *url_string, previous_url);
|
||||
add_callbacks_to_image_request(*image_request, maybe_omit_events, *url_string, previous_url, update_the_image_data_count);
|
||||
|
||||
// AD-HOC: If the image request is already available or fetching, no need to start another fetch.
|
||||
if (image_request->is_available() || image_request->is_fetching())
|
||||
@@ -883,11 +883,11 @@ after_step_7:
|
||||
}));
|
||||
}
|
||||
|
||||
void HTMLImageElement::add_callbacks_to_image_request(GC::Ref<ImageRequest> image_request, bool maybe_omit_events, String const& url_string, String const& previous_url)
|
||||
void HTMLImageElement::add_callbacks_to_image_request(GC::Ref<ImageRequest> image_request, bool maybe_omit_events, String const& url_string, String const& previous_url, u64 update_the_image_data_count)
|
||||
{
|
||||
image_request->add_callbacks(
|
||||
[this, image_request, maybe_omit_events, url_string, previous_url]() {
|
||||
batching_dispatcher().enqueue(GC::create_function(realm().heap(), [this, image_request, maybe_omit_events, url_string, previous_url] {
|
||||
[this, image_request, maybe_omit_events, url_string, previous_url, update_the_image_data_count]() {
|
||||
batching_dispatcher().enqueue(GC::create_function(realm().heap(), [this, image_request, maybe_omit_events, url_string, previous_url, update_the_image_data_count] {
|
||||
// AD-HOC: Bail out if the document became inactive (e.g. iframe removed or navigated)
|
||||
// between when the fetch completed and when this batched callback runs.
|
||||
if (!document().is_fully_active()) {
|
||||
@@ -895,6 +895,13 @@ void HTMLImageElement::add_callbacks_to_image_request(GC::Ref<ImageRequest> imag
|
||||
return;
|
||||
}
|
||||
|
||||
// AD-HOC: If another instance of update_the_image_data was started after the one that initiated this
|
||||
// request, this callback is stale. Bail out to avoid corrupting the state of the newer request.
|
||||
if (update_the_image_data_count != m_update_the_image_data_count) {
|
||||
m_load_event_delayer.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
VERIFY(image_request->shared_resource_request());
|
||||
auto image_data = image_request->shared_resource_request()->image_data();
|
||||
image_request->set_image_data(image_data);
|
||||
@@ -936,7 +943,7 @@ void HTMLImageElement::add_callbacks_to_image_request(GC::Ref<ImageRequest> imag
|
||||
m_load_event_delayer.clear();
|
||||
}));
|
||||
},
|
||||
[this, image_request, maybe_omit_events, url_string, previous_url]() {
|
||||
[this, image_request, maybe_omit_events, url_string, previous_url, update_the_image_data_count]() {
|
||||
// AD-HOC: Bail out if the document became inactive (e.g. iframe removed or navigated)
|
||||
// between when the fetch completed and when this failure callback runs.
|
||||
if (!document().is_fully_active()) {
|
||||
@@ -946,6 +953,13 @@ void HTMLImageElement::add_callbacks_to_image_request(GC::Ref<ImageRequest> imag
|
||||
|
||||
// The image data is not in a supported file format;
|
||||
|
||||
// AD-HOC: If another instance of update_the_image_data was started after the one that initiated this
|
||||
// request, this callback is stale. Bail out to avoid corrupting the state of the newer request.
|
||||
if (update_the_image_data_count != m_update_the_image_data_count) {
|
||||
m_load_event_delayer.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// the user agent must set image request's state to broken,
|
||||
image_request->set_state(ImageRequest::State::Broken);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user