diff --git a/core/src/services/obs/backend.rs b/core/src/services/obs/backend.rs index ea33bf7ecf14..a62ddfa89e84 100644 --- a/core/src/services/obs/backend.rs +++ b/core/src/services/obs/backend.rs @@ -284,6 +284,7 @@ impl Access for ObsBackend { } else { Some(usize::MAX) }, + write_with_user_metadata: true, delete: true, copy: true, @@ -306,12 +307,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 e331f327c770..079c23e31a64 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)