From 4a5ae87059c41ea3e264a0ffef0d9ff4c55b8b83 Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Mon, 18 Mar 2024 15:04:46 +0100 Subject: [PATCH] WIP DAV hierarchy --- aero-dav/src/calencoder.rs | 2 +- aero-dav/src/realization.rs | 2 +- aero-proto/src/dav.rs | 149 +++++++++++++++++++++++++----------- 3 files changed, 106 insertions(+), 47 deletions(-) diff --git a/aero-dav/src/calencoder.rs b/aero-dav/src/calencoder.rs index e00876d..54a35a2 100644 --- a/aero-dav/src/calencoder.rs +++ b/aero-dav/src/calencoder.rs @@ -206,7 +206,7 @@ impl QWrite for ResourceType { async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { match self { Self::Calendar => { - let empty_tag = xml.create_dav_element("calendar"); + let empty_tag = xml.create_cal_element("calendar"); xml.q.write_event_async(Event::Empty(empty_tag)).await }, } diff --git a/aero-dav/src/realization.rs b/aero-dav/src/realization.rs index 8c47fad..7bec729 100644 --- a/aero-dav/src/realization.rs +++ b/aero-dav/src/realization.rs @@ -18,7 +18,7 @@ impl xml::QWrite for Disabled { /// The base WebDAV /// -/// Any extension is kooh is disabled through an object we can't build +/// Any extension is disabled through an object we can't build /// due to a private inner element. #[derive(Debug, PartialEq, Clone)] pub struct Core {} diff --git a/aero-proto/src/dav.rs b/aero-proto/src/dav.rs index 2bc1247..7f0f28d 100644 --- a/aero-proto/src/dav.rs +++ b/aero-proto/src/dav.rs @@ -196,20 +196,22 @@ async fn router(user: std::sync::Arc, req: Request) -> Result = path.split("/").filter(|s| *s != "").collect(); let method = req.method().as_str().to_uppercase(); + let node = match Box::new(RootNode {}).fetch(&user, &path_segments) { + Ok(v) => v, + Err(e) => { + tracing::warn!(err=?e, "dav node fetch failed"); + return Ok(Response::builder() + .status(404) + .body(text_body("Resource not found"))?) + } + }; - match (method.as_str(), path_segments.as_slice()) { - ("OPTIONS", _) => return Ok(Response::builder() + match method.as_str() { + "OPTIONS" => return Ok(Response::builder() .status(200) .header("DAV", "1") .body(text_body(""))?), - ("PROPFIND", []) => propfind_root(user, req).await, - (_, [ username, ..]) if *username != user.username => return Ok(Response::builder() - .status(403) - .body(text_body("Accessing other user ressources is not allowed"))?), - ("PROPFIND", [ _ ]) => propfind_home(user, &req).await, - ("PROPFIND", [ _, "calendar" ]) => propfind_all_calendars(user, &req).await, - ("PROPFIND", [ _, "calendar", colname ]) => propfind_this_calendar(user, &req, colname).await, - ("PROPFIND", [ _, "calendar", colname, event ]) => propfind_event(user, req, colname, event).await, + "PROPFIND" => propfind(user, req, node).await, _ => return Ok(Response::builder() .status(501) .body(text_body("Not implemented"))?), @@ -224,8 +226,7 @@ const SUPPORTED_PROPNAME: [dav::PropertyRequest; 2] = [ dav::PropertyRequest::ResourceType, ]; -async fn propfind_root(user: std::sync::Arc, req: Request) -> Result>> { - let node = RootNode {}; +async fn propfind(user: std::sync::Arc, req: Request, node: Box) -> Result>> { let depth = depth(&req); @@ -258,36 +259,6 @@ async fn propfind_root(user: std::sync::Arc, req: Request) -> Re serialize(node.multistatus_val(&user, &propname, depth)) } -async fn propfind_home(user: std::sync::Arc, req: &Request) -> Result>> { - tracing::info!("user home"); - Ok(Response::new(text_body("Hello World!"))) -} - -async fn propfind_all_calendars(user: std::sync::Arc, req: &Request) -> Result>> { - tracing::info!("calendar"); - Ok(Response::new(text_body("Hello World!"))) -} - -async fn propfind_this_calendar( - user: std::sync::Arc, - req: &Request, - colname: &str -) -> Result>> { - tracing::info!(name=colname, "selected calendar"); - Ok(Response::new(text_body("Hello World!"))) -} - -async fn propfind_event( - user: std::sync::Arc, - req: Request, - colname: &str, - event: &str, -) -> Result>> { - tracing::info!(name=colname, obj=event, "selected event"); - Ok(Response::new(text_body("Hello World!"))) -} - - #[allow(dead_code)] async fn collections(_user: std::sync::Arc, _req: Request) -> Result>> { unimplemented!(); @@ -326,7 +297,7 @@ fn serialize(elem: T) -> Result>(req: Request) -> Result { //--- type ArcUser = std::sync::Arc; -trait DavNode { +trait DavNode: Send { + // ------- specialized logic + // recurence fn children(&self, user: &ArcUser) -> Vec>; + fn fetch(self: Box, user: &ArcUser, path: &[&str]) -> Result>; // node properties + fn path(&self, user: &ArcUser) -> String; fn name(&self, user: &ArcUser) -> String; fn supported_properties(&self, user: &ArcUser) -> dav::PropName; fn properties(&self, user: &ArcUser, props: &dav::PropName) -> dav::PropValue; - // building DAV responses + // ----- common + + /// building DAV responses fn multistatus_name(&self, user: &ArcUser, depth: dav::Depth) -> dav::Multistatus> { let mut names = vec![(".".into(), self.supported_properties(user))]; if matches!(depth, dav::Depth::One | dav::Depth::Infinity) { @@ -436,6 +413,23 @@ trait DavNode { struct RootNode {} impl DavNode for RootNode { + fn fetch(self: Box, user: &ArcUser, path: &[&str]) -> Result> { + if path.len() == 0 { + return Ok(self) + } + + if path[0] == user.username { + let child = Box::new(HomeNode {}); + return child.fetch(user, &path[1..]) + } + + Err(anyhow!("Not found")) + } + + fn path(&self, user: &ArcUser) -> String { + todo!(); + } + fn name(&self, _user: &ArcUser) -> String { "/".into() } @@ -459,6 +453,23 @@ impl DavNode for RootNode { struct HomeNode {} impl DavNode for HomeNode { + fn fetch(self: Box, user: &ArcUser, path: &[&str]) -> Result> { + if path.len() == 0 { + return Ok(self) + } + + if path[0] == "calendar" { + let child = Box::new(CalendarListNode {}); + return child.fetch(user, &path[1..]) + } + + Err(anyhow!("Not found")) + } + + fn path(&self, user: &ArcUser) -> String { + todo!(); + } + fn name(&self, user: &ArcUser) -> String { format!("{}/", user.username) } @@ -482,6 +493,24 @@ impl DavNode for HomeNode { struct CalendarListNode {} impl DavNode for CalendarListNode { + fn fetch(self: Box, user: &ArcUser, path: &[&str]) -> Result> { + if path.len() == 0 { + return Ok(self) + } + + //@FIXME hardcoded logic + if path[0] == "personal" { + let child = Box::new(CalendarNode { name: "personal".to_string() }); + return child.fetch(user, &path[1..]) + } + + Err(anyhow!("Not found")) + } + + fn path(&self, user: &ArcUser) -> String { + todo!(); + } + fn name(&self, _user: &ArcUser) -> String { "calendar/".into() } @@ -507,6 +536,24 @@ struct CalendarNode { name: String, } impl DavNode for CalendarNode { + fn fetch(self: Box, user: &ArcUser, path: &[&str]) -> Result> { + if path.len() == 0 { + return Ok(self) + } + + //@FIXME hardcoded logic + if path[0] == "something.ics" { + let child = Box::new(EventNode { file: "something.ics".to_string() }); + return child.fetch(user, &path[1..]) + } + + Err(anyhow!("Not found")) + } + + fn path(&self, user: &ArcUser) -> String { + todo!(); + } + fn name(&self, _user: &ArcUser) -> String { format!("{}/", self.name) } @@ -535,6 +582,18 @@ struct EventNode { file: String, } impl DavNode for EventNode { + fn fetch(self: Box, user: &ArcUser, path: &[&str]) -> Result> { + if path.len() == 0 { + return Ok(self) + } + + Err(anyhow!("Not found")) + } + + fn path(&self, user: &ArcUser) -> String { + todo!(); + } + fn name(&self, _user: &ArcUser) -> String { self.file.to_string() }