Report more specific invalid attribute selectors (bug 1384216).

This commit is contained in:
Josh Matthews 2017-08-28 17:20:45 -07:00
parent 73e903ad3c
commit 408c34a76d
2 changed files with 55 additions and 24 deletions

View file

@ -49,7 +49,7 @@ fn to_ascii_lowercase(s: &str) -> Cow<str> {
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum SelectorParseError<'i, T> { pub enum SelectorParseError<'i, T> {
PseudoElementInComplexSelector, PseudoElementInComplexSelector,
NoQualifiedNameInAttributeSelector, NoQualifiedNameInAttributeSelector(Token<'i>),
TooManyCompoundSelectorComponentsInNegation, TooManyCompoundSelectorComponentsInNegation,
NegationSelectorComponentNotNamespace, NegationSelectorComponentNotNamespace,
NegationSelectorComponentNotLocalName, NegationSelectorComponentNotLocalName,
@ -61,6 +61,9 @@ pub enum SelectorParseError<'i, T> {
UnsupportedPseudoClassOrElement(CowRcStr<'i>), UnsupportedPseudoClassOrElement(CowRcStr<'i>),
UnexpectedIdent(CowRcStr<'i>), UnexpectedIdent(CowRcStr<'i>),
ExpectedNamespace(CowRcStr<'i>), ExpectedNamespace(CowRcStr<'i>),
ExpectedBarInAttr(Token<'i>),
BadValueInAttr(Token<'i>),
InvalidQualNameInAttr(Token<'i>),
Custom(T), Custom(T),
} }
@ -1107,8 +1110,8 @@ fn parse_type_selector<'i, 't, P, E, Impl, S>(parser: &P, input: &mut CssParser<
S: Push<Component<Impl>>, S: Push<Component<Impl>>,
{ {
match parse_qualified_name(parser, input, /* in_attr_selector = */ false)? { match parse_qualified_name(parser, input, /* in_attr_selector = */ false)? {
None => Ok(false), OptionalQName::None(_) => Ok(false),
Some((namespace, local_name)) => { OptionalQName::Some(namespace, local_name) => {
match namespace { match namespace {
QNamePrefix::ImplicitAnyNamespace => {} QNamePrefix::ImplicitAnyNamespace => {}
QNamePrefix::ImplicitDefaultNamespace(url) => { QNamePrefix::ImplicitDefaultNamespace(url) => {
@ -1176,13 +1179,19 @@ enum QNamePrefix<Impl: SelectorImpl> {
ExplicitNamespace(Impl::NamespacePrefix, Impl::NamespaceUrl), // `prefix|foo` ExplicitNamespace(Impl::NamespacePrefix, Impl::NamespaceUrl), // `prefix|foo`
} }
enum OptionalQName<'i, Impl: SelectorImpl> {
Some(QNamePrefix<Impl>, Option<CowRcStr<'i>>),
None(Token<'i>),
}
/// * `Err(())`: Invalid selector, abort /// * `Err(())`: Invalid selector, abort
/// * `Ok(None)`: Not a simple selector, could be something else. `input` was not consumed. /// * `Ok(None(token))`: Not a simple selector, could be something else. `input` was not consumed,
/// * `Ok(Some((namespace, local_name)))`: `None` for the local name means a `*` universal selector /// but the token is still returned.
/// * `Ok(Some(namespace, local_name))`: `None` for the local name means a `*` universal selector
fn parse_qualified_name<'i, 't, P, E, Impl> fn parse_qualified_name<'i, 't, P, E, Impl>
(parser: &P, input: &mut CssParser<'i, 't>, (parser: &P, input: &mut CssParser<'i, 't>,
in_attr_selector: bool) in_attr_selector: bool)
-> Result<Option<(QNamePrefix<Impl>, Option<CowRcStr<'i>>)>, -> Result<OptionalQName<'i, Impl>,
ParseError<'i, SelectorParseError<'i, E>>> ParseError<'i, SelectorParseError<'i, E>>>
where P: Parser<'i, Impl=Impl, Error=E>, Impl: SelectorImpl where P: Parser<'i, Impl=Impl, Error=E>, Impl: SelectorImpl
{ {
@ -1191,17 +1200,18 @@ fn parse_qualified_name<'i, 't, P, E, Impl>
Some(url) => QNamePrefix::ImplicitDefaultNamespace(url), Some(url) => QNamePrefix::ImplicitDefaultNamespace(url),
None => QNamePrefix::ImplicitAnyNamespace, None => QNamePrefix::ImplicitAnyNamespace,
}; };
Ok(Some((namespace, local_name))) Ok(OptionalQName::Some(namespace, local_name))
}; };
let explicit_namespace = |input: &mut CssParser<'i, 't>, namespace| { let explicit_namespace = |input: &mut CssParser<'i, 't>, namespace| {
match input.next_including_whitespace() { match input.next_including_whitespace() {
Ok(&Token::Delim('*')) if !in_attr_selector => { Ok(&Token::Delim('*')) if !in_attr_selector => {
Ok(Some((namespace, None))) Ok(OptionalQName::Some(namespace, None))
}, },
Ok(&Token::Ident(ref local_name)) => { Ok(&Token::Ident(ref local_name)) => {
Ok(Some((namespace, Some(local_name.clone())))) Ok(OptionalQName::Some(namespace, Some(local_name.clone())))
}, },
Ok(t) if in_attr_selector => Err(SelectorParseError::InvalidQualNameInAttr(t.clone()).into()),
Ok(t) => Err(ParseError::Basic(BasicParseError::UnexpectedToken(t.clone()))), Ok(t) => Err(ParseError::Basic(BasicParseError::UnexpectedToken(t.clone()))),
Err(e) => Err(ParseError::Basic(e)), Err(e) => Err(ParseError::Basic(e)),
} }
@ -1223,7 +1233,7 @@ fn parse_qualified_name<'i, 't, P, E, Impl>
_ => { _ => {
input.reset(&after_ident); input.reset(&after_ident);
if in_attr_selector { if in_attr_selector {
Ok(Some((QNamePrefix::ImplicitNoNamespace, Some(value)))) Ok(OptionalQName::Some(QNamePrefix::ImplicitNoNamespace, Some(value)))
} else { } else {
default_namespace(Some(value)) default_namespace(Some(value))
} }
@ -1241,7 +1251,7 @@ fn parse_qualified_name<'i, 't, P, E, Impl>
input.reset(&after_star); input.reset(&after_star);
if in_attr_selector { if in_attr_selector {
match result { match result {
Ok(t) => Err(ParseError::Basic(BasicParseError::UnexpectedToken(t))), Ok(t) => Err(SelectorParseError::ExpectedBarInAttr(t).into()),
Err(e) => Err(ParseError::Basic(e)), Err(e) => Err(ParseError::Basic(e)),
} }
} else { } else {
@ -1253,9 +1263,13 @@ fn parse_qualified_name<'i, 't, P, E, Impl>
Ok(Token::Delim('|')) => { Ok(Token::Delim('|')) => {
explicit_namespace(input, QNamePrefix::ExplicitNoNamespace) explicit_namespace(input, QNamePrefix::ExplicitNoNamespace)
} }
_ => { Ok(t) => {
input.reset(&start); input.reset(&start);
Ok(None) Ok(OptionalQName::None(t))
}
Err(e) => {
input.reset(&start);
Err(e.into())
} }
} }
} }
@ -1269,9 +1283,10 @@ fn parse_attribute_selector<'i, 't, P, E, Impl>(parser: &P, input: &mut CssParse
let namespace; let namespace;
let local_name; let local_name;
match parse_qualified_name(parser, input, /* in_attr_selector = */ true)? { match parse_qualified_name(parser, input, /* in_attr_selector = */ true)? {
None => return Err(ParseError::Custom(SelectorParseError::NoQualifiedNameInAttributeSelector)), OptionalQName::None(t) =>
Some((_, None)) => unreachable!(), return Err(ParseError::Custom(SelectorParseError::NoQualifiedNameInAttributeSelector(t))),
Some((ns, Some(ln))) => { OptionalQName::Some(_, None) => unreachable!(),
OptionalQName::Some(ns, Some(ln)) => {
local_name = ln; local_name = ln;
namespace = match ns { namespace = match ns {
QNamePrefix::ImplicitNoNamespace | QNamePrefix::ImplicitNoNamespace |
@ -1328,7 +1343,12 @@ fn parse_attribute_selector<'i, 't, P, E, Impl>(parser: &P, input: &mut CssParse
Ok(t) => return Err(SelectorParseError::UnexpectedTokenInAttributeSelector(t.clone()).into()) Ok(t) => return Err(SelectorParseError::UnexpectedTokenInAttributeSelector(t.clone()).into())
}; };
let value = input.expect_ident_or_string()?.clone(); let value = match input.expect_ident_or_string() {
Ok(t) => t.clone(),
Err(BasicParseError::UnexpectedToken(t)) =>
return Err(SelectorParseError::BadValueInAttr(t.clone()).into()),
Err(e) => return Err(e.into()),
};
let never_matches = match operator { let never_matches = match operator {
AttrSelectorOperator::Equal | AttrSelectorOperator::Equal |
AttrSelectorOperator::DashMatch => false, AttrSelectorOperator::DashMatch => false,

View file

@ -214,9 +214,6 @@ fn extract_error_param<'a>(err: ParseError<'a>) -> Option<ErrorString<'a>> {
CssParseError::Custom(SelectorParseError::UnexpectedIdent(ident)) => CssParseError::Custom(SelectorParseError::UnexpectedIdent(ident)) =>
ErrorString::Ident(ident), ErrorString::Ident(ident),
CssParseError::Custom(SelectorParseError::ExpectedNamespace(namespace)) =>
ErrorString::Ident(namespace),
CssParseError::Custom(SelectorParseError::Custom( CssParseError::Custom(SelectorParseError::Custom(
StyleParseError::PropertyDeclaration( StyleParseError::PropertyDeclaration(
PropertyDeclarationParseError::UnknownProperty(property)))) => PropertyDeclarationParseError::UnknownProperty(property)))) =>
@ -250,9 +247,16 @@ fn extract_error_params<'a>(err: ParseError<'a>) -> Option<ErrorParams<'a>> {
PropertyDeclarationParseError::InvalidValue(property, Some(e))))) => PropertyDeclarationParseError::InvalidValue(property, Some(e))))) =>
(Some(ErrorString::Snippet(property.into())), Some(extract_value_error_param(e))), (Some(ErrorString::Snippet(property.into())), Some(extract_value_error_param(e))),
CssParseError::Custom(SelectorParseError::UnexpectedTokenInAttributeSelector(t)) => CssParseError::Custom(SelectorParseError::UnexpectedTokenInAttributeSelector(t)) |
CssParseError::Custom(SelectorParseError::BadValueInAttr(t)) |
CssParseError::Custom(SelectorParseError::ExpectedBarInAttr(t)) |
CssParseError::Custom(SelectorParseError::NoQualifiedNameInAttributeSelector(t)) |
CssParseError::Custom(SelectorParseError::InvalidQualNameInAttr(t)) =>
(None, Some(ErrorString::UnexpectedToken(t))), (None, Some(ErrorString::UnexpectedToken(t))),
CssParseError::Custom(SelectorParseError::ExpectedNamespace(namespace)) =>
(None, Some(ErrorString::Ident(namespace))),
CssParseError::Custom(SelectorParseError::UnsupportedPseudoClassOrElement(p)) => CssParseError::Custom(SelectorParseError::UnsupportedPseudoClassOrElement(p)) =>
(None, Some(ErrorString::Ident(p))), (None, Some(ErrorString::Ident(p))),
@ -324,9 +328,6 @@ impl<'a> ErrorHelpers<'a> for ContextualParseError<'a> {
(b"PEKeyframeBadName\0", Action::Nothing), (b"PEKeyframeBadName\0", Action::Nothing),
ContextualParseError::UnsupportedKeyframePropertyDeclaration(..) => ContextualParseError::UnsupportedKeyframePropertyDeclaration(..) =>
(b"PEBadSelectorKeyframeRuleIgnored\0", Action::Nothing), (b"PEBadSelectorKeyframeRuleIgnored\0", Action::Nothing),
ContextualParseError::InvalidRule(
_, CssParseError::Custom(SelectorParseError::ExpectedNamespace(_))) =>
(b"PEUnknownNamespacePrefix\0", Action::Nothing),
ContextualParseError::InvalidRule( ContextualParseError::InvalidRule(
_, CssParseError::Custom(SelectorParseError::Custom( _, CssParseError::Custom(SelectorParseError::Custom(
StyleParseError::UnexpectedTokenWithinNamespace(_)))) => StyleParseError::UnexpectedTokenWithinNamespace(_)))) =>
@ -335,6 +336,16 @@ impl<'a> ErrorHelpers<'a> for ContextualParseError<'a> {
let prefix = match *err { let prefix = match *err {
CssParseError::Custom(SelectorParseError::UnexpectedTokenInAttributeSelector(_)) => CssParseError::Custom(SelectorParseError::UnexpectedTokenInAttributeSelector(_)) =>
Some(&b"PEAttSelUnexpected\0"[..]), Some(&b"PEAttSelUnexpected\0"[..]),
CssParseError::Custom(SelectorParseError::ExpectedBarInAttr(_)) =>
Some(&b"PEAttSelNoBar\0"[..]),
CssParseError::Custom(SelectorParseError::BadValueInAttr(_)) =>
Some(&b"PEAttSelBadValue\0"[..]),
CssParseError::Custom(SelectorParseError::NoQualifiedNameInAttributeSelector(_)) =>
Some(&b"PEAttributeNameOrNamespaceExpected\0"[..]),
CssParseError::Custom(SelectorParseError::InvalidQualNameInAttr(_)) =>
Some(&b"PEAttributeNameExpected\0"[..]),
CssParseError::Custom(SelectorParseError::ExpectedNamespace(_)) =>
Some(&b"PEUnknownNamespacePrefix\0"[..]),
CssParseError::Custom(SelectorParseError::UnsupportedPseudoClassOrElement(_)) => CssParseError::Custom(SelectorParseError::UnsupportedPseudoClassOrElement(_)) =>
Some(&b"PEPseudoSelUnknown\0"[..]), Some(&b"PEPseudoSelUnknown\0"[..]),
_ => None, _ => None,