diff --git a/crates/dav-proto/src/responses/multistatus.rs b/crates/dav-proto/src/responses/multistatus.rs index d16ea953..ccb9efd4 100644 --- a/crates/dav-proto/src/responses/multistatus.rs +++ b/crates/dav-proto/src/responses/multistatus.rs @@ -80,6 +80,15 @@ impl MultiStatus { self } + pub fn not_found(href: impl Into) -> Self { + let mut response = Self::new(Vec::with_capacity(1)); + response.response.0.push( + Response::new_status([href], StatusCode::NOT_FOUND) + .with_response_description("No resources found"), + ); + response + } + pub fn add_response(&mut self, response: Response) { self.response.0.push(response); } diff --git a/crates/dav/src/calendar/query.rs b/crates/dav/src/calendar/query.rs index fa534822..384a3d2c 100644 --- a/crates/dav/src/calendar/query.rs +++ b/crates/dav/src/calendar/query.rs @@ -4,6 +4,7 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ +use super::freebusy::freebusy_in_range; use crate::{ DavError, common::{ @@ -27,6 +28,7 @@ use dav_proto::{ schema::{ property::{CalDavProperty, CalendarData, DavProperty, TimeRange}, request::{CalendarQuery, Filter, FilterOp, PropFind, Timezone}, + response::MultiStatus, }, }; use groupware::{cache::GroupwareCache, calendar::ArchivedCalendarEvent}; @@ -40,8 +42,6 @@ use store::{ }; use trc::AddContext; -use super::freebusy::freebusy_in_range; - pub(crate) trait CalendarQueryRequestHandler: Sync + Send { fn handle_calendar_query_request( &self, @@ -68,13 +68,14 @@ impl CalendarQueryRequestHandler for Server { .fetch_dav_resources(access_token, account_id, SyncCollection::Calendar) .await .caused_by(trc::location!())?; - let resource = resources - .by_path( - resource_ - .resource - .ok_or(DavError::Code(StatusCode::METHOD_NOT_ALLOWED))?, - ) - .ok_or(DavError::Code(StatusCode::NOT_FOUND))?; + let Some(resource) = resources.by_path( + resource_ + .resource + .ok_or(DavError::Code(StatusCode::METHOD_NOT_ALLOWED))?, + ) else { + return Ok(HttpResponse::new(StatusCode::MULTI_STATUS) + .with_xml_body(MultiStatus::not_found(headers.uri).to_string())); + }; if !resource.is_container() { return Err(DavError::Code(StatusCode::METHOD_NOT_ALLOWED)); } diff --git a/crates/dav/src/card/query.rs b/crates/dav/src/card/query.rs index 6df33f10..ced6a35c 100644 --- a/crates/dav/src/card/query.rs +++ b/crates/dav/src/card/query.rs @@ -22,6 +22,7 @@ use dav_proto::{ schema::{ property::CardDavPropertyName, request::{AddressbookQuery, Filter, FilterOp, VCardPropertyWithGroup}, + response::MultiStatus, }, }; use groupware::cache::GroupwareCache; @@ -57,13 +58,14 @@ impl CardQueryRequestHandler for Server { .fetch_dav_resources(access_token, account_id, SyncCollection::AddressBook) .await .caused_by(trc::location!())?; - let resource = resources - .by_path( - resource_ - .resource - .ok_or(DavError::Code(StatusCode::METHOD_NOT_ALLOWED))?, - ) - .ok_or(DavError::Code(StatusCode::NOT_FOUND))?; + let Some(resource) = resources.by_path( + resource_ + .resource + .ok_or(DavError::Code(StatusCode::METHOD_NOT_ALLOWED))?, + ) else { + return Ok(HttpResponse::new(StatusCode::MULTI_STATUS) + .with_xml_body(MultiStatus::not_found(headers.uri).to_string())); + }; if !resource.is_container() { return Err(DavError::Code(StatusCode::METHOD_NOT_ALLOWED)); } diff --git a/crates/dav/src/common/propfind.rs b/crates/dav/src/common/propfind.rs index f8f8a731..48cff6eb 100644 --- a/crates/dav/src/common/propfind.rs +++ b/crates/dav/src/common/propfind.rs @@ -1134,11 +1134,8 @@ impl PropFindRequestHandler for Server { if !response.response.0.is_empty() || !query.sync_type.is_none() { Ok(HttpResponse::new(StatusCode::MULTI_STATUS).with_xml_body(response.to_string())) } else if !is_propfind { - response.add_response( - Response::new_status([query.uri], StatusCode::NOT_FOUND) - .with_response_description("No resources found"), - ); - Ok(HttpResponse::new(StatusCode::MULTI_STATUS).with_xml_body(response.to_string())) + Ok(HttpResponse::new(StatusCode::MULTI_STATUS) + .with_xml_body(MultiStatus::not_found(query.uri).to_string())) } else { Ok(HttpResponse::new(StatusCode::NOT_FOUND)) } diff --git a/tests/src/webdav/basic.rs b/tests/src/webdav/basic.rs index 3f529e4a..bec2f342 100644 --- a/tests/src/webdav/basic.rs +++ b/tests/src/webdav/basic.rs @@ -66,6 +66,32 @@ pub async fn test(test: &WebDavTest) { jane.request("PROPFIND", "/dav/cal/jane/default/", "") .await .with_status(StatusCode::MULTI_STATUS); + jane.request( + "REPORT", + "/dav/cal/jane/default/", + concat!( + r#""#, + r#""#, + r#""#, + r#""# + ), + ) + .await + .with_status(StatusCode::MULTI_STATUS); + jane.request( + "REPORT", + "/dav/cal/jane/test-404/", + concat!( + r#""#, + r#""#, + r#""#, + r#""# + ), + ) + .await + .with_status(StatusCode::MULTI_STATUS); jane.request("PROPFIND", "/dav/cal/jane/test-404/", "") .await .with_status(StatusCode::NOT_FOUND); diff --git a/tests/src/webdav/mod.rs b/tests/src/webdav/mod.rs index 6db65ab5..67c80be5 100644 --- a/tests/src/webdav/mod.rs +++ b/tests/src/webdav/mod.rs @@ -1036,6 +1036,9 @@ const SERVER: &str = r#" [server] hostname = "webdav.example.org" +[spam-filter] +enable = false + [http] url = "'https://127.0.0.1:8899'"