Refactor encoder+decoder WIP (compile)
This commit is contained in:
parent
b7a990ecdb
commit
8e5d8a8aaa
9 changed files with 689 additions and 447 deletions
|
@ -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");
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
|
|
@ -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,
|
||||
])));
|
||||
}
|
||||
*/
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -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
20
src/dav/error.rs
Normal 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)
|
||||
}
|
||||
}
|
|
@ -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
41
src/dav/realization.rs
Normal 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;
|
||||
}
|
||||
*/
|
138
src/dav/types.rs
138
src/dav/types.rs
|
@ -1,28 +1,20 @@
|
|||
#![allow(dead_code)]
|
||||
use std::fmt::Debug;
|
||||
|
||||
use chrono::{DateTime,FixedOffset};
|
||||
use super::xml;
|
||||
use super::error;
|
||||
|
||||
/// Extension utilities
|
||||
pub struct Disabled(());
|
||||
/// It's how we implement a DAV extension
|
||||
/// (That's the dark magic part...)
|
||||
pub trait ExtensionItem<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
128
src/dav/xml.rs
Normal 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
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in a new issue