mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-28 11:49:44 +00:00
LibWeb: Push promise rejection handling onto UniversalGlobalScopeMixin
This is needed for shadow realms which don't have a window or worker global object. Fixes a crash for the attached test.
This commit is contained in:
parent
fb17f8ff66
commit
6a668f27c7
Notes:
github-actions[bot]
2024-11-30 11:07:17 +00:00
Author: https://github.com/shannonbooth
Commit: 6a668f27c7
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2631
9 changed files with 129 additions and 109 deletions
|
@ -20,7 +20,6 @@
|
|||
#include <LibWeb/HTML/EventLoop/EventLoop.h>
|
||||
#include <LibWeb/HTML/EventSource.h>
|
||||
#include <LibWeb/HTML/ImageBitmap.h>
|
||||
#include <LibWeb/HTML/PromiseRejectionEvent.h>
|
||||
#include <LibWeb/HTML/Scripting/ClassicScript.h>
|
||||
#include <LibWeb/HTML/Scripting/Environments.h>
|
||||
#include <LibWeb/HTML/Scripting/ExceptionReporter.h>
|
||||
|
@ -74,7 +73,6 @@ void WindowOrWorkerGlobalScopeMixin::visit_edges(JS::Cell::Visitor& visitor)
|
|||
entry.value.visit_edges(visitor);
|
||||
visitor.visit(m_registered_event_sources);
|
||||
visitor.visit(m_crypto);
|
||||
visitor.ignore(m_outstanding_rejected_promises_weak_set);
|
||||
}
|
||||
|
||||
void WindowOrWorkerGlobalScopeMixin::finalize()
|
||||
|
@ -791,89 +789,4 @@ GC::Ref<Crypto::Crypto> WindowOrWorkerGlobalScopeMixin::crypto()
|
|||
return GC::Ref { *m_crypto };
|
||||
}
|
||||
|
||||
void WindowOrWorkerGlobalScopeMixin::push_onto_outstanding_rejected_promises_weak_set(JS::Promise* promise)
|
||||
{
|
||||
m_outstanding_rejected_promises_weak_set.append(promise);
|
||||
}
|
||||
|
||||
bool WindowOrWorkerGlobalScopeMixin::remove_from_outstanding_rejected_promises_weak_set(JS::Promise* promise)
|
||||
{
|
||||
return m_outstanding_rejected_promises_weak_set.remove_first_matching([&](JS::Promise* promise_in_set) {
|
||||
return promise == promise_in_set;
|
||||
});
|
||||
}
|
||||
|
||||
void WindowOrWorkerGlobalScopeMixin::push_onto_about_to_be_notified_rejected_promises_list(GC::Ref<JS::Promise> promise)
|
||||
{
|
||||
m_about_to_be_notified_rejected_promises_list.append(GC::make_root(promise));
|
||||
}
|
||||
|
||||
bool WindowOrWorkerGlobalScopeMixin::remove_from_about_to_be_notified_rejected_promises_list(GC::Ref<JS::Promise> promise)
|
||||
{
|
||||
return m_about_to_be_notified_rejected_promises_list.remove_first_matching([&](auto& promise_in_list) {
|
||||
return promise == promise_in_list;
|
||||
});
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/webappapis.html#notify-about-rejected-promises
|
||||
void WindowOrWorkerGlobalScopeMixin::notify_about_rejected_promises(Badge<EventLoop>)
|
||||
{
|
||||
auto& realm = this_impl().realm();
|
||||
|
||||
// 1. Let list be a copy of settings object's about-to-be-notified rejected promises list.
|
||||
auto list = m_about_to_be_notified_rejected_promises_list;
|
||||
|
||||
// 2. If list is empty, return.
|
||||
if (list.is_empty())
|
||||
return;
|
||||
|
||||
// 3. Clear settings object's about-to-be-notified rejected promises list.
|
||||
m_about_to_be_notified_rejected_promises_list.clear();
|
||||
|
||||
// 4. Let global be settings object's global object.
|
||||
// We need this as an event target for the unhandledrejection event below
|
||||
auto& global = verify_cast<DOM::EventTarget>(this_impl());
|
||||
|
||||
// 5. Queue a global task on the DOM manipulation task source given global to run the following substep:
|
||||
queue_global_task(Task::Source::DOMManipulation, global, GC::create_function(realm.heap(), [this, &global, list = move(list)] {
|
||||
auto& realm = global.realm();
|
||||
|
||||
// 1. For each promise p in list:
|
||||
for (auto const& promise : list) {
|
||||
|
||||
// 1. If p's [[PromiseIsHandled]] internal slot is true, continue to the next iteration of the loop.
|
||||
if (promise->is_handled())
|
||||
continue;
|
||||
|
||||
// 2. Let notHandled be the result of firing an event named unhandledrejection at global, using PromiseRejectionEvent, with the cancelable attribute initialized to true,
|
||||
// the promise attribute initialized to p, and the reason attribute initialized to the value of p's [[PromiseResult]] internal slot.
|
||||
PromiseRejectionEventInit event_init {
|
||||
{
|
||||
.bubbles = false,
|
||||
.cancelable = true,
|
||||
.composed = false,
|
||||
},
|
||||
// Sadly we can't use .promise and .reason here, as we can't use the designator on the initialization of DOM::EventInit above.
|
||||
/* .promise = */ *promise,
|
||||
/* .reason = */ promise->result(),
|
||||
};
|
||||
|
||||
auto promise_rejection_event = PromiseRejectionEvent::create(realm, HTML::EventNames::unhandledrejection, event_init);
|
||||
|
||||
bool not_handled = global.dispatch_event(*promise_rejection_event);
|
||||
|
||||
// 3. If notHandled is false, then the promise rejection is handled. Otherwise, the promise rejection is not handled.
|
||||
|
||||
// 4. If p's [[PromiseIsHandled]] internal slot is false, add p to settings object's outstanding rejected promises weak set.
|
||||
if (!promise->is_handled())
|
||||
m_outstanding_rejected_promises_weak_set.append(*promise);
|
||||
|
||||
// This algorithm results in promise rejections being marked as handled or not handled. These concepts parallel handled and not handled script errors.
|
||||
// If a rejection is still not handled after this, then the rejection may be reported to a developer console.
|
||||
if (not_handled)
|
||||
HTML::report_exception_to_console(promise->result(), realm, ErrorInPromise::Yes);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue