drop anyprop as it can't be decoded

This commit is contained in:
Quentin 2024-03-06 20:58:41 +01:00
parent ce2fa5c3bc
commit 67e5953c24
Signed by: quentin
GPG key ID: E9602264D639FF68
5 changed files with 117 additions and 54 deletions

View file

@ -5,7 +5,7 @@ use tokio::io::AsyncWrite;
use super::caltypes::*; use super::caltypes::*;
use super::xml::{QWrite, IWrite, Writer}; 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"; 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> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = xml.create_cal_element("mkcalendar-response"); let start = xml.create_cal_element("mkcalendar-response");
let end = start.to_end(); let end = start.to_end();
@ -810,19 +810,19 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn rfc_calendar_query1_res() { async fn rfc_calendar_query1_res() {
let got = serialize( let got = serialize(
&dav::Multistatus::<Calendar> { &dav::Multistatus::<Calendar,dav::PropValue<Calendar>> {
responses: vec![ responses: vec![
dav::Response { dav::Response {
status_or_propstat: dav::StatusOrPropstat::PropStat( status_or_propstat: dav::StatusOrPropstat::PropStat(
dav::Href("http://cal.example.com/bernard/work/abcd2.ics".into()), dav::Href("http://cal.example.com/bernard/work/abcd2.ics".into()),
vec![dav::PropStat { vec![dav::PropStat {
prop: dav::AnyProp::Value(dav::PropValue(vec![ prop: dav::PropValue(vec![
dav::Property::GetEtag("\"fffff-abcd2\"".into()), dav::Property::GetEtag("\"fffff-abcd2\"".into()),
dav::Property::Extension(Property::CalendarData(CalendarDataPayload { dav::Property::Extension(Property::CalendarData(CalendarDataPayload {
mime: None, mime: None,
payload: "PLACEHOLDER".into() payload: "PLACEHOLDER".into()
})), })),
])), ]),
status: dav::Status(http::status::StatusCode::OK), status: dav::Status(http::status::StatusCode::OK),
error: None, error: None,
responsedescription: None, responsedescription: None,
@ -836,13 +836,13 @@ mod tests {
status_or_propstat: dav::StatusOrPropstat::PropStat( status_or_propstat: dav::StatusOrPropstat::PropStat(
dav::Href("http://cal.example.com/bernard/work/abcd3.ics".into()), dav::Href("http://cal.example.com/bernard/work/abcd3.ics".into()),
vec![dav::PropStat { vec![dav::PropStat {
prop: dav::AnyProp::Value(dav::PropValue(vec![ prop: dav::PropValue(vec![
dav::Property::GetEtag("\"fffff-abcd3\"".into()), dav::Property::GetEtag("\"fffff-abcd3\"".into()),
dav::Property::Extension(Property::CalendarData(CalendarDataPayload{ dav::Property::Extension(Property::CalendarData(CalendarDataPayload{
mime: None, mime: None,
payload: "PLACEHOLDER".into(), payload: "PLACEHOLDER".into(),
})), })),
])), ]),
status: dav::Status(http::status::StatusCode::OK), status: dav::Status(http::status::StatusCode::OK),
error: None, error: None,
responsedescription: None, responsedescription: None,

View file

@ -44,7 +44,7 @@ pub struct MkCalendar<E: dav::Extension>(pub dav::Set<E>);
/// ///
/// <!ELEMENT mkcol-response (propstat+)> /// <!ELEMENT mkcol-response (propstat+)>
#[derive(Debug, PartialEq)] #[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) --- // --- (REPORT PART) ---

View file

@ -84,7 +84,7 @@ impl<E: Extension> QRead<PropertyUpdate<E>> for PropertyUpdate<E> {
} }
/// Generic response /// 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> { async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> {
xml.tag_start(DAV_URN, "multistatus").await?; xml.tag_start(DAV_URN, "multistatus").await?;
let mut responses = Vec::new(); let mut responses = Vec::new();
@ -181,16 +181,74 @@ impl<E: Extension> QRead<Error<E>> for Error<E> {
// ---- INNER XML // ---- 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> { async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> {
if xml.maybe_tag_start(DAV_URN, "response").await?.is_none() { if xml.maybe_tag_start(DAV_URN, "response").await?.is_none() {
return Ok(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!(); 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 { impl QRead<ResponseDescription> for ResponseDescription {
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> { async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> {
if xml.maybe_tag_start(DAV_URN, "responsedescription").await?.is_none() { 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> { impl<E: Extension> QRead<PropertyUpdateItem<E>> for PropertyUpdateItem<E> {
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> { async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> {
if let Some(rm) = Remove::qread(xml).await? { if let Some(rm) = Remove::qread(xml).await? {

View file

@ -53,7 +53,7 @@ impl<E: Extension> QWrite for PropertyUpdate<E> {
/// PROPFIND RESPONSE, PROPPATCH RESPONSE, COPY RESPONSE, MOVE RESPONSE /// PROPFIND RESPONSE, PROPPATCH RESPONSE, COPY RESPONSE, MOVE RESPONSE
/// DELETE 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> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = xml.create_dav_element("multistatus"); let start = xml.create_dav_element("multistatus");
let end = start.to_end(); 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> { impl<E: Extension> QWrite for PropName<E> {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = xml.create_dav_element("prop"); 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> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = xml.create_dav_element("response"); let start = xml.create_dav_element("response");
let end = start.to_end(); 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> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
match self { match self {
Self::Status(many_href, status) => { 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> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = xml.create_dav_element("propstat"); let start = xml.create_dav_element("propstat");
let end = start.to_end(); let end = start.to_end();
@ -681,7 +672,7 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn basic_multistatus() { async fn basic_multistatus() {
let got = serialize( let got = serialize(
&Multistatus::<Core> { &Multistatus::<Core, PropName<Core>> {
responses: vec![], responses: vec![],
responsedescription: Some(ResponseDescription("Hello world".into())) responsedescription: Some(ResponseDescription("Hello world".into()))
}, },
@ -730,18 +721,18 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn rfc_propname_res() { async fn rfc_propname_res() {
let got = serialize( let got = serialize(
&Multistatus::<Core> { &Multistatus::<Core, PropName<Core>> {
responses: vec![ responses: vec![
Response { Response {
status_or_propstat: StatusOrPropstat::PropStat( status_or_propstat: StatusOrPropstat::PropStat(
Href("http://www.example.com/container/".into()), Href("http://www.example.com/container/".into()),
vec![PropStat { vec![PropStat {
prop: AnyProp::Name(PropName(vec![ prop: PropName(vec![
PropertyRequest::CreationDate, PropertyRequest::CreationDate,
PropertyRequest::DisplayName, PropertyRequest::DisplayName,
PropertyRequest::ResourceType, PropertyRequest::ResourceType,
PropertyRequest::SupportedLock, PropertyRequest::SupportedLock,
])), ]),
status: Status(http::status::StatusCode::OK), status: Status(http::status::StatusCode::OK),
error: None, error: None,
responsedescription: None, responsedescription: None,
@ -755,7 +746,7 @@ mod tests {
status_or_propstat: StatusOrPropstat::PropStat( status_or_propstat: StatusOrPropstat::PropStat(
Href("http://www.example.com/container/front.html".into()), Href("http://www.example.com/container/front.html".into()),
vec![PropStat { vec![PropStat {
prop: AnyProp::Name(PropName(vec![ prop: PropName(vec![
PropertyRequest::CreationDate, PropertyRequest::CreationDate,
PropertyRequest::DisplayName, PropertyRequest::DisplayName,
PropertyRequest::GetContentLength, PropertyRequest::GetContentLength,
@ -764,7 +755,7 @@ mod tests {
PropertyRequest::GetLastModified, PropertyRequest::GetLastModified,
PropertyRequest::ResourceType, PropertyRequest::ResourceType,
PropertyRequest::SupportedLock, PropertyRequest::SupportedLock,
])), ]),
status: Status(http::status::StatusCode::OK), status: Status(http::status::StatusCode::OK),
error: None, error: None,
responsedescription: None, responsedescription: None,
@ -831,13 +822,13 @@ mod tests {
async fn rfc_allprop_res() { async fn rfc_allprop_res() {
use chrono::{DateTime,FixedOffset,TimeZone}; use chrono::{DateTime,FixedOffset,TimeZone};
let got = serialize( let got = serialize(
&Multistatus::<Core> { &Multistatus::<Core, PropValue<Core>> {
responses: vec![ responses: vec![
Response { Response {
status_or_propstat: StatusOrPropstat::PropStat( status_or_propstat: StatusOrPropstat::PropStat(
Href("/container/".into()), Href("/container/".into()),
vec![PropStat { vec![PropStat {
prop: AnyProp::Value(PropValue(vec![ prop: PropValue(vec![
Property::CreationDate(FixedOffset::west_opt(8 * 3600) Property::CreationDate(FixedOffset::west_opt(8 * 3600)
.unwrap() .unwrap()
.with_ymd_and_hms(1997, 12, 1, 17, 42, 21) .with_ymd_and_hms(1997, 12, 1, 17, 42, 21)
@ -854,7 +845,7 @@ mod tests {
locktype: LockType::Write, locktype: LockType::Write,
}, },
]), ]),
])), ]),
status: Status(http::status::StatusCode::OK), status: Status(http::status::StatusCode::OK),
error: None, error: None,
responsedescription: None, responsedescription: None,
@ -868,7 +859,7 @@ mod tests {
status_or_propstat: StatusOrPropstat::PropStat( status_or_propstat: StatusOrPropstat::PropStat(
Href("/container/front.html".into()), Href("/container/front.html".into()),
vec![PropStat { vec![PropStat {
prop: AnyProp::Value(PropValue(vec![ prop: PropValue(vec![
Property::CreationDate(FixedOffset::west_opt(8 * 3600) Property::CreationDate(FixedOffset::west_opt(8 * 3600)
.unwrap() .unwrap()
.with_ymd_and_hms(1997, 12, 1, 18, 27, 21) .with_ymd_and_hms(1997, 12, 1, 18, 27, 21)
@ -892,7 +883,7 @@ mod tests {
locktype: LockType::Write, locktype: LockType::Write,
}, },
]), ]),
])), ]),
status: Status(http::status::StatusCode::OK), status: Status(http::status::StatusCode::OK),
error: None, error: None,
responsedescription: None, responsedescription: None,
@ -1029,7 +1020,7 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn rfc_delete_locked2() { async fn rfc_delete_locked2() {
let got = serialize( let got = serialize(
&Multistatus::<Core> { &Multistatus::<Core, PropValue<Core>> {
responses: vec![Response { responses: vec![Response {
status_or_propstat: StatusOrPropstat::Status( status_or_propstat: StatusOrPropstat::Status(
vec![Href("http://www.example.com/container/resource3".into())], vec![Href("http://www.example.com/container/resource3".into())],

View file

@ -7,12 +7,12 @@ use super::error;
/// It's how we implement a DAV extension /// It's how we implement a DAV extension
/// (That's the dark magic part...) /// (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 { pub trait Extension {
type Error: ExtensionItem<Self::Error>; type Error: Node<Self::Error>;
type Property: ExtensionItem<Self::Property>; type Property: Node<Self::Property>;
type PropertyRequest: ExtensionItem<Self::PropertyRequest>; type PropertyRequest: Node<Self::PropertyRequest>;
type ResourceType: ExtensionItem<Self::ResourceType>; type ResourceType: Node<Self::ResourceType>;
} }
/// 14.1. activelock XML Element /// 14.1. activelock XML Element
@ -333,8 +333,8 @@ pub enum LockType {
/// ///
/// <!ELEMENT multistatus (response*, responsedescription?) > /// <!ELEMENT multistatus (response*, responsedescription?) >
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct Multistatus<E: Extension> { pub struct Multistatus<E: Extension, N: Node<N>> {
pub responses: Vec<Response<E>>, pub responses: Vec<Response<E, N>>,
pub responsedescription: Option<ResponseDescription>, pub responsedescription: Option<ResponseDescription>,
} }
@ -383,12 +383,6 @@ pub enum Owner {
/// text or mixed content. /// text or mixed content.
/// ///
/// <!ELEMENT prop ANY > /// <!ELEMENT prop ANY >
#[derive(Debug, PartialEq)]
pub enum AnyProp<E: Extension> {
Name(PropName<E>),
Value(PropValue<E>),
}
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct PropName<E: Extension>(pub Vec<PropertyRequest<E>>); pub struct PropName<E: Extension>(pub Vec<PropertyRequest<E>>);
@ -471,8 +465,8 @@ pub enum PropFind<E: Extension> {
/// ///
/// <!ELEMENT propstat (prop, status, error?, responsedescription?) > /// <!ELEMENT propstat (prop, status, error?, responsedescription?) >
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct PropStat<E: Extension> { pub struct PropStat<E: Extension, N: Node<N>> {
pub prop: AnyProp<E>, pub prop: N,
pub status: Status, pub status: Status,
pub error: Option<Error<E>>, pub error: Option<Error<E>>,
pub responsedescription: Option<ResponseDescription>, pub responsedescription: Option<ResponseDescription>,
@ -520,16 +514,16 @@ pub struct Remove<E: Extension>(pub PropName<E>);
/// --- rewritten as --- /// --- rewritten as ---
/// <!ELEMENT response ((href+, status)|(href, propstat+), error?, responsedescription?, location?> /// <!ELEMENT response ((href+, status)|(href, propstat+), error?, responsedescription?, location?>
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum StatusOrPropstat<E: Extension> { pub enum StatusOrPropstat<E: Extension, N: Node<N>> {
// One status, multiple hrefs... // One status, multiple hrefs...
Status(Vec<Href>, Status), Status(Vec<Href>, Status),
// A single href, multiple properties... // A single href, multiple properties...
PropStat(Href, Vec<PropStat<E>>), PropStat(Href, Vec<PropStat<E, N>>),
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct Response<E: Extension> { pub struct Response<E: Extension, N: Node<N>> {
pub status_or_propstat: StatusOrPropstat<E>, pub status_or_propstat: StatusOrPropstat<E, N>,
pub error: Option<Error<E>>, pub error: Option<Error<E>>,
pub responsedescription: Option<ResponseDescription>, pub responsedescription: Option<ResponseDescription>,
pub location: Option<Location>, pub location: Option<Location>,