From 8e5d8a8aaa7bde2357ca70542a88f744005d58ba Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Tue, 5 Mar 2024 16:07:47 +0100 Subject: Refactor encoder+decoder WIP (compile) --- src/dav/calencoder.rs | 2 + src/dav/caltypes.rs | 32 +-- src/dav/decoder.rs | 132 ++++++++--- src/dav/encoder.rs | 616 +++++++++++++++++++++++-------------------------- src/dav/error.rs | 20 ++ src/dav/mod.rs | 3 + src/dav/realization.rs | 41 ++++ src/dav/types.rs | 138 ++++++----- src/dav/xml.rs | 128 ++++++++++ 9 files changed, 677 insertions(+), 435 deletions(-) create mode 100644 src/dav/error.rs create mode 100644 src/dav/realization.rs create mode 100644 src/dav/xml.rs (limited to 'src') diff --git a/src/dav/calencoder.rs b/src/dav/calencoder.rs index db7ece4..80b8656 100644 --- a/src/dav/calencoder.rs +++ b/src/dav/calencoder.rs @@ -1,3 +1,4 @@ +/* use super::encoder::{QuickWritable, Context}; use super::caltypes::*; use super::types::Extension; @@ -893,3 +894,4 @@ mod tests { assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n"); } } +*/ diff --git a/src/dav/caltypes.rs b/src/dav/caltypes.rs index 7131ec2..c8177e9 100644 --- a/src/dav/caltypes.rs +++ b/src/dav/caltypes.rs @@ -1,7 +1,8 @@ #![allow(dead_code)] +/* use chrono::{DateTime,Utc}; -use super::types as Dav; +use super::types as dav; //@FIXME ACL (rfc3744) is missing, required //@FIXME Versioning (rfc3253) is missing, required @@ -11,15 +12,6 @@ use super::types as Dav; // For reference, non-official extensions documented by SabreDAV: // https://github.com/apple/ccs-calendarserver/tree/master/doc/Extensions -pub struct CalExtension { - pub root: bool -} -impl Dav::Extension for CalExtension { - type Error = Violation; - type Property = Property; - type PropertyRequest = PropertyRequest; - type ResourceType = ResourceType; -} // ----- Root elements ----- @@ -35,7 +27,7 @@ impl Dav::Extension for CalExtension { /// instruction in Section 12.13.2 of [RFC2518]. /// /// -pub struct MkCalendar(pub Dav::Set); +pub struct MkCalendar(pub dav::Set); /// If a response body for a successful request is included, it MUST @@ -51,7 +43,7 @@ pub struct MkCalendar(pub Dav::Set); /// Definition: /// /// -pub struct MkCalendarResponse(pub Vec>); +pub struct MkCalendarResponse(pub Vec>); // --- (REPORT PART) --- @@ -68,8 +60,8 @@ pub struct MkCalendarResponse(pub Vec>); /// -pub struct CalendarQuery { - pub selector: Option>, +pub struct CalendarQuery { + pub selector: Option>, pub filter: Filter, pub timezone: Option, } @@ -88,9 +80,9 @@ pub struct CalendarQuery { /// -pub struct CalendarMultiget { - pub selector: Option>, - pub href: Vec, +pub struct CalendarMultiget { + pub selector: Option>, + pub href: Vec, } /// Name: free-busy-query @@ -1056,10 +1048,10 @@ pub struct LimitRecurrenceSet(pub DateTime, pub DateTime); pub struct LimitFreebusySet(pub DateTime, pub DateTime); /// Used by CalendarQuery & CalendarMultiget -pub enum CalendarSelector { +pub enum CalendarSelector { AllProp, PropName, - Prop(Dav::PropName), + Prop(dav::PropName), } /// Name: comp-filter @@ -1402,4 +1394,4 @@ impl Collation { Self::Unknown(c) => c.as_str(), } } -} +}*/ diff --git a/src/dav/decoder.rs b/src/dav/decoder.rs index 719ea8c..1756464 100644 --- a/src/dav/decoder.rs +++ b/src/dav/decoder.rs @@ -8,33 +8,32 @@ use quick_xml::reader::NsReader; use tokio::io::AsyncBufRead; use super::types::*; +use super::error::*; -#[derive(Debug)] -pub enum ParsingError { - NamespacePrefixAlreadyUsed, - WrongToken, - TagNotFound, - QuickXml(quick_xml::Error), - Eof +/* +// --- Traits ---- + +trait Reader = AsyncBufRead+Unpin+'static; + +trait Decodable: Extension { + async fn decode_propreq(xml: &mut PeekRead) -> Result, ParsingError>; } -impl From for ParsingError { - fn from(value: AttrError) -> Self { - Self::QuickXml(value.into()) +impl Decodable for NoExtension { + async fn decode_propreq(xml: &mut PeekRead) -> Result, ParsingError> { + Ok(None) } } -impl From for ParsingError { - fn from(value: quick_xml::Error) -> Self { - Self::QuickXml(value) - } + +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"; - -trait Reader = AsyncBufRead+Unpin+'static; - pub struct PeekRead { evt: Event<'static>, rdr: NsReader, @@ -117,11 +116,9 @@ impl PeekRead { } } -pub trait QReadable: Sized { - async fn read(xml: &mut PeekRead) -> Result; -} +// ----- Decode ---- -impl QReadable for PropFind { +impl QReadable for PropFind { async fn read(xml: &mut PeekRead) -> Result, ParsingError> { // Find propfind xml.tag_start(DAV_URN, "propfind").await?; @@ -161,13 +158,13 @@ impl QReadable for PropFind { } -impl QReadable for Include { +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::Start(_) => acc.push(PropertyRequest::read(xml).await?), + Event::Start(_) | Event::Empty(_) => acc.push(PropertyRequest::read(xml).await?), Event::End(_) if xml.is_tag(DAV_URN, "include") => break, _ => { xml.skip().await?; }, } @@ -177,13 +174,13 @@ impl QReadable for Include { } } -impl QReadable for PropName { +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::Start(_) | Event::Empty(_) => acc.push(PropertyRequest::read(xml).await?), Event::End(_) if xml.is_tag(DAV_URN, "prop") => break, _ => { xml.skip().await?; }, } @@ -193,12 +190,52 @@ impl QReadable for PropName { } } -impl QReadable for PropertyRequest { +impl QReadable for PropertyRequest { async fn read(xml: &mut PeekRead) -> Result, ParsingError> { - /*match xml.peek() { - - }*/ - unimplemented!(); + loop { + let (need_close, bs) = match xml.peek() { + Event::Start(b) => (true, b), + Event::Empty(b) => (false, b), + _ => { + xml.skip().await?; + continue + }, + }; + + let mut maybe_res = None; + + // Option 1: a pure DAV property + let (ns, loc) = xml.rdr.resolve_element(bs.name()); + if matches!(ns, Bound(Namespace(ns)) if ns == DAV_URN) { + maybe_res = match loc.into_inner() { + b"creationdate" => Some(PropertyRequest::CreationDate), + b"displayname" => Some(PropertyRequest::DisplayName), + b"getcontentlanguage" => Some(PropertyRequest::GetContentLanguage), + b"getcontentlength" => Some(PropertyRequest::GetContentLength), + b"getetag" => Some(PropertyRequest::GetEtag), + b"getlastmodified" => Some(PropertyRequest::GetLastModified), + b"lockdiscovery" => Some(PropertyRequest::LockDiscovery), + b"resourcetype" => Some(PropertyRequest::ResourceType), + b"supportedlock" => Some(PropertyRequest::SupportedLock), + _ => None, + }; + } + + // Option 2: an extension property + if maybe_res.is_none() { + maybe_res = E::decode_propreq(xml).await?.map(PropertyRequest::Extension); + } + + // In any cases, we must close the opened tag + if need_close { + xml.skip().await?; + } + + // Return if something is found - otherwise loop + if let Some(res) = maybe_res { + return Ok(res) + } + } } } @@ -207,7 +244,7 @@ mod tests { use super::*; #[tokio::test] - async fn basic_propfind() { + async fn basic_propfind_propname() { let src = r#" @@ -220,4 +257,37 @@ mod tests { let got = PropFind::::read(&mut rdr).await.unwrap(); assert!(matches!(got, PropFind::PropName)); } +/* + #[tokio::test] + async fn basic_propfind_prop() { + 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_eq!(got, PropFind::Prop(PropName(vec![ + PropertyRequest::DisplayName, + PropertyRequest::GetContentLength, + PropertyRequest::GetContentType, + PropertyRequest::GetEtag, + PropertyRequest::GetLastModified, + PropertyRequest::ResourceType, + PropertyRequest::SupportedLock, + ]))); + } + */ } +*/ diff --git a/src/dav/encoder.rs b/src/dav/encoder.rs index 7778d61..745c396 100644 --- a/src/dav/encoder.rs +++ b/src/dav/encoder.rs @@ -2,390 +2,339 @@ use std::io::Cursor; use quick_xml::Error as QError; use quick_xml::events::{Event, BytesEnd, BytesStart, BytesText}; -use quick_xml::writer::{ElementWriter, Writer}; +use quick_xml::writer::ElementWriter; use quick_xml::name::PrefixDeclaration; use tokio::io::AsyncWrite; use super::types::*; +use super::xml::{Writer,QWrite,IWrite}; -//-------------- TRAITS ---------------------- - -/// Basic encode trait to make a type encodable -pub trait QuickWritable { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError>; -} - -/// Encoding context -pub trait Context: Extension { - fn child(&self) -> Self; - fn create_dav_element(&self, name: &str) -> BytesStart; - async fn hook_error(&self, err: &Self::Error, xml: &mut Writer) -> Result<(), QError>; - async fn hook_property(&self, prop: &Self::Property, xml: &mut Writer) -> Result<(), QError>; - async fn hook_propertyrequest(&self, prop: &Self::PropertyRequest, xml: &mut Writer) -> Result<(), QError>; - async fn hook_resourcetype(&self, prop: &Self::ResourceType, xml: &mut Writer) -> Result<(), QError>; -} - -/// -------------- NoExtension Encoding Context -impl Context for NoExtension { - fn child(&self) -> Self { - Self { root: false } - } - fn create_dav_element(&self, name: &str) -> BytesStart { - let mut start = BytesStart::new(format!("D:{}", name)); - if self.root { - start.push_attribute(("xmlns:D", "DAV:")); - } - start - } - async fn hook_error(&self, _err: &Disabled, _xml: &mut Writer) -> Result<(), QError> { - unreachable!(); - } - async fn hook_property(&self, _prop: &Disabled, _xml: &mut Writer) -> Result<(), QError> { - unreachable!(); - } - async fn hook_propertyrequest(&self, _prop: &Disabled, _xml: &mut Writer) -> Result<(), QError> { - unreachable!(); - } - async fn hook_resourcetype(&self, _restype: &Disabled, _xml: &mut Writer) -> Result<(), QError> { - unreachable!(); - } -} - - -//--------------------- ENCODING -------------------- - // --- XML ROOTS /// PROPFIND REQUEST -impl QuickWritable for PropFind { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { - let start = ctx.create_dav_element("propfind"); +impl QWrite for PropFind { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let start = xml.create_dav_element("propfind"); let end = start.to_end(); - let ctx = ctx.child(); - xml.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; match self { - Self::PropName => xml.write_event_async(Event::Empty(ctx.create_dav_element("propname"))).await?, + Self::PropName => { + let empty_propname = xml.create_dav_element("propname"); + xml.q.write_event_async(Event::Empty(empty_propname)).await? + }, Self::AllProp(maybe_include) => { - xml.write_event_async(Event::Empty(ctx.create_dav_element("allprop"))).await?; + let empty_allprop = xml.create_dav_element("allprop"); + xml.q.write_event_async(Event::Empty(empty_allprop)).await?; if let Some(include) = maybe_include { - include.write(xml, ctx.child()).await?; + include.qwrite(xml).await?; } }, - Self::Prop(propname) => propname.write(xml, ctx.child()).await?, + Self::Prop(propname) => propname.qwrite(xml).await?, } - xml.write_event_async(Event::End(end)).await + xml.q.write_event_async(Event::End(end)).await } } /// PROPPATCH REQUEST -impl QuickWritable for PropertyUpdate { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { - let start = ctx.create_dav_element("propertyupdate"); +impl QWrite for PropertyUpdate { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let start = xml.create_dav_element("propertyupdate"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; for update in self.0.iter() { - update.write(xml, ctx.child()).await?; + update.qwrite(xml).await?; } - xml.write_event_async(Event::End(end)).await + xml.q.write_event_async(Event::End(end)).await } } /// PROPFIND RESPONSE, PROPPATCH RESPONSE, COPY RESPONSE, MOVE RESPONSE /// DELETE RESPONSE, -impl QuickWritable for Multistatus { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { - let start = ctx.create_dav_element("multistatus"); +impl QWrite for Multistatus { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let start = xml.create_dav_element("multistatus"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; for response in self.responses.iter() { - response.write(xml, ctx.child()).await?; + response.qwrite(xml).await?; } if let Some(description) = &self.responsedescription { - description.write(xml, ctx.child()).await?; + description.qwrite(xml).await?; } - xml.write_event_async(Event::End(end)).await?; + xml.q.write_event_async(Event::End(end)).await?; Ok(()) } } /// LOCK REQUEST -impl QuickWritable for LockInfo { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { - let start = ctx.create_dav_element("lockinfo"); +impl QWrite for LockInfo { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let start = xml.create_dav_element("lockinfo"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; - self.lockscope.write(xml, ctx.child()).await?; - self.locktype.write(xml, ctx.child()).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; + self.lockscope.qwrite(xml).await?; + self.locktype.qwrite(xml).await?; if let Some(owner) = &self.owner { - owner.write(xml, ctx.child()).await?; + owner.qwrite(xml).await?; } - xml.write_event_async(Event::End(end)).await + xml.q.write_event_async(Event::End(end)).await } } /// SOME LOCK RESPONSES -impl QuickWritable for PropValue { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { - let start = ctx.create_dav_element("prop"); +impl QWrite for PropValue { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let start = xml.create_dav_element("prop"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; for propval in &self.0 { - propval.write(xml, ctx.child()).await?; + propval.qwrite(xml).await?; } - xml.write_event_async(Event::End(end)).await + xml.q.write_event_async(Event::End(end)).await } } // --- XML inner elements -impl QuickWritable for PropertyUpdateItem { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { +impl QWrite for PropertyUpdateItem { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { match self { - Self::Set(set) => set.write(xml, ctx).await, - Self::Remove(rm) => rm.write(xml, ctx).await, + Self::Set(set) => set.qwrite(xml).await, + Self::Remove(rm) => rm.qwrite(xml).await, } } } -impl QuickWritable for Set { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { - let start = ctx.create_dav_element("set"); +impl QWrite for Set { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let start = xml.create_dav_element("set"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; - self.0.write(xml, ctx.child()).await?; - xml.write_event_async(Event::End(end)).await + xml.q.write_event_async(Event::Start(start.clone())).await?; + self.0.qwrite(xml).await?; + xml.q.write_event_async(Event::End(end)).await } } -impl QuickWritable for Remove { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { - let start = ctx.create_dav_element("remove"); +impl QWrite for Remove { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let start = xml.create_dav_element("remove"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; - self.0.write(xml, ctx.child()).await?; - xml.write_event_async(Event::End(end)).await + xml.q.write_event_async(Event::Start(start.clone())).await?; + self.0.qwrite(xml).await?; + xml.q.write_event_async(Event::End(end)).await } } -impl QuickWritable for AnyProp { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { +impl QWrite for AnyProp { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { match self { - Self::Name(propname) => propname.write(xml, ctx).await, - Self::Value(propval) => propval.write(xml, ctx).await, + Self::Name(propname) => propname.qwrite(xml).await, + Self::Value(propval) => propval.qwrite(xml).await, } } } -impl QuickWritable for PropName { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { - let start = ctx.create_dav_element("prop"); +impl QWrite for PropName { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let start = xml.create_dav_element("prop"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; for propname in &self.0 { - propname.write(xml, ctx.child()).await?; + propname.qwrite(xml).await?; } - xml.write_event_async(Event::End(end)).await + xml.q.write_event_async(Event::End(end)).await } } -impl QuickWritable for Href { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { - let start = ctx.create_dav_element("href"); +impl QWrite for Href { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let start = xml.create_dav_element("href"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; - xml.write_event_async(Event::Text(BytesText::new(&self.0))).await?; - xml.write_event_async(Event::End(end)).await?; - - Ok(()) + xml.q.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Text(BytesText::new(&self.0))).await?; + xml.q.write_event_async(Event::End(end)).await } } -impl QuickWritable for Response { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { - let start = ctx.create_dav_element("response"); +impl QWrite for Response { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let start = xml.create_dav_element("response"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; - self.href.write(xml, ctx.child()).await?; - self.status_or_propstat.write(xml, ctx.child()).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; + self.href.qwrite(xml).await?; + self.status_or_propstat.qwrite(xml).await?; if let Some(error) = &self.error { - error.write(xml, ctx.child()).await?; + error.qwrite(xml).await?; } if let Some(responsedescription) = &self.responsedescription { - responsedescription.write(xml, ctx.child()).await?; + responsedescription.qwrite(xml).await?; } if let Some(location) = &self.location { - location.write(xml, ctx.child()).await?; + location.qwrite(xml).await?; } - xml.write_event_async(Event::End(end)).await?; - - Ok(()) + xml.q.write_event_async(Event::End(end)).await } } -impl QuickWritable for StatusOrPropstat { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { +impl QWrite for StatusOrPropstat { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { match self { - Self::Status(status) => status.write(xml, ctx.child()).await, + Self::Status(status) => status.qwrite(xml).await, Self::PropStat(propstat_list) => { for propstat in propstat_list.iter() { - propstat.write(xml, ctx.child()).await?; + propstat.qwrite(xml).await?; } - Ok(()) } } } } -impl QuickWritable for Status { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { - let start = ctx.create_dav_element("status"); +impl QWrite for Status { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let start = xml.create_dav_element("status"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; let txt = format!("HTTP/1.1 {} {}", self.0.as_str(), self.0.canonical_reason().unwrap_or("No reason")); - xml.write_event_async(Event::Text(BytesText::new(&txt))).await?; + xml.q.write_event_async(Event::Text(BytesText::new(&txt))).await?; - xml.write_event_async(Event::End(end)).await?; + xml.q.write_event_async(Event::End(end)).await?; Ok(()) } } -impl QuickWritable for ResponseDescription { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { - let start = ctx.create_dav_element("responsedescription"); +impl QWrite for ResponseDescription { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let start = xml.create_dav_element("responsedescription"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; - xml.write_event_async(Event::Text(BytesText::new(&self.0))).await?; - xml.write_event_async(Event::End(end)).await?; - - Ok(()) + xml.q.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Text(BytesText::new(&self.0))).await?; + xml.q.write_event_async(Event::End(end)).await } } -impl QuickWritable for Location { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { - let start = ctx.create_dav_element("location"); +impl QWrite for Location { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let start = xml.create_dav_element("location"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; - self.0.write(xml, ctx.child()).await?; - xml.write_event_async(Event::End(end)).await?; - - Ok(()) + xml.q.write_event_async(Event::Start(start.clone())).await?; + self.0.qwrite(xml).await?; + xml.q.write_event_async(Event::End(end)).await } } -impl QuickWritable for PropStat { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { - let start = ctx.create_dav_element("propstat"); +impl QWrite for PropStat { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let start = xml.create_dav_element("propstat"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; - self.prop.write(xml, ctx.child()).await?; - self.status.write(xml, ctx.child()).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; + self.prop.qwrite(xml).await?; + self.status.qwrite(xml).await?; if let Some(error) = &self.error { - error.write(xml, ctx.child()).await?; + error.qwrite(xml).await?; } if let Some(description) = &self.responsedescription { - description.write(xml, ctx.child()).await?; + description.qwrite(xml).await?; } - xml.write_event_async(Event::End(end)).await?; + xml.q.write_event_async(Event::End(end)).await?; Ok(()) } } -impl QuickWritable for Property { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { +impl QWrite for Property { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { use Property::*; match self { CreationDate(date) => { // 1997-12-01T17:42:21-08:00 - let start = ctx.create_dav_element("creationdate"); + let start = xml.create_dav_element("creationdate"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; - xml.write_event_async(Event::Text(BytesText::new(&date.to_rfc3339()))).await?; - xml.write_event_async(Event::End(end)).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Text(BytesText::new(&date.to_rfc3339()))).await?; + xml.q.write_event_async(Event::End(end)).await?; }, DisplayName(name) => { // Example collection - let start = ctx.create_dav_element("displayname"); + let start = xml.create_dav_element("displayname"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; - xml.write_event_async(Event::Text(BytesText::new(name))).await?; - xml.write_event_async(Event::End(end)).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Text(BytesText::new(name))).await?; + xml.q.write_event_async(Event::End(end)).await?; }, GetContentLanguage(lang) => { - let start = ctx.create_dav_element("getcontentlanguage"); + let start = xml.create_dav_element("getcontentlanguage"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; - xml.write_event_async(Event::Text(BytesText::new(lang))).await?; - xml.write_event_async(Event::End(end)).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Text(BytesText::new(lang))).await?; + xml.q.write_event_async(Event::End(end)).await?; }, GetContentLength(len) => { // 4525 - let start = ctx.create_dav_element("getcontentlength"); + let start = xml.create_dav_element("getcontentlength"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; - xml.write_event_async(Event::Text(BytesText::new(&len.to_string()))).await?; - xml.write_event_async(Event::End(end)).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Text(BytesText::new(&len.to_string()))).await?; + xml.q.write_event_async(Event::End(end)).await?; }, GetContentType(ct) => { // text/html - let start = ctx.create_dav_element("getcontenttype"); + let start = xml.create_dav_element("getcontenttype"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; - xml.write_event_async(Event::Text(BytesText::new(&ct))).await?; - xml.write_event_async(Event::End(end)).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Text(BytesText::new(&ct))).await?; + xml.q.write_event_async(Event::End(end)).await?; }, GetEtag(et) => { // "zzyzx" - let start = ctx.create_dav_element("getetag"); + let start = xml.create_dav_element("getetag"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; - xml.write_event_async(Event::Text(BytesText::new(et))).await?; - xml.write_event_async(Event::End(end)).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Text(BytesText::new(et))).await?; + xml.q.write_event_async(Event::End(end)).await?; }, GetLastModified(date) => { // Mon, 12 Jan 1998 09:25:56 GMT - let start = ctx.create_dav_element("getlastmodified"); + let start = xml.create_dav_element("getlastmodified"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; - xml.write_event_async(Event::Text(BytesText::new(&date.to_rfc2822()))).await?; - xml.write_event_async(Event::End(end)).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Text(BytesText::new(&date.to_rfc2822()))).await?; + xml.q.write_event_async(Event::End(end)).await?; }, LockDiscovery(many_locks) => { // ... - let start = ctx.create_dav_element("lockdiscovery"); + let start = xml.create_dav_element("lockdiscovery"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; for lock in many_locks.iter() { - lock.write(xml, ctx.child()).await?; + lock.qwrite(xml).await?; } - xml.write_event_async(Event::End(end)).await?; + xml.q.write_event_async(Event::End(end)).await?; }, ResourceType(many_types) => { // @@ -397,16 +346,16 @@ impl QuickWritable for Property { // // - let start = ctx.create_dav_element("resourcetype"); + let start = xml.create_dav_element("resourcetype"); if many_types.is_empty() { - xml.write_event_async(Event::Empty(start)).await?; + xml.q.write_event_async(Event::Empty(start)).await?; } else { let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; for restype in many_types.iter() { - restype.write(xml, ctx.child()).await?; + restype.qwrite(xml).await?; } - xml.write_event_async(Event::End(end)).await?; + xml.q.write_event_async(Event::End(end)).await?; } }, SupportedLock(many_entries) => { @@ -414,52 +363,56 @@ impl QuickWritable for Property { // ... - let start = ctx.create_dav_element("supportedlock"); + let start = xml.create_dav_element("supportedlock"); if many_entries.is_empty() { - xml.write_event_async(Event::Empty(start)).await?; + xml.q.write_event_async(Event::Empty(start)).await?; } else { let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; for entry in many_entries.iter() { - entry.write(xml, ctx.child()).await?; + entry.qwrite(xml).await?; } - xml.write_event_async(Event::End(end)).await?; + xml.q.write_event_async(Event::End(end)).await?; } }, - Extension(inner) => { - ctx.hook_property(inner, xml).await?; - }, + Extension(inner) => inner.qwrite(xml).await?, }; Ok(()) } } -impl QuickWritable for ResourceType { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { +impl QWrite for ResourceType { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { match self { - Self::Collection => xml.write_event_async(Event::Empty(ctx.create_dav_element("collection"))).await, - Self::Extension(inner) => ctx.hook_resourcetype(inner, xml).await, + Self::Collection => { + let empty_collection = xml.create_dav_element("collection"); + xml.q.write_event_async(Event::Empty(empty_collection)).await + }, + Self::Extension(inner) => inner.qwrite(xml).await, } } } -impl QuickWritable for Include { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { - let start = ctx.create_dav_element("include"); +impl QWrite for Include { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let start = xml.create_dav_element("include"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; for prop in self.0.iter() { - prop.write(xml, ctx.child()).await?; + prop.qwrite(xml).await?; } - xml.write_event_async(Event::End(end)).await + xml.q.write_event_async(Event::End(end)).await } } -impl QuickWritable for PropertyRequest { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { +impl QWrite for PropertyRequest { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { use PropertyRequest::*; - let mut atom = async |c| xml.write_event_async(Event::Empty(ctx.create_dav_element(c))).await; + let mut atom = async |c| { + let empty_tag = xml.create_dav_element(c); + xml.q.write_event_async(Event::Empty(empty_tag)).await + }; match self { CreationDate => atom("creationdate").await, @@ -472,13 +425,13 @@ impl QuickWritable for PropertyRequest { LockDiscovery => atom("lockdiscovery").await, ResourceType => atom("resourcetype").await, SupportedLock => atom("supportedlock").await, - Extension(inner) => ctx.hook_propertyrequest(inner, xml).await, + Extension(inner) => inner.qwrite(xml).await, } } } -impl QuickWritable for ActiveLock { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { +impl QWrite for ActiveLock { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { // // // @@ -494,192 +447,193 @@ impl QuickWritable for ActiveLock { // http://example.com/workspace/webdav/proposal.doc // // - let start = ctx.create_dav_element("activelock"); + let start = xml.create_dav_element("activelock"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; - self.locktype.write(xml, ctx.child()).await?; - self.lockscope.write(xml, ctx.child()).await?; - self.depth.write(xml, ctx.child()).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; + self.locktype.qwrite(xml).await?; + self.lockscope.qwrite(xml).await?; + self.depth.qwrite(xml).await?; if let Some(owner) = &self.owner { - owner.write(xml, ctx.child()).await?; + owner.qwrite(xml).await?; } if let Some(timeout) = &self.timeout { - timeout.write(xml, ctx.child()).await?; + timeout.qwrite(xml).await?; } if let Some(locktoken) = &self.locktoken { - locktoken.write(xml, ctx.child()).await?; + locktoken.qwrite(xml).await?; } - self.lockroot.write(xml, ctx.child()).await?; - xml.write_event_async(Event::End(end)).await?; - - Ok(()) + self.lockroot.qwrite(xml).await?; + xml.q.write_event_async(Event::End(end)).await } } -impl QuickWritable for LockType { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { - let start = ctx.create_dav_element("locktype"); +impl QWrite for LockType { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let start = xml.create_dav_element("locktype"); let end = start.to_end(); - let ctx = ctx.child(); - xml.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; match self { - Self::Write => xml.write_event_async(Event::Empty(ctx.create_dav_element("write"))).await?, + Self::Write => { + let empty_write = xml.create_dav_element("write"); + xml.q.write_event_async(Event::Empty(empty_write)).await? + }, }; - xml.write_event_async(Event::End(end)).await + xml.q.write_event_async(Event::End(end)).await } } -impl QuickWritable for LockScope { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { - let start = ctx.create_dav_element("lockscope"); +impl QWrite for LockScope { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let start = xml.create_dav_element("lockscope"); let end = start.to_end(); - let ctx = ctx.child(); - xml.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; match self { - Self::Exclusive => xml.write_event_async(Event::Empty(ctx.create_dav_element("exclusive"))).await?, - Self::Shared => xml.write_event_async(Event::Empty(ctx.create_dav_element("shared"))).await?, + Self::Exclusive => { + let empty_tag = xml.create_dav_element("exclusive"); + xml.q.write_event_async(Event::Empty(empty_tag)).await? + }, + Self::Shared => { + let empty_tag = xml.create_dav_element("shared"); + xml.q.write_event_async(Event::Empty(empty_tag)).await? + }, }; - xml.write_event_async(Event::End(end)).await + xml.q.write_event_async(Event::End(end)).await } } -impl QuickWritable for Owner { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { - let start = ctx.create_dav_element("owner"); +impl QWrite for Owner { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let start = xml.create_dav_element("owner"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; match self { - Self::Txt(txt) => xml.write_event_async(Event::Text(BytesText::new(&txt))).await?, - Self::Href(href) => href.write(xml, ctx.child()).await?, + Self::Txt(txt) => xml.q.write_event_async(Event::Text(BytesText::new(&txt))).await?, + Self::Href(href) => href.qwrite(xml).await?, } - xml.write_event_async(Event::End(end)).await + xml.q.write_event_async(Event::End(end)).await } } -impl QuickWritable for Depth { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { - let start = ctx.create_dav_element("depth"); +impl QWrite for Depth { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let start = xml.create_dav_element("depth"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; match self { - Self::Zero => xml.write_event_async(Event::Text(BytesText::new("0"))).await?, - Self::One => xml.write_event_async(Event::Text(BytesText::new("1"))).await?, - Self::Infinity => xml.write_event_async(Event::Text(BytesText::new("infinity"))).await?, + Self::Zero => xml.q.write_event_async(Event::Text(BytesText::new("0"))).await?, + Self::One => xml.q.write_event_async(Event::Text(BytesText::new("1"))).await?, + Self::Infinity => xml.q.write_event_async(Event::Text(BytesText::new("infinity"))).await?, }; - xml.write_event_async(Event::End(end)).await + xml.q.write_event_async(Event::End(end)).await } } -impl QuickWritable for Timeout { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { - let start = ctx.create_dav_element("timeout"); +impl QWrite for Timeout { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let start = xml.create_dav_element("timeout"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; match self { Self::Seconds(count) => { let txt = format!("Second-{}", count); - xml.write_event_async(Event::Text(BytesText::new(&txt))).await? + xml.q.write_event_async(Event::Text(BytesText::new(&txt))).await? }, - Self::Infinite => xml.write_event_async(Event::Text(BytesText::new("Infinite"))).await? + Self::Infinite => xml.q.write_event_async(Event::Text(BytesText::new("Infinite"))).await? }; - xml.write_event_async(Event::End(end)).await + xml.q.write_event_async(Event::End(end)).await } } -impl QuickWritable for LockToken { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { - let start = ctx.create_dav_element("locktoken"); +impl QWrite for LockToken { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let start = xml.create_dav_element("locktoken"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; - self.0.write(xml, ctx.child()).await?; - xml.write_event_async(Event::End(end)).await + xml.q.write_event_async(Event::Start(start.clone())).await?; + self.0.qwrite(xml).await?; + xml.q.write_event_async(Event::End(end)).await } } -impl QuickWritable for LockRoot { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { - let start = ctx.create_dav_element("lockroot"); +impl QWrite for LockRoot { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let start = xml.create_dav_element("lockroot"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; - self.0.write(xml, ctx.child()).await?; - xml.write_event_async(Event::End(end)).await + xml.q.write_event_async(Event::Start(start.clone())).await?; + self.0.qwrite(xml).await?; + xml.q.write_event_async(Event::End(end)).await } } -impl QuickWritable for LockEntry { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { - let start = ctx.create_dav_element("lockentry"); +impl QWrite for LockEntry { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let start = xml.create_dav_element("lockentry"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; - self.lockscope.write(xml, ctx.child()).await?; - self.locktype.write(xml, ctx.child()).await?; - xml.write_event_async(Event::End(end)).await + xml.q.write_event_async(Event::Start(start.clone())).await?; + self.lockscope.qwrite(xml).await?; + self.locktype.qwrite(xml).await?; + xml.q.write_event_async(Event::End(end)).await } } -impl QuickWritable for Error { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { - let start = ctx.create_dav_element("error"); +impl QWrite for Error { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let start = xml.create_dav_element("error"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; for violation in &self.0 { - violation.write(xml, ctx.child()).await?; + violation.qwrite(xml).await?; } - xml.write_event_async(Event::End(end)).await?; - - Ok(()) + xml.q.write_event_async(Event::End(end)).await } } -impl QuickWritable for Violation { - async fn write(&self, xml: &mut Writer, ctx: C) -> Result<(), QError> { +impl QWrite for Violation { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let mut atom = async |c| { + let empty_tag = xml.create_dav_element(c); + xml.q.write_event_async(Event::Empty(empty_tag)).await + }; + match self { - Violation::LockTokenMatchesRequestUri => xml.write_event_async(Event::Empty(ctx.create_dav_element("lock-token-matches-request-uri"))).await?, - Violation::LockTokenSubmitted(hrefs) if hrefs.is_empty() => { - xml.write_event_async(Event::Empty(ctx.create_dav_element("lock-token-submitted"))).await? - }, + Violation::LockTokenMatchesRequestUri => atom("lock-token-matches-request-uri").await, + Violation::LockTokenSubmitted(hrefs) if hrefs.is_empty() => atom("lock-token-submitted").await, Violation::LockTokenSubmitted(hrefs) => { - let start = ctx.create_dav_element("lock-token-submitted"); + let start = xml.create_dav_element("lock-token-submitted"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; for href in hrefs { - href.write(xml, ctx.child()).await?; + href.qwrite(xml).await?; } - xml.write_event_async(Event::End(end)).await?; - }, - Violation::NoConflictingLock(hrefs) if hrefs.is_empty() => { - xml.write_event_async(Event::Empty(ctx.create_dav_element("no-conflicting-lock"))).await? + xml.q.write_event_async(Event::End(end)).await }, + Violation::NoConflictingLock(hrefs) if hrefs.is_empty() => atom("no-conflicting-lock").await, Violation::NoConflictingLock(hrefs) => { - let start = ctx.create_dav_element("no-conflicting-lock"); + let start = xml.create_dav_element("no-conflicting-lock"); let end = start.to_end(); - xml.write_event_async(Event::Start(start.clone())).await?; + xml.q.write_event_async(Event::Start(start.clone())).await?; for href in hrefs { - href.write(xml, ctx.child()).await?; + href.qwrite(xml).await?; } - xml.write_event_async(Event::End(end)).await?; - }, - Violation::NoExternalEntities => xml.write_event_async(Event::Empty(ctx.create_dav_element("no-external-entities"))).await?, - Violation::PreservedLiveProperties => xml.write_event_async(Event::Empty(ctx.create_dav_element("preserved-live-properties"))).await?, - Violation::PropfindFiniteDepth => xml.write_event_async(Event::Empty(ctx.create_dav_element("propfind-finite-depth"))).await?, - Violation::CannotModifyProtectedProperty => xml.write_event_async(Event::Empty(ctx.create_dav_element("cannot-modify-protected-property"))).await?, - Violation::Extension(inner) => { - ctx.hook_error(inner, xml).await?; + xml.q.write_event_async(Event::End(end)).await }, - }; - Ok(()) + Violation::NoExternalEntities => atom("no-external-entities").await, + Violation::PreservedLiveProperties => atom("preserved-live-properties").await, + Violation::PropfindFiniteDepth => atom("propfind-finite-depth").await, + Violation::CannotModifyProtectedProperty => atom("cannot-modify-protected-property").await, + Violation::Extension(inner) => inner.qwrite(xml).await, + } } } diff --git a/src/dav/error.rs b/src/dav/error.rs new file mode 100644 index 0000000..1db2895 --- /dev/null +++ b/src/dav/error.rs @@ -0,0 +1,20 @@ +use quick_xml::events::attributes::AttrError; + +#[derive(Debug)] +pub enum ParsingError { + NamespacePrefixAlreadyUsed, + WrongToken, + TagNotFound, + QuickXml(quick_xml::Error), + Eof +} +impl From for ParsingError { + fn from(value: AttrError) -> Self { + Self::QuickXml(value.into()) + } +} +impl From for ParsingError { + fn from(value: quick_xml::Error) -> Self { + Self::QuickXml(value) + } +} diff --git a/src/dav/mod.rs b/src/dav/mod.rs index 835544b..abc46e7 100644 --- a/src/dav/mod.rs +++ b/src/dav/mod.rs @@ -1,3 +1,5 @@ +mod error; +mod xml; mod types; mod caltypes; mod acltypes; @@ -5,6 +7,7 @@ mod versioningtypes; mod encoder; mod calencoder; mod decoder; +mod realization; use std::net::SocketAddr; diff --git a/src/dav/realization.rs b/src/dav/realization.rs new file mode 100644 index 0000000..22c9cfc --- /dev/null +++ b/src/dav/realization.rs @@ -0,0 +1,41 @@ +use super::types as dav; +use super::caltypes as cal; +use super::xml; +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!(); + } +} +impl xml::QWrite for Disabled { + async fn qwrite(&self, xml: &mut xml::Writer) -> Result<(), quick_xml::Error> { + unreachable!(); + } +} + +/// The base WebDAV +/// +/// Any extension is kooh is disabled through an object we can't build +/// due to a private inner element. +pub struct Core {} +impl dav::Extension for Core { + type Error = Disabled; + type Property = Disabled; + type PropertyRequest = Disabled; + type ResourceType = Disabled; +} + +/* +// WebDAV with the base Calendar implementation (RFC4791) +pub struct CalendarMin {} +impl dav::Extension for CalendarMin +{ + type Error = cal::Violation; + type Property = cal::Property; + type PropertyRequest = cal::PropertyRequest; + type ResourceType = cal::ResourceType; +} +*/ diff --git a/src/dav/types.rs b/src/dav/types.rs index a1b1c7f..f2eae3a 100644 --- a/src/dav/types.rs +++ b/src/dav/types.rs @@ -1,28 +1,20 @@ #![allow(dead_code)] +use std::fmt::Debug; use chrono::{DateTime,FixedOffset}; +use super::xml; +use super::error; -/// Extension utilities -pub struct Disabled(()); +/// It's how we implement a DAV extension +/// (That's the dark magic part...) +pub trait ExtensionItem = xml::QRead + xml::QWrite + Debug + PartialEq; pub trait Extension { - type Error; - type Property; - type PropertyRequest; - type ResourceType; + type Error: ExtensionItem; + type Property: ExtensionItem; + type PropertyRequest: ExtensionItem; + type ResourceType: ExtensionItem; } -/// No extension -pub struct NoExtension { - pub root: bool -} -impl Extension for NoExtension { - type Error = Disabled; - type Property = Disabled; - type PropertyRequest = Disabled; - type ResourceType = Disabled; -} - - /// 14.1. activelock XML Element /// /// Name: activelock @@ -30,6 +22,7 @@ impl Extension for NoExtension { /// Purpose: Describes a lock on a resource. /// +#[derive(Debug, PartialEq)] pub struct ActiveLock { pub lockscope: LockScope, pub locktype: LockType, @@ -50,6 +43,7 @@ pub struct ActiveLock { /// elements. /// /// +#[derive(Debug, PartialEq)] pub struct Collection{} /// 14.4 depth XML Element @@ -62,6 +56,7 @@ pub struct Collection{} /// Value: "0" | "1" | "infinity" /// /// +#[derive(Debug, PartialEq)] pub enum Depth { Zero, One, @@ -84,8 +79,10 @@ pub enum Depth { /// postcondition code. Unrecognized elements MUST be ignored. /// /// -pub struct Error(pub Vec>); -pub enum Violation { +#[derive(Debug, PartialEq)] +pub struct Error(pub Vec>); +#[derive(Debug, PartialEq)] +pub enum Violation { /// Name: lock-token-matches-request-uri /// /// Use with: 409 Conflict @@ -169,7 +166,7 @@ pub enum Violation { CannotModifyProtectedProperty, /// Specific errors - Extension(T::Error), + Extension(E::Error), } /// 14.6. exclusive XML Element @@ -179,6 +176,7 @@ pub enum Violation { /// Purpose: Specifies an exclusive lock. /// /// +#[derive(Debug, PartialEq)] pub struct Exclusive {} /// 14.7. href XML Element @@ -194,6 +192,7 @@ pub struct Exclusive {} /// Value: Simple-ref /// /// +#[derive(Debug, PartialEq)] pub struct Href(pub String); @@ -209,7 +208,8 @@ pub struct Href(pub String); /// standards. This element MUST NOT contain text or mixed content. /// /// -pub struct Include(pub Vec>); +#[derive(Debug, PartialEq)] +pub struct Include(pub Vec>); /// 14.9. location XML Element /// @@ -225,6 +225,7 @@ pub struct Include(pub Vec>); /// that would be used in a Location header. /// /// +#[derive(Debug, PartialEq)] pub struct Location(pub Href); /// 14.10. lockentry XML Element @@ -235,6 +236,7 @@ pub struct Location(pub Href); /// resource. /// /// +#[derive(Debug, PartialEq)] pub struct LockEntry { pub lockscope: LockScope, pub locktype: LockType, @@ -248,6 +250,7 @@ pub struct LockEntry { /// specify the type of lock the client wishes to have created. /// /// +#[derive(Debug, PartialEq)] pub struct LockInfo { pub lockscope: LockScope, pub locktype: LockType, @@ -266,6 +269,7 @@ pub struct LockInfo { /// values and the response to LOCK requests. /// /// +#[derive(Debug, PartialEq)] pub struct LockRoot(pub Href); /// 14.13. lockscope XML Element @@ -275,6 +279,7 @@ pub struct LockRoot(pub Href); /// Purpose: Specifies whether a lock is an exclusive lock, or a shared /// lock. /// +#[derive(Debug, PartialEq)] pub enum LockScope { Exclusive, Shared @@ -290,6 +295,7 @@ pub enum LockScope { /// refers to the lock. /// /// +#[derive(Debug, PartialEq)] pub struct LockToken(pub Href); /// 14.15. locktype XML Element @@ -300,6 +306,7 @@ pub struct LockToken(pub Href); /// specification only defines one lock type, the write lock. /// /// +#[derive(Debug, PartialEq)] pub enum LockType { /// 14.30. write XML Element /// @@ -325,8 +332,9 @@ pub enum LockType { /// response descriptions contained within the responses. /// /// -pub struct Multistatus { - pub responses: Vec>, +#[derive(Debug, PartialEq)] +pub struct Multistatus { + pub responses: Vec>, pub responsedescription: Option, } @@ -354,6 +362,7 @@ pub struct Multistatus { /// /// //@FIXME might need support for an extension +#[derive(Debug, PartialEq)] pub enum Owner { Txt(String), Href(Href), @@ -373,12 +382,17 @@ pub enum Owner { /// text or mixed content. /// /// -pub enum AnyProp { - Name(PropName), - Value(PropValue), +#[derive(Debug, PartialEq)] +pub enum AnyProp { + Name(PropName), + Value(PropValue), } -pub struct PropName(pub Vec>); -pub struct PropValue(pub Vec>); + +#[derive(Debug, PartialEq)] +pub struct PropName(pub Vec>); + +#[derive(Debug, PartialEq)] +pub struct PropValue(pub Vec>); /// 14.19. propertyupdate XML Element /// @@ -390,10 +404,13 @@ pub struct PropValue(pub Vec>); /// required to modify the properties on the resource. /// /// -pub struct PropertyUpdate(pub Vec>); -pub enum PropertyUpdateItem { - Remove(Remove), - Set(Set), +#[derive(Debug, PartialEq)] +pub struct PropertyUpdate(pub Vec>); + +#[derive(Debug, PartialEq)] +pub enum PropertyUpdateItem { + Remove(Remove), + Set(Set), } /// 14.2 allprop XML Element @@ -430,10 +447,11 @@ pub enum PropertyUpdateItem { /// values. /// /// -pub enum PropFind { +#[derive(Debug, PartialEq)] +pub enum PropFind { PropName, - AllProp(Option>), - Prop(PropName), + AllProp(Option>), + Prop(PropName), } /// 14.22 propstat XML Element @@ -451,10 +469,11 @@ pub enum PropFind { /// the properties named in 'prop'. /// /// -pub struct PropStat { - pub prop: AnyProp, +#[derive(Debug, PartialEq)] +pub struct PropStat { + pub prop: AnyProp, pub status: Status, - pub error: Option>, + pub error: Option>, pub responsedescription: Option, } @@ -471,7 +490,8 @@ pub struct PropStat { /// the names of properties to be removed are required. /// /// -pub struct Remove(pub PropName); +#[derive(Debug, PartialEq)] +pub struct Remove(pub PropName); /// 14.24. response XML Element /// @@ -495,14 +515,17 @@ pub struct Remove(pub PropName); /// /// -pub enum StatusOrPropstat { +#[derive(Debug, PartialEq)] +pub enum StatusOrPropstat { Status(Status), - PropStat(Vec>), + PropStat(Vec>), } -pub struct Response { + +#[derive(Debug, PartialEq)] +pub struct Response { pub href: Href, // It's wrong according to the spec, but I don't understand why there is an href* - pub status_or_propstat: StatusOrPropstat, - pub error: Option>, + pub status_or_propstat: StatusOrPropstat, + pub error: Option>, pub responsedescription: Option, pub location: Option, } @@ -518,6 +541,7 @@ pub struct Response { /// user. /// /// +#[derive(Debug, PartialEq)] pub struct ResponseDescription(pub String); /// 14.26. set XML Element @@ -536,7 +560,8 @@ pub struct ResponseDescription(pub String); /// property, and MUST be subsequently retrievable using PROPFIND. /// /// -pub struct Set(pub PropValue); +#[derive(Debug, PartialEq)] +pub struct Set(pub PropValue); /// 14.27. shared XML Element /// @@ -546,6 +571,7 @@ pub struct Set(pub PropValue); /// /// /// +#[derive(Debug, PartialEq)] pub struct Shared {} @@ -559,6 +585,7 @@ pub struct Shared {} /// /// //@FIXME: Better typing is possible with an enum for example +#[derive(Debug, PartialEq)] pub struct Status(pub http::status::StatusCode); /// 14.29. timeout XML Element @@ -586,6 +613,7 @@ pub struct Status(pub http::status::StatusCode); /// elapse between granting of the lock at the server, and the automatic /// removal of the lock. The timeout value for TimeType "Second" MUST /// NOT be greater than 2^32-1. +#[derive(Debug, PartialEq)] pub enum Timeout { Seconds(u32), Infinite, @@ -619,7 +647,8 @@ pub enum Timeout { /// the header value could include LWS as defined in [RFC2616], Section /// 4.2. Server implementors SHOULD strip LWS from these values before /// using as WebDAV property values. -pub enum PropertyRequest { +#[derive(Debug, PartialEq)] +pub enum PropertyRequest { CreationDate, DisplayName, GetContentLanguage, @@ -630,9 +659,11 @@ pub enum PropertyRequest { LockDiscovery, ResourceType, SupportedLock, - Extension(T::PropertyRequest), + Extension(E::PropertyRequest), } -pub enum Property { + +#[derive(Debug, PartialEq)] +pub enum Property { /// 15.1. creationdate Property /// /// Name: creationdate @@ -883,7 +914,7 @@ pub enum Property { /// /// /// - ResourceType(Vec>), + ResourceType(Vec>), /// 15.10. supportedlock Property /// @@ -911,10 +942,11 @@ pub enum Property { SupportedLock(Vec), /// Any extension - Extension(T::Property), + Extension(E::Property), } -pub enum ResourceType { +#[derive(Debug, PartialEq)] +pub enum ResourceType { Collection, - Extension(T::ResourceType), + Extension(E::ResourceType), } diff --git a/src/dav/xml.rs b/src/dav/xml.rs new file mode 100644 index 0000000..777f99e --- /dev/null +++ b/src/dav/xml.rs @@ -0,0 +1,128 @@ +use std::collections::HashMap; +use tokio::io::{AsyncWrite, AsyncBufRead}; +use quick_xml::events::{Event, BytesEnd, BytesStart, BytesText}; +use quick_xml::name::{Namespace, QName, PrefixDeclaration, ResolveResult, ResolveResult::*}; +use quick_xml::reader::NsReader; + +use super::error::ParsingError; + +// Async traits +pub trait IWrite = AsyncWrite + Unpin; +pub trait IRead = AsyncBufRead + Unpin + 'static; + +// Serialization/Deserialization traits +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>; +} + +/// Transform a Rust object into an XML stream of characters +pub struct Writer { + pub q: quick_xml::writer::Writer, + root: bool, +} +impl Writer { + pub fn create_dav_element(&mut self, name: &str) -> BytesStart<'static> { + self.create_ns_element("D", name) + } + pub fn create_cal_element(&mut self, name: &str) -> BytesStart<'static> { + self.create_ns_element("C", name) + } + + fn create_ns_element(&mut self, ns: &str, name: &str) -> BytesStart<'static> { + let mut start = BytesStart::new(format!("{}:{}", ns, name)); + //@FIXME not what we want + if self.root { + start.push_attribute(("xmlns:D", "DAV:")); + start.push_attribute(("xmlns:C", "urn:ietf:params:xml:ns:caldav")); + self.root = false; + } + start + } +} + +/// Transform an XML stream of characters into a Rust object +pub struct Reader { + evt: Event<'static>, + rdr: NsReader, + buf: Vec, +} +impl Reader { + 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 + } +} + -- cgit v1.2.3