From 31321b114302f526f363942a3c92d9b9df4f6b16 Mon Sep 17 00:00:00 2001 From: imWildCat Date: Sun, 12 Feb 2023 08:42:25 -0800 Subject: [PATCH] add webdav list_response parser --- src/services/webdav/backend.rs | 18 +- src/services/webdav/list_response.rs | 352 +++++++++++++++++++++++---- 2 files changed, 316 insertions(+), 54 deletions(-) diff --git a/src/services/webdav/backend.rs b/src/services/webdav/backend.rs index 56048508f9cc..5c3b8b3fbe72 100644 --- a/src/services/webdav/backend.rs +++ b/src/services/webdav/backend.rs @@ -269,18 +269,18 @@ impl Accessor for WebdavBackend { ma } - async fn list(&self, path: &str, args: OpList) -> Result<(RpList, ObjectPager)> { - let (_, _) = (path, args); + // async fn list(&self, path: &str, args: OpList) -> Result<(RpList, ObjectPager)> { + // let (_, _) = (path, args); - let empoty_string = AsyncBody::from("".into()); + // let empoty_string = AsyncBody::from("".into()); - let resp = self.webdav_put(path, None, "application/xml".into(), empoty_string); + // let resp = self.webdav_put(path, None, "application/xml".into(), empoty_string); - Err(Error::new( - ErrorKind::Unsupported, - "operation is not supported", - )) - } + // Err(Error::new( + // ErrorKind::Unsupported, + // "operation is not supported", + // )) + // } async fn create(&self, path: &str, _: OpCreate) -> Result { let resp = self diff --git a/src/services/webdav/list_response.rs b/src/services/webdav/list_response.rs index 9a704520737d..32cc4af786f0 100644 --- a/src/services/webdav/list_response.rs +++ b/src/services/webdav/list_response.rs @@ -1,74 +1,84 @@ use serde::Deserialize; -#[derive(Deserialize, Debug)] -#[serde(rename_all = "PascalCase")] +#[derive(Deserialize, Debug, PartialEq)] +#[serde(rename_all = "lowercase")] +pub struct LockEntry { + pub lockscope: LockScopeContainer, + pub locktype: LockTypeContainer, +} + +#[derive(Deserialize, Debug, PartialEq)] +pub struct LockScopeContainer { + #[serde(rename = "$value")] + pub value: LockScope, +} + +#[derive(Deserialize, Debug, PartialEq)] +#[serde(rename_all = "lowercase")] +pub enum LockScope { + Exclusive, +} + +#[derive(Deserialize, Debug, PartialEq)] +pub struct LockTypeContainer { + #[serde(rename = "$value")] + pub value: LockType, +} + +#[derive(Deserialize, Debug, PartialEq)] +#[serde(rename_all = "lowercase")] +pub enum LockType { + Write, +} + +#[derive(Deserialize, Debug, PartialEq)] struct Multistatus { response: Vec, } -#[derive(Deserialize, Debug)] -#[serde(rename_all = "PascalCase")] +#[derive(Deserialize, Debug, PartialEq)] struct ListOpResponse { href: String, propstat: Propstat, } -#[derive(Deserialize, Debug)] -#[serde(rename_all = "PascalCase")] +#[derive(Deserialize, Debug, PartialEq)] struct Propstat { prop: Prop, status: String, } -#[derive(Deserialize, Debug)] -#[serde(rename_all = "PascalCase")] +#[derive(Deserialize, Debug, PartialEq)] struct Prop { displayname: String, getlastmodified: String, - resourcetype: ResourceType, + resourcetype: ResourceTypeContainer, lockdiscovery: (), supportedlock: SupportedLock, } -#[derive(Deserialize, Debug)] -#[serde(rename_all = "PascalCase")] -#[derive(PartialEq)] +#[derive(Deserialize, Debug, PartialEq)] +struct ResourceTypeContainer { + #[serde(rename = "$value")] + value: Option, +} + +#[derive(Deserialize, Debug, PartialEq)] +#[serde(rename_all = "lowercase")] enum ResourceType { Collection, } -#[derive(Deserialize, Debug)] -#[serde(rename_all = "PascalCase")] +#[derive(Deserialize, Debug, PartialEq)] + struct SupportedLock { lockentry: LockEntry, } -#[derive(Deserialize, Debug)] -#[serde(rename_all = "PascalCase")] -struct LockEntry { - lockscope: LockScope, - locktype: LockType, -} - -#[derive(Deserialize, Debug)] -#[serde(rename_all = "PascalCase")] -#[derive(PartialEq)] -enum LockScope { - Exclusive, -} - -#[derive(Deserialize, Debug)] -#[serde(rename_all = "PascalCase")] -#[derive(PartialEq)] -enum LockType { - Write, -} - #[cfg(test)] mod tests { use super::*; use quick_xml::de::from_str; - #[test] fn test_lockentry() { let xml = r#" @@ -77,8 +87,8 @@ mod tests { "#; let lockentry = from_str::(xml).unwrap(); - assert_eq!(lockentry.lockscope, LockScope::Exclusive); - assert_eq!(lockentry.locktype, LockType::Write); + assert_eq!(lockentry.lockscope.value, LockScope::Exclusive); + assert_eq!(lockentry.locktype.value, LockType::Write); } #[test] @@ -91,8 +101,11 @@ mod tests { "#; let supportedlock = from_str::(xml).unwrap(); - assert_eq!(supportedlock.lockentry.lockscope, LockScope::Exclusive); - assert_eq!(supportedlock.lockentry.locktype, LockType::Write); + assert_eq!( + supportedlock.lockentry.lockscope.value, + LockScope::Exclusive + ); + assert_eq!(supportedlock.lockentry.locktype.value, LockType::Write); } #[test] @@ -100,7 +113,7 @@ mod tests { let xml = r#" / - Tue, 07 Feb 2023 06:39:47 GMT + Tue, 01 May 2022 06:39:47 GMT @@ -117,17 +130,266 @@ mod tests { assert_eq!(propstat.prop.displayname, "/"); assert_eq!( propstat.prop.getlastmodified, - "Tue, 07 Feb 2023 06:39:47 GMT" + "Tue, 01 May 2022 06:39:47 GMT" ); - assert_eq!(propstat.prop.resourcetype, ResourceType::Collection); assert_eq!( - propstat.prop.supportedlock.lockentry.lockscope, + propstat.prop.resourcetype.value.unwrap(), + ResourceType::Collection + ); + assert_eq!( + propstat.prop.supportedlock.lockentry.lockscope.value, LockScope::Exclusive ); assert_eq!( - propstat.prop.supportedlock.lockentry.locktype, + propstat.prop.supportedlock.lockentry.locktype.value, LockType::Write ); assert_eq!(propstat.status, "HTTP/1.1 200 OK"); } + + #[test] + fn test_response_simple() { + let xml = r#" + / + + + / + Tue, 01 May 2022 06:39:47 GMT + + + + + + + + + + HTTP/1.1 200 OK + + "#; + + let response = from_str::(xml).unwrap(); + assert_eq!(response.href, "/"); + assert_eq!(response.propstat.prop.displayname, "/"); + assert_eq!( + response.propstat.prop.getlastmodified, + "Tue, 01 May 2022 06:39:47 GMT" + ); + assert_eq!( + response.propstat.prop.resourcetype.value.unwrap(), + ResourceType::Collection + ); + assert_eq!( + response + .propstat + .prop + .supportedlock + .lockentry + .lockscope + .value, + LockScope::Exclusive + ); + assert_eq!( + response + .propstat + .prop + .supportedlock + .lockentry + .locktype + .value, + LockType::Write + ); + assert_eq!(response.propstat.status, "HTTP/1.1 200 OK"); + } + + #[test] + fn test_response_file() { + let xml = r#" + /test_file + + + test_file + 1 + Tue, 07 May 2022 05:52:22 GMT + + + + + + + + + + + + + + HTTP/1.1 200 OK + + "#; + + let response = from_str::(xml).unwrap(); + assert_eq!(response.href, "/test_file"); + assert_eq!(response.propstat.prop.displayname, "test_file"); + assert_eq!( + response.propstat.prop.getlastmodified, + "Tue, 07 May 2022 05:52:22 GMT" + ); + assert_eq!(response.propstat.prop.resourcetype.value, None); + + assert_eq!( + response + .propstat + .prop + .supportedlock + .lockentry + .lockscope + .value, + LockScope::Exclusive + ); + assert_eq!( + response + .propstat + .prop + .supportedlock + .lockentry + .locktype + .value, + LockType::Write + ); + assert_eq!(response.propstat.status, "HTTP/1.1 200 OK"); + } + + #[test] + fn test_with_multiple_items_simple() { + let xml = r#" + + / + + + / + Tue, 01 May 2022 06:39:47 GMT + + + + + + + + + + HTTP/1.1 200 OK + + + + / + + + / + Tue, 01 May 2022 06:39:47 GMT + + + + + + + + + + HTTP/1.1 200 OK + + + "#; + + let multistatus = from_str::(xml).unwrap(); + assert_eq!(multistatus.response.len(), 2); + assert_eq!(multistatus.response[0].href, "/"); + assert_eq!(multistatus.response[0].propstat.prop.displayname, "/"); + assert_eq!( + multistatus.response[0].propstat.prop.getlastmodified, + "Tue, 01 May 2022 06:39:47 GMT" + ); + } + + #[test] + fn test_with_multiple_items_mixed() { + let xml = r#" + + + / + + + / + Tue, 07 May 2022 06:39:47 GMT + + + + + + + + + + + + + + + + HTTP/1.1 200 OK + + + + /testdir/ + + + testdir + Tue, 07 May 2022 06:40:10 GMT + + + + + + + + + + + + + + + + HTTP/1.1 200 OK + + + + /test_file + + + test_file + 1 + Tue, 07 May 2022 05:52:22 GMT + + + + + + + + + + + + + + HTTP/1.1 200 OK + + + "#; + + let multistatus = from_str::(xml).unwrap(); + + assert_eq!(multistatus.response.len(), 3); + } }