Fix typing of Response

This commit is contained in:
Quentin 2024-03-06 18:35:54 +01:00
parent 96a27d7b22
commit ce2fa5c3bc
Signed by: quentin
GPG key ID: E9602264D639FF68
4 changed files with 115 additions and 49 deletions

View file

@ -813,8 +813,9 @@ mod tests {
&dav::Multistatus::<Calendar> { &dav::Multistatus::<Calendar> {
responses: vec![ responses: vec![
dav::Response { dav::Response {
href: dav::Href("http://cal.example.com/bernard/work/abcd2.ics".into()), status_or_propstat: dav::StatusOrPropstat::PropStat(
status_or_propstat: dav::StatusOrPropstat::PropStat(vec![dav::PropStat { dav::Href("http://cal.example.com/bernard/work/abcd2.ics".into()),
vec![dav::PropStat {
prop: dav::AnyProp::Value(dav::PropValue(vec![ prop: dav::AnyProp::Value(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 {
@ -825,14 +826,16 @@ mod tests {
status: dav::Status(http::status::StatusCode::OK), status: dav::Status(http::status::StatusCode::OK),
error: None, error: None,
responsedescription: None, responsedescription: None,
}]), }]
),
location: None, location: None,
error: None, error: None,
responsedescription: None, responsedescription: None,
}, },
dav::Response { dav::Response {
href: dav::Href("http://cal.example.com/bernard/work/abcd3.ics".into()), status_or_propstat: dav::StatusOrPropstat::PropStat(
status_or_propstat: dav::StatusOrPropstat::PropStat(vec![dav::PropStat { dav::Href("http://cal.example.com/bernard/work/abcd3.ics".into()),
vec![dav::PropStat {
prop: dav::AnyProp::Value(dav::PropValue(vec![ prop: dav::AnyProp::Value(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{
@ -843,7 +846,8 @@ mod tests {
status: dav::Status(http::status::StatusCode::OK), status: dav::Status(http::status::StatusCode::OK),
error: None, error: None,
responsedescription: None, responsedescription: None,
}]), }]
),
location: None, location: None,
error: None, error: None,
responsedescription: None, responsedescription: None,

View file

@ -84,7 +84,29 @@ impl<E: Extension> QRead<PropertyUpdate<E>> for PropertyUpdate<E> {
} }
/// Generic response /// 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 // LOCK REQUEST
impl QRead<LockInfo> for LockInfo { impl QRead<LockInfo> for LockInfo {
@ -159,6 +181,27 @@ impl<E: Extension> QRead<Error<E>> for Error<E> {
// ---- INNER XML // ---- 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> { 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

@ -186,7 +186,6 @@ impl<E: Extension> QWrite for Response<E> {
let end = start.to_end(); let end = start.to_end();
xml.q.write_event_async(Event::Start(start.clone())).await?; xml.q.write_event_async(Event::Start(start.clone())).await?;
self.href.qwrite(xml).await?;
self.status_or_propstat.qwrite(xml).await?; self.status_or_propstat.qwrite(xml).await?;
if let Some(error) = &self.error { if let Some(error) = &self.error {
error.qwrite(xml).await?; error.qwrite(xml).await?;
@ -204,8 +203,14 @@ impl<E: Extension> QWrite for Response<E> {
impl<E: Extension> QWrite for StatusOrPropstat<E> { impl<E: Extension> QWrite for StatusOrPropstat<E> {
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(status) => status.qwrite(xml).await, Self::Status(many_href, status) => {
Self::PropStat(propstat_list) => { 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() { for propstat in propstat_list.iter() {
propstat.qwrite(xml).await?; propstat.qwrite(xml).await?;
} }
@ -728,39 +733,43 @@ mod tests {
&Multistatus::<Core> { &Multistatus::<Core> {
responses: vec![ responses: vec![
Response { Response {
href: Href("http://www.example.com/container/".into()), status_or_propstat: StatusOrPropstat::PropStat(
status_or_propstat: StatusOrPropstat::PropStat(vec![PropStat { Href("http://www.example.com/container/".into()),
prop: AnyProp::Name(PropName(vec![ vec![PropStat {
PropertyRequest::CreationDate, prop: AnyProp::Name(PropName(vec![
PropertyRequest::DisplayName, PropertyRequest::CreationDate,
PropertyRequest::ResourceType, PropertyRequest::DisplayName,
PropertyRequest::SupportedLock, PropertyRequest::ResourceType,
])), PropertyRequest::SupportedLock,
status: Status(http::status::StatusCode::OK), ])),
error: None, status: Status(http::status::StatusCode::OK),
responsedescription: None, error: None,
}]), responsedescription: None,
}]
),
error: None, error: None,
responsedescription: None, responsedescription: None,
location: None, location: None,
}, },
Response { Response {
href: Href("http://www.example.com/container/front.html".into()), status_or_propstat: StatusOrPropstat::PropStat(
status_or_propstat: StatusOrPropstat::PropStat(vec![PropStat { Href("http://www.example.com/container/front.html".into()),
prop: AnyProp::Name(PropName(vec![ vec![PropStat {
PropertyRequest::CreationDate, prop: AnyProp::Name(PropName(vec![
PropertyRequest::DisplayName, PropertyRequest::CreationDate,
PropertyRequest::GetContentLength, PropertyRequest::DisplayName,
PropertyRequest::GetContentType, PropertyRequest::GetContentLength,
PropertyRequest::GetEtag, PropertyRequest::GetContentType,
PropertyRequest::GetLastModified, PropertyRequest::GetEtag,
PropertyRequest::ResourceType, PropertyRequest::GetLastModified,
PropertyRequest::SupportedLock, PropertyRequest::ResourceType,
])), PropertyRequest::SupportedLock,
status: Status(http::status::StatusCode::OK), ])),
error: None, status: Status(http::status::StatusCode::OK),
responsedescription: None, error: None,
}]), responsedescription: None,
}
]),
error: None, error: None,
responsedescription: None, responsedescription: None,
location: None, location: None,
@ -825,8 +834,9 @@ mod tests {
&Multistatus::<Core> { &Multistatus::<Core> {
responses: vec![ responses: vec![
Response { Response {
href: Href("/container/".into()), status_or_propstat: StatusOrPropstat::PropStat(
status_or_propstat: StatusOrPropstat::PropStat(vec![PropStat { Href("/container/".into()),
vec![PropStat {
prop: AnyProp::Value(PropValue(vec![ prop: AnyProp::Value(PropValue(vec![
Property::CreationDate(FixedOffset::west_opt(8 * 3600) Property::CreationDate(FixedOffset::west_opt(8 * 3600)
.unwrap() .unwrap()
@ -848,14 +858,16 @@ mod tests {
status: Status(http::status::StatusCode::OK), status: Status(http::status::StatusCode::OK),
error: None, error: None,
responsedescription: None, responsedescription: None,
}]), }]
),
error: None, error: None,
responsedescription: None, responsedescription: None,
location: None, location: None,
}, },
Response { Response {
href: Href("/container/front.html".into()), status_or_propstat: StatusOrPropstat::PropStat(
status_or_propstat: StatusOrPropstat::PropStat(vec![PropStat { Href("/container/front.html".into()),
vec![PropStat {
prop: AnyProp::Value(PropValue(vec![ prop: AnyProp::Value(PropValue(vec![
Property::CreationDate(FixedOffset::west_opt(8 * 3600) Property::CreationDate(FixedOffset::west_opt(8 * 3600)
.unwrap() .unwrap()
@ -884,7 +896,8 @@ mod tests {
status: Status(http::status::StatusCode::OK), status: Status(http::status::StatusCode::OK),
error: None, error: None,
responsedescription: None, responsedescription: None,
}]), }]
),
error: None, error: None,
responsedescription: None, responsedescription: None,
location: None, location: None,
@ -1018,8 +1031,10 @@ mod tests {
let got = serialize( let got = serialize(
&Multistatus::<Core> { &Multistatus::<Core> {
responses: vec![Response { responses: vec![Response {
href: Href("http://www.example.com/container/resource3".into()), status_or_propstat: StatusOrPropstat::Status(
status_or_propstat: StatusOrPropstat::Status(Status(http::status::StatusCode::from_u16(423).unwrap())), vec![Href("http://www.example.com/container/resource3".into())],
Status(http::status::StatusCode::from_u16(423).unwrap())
),
error: Some(Error(vec![Violation::LockTokenSubmitted(vec![])])), error: Some(Error(vec![Violation::LockTokenSubmitted(vec![])])),
responsedescription: None, responsedescription: None,
location: None, location: None,

View file

@ -516,15 +516,19 @@ pub struct Remove<E: Extension>(pub PropName<E>);
/// ///
/// <!ELEMENT response (href, ((href*, status)|(propstat+)), /// <!ELEMENT response (href, ((href*, status)|(propstat+)),
/// error?, responsedescription? , location?) > /// error?, responsedescription? , location?) >
///
/// --- rewritten as ---
/// <!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> {
Status(Status), // One status, multiple hrefs...
PropStat(Vec<PropStat<E>>), Status(Vec<Href>, Status),
// A single href, multiple properties...
PropStat(Href, Vec<PropStat<E>>),
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct Response<E: Extension> { 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 status_or_propstat: StatusOrPropstat<E>,
pub error: Option<Error<E>>, pub error: Option<Error<E>>,
pub responsedescription: Option<ResponseDescription>, pub responsedescription: Option<ResponseDescription>,