From cd687516a8c1a48658d965222416b23a5a11a41b Mon Sep 17 00:00:00 2001 From: Collin O'Connor Date: Tue, 22 Jul 2025 19:53:57 -0400 Subject: [PATCH] add implementation specific attributes --- src/attributes.rs | 20 ++++++++++++++++---- src/aws/client.rs | 5 +++++ src/azure/client.rs | 5 +++++ src/gcp/client.rs | 5 +++++ src/http/client.rs | 1 + 5 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/attributes.rs b/src/attributes.rs index 11cf27c8..91886f37 100644 --- a/src/attributes.rs +++ b/src/attributes.rs @@ -49,6 +49,13 @@ pub enum Attribute { /// /// The String is a user-defined key Metadata(Cow<'static, str>), + /// Specifies an implementation-specific attribute to be sent with the object + /// + /// Attribute is prefixed with implementation-defined prefixes are as follows: + /// - [`AWS`](crate::aws): `x-amz-` + /// - [`Azure`](crate::azure): `x-ms-` + /// - [`GCP`](crate::gcp): `x-goog-` + Other(Cow<'static, str>), } /// The value of an [`Attribute`] @@ -199,10 +206,11 @@ mod tests { (Attribute::ContentType, "test"), (Attribute::CacheControl, "control"), (Attribute::Metadata("key1".into()), "value1"), + (Attribute::Other("key2".into()), "value2"), ]); assert!(!attributes.is_empty()); - assert_eq!(attributes.len(), 6); + assert_eq!(attributes.len(), 7); assert_eq!( attributes.get(&Attribute::ContentType), @@ -215,18 +223,18 @@ mod tests { attributes.insert(Attribute::CacheControl, "v1".into()), Some(metav) ); - assert_eq!(attributes.len(), 6); + assert_eq!(attributes.len(), 7); assert_eq!( attributes.remove(&Attribute::CacheControl).unwrap(), "v1".into() ); - assert_eq!(attributes.len(), 5); + assert_eq!(attributes.len(), 6); let metav: AttributeValue = "v2".into(); attributes.insert(Attribute::CacheControl, metav.clone()); assert_eq!(attributes.get(&Attribute::CacheControl), Some(&metav)); - assert_eq!(attributes.len(), 6); + assert_eq!(attributes.len(), 7); assert_eq!( attributes.get(&Attribute::ContentDisposition), @@ -244,5 +252,9 @@ mod tests { attributes.get(&Attribute::Metadata("key1".into())), Some(&"value1".into()) ); + assert_eq!( + attributes.get(&Attribute::Other("key2".into())), + Some(&"value2".into()) + ); } } diff --git a/src/aws/client.rs b/src/aws/client.rs index a99db159..f09ebe4c 100644 --- a/src/aws/client.rs +++ b/src/aws/client.rs @@ -59,6 +59,7 @@ use std::sync::Arc; const VERSION_HEADER: &str = "x-amz-version-id"; const SHA256_CHECKSUM: &str = "x-amz-checksum-sha256"; +const IMPL_DEFINED_ATTR_HEADER_PREFIX: &str = "x-amz-"; const USER_DEFINED_METADATA_HEADER_PREFIX: &str = "x-amz-meta-"; const ALGORITHM: &str = "x-amz-checksum-algorithm"; @@ -377,6 +378,10 @@ impl Request<'_> { &format!("{USER_DEFINED_METADATA_HEADER_PREFIX}{k_suffix}"), v.as_ref(), ), + Attribute::Other(attr) => builder.header( + &format!("{IMPL_DEFINED_ATTR_HEADER_PREFIX}{attr}"), + v.as_ref(), + ), }; } diff --git a/src/azure/client.rs b/src/azure/client.rs index c7440a07..fa418c60 100644 --- a/src/azure/client.rs +++ b/src/azure/client.rs @@ -49,6 +49,7 @@ use url::Url; const VERSION_HEADER: &str = "x-ms-version-id"; const USER_DEFINED_METADATA_HEADER_PREFIX: &str = "x-ms-meta-"; +const IMPL_DEFINED_ATTR_HEADER_PREFIX: &str = "x-ms-"; static MS_CACHE_CONTROL: HeaderName = HeaderName::from_static("x-ms-blob-cache-control"); static MS_CONTENT_TYPE: HeaderName = HeaderName::from_static("x-ms-blob-content-type"); static MS_CONTENT_DISPOSITION: HeaderName = @@ -246,6 +247,10 @@ impl PutRequest<'_> { &format!("{USER_DEFINED_METADATA_HEADER_PREFIX}{k_suffix}"), v.as_ref(), ), + Attribute::Other(attr) => builder.header( + &format!("{IMPL_DEFINED_ATTR_HEADER_PREFIX}{attr}"), + v.as_ref(), + ), }; } diff --git a/src/gcp/client.rs b/src/gcp/client.rs index a988cc45..eee9de18 100644 --- a/src/gcp/client.rs +++ b/src/gcp/client.rs @@ -51,6 +51,7 @@ use std::sync::Arc; const VERSION_HEADER: &str = "x-goog-generation"; const DEFAULT_CONTENT_TYPE: &str = "application/octet-stream"; const USER_DEFINED_METADATA_HEADER_PREFIX: &str = "x-goog-meta-"; +const IMPL_DEFINED_ATTR_HEADER_PREFIX: &str = "x-goog-"; static VERSION_MATCH: HeaderName = HeaderName::from_static("x-goog-if-generation-match"); @@ -205,6 +206,10 @@ impl Request<'_> { &format!("{USER_DEFINED_METADATA_HEADER_PREFIX}{k_suffix}"), v.as_ref(), ), + Attribute::Other(attr) => builder.header( + &format!("{IMPL_DEFINED_ATTR_HEADER_PREFIX}{attr}"), + v.as_ref(), + ), }; } diff --git a/src/http/client.rs b/src/http/client.rs index 272f7c60..6343ad06 100644 --- a/src/http/client.rs +++ b/src/http/client.rs @@ -198,6 +198,7 @@ impl Client { } // Ignore metadata attributes Attribute::Metadata(_) => builder, + Attribute::Other(attr) => builder.header(&**attr, v.as_ref()), }; }