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::caltypes::*;
use super::types::Extension;
@ -893,3 +894,4 @@ mod tests {
assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n");
}
}
*/

View file

@ -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].
///
/// <!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
@ -51,7 +43,7 @@ pub struct MkCalendar<E: Dav::Extension>(pub Dav::Set<E>);
/// Definition:
///
/// <!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) ---
@ -68,8 +60,8 @@ pub struct MkCalendarResponse<T: Dav::Extension>(pub Vec<Dav::PropStat<T>>);
/// <!ELEMENT calendar-query ((DAV:allprop |
/// DAV:propname |
/// DAV:prop)?, filter, timezone?)>
pub struct CalendarQuery<T: Dav::Extension> {
pub selector: Option<CalendarSelector<T>>,
pub struct CalendarQuery<E: dav::Extension> {
pub selector: Option<CalendarSelector<E>>,
pub filter: Filter,
pub timezone: Option<TimeZone>,
}
@ -88,9 +80,9 @@ pub struct CalendarQuery<T: Dav::Extension> {
/// <!ELEMENT calendar-multiget ((DAV:allprop |
/// DAV:propname |
/// DAV:prop)?, DAV:href+)>
pub struct CalendarMultiget<T: Dav::Extension> {
pub selector: Option<CalendarSelector<T>>,
pub href: Vec<Dav::Href>,
pub struct CalendarMultiget<E: dav::Extension> {
pub selector: Option<CalendarSelector<E>>,
pub href: Vec<dav::Href>,
}
/// 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>);
/// Used by CalendarQuery & CalendarMultiget
pub enum CalendarSelector<T: Dav::Extension> {
pub enum CalendarSelector<E: dav::Extension> {
AllProp,
PropName,
Prop(Dav::PropName<T>),
Prop(dav::PropName<E>),
}
/// Name: comp-filter
@ -1402,4 +1394,4 @@ impl Collation {
Self::Unknown(c) => c.as_str(),
}
}
}
}*/

View file

@ -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<impl Reader>) -> Result<Option<Self::PropertyRequest>, ParsingError>;
}
impl From<AttrError> for ParsingError {
fn from(value: AttrError) -> Self {
Self::QuickXml(value.into())
impl Decodable for NoExtension {
async fn decode_propreq(xml: &mut PeekRead<impl Reader>) -> Result<Option<Disabled>, ParsingError> {
Ok(None)
}
}
impl From<quick_xml::Error> for ParsingError {
fn from(value: quick_xml::Error) -> Self {
Self::QuickXml(value)
}
pub trait QReadable<T: Reader>: Sized {
async fn read(xml: &mut PeekRead<T>) -> Result<Self, ParsingError>;
}
// --- 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<T: Reader> {
evt: Event<'static>,
rdr: NsReader<T>,
@ -117,11 +116,9 @@ impl<T: Reader> PeekRead<T> {
}
}
pub trait QReadable<T: Reader>: Sized {
async fn read(xml: &mut PeekRead<T>) -> Result<Self, ParsingError>;
}
// ----- Decode ----
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> {
// Find propfind
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> {
xml.tag_start(DAV_URN, "include").await?;
let mut acc: Vec<PropertyRequest<E>> = 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<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> {
xml.tag_start(DAV_URN, "prop").await?;
let mut acc: Vec<PropertyRequest<E>> = Vec::new();
loop {
match xml.peek() {
Event::Start(_) => acc.push(PropertyRequest::read(xml).await?),
Event::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<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> {
/*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#"<?xml version="1.0" encoding="utf-8" ?>
<rando/>
<garbage><old/></garbage>
@ -220,4 +257,37 @@ mod tests {
let got = PropFind::<NoExtension>::read(&mut rdr).await.unwrap();
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::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<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
/// PROPFIND REQUEST
impl<C: Context> QuickWritable<C> for PropFind<C> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("propfind");
impl<E: Extension> QWrite for PropFind<E> {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for PropertyUpdate<C> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("propertyupdate");
impl<E: Extension> QWrite for PropertyUpdate<E> {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for Multistatus<C> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("multistatus");
impl<E: Extension> QWrite for Multistatus<E> {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for LockInfo {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("lockinfo");
impl QWrite for LockInfo {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for PropValue<C> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("prop");
impl<E: Extension> QWrite for PropValue<E> {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for PropertyUpdateItem<C> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
impl<E: Extension> QWrite for PropertyUpdateItem<E> {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for Set<C> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("set");
impl<E: Extension> QWrite for Set<E> {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for Remove<C> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("remove");
impl<E: Extension> QWrite for Remove<E> {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for AnyProp<C> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
impl<E: Extension> QWrite for AnyProp<E> {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for PropName<C> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("prop");
impl<E: Extension> QWrite for PropName<E> {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for Href {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("href");
impl QWrite for Href {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for Response<C> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("response");
impl<E: Extension> QWrite for Response<E> {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for StatusOrPropstat<C> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
impl<E: Extension> QWrite for StatusOrPropstat<E> {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for Status {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("status");
impl QWrite for Status {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for ResponseDescription {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("responsedescription");
impl QWrite for ResponseDescription {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for Location {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("location");
impl QWrite for Location {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for PropStat<C> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("propstat");
impl<E: Extension> QWrite for PropStat<E> {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for Property<C> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
impl<E: Extension> QWrite for Property<E> {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
use Property::*;
match self {
CreationDate(date) => {
// <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();
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) => {
// <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();
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) => {
// <D:getcontentlength>4525</D:getcontentlength>
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) => {
// <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();
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) => {
// <D:getetag>"zzyzx"</D:getetag>
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) => {
// <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();
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) => {
// <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();
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) => {
// <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"/>
// </x:resourcetype>
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<C: Context> QuickWritable<C> for Property<C> {
// <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() {
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<C: Context> QuickWritable<C> for ResourceType<C> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
impl<E: Extension> QWrite for ResourceType<E> {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for Include<C> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("include");
impl<E: Extension> QWrite for Include<E> {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for PropertyRequest<C> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
impl<E: Extension> QWrite for PropertyRequest<E> {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for PropertyRequest<C> {
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<C: Context> QuickWritable<C> for ActiveLock {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
impl QWrite for ActiveLock {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
// <D:activelock>
// <D:locktype><D:write/></D:locktype>
// <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:lockroot>
// </D:activelock>
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<C: Context> QuickWritable<C> for LockType {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("locktype");
impl QWrite for LockType {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for LockScope {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("lockscope");
impl QWrite for LockScope {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for Owner {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("owner");
impl QWrite for Owner {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for Depth {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("depth");
impl QWrite for Depth {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for Timeout {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("timeout");
impl QWrite for Timeout {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for LockToken {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("locktoken");
impl QWrite for LockToken {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for LockRoot {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("lockroot");
impl QWrite for LockRoot {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for LockEntry {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("lockentry");
impl QWrite for LockEntry {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for Error<C> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("error");
impl<E: Extension> QWrite for Error<E> {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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<C: Context> QuickWritable<C> for Violation<C> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
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::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?;
},
impl<E: Extension> QWrite for Violation<E> {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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
};
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 caltypes;
mod acltypes;
@ -5,6 +7,7 @@ mod versioningtypes;
mod encoder;
mod calencoder;
mod decoder;
mod realization;
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)]
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<T> = xml::QRead<T> + xml::QWrite + Debug + PartialEq;
pub trait Extension {
type Error;
type Property;
type PropertyRequest;
type ResourceType;
type Error: ExtensionItem<Self::Error>;
type Property: ExtensionItem<Self::Property>;
type PropertyRequest: ExtensionItem<Self::PropertyRequest>;
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
///
/// Name: activelock
@ -30,6 +22,7 @@ impl Extension for NoExtension {
/// Purpose: Describes a lock on a resource.
/// <!ELEMENT activelock (lockscope, locktype, depth, owner?, timeout?,
/// locktoken?, lockroot)>
#[derive(Debug, PartialEq)]
pub struct ActiveLock {
pub lockscope: LockScope,
pub locktype: LockType,
@ -50,6 +43,7 @@ pub struct ActiveLock {
/// elements.
///
/// <!ELEMENT collection EMPTY >
#[derive(Debug, PartialEq)]
pub struct Collection{}
/// 14.4 depth XML Element
@ -62,6 +56,7 @@ pub struct Collection{}
/// Value: "0" | "1" | "infinity"
///
/// <!ELEMENT depth (#PCDATA) >
#[derive(Debug, PartialEq)]
pub enum Depth {
Zero,
One,
@ -84,8 +79,10 @@ pub enum Depth {
/// postcondition code. Unrecognized elements MUST be ignored.
///
/// <!ELEMENT error ANY >
pub struct Error<T: Extension>(pub Vec<Violation<T>>);
pub enum Violation<T: Extension> {
#[derive(Debug, PartialEq)]
pub struct Error<E: Extension>(pub Vec<Violation<E>>);
#[derive(Debug, PartialEq)]
pub enum Violation<E: Extension> {
/// Name: lock-token-matches-request-uri
///
/// Use with: 409 Conflict
@ -169,7 +166,7 @@ pub enum Violation<T: Extension> {
CannotModifyProtectedProperty,
/// Specific errors
Extension(T::Error),
Extension(E::Error),
}
/// 14.6. exclusive XML Element
@ -179,6 +176,7 @@ pub enum Violation<T: Extension> {
/// Purpose: Specifies an exclusive lock.
///
/// <!ELEMENT exclusive EMPTY >
#[derive(Debug, PartialEq)]
pub struct Exclusive {}
/// 14.7. href XML Element
@ -194,6 +192,7 @@ pub struct Exclusive {}
/// Value: Simple-ref
///
/// <!ELEMENT href (#PCDATA)>
#[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.
///
/// <!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
///
@ -225,6 +225,7 @@ pub struct Include<T: Extension>(pub Vec<PropertyRequest<T>>);
/// that would be used in a Location header.
///
/// <!ELEMENT location (href)>
#[derive(Debug, PartialEq)]
pub struct Location(pub Href);
/// 14.10. lockentry XML Element
@ -235,6 +236,7 @@ pub struct Location(pub Href);
/// resource.
///
/// <!ELEMENT lockentry (lockscope, locktype) >
#[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.
///
/// <!ELEMENT lockinfo (lockscope, locktype, owner?) >
#[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.
///
/// <!ELEMENT lockroot (href) >
#[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.
/// <!ELEMENT lockscope (exclusive | shared) >
#[derive(Debug, PartialEq)]
pub enum LockScope {
Exclusive,
Shared
@ -290,6 +295,7 @@ pub enum LockScope {
/// refers to the lock.
///
/// <!ELEMENT locktoken (href) >
#[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.
///
/// <!ELEMENT locktype (write) >
#[derive(Debug, PartialEq)]
pub enum LockType {
/// 14.30. write XML Element
///
@ -325,8 +332,9 @@ pub enum LockType {
/// response descriptions contained within the responses.
///
/// <!ELEMENT multistatus (response*, responsedescription?) >
pub struct Multistatus<T: Extension> {
pub responses: Vec<Response<T>>,
#[derive(Debug, PartialEq)]
pub struct Multistatus<E: Extension> {
pub responses: Vec<Response<E>>,
pub responsedescription: Option<ResponseDescription>,
}
@ -354,6 +362,7 @@ pub struct Multistatus<T: Extension> {
///
/// <!ELEMENT owner ANY >
//@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.
///
/// <!ELEMENT prop ANY >
pub enum AnyProp<T: Extension> {
Name(PropName<T>),
Value(PropValue<T>),
#[derive(Debug, PartialEq)]
pub enum AnyProp<E: Extension> {
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
///
@ -390,10 +404,13 @@ pub struct PropValue<T: Extension>(pub Vec<Property<T>>);
/// required to modify the properties on the resource.
///
/// <!ELEMENT propertyupdate (remove | set)+ >
pub struct PropertyUpdate<T: Extension>(pub Vec<PropertyUpdateItem<T>>);
pub enum PropertyUpdateItem<T: Extension> {
Remove(Remove<T>),
Set(Set<T>),
#[derive(Debug, PartialEq)]
pub struct PropertyUpdate<E: Extension>(pub Vec<PropertyUpdateItem<E>>);
#[derive(Debug, PartialEq)]
pub enum PropertyUpdateItem<E: Extension> {
Remove(Remove<E>),
Set(Set<E>),
}
/// 14.2 allprop XML Element
@ -430,10 +447,11 @@ pub enum PropertyUpdateItem<T: Extension> {
/// values.
///
/// <!ELEMENT propfind ( propname | (allprop, include?) | prop ) >
pub enum PropFind<T: Extension> {
#[derive(Debug, PartialEq)]
pub enum PropFind<E: Extension> {
PropName,
AllProp(Option<Include<T>>),
Prop(PropName<T>),
AllProp(Option<Include<E>>),
Prop(PropName<E>),
}
/// 14.22 propstat XML Element
@ -451,10 +469,11 @@ pub enum PropFind<T: Extension> {
/// the properties named in 'prop'.
///
/// <!ELEMENT propstat (prop, status, error?, responsedescription?) >
pub struct PropStat<T: Extension> {
pub prop: AnyProp<T>,
#[derive(Debug, PartialEq)]
pub struct PropStat<E: Extension> {
pub prop: AnyProp<E>,
pub status: Status,
pub error: Option<Error<T>>,
pub error: Option<Error<E>>,
pub responsedescription: Option<ResponseDescription>,
}
@ -471,7 +490,8 @@ pub struct PropStat<T: Extension> {
/// the names of properties to be removed are required.
///
/// <!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
///
@ -495,14 +515,17 @@ pub struct Remove<T: Extension>(pub PropName<T>);
///
/// <!ELEMENT response (href, ((href*, status)|(propstat+)),
/// error?, responsedescription? , location?) >
pub enum StatusOrPropstat<T: Extension> {
#[derive(Debug, PartialEq)]
pub enum StatusOrPropstat<E: Extension> {
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 status_or_propstat: StatusOrPropstat<T>,
pub error: Option<Error<T>>,
pub status_or_propstat: StatusOrPropstat<E>,
pub error: Option<Error<E>>,
pub responsedescription: Option<ResponseDescription>,
pub location: Option<Location>,
}
@ -518,6 +541,7 @@ pub struct Response<T: Extension> {
/// user.
///
/// <!ELEMENT responsedescription (#PCDATA) >
#[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.
///
/// <!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
///
@ -546,6 +571,7 @@ pub struct Set<T: Extension>(pub PropValue<T>);
///
///
/// <!ELEMENT shared EMPTY >
#[derive(Debug, PartialEq)]
pub struct Shared {}
@ -559,6 +585,7 @@ pub struct Shared {}
///
/// <!ELEMENT status (#PCDATA) >
//@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<T: Extension> {
#[derive(Debug, PartialEq)]
pub enum PropertyRequest<E: Extension> {
CreationDate,
DisplayName,
GetContentLanguage,
@ -630,9 +659,11 @@ pub enum PropertyRequest<T: Extension> {
LockDiscovery,
ResourceType,
SupportedLock,
Extension(T::PropertyRequest),
Extension(E::PropertyRequest),
}
pub enum Property<T: Extension> {
#[derive(Debug, PartialEq)]
pub enum Property<E: Extension> {
/// 15.1. creationdate Property
///
/// Name: creationdate
@ -883,7 +914,7 @@ pub enum Property<T: Extension> {
/// <x:collection/>
/// <f:search-results xmlns:f="http://www.example.com/ns"/>
/// </x:resourcetype>
ResourceType(Vec<ResourceType<T>>),
ResourceType(Vec<ResourceType<E>>),
/// 15.10. supportedlock Property
///
@ -911,10 +942,11 @@ pub enum Property<T: Extension> {
SupportedLock(Vec<LockEntry>),
/// Any extension
Extension(T::Property),
Extension(E::Property),
}
pub enum ResourceType<T: Extension> {
#[derive(Debug, PartialEq)]
pub enum ResourceType<E: Extension> {
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
}
}