aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dav/calencoder.rs16
-rw-r--r--src/dav/decoder.rs45
-rw-r--r--src/dav/encoder.rs93
-rw-r--r--src/dav/types.rs10
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>,