From 566a789bd29f85106302f1f27acfade4ab3678b6 Mon Sep 17 00:00:00 2001 From: frankwang <73262844+Frank-III@users.noreply.github.com> Date: Wed, 11 Dec 2024 01:43:43 -0600 Subject: [PATCH] feat(services/obs): support user defined metadata (#5405) --- core/src/services/obs/backend.rs | 27 +++++++++++++++++++++++++-- core/src/services/obs/core.rs | 11 +++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/core/src/services/obs/backend.rs b/core/src/services/obs/backend.rs index ea33bf7ecf1..28b33d37de4 100644 --- a/core/src/services/obs/backend.rs +++ b/core/src/services/obs/backend.rs @@ -15,6 +15,7 @@ // specific language governing permissions and limitations // under the License. +use std::collections::HashMap; use std::fmt::Debug; use std::fmt::Formatter; use std::sync::Arc; @@ -27,7 +28,7 @@ use reqsign::HuaweicloudObsConfig; use reqsign::HuaweicloudObsCredentialLoader; use reqsign::HuaweicloudObsSigner; -use super::core::ObsCore; +use super::core::{constants, ObsCore}; use super::delete::ObsDeleter; use super::error::parse_error; use super::lister::ObsLister; @@ -284,6 +285,7 @@ impl Access for ObsBackend { } else { Some(usize::MAX) }, + write_with_user_metadata: true, delete: true, copy: true, @@ -306,12 +308,33 @@ impl Access for ObsBackend { async fn stat(&self, path: &str, args: OpStat) -> Result { let resp = self.core.obs_head_object(path, &args).await?; + let headers = resp.headers(); let status = resp.status(); // The response is very similar to azblob. match status { - StatusCode::OK => parse_into_metadata(path, resp.headers()).map(RpStat::new), + StatusCode::OK => { + let mut meta = parse_into_metadata(path, headers)?; + let user_meta = headers + .iter() + .filter_map(|(name, _)| { + name.as_str() + .strip_prefix(constants::X_OBS_META_PREFIX) + .and_then(|stripped_key| { + parse_header_to_str(headers, name) + .unwrap_or(None) + .map(|val| (stripped_key.to_string(), val.to_string())) + }) + }) + .collect::>(); + + if !user_meta.is_empty() { + meta.with_user_metadata(user_meta); + } + + Ok(RpStat::new(meta)) + } StatusCode::NOT_FOUND if path.ends_with('/') => { Ok(RpStat::new(Metadata::new(EntryMode::DIR))) } diff --git a/core/src/services/obs/core.rs b/core/src/services/obs/core.rs index e331f327c77..079c23e31a6 100644 --- a/core/src/services/obs/core.rs +++ b/core/src/services/obs/core.rs @@ -37,6 +37,10 @@ use serde::Serialize; use crate::raw::*; use crate::*; +pub mod constants { + pub const X_OBS_META_PREFIX: &str = "x-obs-meta-"; +} + pub struct ObsCore { pub bucket: String, pub root: String, @@ -167,6 +171,13 @@ impl ObsCore { req = req.header(CONTENT_TYPE, mime) } + // Set user metadata headers. + if let Some(user_metadata) = args.user_metadata() { + for (key, value) in user_metadata { + req = req.header(format!("{}{}", constants::X_OBS_META_PREFIX, key), value) + } + } + let req = req.body(body).map_err(new_request_build_error)?; Ok(req)