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

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


The following commit(s) were added to refs/heads/main by this push:
     new 239d3ed3 feat(core): add presign support for obs (#2253)
239d3ed3 is described below

commit 239d3ed3548500943efc614498a51d1ff9aa75e6
Author: Will Li <[email protected]>
AuthorDate: Tue May 16 11:52:40 2023 +0800

    feat(core): add presign support for obs (#2253)
    
    * add presign support for obs
    
    * update based on comment
---
 core/src/services/obs/backend.rs | 41 ++++++++++++++++++++++++++++--
 core/src/services/obs/core.rs    | 54 +++++++++++++++++++++++++++++++++-------
 2 files changed, 84 insertions(+), 11 deletions(-)

diff --git a/core/src/services/obs/backend.rs b/core/src/services/obs/backend.rs
index 29a745ca..1ffa052e 100644
--- a/core/src/services/obs/backend.rs
+++ b/core/src/services/obs/backend.rs
@@ -50,7 +50,7 @@ use crate::*;
 /// - [ ] rename
 /// - [x] list
 /// - [x] scan
-/// - [ ] presign
+/// - [x] presign
 /// - [ ] blocking
 ///
 /// # Configuration
@@ -332,12 +332,49 @@ impl Accessor for ObsBackend {
                 list_with_delimiter_slash: true,
                 list_without_delimiter: true,
 
+                presign: true,
+                presign_stat: true,
+                presign_read: true,
+                presign_write: true,
+
                 ..Default::default()
             });
 
         am
     }
 
+    async fn presign(&self, path: &str, args: OpPresign) -> Result<RpPresign> {
+        let mut req = match args.operation() {
+            PresignOperation::Stat(v) => {
+                self.core
+                    .obs_head_object_request(path, v.if_match(), 
v.if_none_match())?
+            }
+            PresignOperation::Read(v) => self.core.obs_get_object_request(
+                path,
+                v.range(),
+                v.if_match(),
+                v.if_none_match(),
+            )?,
+            PresignOperation::Write(v) => self.core.obs_put_object_request(
+                path,
+                None,
+                v.content_type(),
+                v.cache_control(),
+                AsyncBody::Empty,
+            )?,
+        };
+        self.core.sign_query(&mut req, args.expire()).await?;
+
+        // We don't need this request anymore, consume it directly.
+        let (parts, _) = req.into_parts();
+
+        Ok(RpPresign::new(PresignedRequest::new(
+            parts.method,
+            parts.uri,
+            parts.headers,
+        )))
+    }
+
     async fn create_dir(&self, path: &str, _: OpCreateDir) -> 
Result<RpCreateDir> {
         let mut req =
             self.core
@@ -411,7 +448,7 @@ impl Accessor for ObsBackend {
 
         let resp = self
             .core
-            .obs_get_head_object(path, args.if_match(), args.if_none_match())
+            .obs_head_object(path, args.if_match(), args.if_none_match())
             .await?;
 
         let status = resp.status();
diff --git a/core/src/services/obs/core.rs b/core/src/services/obs/core.rs
index 2dab3a8b..32491c59 100644
--- a/core/src/services/obs/core.rs
+++ b/core/src/services/obs/core.rs
@@ -17,6 +17,7 @@
 
 use std::fmt::Debug;
 use std::fmt::Formatter;
+use std::time::Duration;
 
 use http::header::CACHE_CONTROL;
 use http::header::CONTENT_LENGTH;
@@ -77,6 +78,18 @@ impl ObsCore {
         self.signer.sign(req, &cred).map_err(new_request_sign_error)
     }
 
+    pub async fn sign_query<T>(&self, req: &mut Request<T>, duration: 
Duration) -> Result<()> {
+        let cred = if let Some(cred) = self.load_credential().await? {
+            cred
+        } else {
+            return Ok(());
+        };
+
+        self.signer
+            .sign_query(req, duration, &cred)
+            .map_err(new_request_sign_error)
+    }
+
     #[inline]
     pub async fn send(&self, req: Request<AsyncBody>) -> 
Result<Response<IncomingAsyncBody>> {
         self.client.send(req).await
@@ -91,6 +104,20 @@ impl ObsCore {
         if_match: Option<&str>,
         if_none_match: Option<&str>,
     ) -> Result<Response<IncomingAsyncBody>> {
+        let mut req = self.obs_get_object_request(path, range, if_match, 
if_none_match)?;
+
+        self.sign(&mut req).await?;
+
+        self.send(req).await
+    }
+
+    pub fn obs_get_object_request(
+        &self,
+        path: &str,
+        range: BytesRange,
+        if_match: Option<&str>,
+        if_none_match: Option<&str>,
+    ) -> Result<Request<AsyncBody>> {
         let p = build_abs_path(&self.root, path);
 
         let url = format!("{}/{}", self.endpoint, percent_encode_path(&p));
@@ -109,13 +136,11 @@ impl ObsCore {
             req = req.header(IF_NONE_MATCH, if_none_match);
         }
 
-        let mut req = req
+        let req = req
             .body(AsyncBody::Empty)
             .map_err(new_request_build_error)?;
 
-        self.sign(&mut req).await?;
-
-        self.send(req).await
+        Ok(req)
     }
 
     pub fn obs_put_object_request(
@@ -148,12 +173,25 @@ impl ObsCore {
         Ok(req)
     }
 
-    pub async fn obs_get_head_object(
+    pub async fn obs_head_object(
         &self,
         path: &str,
         if_match: Option<&str>,
         if_none_match: Option<&str>,
     ) -> Result<Response<IncomingAsyncBody>> {
+        let mut req = self.obs_head_object_request(path, if_match, 
if_none_match)?;
+
+        self.sign(&mut req).await?;
+
+        self.send(req).await
+    }
+
+    pub fn obs_head_object_request(
+        &self,
+        path: &str,
+        if_match: Option<&str>,
+        if_none_match: Option<&str>,
+    ) -> Result<Request<AsyncBody>> {
         let p = build_abs_path(&self.root, path);
 
         let url = format!("{}/{}", self.endpoint, percent_encode_path(&p));
@@ -171,13 +209,11 @@ impl ObsCore {
             req = req.header(IF_NONE_MATCH, if_none_match);
         }
 
-        let mut req = req
+        let req = req
             .body(AsyncBody::Empty)
             .map_err(new_request_build_error)?;
 
-        self.sign(&mut req).await?;
-
-        self.send(req).await
+        Ok(req)
     }
 
     pub async fn obs_delete_object(&self, path: &str) -> 
Result<Response<IncomingAsyncBody>> {

Reply via email to