Refactor encoder+decoder WIP (compile)

This commit is contained in:
Quentin 2024-03-05 16:07:47 +01:00
parent b7a990ecdb
commit 8e5d8a8aaa
Signed by: quentin
GPG key ID: E9602264D639FF68
9 changed files with 689 additions and 447 deletions

View file

@ -1,3 +1,4 @@
/*
use super::encoder::{QuickWritable, Context}; use super::encoder::{QuickWritable, Context};
use super::caltypes::*; use super::caltypes::*;
use super::types::Extension; use super::types::Extension;
@ -893,3 +894,4 @@ mod tests {
assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n"); assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n");
} }
} }
*/

View file

@ -1,7 +1,8 @@
#![allow(dead_code)] #![allow(dead_code)]
/*
use chrono::{DateTime,Utc}; use chrono::{DateTime,Utc};
use super::types as Dav; use super::types as dav;
//@FIXME ACL (rfc3744) is missing, required //@FIXME ACL (rfc3744) is missing, required
//@FIXME Versioning (rfc3253) 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: // For reference, non-official extensions documented by SabreDAV:
// https://github.com/apple/ccs-calendarserver/tree/master/doc/Extensions // 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 ----- // ----- Root elements -----
@ -35,7 +27,7 @@ impl Dav::Extension for CalExtension {
/// instruction in Section 12.13.2 of [RFC2518]. /// instruction in Section 12.13.2 of [RFC2518].
/// ///
/// <!ELEMENT mkcalendar (DAV:set)> /// <!ELEMENT mkcalendar (DAV:set)>
pub struct MkCalendar<E: Dav::Extension>(pub Dav::Set<E>); pub struct MkCalendar<E: dav::Extension>(pub dav::Set<E>);
/// If a response body for a successful request is included, it MUST /// If a response body for a successful request is included, it MUST
@ -51,7 +43,7 @@ pub struct MkCalendar<E: Dav::Extension>(pub Dav::Set<E>);
/// Definition: /// Definition:
/// ///
/// <!ELEMENT mkcol-response (propstat+)> /// <!ELEMENT mkcol-response (propstat+)>
pub struct MkCalendarResponse<T: Dav::Extension>(pub Vec<Dav::PropStat<T>>); pub struct MkCalendarResponse<E: dav::Extension>(pub Vec<dav::PropStat<E>>);
// --- (REPORT PART) --- // --- (REPORT PART) ---
@ -68,8 +60,8 @@ pub struct MkCalendarResponse<T: Dav::Extension>(pub Vec<Dav::PropStat<T>>);
/// <!ELEMENT calendar-query ((DAV:allprop | /// <!ELEMENT calendar-query ((DAV:allprop |
/// DAV:propname | /// DAV:propname |
/// DAV:prop)?, filter, timezone?)> /// DAV:prop)?, filter, timezone?)>
pub struct CalendarQuery<T: Dav::Extension> { pub struct CalendarQuery<E: dav::Extension> {
pub selector: Option<CalendarSelector<T>>, pub selector: Option<CalendarSelector<E>>,
pub filter: Filter, pub filter: Filter,
pub timezone: Option<TimeZone>, pub timezone: Option<TimeZone>,
} }
@ -88,9 +80,9 @@ pub struct CalendarQuery<T: Dav::Extension> {
/// <!ELEMENT calendar-multiget ((DAV:allprop | /// <!ELEMENT calendar-multiget ((DAV:allprop |
/// DAV:propname | /// DAV:propname |
/// DAV:prop)?, DAV:href+)> /// DAV:prop)?, DAV:href+)>
pub struct CalendarMultiget<T: Dav::Extension> { pub struct CalendarMultiget<E: dav::Extension> {
pub selector: Option<CalendarSelector<T>>, pub selector: Option<CalendarSelector<E>>,
pub href: Vec<Dav::Href>, pub href: Vec<dav::Href>,
} }
/// Name: free-busy-query /// Name: free-busy-query
@ -1056,10 +1048,10 @@ pub struct LimitRecurrenceSet(pub DateTime<Utc>, pub DateTime<Utc>);
pub struct LimitFreebusySet(pub DateTime<Utc>, pub DateTime<Utc>); pub struct LimitFreebusySet(pub DateTime<Utc>, pub DateTime<Utc>);
/// Used by CalendarQuery & CalendarMultiget /// Used by CalendarQuery & CalendarMultiget
pub enum CalendarSelector<T: Dav::Extension> { pub enum CalendarSelector<E: dav::Extension> {
AllProp, AllProp,
PropName, PropName,
Prop(Dav::PropName<T>), Prop(dav::PropName<E>),
} }
/// Name: comp-filter /// Name: comp-filter
@ -1402,4 +1394,4 @@ impl Collation {
Self::Unknown(c) => c.as_str(), Self::Unknown(c) => c.as_str(),
} }
} }
} }*/

View file

@ -8,33 +8,32 @@ use quick_xml::reader::NsReader;
use tokio::io::AsyncBufRead; use tokio::io::AsyncBufRead;
use super::types::*; use super::types::*;
use super::error::*;
#[derive(Debug)] /*
pub enum ParsingError { // --- Traits ----
NamespacePrefixAlreadyUsed,
WrongToken, trait Reader = AsyncBufRead+Unpin+'static;
TagNotFound,
QuickXml(quick_xml::Error), trait Decodable: Extension {
Eof async fn decode_propreq(xml: &mut PeekRead<impl Reader>) -> Result<Option<Self::PropertyRequest>, ParsingError>;
} }
impl From<AttrError> for ParsingError { impl Decodable for NoExtension {
fn from(value: AttrError) -> Self { async fn decode_propreq(xml: &mut PeekRead<impl Reader>) -> Result<Option<Disabled>, ParsingError> {
Self::QuickXml(value.into()) Ok(None)
} }
} }
impl From<quick_xml::Error> for ParsingError {
fn from(value: quick_xml::Error) -> Self { pub trait QReadable<T: Reader>: Sized {
Self::QuickXml(value) async fn read(xml: &mut PeekRead<T>) -> Result<Self, ParsingError>;
}
} }
// --- Peek read with namespaces
const DAV_URN: &[u8] = b"DAV:"; const DAV_URN: &[u8] = b"DAV:";
const CALDAV_URN: &[u8] = b"urn:ietf:params:xml:ns:caldav"; const CALDAV_URN: &[u8] = b"urn:ietf:params:xml:ns:caldav";
const CARDDAV_URN: &[u8] = b"urn:ietf:params:xml:ns:carddav"; const CARDDAV_URN: &[u8] = b"urn:ietf:params:xml:ns:carddav";
//const XML_URN: &[u8] = b"xml"; //const XML_URN: &[u8] = b"xml";
trait Reader = AsyncBufRead+Unpin+'static;
pub struct PeekRead<T: Reader> { pub struct PeekRead<T: Reader> {
evt: Event<'static>, evt: Event<'static>,
rdr: NsReader<T>, rdr: NsReader<T>,
@ -117,11 +116,9 @@ impl<T: Reader> PeekRead<T> {
} }
} }
pub trait QReadable<T: Reader>: Sized { // ----- Decode ----
async fn read(xml: &mut PeekRead<T>) -> Result<Self, ParsingError>;
}
impl<E: Extension, T: Reader> QReadable<T> for PropFind<E> { impl<E: Decodable, T: Reader> QReadable<T> for PropFind<E> {
async fn read(xml: &mut PeekRead<T>) -> Result<PropFind<E>, ParsingError> { async fn read(xml: &mut PeekRead<T>) -> Result<PropFind<E>, ParsingError> {
// Find propfind // Find propfind
xml.tag_start(DAV_URN, "propfind").await?; xml.tag_start(DAV_URN, "propfind").await?;
@ -161,13 +158,13 @@ impl<E: Extension, T: Reader> QReadable<T> for PropFind<E> {
} }
impl<E: Extension, T: Reader> QReadable<T> for Include<E> { impl<E: Decodable, T: Reader> QReadable<T> for Include<E> {
async fn read(xml: &mut PeekRead<T>) -> Result<Include<E>, ParsingError> { async fn read(xml: &mut PeekRead<T>) -> Result<Include<E>, ParsingError> {
xml.tag_start(DAV_URN, "include").await?; xml.tag_start(DAV_URN, "include").await?;
let mut acc: Vec<PropertyRequest<E>> = Vec::new(); let mut acc: Vec<PropertyRequest<E>> = Vec::new();
loop { loop {
match xml.peek() { 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, Event::End(_) if xml.is_tag(DAV_URN, "include") => break,
_ => { xml.skip().await?; }, _ => { xml.skip().await?; },
} }
@ -177,13 +174,13 @@ impl<E: Extension, T: Reader> QReadable<T> for Include<E> {
} }
} }
impl<E: Extension, T: Reader> QReadable<T> for PropName<E> { impl<E: Decodable, T: Reader> QReadable<T> for PropName<E> {
async fn read(xml: &mut PeekRead<T>) -> Result<PropName<E>, ParsingError> { async fn read(xml: &mut PeekRead<T>) -> Result<PropName<E>, ParsingError> {
xml.tag_start(DAV_URN, "prop").await?; xml.tag_start(DAV_URN, "prop").await?;
let mut acc: Vec<PropertyRequest<E>> = Vec::new(); let mut acc: Vec<PropertyRequest<E>> = Vec::new();
loop { loop {
match xml.peek() { 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, Event::End(_) if xml.is_tag(DAV_URN, "prop") => break,
_ => { xml.skip().await?; }, _ => { xml.skip().await?; },
} }
@ -193,12 +190,52 @@ impl<E: Extension, T: Reader> QReadable<T> for PropName<E> {
} }
} }
impl<E: Extension, T: Reader> QReadable<T> for PropertyRequest<E> { impl<E: Decodable, T: Reader> QReadable<T> for PropertyRequest<E> {
async fn read(xml: &mut PeekRead<T>) -> Result<PropertyRequest<E>, ParsingError> { async fn read(xml: &mut PeekRead<T>) -> Result<PropertyRequest<E>, ParsingError> {
/*match xml.peek() { loop {
let (need_close, bs) = match xml.peek() {
}*/ Event::Start(b) => (true, b),
unimplemented!(); 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::*; use super::*;
#[tokio::test] #[tokio::test]
async fn basic_propfind() { async fn basic_propfind_propname() {
let src = r#"<?xml version="1.0" encoding="utf-8" ?> let src = r#"<?xml version="1.0" encoding="utf-8" ?>
<rando/> <rando/>
<garbage><old/></garbage> <garbage><old/></garbage>
@ -220,4 +257,37 @@ mod tests {
let got = PropFind::<NoExtension>::read(&mut rdr).await.unwrap(); let got = PropFind::<NoExtension>::read(&mut rdr).await.unwrap();
assert!(matches!(got, PropFind::PropName)); assert!(matches!(got, PropFind::PropName));
} }
/*
#[tokio::test]
async fn basic_propfind_prop() {
let src = r#"<?xml version="1.0" encoding="utf-8" ?>
<rando/>
<garbage><old/></garbage>
<D:propfind xmlns:D="DAV:">
<D:prop>
<displayname/>
<getcontentlength/>
<getcontenttype/>
<getetag/>
<getlastmodified/>
<resourcetype/>
<supportedlock/>
</D:prop>
</D:propfind>
"#;
let mut rdr = PeekRead::new(NsReader::from_reader(src.as_bytes())).await.unwrap();
let got = PropFind::<NoExtension>::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,
])));
}
*/
} }
*/

View file

@ -2,390 +2,339 @@ use std::io::Cursor;
use quick_xml::Error as QError; use quick_xml::Error as QError;
use quick_xml::events::{Event, BytesEnd, BytesStart, BytesText}; 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 quick_xml::name::PrefixDeclaration;
use tokio::io::AsyncWrite; use tokio::io::AsyncWrite;
use super::types::*; use super::types::*;
use super::xml::{Writer,QWrite,IWrite};
//-------------- TRAITS ----------------------
/// Basic encode trait to make a type encodable
pub trait QuickWritable<C: Context> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, 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<impl AsyncWrite+Unpin>) -> Result<(), QError>;
async fn hook_property(&self, prop: &Self::Property, xml: &mut Writer<impl AsyncWrite+Unpin>) -> Result<(), QError>;
async fn hook_propertyrequest(&self, prop: &Self::PropertyRequest, xml: &mut Writer<impl AsyncWrite+Unpin>) -> Result<(), QError>;
async fn hook_resourcetype(&self, prop: &Self::ResourceType, xml: &mut Writer<impl AsyncWrite+Unpin>) -> 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<impl AsyncWrite+Unpin>) -> Result<(), QError> {
unreachable!();
}
async fn hook_property(&self, _prop: &Disabled, _xml: &mut Writer<impl AsyncWrite+Unpin>) -> Result<(), QError> {
unreachable!();
}
async fn hook_propertyrequest(&self, _prop: &Disabled, _xml: &mut Writer<impl AsyncWrite+Unpin>) -> Result<(), QError> {
unreachable!();
}
async fn hook_resourcetype(&self, _restype: &Disabled, _xml: &mut Writer<impl AsyncWrite+Unpin>) -> Result<(), QError> {
unreachable!();
}
}
//--------------------- ENCODING --------------------
// --- XML ROOTS // --- XML ROOTS
/// PROPFIND REQUEST /// PROPFIND REQUEST
impl<C: Context> QuickWritable<C> for PropFind<C> { impl<E: Extension> QWrite for PropFind<E> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = ctx.create_dav_element("propfind"); let start = xml.create_dav_element("propfind");
let end = start.to_end(); 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 { 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) => { 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 { 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 /// PROPPATCH REQUEST
impl<C: Context> QuickWritable<C> for PropertyUpdate<C> { impl<E: Extension> QWrite for PropertyUpdate<E> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = ctx.create_dav_element("propertyupdate"); let start = xml.create_dav_element("propertyupdate");
let end = start.to_end(); 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() { 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 /// PROPFIND RESPONSE, PROPPATCH RESPONSE, COPY RESPONSE, MOVE RESPONSE
/// DELETE RESPONSE, /// DELETE RESPONSE,
impl<C: Context> QuickWritable<C> for Multistatus<C> { impl<E: Extension> QWrite for Multistatus<E> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = ctx.create_dav_element("multistatus"); let start = xml.create_dav_element("multistatus");
let end = start.to_end(); 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() { for response in self.responses.iter() {
response.write(xml, ctx.child()).await?; response.qwrite(xml).await?;
} }
if let Some(description) = &self.responsedescription { 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(()) Ok(())
} }
} }
/// LOCK REQUEST /// LOCK REQUEST
impl<C: Context> QuickWritable<C> for LockInfo { impl QWrite for LockInfo {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = ctx.create_dav_element("lockinfo"); let start = xml.create_dav_element("lockinfo");
let end = start.to_end(); let end = start.to_end();
xml.write_event_async(Event::Start(start.clone())).await?; xml.q.write_event_async(Event::Start(start.clone())).await?;
self.lockscope.write(xml, ctx.child()).await?; self.lockscope.qwrite(xml).await?;
self.locktype.write(xml, ctx.child()).await?; self.locktype.qwrite(xml).await?;
if let Some(owner) = &self.owner { 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 /// SOME LOCK RESPONSES
impl<C: Context> QuickWritable<C> for PropValue<C> { impl<E: Extension> QWrite for PropValue<E> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = ctx.create_dav_element("prop"); let start = xml.create_dav_element("prop");
let end = start.to_end(); 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 { 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 // --- XML inner elements
impl<C: Context> QuickWritable<C> for PropertyUpdateItem<C> { impl<E: Extension> QWrite for PropertyUpdateItem<E> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
match self { match self {
Self::Set(set) => set.write(xml, ctx).await, Self::Set(set) => set.qwrite(xml).await,
Self::Remove(rm) => rm.write(xml, ctx).await, Self::Remove(rm) => rm.qwrite(xml).await,
} }
} }
} }
impl<C: Context> QuickWritable<C> for Set<C> { impl<E: Extension> QWrite for Set<E> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = ctx.create_dav_element("set"); let start = xml.create_dav_element("set");
let end = start.to_end(); let end = start.to_end();
xml.write_event_async(Event::Start(start.clone())).await?; xml.q.write_event_async(Event::Start(start.clone())).await?;
self.0.write(xml, ctx.child()).await?; self.0.qwrite(xml).await?;
xml.write_event_async(Event::End(end)).await xml.q.write_event_async(Event::End(end)).await
} }
} }
impl<C: Context> QuickWritable<C> for Remove<C> { impl<E: Extension> QWrite for Remove<E> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = ctx.create_dav_element("remove"); let start = xml.create_dav_element("remove");
let end = start.to_end(); let end = start.to_end();
xml.write_event_async(Event::Start(start.clone())).await?; xml.q.write_event_async(Event::Start(start.clone())).await?;
self.0.write(xml, ctx.child()).await?; self.0.qwrite(xml).await?;
xml.write_event_async(Event::End(end)).await xml.q.write_event_async(Event::End(end)).await
} }
} }
impl<C: Context> QuickWritable<C> for AnyProp<C> { impl<E: Extension> QWrite for AnyProp<E> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
match self { match self {
Self::Name(propname) => propname.write(xml, ctx).await, Self::Name(propname) => propname.qwrite(xml).await,
Self::Value(propval) => propval.write(xml, ctx).await, Self::Value(propval) => propval.qwrite(xml).await,
} }
} }
} }
impl<C: Context> QuickWritable<C> for PropName<C> { impl<E: Extension> QWrite for PropName<E> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = ctx.create_dav_element("prop"); let start = xml.create_dav_element("prop");
let end = start.to_end(); 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 { 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<C: Context> QuickWritable<C> for Href { impl QWrite for Href {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = ctx.create_dav_element("href"); let start = xml.create_dav_element("href");
let end = start.to_end(); let end = start.to_end();
xml.write_event_async(Event::Start(start.clone())).await?; xml.q.write_event_async(Event::Start(start.clone())).await?;
xml.write_event_async(Event::Text(BytesText::new(&self.0))).await?; xml.q.write_event_async(Event::Text(BytesText::new(&self.0))).await?;
xml.write_event_async(Event::End(end)).await?; xml.q.write_event_async(Event::End(end)).await
Ok(())
} }
} }
impl<C: Context> QuickWritable<C> for Response<C> { impl<E: Extension> QWrite for Response<E> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = ctx.create_dav_element("response"); let start = xml.create_dav_element("response");
let end = start.to_end(); let end = start.to_end();
xml.write_event_async(Event::Start(start.clone())).await?; xml.q.write_event_async(Event::Start(start.clone())).await?;
self.href.write(xml, ctx.child()).await?; self.href.qwrite(xml).await?;
self.status_or_propstat.write(xml, ctx.child()).await?; self.status_or_propstat.qwrite(xml).await?;
if let Some(error) = &self.error { if let Some(error) = &self.error {
error.write(xml, ctx.child()).await?; error.qwrite(xml).await?;
} }
if let Some(responsedescription) = &self.responsedescription { if let Some(responsedescription) = &self.responsedescription {
responsedescription.write(xml, ctx.child()).await?; responsedescription.qwrite(xml).await?;
} }
if let Some(location) = &self.location { if let Some(location) = &self.location {
location.write(xml, ctx.child()).await?; location.qwrite(xml).await?;
} }
xml.write_event_async(Event::End(end)).await?; xml.q.write_event_async(Event::End(end)).await
Ok(())
} }
} }
impl<C: Context> QuickWritable<C> for StatusOrPropstat<C> { impl<E: Extension> QWrite for StatusOrPropstat<E> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
match self { match self {
Self::Status(status) => status.write(xml, ctx.child()).await, Self::Status(status) => status.qwrite(xml).await,
Self::PropStat(propstat_list) => { Self::PropStat(propstat_list) => {
for propstat in propstat_list.iter() { for propstat in propstat_list.iter() {
propstat.write(xml, ctx.child()).await?; propstat.qwrite(xml).await?;
} }
Ok(()) Ok(())
} }
} }
} }
} }
impl<C: Context> QuickWritable<C> for Status { impl QWrite for Status {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = ctx.create_dav_element("status"); let start = xml.create_dav_element("status");
let end = start.to_end(); 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")); 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(()) Ok(())
} }
} }
impl<C: Context> QuickWritable<C> for ResponseDescription { impl QWrite for ResponseDescription {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = ctx.create_dav_element("responsedescription"); let start = xml.create_dav_element("responsedescription");
let end = start.to_end(); let end = start.to_end();
xml.write_event_async(Event::Start(start.clone())).await?; xml.q.write_event_async(Event::Start(start.clone())).await?;
xml.write_event_async(Event::Text(BytesText::new(&self.0))).await?; xml.q.write_event_async(Event::Text(BytesText::new(&self.0))).await?;
xml.write_event_async(Event::End(end)).await?; xml.q.write_event_async(Event::End(end)).await
Ok(())
} }
} }
impl<C: Context> QuickWritable<C> for Location { impl QWrite for Location {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = ctx.create_dav_element("location"); let start = xml.create_dav_element("location");
let end = start.to_end(); let end = start.to_end();
xml.write_event_async(Event::Start(start.clone())).await?; xml.q.write_event_async(Event::Start(start.clone())).await?;
self.0.write(xml, ctx.child()).await?; self.0.qwrite(xml).await?;
xml.write_event_async(Event::End(end)).await?; xml.q.write_event_async(Event::End(end)).await
Ok(())
} }
} }
impl<C: Context> QuickWritable<C> for PropStat<C> { impl<E: Extension> QWrite for PropStat<E> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = ctx.create_dav_element("propstat"); let start = xml.create_dav_element("propstat");
let end = start.to_end(); let end = start.to_end();
xml.write_event_async(Event::Start(start.clone())).await?; xml.q.write_event_async(Event::Start(start.clone())).await?;
self.prop.write(xml, ctx.child()).await?; self.prop.qwrite(xml).await?;
self.status.write(xml, ctx.child()).await?; self.status.qwrite(xml).await?;
if let Some(error) = &self.error { if let Some(error) = &self.error {
error.write(xml, ctx.child()).await?; error.qwrite(xml).await?;
} }
if let Some(description) = &self.responsedescription { 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(()) Ok(())
} }
} }
impl<C: Context> QuickWritable<C> for Property<C> { impl<E: Extension> QWrite for Property<E> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
use Property::*; use Property::*;
match self { match self {
CreationDate(date) => { CreationDate(date) => {
// <D:creationdate>1997-12-01T17:42:21-08:00</D:creationdate> // <D:creationdate>1997-12-01T17:42:21-08:00</D:creationdate>
let start = ctx.create_dav_element("creationdate"); let start = xml.create_dav_element("creationdate");
let end = start.to_end(); let end = start.to_end();
xml.write_event_async(Event::Start(start.clone())).await?; xml.q.write_event_async(Event::Start(start.clone())).await?;
xml.write_event_async(Event::Text(BytesText::new(&date.to_rfc3339()))).await?; xml.q.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::End(end)).await?;
}, },
DisplayName(name) => { DisplayName(name) => {
// <D:displayname>Example collection</D:displayname> // <D:displayname>Example collection</D:displayname>
let start = ctx.create_dav_element("displayname"); let start = xml.create_dav_element("displayname");
let end = start.to_end(); let end = start.to_end();
xml.write_event_async(Event::Start(start.clone())).await?; xml.q.write_event_async(Event::Start(start.clone())).await?;
xml.write_event_async(Event::Text(BytesText::new(name))).await?; xml.q.write_event_async(Event::Text(BytesText::new(name))).await?;
xml.write_event_async(Event::End(end)).await?; xml.q.write_event_async(Event::End(end)).await?;
}, },
GetContentLanguage(lang) => { GetContentLanguage(lang) => {
let start = ctx.create_dav_element("getcontentlanguage"); let start = xml.create_dav_element("getcontentlanguage");
let end = start.to_end(); let end = start.to_end();
xml.write_event_async(Event::Start(start.clone())).await?; xml.q.write_event_async(Event::Start(start.clone())).await?;
xml.write_event_async(Event::Text(BytesText::new(lang))).await?; xml.q.write_event_async(Event::Text(BytesText::new(lang))).await?;
xml.write_event_async(Event::End(end)).await?; xml.q.write_event_async(Event::End(end)).await?;
}, },
GetContentLength(len) => { GetContentLength(len) => {
// <D:getcontentlength>4525</D:getcontentlength> // <D:getcontentlength>4525</D:getcontentlength>
let start = ctx.create_dav_element("getcontentlength"); let start = xml.create_dav_element("getcontentlength");
let end = start.to_end(); let end = start.to_end();
xml.write_event_async(Event::Start(start.clone())).await?; xml.q.write_event_async(Event::Start(start.clone())).await?;
xml.write_event_async(Event::Text(BytesText::new(&len.to_string()))).await?; xml.q.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::End(end)).await?;
}, },
GetContentType(ct) => { GetContentType(ct) => {
// <D:getcontenttype>text/html</D:getcontenttype> // <D:getcontenttype>text/html</D:getcontenttype>
let start = ctx.create_dav_element("getcontenttype"); let start = xml.create_dav_element("getcontenttype");
let end = start.to_end(); let end = start.to_end();
xml.write_event_async(Event::Start(start.clone())).await?; xml.q.write_event_async(Event::Start(start.clone())).await?;
xml.write_event_async(Event::Text(BytesText::new(&ct))).await?; xml.q.write_event_async(Event::Text(BytesText::new(&ct))).await?;
xml.write_event_async(Event::End(end)).await?; xml.q.write_event_async(Event::End(end)).await?;
}, },
GetEtag(et) => { GetEtag(et) => {
// <D:getetag>"zzyzx"</D:getetag> // <D:getetag>"zzyzx"</D:getetag>
let start = ctx.create_dav_element("getetag"); let start = xml.create_dav_element("getetag");
let end = start.to_end(); let end = start.to_end();
xml.write_event_async(Event::Start(start.clone())).await?; xml.q.write_event_async(Event::Start(start.clone())).await?;
xml.write_event_async(Event::Text(BytesText::new(et))).await?; xml.q.write_event_async(Event::Text(BytesText::new(et))).await?;
xml.write_event_async(Event::End(end)).await?; xml.q.write_event_async(Event::End(end)).await?;
}, },
GetLastModified(date) => { GetLastModified(date) => {
// <D:getlastmodified>Mon, 12 Jan 1998 09:25:56 GMT</D:getlastmodified> // <D:getlastmodified>Mon, 12 Jan 1998 09:25:56 GMT</D:getlastmodified>
let start = ctx.create_dav_element("getlastmodified"); let start = xml.create_dav_element("getlastmodified");
let end = start.to_end(); let end = start.to_end();
xml.write_event_async(Event::Start(start.clone())).await?; xml.q.write_event_async(Event::Start(start.clone())).await?;
xml.write_event_async(Event::Text(BytesText::new(&date.to_rfc2822()))).await?; xml.q.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::End(end)).await?;
}, },
LockDiscovery(many_locks) => { LockDiscovery(many_locks) => {
// <D:lockdiscovery><D:activelock> ... </D:activelock></D:lockdiscovery> // <D:lockdiscovery><D:activelock> ... </D:activelock></D:lockdiscovery>
let start = ctx.create_dav_element("lockdiscovery"); let start = xml.create_dav_element("lockdiscovery");
let end = start.to_end(); 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() { 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) => { ResourceType(many_types) => {
// <D:resourcetype><D:collection/></D:resourcetype> // <D:resourcetype><D:collection/></D:resourcetype>
@ -397,16 +346,16 @@ impl<C: Context> QuickWritable<C> for Property<C> {
// <f:search-results xmlns:f="http://www.example.com/ns"/> // <f:search-results xmlns:f="http://www.example.com/ns"/>
// </x:resourcetype> // </x:resourcetype>
let start = ctx.create_dav_element("resourcetype"); let start = xml.create_dav_element("resourcetype");
if many_types.is_empty() { if many_types.is_empty() {
xml.write_event_async(Event::Empty(start)).await?; xml.q.write_event_async(Event::Empty(start)).await?;
} else { } else {
let end = start.to_end(); 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() { 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) => { SupportedLock(many_entries) => {
@ -414,52 +363,56 @@ impl<C: Context> QuickWritable<C> for Property<C> {
// <D:supportedlock> <D:lockentry> ... </D:lockentry> </D:supportedlock> // <D:supportedlock> <D:lockentry> ... </D:lockentry> </D:supportedlock>
let start = ctx.create_dav_element("supportedlock"); let start = xml.create_dav_element("supportedlock");
if many_entries.is_empty() { if many_entries.is_empty() {
xml.write_event_async(Event::Empty(start)).await?; xml.q.write_event_async(Event::Empty(start)).await?;
} else { } else {
let end = start.to_end(); 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() { 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) => { Extension(inner) => inner.qwrite(xml).await?,
ctx.hook_property(inner, xml).await?;
},
}; };
Ok(()) Ok(())
} }
} }
impl<C: Context> QuickWritable<C> for ResourceType<C> { impl<E: Extension> QWrite for ResourceType<E> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
match self { match self {
Self::Collection => xml.write_event_async(Event::Empty(ctx.create_dav_element("collection"))).await, Self::Collection => {
Self::Extension(inner) => ctx.hook_resourcetype(inner, xml).await, 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<C: Context> QuickWritable<C> for Include<C> { impl<E: Extension> QWrite for Include<E> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = ctx.create_dav_element("include"); let start = xml.create_dav_element("include");
let end = start.to_end(); 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() { 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<C: Context> QuickWritable<C> for PropertyRequest<C> { impl<E: Extension> QWrite for PropertyRequest<E> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
use PropertyRequest::*; 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 { match self {
CreationDate => atom("creationdate").await, CreationDate => atom("creationdate").await,
@ -472,13 +425,13 @@ impl<C: Context> QuickWritable<C> for PropertyRequest<C> {
LockDiscovery => atom("lockdiscovery").await, LockDiscovery => atom("lockdiscovery").await,
ResourceType => atom("resourcetype").await, ResourceType => atom("resourcetype").await,
SupportedLock => atom("supportedlock").await, SupportedLock => atom("supportedlock").await,
Extension(inner) => ctx.hook_propertyrequest(inner, xml).await, Extension(inner) => inner.qwrite(xml).await,
} }
} }
} }
impl<C: Context> QuickWritable<C> for ActiveLock { impl QWrite for ActiveLock {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
// <D:activelock> // <D:activelock>
// <D:locktype><D:write/></D:locktype> // <D:locktype><D:write/></D:locktype>
// <D:lockscope><D:exclusive/></D:lockscope> // <D:lockscope><D:exclusive/></D:lockscope>
@ -494,192 +447,193 @@ impl<C: Context> QuickWritable<C> for ActiveLock {
// <D:href>http://example.com/workspace/webdav/proposal.doc</D:href> // <D:href>http://example.com/workspace/webdav/proposal.doc</D:href>
// </D:lockroot> // </D:lockroot>
// </D:activelock> // </D:activelock>
let start = ctx.create_dav_element("activelock"); let start = xml.create_dav_element("activelock");
let end = start.to_end(); let end = start.to_end();
xml.write_event_async(Event::Start(start.clone())).await?; xml.q.write_event_async(Event::Start(start.clone())).await?;
self.locktype.write(xml, ctx.child()).await?; self.locktype.qwrite(xml).await?;
self.lockscope.write(xml, ctx.child()).await?; self.lockscope.qwrite(xml).await?;
self.depth.write(xml, ctx.child()).await?; self.depth.qwrite(xml).await?;
if let Some(owner) = &self.owner { if let Some(owner) = &self.owner {
owner.write(xml, ctx.child()).await?; owner.qwrite(xml).await?;
} }
if let Some(timeout) = &self.timeout { if let Some(timeout) = &self.timeout {
timeout.write(xml, ctx.child()).await?; timeout.qwrite(xml).await?;
} }
if let Some(locktoken) = &self.locktoken { if let Some(locktoken) = &self.locktoken {
locktoken.write(xml, ctx.child()).await?; locktoken.qwrite(xml).await?;
} }
self.lockroot.write(xml, ctx.child()).await?; self.lockroot.qwrite(xml).await?;
xml.write_event_async(Event::End(end)).await?; xml.q.write_event_async(Event::End(end)).await
Ok(())
} }
} }
impl<C: Context> QuickWritable<C> for LockType { impl QWrite for LockType {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = ctx.create_dav_element("locktype"); let start = xml.create_dav_element("locktype");
let end = start.to_end(); 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 { 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<C: Context> QuickWritable<C> for LockScope { impl QWrite for LockScope {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = ctx.create_dav_element("lockscope"); let start = xml.create_dav_element("lockscope");
let end = start.to_end(); 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 { match self {
Self::Exclusive => xml.write_event_async(Event::Empty(ctx.create_dav_element("exclusive"))).await?, Self::Exclusive => {
Self::Shared => xml.write_event_async(Event::Empty(ctx.create_dav_element("shared"))).await?, 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<C: Context> QuickWritable<C> for Owner { impl QWrite for Owner {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = ctx.create_dav_element("owner"); let start = xml.create_dav_element("owner");
let end = start.to_end(); 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 { match self {
Self::Txt(txt) => xml.write_event_async(Event::Text(BytesText::new(&txt))).await?, Self::Txt(txt) => xml.q.write_event_async(Event::Text(BytesText::new(&txt))).await?,
Self::Href(href) => href.write(xml, ctx.child()).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<C: Context> QuickWritable<C> for Depth { impl QWrite for Depth {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = ctx.create_dav_element("depth"); let start = xml.create_dav_element("depth");
let end = start.to_end(); 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 { match self {
Self::Zero => xml.write_event_async(Event::Text(BytesText::new("0"))).await?, Self::Zero => xml.q.write_event_async(Event::Text(BytesText::new("0"))).await?,
Self::One => xml.write_event_async(Event::Text(BytesText::new("1"))).await?, Self::One => xml.q.write_event_async(Event::Text(BytesText::new("1"))).await?,
Self::Infinity => xml.write_event_async(Event::Text(BytesText::new("infinity"))).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<C: Context> QuickWritable<C> for Timeout { impl QWrite for Timeout {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = ctx.create_dav_element("timeout"); let start = xml.create_dav_element("timeout");
let end = start.to_end(); 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 { match self {
Self::Seconds(count) => { Self::Seconds(count) => {
let txt = format!("Second-{}", 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<C: Context> QuickWritable<C> for LockToken { impl QWrite for LockToken {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = ctx.create_dav_element("locktoken"); let start = xml.create_dav_element("locktoken");
let end = start.to_end(); let end = start.to_end();
xml.write_event_async(Event::Start(start.clone())).await?; xml.q.write_event_async(Event::Start(start.clone())).await?;
self.0.write(xml, ctx.child()).await?; self.0.qwrite(xml).await?;
xml.write_event_async(Event::End(end)).await xml.q.write_event_async(Event::End(end)).await
} }
} }
impl<C: Context> QuickWritable<C> for LockRoot { impl QWrite for LockRoot {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = ctx.create_dav_element("lockroot"); let start = xml.create_dav_element("lockroot");
let end = start.to_end(); let end = start.to_end();
xml.write_event_async(Event::Start(start.clone())).await?; xml.q.write_event_async(Event::Start(start.clone())).await?;
self.0.write(xml, ctx.child()).await?; self.0.qwrite(xml).await?;
xml.write_event_async(Event::End(end)).await xml.q.write_event_async(Event::End(end)).await
} }
} }
impl<C: Context> QuickWritable<C> for LockEntry { impl QWrite for LockEntry {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = ctx.create_dav_element("lockentry"); let start = xml.create_dav_element("lockentry");
let end = start.to_end(); let end = start.to_end();
xml.write_event_async(Event::Start(start.clone())).await?; xml.q.write_event_async(Event::Start(start.clone())).await?;
self.lockscope.write(xml, ctx.child()).await?; self.lockscope.qwrite(xml).await?;
self.locktype.write(xml, ctx.child()).await?; self.locktype.qwrite(xml).await?;
xml.write_event_async(Event::End(end)).await xml.q.write_event_async(Event::End(end)).await
} }
} }
impl<C: Context> QuickWritable<C> for Error<C> { impl<E: Extension> QWrite for Error<E> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = ctx.create_dav_element("error"); let start = xml.create_dav_element("error");
let end = start.to_end(); 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 { for violation in &self.0 {
violation.write(xml, ctx.child()).await?; violation.qwrite(xml).await?;
} }
xml.write_event_async(Event::End(end)).await?; xml.q.write_event_async(Event::End(end)).await
Ok(())
} }
} }
impl<C: Context> QuickWritable<C> for Violation<C> { impl<E: Extension> QWrite for Violation<E> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
match self { let mut atom = async |c| {
Violation::LockTokenMatchesRequestUri => xml.write_event_async(Event::Empty(ctx.create_dav_element("lock-token-matches-request-uri"))).await?, let empty_tag = xml.create_dav_element(c);
Violation::LockTokenSubmitted(hrefs) if hrefs.is_empty() => { xml.q.write_event_async(Event::Empty(empty_tag)).await
xml.write_event_async(Event::Empty(ctx.create_dav_element("lock-token-submitted"))).await?
},
Violation::LockTokenSubmitted(hrefs) => {
let start = ctx.create_dav_element("lock-token-submitted");
let end = start.to_end();
xml.write_event_async(Event::Start(start.clone())).await?;
for href in hrefs {
href.write(xml, ctx.child()).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?
},
Violation::NoConflictingLock(hrefs) => {
let start = ctx.create_dav_element("no-conflicting-lock");
let end = start.to_end();
xml.write_event_async(Event::Start(start.clone())).await?;
for href in hrefs {
href.write(xml, ctx.child()).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?;
},
}; };
Ok(())
match self {
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 = xml.create_dav_element("lock-token-submitted");
let end = start.to_end();
xml.q.write_event_async(Event::Start(start.clone())).await?;
for href in hrefs {
href.qwrite(xml).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 = xml.create_dav_element("no-conflicting-lock");
let end = start.to_end();
xml.q.write_event_async(Event::Start(start.clone())).await?;
for href in hrefs {
href.qwrite(xml).await?;
}
xml.q.write_event_async(Event::End(end)).await
},
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,
}
} }
} }

20
src/dav/error.rs Normal file
View file

@ -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<AttrError> for ParsingError {
fn from(value: AttrError) -> Self {
Self::QuickXml(value.into())
}
}
impl From<quick_xml::Error> for ParsingError {
fn from(value: quick_xml::Error) -> Self {
Self::QuickXml(value)
}
}

View file

@ -1,3 +1,5 @@
mod error;
mod xml;
mod types; mod types;
mod caltypes; mod caltypes;
mod acltypes; mod acltypes;
@ -5,6 +7,7 @@ mod versioningtypes;
mod encoder; mod encoder;
mod calencoder; mod calencoder;
mod decoder; mod decoder;
mod realization;
use std::net::SocketAddr; use std::net::SocketAddr;

41
src/dav/realization.rs Normal file
View file

@ -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<Disabled> for Disabled {
async fn qread(&self, xml: &mut xml::Reader<impl xml::IRead>) -> Result<Option<Self>, error::ParsingError> {
unreachable!();
}
}
impl xml::QWrite for Disabled {
async fn qwrite(&self, xml: &mut xml::Writer<impl xml::IWrite>) -> 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;
}
*/

View file

@ -1,28 +1,20 @@
#![allow(dead_code)] #![allow(dead_code)]
use std::fmt::Debug;
use chrono::{DateTime,FixedOffset}; use chrono::{DateTime,FixedOffset};
use super::xml;
use super::error;
/// Extension utilities /// It's how we implement a DAV extension
pub struct Disabled(()); /// (That's the dark magic part...)
pub trait ExtensionItem<T> = xml::QRead<T> + xml::QWrite + Debug + PartialEq;
pub trait Extension { pub trait Extension {
type Error; type Error: ExtensionItem<Self::Error>;
type Property; type Property: ExtensionItem<Self::Property>;
type PropertyRequest; type PropertyRequest: ExtensionItem<Self::PropertyRequest>;
type ResourceType; type ResourceType: ExtensionItem<Self::ResourceType>;
} }
/// 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 /// 14.1. activelock XML Element
/// ///
/// Name: activelock /// Name: activelock
@ -30,6 +22,7 @@ impl Extension for NoExtension {
/// Purpose: Describes a lock on a resource. /// Purpose: Describes a lock on a resource.
/// <!ELEMENT activelock (lockscope, locktype, depth, owner?, timeout?, /// <!ELEMENT activelock (lockscope, locktype, depth, owner?, timeout?,
/// locktoken?, lockroot)> /// locktoken?, lockroot)>
#[derive(Debug, PartialEq)]
pub struct ActiveLock { pub struct ActiveLock {
pub lockscope: LockScope, pub lockscope: LockScope,
pub locktype: LockType, pub locktype: LockType,
@ -50,6 +43,7 @@ pub struct ActiveLock {
/// elements. /// elements.
/// ///
/// <!ELEMENT collection EMPTY > /// <!ELEMENT collection EMPTY >
#[derive(Debug, PartialEq)]
pub struct Collection{} pub struct Collection{}
/// 14.4 depth XML Element /// 14.4 depth XML Element
@ -62,6 +56,7 @@ pub struct Collection{}
/// Value: "0" | "1" | "infinity" /// Value: "0" | "1" | "infinity"
/// ///
/// <!ELEMENT depth (#PCDATA) > /// <!ELEMENT depth (#PCDATA) >
#[derive(Debug, PartialEq)]
pub enum Depth { pub enum Depth {
Zero, Zero,
One, One,
@ -84,8 +79,10 @@ pub enum Depth {
/// postcondition code. Unrecognized elements MUST be ignored. /// postcondition code. Unrecognized elements MUST be ignored.
/// ///
/// <!ELEMENT error ANY > /// <!ELEMENT error ANY >
pub struct Error<T: Extension>(pub Vec<Violation<T>>); #[derive(Debug, PartialEq)]
pub enum Violation<T: Extension> { pub struct Error<E: Extension>(pub Vec<Violation<E>>);
#[derive(Debug, PartialEq)]
pub enum Violation<E: Extension> {
/// Name: lock-token-matches-request-uri /// Name: lock-token-matches-request-uri
/// ///
/// Use with: 409 Conflict /// Use with: 409 Conflict
@ -169,7 +166,7 @@ pub enum Violation<T: Extension> {
CannotModifyProtectedProperty, CannotModifyProtectedProperty,
/// Specific errors /// Specific errors
Extension(T::Error), Extension(E::Error),
} }
/// 14.6. exclusive XML Element /// 14.6. exclusive XML Element
@ -179,6 +176,7 @@ pub enum Violation<T: Extension> {
/// Purpose: Specifies an exclusive lock. /// Purpose: Specifies an exclusive lock.
/// ///
/// <!ELEMENT exclusive EMPTY > /// <!ELEMENT exclusive EMPTY >
#[derive(Debug, PartialEq)]
pub struct Exclusive {} pub struct Exclusive {}
/// 14.7. href XML Element /// 14.7. href XML Element
@ -194,6 +192,7 @@ pub struct Exclusive {}
/// Value: Simple-ref /// Value: Simple-ref
/// ///
/// <!ELEMENT href (#PCDATA)> /// <!ELEMENT href (#PCDATA)>
#[derive(Debug, PartialEq)]
pub struct Href(pub String); pub struct Href(pub String);
@ -209,7 +208,8 @@ pub struct Href(pub String);
/// standards. This element MUST NOT contain text or mixed content. /// standards. This element MUST NOT contain text or mixed content.
/// ///
/// <!ELEMENT include ANY > /// <!ELEMENT include ANY >
pub struct Include<T: Extension>(pub Vec<PropertyRequest<T>>); #[derive(Debug, PartialEq)]
pub struct Include<E: Extension>(pub Vec<PropertyRequest<E>>);
/// 14.9. location XML Element /// 14.9. location XML Element
/// ///
@ -225,6 +225,7 @@ pub struct Include<T: Extension>(pub Vec<PropertyRequest<T>>);
/// that would be used in a Location header. /// that would be used in a Location header.
/// ///
/// <!ELEMENT location (href)> /// <!ELEMENT location (href)>
#[derive(Debug, PartialEq)]
pub struct Location(pub Href); pub struct Location(pub Href);
/// 14.10. lockentry XML Element /// 14.10. lockentry XML Element
@ -235,6 +236,7 @@ pub struct Location(pub Href);
/// resource. /// resource.
/// ///
/// <!ELEMENT lockentry (lockscope, locktype) > /// <!ELEMENT lockentry (lockscope, locktype) >
#[derive(Debug, PartialEq)]
pub struct LockEntry { pub struct LockEntry {
pub lockscope: LockScope, pub lockscope: LockScope,
pub locktype: LockType, pub locktype: LockType,
@ -248,6 +250,7 @@ pub struct LockEntry {
/// specify the type of lock the client wishes to have created. /// specify the type of lock the client wishes to have created.
/// ///
/// <!ELEMENT lockinfo (lockscope, locktype, owner?) > /// <!ELEMENT lockinfo (lockscope, locktype, owner?) >
#[derive(Debug, PartialEq)]
pub struct LockInfo { pub struct LockInfo {
pub lockscope: LockScope, pub lockscope: LockScope,
pub locktype: LockType, pub locktype: LockType,
@ -266,6 +269,7 @@ pub struct LockInfo {
/// values and the response to LOCK requests. /// values and the response to LOCK requests.
/// ///
/// <!ELEMENT lockroot (href) > /// <!ELEMENT lockroot (href) >
#[derive(Debug, PartialEq)]
pub struct LockRoot(pub Href); pub struct LockRoot(pub Href);
/// 14.13. lockscope XML Element /// 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 /// Purpose: Specifies whether a lock is an exclusive lock, or a shared
/// lock. /// lock.
/// <!ELEMENT lockscope (exclusive | shared) > /// <!ELEMENT lockscope (exclusive | shared) >
#[derive(Debug, PartialEq)]
pub enum LockScope { pub enum LockScope {
Exclusive, Exclusive,
Shared Shared
@ -290,6 +295,7 @@ pub enum LockScope {
/// refers to the lock. /// refers to the lock.
/// ///
/// <!ELEMENT locktoken (href) > /// <!ELEMENT locktoken (href) >
#[derive(Debug, PartialEq)]
pub struct LockToken(pub Href); pub struct LockToken(pub Href);
/// 14.15. locktype XML Element /// 14.15. locktype XML Element
@ -300,6 +306,7 @@ pub struct LockToken(pub Href);
/// specification only defines one lock type, the write lock. /// specification only defines one lock type, the write lock.
/// ///
/// <!ELEMENT locktype (write) > /// <!ELEMENT locktype (write) >
#[derive(Debug, PartialEq)]
pub enum LockType { pub enum LockType {
/// 14.30. write XML Element /// 14.30. write XML Element
/// ///
@ -325,8 +332,9 @@ pub enum LockType {
/// response descriptions contained within the responses. /// response descriptions contained within the responses.
/// ///
/// <!ELEMENT multistatus (response*, responsedescription?) > /// <!ELEMENT multistatus (response*, responsedescription?) >
pub struct Multistatus<T: Extension> { #[derive(Debug, PartialEq)]
pub responses: Vec<Response<T>>, pub struct Multistatus<E: Extension> {
pub responses: Vec<Response<E>>,
pub responsedescription: Option<ResponseDescription>, pub responsedescription: Option<ResponseDescription>,
} }
@ -354,6 +362,7 @@ pub struct Multistatus<T: Extension> {
/// ///
/// <!ELEMENT owner ANY > /// <!ELEMENT owner ANY >
//@FIXME might need support for an extension //@FIXME might need support for an extension
#[derive(Debug, PartialEq)]
pub enum Owner { pub enum Owner {
Txt(String), Txt(String),
Href(Href), Href(Href),
@ -373,12 +382,17 @@ pub enum Owner {
/// text or mixed content. /// text or mixed content.
/// ///
/// <!ELEMENT prop ANY > /// <!ELEMENT prop ANY >
pub enum AnyProp<T: Extension> { #[derive(Debug, PartialEq)]
Name(PropName<T>), pub enum AnyProp<E: Extension> {
Value(PropValue<T>), Name(PropName<E>),
Value(PropValue<E>),
} }
pub struct PropName<T: Extension>(pub Vec<PropertyRequest<T>>);
pub struct PropValue<T: Extension>(pub Vec<Property<T>>); #[derive(Debug, PartialEq)]
pub struct PropName<E: Extension>(pub Vec<PropertyRequest<E>>);
#[derive(Debug, PartialEq)]
pub struct PropValue<E: Extension>(pub Vec<Property<E>>);
/// 14.19. propertyupdate XML Element /// 14.19. propertyupdate XML Element
/// ///
@ -390,10 +404,13 @@ pub struct PropValue<T: Extension>(pub Vec<Property<T>>);
/// required to modify the properties on the resource. /// required to modify the properties on the resource.
/// ///
/// <!ELEMENT propertyupdate (remove | set)+ > /// <!ELEMENT propertyupdate (remove | set)+ >
pub struct PropertyUpdate<T: Extension>(pub Vec<PropertyUpdateItem<T>>); #[derive(Debug, PartialEq)]
pub enum PropertyUpdateItem<T: Extension> { pub struct PropertyUpdate<E: Extension>(pub Vec<PropertyUpdateItem<E>>);
Remove(Remove<T>),
Set(Set<T>), #[derive(Debug, PartialEq)]
pub enum PropertyUpdateItem<E: Extension> {
Remove(Remove<E>),
Set(Set<E>),
} }
/// 14.2 allprop XML Element /// 14.2 allprop XML Element
@ -430,10 +447,11 @@ pub enum PropertyUpdateItem<T: Extension> {
/// values. /// values.
/// ///
/// <!ELEMENT propfind ( propname | (allprop, include?) | prop ) > /// <!ELEMENT propfind ( propname | (allprop, include?) | prop ) >
pub enum PropFind<T: Extension> { #[derive(Debug, PartialEq)]
pub enum PropFind<E: Extension> {
PropName, PropName,
AllProp(Option<Include<T>>), AllProp(Option<Include<E>>),
Prop(PropName<T>), Prop(PropName<E>),
} }
/// 14.22 propstat XML Element /// 14.22 propstat XML Element
@ -451,10 +469,11 @@ pub enum PropFind<T: Extension> {
/// the properties named in 'prop'. /// the properties named in 'prop'.
/// ///
/// <!ELEMENT propstat (prop, status, error?, responsedescription?) > /// <!ELEMENT propstat (prop, status, error?, responsedescription?) >
pub struct PropStat<T: Extension> { #[derive(Debug, PartialEq)]
pub prop: AnyProp<T>, pub struct PropStat<E: Extension> {
pub prop: AnyProp<E>,
pub status: Status, pub status: Status,
pub error: Option<Error<T>>, pub error: Option<Error<E>>,
pub responsedescription: Option<ResponseDescription>, pub responsedescription: Option<ResponseDescription>,
} }
@ -471,7 +490,8 @@ pub struct PropStat<T: Extension> {
/// the names of properties to be removed are required. /// the names of properties to be removed are required.
/// ///
/// <!ELEMENT remove (prop) > /// <!ELEMENT remove (prop) >
pub struct Remove<T: Extension>(pub PropName<T>); #[derive(Debug, PartialEq)]
pub struct Remove<E: Extension>(pub PropName<E>);
/// 14.24. response XML Element /// 14.24. response XML Element
/// ///
@ -495,14 +515,17 @@ pub struct Remove<T: Extension>(pub PropName<T>);
/// ///
/// <!ELEMENT response (href, ((href*, status)|(propstat+)), /// <!ELEMENT response (href, ((href*, status)|(propstat+)),
/// error?, responsedescription? , location?) > /// error?, responsedescription? , location?) >
pub enum StatusOrPropstat<T: Extension> { #[derive(Debug, PartialEq)]
pub enum StatusOrPropstat<E: Extension> {
Status(Status), Status(Status),
PropStat(Vec<PropStat<T>>), PropStat(Vec<PropStat<E>>),
} }
pub struct Response<T: Extension> {
#[derive(Debug, PartialEq)]
pub struct Response<E: Extension> {
pub href: Href, // It's wrong according to the spec, but I don't understand why there is an href* 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<T>, pub status_or_propstat: StatusOrPropstat<E>,
pub error: Option<Error<T>>, pub error: Option<Error<E>>,
pub responsedescription: Option<ResponseDescription>, pub responsedescription: Option<ResponseDescription>,
pub location: Option<Location>, pub location: Option<Location>,
} }
@ -518,6 +541,7 @@ pub struct Response<T: Extension> {
/// user. /// user.
/// ///
/// <!ELEMENT responsedescription (#PCDATA) > /// <!ELEMENT responsedescription (#PCDATA) >
#[derive(Debug, PartialEq)]
pub struct ResponseDescription(pub String); pub struct ResponseDescription(pub String);
/// 14.26. set XML Element /// 14.26. set XML Element
@ -536,7 +560,8 @@ pub struct ResponseDescription(pub String);
/// property, and MUST be subsequently retrievable using PROPFIND. /// property, and MUST be subsequently retrievable using PROPFIND.
/// ///
/// <!ELEMENT set (prop) > /// <!ELEMENT set (prop) >
pub struct Set<T: Extension>(pub PropValue<T>); #[derive(Debug, PartialEq)]
pub struct Set<E: Extension>(pub PropValue<E>);
/// 14.27. shared XML Element /// 14.27. shared XML Element
/// ///
@ -546,6 +571,7 @@ pub struct Set<T: Extension>(pub PropValue<T>);
/// ///
/// ///
/// <!ELEMENT shared EMPTY > /// <!ELEMENT shared EMPTY >
#[derive(Debug, PartialEq)]
pub struct Shared {} pub struct Shared {}
@ -559,6 +585,7 @@ pub struct Shared {}
/// ///
/// <!ELEMENT status (#PCDATA) > /// <!ELEMENT status (#PCDATA) >
//@FIXME: Better typing is possible with an enum for example //@FIXME: Better typing is possible with an enum for example
#[derive(Debug, PartialEq)]
pub struct Status(pub http::status::StatusCode); pub struct Status(pub http::status::StatusCode);
/// 14.29. timeout XML Element /// 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 /// elapse between granting of the lock at the server, and the automatic
/// removal of the lock. The timeout value for TimeType "Second" MUST /// removal of the lock. The timeout value for TimeType "Second" MUST
/// NOT be greater than 2^32-1. /// NOT be greater than 2^32-1.
#[derive(Debug, PartialEq)]
pub enum Timeout { pub enum Timeout {
Seconds(u32), Seconds(u32),
Infinite, Infinite,
@ -619,7 +647,8 @@ pub enum Timeout {
/// the header value could include LWS as defined in [RFC2616], Section /// the header value could include LWS as defined in [RFC2616], Section
/// 4.2. Server implementors SHOULD strip LWS from these values before /// 4.2. Server implementors SHOULD strip LWS from these values before
/// using as WebDAV property values. /// using as WebDAV property values.
pub enum PropertyRequest<T: Extension> { #[derive(Debug, PartialEq)]
pub enum PropertyRequest<E: Extension> {
CreationDate, CreationDate,
DisplayName, DisplayName,
GetContentLanguage, GetContentLanguage,
@ -630,9 +659,11 @@ pub enum PropertyRequest<T: Extension> {
LockDiscovery, LockDiscovery,
ResourceType, ResourceType,
SupportedLock, SupportedLock,
Extension(T::PropertyRequest), Extension(E::PropertyRequest),
} }
pub enum Property<T: Extension> {
#[derive(Debug, PartialEq)]
pub enum Property<E: Extension> {
/// 15.1. creationdate Property /// 15.1. creationdate Property
/// ///
/// Name: creationdate /// Name: creationdate
@ -883,7 +914,7 @@ pub enum Property<T: Extension> {
/// <x:collection/> /// <x:collection/>
/// <f:search-results xmlns:f="http://www.example.com/ns"/> /// <f:search-results xmlns:f="http://www.example.com/ns"/>
/// </x:resourcetype> /// </x:resourcetype>
ResourceType(Vec<ResourceType<T>>), ResourceType(Vec<ResourceType<E>>),
/// 15.10. supportedlock Property /// 15.10. supportedlock Property
/// ///
@ -911,10 +942,11 @@ pub enum Property<T: Extension> {
SupportedLock(Vec<LockEntry>), SupportedLock(Vec<LockEntry>),
/// Any extension /// Any extension
Extension(T::Property), Extension(E::Property),
} }
pub enum ResourceType<T: Extension> { #[derive(Debug, PartialEq)]
pub enum ResourceType<E: Extension> {
Collection, Collection,
Extension(T::ResourceType), Extension(E::ResourceType),
} }

128
src/dav/xml.rs Normal file
View file

@ -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<impl IWrite>) -> Result<(), quick_xml::Error>;
}
pub trait QRead<T> {
async fn qread(&self, xml: &mut Reader<impl IRead>) -> Result<Option<T>, ParsingError>;
}
/// Transform a Rust object into an XML stream of characters
pub struct Writer<T: IWrite> {
pub q: quick_xml::writer::Writer<T>,
root: bool,
}
impl<T: IWrite> Writer<T> {
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<T: IRead> {
evt: Event<'static>,
rdr: NsReader<T>,
buf: Vec<u8>,
}
impl<T: IRead> Reader<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 })
}
fn peek(&self) -> &Event<'static> {
&self.evt
}
/// 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::End(_) => Err(ParsingError::WrongToken),
Event::Eof => Err(ParsingError::Eof),
_ => self.next().await,
}
}
/// 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();
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
}
}