LibWeb: Don't keep HTMLMediaElement alive in its fetch callbacks

This isn't strictly necessary to allow the element to be collected, but
it doesn't make sense for a fetch to keep the media element alive.
This commit is contained in:
Zaggy1024 2026-02-11 17:48:39 -06:00 committed by Gregory Bertilson
parent a3619cd995
commit d146adfd66
Notes: github-actions[bot] 2026-02-18 19:15:44 +00:00

View file

@ -1084,13 +1084,16 @@ void HTMLMediaElement::fetch_resource(NonnullRefPtr<FetchData> const& fetch_data
// 8. Fetch request, with processResponse set to the following steps given response response:
Fetch::Infrastructure::FetchAlgorithms::Input fetch_algorithms_input {};
fetch_algorithms_input.process_response = [this, byte_range = move(byte_range), fetch_data, fetch_generation](auto response) mutable {
fetch_algorithms_input.process_response = [weak_self = GC::Weak(*this), byte_range = move(byte_range), fetch_data, fetch_generation](auto response) mutable {
if (!weak_self)
return;
// 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();
// 1. Let global be the media element's node document's relevant global object.
auto& global = document().realm().global_object();
auto& global = weak_self->document().realm().global_object();
if (auto content_length = response->header_list()->extract_length(); content_length.template has<u64>()) {
auto actual_length = fetch_data->offset + content_length.template get<u64>();
@ -1102,7 +1105,7 @@ void HTMLMediaElement::fetch_resource(NonnullRefPtr<FetchData> const& fetch_data
// 4. If the result of verifying response given the current media resource and byteRange is false, then abort these steps.
// NOTE: We do this step before creating the updateMedia task so that we can invoke the failure callback.
auto maybe_verify_response_failure = verify_response_or_get_failure_reason(response, byte_range, fetch_data);
auto maybe_verify_response_failure = weak_self->verify_response_or_get_failure_reason(response, byte_range, fetch_data);
if (maybe_verify_response_failure.has_value()) {
fetch_data->failure_callback(maybe_verify_response_failure.value());
return;
@ -1111,8 +1114,10 @@ void HTMLMediaElement::fetch_resource(NonnullRefPtr<FetchData> const& fetch_data
// 2. Let updateMedia be to queue a media element task given the media element to run the first appropriate steps from the media data processing
// steps list below. (A new task is used for this so that the work described below occurs relative to the appropriate media element event task
// source rather than using the networking task source.)
auto update_media = GC::create_function(heap(), [this, fetch_data, fetch_generation](ByteBuffer media_data) mutable {
if (fetch_generation != m_current_fetch_generation)
auto update_media = GC::create_function(weak_self->heap(), [weak_self, fetch_data, fetch_generation](ByteBuffer media_data) mutable {
if (!weak_self)
return;
if (fetch_generation != weak_self->m_current_fetch_generation)
return;
// 6. Update the media data with the contents of response's unsafe response obtained in this fashion. response can be CORS-same-origin or
@ -1121,8 +1126,8 @@ void HTMLMediaElement::fetch_resource(NonnullRefPtr<FetchData> const& fetch_data
fetch_data->stream->add_chunk_at(fetch_data->offset, media_data.bytes());
fetch_data->offset += media_data.size();
queue_a_media_element_task([this] {
process_media_data(FetchingStatus::Ongoing).release_value_but_fixme_should_propagate_errors();
weak_self->queue_a_media_element_task([&self = *weak_self] {
self.process_media_data(FetchingStatus::Ongoing).release_value_but_fixme_should_propagate_errors();
});
});
@ -1130,18 +1135,20 @@ void HTMLMediaElement::fetch_resource(NonnullRefPtr<FetchData> const& fetch_data
// and if all of the data is available to the user agent without network access, then, the user agent must move on to the final step below.
// This might never happen, e.g. when streaming an infinite resource such as web radio, or if the resource is longer than the user agent's
// ability to cache data.
auto process_end_of_media = GC::create_function(heap(), [this, fetch_data, fetch_generation] {
if (fetch_generation != m_current_fetch_generation)
auto process_end_of_media = GC::create_function(weak_self->heap(), [weak_self, fetch_data, fetch_generation] {
if (!weak_self)
return;
if (fetch_generation != weak_self->m_current_fetch_generation)
return;
fetch_data->stream->reached_end_of_body();
queue_a_media_element_task([this] {
process_media_data(FetchingStatus::Complete).release_value_but_fixme_should_propagate_errors();
weak_self->queue_a_media_element_task([&self = *weak_self] {
self.process_media_data(FetchingStatus::Complete).release_value_but_fixme_should_propagate_errors();
});
});
VERIFY(response->body());
auto empty_algorithm = GC::create_function(heap(), [](JS::Value) { });
auto empty_algorithm = GC::create_function(weak_self->heap(), [](JS::Value) { });
// 5. Otherwise, incrementally read response's body given updateMedia, processEndOfMedia, an empty algorithm, and global.
response->body()->incrementally_read(update_media, process_end_of_media, empty_algorithm, GC::Ref { global });