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:
parent
290db9d690
commit
8642801889
13 changed files with 181 additions and 89 deletions
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
|
|
|
|||
30
Libraries/LibWeb/HTML/Parser/ParserScriptingMode.h
Normal file
30
Libraries/LibWeb/HTML/Parser/ParserScriptingMode.h
Normal 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,
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -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 xhr’s 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.
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
@ -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>
|
||||
Loading…
Reference in a new issue