Coverage Report

Created: 2025-08-28 06:26

/src/serenity/Userland/Libraries/LibWeb/HTML/WorkerGlobalScope.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2022, Andrew Kaster <akaster@serenityos.org>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#include <AK/Vector.h>
8
#include <LibWeb/Bindings/Intrinsics.h>
9
#include <LibWeb/Bindings/WorkerGlobalScopePrototype.h>
10
#include <LibWeb/CSS/FontFaceSet.h>
11
#include <LibWeb/HTML/EventHandler.h>
12
#include <LibWeb/HTML/EventNames.h>
13
#include <LibWeb/HTML/MessageEvent.h>
14
#include <LibWeb/HTML/MessagePort.h>
15
#include <LibWeb/HTML/Scripting/ClassicScript.h>
16
#include <LibWeb/HTML/StructuredSerialize.h>
17
#include <LibWeb/HTML/WorkerGlobalScope.h>
18
#include <LibWeb/HTML/WorkerLocation.h>
19
#include <LibWeb/HTML/WorkerNavigator.h>
20
#include <LibWeb/Page/Page.h>
21
22
namespace Web::HTML {
23
24
JS_DEFINE_ALLOCATOR(WorkerGlobalScope);
25
26
WorkerGlobalScope::WorkerGlobalScope(JS::Realm& realm, JS::NonnullGCPtr<Web::Page> page)
27
0
    : DOM::EventTarget(realm)
28
0
    , m_page(page)
29
0
{
30
0
}
31
32
0
WorkerGlobalScope::~WorkerGlobalScope() = default;
33
34
void WorkerGlobalScope::initialize_web_interfaces_impl()
35
0
{
36
0
    auto& realm = this->realm();
37
0
    Base::initialize(realm);
38
39
0
    WindowOrWorkerGlobalScopeMixin::initialize(realm);
40
41
0
    m_navigator = WorkerNavigator::create(*this);
42
0
}
43
44
void WorkerGlobalScope::visit_edges(Cell::Visitor& visitor)
45
0
{
46
0
    Base::visit_edges(visitor);
47
0
    WindowOrWorkerGlobalScopeMixin::visit_edges(visitor);
48
49
0
    visitor.visit(m_location);
50
0
    visitor.visit(m_navigator);
51
0
    visitor.visit(m_internal_port);
52
0
    visitor.visit(m_page);
53
0
    visitor.visit(m_fonts);
54
0
}
55
56
void WorkerGlobalScope::finalize()
57
0
{
58
0
    Base::finalize();
59
0
    WindowOrWorkerGlobalScopeMixin::finalize();
60
0
}
61
62
void WorkerGlobalScope::set_internal_port(JS::NonnullGCPtr<MessagePort> port)
63
0
{
64
0
    m_internal_port = port;
65
0
    m_internal_port->set_worker_event_target(*this);
66
0
}
67
68
// https://html.spec.whatwg.org/multipage/workers.html#close-a-worker
69
void WorkerGlobalScope::close_a_worker()
70
0
{
71
    // 1. Discard any tasks that have been added to workerGlobal's relevant agent's event loop's task queues.
72
0
    relevant_settings_object(*this).responsible_event_loop().task_queue().remove_tasks_matching([](HTML::Task const& task) {
73
        // NOTE: We don't discard tasks with the PostedMessage source, as the spec expects PostMessage() to act as if it is invoked immediately
74
0
        return task.source() != HTML::Task::Source::PostedMessage;
75
0
    });
76
77
    // 2. Set workerGlobal's closing flag to true. (This prevents any further tasks from being queued.)
78
0
    m_closing = true;
79
0
}
80
81
// https://html.spec.whatwg.org/multipage/workers.html#importing-scripts-and-libraries
82
WebIDL::ExceptionOr<void> WorkerGlobalScope::import_scripts(Vector<String> const& urls, PerformTheFetchHook perform_fetch)
83
0
{
84
    // The algorithm may optionally be customized by supplying custom perform the fetch hooks,
85
    // which if provided will be used when invoking fetch a classic worker-imported script.
86
    // NOTE: Service Workers is an example of a specification that runs this algorithm with its own options for the perform the fetch hook.
87
88
    // FIXME: 1. If worker global scope's type is "module", throw a TypeError exception.
89
90
    // 2. Let settings object be the current settings object.
91
0
    auto& settings_object = HTML::current_settings_object();
92
93
    // 3. If urls is empty, return.
94
0
    if (urls.is_empty())
95
0
        return {};
96
97
    // 4. Let urlRecords be « ».
98
0
    Vector<URL::URL> url_records;
99
0
    url_records.ensure_capacity(urls.size());
100
101
    // 5. For each url of urls:
102
0
    for (auto const& url : urls) {
103
        // 1. Let urlRecord be the result of encoding-parsing a URL given url, relative to settings object.
104
0
        auto url_record = settings_object.parse_url(url);
105
106
        // 2. If urlRecord is failure, then throw a "SyntaxError" DOMException.
107
0
        if (!url_record.is_valid())
108
0
            return WebIDL::SyntaxError::create(realm(), "Invalid URL"_string);
109
110
        // 3. Append urlRecord to urlRecords.
111
0
        url_records.unchecked_append(url_record);
112
0
    }
113
114
    // 6. For each urlRecord of urlRecords:
115
0
    for (auto const& url_record : url_records) {
116
        // 1. Fetch a classic worker-imported script given urlRecord and settings object, passing along performFetch if provided.
117
        //    If this succeeds, let script be the result. Otherwise, rethrow the exception.
118
0
        auto classic_script = TRY(HTML::fetch_a_classic_worker_imported_script(url_record, settings_object, perform_fetch));
119
120
        // 2. Run the classic script script, with the rethrow errors argument set to true.
121
        // NOTE: script will run until it either returns, fails to parse, fails to catch an exception,
122
        //       or gets prematurely aborted by the terminate a worker algorithm defined above.
123
        // If an exception was thrown or if the script was prematurely aborted, then abort all these steps,
124
        // letting the exception or aborting continue to be processed by the calling script.
125
0
        TRY(classic_script->run(ClassicScript::RethrowErrors::Yes));
126
0
    }
127
128
0
    return {};
129
0
}
130
131
// https://html.spec.whatwg.org/multipage/workers.html#dom-workerglobalscope-location
132
JS::NonnullGCPtr<WorkerLocation> WorkerGlobalScope::location() const
133
0
{
134
    // The location attribute must return the WorkerLocation object whose associated WorkerGlobalScope object is the WorkerGlobalScope object.
135
0
    return *m_location;
136
0
}
137
138
// https://html.spec.whatwg.org/multipage/workers.html#dom-worker-navigator
139
JS::NonnullGCPtr<WorkerNavigator> WorkerGlobalScope::navigator() const
140
0
{
141
    // The navigator attribute of the WorkerGlobalScope interface must return an instance of the WorkerNavigator interface,
142
    // which represents the identity and state of the user agent (the client).
143
0
    return *m_navigator;
144
0
}
145
146
#undef __ENUMERATE
147
#define __ENUMERATE(attribute_name, event_name)                               \
148
    void WorkerGlobalScope::set_##attribute_name(WebIDL::CallbackType* value) \
149
0
    {                                                                         \
150
0
        set_event_handler_attribute(event_name, move(value));                 \
151
0
    }                                                                         \
Unexecuted instantiation: Web::HTML::WorkerGlobalScope::set_onerror(Web::WebIDL::CallbackType*)
Unexecuted instantiation: Web::HTML::WorkerGlobalScope::set_onlanguagechange(Web::WebIDL::CallbackType*)
Unexecuted instantiation: Web::HTML::WorkerGlobalScope::set_ononline(Web::WebIDL::CallbackType*)
Unexecuted instantiation: Web::HTML::WorkerGlobalScope::set_onoffline(Web::WebIDL::CallbackType*)
Unexecuted instantiation: Web::HTML::WorkerGlobalScope::set_onrejectionhandled(Web::WebIDL::CallbackType*)
Unexecuted instantiation: Web::HTML::WorkerGlobalScope::set_onunhandledrejection(Web::WebIDL::CallbackType*)
152
    WebIDL::CallbackType* WorkerGlobalScope::attribute_name()                 \
153
0
    {                                                                         \
154
0
        return event_handler_attribute(event_name);                           \
155
0
    }
Unexecuted instantiation: Web::HTML::WorkerGlobalScope::onerror()
Unexecuted instantiation: Web::HTML::WorkerGlobalScope::onlanguagechange()
Unexecuted instantiation: Web::HTML::WorkerGlobalScope::ononline()
Unexecuted instantiation: Web::HTML::WorkerGlobalScope::onoffline()
Unexecuted instantiation: Web::HTML::WorkerGlobalScope::onrejectionhandled()
Unexecuted instantiation: Web::HTML::WorkerGlobalScope::onunhandledrejection()
156
ENUMERATE_WORKER_GLOBAL_SCOPE_EVENT_HANDLERS(__ENUMERATE)
157
#undef __ENUMERATE
158
159
JS::NonnullGCPtr<CSS::FontFaceSet> WorkerGlobalScope::fonts()
160
0
{
161
0
    if (!m_fonts)
162
0
        m_fonts = CSS::FontFaceSet::create(realm());
163
0
    return *m_fonts;
164
0
}
165
166
}