diff --git a/Tests/LibWeb/Text/expected/video-canceled-load.txt b/Tests/LibWeb/Text/expected/video-canceled-load.txt
new file mode 100644
index 00000000000..6d15bb54988
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/video-canceled-load.txt
@@ -0,0 +1 @@
+ wfh
diff --git a/Tests/LibWeb/Text/input/video-canceled-load.html b/Tests/LibWeb/Text/input/video-canceled-load.html
new file mode 100644
index 00000000000..2c1d94ee495
--- /dev/null
+++ b/Tests/LibWeb/Text/input/video-canceled-load.html
@@ -0,0 +1,13 @@
+
+
+
diff --git a/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp b/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp
index 83b03905084..2201b763ff9 100644
--- a/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp
+++ b/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp
@@ -627,7 +627,7 @@ WebIDL::ExceptionOr fetch_response_handover(JS::Realm& realm, Infrastructu
auto task_destination = fetch_params.task_destination().get>();
// 5. Queue a fetch task to run processResponseEndOfBodyTask with fetchParams’s task destination.
- Infrastructure::queue_fetch_task(task_destination, move(process_response_end_of_body_task));
+ Infrastructure::queue_fetch_task(fetch_params.controller(), task_destination, move(process_response_end_of_body_task));
};
// FIXME: Handle 'parallel queue' task destination
@@ -636,7 +636,7 @@ WebIDL::ExceptionOr fetch_response_handover(JS::Realm& realm, Infrastructu
// 4. If fetchParams’s process response is non-null, then queue a fetch task to run fetchParams’s process response
// given response, with fetchParams’s task destination.
if (fetch_params.algorithms()->process_response()) {
- Infrastructure::queue_fetch_task(task_destination, [&fetch_params, &response]() {
+ Infrastructure::queue_fetch_task(fetch_params.controller(), task_destination, [&fetch_params, &response]() {
fetch_params.algorithms()->process_response()(response);
});
}
@@ -674,7 +674,7 @@ WebIDL::ExceptionOr fetch_response_handover(JS::Realm& realm, Infrastructu
// 3. If internalResponse's body is null, then queue a fetch task to run processBody given null, with
// fetchParams’s task destination.
if (!internal_response->body()) {
- Infrastructure::queue_fetch_task(task_destination, [process_body = move(process_body)]() {
+ Infrastructure::queue_fetch_task(fetch_params.controller(), task_destination, [process_body = move(process_body)]() {
process_body({});
});
}
diff --git a/Userland/Libraries/LibWeb/Fetch/Infrastructure/FetchController.cpp b/Userland/Libraries/LibWeb/Fetch/Infrastructure/FetchController.cpp
index b3805800d85..047d77efeb8 100644
--- a/Userland/Libraries/LibWeb/Fetch/Infrastructure/FetchController.cpp
+++ b/Userland/Libraries/LibWeb/Fetch/Infrastructure/FetchController.cpp
@@ -9,6 +9,7 @@
#include
#include
#include
+#include
#include
namespace Web::Fetch::Infrastructure {
@@ -105,11 +106,29 @@ void FetchController::stop_fetch()
// 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.
+ // cancelling any queued fetch tasks and then ignoring any callbacks.
+ auto ongoing_fetch_tasks = move(m_ongoing_fetch_tasks);
+
+ HTML::main_thread_event_loop().task_queue().remove_tasks_matching([&](auto const& task) {
+ return ongoing_fetch_tasks.remove_all_matching([&](u64, int task_id) {
+ return task.id() == task_id;
+ });
+ });
+
if (m_fetch_params) {
auto fetch_algorithms = FetchAlgorithms::create(vm, {});
m_fetch_params->set_algorithms(fetch_algorithms);
}
}
+void FetchController::fetch_task_queued(u64 fetch_task_id, int event_id)
+{
+ m_ongoing_fetch_tasks.set(fetch_task_id, event_id);
+}
+
+void FetchController::fetch_task_complete(u64 fetch_task_id)
+{
+ m_ongoing_fetch_tasks.remove(fetch_task_id);
+}
+
}
diff --git a/Userland/Libraries/LibWeb/Fetch/Infrastructure/FetchController.h b/Userland/Libraries/LibWeb/Fetch/Infrastructure/FetchController.h
index 7828660d3c8..879bd7f3876 100644
--- a/Userland/Libraries/LibWeb/Fetch/Infrastructure/FetchController.h
+++ b/Userland/Libraries/LibWeb/Fetch/Infrastructure/FetchController.h
@@ -7,6 +7,7 @@
#pragma once
#include
+#include
#include
#include
#include
@@ -48,6 +49,10 @@ public:
void stop_fetch();
+ u64 next_fetch_task_id() { return m_next_fetch_task_id++; }
+ void fetch_task_queued(u64 fetch_task_id, int event_id);
+ void fetch_task_complete(u64 fetch_task_id);
+
private:
FetchController();
@@ -78,6 +83,9 @@ private:
JS::GCPtr> m_next_manual_redirect_steps;
JS::GCPtr m_fetch_params;
+
+ HashMap m_ongoing_fetch_tasks;
+ u64 m_next_fetch_task_id { 0 };
};
}
diff --git a/Userland/Libraries/LibWeb/Fetch/Infrastructure/Task.cpp b/Userland/Libraries/LibWeb/Fetch/Infrastructure/Task.cpp
index 3718f91acd5..54e0a733c77 100644
--- a/Userland/Libraries/LibWeb/Fetch/Infrastructure/Task.cpp
+++ b/Userland/Libraries/LibWeb/Fetch/Infrastructure/Task.cpp
@@ -4,18 +4,34 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
+#include
#include
#include
namespace Web::Fetch::Infrastructure {
// https://fetch.spec.whatwg.org/#queue-a-fetch-task
-void queue_fetch_task(JS::Object& task_destination, JS::SafeFunction algorithm)
+int queue_fetch_task(JS::Object& task_destination, JS::SafeFunction algorithm)
{
// FIXME: 1. If taskDestination is a parallel queue, then enqueue algorithm to taskDestination.
// 2. Otherwise, queue a global task on the networking task source with taskDestination and algorithm.
- HTML::queue_global_task(HTML::Task::Source::Networking, task_destination, move(algorithm));
+ return HTML::queue_global_task(HTML::Task::Source::Networking, task_destination, move(algorithm));
+}
+
+// AD-HOC: This overload allows tracking the queued task within the fetch controller so that we may cancel queued tasks
+// when the spec indicates that we must stop an ongoing fetch.
+int queue_fetch_task(JS::NonnullGCPtr fetch_controller, JS::Object& task_destination, JS::SafeFunction algorithm)
+{
+ auto fetch_task_id = fetch_controller->next_fetch_task_id();
+
+ int event_id = queue_fetch_task(task_destination, [fetch_controller, fetch_task_id, algorithm = move(algorithm)]() {
+ fetch_controller->fetch_task_complete(fetch_task_id);
+ algorithm();
+ });
+
+ fetch_controller->fetch_task_queued(fetch_task_id, event_id);
+ return event_id;
}
}
diff --git a/Userland/Libraries/LibWeb/Fetch/Infrastructure/Task.h b/Userland/Libraries/LibWeb/Fetch/Infrastructure/Task.h
index b026e412c2f..c305accd798 100644
--- a/Userland/Libraries/LibWeb/Fetch/Infrastructure/Task.h
+++ b/Userland/Libraries/LibWeb/Fetch/Infrastructure/Task.h
@@ -10,12 +10,14 @@
#include
#include
#include
+#include
namespace Web::Fetch::Infrastructure {
// FIXME: 'or a parallel queue'
using TaskDestination = Variant>;
-void queue_fetch_task(JS::Object&, JS::SafeFunction);
+int queue_fetch_task(JS::Object&, JS::SafeFunction);
+int queue_fetch_task(JS::NonnullGCPtr, JS::Object&, JS::SafeFunction);
}