diff options
-rw-r--r-- | src/dav/decoder.rs | 140 | ||||
-rw-r--r-- | src/dav/mod.rs | 1 |
2 files changed, 141 insertions, 0 deletions
diff --git a/src/dav/decoder.rs b/src/dav/decoder.rs new file mode 100644 index 0000000..5996a05 --- /dev/null +++ b/src/dav/decoder.rs @@ -0,0 +1,140 @@ +use std::borrow::Cow; + +use im::HashMap; +use quick_xml::events::{BytesStart, BytesText}; +use quick_xml::events::attributes::AttrError; +use quick_xml::name::PrefixDeclaration; +use quick_xml::reader::Reader; +use tokio::io::AsyncBufRead; + +use super::types::*; + +pub enum ParsingError { + NamespacePrefixAlreadyUsed, + WrongToken, + QuickXml(quick_xml::Error) +} +impl From<AttrError> for ParsingError { + fn from(value: AttrError) -> Self { + Self::QuickXml(value.into()) + } +} +impl From<quick_xml::Error> for ParsingError { + fn from(value: quick_xml::Error) -> Self { + Self::QuickXml(value) + } +} + +const DAV_URN: &[u8] = b"DAV:"; +const CALDAV_URN: &[u8] = b"urn:ietf:params:xml:ns:caldav"; +const CARDDAV_URN: &[u8] = b"urn:ietf:params:xml:ns:carddav"; +const XML_URN: &[u8] = b"xml"; + +#[derive(PartialEq, Clone)] +pub enum XmlNamespace { + None, + Dav, + CalDav, + CardDav, + Xml, + Unknown(Vec<u8>), +} +impl From<&[u8]> for XmlNamespace { + fn from(value: &[u8]) -> Self { + match value { + [] => Self::None, + DAV_URN => Self::Dav, + CALDAV_URN => Self::CalDav, + CARDDAV_URN => Self::CardDav, + XML_URN => Self::Xml, + v => Self::Unknown(v.into()), + } + } +} + +/// Context must stay cheap to clone +/// as we are cloning it from one fonction to another +#[derive(Clone)] +pub struct Context<'a, E: Extension + Clone> { + pub aliases: HashMap<&'a [u8], XmlNamespace>, + phantom: std::marker::PhantomData<E>, +} +impl<'a, E: Extension + Clone> Context<'a, E> { + /// External buffer + pub fn new() -> Self { + Self { + aliases: HashMap::new(), + phantom: std::marker::PhantomData + } + } + + pub fn ns_scan(&mut self, token: &'a BytesStart<'a>) -> Result<(XmlNamespace, &[u8]), ParsingError> { + // Register namespace aliases from attributes (aka namespace bindings) + for attr_res in token.attributes() { + let attr = attr_res?; + match attr.key.as_namespace_binding() { + None => (), + Some(PrefixDeclaration::Named(prefix)) => self.ns_alias(attr.value.as_ref(), prefix.as_ref())?, + Some(PrefixDeclaration::Default) => self.ns_default(attr.value.as_ref())?, + } + } + + // Decompose tag name + let (key, maybe_prefix) = token.name().decompose(); + let ns = self.ns_resolve(maybe_prefix.map(|p| p.into_inner()).unwrap_or(&b""[..])); + + Ok((ns, key.into_inner())) + } + + fn ns_default(&mut self, fqns: &[u8]) -> Result<(), ParsingError> { + self.ns_alias(fqns, &b""[..]) + } + + fn ns_alias(&mut self, fqns: &[u8], alias: &'a [u8]) -> Result<(), ParsingError> { + let parsed_ns = XmlNamespace::from(fqns); + if let Some(reg_fqns) = self.aliases.get(alias) { + if *reg_fqns != parsed_ns { + return Err(ParsingError::NamespacePrefixAlreadyUsed) + } + } + self.aliases.insert(alias, parsed_ns); + Ok(()) + } + + // If the namespace is not found in the alias table (binding table) + // we suppose it's a fully qualified namespace (fqns) + fn ns_resolve(&self, prefix: &[u8]) -> XmlNamespace { + match self.aliases.get(prefix) { + Some(fqns) => fqns.clone(), + None => XmlNamespace::from(prefix), + } + } +} + +trait DavReader<'a> { + async fn doctype(&self) -> Result<(), ParsingError>; + async fn tag(&self) -> Result<BytesStart<'a>, ParsingError>; + async fn txt(&self) -> Result<Cow<'a, u8>, ParsingError>; +} +/*impl<'a, I: AsyncBufRead+Unpin> DavReader<'a> for Reader<I> { + async fn doctype(&self) -> Result<(), ParsingError> { + } + async fn tag(&self) -> Result<BytesStart<'a>, ParsingError> { + } + async fn txt(&self) -> Result<Cow<'a, u8>, ParsingError> { + } +}*/ + +pub async fn propfind<E: Extension+Clone>( + xml: &mut Reader<impl AsyncBufRead+Unpin>, + ctx: Context<'_, E>, + buf: &mut Vec<u8>, +) -> Result<PropFind<E>, ParsingError> { + let local = ctx.clone(); + + match xml.read_event_into_async(buf).await? { + _ => unimplemented!(), + } + + unimplemented!(); +} diff --git a/src/dav/mod.rs b/src/dav/mod.rs index 4044895..835544b 100644 --- a/src/dav/mod.rs +++ b/src/dav/mod.rs @@ -4,6 +4,7 @@ mod acltypes; mod versioningtypes; mod encoder; mod calencoder; +mod decoder; use std::net::SocketAddr; |