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

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


The following commit(s) were added to refs/heads/main by this push:
     new 0f8b4613d feat(services/swift): add conditional request headers for 
stat and read (#7208)
0f8b4613d is described below

commit 0f8b4613dae906484ece0b270f02d729472bb344
Author: Ben Roeder <[email protected]>
AuthorDate: Sun Feb 22 16:49:26 2026 -0800

    feat(services/swift): add conditional request headers for stat and read 
(#7208)
    
    feat(services/swift): add conditional request headers
    
    Add If-Match, If-None-Match, If-Modified-Since, If-Unmodified-Since
    support for stat and read operations.
    
    Map HTTP 304 Not Modified to ConditionNotMatch error kind.
    
    Note: Swift does not support If-Match on PUT and only supports
    If-None-Match: * (not specific etag values) on PUT, so write
    conditional capabilities are not declared.
---
 core/services/swift/src/backend.rs | 13 +++++++++++--
 core/services/swift/src/core.rs    | 34 ++++++++++++++++++++++++++++++++--
 core/services/swift/src/error.rs   |  4 +++-
 3 files changed, 46 insertions(+), 5 deletions(-)

diff --git a/core/services/swift/src/backend.rs 
b/core/services/swift/src/backend.rs
index 088e54abd..3bc7bd00a 100644
--- a/core/services/swift/src/backend.rs
+++ b/core/services/swift/src/backend.rs
@@ -144,7 +144,16 @@ impl Builder for SwiftBuilder {
                         .set_root(&root)
                         .set_native_capability(Capability {
                             stat: true,
+                            stat_with_if_match: true,
+                            stat_with_if_none_match: true,
+                            stat_with_if_modified_since: true,
+                            stat_with_if_unmodified_since: true,
+
                             read: true,
+                            read_with_if_match: true,
+                            read_with_if_none_match: true,
+                            read_with_if_modified_since: true,
+                            read_with_if_unmodified_since: true,
 
                             write: true,
                             write_can_empty: true,
@@ -192,8 +201,8 @@ impl Access for SwiftBackend {
         self.core.info.clone()
     }
 
-    async fn stat(&self, path: &str, _args: OpStat) -> Result<RpStat> {
-        let resp = self.core.swift_get_metadata(path).await?;
+    async fn stat(&self, path: &str, args: OpStat) -> Result<RpStat> {
+        let resp = self.core.swift_get_metadata(path, &args).await?;
 
         match resp.status() {
             StatusCode::OK | StatusCode::NO_CONTENT => {
diff --git a/core/services/swift/src/core.rs b/core/services/swift/src/core.rs
index ef837f531..6301b7974 100644
--- a/core/services/swift/src/core.rs
+++ b/core/services/swift/src/core.rs
@@ -21,6 +21,10 @@ use std::sync::Arc;
 use http::Request;
 use http::Response;
 use http::header;
+use http::header::IF_MATCH;
+use http::header::IF_MODIFIED_SINCE;
+use http::header::IF_NONE_MATCH;
+use http::header::IF_UNMODIFIED_SINCE;
 use serde::Deserialize;
 
 use opendal_core::raw::*;
@@ -156,7 +160,7 @@ impl SwiftCore {
         &self,
         path: &str,
         range: BytesRange,
-        _arg: &OpRead,
+        args: &OpRead,
     ) -> Result<Response<HttpBody>> {
         let p = build_abs_path(&self.root, path)
             .trim_end_matches('/')
@@ -177,6 +181,19 @@ impl SwiftCore {
             req = req.header(header::RANGE, range.to_header());
         }
 
+        if let Some(if_match) = args.if_match() {
+            req = req.header(IF_MATCH, if_match);
+        }
+        if let Some(if_none_match) = args.if_none_match() {
+            req = req.header(IF_NONE_MATCH, if_none_match);
+        }
+        if let Some(if_modified_since) = args.if_modified_since() {
+            req = req.header(IF_MODIFIED_SINCE, 
if_modified_since.format_http_date());
+        }
+        if let Some(if_unmodified_since) = args.if_unmodified_since() {
+            req = req.header(IF_UNMODIFIED_SINCE, 
if_unmodified_since.format_http_date());
+        }
+
         let req = req
             .extension(Operation::Read)
             .body(Buffer::new())
@@ -225,7 +242,7 @@ impl SwiftCore {
         self.info.http_client().send(req).await
     }
 
-    pub async fn swift_get_metadata(&self, path: &str) -> 
Result<Response<Buffer>> {
+    pub async fn swift_get_metadata(&self, path: &str, args: &OpStat) -> 
Result<Response<Buffer>> {
         let p = build_abs_path(&self.root, path);
 
         let url = format!(
@@ -239,6 +256,19 @@ impl SwiftCore {
 
         req = req.header("X-Auth-Token", &self.token);
 
+        if let Some(if_match) = args.if_match() {
+            req = req.header(IF_MATCH, if_match);
+        }
+        if let Some(if_none_match) = args.if_none_match() {
+            req = req.header(IF_NONE_MATCH, if_none_match);
+        }
+        if let Some(if_modified_since) = args.if_modified_since() {
+            req = req.header(IF_MODIFIED_SINCE, 
if_modified_since.format_http_date());
+        }
+        if let Some(if_unmodified_since) = args.if_unmodified_since() {
+            req = req.header(IF_UNMODIFIED_SINCE, 
if_unmodified_since.format_http_date());
+        }
+
         let req = req
             .extension(Operation::Stat)
             .body(Buffer::new())
diff --git a/core/services/swift/src/error.rs b/core/services/swift/src/error.rs
index a062ac6d9..32d5d57c1 100644
--- a/core/services/swift/src/error.rs
+++ b/core/services/swift/src/error.rs
@@ -39,7 +39,9 @@ pub(super) fn parse_error(resp: Response<Buffer>) -> Error {
     let (kind, retryable) = match parts.status {
         StatusCode::NOT_FOUND => (ErrorKind::NotFound, false),
         StatusCode::UNAUTHORIZED | StatusCode::FORBIDDEN => 
(ErrorKind::PermissionDenied, false),
-        StatusCode::PRECONDITION_FAILED => (ErrorKind::ConditionNotMatch, 
false),
+        StatusCode::NOT_MODIFIED | StatusCode::PRECONDITION_FAILED => {
+            (ErrorKind::ConditionNotMatch, false)
+        }
         StatusCode::INTERNAL_SERVER_ERROR
         | StatusCode::BAD_GATEWAY
         | StatusCode::SERVICE_UNAVAILABLE

Reply via email to