LibWeb: Set fragment scripting mode from the context document

This corresponds with the editorial change to the HTML standard
introducing the parsing mode enum of:

https://github.com/whatwg/html/commit/01c45cede

And a follow up normative change of:

https://github.com/whatwg/html/commit/508706c80

Making fragment parsing derive its scripting mode from the context
document.
This commit is contained in:
Shannon Booth 2026-04-12 13:31:30 +02:00 committed by Shannon Booth
parent 290db9d690
commit 8642801889
13 changed files with 181 additions and 89 deletions

View file

@ -7277,7 +7277,8 @@ void Document::parse_html_from_a_string(StringView html)
// 2. Create an HTML parser parser, associated with document.
// 3. Place html into the input stream for parser. The encoding confidence is irrelevant.
// FIXME: We don't have the concept of encoding confidence yet.
auto parser = HTML::HTMLParser::create(*this, html, "UTF-8"sv);
auto scripting_mode = is_scripting_enabled() ? HTML::ParserScriptingMode::Normal : HTML::ParserScriptingMode::Disabled;
auto parser = HTML::HTMLParser::create(*this, html, scripting_mode, "UTF-8"sv);
// 4. Start parser and let it run until it has consumed all the characters just inserted into the input stream.
parser->run(as<HTML::Window>(HTML::relevant_global_object(*this)).associated_document().url());

View file

@ -2350,27 +2350,31 @@ bool Element::is_actually_disabled() const
}
// https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#fragment-parsing-algorithm-steps
WebIDL::ExceptionOr<GC::Ref<DOM::DocumentFragment>> Element::parse_fragment(StringView markup)
WebIDL::ExceptionOr<GC::Ref<DOM::DocumentFragment>> Element::parse_fragment(StringView markup, HTML::ParserScriptingMode scripting_mode)
{
// 1. Let algorithm be the HTML fragment parsing algorithm.
auto algorithm = HTML::HTMLParser::parse_html_fragment;
// 1. Assert: scriptingMode is either Inert or Fragment.
VERIFY(scripting_mode == HTML::ParserScriptingMode::Inert || scripting_mode == HTML::ParserScriptingMode::Fragment);
// 2. If context's node document is an XML document, then set algorithm to the XML fragment parsing algorithm.
// 2. Let newChildren be null.
Vector<GC::Root<Node>> new_children;
// 3. If context's node document is an XML document, then set newChildren to the result of invoking the XML fragment parsing algorithm given context and markup.
if (document().is_xml_document()) {
algorithm = XMLFragmentParser::parse_xml_fragment;
new_children = TRY(XMLFragmentParser::parse_xml_fragment(*this, markup));
}
// 4. Otherwise, set newChildren to the result of invoking the HTML fragment parsing algorithm given context, markup, false, and scriptingMode.
else {
new_children = TRY(HTML::HTMLParser::parse_html_fragment(*this, markup, HTML::HTMLParser::AllowDeclarativeShadowRoots::No, scripting_mode));
}
// 3. Let newChildren be the result of invoking algorithm given context and markup.
auto new_children = TRY(algorithm(*this, markup, HTML::HTMLParser::AllowDeclarativeShadowRoots::No));
// 4. Let fragment be a new DocumentFragment whose node document is context's node document.
// 5. Let fragment be a new DocumentFragment whose node document is context's node document.
auto fragment = realm().create<DOM::DocumentFragment>(document());
// 5. For each node of newChildren, in tree order: append node to fragment.
// 6. For each node of newChildren, in tree order: append node to fragment.
for (auto& child : new_children)
TRY(fragment->append_child(*child));
// 6. Return fragment.
// 7. Return fragment.
return fragment;
}

View file

@ -24,6 +24,7 @@
#include <LibWeb/Export.h>
#include <LibWeb/HTML/AttributeNames.h>
#include <LibWeb/HTML/EventLoop/Task.h>
#include <LibWeb/HTML/Parser/ParserScriptingMode.h>
#include <LibWeb/HTML/ScrollOptions.h>
#include <LibWeb/HTML/TagNames.h>
#include <LibWeb/HTML/TokenizedFeatures.h>
@ -254,7 +255,7 @@ public:
CSS::StyleSheetList& document_or_shadow_root_style_sheets();
ElementByIdMap& document_or_shadow_root_element_by_id_map();
WebIDL::ExceptionOr<GC::Ref<DOM::DocumentFragment>> parse_fragment(StringView markup);
WebIDL::ExceptionOr<GC::Ref<DOM::DocumentFragment>> parse_fragment(StringView markup, HTML::ParserScriptingMode = HTML::ParserScriptingMode::Inert);
[[nodiscard]] GC::Ptr<Element const> element_to_inherit_style_from(Optional<CSS::PseudoElement>) const;

View file

@ -1281,20 +1281,8 @@ WebIDL::ExceptionOr<GC::Ref<DocumentFragment>> Range::create_contextual_fragment
element = TRY(DOM::create_element(node->document(), HTML::TagNames::body, Namespace::HTML));
}
// 7. Let fragment node be the result of invoking the fragment parsing algorithm steps with element and compliantString.
auto fragment_node = TRY(element->parse_fragment(compliant_string.to_utf8_but_should_be_ported_to_utf16()));
// 8. For each script of fragment node's script element descendants:
fragment_node->for_each_in_subtree_of_type<HTML::HTMLScriptElement>([&](HTML::HTMLScriptElement& script_element) {
// 8.1 Set scripts already started to false.
script_element.unmark_as_already_started({});
// 8.2 Set scripts parser document to null.
script_element.unmark_as_parser_inserted({});
return TraversalDecision::Continue;
});
// 5. Return fragment node.
return fragment_node;
// 7. Return the result of invoking the fragment parsing algorithm steps with element, compliantString, and Fragment.
return element->parse_fragment(compliant_string.to_utf8_but_should_be_ported_to_utf16(), HTML::ParserScriptingMode::Fragment);
}
}

View file

@ -1658,7 +1658,8 @@ void Navigable::populate_session_history_entry_document(
auto error_url = result->redirected_url.value_or(url);
auto error_html = load_error_page(error_url, error_message).release_value_but_fixme_should_propagate_errors();
output->document = create_document_for_inline_content(this, navigation_id, user_involvement, [this, error_html](auto& document) {
auto parser = HTML::HTMLParser::create(document, error_html, "utf-8"sv);
auto scripting_mode = document.is_scripting_enabled() ? HTML::ParserScriptingMode::Normal : HTML::ParserScriptingMode::Disabled;
auto parser = HTMLParser::create(document, error_html, scripting_mode, "utf-8"sv);
document.set_url(URL::about_error());
parser->run();

View file

@ -157,9 +157,9 @@ static bool is_html_integration_point(DOM::Element const& element)
return false;
}
HTMLParser::HTMLParser(DOM::Document& document, StringView input, StringView encoding)
HTMLParser::HTMLParser(DOM::Document& document, ParserScriptingMode scripting_mode, StringView input, StringView encoding)
: m_tokenizer(input, encoding)
, m_scripting_enabled(document.is_scripting_enabled())
, m_scripting_mode(scripting_mode)
, m_document(document)
{
m_tokenizer.set_parser({}, *this);
@ -172,8 +172,8 @@ HTMLParser::HTMLParser(DOM::Document& document, StringView input, StringView enc
m_document->set_encoding(MUST(String::from_utf8(standardized_encoding.value())));
}
HTMLParser::HTMLParser(DOM::Document& document)
: m_scripting_enabled(document.is_scripting_enabled())
HTMLParser::HTMLParser(DOM::Document& document, ParserScriptingMode scripting_mode)
: m_scripting_mode(scripting_mode)
, m_document(document)
{
m_document->set_parser({}, *this);
@ -1170,16 +1170,16 @@ void HTMLParser::handle_in_head(HTMLToken& token)
return;
}
// -> A start tag whose tag name is "noscript", if the scripting flag is enabled
// -> A start tag whose tag name is "noscript", if scripting mode is not Disabled
// -> A start tag whose tag name is one of: "noframes", "style"
if (token.is_start_tag() && ((token.tag_name() == HTML::TagNames::noscript && m_scripting_enabled) || token.tag_name() == HTML::TagNames::noframes || token.tag_name() == HTML::TagNames::style)) {
if (token.is_start_tag() && ((token.tag_name() == HTML::TagNames::noscript && m_scripting_mode != ParserScriptingMode::Disabled) || token.tag_name() == HTML::TagNames::noframes || token.tag_name() == HTML::TagNames::style)) {
// Follow the generic raw text element parsing algorithm.
parse_generic_raw_text_element(token);
return;
}
// -> A start tag whose tag name is "noscript", if the scripting flag is disabled
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::noscript && !m_scripting_enabled) {
// -> A start tag whose tag name is "noscript", if scripting mode is Disabled
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::noscript && m_scripting_mode == ParserScriptingMode::Disabled) {
// Insert an HTML element for the token.
(void)insert_html_element(token);
@ -1200,18 +1200,26 @@ void HTMLParser::handle_in_head(HTMLToken& token)
auto element = create_element_for(token, Namespace::HTML, *adjusted_insertion_location.parent);
auto& script_element = as<HTMLScriptElement>(*element);
// 3. Set the element's parser document to the Document, and set the element's force async to false.
script_element.set_parser_document(Badge<HTMLParser> {}, document());
// 3. If the scripting mode is not Fragment, then set the element's parser document to the Document.
// NOTE: The Fragment scripting mode treats parser-inserted scripts as if they were not parser-inserted,
// allowing, for example, executing scripts when applying a fragment created by createContextualFragment().
if (m_scripting_mode != ParserScriptingMode::Fragment)
script_element.set_parser_document(Badge<HTMLParser> {}, document());
// 4. Set the element's force async to false.
// NOTE: This ensures that, if the script is external, any document.write() calls in the script will execute
// in-line, instead of blowing the document away, as would happen in most other cases. It also prevents
// the script from executing until the end tag is seen.
script_element.set_force_async(Badge<HTMLParser> {}, false);
script_element.set_source_line_number({}, token.start_position().line + 1); // FIXME: This +1 is incorrect for script tags whose script does not start on a new line
// 4. If the parser was created as part of the HTML fragment parsing algorithm, then set the script element's
// already started to true. (fragment case)
if (m_parsing_fragment) {
// 5. If the parser's scripting mode is Inert, then set the script element's already started to true. (fragment case)
if (m_scripting_mode == ParserScriptingMode::Inert) {
script_element.set_already_started(Badge<HTMLParser> {}, true);
}
// 5. If the parser was invoked via the document.write() or document.writeln() methods, then optionally set the
// 6. If the parser was invoked via the document.write() or document.writeln() methods, then optionally set the
// script element's already started to true. (For example, the user agent might use this clause to prevent
// execution of cross-origin scripts inserted via document.write() under slow network conditions, or when
// the page has already taken a long time to load.)
@ -1219,19 +1227,19 @@ void HTMLParser::handle_in_head(HTMLToken& token)
TODO();
}
// 6. Insert the newly created element at the adjusted insertion location.
// 7. Insert the newly created element at the adjusted insertion location.
adjusted_insertion_location.parent->insert_before(*element, adjusted_insertion_location.insert_before_sibling, false);
// 7. Push the element onto the stack of open elements so that it is the new current node.
// 8. Push the element onto the stack of open elements so that it is the new current node.
m_stack_of_open_elements.push(element);
// 8. Switch the tokenizer to the script data state.
// 9. Switch the tokenizer to the script data state.
m_tokenizer.switch_to({}, HTMLTokenizer::State::ScriptData);
// 9. Set the original insertion mode to the current insertion mode.
// 10. Set the original insertion mode to the current insertion mode.
m_original_insertion_mode = m_insertion_mode;
// 10. Switch the insertion mode to "text".
// 11. Switch the insertion mode to "text".
m_insertion_mode = InsertionMode::Text;
return;
}
@ -3029,8 +3037,8 @@ void HTMLParser::handle_in_body(HTMLToken& token)
}
// -> A start tag whose tag name is "noembed"
// -> A start tag whose tag name is "noscript", if the scripting flag is enabled
if (token.is_start_tag() && ((token.tag_name() == HTML::TagNames::noembed) || (token.tag_name() == HTML::TagNames::noscript && m_scripting_enabled))) {
// -> A start tag whose tag name is "noscript", if scripting mode is not Disabled
if (token.is_start_tag() && ((token.tag_name() == HTML::TagNames::noembed) || (token.tag_name() == HTML::TagNames::noscript && m_scripting_mode != ParserScriptingMode::Disabled))) {
// Follow the generic raw text element parsing algorithm.
parse_generic_raw_text_element(token);
return;
@ -4944,9 +4952,12 @@ DOM::Document& HTMLParser::document()
}
// https://html.spec.whatwg.org/multipage/parsing.html#parsing-html-fragments
WebIDL::ExceptionOr<Vector<GC::Root<DOM::Node>>> HTMLParser::parse_html_fragment(DOM::Element& context_element, StringView markup, AllowDeclarativeShadowRoots allow_declarative_shadow_roots)
WebIDL::ExceptionOr<Vector<GC::Root<DOM::Node>>> HTMLParser::parse_html_fragment(DOM::Element& context_element, StringView markup, AllowDeclarativeShadowRoots allow_declarative_shadow_roots, ParserScriptingMode scripting_mode)
{
// 1. Let document be a Document node whose type is "html".
// 1. Assert: scriptingMode is either Inert or Fragment.
VERIFY(scripting_mode == HTML::ParserScriptingMode::Inert || scripting_mode == HTML::ParserScriptingMode::Fragment);
// 2. Let document be a Document node whose type is "html".
auto temp_document = DOM::Document::create_for_fragment_parsing(context_element.realm());
temp_document->set_document_type(DOM::Document::Type::HTML);
@ -4955,24 +4966,32 @@ WebIDL::ExceptionOr<Vector<GC::Root<DOM::Node>>> HTMLParser::parse_html_fragment
// Spec issue: https://github.com/whatwg/html/issues/12210
temp_document->set_about_base_url(context_element.document().about_base_url());
// 2. If context's node document is in quirks mode, then set document's mode to "quirks".
if (context_element.document().in_quirks_mode())
// 3. Let contextDocument be context's node document.
auto& context_document = context_element.document();
// 4. If contextDocument is in quirks mode, then set document's mode to "quirks".
if (context_document.in_quirks_mode()) {
temp_document->set_quirks_mode(DOM::QuirksMode::Yes);
// 3. Otherwise, if context's node document is in limited-quirks mode, then set document's mode to "limited-quirks".
else if (context_element.document().in_limited_quirks_mode())
}
// 5. Otherwise, if context's node document is in limited-quirks mode, then set document's mode to "limited-quirks".
else if (context_element.document().in_limited_quirks_mode()) {
temp_document->set_quirks_mode(DOM::QuirksMode::Limited);
}
// 4. If allowDeclarativeShadowRoots is true, then set document's allow declarative shadow roots to true.
// 6. If allowDeclarativeShadowRoots is true, then set document's allow declarative shadow roots to true.
if (allow_declarative_shadow_roots == AllowDeclarativeShadowRoots::Yes)
temp_document->set_allow_declarative_shadow_roots(true);
// 5. Create a new HTML parser, and associate it with document.
auto parser = HTMLParser::create(*temp_document, markup, "utf-8"sv);
// 7. Create a new HTML parser, and associate it with document.
// 8. If contextDocument's scripting is disabled, then set scriptingMode to Disabled.
// 9. Set the parser's scripting mode to scriptingMode.
if (context_element.document().is_scripting_disabled())
scripting_mode = HTML::ParserScriptingMode::Disabled;
auto parser = HTMLParser::create(*temp_document, markup, scripting_mode, "utf-8"sv);
parser->m_context_element = context_element;
parser->m_parsing_fragment = true;
// 6. Set the state of the HTML parser's tokenization stage as follows, switching on the context element:
// 10. Set the state of the HTML parser's tokenization stage as follows, switching on the context element:
// - title
// - textarea
if (context_element.local_name().is_one_of(HTML::TagNames::title, HTML::TagNames::textarea)) {
@ -4995,8 +5014,8 @@ WebIDL::ExceptionOr<Vector<GC::Root<DOM::Node>>> HTMLParser::parse_html_fragment
}
// - noscript
else if (context_element.local_name().is_one_of(HTML::TagNames::noscript)) {
// If the scripting flag is enabled, switch the tokenizer to the RAWTEXT state. Otherwise, leave the tokenizer in the data state.
if (context_element.document().is_scripting_enabled())
// If scripting mode is not Disabled, switch the tokenizer to the RAWTEXT state. Otherwise, leave the tokenizer in the data state.
if (scripting_mode != HTML::ParserScriptingMode::Disabled)
parser->m_tokenizer.switch_to({}, HTMLTokenizer::State::RAWTEXT);
}
// - plaintext
@ -5009,37 +5028,37 @@ WebIDL::ExceptionOr<Vector<GC::Root<DOM::Node>>> HTMLParser::parse_html_fragment
// Leave the tokenizer in the data state.
}
// 7. Let root be the result of creating an element given document, "html", the HTML namespace, null, null, false,
// 11. Let root be the result of creating an element given document, "html", the HTML namespace, null, null, false,
// and context's custom element registry.
auto root = MUST(create_element(context_element.document(), HTML::TagNames::html, Namespace::HTML, {}, {}, false, context_element.custom_element_registry()));
// 8. Append root to document.
// 12. Append root to document.
MUST(temp_document->append_child(root));
// 9. Set up the HTML parser's stack of open elements so that it contains just the single element root.
// 13. Set up the HTML parser's stack of open elements so that it contains just the single element root.
parser->m_stack_of_open_elements.push(root);
// 10. If context is a template element, then push "in template" onto the stack of template insertion modes
// 14. If context is a template element, then push "in template" onto the stack of template insertion modes
// so that it is the new current template insertion mode.
if (context_element.local_name() == HTML::TagNames::template_)
parser->m_stack_of_template_insertion_modes.append(InsertionMode::InTemplate);
// FIXME: 11. Create a start tag token whose name is the local name of context and whose attributes are the attributes of context.
// FIXME: 15. Create a start tag token whose name is the local name of context and whose attributes are the attributes of context.
// Let this start tag token be the start tag token of context; e.g. for the purposes of determining if it is an HTML integration point.
// 12. Reset the parser's insertion mode appropriately.
// 16. Reset the parser's insertion mode appropriately.
parser->reset_the_insertion_mode_appropriately();
// 13. Set the HTML parser's form element pointer to the nearest node to context that is a form element
// 17. Set the HTML parser's form element pointer to the nearest node to context that is a form element
// (going straight up the ancestor chain, and including the element itself, if it is a form element), if any.
// (If there is no such form element, the form element pointer keeps its initial value, null.)
parser->m_form_element = context_element.first_ancestor_of_type<HTMLFormElement>();
// 14. Place the input into the input stream for the HTML parser just created. The encoding confidence is irrelevant.
// 15. Start the HTML parser and let it run until it has consumed all the characters just inserted into the input stream.
// 18. Place the input into the input stream for the HTML parser just created. The encoding confidence is irrelevant.
// 19. Start the HTML parser and let it run until it has consumed all the characters just inserted into the input stream.
parser->run(context_element.document().url());
// 16. Return root's children, in tree order.
// 20. Return root's children, in tree order.
Vector<GC::Root<DOM::Node>> children;
while (GC::Ptr<DOM::Node> child = root->first_child()) {
MUST(root->remove_child(*child));
@ -5051,21 +5070,23 @@ WebIDL::ExceptionOr<Vector<GC::Root<DOM::Node>>> HTMLParser::parse_html_fragment
GC::Ref<HTMLParser> HTMLParser::create_for_scripting(DOM::Document& document)
{
return document.realm().create<HTMLParser>(document);
auto scripting_mode = document.is_scripting_enabled() ? ParserScriptingMode::Normal : ParserScriptingMode::Disabled;
return document.realm().create<HTMLParser>(document, scripting_mode);
}
GC::Ref<HTMLParser> HTMLParser::create_with_uncertain_encoding(DOM::Document& document, ByteBuffer const& input, Optional<MimeSniff::MimeType> maybe_mime_type)
{
auto scripting_mode = document.is_scripting_enabled() ? ParserScriptingMode::Normal : ParserScriptingMode::Disabled;
if (document.has_encoding())
return document.realm().create<HTMLParser>(document, input, document.encoding().value().to_byte_string());
return document.realm().create<HTMLParser>(document, scripting_mode, input, document.encoding().value().to_byte_string());
auto encoding = run_encoding_sniffing_algorithm(document, input, maybe_mime_type);
dbgln_if(HTML_PARSER_DEBUG, "The encoding sniffing algorithm returned encoding '{}'", encoding);
return document.realm().create<HTMLParser>(document, input, encoding);
return document.realm().create<HTMLParser>(document, scripting_mode, input, encoding);
}
GC::Ref<HTMLParser> HTMLParser::create(DOM::Document& document, StringView input, StringView encoding)
GC::Ref<HTMLParser> HTMLParser::create(DOM::Document& document, StringView input, ParserScriptingMode scripting_mode, StringView encoding)
{
return document.realm().create<HTMLParser>(document, input, encoding);
return document.realm().create<HTMLParser>(document, scripting_mode, input, encoding);
}
enum class AttributeMode {

View file

@ -12,6 +12,7 @@
#include <LibWeb/Export.h>
#include <LibWeb/HTML/Parser/HTMLTokenizer.h>
#include <LibWeb/HTML/Parser/ListOfActiveFormattingElements.h>
#include <LibWeb/HTML/Parser/ParserScriptingMode.h>
#include <LibWeb/HTML/Parser/StackOfOpenElements.h>
#include <LibWeb/MimeSniff/MimeType.h>
#include <LibWeb/Platform/Timer.h>
@ -52,7 +53,7 @@ public:
static GC::Ref<HTMLParser> create_for_scripting(DOM::Document&);
static GC::Ref<HTMLParser> create_with_uncertain_encoding(DOM::Document&, ByteBuffer const& input, Optional<MimeSniff::MimeType> maybe_mime_type = {});
static GC::Ref<HTMLParser> create(DOM::Document&, StringView input, StringView encoding);
static GC::Ref<HTMLParser> create(DOM::Document&, StringView input, ParserScriptingMode, StringView encoding);
void run(HTMLTokenizer::StopAtInsertionPoint = HTMLTokenizer::StopAtInsertionPoint::No);
void run(URL::URL const&, HTMLTokenizer::StopAtInsertionPoint = HTMLTokenizer::StopAtInsertionPoint::No);
@ -64,7 +65,7 @@ public:
No,
Yes,
};
static WebIDL::ExceptionOr<Vector<GC::Root<DOM::Node>>> parse_html_fragment(DOM::Element& context_element, StringView, AllowDeclarativeShadowRoots = AllowDeclarativeShadowRoots::No);
static WebIDL::ExceptionOr<Vector<GC::Root<DOM::Node>>> parse_html_fragment(DOM::Element& context_element, StringView markup, AllowDeclarativeShadowRoots = AllowDeclarativeShadowRoots::No, ParserScriptingMode = ParserScriptingMode::Inert);
enum class SerializableShadowRoots {
No,
@ -93,8 +94,8 @@ public:
size_t script_nesting_level() const { return m_script_nesting_level; }
private:
HTMLParser(DOM::Document&, StringView input, StringView encoding);
HTMLParser(DOM::Document&);
HTMLParser(DOM::Document&, ParserScriptingMode, StringView input, StringView encoding);
HTMLParser(DOM::Document&, ParserScriptingMode);
virtual void visit_edges(Cell::Visitor&) override;
virtual void initialize(JS::Realm&) override;
@ -195,9 +196,8 @@ private:
bool m_frameset_ok { true };
bool m_parsing_fragment { false };
// https://html.spec.whatwg.org/multipage/parsing.html#scripting-flag
// The scripting flag is set to "enabled" if scripting was enabled for the Document with which the parser is associated when the parser was created, and "disabled" otherwise.
bool m_scripting_enabled { true };
// https://html.spec.whatwg.org/multipage/parsing.html#scripting-mode
ParserScriptingMode m_scripting_mode {};
bool m_invoked_via_document_write { false };
bool m_aborted { false };

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2026, Shannon Booth <shannon@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Types.h>
namespace Web::HTML {
// https://html.spec.whatwg.org/multipage/parsing.html#parser-scripting-mode
enum class ParserScriptingMode : u8 {
// Scripts are processed when inserted, respecting async and defer attributes and blocking the parser when encountering a classic script.
Normal,
// Scripts are disabled, and the noscript element can represent fallback content.
Disabled,
// Scripts are enabled, however they are marked as already started, essentially preventing them from executing.
// This is the default mode of the HTML fragment parsing algorithm.
Inert,
// Scripts are executed as soon as they are inserted into the document as part of a the HTML fragment parsing
// algorithm, ignoring async and defer attributes. This mode is used by createContextualFragment().
Fragment,
};
}

View file

@ -308,7 +308,8 @@ void XMLHttpRequest::set_document_response()
charset = "UTF-8"_string;
// 5.4. Let document be a document that represents the result parsing xhrs received bytes following the rules set forth in the HTML Standard for an HTML parser with scripting disabled and a known definite encoding charset.
auto parser = HTML::HTMLParser::create(*document, m_received_bytes, charset.value());
auto scripting_mode = document->is_scripting_enabled() ? HTML::ParserScriptingMode::Normal : HTML::ParserScriptingMode::Disabled;
auto parser = HTML::HTMLParser::create(*document, m_received_bytes, scripting_mode, charset.value());
parser->run(document->url());
// 5.5. Flag document as an HTML document.

View file

@ -15,7 +15,7 @@
namespace Web {
// https://html.spec.whatwg.org/multipage/xhtml.html#parsing-xhtml-fragments
WebIDL::ExceptionOr<Vector<GC::Root<DOM::Node>>> XMLFragmentParser::parse_xml_fragment(DOM::Element& context, StringView input, HTML::HTMLParser::AllowDeclarativeShadowRoots allow_declarative_shadow_roots)
WebIDL::ExceptionOr<Vector<GC::Root<DOM::Node>>> XMLFragmentParser::parse_xml_fragment(DOM::Element& context, StringView input)
{
// 1. Create a new XML parser.
// NB: The feed will be used to create the parser below
@ -69,8 +69,6 @@ WebIDL::ExceptionOr<Vector<GC::Root<DOM::Node>>> XMLFragmentParser::parse_xml_fr
GC::Ptr<DOM::Document> document = DOM::Document::create(context.realm());
document->set_document_type(DOM::Document::Type::XML);
if (allow_declarative_shadow_roots == HTML::HTMLParser::AllowDeclarativeShadowRoots::Yes)
document->set_allow_declarative_shadow_roots(true);
XML::Parser parser(feed.string_view(), { .resolve_named_html_entity = resolve_named_html_entity });
XMLDocumentBuilder builder { *document, XMLScriptingSupport::Disabled };

View file

@ -14,7 +14,7 @@ namespace Web {
class XMLFragmentParser final {
public:
static WebIDL::ExceptionOr<Vector<GC::Root<DOM::Node>>> parse_xml_fragment(DOM::Element& context, StringView markup, HTML::HTMLParser::AllowDeclarativeShadowRoots = HTML::HTMLParser::AllowDeclarativeShadowRoots::No);
static WebIDL::ExceptionOr<Vector<GC::Root<DOM::Node>>> parse_xml_fragment(DOM::Element& context, StringView markup);
};
}

View file

@ -0,0 +1,9 @@
Harness status: OK
Found 1 tests
1 Pass
Pass
HTML5 Sandbox: an iframe with same-origin and no allow-scripts does not
run scripts from a contextual fragment.

View file

@ -0,0 +1,38 @@
<!doctype html>
<html>
<head>
<title>
HTML5 Sandbox: an iframe with same-origin and no allow-scripts does not
run scripts from a contextual fragment.
</title>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
<link
rel="help"
href="http://dev.w3.org/html5/spec/Overview.html#attr-iframe-sandbox"
/>
<meta
name="assert"
content="an iframe with same-origin and no allow-scripts does not run scripts from a contextual fragment."
/>
<script src="../../../../resources/testharness.js"></script>
<script src="../../../../resources/testharnessreport.js"></script>
</head>
<body>
<script type="text/javascript">
test((t) => {
const iframe = document.createElement("iframe");
iframe.sandbox = "allow-same-origin";
document.body.appendChild(iframe);
const doc = iframe.contentDocument;
const html =
`<script>window.did_run_script = true</` +
`script><noscript><div id=nos></div>`;
iframe.contentWindow.did_run_script = false;
const fragment = doc.createRange().createContextualFragment(html);
doc.body.appendChild(fragment);
assert_false(iframe.contentWindow.did_run_script);
assert_not_equals(doc.getElementById("nos"), null);
});
</script>
</body>
</html>