From be34cc309187bd5a59ef639473d851ec53b43eec Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Mon, 19 Jan 2026 16:22:21 +0100 Subject: [PATCH] xml: Implement namespace for Unparsed --- crates/dav/src/resource/methods/proppatch.rs | 9 ++++--- crates/store/src/error.rs | 1 - crates/xml/src/namespace.rs | 2 +- crates/xml/src/unparsed.rs | 26 +++++++++++++------- 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/crates/dav/src/resource/methods/proppatch.rs b/crates/dav/src/resource/methods/proppatch.rs index cbeb8b0..5628cfe 100644 --- a/crates/dav/src/resource/methods/proppatch.rs +++ b/crates/dav/src/resource/methods/proppatch.rs @@ -71,6 +71,7 @@ pub async fn axum_route_proppatch( route_proppatch(&path, uri.path(), &body, &principal, &resource_service).await } +#[allow(clippy::too_many_lines)] pub async fn route_proppatch( path_components: &R::PathComponents, path: &str, @@ -116,12 +117,14 @@ pub async fn route_proppatch( } } SetPropertyPropWrapper::Invalid(invalid) => { - let propname = invalid.tag_name(); + let Unparsed(propns, propname) = invalid; if let Some(full_propname) = ::list_props() .into_iter() .find_map(|(ns, tag)| { - if tag == propname.as_str() { + if (ns, tag) + == (propns.as_ref().map(NamespaceOwned::as_ref), &propname) + { Some((ns.map(NamespaceOwned::from), tag.to_owned())) } else { None @@ -133,7 +136,7 @@ pub async fn route_proppatch( // - internal properties props_conflict.push(full_propname); } else { - props_not_found.push((None, propname)); + props_not_found.push((propns, propname)); } } } diff --git a/crates/store/src/error.rs b/crates/store/src/error.rs index d20dc06..35960cf 100644 --- a/crates/store/src/error.rs +++ b/crates/store/src/error.rs @@ -36,7 +36,6 @@ impl Error { Self::NotFound => StatusCode::NOT_FOUND, Self::AlreadyExists => StatusCode::CONFLICT, Self::ReadOnly => StatusCode::FORBIDDEN, - // TODO: Can also be Bad Request, depending on when this is raised Self::IcalError(_err) => StatusCode::INTERNAL_SERVER_ERROR, Self::InvalidPrincipalType(_) => StatusCode::BAD_REQUEST, _ => StatusCode::INTERNAL_SERVER_ERROR, diff --git a/crates/xml/src/namespace.rs b/crates/xml/src/namespace.rs index 749827c..e0b4344 100644 --- a/crates/xml/src/namespace.rs +++ b/crates/xml/src/namespace.rs @@ -1,6 +1,6 @@ use quick_xml::name::Namespace; -#[derive(Debug, Clone, Default, PartialEq, Eq)] +#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)] pub struct NamespaceOwned(pub Vec); impl<'a> From> for NamespaceOwned { diff --git a/crates/xml/src/unparsed.rs b/crates/xml/src/unparsed.rs index f8873a1..568f81e 100644 --- a/crates/xml/src/unparsed.rs +++ b/crates/xml/src/unparsed.rs @@ -1,18 +1,21 @@ use std::io::BufRead; -use quick_xml::events::BytesStart; +use quick_xml::{events::BytesStart, name::ResolveResult}; -use crate::{XmlDeserialize, XmlError}; +use crate::{NamespaceOwned, XmlDeserialize, XmlError}; -// TODO: actually implement #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Unparsed(String); +pub struct Unparsed(pub Option, pub String); impl Unparsed { #[must_use] - pub fn tag_name(&self) -> String { - // TODO: respect namespace? - self.0.clone() + pub const fn ns(&self) -> Option<&NamespaceOwned> { + self.0.as_ref() + } + + #[must_use] + pub const fn tag_name(&self) -> &str { + self.1.as_str() } } @@ -27,7 +30,12 @@ impl XmlDeserialize for Unparsed { let mut buf = vec![]; reader.read_to_end_into(start.name(), &mut buf)?; } - let tag_name = String::from_utf8_lossy(start.local_name().as_ref()).to_string(); - Ok(Self(tag_name)) + let (ns, tag_name) = reader.resolver().resolve_element(start.name()); + let ns: Option = match ns { + ResolveResult::Bound(ns) => Some(ns.into()), + ResolveResult::Unbound | ResolveResult::Unknown(_) => None, + }; + let tag_name = String::from_utf8_lossy(tag_name.as_ref()).to_string(); + Ok(Self(ns, tag_name)) } }