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

LibWeb: Invent a method to stop an in-progress fetch without errors

The HTMLMediaElement will need to stop fetching processes when its load
algorithm is invoked while a fetch is ongoing. We don't have a way to
really stop the process, due to the way it runs on nested deferred task
invocations. So for now, this swaps the fetch callbacks (e.g. to process
a fetch response) with empty callbacks.
This commit is contained in:
Timothy Flynn 2023-04-19 09:15:16 -04:00 committed by Andreas Kling
parent 1fb0c7826b
commit 8d4d01d99a
3 changed files with 26 additions and 0 deletions

View file

@ -6,7 +6,9 @@
#include <LibJS/Heap/Heap.h> #include <LibJS/Heap/Heap.h>
#include <LibJS/Runtime/VM.h> #include <LibJS/Runtime/VM.h>
#include <LibWeb/Fetch/Infrastructure/FetchAlgorithms.h>
#include <LibWeb/Fetch/Infrastructure/FetchController.h> #include <LibWeb/Fetch/Infrastructure/FetchController.h>
#include <LibWeb/Fetch/Infrastructure/FetchParams.h>
#include <LibWeb/WebIDL/DOMException.h> #include <LibWeb/WebIDL/DOMException.h>
namespace Web::Fetch::Infrastructure { namespace Web::Fetch::Infrastructure {
@ -22,6 +24,7 @@ void FetchController::visit_edges(JS::Cell::Visitor& visitor)
{ {
Base::visit_edges(visitor); Base::visit_edges(visitor);
visitor.visit(m_full_timing_info); visitor.visit(m_full_timing_info);
visitor.visit(m_fetch_params);
} }
// https://fetch.spec.whatwg.org/#finalize-and-report-timing // https://fetch.spec.whatwg.org/#finalize-and-report-timing
@ -81,4 +84,18 @@ void FetchController::terminate()
m_state = State::Terminated; m_state = State::Terminated;
} }
void FetchController::stop_fetch()
{
auto& vm = this->vm();
// AD-HOC: Some HTML elements need to stop an ongoing fetching process without causing any network error to be raised
// (which abort() and terminate() will both do). This is tricky because the fetch process runs across several
// nested Platform::EventLoopPlugin::deferred_invoke() invocations. For now, we "stop" the fetch process by
// ignoring any callbacks.
if (m_fetch_params) {
auto fetch_algorithms = FetchAlgorithms::create(vm, {});
m_fetch_params->set_algorithms(fetch_algorithms);
}
}
} }

View file

@ -6,11 +6,13 @@
#pragma once #pragma once
#include <AK/Badge.h>
#include <LibJS/Forward.h> #include <LibJS/Forward.h>
#include <LibJS/Heap/Cell.h> #include <LibJS/Heap/Cell.h>
#include <LibJS/Heap/GCPtr.h> #include <LibJS/Heap/GCPtr.h>
#include <LibJS/SafeFunction.h> #include <LibJS/SafeFunction.h>
#include <LibWeb/Fetch/Infrastructure/FetchTimingInfo.h> #include <LibWeb/Fetch/Infrastructure/FetchTimingInfo.h>
#include <LibWeb/Forward.h>
namespace Web::Fetch::Infrastructure { namespace Web::Fetch::Infrastructure {
@ -39,6 +41,10 @@ public:
void abort(JS::Realm&, Optional<JS::Value>); void abort(JS::Realm&, Optional<JS::Value>);
void terminate(); void terminate();
void set_fetch_params(Badge<FetchParams>, JS::NonnullGCPtr<FetchParams> fetch_params) { m_fetch_params = fetch_params; }
void stop_fetch();
private: private:
FetchController(); FetchController();
@ -67,6 +73,8 @@ private:
// next manual redirect steps (default null) // next manual redirect steps (default null)
// Null or an algorithm accepting nothing. // Null or an algorithm accepting nothing.
Optional<JS::SafeFunction<void()>> m_next_manual_redirect_steps; Optional<JS::SafeFunction<void()>> m_next_manual_redirect_steps;
JS::GCPtr<FetchParams> m_fetch_params;
}; };
} }

View file

@ -17,6 +17,7 @@ FetchParams::FetchParams(JS::NonnullGCPtr<Request> request, JS::NonnullGCPtr<Fet
, m_controller(controller) , m_controller(controller)
, m_timing_info(timing_info) , m_timing_info(timing_info)
{ {
m_controller->set_fetch_params({}, *this);
} }
JS::NonnullGCPtr<FetchParams> FetchParams::create(JS::VM& vm, JS::NonnullGCPtr<Request> request, JS::NonnullGCPtr<FetchTimingInfo> timing_info) JS::NonnullGCPtr<FetchParams> FetchParams::create(JS::VM& vm, JS::NonnullGCPtr<Request> request, JS::NonnullGCPtr<FetchTimingInfo> timing_info)