diff options
-rw-r--r-- | src/dav/decoder.rs | 166 | ||||
-rw-r--r-- | src/main.rs | 1 |
2 files changed, 132 insertions, 35 deletions
diff --git a/src/dav/decoder.rs b/src/dav/decoder.rs index f6cbd27..719ea8c 100644 --- a/src/dav/decoder.rs +++ b/src/dav/decoder.rs @@ -1,4 +1,5 @@ use std::borrow::Cow; +use std::future::Future; use quick_xml::events::{Event, BytesStart, BytesDecl, BytesText}; use quick_xml::events::attributes::AttrError; @@ -13,7 +14,8 @@ pub enum ParsingError { NamespacePrefixAlreadyUsed, WrongToken, TagNotFound, - QuickXml(quick_xml::Error) + QuickXml(quick_xml::Error), + Eof } impl From<AttrError> for ParsingError { fn from(value: AttrError) -> Self { @@ -29,15 +31,16 @@ impl From<quick_xml::Error> for ParsingError { 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)); +//const XML_URN: &[u8] = b"xml"; -pub struct PeekRead<T: AsyncBufRead+Unpin> { +trait Reader = AsyncBufRead+Unpin+'static; + +pub struct PeekRead<T: Reader> { evt: Event<'static>, rdr: NsReader<T>, buf: Vec<u8>, } -impl<T: AsyncBufRead+Unpin> PeekRead<T> { +impl<T: Reader> 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(); @@ -48,67 +51,154 @@ impl<T: AsyncBufRead+Unpin> PeekRead<T> { 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> { + + /// skip tag. Can't skip end, can't skip eof. + async fn skip(&mut self) -> Result<Event<'static>, 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), + Event::End(_) => Err(ParsingError::WrongToken), + Event::Eof => Err(ParsingError::Eof), + _ => self.next().await, } } - // read one more tag - async fn next(&mut self) -> Result<(), ParsingError> { + /// read one more tag + async fn next(&mut self) -> Result<Event<'static>, ParsingError> { let evt = self.rdr.read_event_into_async(&mut self.buf).await?.into_owned(); self.buf.clear(); - self.evt = evt; - Ok(()) + let old_evt = std::mem::replace(&mut self.evt, evt); + Ok(old_evt) + } + + + /// check if this is the desired tag + fn is_tag(&self, ns: &[u8], key: &str) -> bool { + let qname = match self.peek() { + Event::Start(bs) | Event::Empty(bs) => bs.name(), + Event::End(be) => be.name(), + _ => return false, + }; + + let (extr_ns, local) = self.rdr.resolve_element(qname); + + if local.into_inner() != key.as_bytes() { + return false + } + + match extr_ns { + ResolveResult::Bound(v) => v.into_inner() == ns, + _ => false, + } + } + + /// find start tag + async fn tag_start(&mut self, ns: &[u8], key: &str) -> Result<Event<'static>, ParsingError> { + loop { + match self.peek() { + Event::Start(b) if self.is_tag(ns, key) => break, + _ => { self.skip().await?; }, + } + } + self.next().await + } + + // find stop tag + async fn tag_stop(&mut self, ns: &[u8], key: &str) -> Result<Event<'static>, ParsingError> { + loop { + match self.peek() { + Event::End(b) if self.is_tag(ns, key) => break, + _ => { self.skip().await?; }, + } + } + self.next().await } } -pub trait QReadable<T: AsyncBufRead+Unpin>: Sized { +pub trait QReadable<T: Reader>: Sized { async fn read(xml: &mut PeekRead<T>) -> Result<Self, ParsingError>; } -impl<E: Extension, T: AsyncBufRead+Unpin> QReadable<T> for PropFind<E> { +impl<E: Extension, T: Reader> 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?, - } - } - xml.next().await?; + xml.tag_start(DAV_URN, "propfind").await?; // Find any tag - let propfind = loop { + let propfind: PropFind<E> = loop { match xml.peek() { - Event::Start(b) | Event::Empty(b) if b.local_name().into_inner() == &b"allprop"[..] => { - unimplemented!() + Event::Start(_) if xml.is_tag(DAV_URN, "allprop") => { + xml.tag_start(DAV_URN, "allprop").await?; + let r = PropFind::AllProp(Some(Include::read(xml).await?)); + xml.tag_stop(DAV_URN, "allprop").await?; + break r }, - Event::Start(b) if b.local_name().into_inner() == &b"prop"[..] => { - unimplemented!(); + Event::Start(_) if xml.is_tag(DAV_URN, "prop") => { + xml.tag_start(DAV_URN, "prop").await?; + let r = PropFind::Prop(PropName::read(xml).await?); + xml.tag_stop(DAV_URN, "prop").await?; + break r }, - Event::Empty(b) if b.local_name().into_inner() == &b"propname"[..] => break PropFind::PropName, - _ => xml.skip().await?, + Event::Empty(_) if xml.is_tag(DAV_URN, "allprop") => { + xml.next().await?; + break PropFind::AllProp(None) + }, + Event::Empty(_) if xml.is_tag(DAV_URN, "propname") => { + xml.next().await?; + break PropFind::PropName + }, + _ => { xml.skip().await?; }, } }; - xml.next().await?; // Close tag + xml.tag_stop(DAV_URN, "propfind").await?; + + Ok(propfind) + } +} + + +impl<E: Extension, T: Reader> QReadable<T> for Include<E> { + async fn read(xml: &mut PeekRead<T>) -> Result<Include<E>, ParsingError> { + xml.tag_start(DAV_URN, "include").await?; + let mut acc: Vec<PropertyRequest<E>> = Vec::new(); loop { match xml.peek() { - Event::End(b) if b.local_name().into_inner() == &b"propfind"[..] => break, - _ => xml.skip().await?, + Event::Start(_) => acc.push(PropertyRequest::read(xml).await?), + Event::End(_) if xml.is_tag(DAV_URN, "include") => break, + _ => { xml.skip().await?; }, } } + xml.tag_stop(DAV_URN, "include").await?; + Ok(Include(acc)) + } +} - Ok(propfind) +impl<E: Extension, T: Reader> QReadable<T> for PropName<E> { + async fn read(xml: &mut PeekRead<T>) -> Result<PropName<E>, ParsingError> { + xml.tag_start(DAV_URN, "prop").await?; + let mut acc: Vec<PropertyRequest<E>> = Vec::new(); + loop { + match xml.peek() { + Event::Start(_) => acc.push(PropertyRequest::read(xml).await?), + Event::End(_) if xml.is_tag(DAV_URN, "prop") => break, + _ => { xml.skip().await?; }, + } + } + xml.tag_stop(DAV_URN, "prop").await?; + Ok(PropName(acc)) + } +} + +impl<E: Extension, T: Reader> QReadable<T> for PropertyRequest<E> { + async fn read(xml: &mut PeekRead<T>) -> Result<PropertyRequest<E>, ParsingError> { + /*match xml.peek() { + + }*/ + unimplemented!(); } } @@ -118,7 +208,13 @@ mod tests { #[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>"#; + let src = r#"<?xml version="1.0" encoding="utf-8" ?> +<rando/> +<garbage><old/></garbage> +<D:propfind xmlns:D="DAV:"> + <D:propname/> +</D:propfind> +"#; let mut rdr = PeekRead::new(NsReader::from_reader(src.as_bytes())).await.unwrap(); let got = PropFind::<NoExtension>::read(&mut rdr).await.unwrap(); diff --git a/src/main.rs b/src/main.rs index c9ce42d..e098d44 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ #![feature(type_alias_impl_trait)] #![feature(async_fn_in_trait)] #![feature(async_closure)] +#![feature(trait_alias)] mod auth; mod bayou; |