diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/dav/decoder.rs | 173 | ||||
-rw-r--r-- | src/dav/types.rs | 3 |
2 files changed, 82 insertions, 94 deletions
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<AttrError> 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<u8>), +pub struct PeekRead<T: AsyncBufRead+Unpin> { + evt: Event<'static>, + rdr: NsReader<T>, + buf: 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()), - } +impl<T: AsyncBufRead+Unpin> PeekRead<T> { + async fn new(mut rdr: NsReader<T>) -> Result<Self, ParsingError> { + let mut buf: Vec<u8> = 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<E>, -} -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 } - - 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())?, - } + // 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), } - - // 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""[..]) + // 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<T: AsyncBufRead+Unpin>: Sized { + async fn read(xml: &mut PeekRead<T>) -> Result<Self, ParsingError>; +} - 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) +impl<E: Extension, T: AsyncBufRead+Unpin> QReadable<T> for PropFind<E> { + async fn read(xml: &mut PeekRead<T>) -> Result<PropFind<E>, ParsingError> { + + // Find propfind + loop { + match xml.peek() { + Event::Start(b) if b.local_name().into_inner() == &b"propfind"[..] => break, + _ => xml.skip().await?, } } - 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), + 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?, + } } + + Ok(propfind) } } -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> { - } -}*/ +#[cfg(test)] +mod tests { + use super::*; -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(); + #[tokio::test] + async fn basic_propfind() { + let src = r#"<?xml version="1.0" encoding="utf-8" ?><rando/><garbage><old/></garbage><D:propfind xmlns:D="DAV:"><D:propname/></D:propfind>"#; - match xml.read_event_into_async(buf).await? { - _ => unimplemented!(), + let mut rdr = PeekRead::new(NsReader::from_reader(src.as_bytes())).await.unwrap(); + let got = PropFind::<NoExtension>::read(&mut rdr).await.unwrap(); + assert!(matches!(got, PropFind::PropName)); } - - unimplemented!(); } 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 /// |