diff --git a/src/dav/caldecoder.rs b/src/dav/caldecoder.rs index 75af4b7..b45d649 100644 --- a/src/dav/caldecoder.rs +++ b/src/dav/caldecoder.rs @@ -7,25 +7,25 @@ use super::error; // ---- EXTENSIONS --- impl xml::QRead for Violation { - async fn qread(&self, xml: &mut xml::Reader) -> Result, error::ParsingError> { + async fn qread(xml: &mut xml::Reader) -> Result, error::ParsingError> { unreachable!(); } } impl xml::QRead for Property { - async fn qread(&self, xml: &mut xml::Reader) -> Result, error::ParsingError> { + async fn qread(xml: &mut xml::Reader) -> Result, error::ParsingError> { unreachable!(); } } impl xml::QRead for PropertyRequest { - async fn qread(&self, xml: &mut xml::Reader) -> Result, error::ParsingError> { + async fn qread(xml: &mut xml::Reader) -> Result, error::ParsingError> { unreachable!(); } } impl xml::QRead for ResourceType { - async fn qread(&self, xml: &mut xml::Reader) -> Result, error::ParsingError> { + async fn qread(xml: &mut xml::Reader) -> Result, error::ParsingError> { unreachable!(); } } diff --git a/src/dav/decoder.rs b/src/dav/decoder.rs index 1756464..a7fdca5 100644 --- a/src/dav/decoder.rs +++ b/src/dav/decoder.rs @@ -8,135 +8,25 @@ use quick_xml::reader::NsReader; use tokio::io::AsyncBufRead; use super::types::*; -use super::error::*; +use super::error::ParsingError; +use super::xml::{QRead, Reader, IRead, DAV_URN, CAL_URN}; -/* -// --- Traits ---- - -trait Reader = AsyncBufRead+Unpin+'static; - -trait Decodable: Extension { - async fn decode_propreq(xml: &mut PeekRead) -> Result, ParsingError>; -} -impl Decodable for NoExtension { - async fn decode_propreq(xml: &mut PeekRead) -> Result, ParsingError> { - Ok(None) - } -} - -pub trait QReadable: Sized { - async fn read(xml: &mut PeekRead) -> Result; -} - -// --- Peek read with namespaces - -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"; -pub struct PeekRead { - evt: Event<'static>, - rdr: NsReader, - buf: Vec, -} -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 }) - } - - fn peek(&self) -> &Event<'static> { - &self.evt - } - - /// 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::End(_) => Err(ParsingError::WrongToken), - Event::Eof => Err(ParsingError::Eof), - _ => self.next().await, - } - } - - /// 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(); - 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 - } -} - -// ----- Decode ---- - -impl QReadable for PropFind { - async fn read(xml: &mut PeekRead) -> Result, ParsingError> { +impl QRead> for PropFind { + async fn qread(xml: &mut Reader) -> Result, ParsingError> { // Find propfind xml.tag_start(DAV_URN, "propfind").await?; - // Find any tag let propfind: PropFind = loop { match xml.peek() { 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?)); + let r = PropFind::AllProp(Include::qread(xml).await?); xml.tag_stop(DAV_URN, "allprop").await?; break r }, 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 + let propname = PropName::qread(xml).await?.ok_or(ParsingError::MissingChild)?; + break PropFind::Prop(propname); }, Event::Empty(_) if xml.is_tag(DAV_URN, "allprop") => { xml.next().await?; @@ -153,49 +43,52 @@ impl QReadable for PropFind { // Close tag xml.tag_stop(DAV_URN, "propfind").await?; - Ok(propfind) + Ok(Some(propfind)) } } -impl QReadable for Include { - async fn read(xml: &mut PeekRead) -> Result, ParsingError> { +impl QRead> for Include { + async fn qread(xml: &mut Reader) -> Result, ParsingError> { xml.tag_start(DAV_URN, "include").await?; let mut acc: Vec> = Vec::new(); loop { match xml.peek() { - Event::Start(_) | Event::Empty(_) => acc.push(PropertyRequest::read(xml).await?), + Event::Start(_) | Event::Empty(_) => { + PropertyRequest::qread(xml).await?.map(|v| acc.push(v)); + }, Event::End(_) if xml.is_tag(DAV_URN, "include") => break, _ => { xml.skip().await?; }, } } xml.tag_stop(DAV_URN, "include").await?; - Ok(Include(acc)) + Ok(Some(Include(acc))) } } -impl QReadable for PropName { - async fn read(xml: &mut PeekRead) -> Result, ParsingError> { +impl QRead> for PropName { + async fn qread(xml: &mut Reader) -> Result, ParsingError> { xml.tag_start(DAV_URN, "prop").await?; let mut acc: Vec> = Vec::new(); loop { match xml.peek() { - Event::Start(_) | Event::Empty(_) => acc.push(PropertyRequest::read(xml).await?), + Event::Start(_) | Event::Empty(_) => { + PropertyRequest::qread(xml).await?.map(|v| acc.push(v)); + }, Event::End(_) if xml.is_tag(DAV_URN, "prop") => break, _ => { xml.skip().await?; }, } } xml.tag_stop(DAV_URN, "prop").await?; - Ok(PropName(acc)) + Ok(Some(PropName(acc))) } } -impl QReadable for PropertyRequest { - async fn read(xml: &mut PeekRead) -> Result, ParsingError> { +impl QRead> for PropertyRequest { + async fn qread(xml: &mut Reader) -> Result, ParsingError> { loop { - let (need_close, bs) = match xml.peek() { - Event::Start(b) => (true, b), - Event::Empty(b) => (false, b), + let bs = match xml.peek() { + Event::Start(b) | Event::Empty(b) => b, _ => { xml.skip().await?; continue @@ -212,6 +105,7 @@ impl QReadable for PropertyRequest { b"displayname" => Some(PropertyRequest::DisplayName), b"getcontentlanguage" => Some(PropertyRequest::GetContentLanguage), b"getcontentlength" => Some(PropertyRequest::GetContentLength), + b"getcontenttype" => Some(PropertyRequest::GetContentType), b"getetag" => Some(PropertyRequest::GetEtag), b"getlastmodified" => Some(PropertyRequest::GetLastModified), b"lockdiscovery" => Some(PropertyRequest::LockDiscovery), @@ -223,18 +117,13 @@ impl QReadable for PropertyRequest { // Option 2: an extension property if maybe_res.is_none() { - maybe_res = E::decode_propreq(xml).await?.map(PropertyRequest::Extension); + maybe_res = E::PropertyRequest::qread(xml).await?.map(PropertyRequest::Extension); } - // In any cases, we must close the opened tag - if need_close { - xml.skip().await?; - } + // Close the current tag + xml.skip().await?; - // Return if something is found - otherwise loop - if let Some(res) = maybe_res { - return Ok(res) - } + return Ok(maybe_res) } } } @@ -242,6 +131,7 @@ impl QReadable for PropertyRequest { #[cfg(test)] mod tests { use super::*; + use crate::dav::realization::Core; #[tokio::test] async fn basic_propfind_propname() { @@ -253,11 +143,12 @@ mod tests { "#; - 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)); + let mut rdr = Reader::new(NsReader::from_reader(src.as_bytes())).await.unwrap(); + let got = PropFind::::qread(&mut rdr).await.unwrap().unwrap(); + + assert_eq!(got, PropFind::::PropName); } -/* + #[tokio::test] async fn basic_propfind_prop() { let src = r#" @@ -265,19 +156,20 @@ mod tests { - - - - - - - + + + + + + + "#; - let mut rdr = PeekRead::new(NsReader::from_reader(src.as_bytes())).await.unwrap(); - let got = PropFind::::read(&mut rdr).await.unwrap(); + let mut rdr = Reader::new(NsReader::from_reader(src.as_bytes())).await.unwrap(); + let got = PropFind::::qread(&mut rdr).await.unwrap().unwrap(); + assert_eq!(got, PropFind::Prop(PropName(vec![ PropertyRequest::DisplayName, PropertyRequest::GetContentLength, @@ -288,6 +180,4 @@ mod tests { PropertyRequest::SupportedLock, ]))); } - */ } -*/ diff --git a/src/dav/error.rs b/src/dav/error.rs index 1db2895..5bd8ed3 100644 --- a/src/dav/error.rs +++ b/src/dav/error.rs @@ -2,6 +2,7 @@ use quick_xml::events::attributes::AttrError; #[derive(Debug)] pub enum ParsingError { + MissingChild, NamespacePrefixAlreadyUsed, WrongToken, TagNotFound, diff --git a/src/dav/realization.rs b/src/dav/realization.rs index a02de94..1898173 100644 --- a/src/dav/realization.rs +++ b/src/dav/realization.rs @@ -6,8 +6,8 @@ use super::error; #[derive(Debug, PartialEq)] pub struct Disabled(()); impl xml::QRead for Disabled { - async fn qread(&self, xml: &mut xml::Reader) -> Result, error::ParsingError> { - unreachable!(); + async fn qread(xml: &mut xml::Reader) -> Result, error::ParsingError> { + Ok(None) } } impl xml::QWrite for Disabled { @@ -20,6 +20,7 @@ impl xml::QWrite for Disabled { /// /// Any extension is kooh is disabled through an object we can't build /// due to a private inner element. +#[derive(Debug, PartialEq)] pub struct Core {} impl dav::Extension for Core { type Error = Disabled; @@ -29,6 +30,7 @@ impl dav::Extension for Core { } // WebDAV with the base Calendar implementation (RFC4791) +#[derive(Debug, PartialEq)] pub struct Calendar {} impl dav::Extension for Calendar { diff --git a/src/dav/xml.rs b/src/dav/xml.rs index 495c9a5..5ebda02 100644 --- a/src/dav/xml.rs +++ b/src/dav/xml.rs @@ -5,6 +5,11 @@ use quick_xml::reader::NsReader; use super::error::ParsingError; +// Constants +pub const DAV_URN: &[u8] = b"DAV:"; +pub const CAL_URN: &[u8] = b"urn:ietf:params:xml:ns:caldav"; +pub const CARD_URN: &[u8] = b"urn:ietf:params:xml:ns:carddav"; + // Async traits pub trait IWrite = AsyncWrite + Unpin; pub trait IRead = AsyncBufRead + Unpin + 'static; @@ -14,7 +19,7 @@ pub trait QWrite { async fn qwrite(&self, xml: &mut Writer) -> Result<(), quick_xml::Error>; } pub trait QRead { - async fn qread(&self, xml: &mut Reader) -> Result, ParsingError>; + async fn qread(xml: &mut Reader) -> Result, ParsingError>; } /// Transform a Rust object into an XML stream of characters @@ -42,24 +47,24 @@ impl Writer { /// Transform an XML stream of characters into a Rust object pub struct Reader { + pub rdr: NsReader, evt: Event<'static>, - rdr: NsReader, buf: Vec, } impl Reader { - async fn new(mut rdr: NsReader) -> Result { + pub 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 }) } - fn peek(&self) -> &Event<'static> { + pub fn peek(&self) -> &Event<'static> { &self.evt } /// skip tag. Can't skip end, can't skip eof. - async fn skip(&mut self) -> Result, ParsingError> { + pub 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?; @@ -72,7 +77,7 @@ impl Reader { } /// read one more tag - async fn next(&mut self) -> Result, ParsingError> { + pub async fn next(&mut self) -> Result, ParsingError> { let evt = self.rdr.read_event_into_async(&mut self.buf).await?.into_owned(); self.buf.clear(); let old_evt = std::mem::replace(&mut self.evt, evt); @@ -81,7 +86,7 @@ impl Reader { /// check if this is the desired tag - fn is_tag(&self, ns: &[u8], key: &str) -> bool { + pub 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(), @@ -101,7 +106,7 @@ impl Reader { } /// find start tag - async fn tag_start(&mut self, ns: &[u8], key: &str) -> Result, ParsingError> { + pub 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, @@ -112,7 +117,7 @@ impl Reader { } // find stop tag - async fn tag_stop(&mut self, ns: &[u8], key: &str) -> Result, ParsingError> { + pub 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,