diff options
-rw-r--r-- | src/dav/calencoder.rs | 14 | ||||
-rw-r--r-- | src/dav/caltypes.rs | 2 | ||||
-rw-r--r-- | src/dav/decoder.rs | 82 | ||||
-rw-r--r-- | src/dav/encoder.rs | 41 | ||||
-rw-r--r-- | src/dav/types.rs | 32 |
5 files changed, 117 insertions, 54 deletions
diff --git a/src/dav/calencoder.rs b/src/dav/calencoder.rs index 114eee9..cadfc78 100644 --- a/src/dav/calencoder.rs +++ b/src/dav/calencoder.rs @@ -5,7 +5,7 @@ use tokio::io::AsyncWrite; use super::caltypes::*; use super::xml::{QWrite, IWrite, Writer}; -use super::types::Extension; +use super::types::{Extension, Node}; const ICAL_DATETIME_FMT: &str = "%Y%m%dT%H%M%SZ"; @@ -23,7 +23,7 @@ impl<E: Extension> QWrite for MkCalendar<E> { } } -impl<E: Extension> QWrite for MkCalendarResponse<E> { +impl<E: Extension, N: Node<N>> QWrite for MkCalendarResponse<E,N> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> { let start = xml.create_cal_element("mkcalendar-response"); let end = start.to_end(); @@ -810,19 +810,19 @@ mod tests { #[tokio::test] async fn rfc_calendar_query1_res() { let got = serialize( - &dav::Multistatus::<Calendar> { + &dav::Multistatus::<Calendar,dav::PropValue<Calendar>> { responses: vec![ dav::Response { status_or_propstat: dav::StatusOrPropstat::PropStat( dav::Href("http://cal.example.com/bernard/work/abcd2.ics".into()), vec![dav::PropStat { - prop: dav::AnyProp::Value(dav::PropValue(vec![ + prop: dav::PropValue(vec![ dav::Property::GetEtag("\"fffff-abcd2\"".into()), dav::Property::Extension(Property::CalendarData(CalendarDataPayload { mime: None, payload: "PLACEHOLDER".into() })), - ])), + ]), status: dav::Status(http::status::StatusCode::OK), error: None, responsedescription: None, @@ -836,13 +836,13 @@ mod tests { status_or_propstat: dav::StatusOrPropstat::PropStat( dav::Href("http://cal.example.com/bernard/work/abcd3.ics".into()), vec![dav::PropStat { - prop: dav::AnyProp::Value(dav::PropValue(vec![ + prop: dav::PropValue(vec![ dav::Property::GetEtag("\"fffff-abcd3\"".into()), dav::Property::Extension(Property::CalendarData(CalendarDataPayload{ mime: None, payload: "PLACEHOLDER".into(), })), - ])), + ]), status: dav::Status(http::status::StatusCode::OK), error: None, responsedescription: None, diff --git a/src/dav/caltypes.rs b/src/dav/caltypes.rs index 68e7baf..d9cbb12 100644 --- a/src/dav/caltypes.rs +++ b/src/dav/caltypes.rs @@ -44,7 +44,7 @@ pub struct MkCalendar<E: dav::Extension>(pub dav::Set<E>); /// /// <!ELEMENT mkcol-response (propstat+)> #[derive(Debug, PartialEq)] -pub struct MkCalendarResponse<E: dav::Extension>(pub Vec<dav::PropStat<E>>); +pub struct MkCalendarResponse<E: dav::Extension, N: dav::Node<N>>(pub Vec<dav::PropStat<E,N>>); // --- (REPORT PART) --- diff --git a/src/dav/decoder.rs b/src/dav/decoder.rs index 66c0839..41eca36 100644 --- a/src/dav/decoder.rs +++ b/src/dav/decoder.rs @@ -84,7 +84,7 @@ impl<E: Extension> QRead<PropertyUpdate<E>> for PropertyUpdate<E> { } /// Generic response -impl<E: Extension> QRead<Multistatus<E>> for Multistatus<E> { +impl<E: Extension, N: Node<N>> QRead<Multistatus<E,N>> for Multistatus<E,N> { async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> { xml.tag_start(DAV_URN, "multistatus").await?; let mut responses = Vec::new(); @@ -181,16 +181,74 @@ impl<E: Extension> QRead<Error<E>> for Error<E> { // ---- INNER XML -impl<E: Extension> QRead<Response<E>> for Response<E> { +impl<E: Extension, N: Node<N>> QRead<Response<E,N>> for Response<E,N> { async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> { if xml.maybe_tag_start(DAV_URN, "response").await?.is_none() { return Ok(None) } + let (mut status, mut error, mut responsedescription, mut location) = (None, None, None, None); + let mut href = Vec::new(); + let mut propstat = Vec::new(); + loop { + if let Some(v) = Status::qread(xml).await? { + status = Some(v); + } else if let Some(v) = Href::qread(xml).await? { + href.push(v); + } else if let Some(v) = PropStat::qread(xml).await? { + propstat.push(v); + } else if let Some(v) = Error::qread(xml).await? { + error = Some(v); + } else if let Some(v) = ResponseDescription::qread(xml).await? { + responsedescription = Some(v); + } else if let Some(v) = Location::qread(xml).await? { + location = Some(v); + } else { + match xml.peek() { + Event::End(_) => break, + _ => { xml.skip().await? }, + }; + } + } + + xml.tag_stop(DAV_URN, "response").await?; + match (status, &propstat[..], &href[..]) { + (Some(status), &[], &[_, ..]) => Ok(Some(Response { + status_or_propstat: StatusOrPropstat::Status(href, status), + error, responsedescription, location, + })), + (None, &[_, ..], &[_, ..]) => Ok(Some(Response { + status_or_propstat: StatusOrPropstat::PropStat(href.into_iter().next().unwrap(), propstat), + error, responsedescription, location, + })), + (Some(_), &[_, ..], _) => Err(ParsingError::InvalidValue), + _ => Err(ParsingError::MissingChild), + } + } +} + +impl<E: Extension, N: Node<N>> QRead<PropStat<E,N>> for PropStat<E,N> { + async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> { + if xml.maybe_tag_start(DAV_URN, "propstat").await?.is_none() { + return Ok(None) + } unimplemented!(); } } +impl QRead<Status> for Status { + async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> { + if xml.maybe_tag_start(DAV_URN, "status").await?.is_none() { + return Ok(None) + } + let fullcode = xml.tag_string().await?; + let txtcode = fullcode.splitn(3, ' ').nth(1).ok_or(ParsingError::InvalidValue)?; + let code = http::status::StatusCode::from_bytes(txtcode.as_bytes()).or(Err(ParsingError::InvalidValue))?; + xml.tag_stop(DAV_URN, "status").await?; + Ok(Some(Status(code))) + } +} + impl QRead<ResponseDescription> for ResponseDescription { async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> { if xml.maybe_tag_start(DAV_URN, "responsedescription").await?.is_none() { @@ -202,6 +260,26 @@ impl QRead<ResponseDescription> for ResponseDescription { } } +impl QRead<Location> for Location { + async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> { + if xml.maybe_tag_start(DAV_URN, "location").await?.is_none() { + return Ok(None) + } + let href = loop { + if let Some(v) = Href::qread(xml).await? { + break v + } + + match xml.peek() { + Event::End(_) => return Err(ParsingError::MissingChild), + _ => xml.skip().await?, + }; + }; + xml.tag_stop(DAV_URN, "location").await?; + Ok(Some(Location(href))) + } +} + impl<E: Extension> QRead<PropertyUpdateItem<E>> for PropertyUpdateItem<E> { async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> { if let Some(rm) = Remove::qread(xml).await? { diff --git a/src/dav/encoder.rs b/src/dav/encoder.rs index 5736217..9e60f29 100644 --- a/src/dav/encoder.rs +++ b/src/dav/encoder.rs @@ -53,7 +53,7 @@ impl<E: Extension> QWrite for PropertyUpdate<E> { /// PROPFIND RESPONSE, PROPPATCH RESPONSE, COPY RESPONSE, MOVE RESPONSE /// DELETE RESPONSE, -impl<E: Extension> QWrite for Multistatus<E> { +impl<E: Extension, N: Node<N>> QWrite for Multistatus<E,N> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> { let start = xml.create_dav_element("multistatus"); let end = start.to_end(); @@ -146,15 +146,6 @@ impl<E: Extension> QWrite for Remove<E> { } -impl<E: Extension> QWrite for AnyProp<E> { - async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> { - match self { - Self::Name(propname) => propname.qwrite(xml).await, - Self::Value(propval) => propval.qwrite(xml).await, - } - } -} - 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"); @@ -180,7 +171,7 @@ impl QWrite for Href { } } -impl<E: Extension> QWrite for Response<E> { +impl<E: Extension, N: Node<N>> QWrite for Response<E,N> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> { let start = xml.create_dav_element("response"); let end = start.to_end(); @@ -200,7 +191,7 @@ impl<E: Extension> QWrite for Response<E> { } } -impl<E: Extension> QWrite for StatusOrPropstat<E> { +impl<E: Extension, N: Node<N>> QWrite for StatusOrPropstat<E,N> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> { match self { Self::Status(many_href, status) => { @@ -258,7 +249,7 @@ impl QWrite for Location { } } -impl<E: Extension> QWrite for PropStat<E> { +impl<E: Extension, N: Node<N>> QWrite for PropStat<E,N> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> { let start = xml.create_dav_element("propstat"); let end = start.to_end(); @@ -681,7 +672,7 @@ mod tests { #[tokio::test] async fn basic_multistatus() { let got = serialize( - &Multistatus::<Core> { + &Multistatus::<Core, PropName<Core>> { responses: vec![], responsedescription: Some(ResponseDescription("Hello world".into())) }, @@ -730,18 +721,18 @@ mod tests { #[tokio::test] async fn rfc_propname_res() { let got = serialize( - &Multistatus::<Core> { + &Multistatus::<Core, PropName<Core>> { responses: vec![ Response { status_or_propstat: StatusOrPropstat::PropStat( Href("http://www.example.com/container/".into()), vec![PropStat { - prop: AnyProp::Name(PropName(vec![ + prop: PropName(vec![ PropertyRequest::CreationDate, PropertyRequest::DisplayName, PropertyRequest::ResourceType, PropertyRequest::SupportedLock, - ])), + ]), status: Status(http::status::StatusCode::OK), error: None, responsedescription: None, @@ -755,7 +746,7 @@ mod tests { status_or_propstat: StatusOrPropstat::PropStat( Href("http://www.example.com/container/front.html".into()), vec![PropStat { - prop: AnyProp::Name(PropName(vec![ + prop: PropName(vec![ PropertyRequest::CreationDate, PropertyRequest::DisplayName, PropertyRequest::GetContentLength, @@ -764,7 +755,7 @@ mod tests { PropertyRequest::GetLastModified, PropertyRequest::ResourceType, PropertyRequest::SupportedLock, - ])), + ]), status: Status(http::status::StatusCode::OK), error: None, responsedescription: None, @@ -831,13 +822,13 @@ mod tests { async fn rfc_allprop_res() { use chrono::{DateTime,FixedOffset,TimeZone}; let got = serialize( - &Multistatus::<Core> { + &Multistatus::<Core, PropValue<Core>> { responses: vec![ Response { status_or_propstat: StatusOrPropstat::PropStat( Href("/container/".into()), vec![PropStat { - prop: AnyProp::Value(PropValue(vec![ + prop: PropValue(vec![ Property::CreationDate(FixedOffset::west_opt(8 * 3600) .unwrap() .with_ymd_and_hms(1997, 12, 1, 17, 42, 21) @@ -854,7 +845,7 @@ mod tests { locktype: LockType::Write, }, ]), - ])), + ]), status: Status(http::status::StatusCode::OK), error: None, responsedescription: None, @@ -868,7 +859,7 @@ mod tests { status_or_propstat: StatusOrPropstat::PropStat( Href("/container/front.html".into()), vec![PropStat { - prop: AnyProp::Value(PropValue(vec![ + prop: PropValue(vec![ Property::CreationDate(FixedOffset::west_opt(8 * 3600) .unwrap() .with_ymd_and_hms(1997, 12, 1, 18, 27, 21) @@ -892,7 +883,7 @@ mod tests { locktype: LockType::Write, }, ]), - ])), + ]), status: Status(http::status::StatusCode::OK), error: None, responsedescription: None, @@ -1029,7 +1020,7 @@ mod tests { #[tokio::test] async fn rfc_delete_locked2() { let got = serialize( - &Multistatus::<Core> { + &Multistatus::<Core, PropValue<Core>> { responses: vec![Response { status_or_propstat: StatusOrPropstat::Status( vec![Href("http://www.example.com/container/resource3".into())], diff --git a/src/dav/types.rs b/src/dav/types.rs index b3842de..246a4bd 100644 --- a/src/dav/types.rs +++ b/src/dav/types.rs @@ -7,12 +7,12 @@ use super::error; /// 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 Node<T> = xml::QRead<T> + xml::QWrite + Debug + PartialEq; pub trait Extension { - type Error: ExtensionItem<Self::Error>; - type Property: ExtensionItem<Self::Property>; - type PropertyRequest: ExtensionItem<Self::PropertyRequest>; - type ResourceType: ExtensionItem<Self::ResourceType>; + type Error: Node<Self::Error>; + type Property: Node<Self::Property>; + type PropertyRequest: Node<Self::PropertyRequest>; + type ResourceType: Node<Self::ResourceType>; } /// 14.1. activelock XML Element @@ -333,8 +333,8 @@ pub enum LockType { /// /// <!ELEMENT multistatus (response*, responsedescription?) > #[derive(Debug, PartialEq)] -pub struct Multistatus<E: Extension> { - pub responses: Vec<Response<E>>, +pub struct Multistatus<E: Extension, N: Node<N>> { + pub responses: Vec<Response<E, N>>, pub responsedescription: Option<ResponseDescription>, } @@ -384,12 +384,6 @@ pub enum Owner { /// /// <!ELEMENT prop ANY > #[derive(Debug, PartialEq)] -pub enum AnyProp<E: Extension> { - Name(PropName<E>), - Value(PropValue<E>), -} - -#[derive(Debug, PartialEq)] pub struct PropName<E: Extension>(pub Vec<PropertyRequest<E>>); #[derive(Debug, PartialEq)] @@ -471,8 +465,8 @@ pub enum PropFind<E: Extension> { /// /// <!ELEMENT propstat (prop, status, error?, responsedescription?) > #[derive(Debug, PartialEq)] -pub struct PropStat<E: Extension> { - pub prop: AnyProp<E>, +pub struct PropStat<E: Extension, N: Node<N>> { + pub prop: N, pub status: Status, pub error: Option<Error<E>>, pub responsedescription: Option<ResponseDescription>, @@ -520,16 +514,16 @@ pub struct Remove<E: Extension>(pub PropName<E>); /// --- rewritten as --- /// <!ELEMENT response ((href+, status)|(href, propstat+), error?, responsedescription?, location?> #[derive(Debug, PartialEq)] -pub enum StatusOrPropstat<E: Extension> { +pub enum StatusOrPropstat<E: Extension, N: Node<N>> { // One status, multiple hrefs... Status(Vec<Href>, Status), // A single href, multiple properties... - PropStat(Href, Vec<PropStat<E>>), + PropStat(Href, Vec<PropStat<E, N>>), } #[derive(Debug, PartialEq)] -pub struct Response<E: Extension> { - pub status_or_propstat: StatusOrPropstat<E>, +pub struct Response<E: Extension, N: Node<N>> { + pub status_or_propstat: StatusOrPropstat<E, N>, pub error: Option<Error<E>>, pub responsedescription: Option<ResponseDescription>, pub location: Option<Location>, |