WIP lock/propertyupdate implementation

This commit is contained in:
Quentin 2024-03-06 12:42:27 +01:00
parent ba32a0d4a6
commit 05c952f020
Signed by: quentin
GPG Key ID: E9602264D639FF68
4 changed files with 407 additions and 76 deletions

View File

@ -12,6 +12,8 @@ use super::error::ParsingError;
use super::xml::{QRead, Reader, IRead, DAV_URN, CAL_URN};
// ---- ROOT ----
/// Propfind request
impl<E: Extension> QRead<PropFind<E>> for PropFind<E> {
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> {
// Find propfind
@ -48,6 +50,37 @@ impl<E: Extension> QRead<PropFind<E>> for PropFind<E> {
}
}
/// PROPPATCH request
impl<E: Extension> QRead<PropertyUpdate<E>> for PropertyUpdate<E> {
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> {
xml.tag_start(DAV_URN, "propertyupdate").await?;
let mut collected_items = Vec::new();
loop {
// Try to collect a property item
if let Some(item) = PropertyUpdateItem::qread(xml).await? {
collected_items.push(item);
continue
}
// Skip or stop otherwise
match xml.peek() {
Event::End(_) => break,
_ => { xml.skip().await?; },
}
}
xml.tag_stop(DAV_URN, "propertyupdate").await?;
Ok(Some(PropertyUpdate(collected_items)))
}
}
//@TODO Multistatus
//@TODO LockInfo
//@TODO PropValue
/// Error response
impl<E: Extension> QRead<Error<E>> for Error<E> {
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> {
xml.tag_start(DAV_URN, "error").await?;
@ -66,7 +99,56 @@ impl<E: Extension> QRead<Error<E>> for Error<E> {
}
}
// ---- INNER XML
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? {
return Ok(Some(PropertyUpdateItem::Remove(rm)))
}
Ok(Set::qread(xml).await?.map(PropertyUpdateItem::Set))
}
}
impl<E: Extension> QRead<Remove<E>> for Remove<E> {
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> {
match xml.peek() {
Event::Start(b) if xml.is_tag(DAV_URN, "remove") => xml.next().await?,
_ => return Ok(None),
};
let propname = loop {
match xml.peek() {
Event::Start(b) | Event::Empty(b) if xml.is_tag(DAV_URN, "prop") => break PropName::qread(xml).await?,
_ => xml.skip().await?,
};
};
xml.tag_stop(DAV_URN, "remove").await?;
Ok(propname.map(Remove))
}
}
impl<E: Extension> QRead<Set<E>> for Set<E> {
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> {
match xml.peek() {
Event::Start(b) if xml.is_tag(DAV_URN, "set") => xml.next().await?,
_ => return Ok(None),
};
let propvalue = loop {
match xml.peek() {
Event::Start(b) | Event::Empty(b) if xml.is_tag(DAV_URN, "prop") => break PropValue::qread(xml).await?,
_ => xml.skip().await?,
};
};
xml.tag_stop(DAV_URN, "set").await?;
Ok(propvalue.map(Set))
}
}
impl<E: Extension> QRead<Violation<E>> for Violation<E> {
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> {
loop {
@ -163,13 +245,17 @@ impl<E: Extension> QRead<Violation<E>> for Violation<E> {
impl<E: Extension> QRead<Include<E>> for Include<E> {
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> {
xml.tag_start(DAV_URN, "include").await?;
let mut acc: Vec<PropertyRequest<E>> = Vec::new();
let mut acc = Vec::new();
loop {
// Found a property
if let Some(prop) = PropertyRequest::qread(xml).await? {
acc.push(prop);
continue;
}
// Otherwise skip or escape
match xml.peek() {
Event::Start(_) | Event::Empty(_) => {
PropertyRequest::qread(xml).await?.map(|v| acc.push(v));
},
Event::End(_) if xml.is_tag(DAV_URN, "include") => break,
Event::End(_) => break,
_ => { xml.skip().await?; },
}
}
@ -181,13 +267,17 @@ impl<E: Extension> QRead<Include<E>> for Include<E> {
impl<E: Extension> QRead<PropName<E>> for PropName<E> {
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> {
xml.tag_start(DAV_URN, "prop").await?;
let mut acc: Vec<PropertyRequest<E>> = Vec::new();
let mut acc = Vec::new();
loop {
// Found a property
if let Some(prop) = PropertyRequest::qread(xml).await? {
acc.push(prop);
continue;
}
// Otherwise skip or escape
match xml.peek() {
Event::Start(_) | Event::Empty(_) => {
PropertyRequest::qread(xml).await?.map(|v| acc.push(v));
},
Event::End(_) if xml.is_tag(DAV_URN, "prop") => break,
Event::End(_) => break,
_ => { xml.skip().await?; },
}
}
@ -198,46 +288,270 @@ impl<E: Extension> QRead<PropName<E>> for PropName<E> {
impl<E: Extension> QRead<PropertyRequest<E>> for PropertyRequest<E> {
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> {
loop {
let bs = match xml.peek() {
Event::Start(b) | Event::Empty(b) => b,
_ => {
xml.skip().await?;
continue
},
let bs = match xml.peek() {
Event::Start(b) | Event::Empty(b) => b,
_ => return Ok(None),
};
let mut maybe_res = None;
// Option 1: a pure core DAV property
let (ns, loc) = xml.rdr.resolve_element(bs.name());
if matches!(ns, Bound(Namespace(ns)) if ns == DAV_URN) {
maybe_res = match loc.into_inner() {
b"creationdate" => Some(PropertyRequest::CreationDate),
b"displayname" => Some(PropertyRequest::DisplayName),
b"getcontentlanguage" => Some(PropertyRequest::GetContentLanguage),
b"getcontentlength" => Some(PropertyRequest::GetContentLength),
b"getcontenttype" => Some(PropertyRequest::GetContentType),
b"getetag" => Some(PropertyRequest::GetEtag),
b"getlastmodified" => Some(PropertyRequest::GetLastModified),
b"lockdiscovery" => Some(PropertyRequest::LockDiscovery),
b"resourcetype" => Some(PropertyRequest::ResourceType),
b"supportedlock" => Some(PropertyRequest::SupportedLock),
_ => None,
};
let mut maybe_res = None;
// Option 1: a pure DAV property
let (ns, loc) = xml.rdr.resolve_element(bs.name());
if matches!(ns, Bound(Namespace(ns)) if ns == DAV_URN) {
maybe_res = match loc.into_inner() {
b"creationdate" => Some(PropertyRequest::CreationDate),
b"displayname" => Some(PropertyRequest::DisplayName),
b"getcontentlanguage" => Some(PropertyRequest::GetContentLanguage),
b"getcontentlength" => Some(PropertyRequest::GetContentLength),
b"getcontenttype" => Some(PropertyRequest::GetContentType),
b"getetag" => Some(PropertyRequest::GetEtag),
b"getlastmodified" => Some(PropertyRequest::GetLastModified),
b"lockdiscovery" => Some(PropertyRequest::LockDiscovery),
b"resourcetype" => Some(PropertyRequest::ResourceType),
b"supportedlock" => Some(PropertyRequest::SupportedLock),
_ => None,
};
// Close the current tag if we read something
if maybe_res.is_some() {
xml.skip().await?;
}
// Close the current tag if we read something
if maybe_res.is_some() {
xml.skip().await?;
}
// Option 2: an extension property, delegating
if maybe_res.is_none() {
maybe_res = E::PropertyRequest::qread(xml).await?.map(PropertyRequest::Extension);
}
return Ok(maybe_res)
}
// Option 2: an extension property, delegating
if maybe_res.is_none() {
maybe_res = E::PropertyRequest::qread(xml).await?.map(PropertyRequest::Extension);
}
Ok(maybe_res)
}
}
impl<E: Extension> QRead<PropValue<E>> for PropValue<E> {
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> {
xml.tag_start(DAV_URN, "prop").await?;
let mut acc = Vec::new();
loop {
// Found a property
if let Some(prop) = Property::qread(xml).await? {
acc.push(prop);
continue;
}
// Otherwise skip or escape
match xml.peek() {
Event::End(_) => break,
_ => { xml.skip().await?; },
}
}
xml.tag_stop(DAV_URN, "prop").await?;
Ok(Some(PropValue(acc)))
}
}
impl<E: Extension> QRead<Property<E>> for Property<E> {
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> {
use chrono::{DateTime, FixedOffset, TimeZone};
let bs = match xml.peek() {
Event::Start(b) | Event::Empty(b) => b,
_ => return Ok(None),
};
let mut maybe_res = None;
// Option 1: a pure core DAV property
let (ns, loc) = xml.rdr.resolve_element(bs.name());
if matches!(ns, Bound(Namespace(ns)) if ns == DAV_URN) {
maybe_res = match loc.into_inner() {
b"creationdate" => {
xml.next().await?;
let datestr = xml.tag_string().await?;
Some(Property::CreationDate(DateTime::parse_from_rfc3339(datestr.as_str())?))
},
b"displayname" => {
xml.next().await?;
Some(Property::DisplayName(xml.tag_string().await?))
},
b"getcontentlanguage" => {
xml.next().await?;
Some(Property::GetContentLanguage(xml.tag_string().await?))
},
b"getcontentlength" => {
xml.next().await?;
let cl = xml.tag_string().await?.parse::<u64>()?;
Some(Property::GetContentLength(cl))
},
b"getcontenttype" => {
xml.next().await?;
Some(Property::GetContentType(xml.tag_string().await?))
},
b"getetag" => {
xml.next().await?;
Some(Property::GetEtag(xml.tag_string().await?))
},
b"getlastmodified" => {
xml.next().await?;
xml.next().await?;
let datestr = xml.tag_string().await?;
Some(Property::CreationDate(DateTime::parse_from_rfc2822(datestr.as_str())?))
},
b"lockdiscovery" => {
// start tag
xml.next().await?;
let mut acc = Vec::new();
loop {
// If we find a lock
if let Some(lock) = ActiveLock::qread(xml).await? {
acc.push(lock);
continue
}
// Otherwise
match xml.peek() {
Event::End(_) => break,
_ => { xml.skip().await?; },
}
}
xml.tag_stop(DAV_URN, "lockdiscovery").await?;
Some(Property::LockDiscovery(acc))
},
b"resourcetype" => {
xml.next().await?;
let mut acc = Vec::new();
loop {
// If we find a resource type...
if let Some(restype) = ResourceType::qread(xml).await? {
acc.push(restype);
continue
}
// Otherwise
match xml.peek() {
Event::End(_) => break,
_ => { xml.skip().await?; },
}
}
xml.tag_stop(DAV_URN, "resourcetype").await?;
Some(Property::ResourceType(acc))
},
b"supportedlock" => {
xml.next().await?;
let mut acc = Vec::new();
loop {
// If we find a resource type...
if let Some(restype) = LockEntry::qread(xml).await? {
acc.push(restype);
continue
}
// Otherwise
match xml.peek() {
Event::End(_) => break,
_ => { xml.skip().await?; },
}
}
xml.tag_stop(DAV_URN, "supportedlock").await?;
Some(Property::SupportedLock(acc))
},
_ => None,
};
}
// Option 2: an extension property, delegating
if maybe_res.is_none() {
maybe_res = E::Property::qread(xml).await?.map(Property::Extension);
}
Ok(maybe_res)
}
}
impl QRead<ActiveLock> for ActiveLock {
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> {
unimplemented!();
}
}
impl<E: Extension> QRead<ResourceType<E>> for ResourceType<E> {
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> {
match xml.peek() {
Event::Empty(b) if xml.is_tag(DAV_URN, "collection") => {
xml.next().await?;
Ok(Some(ResourceType::Collection))
},
_ => Ok(E::ResourceType::qread(xml).await?.map(ResourceType::Extension)),
}
}
}
impl QRead<LockEntry> for LockEntry {
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> {
xml.tag_start(DAV_URN, "lockentry").await?;
let (mut maybe_scope, mut maybe_type) = (None, None);
loop {
match xml.peek() {
Event::Start(b) if xml.is_tag(DAV_URN, "lockscope") => {
maybe_scope = LockScope::qread(xml).await?;
},
Event::Start(b) if xml.is_tag(DAV_URN, "lockentry") => {
maybe_type = LockType::qread(xml).await?;
}
Event::End(_) => break,
_ => { xml.skip().await?; },
}
}
let lockentry = match (maybe_scope, maybe_type) {
(Some(lockscope), Some(locktype)) => LockEntry { lockscope, locktype },
_ => return Err(ParsingError::MissingChild),
};
xml.tag_stop(DAV_URN, "lockentry").await?;
Ok(Some(lockentry))
}
}
impl QRead<LockScope> for LockScope {
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> {
xml.tag_start(DAV_URN, "lockscope").await?;
let lockscope = loop {
match xml.peek() {
Event::Empty(b) if xml.is_tag(DAV_URN, "exclusive") => {
xml.next().await?;
break LockScope::Exclusive
},
Event::Empty(b) if xml.is_tag(DAV_URN, "shared") => {
xml.next().await?;
break LockScope::Shared
}
_ => xml.skip().await?,
};
};
xml.tag_stop(DAV_URN, "lockscope").await?;
Ok(Some(lockscope))
}
}
impl QRead<LockType> for LockType {
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Option<Self>, ParsingError> {
xml.tag_start(DAV_URN, "locktype").await?;
let locktype = loop {
match xml.peek() {
Event::Empty(b) if xml.is_tag(DAV_URN, "write") => {
xml.next().await?;
break LockType::Write
}
_ => xml.skip().await?,
};
};
xml.tag_stop(DAV_URN, "locktype").await?;
Ok(Some(locktype))
}
}
@ -248,22 +562,7 @@ impl QRead<Href> for Href {
_ => return Ok(None),
};
let mut url = String::new();
loop {
match xml.peek() {
Event::End(_) => break,
Event::Start(_) | Event::Empty(_) => return Err(ParsingError::WrongToken),
Event::CData(unescaped) => {
url.push_str(std::str::from_utf8(unescaped.as_ref())?);
xml.next().await?
},
Event::Text(escaped) => {
url.push_str(escaped.unescape()?.as_ref());
xml.next().await?
}
_ => xml.skip().await?,
};
}
let mut url = xml.tag_string().await?;
xml.tag_stop(DAV_URN, "href").await?;
Ok(Some(Href(url)))
}

View File

@ -101,6 +101,20 @@ impl<E: Extension> QWrite for PropValue<E> {
}
}
/// Error response
impl<E: Extension> QWrite for Error<E> {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = xml.create_dav_element("error");
let end = start.to_end();
xml.q.write_event_async(Event::Start(start.clone())).await?;
for violation in &self.0 {
violation.qwrite(xml).await?;
}
xml.q.write_event_async(Event::End(end)).await
}
}
// --- XML inner elements
impl<E: Extension> QWrite for PropertyUpdateItem<E> {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
@ -584,19 +598,6 @@ impl QWrite for LockEntry {
}
}
impl<E: Extension> QWrite for Error<E> {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let start = xml.create_dav_element("error");
let end = start.to_end();
xml.q.write_event_async(Event::Start(start.clone())).await?;
for violation in &self.0 {
violation.qwrite(xml).await?;
}
xml.q.write_event_async(Event::End(end)).await
}
}
impl<E: Extension> QWrite for Violation<E> {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let mut atom = async |c| {

View File

@ -8,6 +8,8 @@ pub enum ParsingError {
TagNotFound,
Utf8Error(std::str::Utf8Error),
QuickXml(quick_xml::Error),
Chrono(chrono::format::ParseError),
Int(std::num::ParseIntError),
Eof
}
impl From<AttrError> for ParsingError {
@ -25,3 +27,14 @@ impl From<std::str::Utf8Error> for ParsingError {
Self::Utf8Error(value)
}
}
impl From<chrono::format::ParseError> for ParsingError {
fn from(value: chrono::format::ParseError) -> Self {
Self::Chrono(value)
}
}
impl From<std::num::ParseIntError> for ParsingError {
fn from(value: std::num::ParseIntError) -> Self {
Self::Int(value)
}
}

View File

@ -129,5 +129,23 @@ impl<T: IRead> Reader<T> {
}
self.next().await
}
pub async fn tag_string(&mut self) -> Result<String, ParsingError> {
let mut acc = String::new();
loop {
match self.peek() {
Event::CData(unescaped) => {
acc.push_str(std::str::from_utf8(unescaped.as_ref())?);
self.next().await?
},
Event::Text(escaped) => {
acc.push_str(escaped.unescape()?.as_ref());
self.next().await?
}
Event::End(_) | Event::Start(_) | Event::Empty(_) => return Ok(acc),
_ => self.next().await?,
};
}
}
}