diff options
-rw-r--r-- | src/dav/calencoder.rs | 16 | ||||
-rw-r--r-- | src/dav/decoder.rs | 45 | ||||
-rw-r--r-- | src/dav/encoder.rs | 93 | ||||
-rw-r--r-- | src/dav/types.rs | 10 |
4 files changed, 115 insertions, 49 deletions
diff --git a/src/dav/calencoder.rs b/src/dav/calencoder.rs index d030aa1..114eee9 100644 --- a/src/dav/calencoder.rs +++ b/src/dav/calencoder.rs @@ -813,8 +813,9 @@ mod tests { &dav::Multistatus::<Calendar> { responses: vec![ dav::Response { - href: dav::Href("http://cal.example.com/bernard/work/abcd2.ics".into()), - status_or_propstat: dav::StatusOrPropstat::PropStat(vec![dav::PropStat { + 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![ dav::Property::GetEtag("\"fffff-abcd2\"".into()), dav::Property::Extension(Property::CalendarData(CalendarDataPayload { @@ -825,14 +826,16 @@ mod tests { status: dav::Status(http::status::StatusCode::OK), error: None, responsedescription: None, - }]), + }] + ), location: None, error: None, responsedescription: None, }, dav::Response { - href: dav::Href("http://cal.example.com/bernard/work/abcd3.ics".into()), - status_or_propstat: dav::StatusOrPropstat::PropStat(vec![dav::PropStat { + 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![ dav::Property::GetEtag("\"fffff-abcd3\"".into()), dav::Property::Extension(Property::CalendarData(CalendarDataPayload{ @@ -843,7 +846,8 @@ mod tests { status: dav::Status(http::status::StatusCode::OK), error: None, responsedescription: None, - }]), + }] + ), location: None, error: None, responsedescription: None, diff --git a/src/dav/decoder.rs b/src/dav/decoder.rs index 042a608..66c0839 100644 --- a/src/dav/decoder.rs +++ b/src/dav/decoder.rs @@ -84,7 +84,29 @@ impl<E: Extension> QRead<PropertyUpdate<E>> for PropertyUpdate<E> { } /// Generic response -//@TODO Multistatus +impl<E: Extension> QRead<Multistatus<E>> for Multistatus<E> { + async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> { + xml.tag_start(DAV_URN, "multistatus").await?; + let mut responses = Vec::new(); + let mut responsedescription = None; + + loop { + if let Some(v) = Response::qread(xml).await? { + responses.push(v); + } else if let Some(v) = ResponseDescription::qread(xml).await? { + responsedescription = Some(v); + } else { + match xml.peek() { + Event::End(_) => break, + _ => xml.skip().await?, + }; + } + } + + xml.tag_stop(DAV_URN, "multistatus").await?; + Ok(Some(Multistatus { responses, responsedescription })) + } +} // LOCK REQUEST impl QRead<LockInfo> for LockInfo { @@ -159,6 +181,27 @@ impl<E: Extension> QRead<Error<E>> for Error<E> { // ---- INNER XML +impl<E: Extension> QRead<Response<E>> for Response<E> { + 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) + } + + unimplemented!(); + } +} + +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() { + return Ok(None) + } + let cnt = xml.tag_string().await?; + xml.tag_stop(DAV_URN, "responsedescription").await?; + Ok(Some(ResponseDescription(cnt))) + } +} + 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 ec937c6..5736217 100644 --- a/src/dav/encoder.rs +++ b/src/dav/encoder.rs @@ -186,7 +186,6 @@ impl<E: Extension> QWrite for Response<E> { let end = start.to_end(); 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.qwrite(xml).await?; @@ -204,8 +203,14 @@ impl<E: Extension> QWrite for Response<E> { impl<E: Extension> QWrite for StatusOrPropstat<E> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> { match self { - Self::Status(status) => status.qwrite(xml).await, - Self::PropStat(propstat_list) => { + Self::Status(many_href, status) => { + for href in many_href.iter() { + href.qwrite(xml).await?; + } + status.qwrite(xml).await + }, + Self::PropStat(href, propstat_list) => { + href.qwrite(xml).await?; for propstat in propstat_list.iter() { propstat.qwrite(xml).await?; } @@ -728,39 +733,43 @@ mod tests { &Multistatus::<Core> { responses: vec![ Response { - href: Href("http://www.example.com/container/".into()), - status_or_propstat: StatusOrPropstat::PropStat(vec![PropStat { - prop: AnyProp::Name(PropName(vec![ - PropertyRequest::CreationDate, - PropertyRequest::DisplayName, - PropertyRequest::ResourceType, - PropertyRequest::SupportedLock, - ])), - status: Status(http::status::StatusCode::OK), - error: None, - responsedescription: None, - }]), + status_or_propstat: StatusOrPropstat::PropStat( + Href("http://www.example.com/container/".into()), + vec![PropStat { + prop: AnyProp::Name(PropName(vec![ + PropertyRequest::CreationDate, + PropertyRequest::DisplayName, + PropertyRequest::ResourceType, + PropertyRequest::SupportedLock, + ])), + status: Status(http::status::StatusCode::OK), + error: None, + responsedescription: None, + }] + ), error: None, responsedescription: None, location: None, }, Response { - href: Href("http://www.example.com/container/front.html".into()), - status_or_propstat: StatusOrPropstat::PropStat(vec![PropStat { - prop: AnyProp::Name(PropName(vec![ - PropertyRequest::CreationDate, - PropertyRequest::DisplayName, - PropertyRequest::GetContentLength, - PropertyRequest::GetContentType, - PropertyRequest::GetEtag, - PropertyRequest::GetLastModified, - PropertyRequest::ResourceType, - PropertyRequest::SupportedLock, - ])), - status: Status(http::status::StatusCode::OK), - error: None, - responsedescription: None, - }]), + status_or_propstat: StatusOrPropstat::PropStat( + Href("http://www.example.com/container/front.html".into()), + vec![PropStat { + prop: AnyProp::Name(PropName(vec![ + PropertyRequest::CreationDate, + PropertyRequest::DisplayName, + PropertyRequest::GetContentLength, + PropertyRequest::GetContentType, + PropertyRequest::GetEtag, + PropertyRequest::GetLastModified, + PropertyRequest::ResourceType, + PropertyRequest::SupportedLock, + ])), + status: Status(http::status::StatusCode::OK), + error: None, + responsedescription: None, + } + ]), error: None, responsedescription: None, location: None, @@ -825,8 +834,9 @@ mod tests { &Multistatus::<Core> { responses: vec![ Response { - href: Href("/container/".into()), - status_or_propstat: StatusOrPropstat::PropStat(vec![PropStat { + status_or_propstat: StatusOrPropstat::PropStat( + Href("/container/".into()), + vec![PropStat { prop: AnyProp::Value(PropValue(vec![ Property::CreationDate(FixedOffset::west_opt(8 * 3600) .unwrap() @@ -848,14 +858,16 @@ mod tests { status: Status(http::status::StatusCode::OK), error: None, responsedescription: None, - }]), + }] + ), error: None, responsedescription: None, location: None, }, Response { - href: Href("/container/front.html".into()), - status_or_propstat: StatusOrPropstat::PropStat(vec![PropStat { + status_or_propstat: StatusOrPropstat::PropStat( + Href("/container/front.html".into()), + vec![PropStat { prop: AnyProp::Value(PropValue(vec![ Property::CreationDate(FixedOffset::west_opt(8 * 3600) .unwrap() @@ -884,7 +896,8 @@ mod tests { status: Status(http::status::StatusCode::OK), error: None, responsedescription: None, - }]), + }] + ), error: None, responsedescription: None, location: None, @@ -1018,8 +1031,10 @@ mod tests { let got = serialize( &Multistatus::<Core> { responses: vec![Response { - href: Href("http://www.example.com/container/resource3".into()), - status_or_propstat: StatusOrPropstat::Status(Status(http::status::StatusCode::from_u16(423).unwrap())), + status_or_propstat: StatusOrPropstat::Status( + vec![Href("http://www.example.com/container/resource3".into())], + Status(http::status::StatusCode::from_u16(423).unwrap()) + ), error: Some(Error(vec![Violation::LockTokenSubmitted(vec![])])), responsedescription: None, location: None, diff --git a/src/dav/types.rs b/src/dav/types.rs index 08c0bc6..b3842de 100644 --- a/src/dav/types.rs +++ b/src/dav/types.rs @@ -516,15 +516,19 @@ pub struct Remove<E: Extension>(pub PropName<E>); /// /// <!ELEMENT response (href, ((href*, status)|(propstat+)), /// error?, responsedescription? , location?) > +/// +/// --- rewritten as --- +/// <!ELEMENT response ((href+, status)|(href, propstat+), error?, responsedescription?, location?> #[derive(Debug, PartialEq)] pub enum StatusOrPropstat<E: Extension> { - Status(Status), - PropStat(Vec<PropStat<E>>), + // One status, multiple hrefs... + Status(Vec<Href>, Status), + // A single href, multiple properties... + PropStat(Href, Vec<PropStat<E>>), } #[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<E>, pub error: Option<Error<E>>, pub responsedescription: Option<ResponseDescription>, |