diff --git a/src/dav/decoder.rs b/src/dav/decoder.rs index 5996a05..f6cbd27 100644 --- a/src/dav/decoder.rs +++ b/src/dav/decoder.rs @@ -1,17 +1,18 @@ use std::borrow::Cow; -use im::HashMap; -use quick_xml::events::{BytesStart, BytesText}; +use quick_xml::events::{Event, BytesStart, BytesDecl, BytesText}; use quick_xml::events::attributes::AttrError; -use quick_xml::name::PrefixDeclaration; -use quick_xml::reader::Reader; +use quick_xml::name::{Namespace, QName, PrefixDeclaration, ResolveResult, ResolveResult::*}; +use quick_xml::reader::NsReader; use tokio::io::AsyncBufRead; use super::types::*; +#[derive(Debug)] pub enum ParsingError { NamespacePrefixAlreadyUsed, WrongToken, + TagNotFound, QuickXml(quick_xml::Error) } impl From for ParsingError { @@ -29,112 +30,98 @@ 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"; +const DAV_NS: ResolveResult = Bound(Namespace(DAV_URN)); -#[derive(PartialEq, Clone)] -pub enum XmlNamespace { - None, - Dav, - CalDav, - CardDav, - Xml, - Unknown(Vec), +pub struct PeekRead { + evt: Event<'static>, + rdr: NsReader, + buf: Vec, } -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()), - } +impl PeekRead { + async fn new(mut rdr: NsReader) -> Result { + let mut buf: Vec = vec![]; + let evt = rdr.read_event_into_async(&mut buf).await?.into_owned(); + buf.clear(); + Ok(Self { evt, rdr, buf }) } -} -/// 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, -} -impl<'a, E: Extension + Clone> Context<'a, E> { - /// External buffer - pub fn new() -> Self { - Self { - aliases: HashMap::new(), - phantom: std::marker::PhantomData + fn peek(&self) -> &Event<'static> { + &self.evt + } + // skip tag, some tags can't be skipped like end, text, cdata + async fn skip(&mut self) -> Result<(), ParsingError> { + match &self.evt { + Event::Start(b) => { + let _span = self.rdr.read_to_end_into_async(b.to_end().name(), &mut self.buf).await?; + self.next().await + }, + Event::Empty(_) | Event::Comment(_) | Event::PI(_) | Event::Decl(_) | Event::DocType(_) => self.next().await, + _ => return Err(ParsingError::WrongToken), } } - 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())?, + // read one more tag + async fn next(&mut self) -> Result<(), ParsingError> { + let evt = self.rdr.read_event_into_async(&mut self.buf).await?.into_owned(); + self.buf.clear(); + self.evt = evt; + Ok(()) + } +} + +pub trait QReadable: Sized { + async fn read(xml: &mut PeekRead) -> Result; +} + +impl QReadable for PropFind { + async fn read(xml: &mut PeekRead) -> Result, ParsingError> { + + // Find propfind + loop { + match xml.peek() { + Event::Start(b) if b.local_name().into_inner() == &b"propfind"[..] => break, + _ => xml.skip().await?, + } + } + xml.next().await?; + + // Find any tag + let propfind = loop { + match xml.peek() { + Event::Start(b) | Event::Empty(b) if b.local_name().into_inner() == &b"allprop"[..] => { + unimplemented!() + }, + Event::Start(b) if b.local_name().into_inner() == &b"prop"[..] => { + unimplemented!(); + }, + Event::Empty(b) if b.local_name().into_inner() == &b"propname"[..] => break PropFind::PropName, + _ => xml.skip().await?, + } + }; + xml.next().await?; + + // Close tag + loop { + match xml.peek() { + Event::End(b) if b.local_name().into_inner() == &b"propfind"[..] => break, + _ => xml.skip().await?, } } - // 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), - } + Ok(propfind) } } -trait DavReader<'a> { - async fn doctype(&self) -> Result<(), ParsingError>; - async fn tag(&self) -> Result, ParsingError>; - async fn txt(&self) -> Result, ParsingError>; -} -/*impl<'a, I: AsyncBufRead+Unpin> DavReader<'a> for Reader { - async fn doctype(&self) -> Result<(), ParsingError> { - } - async fn tag(&self) -> Result, ParsingError> { - } - async fn txt(&self) -> Result, ParsingError> { - } -}*/ - -pub async fn propfind( - xml: &mut Reader, - ctx: Context<'_, E>, - buf: &mut Vec, -) -> Result, ParsingError> { - let local = ctx.clone(); - - match xml.read_event_into_async(buf).await? { - _ => unimplemented!(), - } - - unimplemented!(); +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn basic_propfind() { + let src = r#""#; + + let mut rdr = PeekRead::new(NsReader::from_reader(src.as_bytes())).await.unwrap(); + let got = PropFind::::read(&mut rdr).await.unwrap(); + assert!(matches!(got, PropFind::PropName)); + } } diff --git a/src/dav/types.rs b/src/dav/types.rs index 7e3eb1c..a1b1c7f 100644 --- a/src/dav/types.rs +++ b/src/dav/types.rs @@ -20,7 +20,8 @@ impl Extension for NoExtension { type Property = Disabled; type PropertyRequest = Disabled; type ResourceType = Disabled; - } +} + /// 14.1. activelock XML Element ///