aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dav/calencoder.rs14
-rw-r--r--src/dav/caltypes.rs2
-rw-r--r--src/dav/decoder.rs82
-rw-r--r--src/dav/encoder.rs41
-rw-r--r--src/dav/types.rs32
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>,