parsers: port SASL over to derive macros
You may note that I removed the `exhaustive` flag on the DefinedCondition enum. This is because other elements in the same namespace may occur as siblings of that enum, hence using `exhaustive` may cause incorrect parse errors. (If parsing attempts to process the `<text/>` child as DefinedCondition first, DefinedCondition will return a fatal parser error if it is set as exhaustive because no condition matches `text`.)
This commit is contained in:
parent
1ecb95881c
commit
cbc4648b3c
1 changed files with 11 additions and 71 deletions
|
|
@ -4,14 +4,9 @@
|
||||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
use xso::{
|
use xso::{text::Base64, AsXml, FromXml};
|
||||||
error::{Error, FromElementError},
|
|
||||||
text::Base64,
|
|
||||||
AsXml, FromXml,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::ns;
|
use crate::ns;
|
||||||
use minidom::Element;
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
generate_attribute!(
|
generate_attribute!(
|
||||||
|
|
@ -99,7 +94,7 @@ pub struct Success {
|
||||||
|
|
||||||
/// List of possible failure conditions for SASL.
|
/// List of possible failure conditions for SASL.
|
||||||
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
|
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
|
||||||
#[xml(namespace = ns::SASL, exhaustive)]
|
#[xml(namespace = ns::SASL)]
|
||||||
pub enum DefinedCondition {
|
pub enum DefinedCondition {
|
||||||
/// The client aborted the authentication with
|
/// The client aborted the authentication with
|
||||||
/// [abort](struct.Abort.html).
|
/// [abort](struct.Abort.html).
|
||||||
|
|
@ -153,82 +148,27 @@ pub enum DefinedCondition {
|
||||||
type Lang = String;
|
type Lang = String;
|
||||||
|
|
||||||
/// Sent by the server on SASL failure.
|
/// Sent by the server on SASL failure.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(FromXml, AsXml, Debug, Clone)]
|
||||||
|
#[xml(namespace = ns::SASL, name = "failure")]
|
||||||
pub struct Failure {
|
pub struct Failure {
|
||||||
/// One of the allowed defined-conditions for SASL.
|
/// One of the allowed defined-conditions for SASL.
|
||||||
|
#[xml(child)]
|
||||||
pub defined_condition: DefinedCondition,
|
pub defined_condition: DefinedCondition,
|
||||||
|
|
||||||
/// A human-readable explanation for the failure.
|
/// A human-readable explanation for the failure.
|
||||||
|
#[xml(extract(n = .., name = "text", fields(
|
||||||
|
attribute(type_ = String, name = "xml:lang"),
|
||||||
|
text(type_ = String),
|
||||||
|
)))]
|
||||||
pub texts: BTreeMap<Lang, String>,
|
pub texts: BTreeMap<Lang, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Element> for Failure {
|
|
||||||
type Error = FromElementError;
|
|
||||||
|
|
||||||
fn try_from(root: Element) -> Result<Failure, FromElementError> {
|
|
||||||
check_self!(root, "failure", SASL);
|
|
||||||
check_no_attributes!(root, "failure");
|
|
||||||
|
|
||||||
let mut defined_condition = None;
|
|
||||||
let mut texts = BTreeMap::new();
|
|
||||||
|
|
||||||
for child in root.children() {
|
|
||||||
if child.is("text", ns::SASL) {
|
|
||||||
check_no_unknown_attributes!(child, "text", ["xml:lang"]);
|
|
||||||
check_no_children!(child, "text");
|
|
||||||
let lang = get_attr!(child, "xml:lang", Default);
|
|
||||||
if texts.insert(lang, child.text()).is_some() {
|
|
||||||
return Err(Error::Other(
|
|
||||||
"Text element present twice for the same xml:lang in failure element.",
|
|
||||||
)
|
|
||||||
.into());
|
|
||||||
}
|
|
||||||
} else if child.has_ns(ns::SASL) {
|
|
||||||
if defined_condition.is_some() {
|
|
||||||
return Err(Error::Other(
|
|
||||||
"Failure must not have more than one defined-condition.",
|
|
||||||
)
|
|
||||||
.into());
|
|
||||||
}
|
|
||||||
check_no_attributes!(child, "defined-condition");
|
|
||||||
check_no_children!(child, "defined-condition");
|
|
||||||
let condition = match DefinedCondition::try_from(child.clone()) {
|
|
||||||
Ok(condition) => condition,
|
|
||||||
// TODO: do we really want to eat this error?
|
|
||||||
Err(_) => DefinedCondition::NotAuthorized,
|
|
||||||
};
|
|
||||||
defined_condition = Some(condition);
|
|
||||||
} else {
|
|
||||||
return Err(Error::Other("Unknown element in Failure.").into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let defined_condition =
|
|
||||||
defined_condition.ok_or(Error::Other("Failure must have a defined-condition."))?;
|
|
||||||
|
|
||||||
Ok(Failure {
|
|
||||||
defined_condition,
|
|
||||||
texts,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Failure> for Element {
|
|
||||||
fn from(failure: Failure) -> Element {
|
|
||||||
Element::builder("failure", ns::SASL)
|
|
||||||
.append(failure.defined_condition)
|
|
||||||
.append_all(failure.texts.into_iter().map(|(lang, text)| {
|
|
||||||
Element::builder("text", ns::SASL)
|
|
||||||
.attr("xml:lang", lang)
|
|
||||||
.append(text)
|
|
||||||
}))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
use minidom::Element;
|
||||||
|
|
||||||
#[cfg(target_pointer_width = "32")]
|
#[cfg(target_pointer_width = "32")]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_size() {
|
fn test_size() {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue