LibWeb: Implement WorkerGlobalScope.importScripts()

This method allows workers to synchronously import one or more scripts.
This commit is contained in:
Tim Ledbetter 2024-05-23 13:57:08 +01:00 committed by Andreas Kling
commit bb923983fc
Notes: sideshowbarker 2024-07-17 03:19:14 +09:00
8 changed files with 134 additions and 12 deletions

View file

@ -12,6 +12,7 @@
#include <LibWeb/HTML/EventHandler.h>
#include <LibWeb/HTML/EventNames.h>
#include <LibWeb/HTML/MessageEvent.h>
#include <LibWeb/HTML/Scripting/ClassicScript.h>
#include <LibWeb/HTML/StructuredSerialize.h>
#include <LibWeb/HTML/WorkerGlobalScope.h>
#include <LibWeb/HTML/WorkerLocation.h>
@ -70,28 +71,51 @@ void WorkerGlobalScope::set_internal_port(JS::NonnullGCPtr<MessagePort> port)
}
// https://html.spec.whatwg.org/multipage/workers.html#importing-scripts-and-libraries
WebIDL::ExceptionOr<void> WorkerGlobalScope::import_scripts(Vector<String> urls)
WebIDL::ExceptionOr<void> WorkerGlobalScope::import_scripts(Vector<String> const& urls, PerformTheFetchHook perform_fetch)
{
// The algorithm may optionally be customized by supplying custom perform the fetch hooks,
// which if provided will be used when invoking fetch a classic worker-imported script.
// NOTE: Service Workers is an example of a specification that runs this algorithm with its own options for the perform the fetch hook.
// FIXME: 1. If worker global scope's type is "module", throw a TypeError exception.
// FIXME: 2. Let settings object be the current settings object.
// 2. Let settings object be the current settings object.
auto& settings_object = HTML::current_settings_object();
// 3. If urls is empty, return.
if (urls.is_empty())
return {};
// FIXME: 4. Parse each value in urls relative to settings object. If any fail, throw a "SyntaxError" DOMException.
// FIXME: 5. For each url in the resulting URL records, run these substeps:
// 1. Fetch a classic worker-imported script given url and settings object, passing along any custom perform the fetch steps provided.
// If this succeeds, let script be the result. Otherwise, rethrow the exception.
// 2. Run the classic script script, with the rethrow errors argument set to true.
// NOTE: script will run until it either returns, fails to parse, fails to catch an exception,
// or gets prematurely aborted by the terminate a worker algorithm defined above.
// If an exception was thrown or if the script was prematurely aborted, then abort all these steps,
// letting the exception or aborting continue to be processed by the calling script.
// 4. Let urlRecords be « ».
Vector<URL::URL> url_records;
url_records.ensure_capacity(urls.size());
// 5. For each url of urls:
for (auto const& url : urls) {
// 1. Let urlRecord be the result of encoding-parsing a URL given url, relative to settings object.
auto url_record = settings_object.parse_url(url);
// 2. If urlRecord is failure, then throw a "SyntaxError" DOMException.
if (!url_record.is_valid())
return WebIDL::SyntaxError::create(realm(), "Invalid URL"_fly_string);
// 3. Append urlRecord to urlRecords.
url_records.unchecked_append(url_record);
}
// 6. For each urlRecord of urlRecords:
for (auto const& url_record : url_records) {
// 1. Fetch a classic worker-imported script given urlRecord and settings object, passing along performFetch if provided.
// If this succeeds, let script be the result. Otherwise, rethrow the exception.
auto classic_script = TRY(HTML::fetch_a_classic_worker_imported_script(url_record, settings_object, perform_fetch));
// 2. Run the classic script script, with the rethrow errors argument set to true.
// NOTE: script will run until it either returns, fails to parse, fails to catch an exception,
// or gets prematurely aborted by the terminate a worker algorithm defined above.
// If an exception was thrown or if the script was prematurely aborted, then abort all these steps,
// letting the exception or aborting continue to be processed by the calling script.
TRY(classic_script->run(ClassicScript::RethrowErrors::Yes));
}
return {};
}