diff --git a/Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp b/Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp index 958f93079dd..9dc09f17bb3 100644 --- a/Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp +++ b/Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp @@ -235,11 +235,12 @@ ErrorOr initialize_main_thread_vm(HTML::EventLoop::Type type) // 2. Queue a global task on the JavaScript engine task source given global to perform the following steps: HTML::queue_global_task(HTML::Task::Source::JavaScriptEngine, global, JS::create_heap_function(s_main_thread_vm->heap(), [&finalization_registry] { - // 1. Let entry be finalizationRegistry.[[CleanupCallback]].[[Callback]].[[Realm]]'s environment settings object. - auto& entry = host_defined_environment_settings_object(*finalization_registry.cleanup_callback().callback().realm()); + // FIXME: 1. Let entry be finalizationRegistry.[[CleanupCallback]].[[Callback]].[[Realm]]'s environment settings object. + auto& realm = *finalization_registry.cleanup_callback().callback().realm(); + auto& entry = host_defined_environment_settings_object(realm); // 2. Check if we can run script with entry. If this returns "do not run", then return. - if (entry.can_run_script() == HTML::RunScriptDecision::DoNotRun) + if (HTML::can_run_script(realm) == HTML::RunScriptDecision::DoNotRun) return; // 3. Prepare to run script with entry. @@ -276,16 +277,16 @@ ErrorOr initialize_main_thread_vm(HTML::EventLoop::Type type) auto& heap = realm ? realm->heap() : s_main_thread_vm->heap(); // NOTE: This keeps job_settings alive by keeping realm alive, which is holding onto job_settings. - HTML::queue_a_microtask(script ? script->settings_object().responsible_document().ptr() : nullptr, JS::create_heap_function(heap, [job_settings, job = move(job), script_or_module = move(script_or_module)] { + HTML::queue_a_microtask(script ? script->settings_object().responsible_document().ptr() : nullptr, JS::create_heap_function(heap, [realm, job_settings, job = move(job), script_or_module = move(script_or_module)] { // The dummy execution context has to be kept up here to keep it alive for the duration of the function. OwnPtr dummy_execution_context; - if (job_settings) { - // 1. If job settings is not null, then check if we can run script with job settings. If this returns "do not run" then return. - if (job_settings->can_run_script() == HTML::RunScriptDecision::DoNotRun) + if (realm) { + // 1. If realm is not null, then check if we can run script with realm. If this returns "do not run" then return. + if (HTML::can_run_script(*realm) == HTML::RunScriptDecision::DoNotRun) return; - // 2. If job settings is not null, then prepare to run script with job settings. + // FIXME: 2. If realm is not null, then prepare to run script with realm. job_settings->prepare_to_run_script(); // IMPLEMENTATION DEFINED: Additionally to preparing to run a script, we also prepare to run a callback here. This matches WebIDL's diff --git a/Userland/Libraries/LibWeb/DOM/Node.cpp b/Userland/Libraries/LibWeb/DOM/Node.cpp index a39b7f215fc..52d8d22a742 100644 --- a/Userland/Libraries/LibWeb/DOM/Node.cpp +++ b/Userland/Libraries/LibWeb/DOM/Node.cpp @@ -1450,16 +1450,18 @@ void Node::serialize_tree_as_json(JsonObjectSerializer& object) c } // https://html.spec.whatwg.org/multipage/webappapis.html#concept-n-script +// https://whatpr.org/html/9893/webappapis.html#concept-n-script bool Node::is_scripting_enabled() const { - // Scripting is enabled for a node node if node's node document's browsing context is non-null, and scripting is enabled for node's relevant settings object. - return document().browsing_context() && const_cast(document()).relevant_settings_object().is_scripting_enabled(); + // Scripting is enabled for a node node if node's node document's browsing context is non-null, and scripting is enabled for node's relevant realm. + return document().browsing_context() && HTML::is_scripting_enabled(HTML::relevant_realm(*this)); } // https://html.spec.whatwg.org/multipage/webappapis.html#concept-n-noscript +// https://whatpr.org/html/9893/webappapis.html#concept-n-script bool Node::is_scripting_disabled() const { - // Scripting is disabled for a node when scripting is not enabled, i.e., when its node document's browsing context is null or when scripting is disabled for its relevant settings object. + // Scripting is disabled for a node when scripting is not enabled, i.e., when its node document's browsing context is null or when scripting is disabled for its relevant realm. return !is_scripting_enabled(); } diff --git a/Userland/Libraries/LibWeb/HTML/Scripting/ClassicScript.cpp b/Userland/Libraries/LibWeb/HTML/Scripting/ClassicScript.cpp index 296ccfe65ea..9fc8a96987f 100644 --- a/Userland/Libraries/LibWeb/HTML/Scripting/ClassicScript.cpp +++ b/Userland/Libraries/LibWeb/HTML/Scripting/ClassicScript.cpp @@ -19,22 +19,24 @@ namespace Web::HTML { JS_DEFINE_ALLOCATOR(ClassicScript); // https://html.spec.whatwg.org/multipage/webappapis.html#creating-a-classic-script +// https://whatpr.org/html/9893/webappapis.html#creating-a-classic-script JS::NonnullGCPtr ClassicScript::create(ByteString filename, StringView source, EnvironmentSettingsObject& environment_settings_object, URL::URL base_url, size_t source_line_number, MutedErrors muted_errors) { - auto& vm = environment_settings_object.realm().vm(); + auto& realm = environment_settings_object.realm(); + auto& vm = realm.vm(); // 1. If muted errors is true, then set baseURL to about:blank. if (muted_errors == MutedErrors::Yes) base_url = "about:blank"sv; - // 2. If scripting is disabled for settings object, then set source to the empty string. - if (environment_settings_object.is_scripting_disabled()) + // 2. If scripting is disabled for realm, then set source to the empty string. + if (is_scripting_disabled(realm)) source = ""sv; // 3. Let script be a new classic script that this algorithm will subsequently initialize. auto script = vm.heap().allocate_without_realm(move(base_url), move(filename), environment_settings_object); - // 4. Set script's settings object to settings. (NOTE: This was already done when constructing.) + // FIXME: 4. Set script's realm to realm. (NOTE: This was already done when constructing.) // 5. Set script's base URL to baseURL. (NOTE: This was already done when constructing.) @@ -49,9 +51,9 @@ JS::NonnullGCPtr ClassicScript::create(ByteString filename, Strin // FIXME: 9. Record classic script creation time given script and sourceURLForWindowScripts . - // 10. Let result be ParseScript(source, settings's Realm, script). + // 10. Let result be ParseScript(source, realm, script). auto parse_timer = Core::ElapsedTimer::start_new(); - auto result = JS::Script::parse(source, environment_settings_object.realm(), script->filename(), script, source_line_number); + auto result = JS::Script::parse(source, realm, script->filename(), script, source_line_number); dbgln_if(HTML_SCRIPT_DEBUG, "ClassicScript: Parsed {} in {}ms", script->filename(), parse_timer.elapsed()); // 11. If result is a list of errors, then: @@ -60,7 +62,7 @@ JS::NonnullGCPtr ClassicScript::create(ByteString filename, Strin dbgln_if(HTML_SCRIPT_DEBUG, "ClassicScript: Failed to parse: {}", parse_error.to_string()); // 1. Set script's parse error and its error to rethrow to result[0]. - script->set_parse_error(JS::SyntaxError::create(environment_settings_object.realm(), parse_error.to_string())); + script->set_parse_error(JS::SyntaxError::create(realm, parse_error.to_string())); script->set_error_to_rethrow(script->parse_error()); // 2. Return script. @@ -75,13 +77,15 @@ JS::NonnullGCPtr ClassicScript::create(ByteString filename, Strin } // https://html.spec.whatwg.org/multipage/webappapis.html#run-a-classic-script +// https://whatpr.org/html/9893/webappapis.html#run-a-classic-script JS::Completion ClassicScript::run(RethrowErrors rethrow_errors) { // 1. Let settings be the settings object of script. auto& settings = settings_object(); + auto& realm = settings.realm(); // 2. Check if we can run script with settings. If this returns "do not run" then return NormalCompletion(empty). - if (settings.can_run_script() == RunScriptDecision::DoNotRun) + if (can_run_script(realm) == RunScriptDecision::DoNotRun) return JS::normal_completion({}); // 3. Prepare to run script given settings. @@ -121,7 +125,7 @@ JS::Completion ClassicScript::run(RethrowErrors rethrow_errors) settings.clean_up_after_running_script(); // 2. Throw a "NetworkError" DOMException. - return throw_completion(WebIDL::NetworkError::create(settings.realm(), "Script error."_string)); + return throw_completion(WebIDL::NetworkError::create(realm, "Script error."_string)); } // 3. Otherwise, rethrow errors is false. Perform the following steps: diff --git a/Userland/Libraries/LibWeb/HTML/Scripting/Environments.cpp b/Userland/Libraries/LibWeb/HTML/Scripting/Environments.cpp index a2d4e770e56..eebfc7678dc 100644 --- a/Userland/Libraries/LibWeb/HTML/Scripting/Environments.cpp +++ b/Userland/Libraries/LibWeb/HTML/Scripting/Environments.cpp @@ -100,14 +100,15 @@ EventLoop& EnvironmentSettingsObject::responsible_event_loop() } // https://html.spec.whatwg.org/multipage/webappapis.html#check-if-we-can-run-script -RunScriptDecision EnvironmentSettingsObject::can_run_script() +// https://whatpr.org/html/9893/webappapis.html#check-if-we-can-run-script +RunScriptDecision can_run_script(JS::Realm const& realm) { - // 1. If the global object specified by settings is a Window object whose Document object is not fully active, then return "do not run". - if (is(global_object()) && !verify_cast(global_object()).associated_document().is_fully_active()) + // 1. If the global object specified by realm is a Window object whose Document object is not fully active, then return "do not run". + if (is(realm.global_object()) && !verify_cast(realm.global_object()).associated_document().is_fully_active()) return RunScriptDecision::DoNotRun; - // 2. If scripting is disabled for settings, then return "do not run". - if (is_scripting_disabled()) + // 2. If scripting is disabled for realm, then return "do not run". + if (is_scripting_disabled(realm)) return RunScriptDecision::DoNotRun; // 3. Return "run". @@ -208,20 +209,20 @@ void EnvironmentSettingsObject::clean_up_after_running_callback() } // https://html.spec.whatwg.org/multipage/webappapis.html#concept-environment-script -bool EnvironmentSettingsObject::is_scripting_enabled() const +// https://whatpr.org/html/9893/webappapis.html#concept-environment-script +bool is_scripting_enabled(JS::Realm const& realm) { - // Scripting is enabled for an environment settings object settings when all of the following conditions are true: + // Scripting is enabled for a realm realm when all of the following conditions are true: // The user agent supports scripting. // NOTE: This is always true in LibWeb :^) // FIXME: Do the right thing for workers. - if (!is(m_realm_execution_context->realm->global_object())) + if (!is(realm.global_object())) return true; - // The user has not disabled scripting for settings at this time. (User agents may provide users with the option to disable scripting globally, or in a finer-grained manner, e.g., on a per-origin basis, down to the level of individual environment settings objects.) - auto document = const_cast(*this).responsible_document(); - VERIFY(document); - if (!document->page().is_scripting_enabled()) + // The user has not disabled scripting for realm at this time. (User agents may provide users with the option to disable scripting globally, or in a finer-grained manner, e.g., on a per-origin basis, down to the level of individual realms.) + auto const& document = verify_cast(realm.global_object()).associated_document(); + if (!document.page().is_scripting_enabled()) return false; // FIXME: Either settings's global object is not a Window object, or settings's global object's associated Document's active sandboxing flag set does not have its sandboxed scripts browsing context flag set. @@ -230,10 +231,11 @@ bool EnvironmentSettingsObject::is_scripting_enabled() const } // https://html.spec.whatwg.org/multipage/webappapis.html#concept-environment-noscript -bool EnvironmentSettingsObject::is_scripting_disabled() const +// https://whatpr.org/html/9893/webappapis.html#concept-environment-noscript +bool is_scripting_disabled(JS::Realm const& realm) { - // Scripting is disabled for an environment settings object when scripting is not enabled for it, i.e., when any of the above conditions are false. - return !is_scripting_enabled(); + // Scripting is disabled for a realm when scripting is not enabled for it, i.e., when any of the above conditions are false. + return !is_scripting_enabled(realm); } // https://html.spec.whatwg.org/multipage/webappapis.html#module-type-allowed diff --git a/Userland/Libraries/LibWeb/HTML/Scripting/Environments.h b/Userland/Libraries/LibWeb/HTML/Scripting/Environments.h index 21a185df676..7723f0637e9 100644 --- a/Userland/Libraries/LibWeb/HTML/Scripting/Environments.h +++ b/Userland/Libraries/LibWeb/HTML/Scripting/Environments.h @@ -94,16 +94,12 @@ public: // https://fetch.spec.whatwg.org/#concept-fetch-group Vector>& fetch_group() { return m_fetch_group; } - RunScriptDecision can_run_script(); void prepare_to_run_script(); void clean_up_after_running_script(); void prepare_to_run_callback(); void clean_up_after_running_callback(); - bool is_scripting_enabled() const; - bool is_scripting_disabled() const; - bool module_type_allowed(StringView module_type) const; void disallow_further_import_maps(); @@ -139,6 +135,10 @@ private: bool m_discarded { false }; }; +RunScriptDecision can_run_script(JS::Realm const&); +bool is_scripting_enabled(JS::Realm const&); +bool is_scripting_disabled(JS::Realm const&); + EnvironmentSettingsObject& incumbent_settings_object(); JS::Realm& incumbent_realm(); JS::Object& incumbent_global_object(); diff --git a/Userland/Libraries/LibWeb/HTML/Scripting/ModuleScript.cpp b/Userland/Libraries/LibWeb/HTML/Scripting/ModuleScript.cpp index ea5f198c17e..1e4be66b737 100644 --- a/Userland/Libraries/LibWeb/HTML/Scripting/ModuleScript.cpp +++ b/Userland/Libraries/LibWeb/HTML/Scripting/ModuleScript.cpp @@ -30,18 +30,19 @@ JavaScriptModuleScript::JavaScriptModuleScript(URL::URL base_url, ByteString fil } // https://html.spec.whatwg.org/multipage/webappapis.html#creating-a-javascript-module-script +// https://whatpr.org/html/9893/webappapis.html#creating-a-javascript-module-script WebIDL::ExceptionOr> JavaScriptModuleScript::create(ByteString const& filename, StringView source, EnvironmentSettingsObject& settings_object, URL::URL base_url) { - // 1. If scripting is disabled for settings, then set source to the empty string. - if (settings_object.is_scripting_disabled()) - source = ""sv; - auto& realm = settings_object.realm(); + // 1. If scripting is disabled for settings, then set source to the empty string. + if (HTML::is_scripting_disabled(realm)) + source = ""sv; + // 2. Let script be a new module script that this algorithm will subsequently initialize. auto script = realm.heap().allocate(realm, move(base_url), filename, settings_object); - // 3. Set script's settings object to settings. + // FIXME: 3. Set script's settings object to settings. // NOTE: This was already done when constructing. // 4. Set script's base URL to baseURL. @@ -53,8 +54,8 @@ WebIDL::ExceptionOr> JavaScriptModuleScript::c script->set_parse_error(JS::js_null()); script->set_error_to_rethrow(JS::js_null()); - // 7. Let result be ParseModule(source, settings's Realm, script). - auto result = JS::SourceTextModule::parse(source, settings_object.realm(), filename.view(), script); + // 7. Let result be ParseModule(source, realm, script). + auto result = JS::SourceTextModule::parse(source, realm, filename.view(), script); // 8. If result is a list of errors, then: if (result.is_error()) { @@ -62,7 +63,7 @@ WebIDL::ExceptionOr> JavaScriptModuleScript::c dbgln("JavaScriptModuleScript: Failed to parse: {}", parse_error.to_string()); // 1. Set script's parse error to result[0]. - script->set_parse_error(JS::SyntaxError::create(settings_object.realm(), parse_error.to_string())); + script->set_parse_error(JS::SyntaxError::create(realm, parse_error.to_string())); // 2. Return script. return script; @@ -75,7 +76,7 @@ WebIDL::ExceptionOr> JavaScriptModuleScript::c for (auto const& attribute : requested.attributes) { if (attribute.key != "type"sv) { // 1. Let error be a new SyntaxError exception. - auto error = JS::SyntaxError::create(settings_object.realm(), "Module request attributes must only contain a type attribute"_string); + auto error = JS::SyntaxError::create(realm, "Module request attributes must only contain a type attribute"_string); // 2. Set script's parse error to error. script->set_parse_error(error); @@ -118,13 +119,15 @@ WebIDL::ExceptionOr> JavaScriptModuleScript::c } // https://html.spec.whatwg.org/multipage/webappapis.html#run-a-module-script +// https://whatpr.org/html/9893/webappapis.html#run-a-module-script JS::Promise* JavaScriptModuleScript::run(PreventErrorReporting) { // 1. Let settings be the settings object of script. auto& settings = settings_object(); + auto& realm = settings.realm(); - // 2. Check if we can run script with settings. If this returns "do not run", then return a promise resolved with undefined. - if (settings.can_run_script() == RunScriptDecision::DoNotRun) { + // 2. Check if we can run script with realm. If this returns "do not run", then return a promise resolved with undefined. + if (can_run_script(realm) == RunScriptDecision::DoNotRun) { auto promise = JS::Promise::create(settings.realm()); promise->fulfill(JS::js_undefined()); return promise; @@ -138,7 +141,7 @@ JS::Promise* JavaScriptModuleScript::run(PreventErrorReporting) // 5. If script's error to rethrow is not null, then set evaluationPromise to a promise rejected with script's error to rethrow. if (!error_to_rethrow().is_null()) { - evaluation_promise = JS::Promise::create(settings.realm()); + evaluation_promise = JS::Promise::create(realm); evaluation_promise->reject(error_to_rethrow()); } // 6. Otherwise: @@ -149,7 +152,7 @@ JS::Promise* JavaScriptModuleScript::run(PreventErrorReporting) // NON-STANDARD: To ensure that LibJS can find the module on the stack, we push a new execution context. auto module_execution_context = JS::ExecutionContext::create(); - module_execution_context->realm = &settings.realm(); + module_execution_context->realm = &realm; module_execution_context->script_or_module = JS::NonnullGCPtr { *record }; vm().push_execution_context(*module_execution_context); @@ -160,8 +163,8 @@ JS::Promise* JavaScriptModuleScript::run(PreventErrorReporting) // If Evaluate fails to complete as a result of the user agent aborting the running script, // then set evaluationPromise to a promise rejected with a new "QuotaExceededError" DOMException. if (elevation_promise_or_error.is_error()) { - auto promise = JS::Promise::create(settings_object().realm()); - promise->reject(WebIDL::QuotaExceededError::create(settings_object().realm(), "Failed to evaluate module script"_string).ptr()); + auto promise = JS::Promise::create(realm); + promise->reject(WebIDL::QuotaExceededError::create(realm, "Failed to evaluate module script"_string).ptr()); evaluation_promise = promise; } else {