LibWeb: Don't construct stylesheet when modifying CSSStyleSheet rules
Some checks are pending
CI / Lagom (arm64, Sanitizer_CI, false, macos-15, macOS, Clang) (push) Waiting to run
CI / Lagom (x86_64, Fuzzers_CI, false, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, false, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, true, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (arm64, macos-15, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (x86_64, ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run

Previously, `CSSStyleSheet.replace()` and `CSSStyleSheet.replaceSync()`
parsed the given CSS text into a temporary stylesheet object, from
which a list of rules was extracted. Doing this had the unintended
side-effect that a fetch request would be started if the given CSS text
referenced any external resources. This fetch request would cause a
crash, since the temporary stylesheet object didn't set the constructed
flag, or constructor document. We now parse the given CSS text as a
list of rules without constructing a temporary stylesheet.
This commit is contained in:
Tim Ledbetter 2025-04-15 18:01:54 +01:00 committed by Sam Atkins
commit ca200142e9
Notes: github-actions[bot] 2025-04-16 21:04:15 +00:00
5 changed files with 95 additions and 6 deletions

View file

@ -1,7 +1,7 @@
/*
* Copyright (c) 2019-2022, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2022-2024, Sam Atkins <sam@ladybird.org>
* Copyright (c) 2024, Tim Ledbetter <timledbetter@gmail.com>
* Copyright (c) 2024-2025, Tim Ledbetter <tim.ledbetter@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -207,8 +207,7 @@ GC::Ref<WebIDL::Promise> CSSStyleSheet::replace(String text)
HTML::TemporaryExecutionContext execution_context { realm, HTML::TemporaryExecutionContext::CallbacksEnabled::Yes };
// 1. Let rules be the result of running parse a stylesheets contents from text.
auto parsed_stylesheet = parse_css_stylesheet(make_parsing_params(), text);
auto& rules = parsed_stylesheet->rules();
auto rules = CSS::Parser::Parser::create(make_parsing_params(), text).parse_as_stylesheet_contents();
// 2. If rules contains one or more @import rules, remove those rules from rules.
GC::RootVector<GC::Ref<CSSRule>> rules_without_import(realm.heap());
@ -240,8 +239,7 @@ WebIDL::ExceptionOr<void> CSSStyleSheet::replace_sync(StringView text)
return WebIDL::NotAllowedError::create(realm(), "Can't call replaceSync() on non-modifiable stylesheets"_string);
// 2. Let rules be the result of running parse a stylesheets contents from text.
auto parsed_stylesheet = parse_css_stylesheet(make_parsing_params(), text);
auto& rules = parsed_stylesheet->rules();
auto rules = CSS::Parser::Parser::create(make_parsing_params(), text).parse_as_stylesheet_contents();
// 3. If rules contains one or more @import rules, remove those rules from rules.
GC::RootVector<GC::Ref<CSSRule>> rules_without_import(realm().heap());
@ -250,7 +248,7 @@ WebIDL::ExceptionOr<void> CSSStyleSheet::replace_sync(StringView text)
rules_without_import.append(rule);
}
// 4.Set sheets CSS rules to rules.
// 4. Set sheets CSS rules to rules.
m_rules->set_rules({}, rules_without_import);
return {};

View file

@ -118,6 +118,22 @@ Vector<Rule> Parser::parse_a_stylesheets_contents(TokenStream<T>& input)
return consume_a_stylesheets_contents(input);
}
GC::RootVector<GC::Ref<CSSRule>> Parser::parse_as_stylesheet_contents()
{
auto raw_rules = parse_a_stylesheets_contents(m_token_stream);
GC::RootVector<GC::Ref<CSSRule>> rules(realm().heap());
for (auto const& raw_rule : raw_rules) {
auto rule = convert_to_rule(raw_rule, Nested::No);
if (!rule) {
log_parse_error();
continue;
}
rules.append(*rule);
}
return rules;
}
// https://drafts.csswg.org/css-syntax/#parse-a-css-stylesheet
GC::Ref<CSS::CSSStyleSheet> Parser::parse_as_css_stylesheet(Optional<::URL::URL> location, Vector<NonnullRefPtr<MediaQuery>> media_query_list)
{

View file

@ -100,6 +100,7 @@ public:
Vector<Descriptor> parse_as_list_of_descriptors(AtRuleID);
CSSRule* parse_as_css_rule();
Optional<StyleProperty> parse_as_supports_condition();
GC::RootVector<GC::Ref<CSSRule>> parse_as_stylesheet_contents();
enum class SelectorParsingMode {
Standard,