2021-09-09 13:03:01 -03:00
/*
2024-10-04 08:19:50 -03:00
* Copyright ( c ) 2021 - 2023 , Andreas Kling < andreas @ ladybird . org >
2021-09-09 13:03:01 -03:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2022-02-05 12:18:22 -03:00
# include <AK/Debug.h>
2021-09-12 16:56:44 -03:00
# include <LibCore/ElapsedTimer.h>
2023-06-17 08:16:35 -03:00
# include <LibJS/Bytecode/Interpreter.h>
2021-10-14 12:12:53 -03:00
# include <LibWeb/Bindings/ExceptionOrUtils.h>
2021-09-09 13:03:01 -03:00
# include <LibWeb/HTML/Scripting/ClassicScript.h>
2021-10-14 12:12:53 -03:00
# include <LibWeb/HTML/Scripting/Environments.h>
2022-02-07 11:12:41 -03:00
# include <LibWeb/HTML/Scripting/ExceptionReporter.h>
2024-09-26 11:40:23 -03:00
# include <LibWeb/HTML/WindowOrWorkerGlobalScope.h>
2022-09-25 13:28:46 -03:00
# include <LibWeb/WebIDL/DOMException.h>
2021-09-09 13:03:01 -03:00
namespace Web : : HTML {
2023-11-19 15:47:52 -03:00
JS_DEFINE_ALLOCATOR ( ClassicScript ) ;
2021-09-09 14:03:50 -03:00
// https://html.spec.whatwg.org/multipage/webappapis.html#creating-a-classic-script
2024-03-18 00:22:27 -03:00
JS : : NonnullGCPtr < ClassicScript > ClassicScript : : create ( ByteString filename , StringView source , EnvironmentSettingsObject & environment_settings_object , URL : : URL base_url , size_t source_line_number , MutedErrors muted_errors )
2021-09-09 13:03:01 -03:00
{
2022-09-05 09:32:33 -03:00
auto & vm = environment_settings_object . realm ( ) . vm ( ) ;
2021-09-09 14:03:50 -03:00
// 1. If muted errors was not provided, let it be false. (NOTE: This is taken care of by the default argument.)
// 2. If muted errors is true, then set baseURL to about:blank.
if ( muted_errors = = MutedErrors : : Yes )
2022-07-11 14:32:29 -03:00
base_url = " about:blank " sv ;
2021-09-09 14:03:50 -03:00
2022-03-30 18:42:09 -03:00
// 3. If scripting is disabled for settings, then set source to the empty string.
if ( environment_settings_object . is_scripting_disabled ( ) )
2022-07-11 14:32:29 -03:00
source = " " sv ;
2021-09-09 14:03:50 -03:00
// 4. Let script be a new classic script that this algorithm will subsequently initialize.
2022-09-05 09:32:33 -03:00
auto script = vm . heap ( ) . allocate_without_realm < ClassicScript > ( move ( base_url ) , move ( filename ) , environment_settings_object ) ;
2021-09-09 14:03:50 -03:00
2021-10-14 12:12:53 -03:00
// 5. Set script's settings object to settings. (NOTE: This was already done when constructing.)
2021-09-09 14:03:50 -03:00
// 6. Set script's base URL to baseURL. (NOTE: This was already done when constructing.)
// FIXME: 7. Set script's fetch options to options.
// 8. Set script's muted errors to muted errors.
script - > m_muted_errors = muted_errors ;
2023-05-18 14:05:56 -03:00
// 9. Set script's parse error and error to rethrow to null.
script - > set_parse_error ( JS : : js_null ( ) ) ;
script - > set_error_to_rethrow ( JS : : js_null ( ) ) ;
2021-09-09 14:03:50 -03:00
// 10. Let result be ParseScript(source, settings's Realm, script).
2021-09-14 16:00:41 -03:00
auto parse_timer = Core : : ElapsedTimer : : start_new ( ) ;
2022-09-05 09:32:33 -03:00
auto result = JS : : Script : : parse ( source , environment_settings_object . realm ( ) , script - > filename ( ) , script , source_line_number ) ;
2022-02-05 12:18:22 -03:00
dbgln_if ( HTML_SCRIPT_DEBUG , " ClassicScript: Parsed {} in {}ms " , script - > filename ( ) , parse_timer . elapsed ( ) ) ;
2021-09-09 14:03:50 -03:00
2021-09-14 15:56:57 -03:00
// 11. If result is a list of errors, then:
if ( result . is_error ( ) ) {
2021-10-14 12:12:53 -03:00
auto & parse_error = result . error ( ) . first ( ) ;
2024-04-05 04:26:03 -03:00
dbgln_if ( HTML_SCRIPT_DEBUG , " ClassicScript: Failed to parse: {} " , parse_error . to_string ( ) ) ;
2021-10-14 12:12:53 -03:00
2023-05-18 14:05:56 -03:00
// 1. Set script's parse error and its error to rethrow to result[0].
2024-04-04 19:39:53 -03:00
script - > set_parse_error ( JS : : SyntaxError : : create ( environment_settings_object . realm ( ) , parse_error . to_string ( ) ) ) ;
2023-05-18 14:05:56 -03:00
script - > set_error_to_rethrow ( script - > parse_error ( ) ) ;
2021-09-14 15:56:57 -03:00
// 2. Return script.
2022-12-14 14:40:33 -03:00
return script ;
2021-09-14 15:56:57 -03:00
}
2021-09-09 14:03:50 -03:00
// 12. Set script's record to result.
2022-09-05 09:32:33 -03:00
script - > m_script_record = * result . release_value ( ) ;
2021-09-09 14:03:50 -03:00
// 13. Return script.
2022-12-14 14:40:33 -03:00
return script ;
2021-09-09 14:03:50 -03:00
}
// https://html.spec.whatwg.org/multipage/webappapis.html#run-a-classic-script
2024-10-29 14:51:55 -03:00
JS : : Completion ClassicScript : : run ( RethrowErrors rethrow_errors )
2021-09-09 14:03:50 -03:00
{
2022-06-27 15:50:40 -03:00
// 1. Let settings be the settings object of script.
auto & settings = settings_object ( ) ;
2021-10-14 12:12:53 -03:00
// 2. Check if we can run script with settings. If this returns "do not run" then return NormalCompletion(empty).
2022-06-27 15:50:40 -03:00
if ( settings . can_run_script ( ) = = RunScriptDecision : : DoNotRun )
2021-10-14 12:12:53 -03:00
return JS : : normal_completion ( { } ) ;
// 3. Prepare to run script given settings.
2022-06-27 15:50:40 -03:00
settings . prepare_to_run_script ( ) ;
2021-10-14 12:12:53 -03:00
// 4. Let evaluationStatus be null.
JS : : Completion evaluation_status ;
// 5. If script's error to rethrow is not null, then set evaluationStatus to Completion { [[Type]]: throw, [[Value]]: script's error to rethrow, [[Target]]: empty }.
2023-05-18 14:05:56 -03:00
if ( ! error_to_rethrow ( ) . is_null ( ) ) {
2024-05-10 04:28:48 -03:00
evaluation_status = JS : : Completion { JS : : Completion : : Type : : Throw , error_to_rethrow ( ) } ;
2021-10-14 12:12:53 -03:00
} else {
auto timer = Core : : ElapsedTimer : : start_new ( ) ;
// 6. Otherwise, set evaluationStatus to ScriptEvaluation(script's record).
2024-10-29 14:51:55 -03:00
evaluation_status = vm ( ) . bytecode_interpreter ( ) . run ( * m_script_record ) ;
2021-10-14 12:12:53 -03:00
// FIXME: If ScriptEvaluation does not complete because the user agent has aborted the running script, leave evaluationStatus as null.
dbgln_if ( HTML_SCRIPT_DEBUG , " ClassicScript: Finished running script {}, Duration: {}ms " , filename ( ) , timer . elapsed ( ) ) ;
2021-09-17 20:38:40 -03:00
}
2021-10-14 12:12:53 -03:00
// 7. If evaluationStatus is an abrupt completion, then:
if ( evaluation_status . is_abrupt ( ) ) {
// 1. If rethrow errors is true and script's muted errors is false, then:
if ( rethrow_errors = = RethrowErrors : : Yes & & m_muted_errors = = MutedErrors : : No ) {
// 1. Clean up after running script with settings.
2022-06-27 15:50:40 -03:00
settings . clean_up_after_running_script ( ) ;
2021-09-09 14:03:50 -03:00
2021-10-14 12:12:53 -03:00
// 2. Rethrow evaluationStatus.[[Value]].
return JS : : throw_completion ( * evaluation_status . value ( ) ) ;
}
2022-01-16 09:16:04 -03:00
2021-10-14 12:12:53 -03:00
// 2. If rethrow errors is true and script's muted errors is true, then:
if ( rethrow_errors = = RethrowErrors : : Yes & & m_muted_errors = = MutedErrors : : Yes ) {
// 1. Clean up after running script with settings.
2022-06-27 15:50:40 -03:00
settings . clean_up_after_running_script ( ) ;
2022-01-08 17:28:27 -03:00
2021-10-14 12:12:53 -03:00
// 2. Throw a "NetworkError" DOMException.
2024-10-12 15:56:21 -03:00
return throw_completion ( WebIDL : : NetworkError : : create ( settings . realm ( ) , " Script error. " _string ) ) ;
2021-10-14 12:12:53 -03:00
}
2022-01-16 09:16:04 -03:00
2021-10-14 12:12:53 -03:00
// 3. Otherwise, rethrow errors is false. Perform the following steps:
VERIFY ( rethrow_errors = = RethrowErrors : : No ) ;
2022-01-16 09:16:04 -03:00
2024-09-26 11:40:23 -03:00
// 1. Report an exception given by evaluationStatus.[[Value]] for script's settings object's global object.
auto * window_or_worker = dynamic_cast < WindowOrWorkerGlobalScopeMixin * > ( & settings . global_object ( ) ) ;
VERIFY ( window_or_worker ) ;
window_or_worker - > report_an_exception ( * evaluation_status . value ( ) ) ;
2021-10-14 12:12:53 -03:00
// 2. Clean up after running script with settings.
2022-06-27 15:50:40 -03:00
settings . clean_up_after_running_script ( ) ;
2021-10-14 12:12:53 -03:00
// 3. Return evaluationStatus.
return evaluation_status ;
2022-01-08 17:28:27 -03:00
}
2021-10-14 12:12:53 -03:00
// 8. Clean up after running script with settings.
2022-06-27 15:50:40 -03:00
settings . clean_up_after_running_script ( ) ;
2021-10-14 12:12:53 -03:00
// 9. If evaluationStatus is a normal completion, then return evaluationStatus.
VERIFY ( ! evaluation_status . is_abrupt ( ) ) ;
return evaluation_status ;
// FIXME: 10. If we've reached this point, evaluationStatus was left as null because the script was aborted prematurely during evaluation.
// Return Completion { [[Type]]: throw, [[Value]]: a new "QuotaExceededError" DOMException, [[Target]]: empty }.
2021-09-09 13:03:01 -03:00
}
2024-03-18 00:22:27 -03:00
ClassicScript : : ClassicScript ( URL : : URL base_url , ByteString filename , EnvironmentSettingsObject & environment_settings_object )
2022-06-27 15:50:40 -03:00
: Script ( move ( base_url ) , move ( filename ) , environment_settings_object )
2021-09-09 13:03:01 -03:00
{
}
2022-03-14 16:21:51 -03:00
ClassicScript : : ~ ClassicScript ( ) = default ;
2021-09-09 13:03:01 -03:00
2022-09-05 09:32:33 -03:00
void ClassicScript : : visit_edges ( Cell : : Visitor & visitor )
{
Base : : visit_edges ( visitor ) ;
visitor . visit ( m_script_record ) ;
}
2021-09-09 13:03:01 -03:00
}