fix(selectors): accept webkit compatibility pseudos

This commit is contained in:
ldm0
2026-09-28 01:46:58 +08:00
parent 37224fef22
commit f07b2abff2
5 changed files with 164 additions and 38 deletions
@@ -30,6 +30,7 @@ content-security-policy/resource-hints/prefetch-generate-directives.html
content-security-policy/resource-hints/prefetch-no-csp.html
content-security-policy/sandbox/autoplay-disabled-by-csp.html
content-security-policy/sandbox/window-reuse-sandboxed.html
content-security-policy/script-src/non-nonceable-elements.html
content-security-policy/script-src/nonce-enforce-blocked.html
content-security-policy/script-src/script-src-trusted_types_eval_DedicatedWorker.html
content-security-policy/securitypolicyviolation/blockeduri-inline.html
@@ -2552,6 +2553,7 @@ dom/ranges/tentative/OpaqueRange-range-updates.html
dom/ranges/tentative/OpaqueRange-supported-elements.html
dom/ranges/tentative/OpaqueRange-unsupported-elements.html
dom/ranges/tentative/OpaqueRange-validation.html
domparsing/DOMParser-parseFromString-html.html
domparsing/DOMParser-parseFromString-url-base-pushstate.html
domparsing/DOMParser-parseFromString-url-base.html
domparsing/DOMParser-parseFromString-url-moretests.html
@@ -3607,15 +3609,24 @@ svg/types/scripted/SVGLengthList-basics.html
svg/types/scripted/SVGList-parse-invalid-clears-items.html
svg/types/scripted/SVGMatrix-tentative.html
svg/types/scripted/SVGPoint.html
trusted-types/Document-write-appending-line-feed.html
trusted-types/Document-write.html
trusted-types/Element-setAttribute-respects-Elements-node-documents-globals-CSP-after-adoption-from-non-TT-realm.html
trusted-types/GlobalEventHandlers-onclick.html
trusted-types/HTMLElement-generic.html
trusted-types/ServiceWorkerContainer-register-from-DedicatedWorker.https.html
trusted-types/ServiceWorkerContainer-register-from-ServiceWorker.https.html
trusted-types/ServiceWorkerContainer-register-from-SharedWorker.https.html
trusted-types/TrustedType-AttributeNodes.html
trusted-types/TrustedTypePolicyFactory-constants.html
trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-none.html
trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests.html
trusted-types/TrustedTypePolicyFactory-defaultPolicy.html
trusted-types/TrustedTypePolicyFactory-getAttributeType-namespace.html
trusted-types/TrustedTypePolicyFactory-getAttributeType-svg.html
trusted-types/TrustedTypePolicyFactory-getAttributeType.html
trusted-types/Window-TrustedTypes.html
trusted-types/block-Document-execCommand.html
trusted-types/block-string-assignment-to-Document-write.html
trusted-types/block-string-assignment-to-Element-outerHTML.html
trusted-types/block-string-assignment-to-Element-setAttribute.html
@@ -3627,8 +3638,13 @@ trusted-types/block-string-assignment-to-attribute-via-attribute-node.html
trusted-types/eval-function-constructor-untrusted-arguments-and-applying-default-policy.html
trusted-types/eval-function-constructor.html
trusted-types/inheriting-csp-for-local-schemes.html
trusted-types/legacy-trusted-script-urls.html
trusted-types/modify-attributes-in-callback.html
trusted-types/require-trusted-types-for-TypeError-belongs-to-the-global-object-realm.html
trusted-types/script-enforcement-006.html
trusted-types/script-enforcement-007.html
trusted-types/script-enforcement-010.html
trusted-types/script-enforcement-011.html
trusted-types/set-attributes-require-trusted-types-default-policy.html
trusted-types/set-attributes-require-trusted-types-no-default-policy-error-cases.html
trusted-types/set-attributes-require-trusted-types-no-default-policy.html
@@ -3637,17 +3653,27 @@ trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-001.html
trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-002.html
trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-003.html
trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-004-worker.html
trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-005.html
trusted-types/trusted-types-createHTMLDocument.html
trusted-types/trusted-types-duplicate-names-list.html
trusted-types/trusted-types-duplicate-names-without-enforcement.html
trusted-types/trusted-types-duplicate-names.html
trusted-types/trusted-types-eval-reporting-report-only.html
trusted-types/trusted-types-event-handlers.html
trusted-types/trusted-types-report-only.html
trusted-types/trusted-types-reporting-check-report-DedicatedWorker-create-policy.html
trusted-types/trusted-types-reporting-check-report-DedicatedWorker-sink-mismatch.html
trusted-types/trusted-types-reporting-clipping-of-sample.html
trusted-types/trusted-types-reporting-for-DedicatedWorker-ServiceWorkerContainer-register.https.html
trusted-types/trusted-types-reporting-for-Document-execCommand.html
trusted-types/trusted-types-reporting-for-Document-write.html
trusted-types/trusted-types-reporting-for-Element-setAttribute.html
trusted-types/trusted-types-reporting-for-HTMLIFrameElement-srcdoc.html
trusted-types/trusted-types-reporting-for-ServiceWorker-ServiceWorkerContainer-register.https.html
trusted-types/trusted-types-reporting-for-SharedWorker-ServiceWorkerContainer-register.https.html
trusted-types/trusted-types-reporting.html
trusted-types/trusted-types-secondary-document.html
trusted-types/trusted-types-svg-script-set-href.html
uievents/interface/click-event.htm
uievents/order-of-events/focus-events/focus-automated-blink-webkit.html
url/a-element.html?exclude=(file|javascript|mailto)
@@ -211,7 +211,6 @@ content-security-policy/script-src/hash-always-converted-to-utf-8/iso-8859-9.htm
content-security-policy/script-src/hash-always-converted-to-utf-8/utf-8-lone-surrogate.html
content-security-policy/script-src/hash-always-converted-to-utf-8/utf-8.html
content-security-policy/script-src/javascript-window-open-blocked.html
content-security-policy/script-src/non-nonceable-elements.html
content-security-policy/script-src/script-src-1_1.html
content-security-policy/script-src/script-src-1_10_1.html
content-security-policy/script-src/script-src-1_2.html
@@ -4098,7 +4097,6 @@ dom/traversal/TreeWalker.html
dom/window-extends-event-target.html
dom/xpath-result-single-node-value-nullable.html
domparsing/DOMParser-parseFromString-encoding.html
domparsing/DOMParser-parseFromString-html.html
domparsing/DOMParser-parseFromString-stylesheets.html
domparsing/DOMParser-parseFromString-xml-parsererror.html
domparsing/createContextualFragment-in-detached-xml-document-crash.html
@@ -8604,14 +8602,12 @@ trusted-types/DedicatedWorker-eval.html
trusted-types/DedicatedWorker-importScripts.html
trusted-types/DedicatedWorker-setTimeout-setInterval.html
trusted-types/Document-execCommand.html
trusted-types/Document-write-appending-line-feed.html
trusted-types/Element-insertAdjacentHTML.html
trusted-types/Element-outerHTML.html
trusted-types/Element-setAttribute-respects-Elements-node-documents-globals-CSP-after-adoption-from-TT-realm.html
trusted-types/Element-setAttribute.html
trusted-types/Element-setAttributeNS.html
trusted-types/Element-toggleAttribute.html
trusted-types/GlobalEventHandlers-onclick.html
trusted-types/HTMLScriptElement-internal-slot.html
trusted-types/Node-multiple-arguments-tt-enforced.html
trusted-types/Node-multiple-arguments.html
@@ -8628,7 +8624,6 @@ trusted-types/SharedWorker-setTimeout-setInterval.html
trusted-types/TrustedTypePolicy-CSP-no-name.html
trusted-types/TrustedTypePolicy-CSP-wildcard.html
trusted-types/TrustedTypePolicy-createXXX.html
trusted-types/TrustedTypePolicyFactory-constants.html
trusted-types/TrustedTypePolicyFactory-createPolicy-createXYZTests.html
trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-case.html
trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-case2.html
@@ -8636,18 +8631,12 @@ trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-noNamesGiven.html
trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-none-none-name.html
trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-none-none.html
trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-none-skip.html
trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-none.html
trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-wildcard.html
trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests.html
trusted-types/TrustedTypePolicyFactory-createPolicy-non-tt-policy-name.html
trusted-types/TrustedTypePolicyFactory-createPolicy-unenforced.html
trusted-types/TrustedTypePolicyFactory-defaultPolicy.html
trusted-types/TrustedTypePolicyFactory-getAttributeType-namespace.html
trusted-types/TrustedTypePolicyFactory-getAttributeType-svg.html
trusted-types/TrustedTypePolicyFactory-isXXX.html
trusted-types/Window-block-eval-function-constructor.html
trusted-types/Window-setTimeout-setInterval.html
trusted-types/block-Document-execCommand.html
trusted-types/block-string-assignment-to-DOMParser-parseFromString.html
trusted-types/block-string-assignment-to-DedicatedWorker-setTimeout-setInterval.html
trusted-types/block-string-assignment-to-Document-parseHTMLUnsafe.html
@@ -8676,7 +8665,6 @@ trusted-types/eval-no-csp-no-tt.html
trusted-types/eval-with-non-trusted-script-object.html
trusted-types/eval-with-permissive-csp.html
trusted-types/get-trusted-types-compliant-attribute-value.html
trusted-types/legacy-trusted-script-urls.html
trusted-types/legacy-trusted-scripts.html
trusted-types/navigate-to-javascript-url-001.html
trusted-types/navigate-to-javascript-url-002.html
@@ -8695,10 +8683,6 @@ trusted-types/script-enforcement-002.html
trusted-types/script-enforcement-003.html
trusted-types/script-enforcement-004.html
trusted-types/script-enforcement-005.html
trusted-types/script-enforcement-006.html
trusted-types/script-enforcement-007.html
trusted-types/script-enforcement-010.html
trusted-types/script-enforcement-011.html
trusted-types/script-enforcement-012.html
trusted-types/script-enforcement-013.html
trusted-types/script-enforcement-014.html
@@ -8708,22 +8692,14 @@ trusted-types/script-enforcement-017.html
trusted-types/set-attributes-no-require-trusted-types.html
trusted-types/should-sink-type-mismatch-violation-be-blocked-by-csp-001.html
trusted-types/should-sink-type-mismatch-violation-be-blocked-by-csp-003.html
trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-005.html
trusted-types/trusted-types-duplicate-names-list-report-only.html
trusted-types/trusted-types-duplicate-names-list.html
trusted-types/trusted-types-duplicate-names-without-enforcement.html
trusted-types/trusted-types-duplicate-names.html
trusted-types/trusted-types-eval-reporting-no-unsafe-eval.html
trusted-types/trusted-types-eval-reporting-report-only.html
trusted-types/trusted-types-reporting-check-report-DedicatedWorker-create-policy.html
trusted-types/trusted-types-reporting-clipping-of-sample.html
trusted-types/trusted-types-reporting-for-DOMParser-parseFromString.html
trusted-types/trusted-types-reporting-for-DedicatedWorker-DedicatedWorker-constructor.html
trusted-types/trusted-types-reporting-for-DedicatedWorker-eval.html
trusted-types/trusted-types-reporting-for-DedicatedWorker-function-constructor.html
trusted-types/trusted-types-reporting-for-DedicatedWorker-importScripts.html
trusted-types/trusted-types-reporting-for-DedicatedWorker-setTimeout-setInterval.html
trusted-types/trusted-types-reporting-for-Document-execCommand.html
trusted-types/trusted-types-reporting-for-Document-parseHTMLUnsafe.html
trusted-types/trusted-types-reporting-for-Element-innerHTML.html
trusted-types/trusted-types-reporting-for-Element-insertAdjacentHTML.html
@@ -8751,11 +8727,9 @@ trusted-types/trusted-types-reporting-for-Window-SharedWorker-constructor.html
trusted-types/trusted-types-reporting-for-Window-eval.html
trusted-types/trusted-types-reporting-for-Window-function-constructor.html
trusted-types/trusted-types-reporting-for-Window-setTimeout-setInterval.html
trusted-types/trusted-types-reporting.html
trusted-types/trusted-types-sandbox-allow-scripts.html
trusted-types/trusted-types-sandbox-no-allow-scripts.html
trusted-types/trusted-types-source-file-path.html
trusted-types/trusted-types-svg-script-set-href.html
trusted-types/trusted-types-tojson.html
trusted-types/tt-block-eval.html
uievents/constructors/inputevent-constructor.html
+81 -5
View File
@@ -668,6 +668,43 @@ pub(crate) fn dom_api_selector_list_contains_known_pseudo_element(selector_text:
false
}
pub(crate) fn webkit_compat_pseudo_element_validation_selector(
selector_text: &str,
) -> Option<String> {
let mut input = ParserInput::new(selector_text);
let mut parser = Parser::new(&mut input);
let mut replacements = Vec::new();
while !parser.is_exhausted() {
let Ok(token) = parser.next_including_whitespace_and_comments().cloned() else {
return None;
};
if !matches!(token, Token::Colon) {
continue;
}
let Ok(Token::Colon) = parser.next_including_whitespace_and_comments().cloned() else {
continue;
};
let name_start = parser.position().byte_index();
let Ok(Token::Ident(name)) = parser.next_including_whitespace_and_comments().cloned()
else {
continue;
};
if is_unknown_webkit_pseudo_element_name(&name) {
replacements.push((name_start, parser.position().byte_index()));
}
}
if replacements.is_empty() {
return None;
}
let mut selector = selector_text.to_owned();
for (start, end) in replacements.into_iter().rev() {
selector.replace_range(start..end, "part(webkit-compat)");
}
Some(selector)
}
pub(crate) fn selector_list_has_invalid_terminal_pseudo_element_chain(selector_text: &str) -> bool {
let mut input = ParserInput::new(selector_text);
let mut parser = Parser::new(&mut input);
@@ -721,22 +758,23 @@ fn parse_known_pseudo_element_after_colon(
parser: &mut Parser<'_, '_>,
) -> Option<KnownPseudoElementKind> {
let state = parser.state();
if !matches!(
let has_double_colon = matches!(
parser
.next_including_whitespace_and_comments()
.cloned()
.ok()?,
Token::Colon
) {
);
if !has_double_colon {
parser.reset(&state);
}
let Ok(token) = parser.next_including_whitespace_and_comments().cloned() else {
return None;
};
match token {
Token::Ident(name) => {
is_known_terminal_pseudo_element_name(&name).then_some(KnownPseudoElementKind::Terminal)
}
Token::Ident(name) => (is_known_terminal_pseudo_element_name(&name)
|| (has_double_colon && is_unknown_webkit_pseudo_element_name(&name)))
.then_some(KnownPseudoElementKind::Terminal),
Token::Function(name) => {
let kind = match name.to_ascii_lowercase().as_str() {
"cue" | "highlight" => KnownPseudoElementKind::Terminal,
@@ -750,6 +788,12 @@ fn parse_known_pseudo_element_after_colon(
}
}
fn is_unknown_webkit_pseudo_element_name(name: &str) -> bool {
const WEBKIT_PREFIX: &str = "-webkit-";
name.get(..WEBKIT_PREFIX.len())
.is_some_and(|prefix| prefix.eq_ignore_ascii_case(WEBKIT_PREFIX))
}
fn is_known_terminal_pseudo_element_name(name: &str) -> bool {
matches!(
name.to_ascii_lowercase().as_str(),
@@ -1157,6 +1201,12 @@ mod tests {
assert!(dom_api_selector_list_has_only_known_pseudo_elements(
"#target::highlight(foo)"
));
assert!(dom_api_selector_list_has_only_known_pseudo_elements(
"span::-WeBkIt-something-invalid"
));
assert!(!dom_api_selector_list_has_only_known_pseudo_elements(
"input:-webkit-autofill"
));
}
#[test]
@@ -1178,6 +1228,23 @@ mod tests {
));
}
#[test]
fn rewrites_webkit_compat_pseudo_elements_only_for_stylo_validation() {
assert_eq!(
webkit_compat_pseudo_element_validation_selector(
"span::-WeBkIt-something-invalid:active"
)
.as_deref(),
Some("span::part(webkit-compat):active")
);
assert_eq!(
webkit_compat_pseudo_element_validation_selector(
r#"[data-value='::-webkit-something-invalid']"#
),
None
);
}
#[test]
fn detects_invalid_terminal_pseudo_element_chains() {
assert!(selector_list_has_invalid_terminal_pseudo_element_chain(
@@ -1189,6 +1256,15 @@ mod tests {
assert!(selector_list_has_invalid_terminal_pseudo_element_chain(
"::highlight(foo)::part(label)"
));
assert!(selector_list_has_invalid_terminal_pseudo_element_chain(
"span::-webkit-something-invalid::before"
));
assert!(!selector_list_has_invalid_terminal_pseudo_element_chain(
"span::-webkit-something-invalid:active"
));
assert!(!selector_list_has_invalid_terminal_pseudo_element_chain(
"input:-webkit-autofill::before"
));
assert!(!selector_list_has_invalid_terminal_pseudo_element_chain(
"::part(label)::highlight(foo)"
));
+24
View File
@@ -406,6 +406,12 @@ mod tests {
assert!(validate_style_rule_selector_list(".one, main > .two").is_ok());
assert!(validate_style_rule_selector_list("::part(mypart):lang(en)").is_ok());
assert!(validate_style_rule_selector_list("::part(mypart):dir(ltr)").is_ok());
assert!(
validate_style_rule_selector_list("span::-webkit-something-invalid:active").is_ok()
);
assert!(
validate_style_rule_selector_list("span::-webkit-something-invalid::before").is_err()
);
assert!(validate_style_rule_selector_list("").is_err());
assert!(validate_style_rule_selector_list("div[").is_err());
assert!(validate_style_rule_selector_list(".one,").is_err());
@@ -419,6 +425,7 @@ mod tests {
assert!(validate_supports_selector_list("::part(mypart):is(:hover)").is_ok());
assert!(validate_supports_selector_list("::part(mypart):is(:first-child)").is_err());
assert!(validate_supports_selector_list("::part(mypart):where(:first-child)").is_err());
assert!(validate_supports_selector_list("span::-webkit-something-invalid").is_err());
}
#[test]
@@ -1276,6 +1283,23 @@ mod tests {
.query_selector_host(&host, "invalid# ::before")
.is_err()
);
assert_eq!(
engine
.query_selector_host(&host, "span::-webkit-something-invalid")
.unwrap(),
None
);
assert_eq!(
engine
.query_selector_host(&host, "span::-webkit-something-invalid:active")
.unwrap(),
None
);
assert!(
engine
.query_selector_host(&host, "span::-webkit-something-invalid::before")
.is_err()
);
}
#[test]
+33 -7
View File
@@ -3,6 +3,7 @@ use crate::cssom_selector::{
dom_api_selector_list_has_only_known_pseudo_elements,
dom_api_selector_text_with_trailing_attribute_recovery,
selector_list_has_invalid_terminal_pseudo_element_chain,
webkit_compat_pseudo_element_validation_selector,
};
use cssparser::ToCss;
use selectors::parser::ParseRelative;
@@ -83,12 +84,20 @@ fn parse_dom_api_selector_list_text_for_url(
}
pub(crate) fn validate_style_rule_selector_list(selector: &str) -> Result<(), SelectorError> {
parse_style_rule_selector_list_for_url(
selector,
Url::parse("about:blank").expect("about:blank is valid"),
false,
)
.map(|_| ())
if selector_list_has_invalid_terminal_pseudo_element_chain(selector) {
return Err(SelectorError::syntax(
"terminal pseudo-elements cannot be chained",
));
}
let url = Url::parse("about:blank").expect("about:blank is valid");
parse_style_rule_selector_list_for_url(selector, url.clone(), false)
.or_else(|error| {
let Some(selector) = webkit_compat_pseudo_element_validation_selector(selector) else {
return Err(error);
};
parse_style_rule_selector_list_for_url(&selector, url, false)
})
.map(|_| ())
}
pub(crate) fn validate_supports_selector_list(selector: &str) -> Result<(), SelectorError> {
@@ -121,12 +130,29 @@ pub(crate) fn validate_style_rule_selector_list_with_namespaces(
selector: &str,
namespace_context: &StyleRuleNamespaceContext,
) -> Result<(), SelectorError> {
if selector_list_has_invalid_terminal_pseudo_element_chain(selector) {
return Err(SelectorError::syntax(
"terminal pseudo-elements cannot be chained",
));
}
let url = Url::parse("about:blank").expect("about:blank is valid");
parse_style_rule_selector_list_for_url_and_namespaces(
selector,
Url::parse("about:blank").expect("about:blank is valid"),
url.clone(),
namespace_context,
false,
)
.or_else(|error| {
let Some(selector) = webkit_compat_pseudo_element_validation_selector(selector) else {
return Err(error);
};
parse_style_rule_selector_list_for_url_and_namespaces(
&selector,
url,
namespace_context,
false,
)
})
.map(|_| ())
}