This is an automated email from the ASF dual-hosted git repository.

suyanhanx pushed a commit to branch webdav-copy
in repository https://gitbox.apache.org/repos/asf/incubator-opendal.git

commit 72dd6a31eefcb165e3653256fc7a83fa8953564f
Author: suyanhanx <[email protected]>
AuthorDate: Fri Apr 7 15:36:42 2023 +0800

    feat(webdav): support copy
    
    Signed-off-by: suyanhanx <[email protected]>
---
 core/src/services/webdav/backend.rs | 42 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/core/src/services/webdav/backend.rs 
b/core/src/services/webdav/backend.rs
index 5b1180c5..ca824b6e 100644
--- a/core/src/services/webdav/backend.rs
+++ b/core/src/services/webdav/backend.rs
@@ -44,6 +44,7 @@ use crate::*;
 ///
 /// - [x] read
 /// - [x] write
+/// - [x] copy
 /// - [x] list
 /// - [ ] ~~scan~~
 /// - [ ] ~~presign~~
@@ -265,7 +266,10 @@ impl Accessor for WebdavBackend {
         ma.set_scheme(Scheme::Webdav)
             .set_root(&self.root)
             .set_capabilities(
-                AccessorCapability::Read | AccessorCapability::Write | 
AccessorCapability::List,
+                AccessorCapability::Read
+                    | AccessorCapability::Write
+                    | AccessorCapability::Copy
+                    | AccessorCapability::List,
             )
             .set_hints(AccessorHint::ReadStreamable);
 
@@ -318,6 +322,17 @@ impl Accessor for WebdavBackend {
         Ok((RpWrite::default(), WebdavWriter::new(self.clone(), args, p)))
     }
 
+    async fn copy(&self, from: &str, to: &str, _args: OpCopy) -> 
Result<RpCopy> {
+        let resp = self.webdav_copy(from, to).await?;
+
+        let status = resp.status();
+
+        match status {
+            StatusCode::CREATED | StatusCode::NO_CONTENT => 
Ok(RpCopy::default()),
+            _ => Err(parse_error(resp).await?),
+        }
+    }
+
     async fn stat(&self, path: &str, _: OpStat) -> Result<RpStat> {
         // Stat root always returns a DIR.
         if path == "/" {
@@ -549,6 +564,31 @@ impl WebdavBackend {
         self.client.send_async(req).await
     }
 
+    async fn webdav_copy(&self, from: &str, to: &str) -> 
Result<Response<IncomingAsyncBody>> {
+        let source = build_abs_path(&self.root, from);
+        let target = build_abs_path(&self.root, to);
+
+        let source = format!("{}/{}", self.endpoint, 
percent_encode_path(&source));
+        let target = format!("{}/{}", self.endpoint, 
percent_encode_path(&target));
+
+        let mut req = Request::builder().method("COPY").uri(&source);
+
+        if let Some(auth) = &self.authorization {
+            req = req.header(header::AUTHORIZATION, auth);
+        }
+
+        req = req.header("Destination", target);
+
+        // We always specific "T" for keeping to overwrite the destination.
+        req = req.header("Overwrite", "T");
+
+        let req = req
+            .body(AsyncBody::Empty)
+            .map_err(new_request_build_error)?;
+
+        self.client.send_async(req).await
+    }
+
     async fn create_internal(&self, abs_path: &str) -> Result<RpCreate> {
         let resp = if abs_path.ends_with('/') {
             self.webdav_mkcol(abs_path, None, None, AsyncBody::Empty)

Reply via email to