-
Notifications
You must be signed in to change notification settings - Fork 596
feat(core/services-azblob): support user defined metadata #5274
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
23bb518
f645cc6
4c6476a
398efed
39e4d62
72e6e10
155bb1a
1927932
4282d5d
d28eae6
4d6057b
3228bd2
d76c46d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -33,6 +33,7 @@ use reqsign::AzureStorageSigner; | |||
use sha2::Digest; | ||||
use sha2::Sha256; | ||||
|
||||
use super::core::constants::X_MS_META_PREFIX; | ||||
use super::error::parse_error; | ||||
use super::lister::AzblobLister; | ||||
use super::writer::AzblobWriter; | ||||
|
@@ -517,6 +518,7 @@ impl Access for AzblobBackend { | |||
write_can_multi: true, | ||||
write_with_cache_control: true, | ||||
write_with_content_type: true, | ||||
write_with_user_metadata: true, | ||||
|
||||
delete: true, | ||||
copy: true, | ||||
|
@@ -545,7 +547,17 @@ impl Access for AzblobBackend { | |||
let status = resp.status(); | ||||
|
||||
match status { | ||||
StatusCode::OK => parse_into_metadata(path, resp.headers()).map(RpStat::new), | ||||
StatusCode::OK => { | ||||
let headers = resp.headers(); | ||||
let mut meta = parse_into_metadata(path, headers)?; | ||||
|
||||
let user_meta = parse_prefixed_headers(headers, X_MS_META_PREFIX); | ||||
if !user_meta.is_empty() { | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This check is also done in the s3 backend. Should we always call Or can we for example, add that checking inside opendal/core/src/types/metadata.rs Line 524 in 1927932
I find that checking in each backend if the hashmap is empty is error-prone boilerplate... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's fine to have such a check. OpenDAL tends to have more readable code because we have many services, and that code is rarely modified. |
||||
meta.with_user_metadata(user_meta); | ||||
} | ||||
|
||||
Ok(RpStat::new(meta)) | ||||
} | ||||
_ => Err(parse_error(resp)), | ||||
} | ||||
} | ||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,7 @@ use std::time::Duration; | |
use base64::prelude::BASE64_STANDARD; | ||
use base64::Engine; | ||
use bytes::Bytes; | ||
use constants::X_MS_META_PREFIX; | ||
use http::header::HeaderName; | ||
use http::header::CONTENT_LENGTH; | ||
use http::header::CONTENT_TYPE; | ||
|
@@ -42,13 +43,14 @@ use uuid::Uuid; | |
use crate::raw::*; | ||
use crate::*; | ||
|
||
mod constants { | ||
pub mod constants { | ||
pub const X_MS_VERSION: &str = "x-ms-version"; | ||
|
||
pub const X_MS_BLOB_TYPE: &str = "x-ms-blob-type"; | ||
pub const X_MS_COPY_SOURCE: &str = "x-ms-copy-source"; | ||
pub const X_MS_BLOB_CACHE_CONTROL: &str = "x-ms-blob-cache-control"; | ||
pub const X_MS_BLOB_CONDITION_APPENDPOS: &str = "x-ms-blob-condition-appendpos"; | ||
pub const X_MS_META_PREFIX: &str = "x-ms-meta-"; | ||
|
||
// Server-side encryption with customer-provided headers | ||
pub const X_MS_ENCRYPTION_KEY: &str = "x-ms-encryption-key"; | ||
|
@@ -243,12 +245,19 @@ impl AzblobCore { | |
|
||
let mut req = Request::put(&url); | ||
|
||
if let Some(user_metadata) = args.user_metadata() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm setting the metadata headers only for the Should this also be done for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see that in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Not sure for now; I will need some time to delve into the documentation.
I remember that only the first append request can include user metadata, but I'm not sure about that. Feel free to do more research on this. |
||
for (key, value) in user_metadata { | ||
req = req.header(format!("{X_MS_META_PREFIX}{key}"), value) | ||
} | ||
} | ||
|
||
// Set SSE headers. | ||
req = self.insert_sse_headers(req); | ||
|
||
if let Some(cache_control) = args.cache_control() { | ||
req = req.header(constants::X_MS_BLOB_CACHE_CONTROL, cache_control); | ||
} | ||
|
||
if let Some(size) = size { | ||
req = req.header(CONTENT_LENGTH, size) | ||
} | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -15,13 +15,13 @@ | |||||
// specific language governing permissions and limitations | ||||||
// under the License. | ||||||
|
||||||
use std::collections::HashMap; | ||||||
use std::fmt::Debug; | ||||||
use std::fmt::Formatter; | ||||||
use std::fmt::Write; | ||||||
use std::time::Duration; | ||||||
|
||||||
use bytes::Bytes; | ||||||
use constants::X_OSS_META_PREFIX; | ||||||
use http::header::CACHE_CONTROL; | ||||||
use http::header::CONTENT_DISPOSITION; | ||||||
use http::header::CONTENT_LENGTH; | ||||||
|
@@ -190,7 +190,7 @@ impl OssCore { | |||||
"the format of the user metadata key is invalid, please refer the document", | ||||||
)); | ||||||
} | ||||||
req = req.header(format!("{}{}", constants::X_OSS_META_PREFIX, key), value) | ||||||
req = req.header(format!("{X_OSS_META_PREFIX}{key}"), value) | ||||||
} | ||||||
} | ||||||
|
||||||
|
@@ -213,28 +213,11 @@ impl OssCore { | |||||
/// # Notes | ||||||
/// | ||||||
/// before return the user defined metadata, we'll strip the user_metadata_prefix from the key | ||||||
pub fn parse_metadata( | ||||||
&self, | ||||||
path: &str, | ||||||
user_metadata_prefix: &str, | ||||||
headers: &HeaderMap, | ||||||
) -> Result<Metadata> { | ||||||
pub fn parse_metadata(&self, path: &str, headers: &HeaderMap) -> Result<Metadata> { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the opendal/core/src/services/azblob/backend.rs Line 552 in 4d6057b
But in the opendal/core/src/services/oss/backend.rs Line 492 in 4d6057b
I think we should unify this in order to be consistent. In my opinion, maybe we can create a new What do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Hi, it's better not to do this since every service has its own functions. You'll see if you delve into the implementation of different services. The |
||||||
let mut m = parse_into_metadata(path, headers)?; | ||||||
|
||||||
let data: HashMap<String, String> = headers | ||||||
.iter() | ||||||
.filter_map(|(key, _)| { | ||||||
key.as_str() | ||||||
.strip_prefix(user_metadata_prefix) | ||||||
.and_then(|stripped_key| { | ||||||
parse_header_to_str(headers, key) | ||||||
.unwrap_or(None) | ||||||
.map(|val| (stripped_key.to_string(), val.to_string())) | ||||||
}) | ||||||
}) | ||||||
.collect(); | ||||||
if !data.is_empty() { | ||||||
m.with_user_metadata(data); | ||||||
let user_meta = parse_prefixed_headers(headers, X_OSS_META_PREFIX); | ||||||
if !user_meta.is_empty() { | ||||||
m.with_user_metadata(user_meta); | ||||||
} | ||||||
|
||||||
Ok(m) | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,7 @@ use std::time::Duration; | |
use base64::prelude::BASE64_STANDARD; | ||
use base64::Engine; | ||
use bytes::Bytes; | ||
use constants::X_AMZ_META_PREFIX; | ||
use http::header::HeaderName; | ||
use http::header::CACHE_CONTROL; | ||
use http::header::CONTENT_DISPOSITION; | ||
|
@@ -462,7 +463,7 @@ impl S3Core { | |
// Set user metadata headers. | ||
if let Some(user_metadata) = args.user_metadata() { | ||
for (key, value) in user_metadata { | ||
req = req.header(format!("{}{}", constants::X_AMZ_META_PREFIX, key), value) | ||
req = req.header(format!("{X_AMZ_META_PREFIX}{key}"), value) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changed this in order to be consistent with what I did in the azure part. It is more idiomatic to use string interpolation |
||
} | ||
} | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.