From b7a990ecdb0346e12cfeb0de34565f51af61ec80 Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Mon, 4 Mar 2024 22:27:37 +0100 Subject: Decoder is starting to work --- src/dav/decoder.rs | 166 ++++++++++++++++++++++++++++++++++++++++++----------- 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 for ParsingError { fn from(value: AttrError) -> Self { @@ -29,15 +31,16 @@ impl From 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 { +trait Reader = AsyncBufRead+Unpin+'static; + +pub struct PeekRead { evt: Event<'static>, rdr: NsReader, buf: Vec, } -impl PeekRead { +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(); @@ -48,67 +51,154 @@ impl PeekRead { 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, 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, 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, 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, ParsingError> { + loop { + match self.peek() { + Event::End(b) if self.is_tag(ns, key) => break, + _ => { self.skip().await?; }, + } + } + self.next().await } } -pub trait QReadable: Sized { +pub trait QReadable: Sized { async fn read(xml: &mut PeekRead) -> Result; } -impl QReadable for PropFind { +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?; + xml.tag_start(DAV_URN, "propfind").await?; // Find any tag - let propfind = loop { + let propfind: PropFind = 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 QReadable for Include { + async fn read(xml: &mut PeekRead) -> Result, ParsingError> { + xml.tag_start(DAV_URN, "include").await?; + let mut acc: Vec> = 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 QReadable for PropName { + async fn read(xml: &mut PeekRead) -> Result, ParsingError> { + xml.tag_start(DAV_URN, "prop").await?; + let mut acc: Vec> = 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 QReadable for PropertyRequest { + async fn read(xml: &mut PeekRead) -> Result, ParsingError> { + /*match xml.peek() { + + }*/ + unimplemented!(); } } @@ -118,7 +208,13 @@ mod tests { #[tokio::test] async fn basic_propfind() { - let src = r#""#; + let src = r#" + + + + + +"#; let mut rdr = PeekRead::new(NsReader::from_reader(src.as_bytes())).await.unwrap(); let got = PropFind::::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; -- cgit v1.2.3