diff --git a/core/Cargo.lock b/core/Cargo.lock index dae887b1db98..02886b5090d5 100644 --- a/core/Cargo.lock +++ b/core/Cargo.lock @@ -9324,9 +9324,9 @@ dependencies = [ [[package]] name = "reqsign-volcengine-tos" -version = "3.1.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ac4120764e6cf8b8bd431c9256bf1defeb2331ae616d353ee9d6b750c39f62" +checksum = "173387eb5ae4cf6a0a7098665ebcc6729862819dc3d95a81aee840767803e3d9" dependencies = [ "anyhow", "http 1.4.2", diff --git a/core/services/tos/Cargo.toml b/core/services/tos/Cargo.toml index 03b38058119a..ac11be4894cc 100644 --- a/core/services/tos/Cargo.toml +++ b/core/services/tos/Cargo.toml @@ -40,6 +40,6 @@ opendal-core = { path = "../../core", version = "0.58.1", default-features = fal quick-xml = { workspace = true, features = ["serialize", "overlapped-lists"] } reqsign-core = { version = "3.2.0", default-features = false } reqsign-file-read-tokio = { version = "3.0.3", default-features = false } -reqsign-volcengine-tos = "3.0.3" +reqsign-volcengine-tos = "3.1.1" serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } diff --git a/core/services/tos/src/backend.rs b/core/services/tos/src/backend.rs index 74b1c38fd067..5526cee403ae 100644 --- a/core/services/tos/src/backend.rs +++ b/core/services/tos/src/backend.rs @@ -33,7 +33,7 @@ use crate::writer::TosWriter; use http::StatusCode; use opendal_core::OperationContext; use opendal_core::raw::*; -use opendal_core::{Builder, Capability, EntryMode, Error, ErrorKind, Result}; +use opendal_core::{Buffer, Builder, Capability, EntryMode, Error, ErrorKind, Result}; use reqsign_core::{Context, OsEnv, ProvideCredentialChain, Signer}; use reqsign_file_read_tokio::TokioFileRead; use reqsign_volcengine_tos::{EnvCredentialProvider, RequestSigner, StaticCredentialProvider}; @@ -215,6 +215,12 @@ impl Builder for TosBuilder { list_with_versions: true, list_with_deleted: true, + presign: true, + presign_stat: true, + presign_read: true, + presign_write: true, + presign_delete: true, + stat: true, stat_with_if_match: true, stat_with_if_none_match: true, @@ -416,13 +422,31 @@ impl Service for TosBackend { async fn presign( &self, - _ctx: &OperationContext, - _path: &str, - _args: OpPresign, + ctx: &OperationContext, + path: &str, + args: OpPresign, ) -> Result { - Err(Error::new( - ErrorKind::Unsupported, - "operation is not supported", - )) + let (expire, op) = args.into_parts(); + let req = match op { + PresignOperation::Stat(v) => self.core.tos_head_object_request(path, v), + PresignOperation::Read(range, v) => self.core.tos_get_object_request(path, range, &v), + PresignOperation::Write(v) => { + self.core + .tos_put_object_request(path, None, &v, Buffer::new()) + } + PresignOperation::Delete(v) => self.core.tos_delete_object_request(path, &v), + _ => Err(Error::new( + ErrorKind::Unsupported, + "operation is not supported", + )), + }?; + let req = self.core.sign_query(ctx, req, expire).await?; + let (parts, _) = req.into_parts(); + + Ok(RpPresign::new(PresignedRequest::new( + parts.method, + parts.uri, + parts.headers, + ))) } } diff --git a/core/services/tos/src/core.rs b/core/services/tos/src/core.rs index f32066cd35aa..ed3436df61c5 100644 --- a/core/services/tos/src/core.rs +++ b/core/services/tos/src/core.rs @@ -16,6 +16,7 @@ // under the License. use std::fmt::Debug; +use std::time::Duration; use http::Request; use http::Response; @@ -99,6 +100,27 @@ impl TosCore { ) } + pub async fn sign_query( + &self, + ctx: &OperationContext, + req: Request, + duration: Duration, + ) -> Result> { + if self.skip_signature { + return Ok(req); + } + + let (mut parts, body) = req.into_parts(); + self.signer(ctx) + .sign(&mut parts, Some(duration)) + .await + .map_err(|e| new_request_sign_error(e.into()))?; + + parts.headers.remove(HOST); + + Ok(Request::from_parts(parts, body)) + } + pub async fn send( &self, ctx: &OperationContext, @@ -413,12 +435,11 @@ impl TosCore { self.send(ctx, req).await } - pub async fn tos_delete_object( + pub fn tos_delete_object_request( &self, - ctx: &OperationContext, path: &str, args: &OpDelete, - ) -> Result> { + ) -> Result> { let p = build_abs_path(&self.root, path); let mut url = format!( @@ -444,11 +465,19 @@ impl TosCore { let req = Request::delete(&url); - let req = req - .extension(Operation::Delete) + req.extension(Operation::Delete) .extension(ServiceOperation("DeleteObject")) .body(Buffer::new()) - .map_err(new_request_build_error)?; + .map_err(new_request_build_error) + } + + pub async fn tos_delete_object( + &self, + ctx: &OperationContext, + path: &str, + args: &OpDelete, + ) -> Result> { + let req = self.tos_delete_object_request(path, args)?; self.send(ctx, req).await } diff --git a/core/services/tos/src/docs.md b/core/services/tos/src/docs.md index 01610d88cec2..6f688f1a6941 100644 --- a/core/services/tos/src/docs.md +++ b/core/services/tos/src/docs.md @@ -10,7 +10,7 @@ Depending on its configuration and the backing system, this service can expose: - [x] list - [x] copy - [ ] rename -- [ ] presign +- [x] presign Inspect the effective capability set with [`opendal_core::Operator::info`] and [`opendal_core::OperatorInfo::capability`] after building an operator.