Skip to content

Commit 95efc50

Browse files
committed
Restrict complex selectors to only allow subclass selectors in final position
1 parent d723bae commit 95efc50

File tree

1 file changed

+25
-18
lines changed

1 file changed

+25
-18
lines changed

src/wp-includes/html-api/class-wp-css-selectors.php

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,7 +1066,8 @@ public static function parse( string $input, int &$offset ): ?self {
10661066
return null;
10671067
}
10681068

1069-
$selectors = array( $selector );
1069+
$selectors = array( $selector );
1070+
$has_preceding_subclass_selector = null !== $selector->subclass_selectors;
10701071

10711072
$found_whitespace = self::parse_whitespace( $input, $updated_offset );
10721073
while ( $updated_offset < strlen( $input ) ) {
@@ -1075,22 +1076,13 @@ public static function parse( string $input, int &$offset ): ?self {
10751076
self::COMBINATOR_NEXT_SIBLING === $input[ $updated_offset ] ||
10761077
self::COMBINATOR_SUBSEQUENT_SIBLING === $input[ $updated_offset ]
10771078
) {
1078-
$combinator = $input[ $updated_offset ];
1079-
++$updated_offset;
1080-
self::parse_whitespace( $input, $updated_offset );
1081-
1082-
// Failure to find a selector here is a parse error
1083-
$selector = WP_CSS_Selector::parse( $input, $updated_offset );
1084-
// Failure to find a selector is a parse error.
1085-
if ( null === $selector ) {
1086-
return null;
1087-
}
1088-
$selectors[] = $combinator;
1089-
$selectors[] = $selector;
1090-
} elseif ( ! $found_whitespace ) {
1091-
break;
1092-
} else {
1079+
$combinator = $input[ $updated_offset ];
1080+
++$updated_offset;
1081+
self::parse_whitespace( $input, $updated_offset );
10931082

1083+
// Failure to find a selector here is a parse error
1084+
$selector = WP_CSS_Selector::parse( $input, $updated_offset );
1085+
} elseif ( $found_whitespace ) {
10941086
/*
10951087
* Whitespace is ambiguous, it could be a descendant combinator or
10961088
* insignificant whitespace.
@@ -1099,9 +1091,24 @@ public static function parse( string $input, int &$offset ): ?self {
10991091
if ( null === $selector ) {
11001092
break;
11011093
}
1102-
$selectors[] = self::COMBINATOR_DESCENDANT;
1103-
$selectors[] = $selector;
1094+
$combinator = self::COMBINATOR_DESCENDANT;
1095+
} else {
1096+
break;
1097+
}
1098+
1099+
if ( null === $selector ) {
1100+
return null;
11041101
}
1102+
1103+
// `div > .className` is valid, but `.className > div` is not.
1104+
if ( $has_preceding_subclass_selector ) {
1105+
throw new Exception( 'Unsupported non-final subclass selector.' );
1106+
}
1107+
$has_preceding_subclass_selector = null !== $selector->subclass_selectors;
1108+
1109+
$selectors[] = $combinator;
1110+
$selectors[] = $selector;
1111+
11051112
$found_whitespace = self::parse_whitespace( $input, $updated_offset );
11061113
}
11071114
$offset = $updated_offset;

0 commit comments

Comments
 (0)