From 4135c3885c8789949e57d0d4de336b0663c411f2 Mon Sep 17 00:00:00 2001 From: Shannon Booth Date: Sun, 14 Jan 2024 15:59:38 +1300 Subject: [PATCH] LibWeb: Only wait for document to be ready for scripts if executing one HTML fragments are parsed with a temporary HTML document that never has its flag set to say that it is ready to have scripts executed. For these fragments, in the HTMLParser, these scripts are prepared, but execute_script is never called on them. This results in the HTMLParser waiting forever on the document to be ready to have scripts executed. To fix this, only wait for the document to be ready if we are definitely going to execute a script. This fixes a hang processing the HTML in the attached test, as seen on: https://github.com/SerenityOS/serenity Fixes: #22735 --- .../Text/expected/HTML/set-innerHTML-with-script.txt | 1 + .../Text/input/HTML/set-innerHTML-with-script.html | 9 +++++++++ Userland/Libraries/LibWeb/HTML/HTMLScriptElement.cpp | 5 +++++ Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp | 8 +------- 4 files changed, 16 insertions(+), 7 deletions(-) create mode 100644 Tests/LibWeb/Text/expected/HTML/set-innerHTML-with-script.txt create mode 100644 Tests/LibWeb/Text/input/HTML/set-innerHTML-with-script.html diff --git a/Tests/LibWeb/Text/expected/HTML/set-innerHTML-with-script.txt b/Tests/LibWeb/Text/expected/HTML/set-innerHTML-with-script.txt new file mode 100644 index 0000000000..5df6241a8b --- /dev/null +++ b/Tests/LibWeb/Text/expected/HTML/set-innerHTML-with-script.txt @@ -0,0 +1 @@ + PASS diff --git a/Tests/LibWeb/Text/input/HTML/set-innerHTML-with-script.html b/Tests/LibWeb/Text/input/HTML/set-innerHTML-with-script.html new file mode 100644 index 0000000000..46301fc433 --- /dev/null +++ b/Tests/LibWeb/Text/input/HTML/set-innerHTML-with-script.html @@ -0,0 +1,9 @@ + +
+ diff --git a/Userland/Libraries/LibWeb/HTML/HTMLScriptElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLScriptElement.cpp index 79b413e6e2..65b2f523c1 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLScriptElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLScriptElement.cpp @@ -71,6 +71,11 @@ void HTMLScriptElement::begin_delaying_document_load_event(DOM::Document& docume // https://html.spec.whatwg.org/multipage/scripting.html#execute-the-script-block void HTMLScriptElement::execute_script() { + // https://html.spec.whatwg.org/multipage/document-lifecycle.html#read-html + // Before any script execution occurs, the user agent must wait for scripts may run for the newly-created document to be true for document. + if (!m_document->ready_to_run_scripts()) + main_thread_event_loop().spin_until([&] { return m_document->ready_to_run_scripts(); }); + // 1. Let document be el's node document. JS::NonnullGCPtr document = this->document(); diff --git a/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp b/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp index b88ccca90b..19b0f8220c 100644 --- a/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp +++ b/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp @@ -1,7 +1,7 @@ /* * Copyright (c) 2020-2022, Andreas Kling * Copyright (c) 2021, Luke Wilde - * Copyright (c) 2023, Shannon Booth + * Copyright (c) 2023-2024, Shannon Booth * * SPDX-License-Identifier: BSD-2-Clause */ @@ -2729,12 +2729,6 @@ void HTMLParser::handle_text(HTMLToken& token) // -> An end tag whose tag name is "script" if (token.is_end_tag() && token.tag_name() == HTML::TagNames::script) { - // https://html.spec.whatwg.org/multipage/document-lifecycle.html#read-html - // Before any script execution occurs, the user agent must wait for scripts may run for the newly-created document to be true for document. - if (!m_document->ready_to_run_scripts()) { - main_thread_event_loop().spin_until([&] { return m_document->ready_to_run_scripts(); }); - } - // FIXME: If the active speculative HTML parser is null and the JavaScript execution context stack is empty, then perform a microtask checkpoint. // Non-standard: Make sure the