From 54afecdaac717ea4c4fe203285d086dc75639ca8 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Tue, 28 Jun 2022 11:55:46 +0200 Subject: [PATCH 1/2] Consistent header method naming --- sdk/core/src/error/http_error.rs | 2 +- sdk/core/src/headers/mod.rs | 82 +++++++++++-------- sdk/core/src/headers/utilities.rs | 22 ++--- sdk/core/src/request_options/next_marker.rs | 2 +- sdk/data_cosmos/src/headers/from_headers.rs | 22 ++--- ...continuation_next_partition_and_row_key.rs | 4 +- .../src/continuation_next_table_name.rs | 2 +- .../src/responses/insert_entity_response.rs | 2 +- .../src/service/responses/query_response.rs | 2 +- .../src/service_bus/mod.rs | 2 +- .../account/operations/find_blobs_by_tags.rs | 1 + sdk/storage/src/authorization_policy.rs | 6 +- .../core/clients/storage_account_client.rs | 4 +- sdk/storage/src/core/headers/mod.rs | 4 +- sdk/storage_blobs/src/blob/mod.rs | 26 +++--- sdk/storage_blobs/src/container/mod.rs | 4 +- .../src/container/operations/get_acl.rs | 6 +- .../container/operations/get_properties.rs | 2 +- .../src/authorization_policies/shared_key.rs | 6 +- .../src/operations/path_head.rs | 4 +- sdk/storage_datalake/src/properties.rs | 2 +- .../src/operations/update_message.rs | 3 +- 22 files changed, 110 insertions(+), 100 deletions(-) diff --git a/sdk/core/src/error/http_error.rs b/sdk/core/src/error/http_error.rs index 5218554601..c984ac2f87 100644 --- a/sdk/core/src/error/http_error.rs +++ b/sdk/core/src/error/http_error.rs @@ -71,7 +71,7 @@ impl std::error::Error for HttpError {} /// /// For more info, see [here](https://github.com/microsoft/api-guidelines/blob/vNext/azure/Guidelines.md#handling-errors) fn get_error_code_from_header(response: &Response) -> Option { - response.headers().get_as_string(&headers::ERROR_CODE) + response.headers().get_optional_string(&headers::ERROR_CODE) } /// Gets the error code if it's present in the body diff --git a/sdk/core/src/headers/mod.rs b/sdk/core/src/headers/mod.rs index 9a1d8c1eb5..3d4a552fee 100644 --- a/sdk/core/src/headers/mod.rs +++ b/sdk/core/src/headers/mod.rs @@ -59,68 +59,78 @@ impl Headers { Self(Default::default()) } - /// Get a header value given a specific header name - pub fn get(&self, key: &HeaderName) -> Option<&HeaderValue> { - self.0.get(key) - } - - /// Get a header value or error if it is not found - pub fn get_or_err(&self, key: &HeaderName) -> crate::Result<&HeaderValue> { - self.get(key).ok_or_else(|| { - Error::with_message(ErrorKind::DataConversion, || { - format!("header not found {}", key.as_str()) - }) - }) + /// Get a header value as a String or error if it is not found + pub fn get_string(&self, key: &HeaderName) -> crate::Result { + Ok(self.get_str(key)?.to_owned()) } - /// Get a header value as a str - pub fn get_as_str(&self, key: &HeaderName) -> Option<&str> { - self.get(key).map(|v| v.as_str()) + /// Optionally get a header value as a String + pub fn get_optional_string(&self, key: &HeaderName) -> Option { + self.get_string(key).ok() } /// Get a header value as a str or error if it is not found - pub fn get_as_str_or_err(&self, key: &HeaderName) -> crate::Result<&str> { - self.get_or_err(key).map(|v| v.as_str()) + pub fn get_str(&self, key: &HeaderName) -> crate::Result<&str> { + self.get_with(key, |s| crate::Result::Ok(s.as_str())) } - /// Get a header value as a String - pub fn get_as_string(&self, key: &HeaderName) -> Option { - self.get(key).map(|v| v.as_str().to_string()) + /// Optionally get a header value as a str + pub fn get_optional_str(&self, key: &HeaderName) -> Option<&str> { + self.get_str(key).ok() } - /// Get a header value as a String or error if it is not found - pub fn get_as_string_or_err(&self, key: &HeaderName) -> crate::Result { - self.get_or_err(key).map(|v| v.as_str().to_string()) + /// Get a header value parsing it as the type or error if it's not found or it fails to parse + pub fn get_as(&self, key: &HeaderName) -> crate::Result + where + V: FromStr, + E: std::error::Error + Send + Sync + 'static, + { + self.get_with(key, |s| s.as_str().parse()) } + /// Optionally get a header value parsing it as the type or error if it fails to parse pub fn get_optional_as(&self, key: &HeaderName) -> crate::Result> where V: FromStr, E: std::error::Error + Send + Sync + 'static, { - self.get(key) - .map(|v: &HeaderValue| { - let v = v.as_str(); - v.parse::().with_context(ErrorKind::DataConversion, || { - let ty = std::any::type_name::(); - format!("unable to parse header '{key:?}: {v}' into {ty}",) - }) - }) - .transpose() + self.get_optional_with(key, |s| s.as_str().parse()) } - pub fn get_as(&self, key: &HeaderName) -> crate::Result + /// Get a header value using the parser or error if it is not found or fails to parse + pub fn get_with<'a, V, F, E>(&'a self, key: &HeaderName, parser: F) -> crate::Result where - V: FromStr, + F: FnOnce(&'a HeaderValue) -> Result, E: std::error::Error + Send + Sync + 'static, { - self.get_optional_as(key)?.ok_or_else(|| { - Error::with_message(ErrorKind::Other, || { + self.get_optional_with(key, parser)?.ok_or_else(|| { + Error::with_message(ErrorKind::DataConversion, || { format!("header not found {}", key.as_str()) }) }) } + /// Optionally get a header value using the parser or error if it fails to parse + pub fn get_optional_with<'a, V, F, E>( + &'a self, + key: &HeaderName, + parser: F, + ) -> crate::Result> + where + F: FnOnce(&'a HeaderValue) -> Result, + E: std::error::Error + Send + Sync + 'static, + { + self.0 + .get(key) + .map(|v: &HeaderValue| { + parser(v).with_context(ErrorKind::DataConversion, || { + let ty = std::any::type_name::(); + format!("unable to parse header '{key:?}: {v:?}' into {ty}",) + }) + }) + .transpose() + } + /// Insert a header name/value pair pub fn insert(&mut self, key: K, value: V) where diff --git a/sdk/core/src/headers/utilities.rs b/sdk/core/src/headers/utilities.rs index 2766d645b0..2df064f932 100644 --- a/sdk/core/src/headers/utilities.rs +++ b/sdk/core/src/headers/utilities.rs @@ -36,7 +36,7 @@ pub fn request_id_from_headers(headers: &Headers) -> crate::Result { } pub fn client_request_id_from_headers_optional(headers: &Headers) -> Option { - headers.get_as_string(&CLIENT_REQUEST_ID) + headers.get_optional_string(&CLIENT_REQUEST_ID) } pub fn last_modified_from_headers_optional( @@ -57,7 +57,7 @@ pub fn rfc2822_from_headers_mandatory( headers: &Headers, header_name: &HeaderName, ) -> crate::Result> { - let date = headers.get_as_str_or_err(header_name)?; + let date = headers.get_str(header_name)?; utc_date_from_rfc2822(date) } @@ -69,23 +69,23 @@ pub fn utc_date_from_rfc2822(date: &str) -> crate::Result> { pub fn continuation_token_from_headers_optional( headers: &Headers, ) -> crate::Result> { - Ok(headers.get_as_string(&CONTINUATION)) + Ok(headers.get_optional_string(&CONTINUATION)) } pub fn sku_name_from_headers(headers: &Headers) -> crate::Result { - headers.get_as_string_or_err(&SKU_NAME) + headers.get_string(&SKU_NAME) } pub fn account_kind_from_headers(headers: &Headers) -> crate::Result { - headers.get_as_string_or_err(&ACCOUNT_KIND) + headers.get_string(&ACCOUNT_KIND) } pub fn etag_from_headers_optional(headers: &Headers) -> crate::Result> { - Ok(headers.get_as_string(&ETAG)) + Ok(headers.get_optional_string(&ETAG)) } pub fn etag_from_headers(headers: &Headers) -> crate::Result { - headers.get_as_string_or_err(&ETAG) + headers.get_string(&ETAG) } pub fn lease_time_from_headers(headers: &Headers) -> crate::Result { @@ -107,15 +107,15 @@ pub fn sequence_number_from_headers(headers: &Headers) -> crate::Result { } pub fn session_token_from_headers(headers: &Headers) -> crate::Result { - headers.get_as_string_or_err(&SESSION_TOKEN) + headers.get_string(&SESSION_TOKEN) } pub fn server_from_headers(headers: &Headers) -> crate::Result<&str> { - headers.get_as_str_or_err(&SERVER) + headers.get_str(&SERVER) } pub fn version_from_headers(headers: &Headers) -> crate::Result<&str> { - headers.get_as_str_or_err(&VERSION) + headers.get_str(&VERSION) } pub fn request_server_encrypted_from_headers(headers: &Headers) -> crate::Result { @@ -123,7 +123,7 @@ pub fn request_server_encrypted_from_headers(headers: &Headers) -> crate::Result } pub fn content_type_from_headers(headers: &Headers) -> crate::Result<&str> { - headers.get_as_str_or_err(&CONTENT_TYPE) + headers.get_str(&CONTENT_TYPE) } pub fn item_count_from_headers(headers: &Headers) -> crate::Result { diff --git a/sdk/core/src/request_options/next_marker.rs b/sdk/core/src/request_options/next_marker.rs index 4d2d903dd3..8f70369476 100644 --- a/sdk/core/src/request_options/next_marker.rs +++ b/sdk/core/src/request_options/next_marker.rs @@ -32,7 +32,7 @@ impl NextMarker { } pub fn from_header_optional(headers: &Headers) -> crate::Result> { - let header_as_str = headers.get_as_str(&headers::CONTINUATION); + let header_as_str = headers.get_optional_str(&headers::CONTINUATION); Ok(header_as_str .filter(|h| !h.is_empty()) diff --git a/sdk/data_cosmos/src/headers/from_headers.rs b/sdk/data_cosmos/src/headers/from_headers.rs index 4dad311ec0..22e0be15cc 100644 --- a/sdk/data_cosmos/src/headers/from_headers.rs +++ b/sdk/data_cosmos/src/headers/from_headers.rs @@ -24,24 +24,24 @@ pub(crate) fn activity_id_from_headers(headers: &Headers) -> azure_core::Result< } pub(crate) fn content_path_from_headers(headers: &Headers) -> azure_core::Result<&str> { - headers.get_as_str_or_err(&HEADER_CONTENT_PATH) + headers.get_str(&HEADER_CONTENT_PATH) } pub(crate) fn alt_content_path_from_headers(headers: &Headers) -> azure_core::Result<&str> { - headers.get_as_str_or_err(&HEADER_ALT_CONTENT_PATH) + headers.get_str(&HEADER_ALT_CONTENT_PATH) } pub(crate) fn resource_quota_from_headers( headers: &Headers, ) -> azure_core::Result> { - let s = headers.get_as_str_or_err(&HEADER_RESOURCE_QUOTA)?; + let s = headers.get_str(&HEADER_RESOURCE_QUOTA)?; resource_quotas_from_str(s) } pub(crate) fn resource_usage_from_headers( headers: &Headers, ) -> azure_core::Result> { - let s = headers.get_as_str_or_err(&HEADER_RESOURCE_USAGE)?; + let s = headers.get_str(&HEADER_RESOURCE_USAGE)?; resource_quotas_from_str(s) } @@ -104,7 +104,7 @@ pub(crate) fn transport_request_id_from_headers(headers: &Headers) -> azure_core } pub(crate) fn global_committed_lsn_from_headers(headers: &Headers) -> azure_core::Result { - let s = headers.get_as_str_or_err(&HEADER_GLOBAL_COMMITTED_LSN)?; + let s = headers.get_str(&HEADER_GLOBAL_COMMITTED_LSN)?; Ok(if s == "-1" { 0 } else { @@ -140,23 +140,23 @@ pub(crate) fn current_replica_set_size_from_headers_optional( } pub(crate) fn schema_version_from_headers(headers: &Headers) -> azure_core::Result<&str> { - headers.get_as_str_or_err(&HEADER_SCHEMA_VERSION) + headers.get_str(&HEADER_SCHEMA_VERSION) } pub(crate) fn server_from_headers(headers: &Headers) -> azure_core::Result<&str> { - headers.get_as_str_or_err(&headers::SERVER) + headers.get_str(&headers::SERVER) } pub(crate) fn service_version_from_headers(headers: &Headers) -> azure_core::Result<&str> { - headers.get_as_str_or_err(&HEADER_SERVICE_VERSION) + headers.get_str(&HEADER_SERVICE_VERSION) } pub(crate) fn content_location_from_headers(headers: &Headers) -> azure_core::Result<&str> { - headers.get_as_str_or_err(&headers::CONTENT_LOCATION) + headers.get_str(&headers::CONTENT_LOCATION) } pub(crate) fn gateway_version_from_headers(headers: &Headers) -> azure_core::Result<&str> { - headers.get_as_str_or_err(&HEADER_GATEWAY_VERSION) + headers.get_str(&HEADER_GATEWAY_VERSION) } pub(crate) fn max_media_storage_usage_mb_from_headers( @@ -173,7 +173,7 @@ fn _date_from_headers( headers: &Headers, header_name: &HeaderName, ) -> azure_core::Result> { - let date = headers.get_as_str_or_err(header_name)?; + let date = headers.get_str(header_name)?; // since Azure returns "GMT" instead of +0000 as timezone we replace it ourselves. // For example: Wed, 15 Jan 2020 23:39:44.369 GMT let date = date.replace("GMT", "+0000"); diff --git a/sdk/data_tables/src/continuation_next_partition_and_row_key.rs b/sdk/data_tables/src/continuation_next_partition_and_row_key.rs index 96f6aeaa86..99ddbe447c 100644 --- a/sdk/data_tables/src/continuation_next_partition_and_row_key.rs +++ b/sdk/data_tables/src/continuation_next_partition_and_row_key.rs @@ -19,12 +19,12 @@ impl ContinuationNextPartitionAndRowKey { } pub fn from_header_optional(headers: &Headers) -> azure_core::Result> { - let partition_header_as_str = headers.get_as_str(&HeaderName::from_static( + let partition_header_as_str = headers.get_optional_str(&HeaderName::from_static( "x-ms-continuation-NextPartitionKey", )); let row_header_as_str = - headers.get_as_str(&HeaderName::from_static("x-ms-continuation-NextRowKey")); + headers.get_optional_str(&HeaderName::from_static("x-ms-continuation-NextRowKey")); Ok(partition_header_as_str.filter(|h| !h.is_empty()).map(|h| { ContinuationNextPartitionAndRowKey::new( diff --git a/sdk/data_tables/src/continuation_next_table_name.rs b/sdk/data_tables/src/continuation_next_table_name.rs index 1fcb6043c9..6514c6c59b 100644 --- a/sdk/data_tables/src/continuation_next_table_name.rs +++ b/sdk/data_tables/src/continuation_next_table_name.rs @@ -17,7 +17,7 @@ impl ContinuationNextTableName { pub fn from_header_optional(headers: &Headers) -> azure_core::Result> { let header_as_str = - headers.get_as_str(&HeaderName::from_static("x-ms-continuation-NextTableName")); + headers.get_optional_str(&HeaderName::from_static("x-ms-continuation-NextTableName")); Ok(header_as_str .filter(|h| !h.is_empty()) diff --git a/sdk/data_tables/src/responses/insert_entity_response.rs b/sdk/data_tables/src/responses/insert_entity_response.rs index b85628f4e3..0fa2ebdeaa 100644 --- a/sdk/data_tables/src/responses/insert_entity_response.rs +++ b/sdk/data_tables/src/responses/insert_entity_response.rs @@ -29,7 +29,7 @@ where fn try_from(response: CollectedResponse) -> azure_core::Result { let headers = response.headers(); let entity_with_metadata = - match headers.get_as_str_or_err(&HeaderName::from_static("preference-applied"))? { + match headers.get_str(&HeaderName::from_static("preference-applied"))? { "return-no-content" => None, "return-content" => Some(response.clone().try_into()?), _ => { diff --git a/sdk/iot_hub/src/service/responses/query_response.rs b/sdk/iot_hub/src/service/responses/query_response.rs index e0bacbfcd0..33b43660d0 100644 --- a/sdk/iot_hub/src/service/responses/query_response.rs +++ b/sdk/iot_hub/src/service/responses/query_response.rs @@ -22,7 +22,7 @@ impl std::convert::TryFrom for QueryResponse Ok(QueryResponse { result: serde_json::from_slice(body)?, continuation_token: continuation_token_from_headers_optional(headers)?, - item_type: headers.get_as_string_or_err(&headers::ITEM_TYPE)?, + item_type: headers.get_string(&headers::ITEM_TYPE)?, }) } } diff --git a/sdk/messaging_servicebus/src/service_bus/mod.rs b/sdk/messaging_servicebus/src/service_bus/mod.rs index 1105b12029..b3e412ff0d 100644 --- a/sdk/messaging_servicebus/src/service_bus/mod.rs +++ b/sdk/messaging_servicebus/src/service_bus/mod.rs @@ -173,7 +173,7 @@ async fn peek_lock_message2( let status = res.status(); let lock_location = res .headers() - .get_as_string(&headers::LOCATION) + .get_optional_string(&headers::LOCATION) .unwrap_or_default(); let body = body_bytes_to_utf8(&res.into_body().await)?; diff --git a/sdk/storage/src/account/operations/find_blobs_by_tags.rs b/sdk/storage/src/account/operations/find_blobs_by_tags.rs index de623fd243..ad0441b987 100644 --- a/sdk/storage/src/account/operations/find_blobs_by_tags.rs +++ b/sdk/storage/src/account/operations/find_blobs_by_tags.rs @@ -33,6 +33,7 @@ impl FindBlobsByTagsBuilder { next_marker: NextMarker => Some(next_marker), max_results: MaxResults => Some(max_results), timeout: Timeout => Some(timeout), + context: Context => context, } // TODO: Make this a stream instead of a `Future` diff --git a/sdk/storage/src/authorization_policy.rs b/sdk/storage/src/authorization_policy.rs index 053cf829e0..cd33520f4a 100644 --- a/sdk/storage/src/authorization_policy.rs +++ b/sdk/storage/src/authorization_policy.rs @@ -91,7 +91,7 @@ fn generate_authorization( } fn add_if_exists<'a>(h: &'a Headers, key: &HeaderName) -> &'a str { - h.get_as_str(key).unwrap_or_default() + h.get_optional_str(key).unwrap_or_default() } #[allow(unknown_lints)] @@ -117,7 +117,7 @@ fn string_to_sign( // content length must only be specified if != 0 // this is valid from 2015-02-21 let content_length = h - .get_as_str(&CONTENT_LENGTH) + .get_optional_str(&CONTENT_LENGTH) .filter(|&v| v != "0") .unwrap_or_default(); format!( @@ -151,7 +151,7 @@ fn canonicalize_header(headers: &Headers) -> String { let mut result = String::new(); for header_name in names { - let value = headers.get_as_str(header_name).unwrap(); + let value = headers.get_optional_str(header_name).unwrap(); let name = header_name.as_str(); result = format!("{result}{name}:{value}\n"); } diff --git a/sdk/storage/src/core/clients/storage_account_client.rs b/sdk/storage/src/core/clients/storage_account_client.rs index 22acf3dd23..f39035886b 100644 --- a/sdk/storage/src/core/clients/storage_account_client.rs +++ b/sdk/storage/src/core/clients/storage_account_client.rs @@ -547,7 +547,7 @@ fn generate_authorization( } fn add_if_exists<'a>(headers: &'a Headers, key: &HeaderName) -> &'a str { - headers.get_as_str(key).unwrap_or_default() + headers.get_optional_str(key).unwrap_or_default() } fn string_to_sign( @@ -572,7 +572,7 @@ fn string_to_sign( // content length must only be specified if != 0 // this is valid from 2015-02-21 let cl = headers - .get_as_str(&CONTENT_LENGTH) + .get_optional_str(&CONTENT_LENGTH) .filter(|&s| s != "0") .unwrap_or_default(); format!( diff --git a/sdk/storage/src/core/headers/mod.rs b/sdk/storage/src/core/headers/mod.rs index de5ed93364..fbac8fa0cc 100644 --- a/sdk/storage/src/core/headers/mod.rs +++ b/sdk/storage/src/core/headers/mod.rs @@ -47,7 +47,7 @@ pub fn content_crc64_from_headers_optional( headers: &Headers, ) -> azure_core::Result> { headers - .get_as_str(&CONTENT_CRC64) + .get_optional_str(&CONTENT_CRC64) .map(|content_crc64| { ConsistencyCRC64::decode(content_crc64).with_context(ErrorKind::DataConversion, || { format!("failed to decode content_crc64 from headers: {content_crc64}") @@ -68,7 +68,7 @@ pub fn content_md5_from_headers_optional( headers: &Headers, ) -> azure_core::Result> { headers - .get_as_str(&headers::CONTENT_MD5) + .get_optional_str(&headers::CONTENT_MD5) .map(|content_md5| { ConsistencyMD5::decode(content_md5).with_context(ErrorKind::DataConversion, || { format!("failed to decode content_md5 from headers: {content_md5}") diff --git a/sdk/storage_blobs/src/blob/mod.rs b/sdk/storage_blobs/src/blob/mod.rs index d00dc8a189..cfb1348147 100644 --- a/sdk/storage_blobs/src/blob/mod.rs +++ b/sdk/storage_blobs/src/blob/mod.rs @@ -197,7 +197,7 @@ impl Blob { ) -> azure_core::Result { #[cfg(not(feature = "azurite_workaround"))] let creation_time = { - let creation_time = h.get_as_str_or_err(&headers::CREATION_TIME)?; + let creation_time = h.get_str(&headers::CREATION_TIME)?; let creation_time = DateTime::parse_from_rfc2822(creation_time).map_kind(ErrorKind::DataConversion)?; DateTime::from_utc(creation_time.naive_utc(), Utc) @@ -206,53 +206,53 @@ impl Blob { let creation_time = get_creation_time(h)?; let content_type = h - .get_as_str(&headers::CONTENT_TYPE) + .get_optional_str(&headers::CONTENT_TYPE) .unwrap_or(content_type::APPLICATION_OCTET_STREAM.as_str()) .to_string(); let content_length = h.get_as(&headers::CONTENT_LENGTH)?; - let last_modified = h.get_as_str_or_err(&headers::LAST_MODIFIED)?; + let last_modified = h.get_str(&headers::LAST_MODIFIED)?; let last_modified = from_azure_time(last_modified)?; - let etag = h.get_as_str_or_err(&headers::ETAG)?.into(); + let etag = h.get_str(&headers::ETAG)?.into(); let blob_sequence_number = h.get_optional_as(&headers::BLOB_SEQUENCE_NUMBER)?; let blob_type = h.get_as(&headers::BLOB_TYPE)?; let access_tier = h.get_optional_as(&headers::BLOB_ACCESS_TIER)?; - let content_encoding = h.get_as_string(&headers::CONTENT_ENCODING); - let content_language = h.get_as_string(&headers::CONTENT_LANGUAGE); + let content_encoding = h.get_optional_string(&headers::CONTENT_ENCODING); + let content_language = h.get_optional_string(&headers::CONTENT_LANGUAGE); let content_md5 = h - .get_as_str(&headers::CONTENT_MD5) + .get_optional_str(&headers::CONTENT_MD5) .map(|header| ConsistencyMD5::decode(header.as_bytes())) .transpose() .map_kind(ErrorKind::DataConversion)?; let content_crc64 = h - .get_as_str(&azure_storage::headers::CONTENT_CRC64) + .get_optional_str(&azure_storage::headers::CONTENT_CRC64) .map(|header| ConsistencyCRC64::decode(header.as_bytes())) .transpose() .map_kind(ErrorKind::DataConversion)?; - let cache_control = h.get_as_string(&headers::CACHE_CONTROL); - let content_disposition = h.get_as_string(&headers::CONTENT_DISPOSITION); + let cache_control = h.get_optional_string(&headers::CACHE_CONTROL); + let content_disposition = h.get_optional_string(&headers::CONTENT_DISPOSITION); let lease_status = h.get_as(&headers::LEASE_STATUS)?; let lease_state = h.get_as(&headers::LEASE_STATE)?; let lease_duration = h.get_optional_as(&headers::LEASE_DURATION)?; let copy_id = h.get_optional_as(&azure_storage::headers::COPY_ID)?; let copy_status = h.get_optional_as(&headers::COPY_STATUS)?; - let copy_source = h.get_as_string(&headers::COPY_SOURCE); + let copy_source = h.get_optional_string(&headers::COPY_SOURCE); let copy_progress = h.get_optional_as(&headers::COPY_PROGRESS)?; let copy_completion_time: Option> = h - .get_as_str(&headers::COPY_COMPLETION_TIME) + .get_optional_str(&headers::COPY_COMPLETION_TIME) .and_then(|cct| { Some(DateTime::from_utc( DateTime::parse_from_rfc2822(cct).ok()?.naive_utc(), Utc, )) }); - let copy_status_description = h.get_as_string(&headers::COPY_STATUS_DESCRIPTION); + let copy_status_description = h.get_optional_string(&headers::COPY_STATUS_DESCRIPTION); let server_encrypted = h.get_as(&headers::SERVER_ENCRYPTED)?; let mut metadata = HashMap::new(); diff --git a/sdk/storage_blobs/src/container/mod.rs b/sdk/storage_blobs/src/container/mod.rs index 03646f5bea..8a2616aa77 100644 --- a/sdk/storage_blobs/src/container/mod.rs +++ b/sdk/storage_blobs/src/container/mod.rs @@ -85,12 +85,12 @@ impl Container { where NAME: Into, { - let last_modified = headers.get_as_str_or_err(&headers::LAST_MODIFIED)?; + let last_modified = headers.get_str(&headers::LAST_MODIFIED)?; let last_modified = DateTime::parse_from_rfc2822(last_modified).map_kind(ErrorKind::DataConversion)?; let last_modified = DateTime::from_utc(last_modified.naive_utc(), Utc); - let e_tag = headers.get_as_string_or_err(&headers::ETAG)?; + let e_tag = headers.get_string(&headers::ETAG)?; let lease_status = headers.get_as(&LEASE_STATUS)?; let lease_state = headers.get_as(&LEASE_STATE)?; diff --git a/sdk/storage_blobs/src/container/operations/get_acl.rs b/sdk/storage_blobs/src/container/operations/get_acl.rs index dfff0fd8ec..54bd36a997 100644 --- a/sdk/storage_blobs/src/container/operations/get_acl.rs +++ b/sdk/storage_blobs/src/container/operations/get_acl.rs @@ -76,15 +76,15 @@ impl GetACLResponse { // todo: parse SAS policies let public_access = public_access_from_header(&headers)?; - let etag = headers.get_as_string_or_err(&headers::ETAG)?; + let etag = headers.get_string(&headers::ETAG)?; - let last_modified = headers.get_as_str_or_err(&headers::LAST_MODIFIED)?; + let last_modified = headers.get_str(&headers::LAST_MODIFIED)?; let last_modified = DateTime::parse_from_rfc2822(last_modified).map_kind(ErrorKind::DataConversion)?; let request_id = headers.get_as(&headers::REQUEST_ID)?; - let date = headers.get_as_str_or_err(&headers::DATE)?; + let date = headers.get_str(&headers::DATE)?; let date = DateTime::parse_from_rfc2822(date).map_kind(ErrorKind::DataConversion)?; let stored_access_policy_list = StoredAccessPolicyList::from_xml(&body)?; diff --git a/sdk/storage_blobs/src/container/operations/get_properties.rs b/sdk/storage_blobs/src/container/operations/get_properties.rs index a8a1db7a09..904d004d4b 100644 --- a/sdk/storage_blobs/src/container/operations/get_properties.rs +++ b/sdk/storage_blobs/src/container/operations/get_properties.rs @@ -75,7 +75,7 @@ impl GetPropertiesResponse { ) -> azure_core::Result { let request_id = headers.get_as(&headers::REQUEST_ID)?; - let date = DateTime::parse_from_rfc2822(headers.get_as_str_or_err(&headers::DATE)?) + let date = DateTime::parse_from_rfc2822(headers.get_str(&headers::DATE)?) .map_kind(ErrorKind::DataConversion)?; let container = Container::from_response(container_name, headers)?; diff --git a/sdk/storage_datalake/src/authorization_policies/shared_key.rs b/sdk/storage_datalake/src/authorization_policies/shared_key.rs index a84abeac09..370c2e9f5d 100644 --- a/sdk/storage_datalake/src/authorization_policies/shared_key.rs +++ b/sdk/storage_datalake/src/authorization_policies/shared_key.rs @@ -84,7 +84,7 @@ fn string_to_sign( // content length must only be specified if != 0 // this is valid from 2015-02-21 let cl = http_headers - .get_as_str(&headers::CONTENT_LENGTH) + .get_optional_str(&headers::CONTENT_LENGTH) .filter(|&s| s != "0") .unwrap_or_default(); format!( @@ -127,7 +127,7 @@ fn string_to_sign( } fn add_if_exists<'a>(h: &'a Headers, key: &HeaderName) -> &'a str { - h.get_as_str(key).unwrap_or_default() + h.get_optional_str(key).unwrap_or_default() } fn canonicalize_header(headers: &Headers) -> String { @@ -140,7 +140,7 @@ fn canonicalize_header(headers: &Headers) -> String { let mut result = String::new(); for name in names { - let value = headers.get_as_str(name).unwrap(); + let value = headers.get_optional_str(name).unwrap(); result = result + name.as_str() + ":" + value + "\n"; } result diff --git a/sdk/storage_datalake/src/operations/path_head.rs b/sdk/storage_datalake/src/operations/path_head.rs index b8aff8a57c..8a84435466 100644 --- a/sdk/storage_datalake/src/operations/path_head.rs +++ b/sdk/storage_datalake/src/operations/path_head.rs @@ -102,10 +102,10 @@ impl HeadPathResponse { content_length: headers.get_optional_as(&headers::CONTENT_LENGTH)?, content_type: headers.get_optional_as(&headers::CONTENT_TYPE)?, properties: headers - .get_as_str(&headers::PROPERTIES) + .get_optional_str(&headers::PROPERTIES) .map(Properties::try_from) .transpose()?, - acl: headers.get_as_string(&headers::ACL), + acl: headers.get_optional_string(&headers::ACL), }) } } diff --git a/sdk/storage_datalake/src/properties.rs b/sdk/storage_datalake/src/properties.rs index d303efdde7..445e1ee343 100644 --- a/sdk/storage_datalake/src/properties.rs +++ b/sdk/storage_datalake/src/properties.rs @@ -53,7 +53,7 @@ impl TryFrom<&Headers> for Properties { type Error = crate::Error; fn try_from(headers: &Headers) -> Result { - let header_value = headers.get_as_str_or_err(&PROPERTIES)?; + let header_value = headers.get_str(&PROPERTIES)?; Properties::try_from(header_value) } } diff --git a/sdk/storage_queues/src/operations/update_message.rs b/sdk/storage_queues/src/operations/update_message.rs index 7e0f3cf7c5..e2a079ea01 100644 --- a/sdk/storage_queues/src/operations/update_message.rs +++ b/sdk/storage_queues/src/operations/update_message.rs @@ -97,8 +97,7 @@ impl std::convert::TryFrom for UpdateMessageResponse { headers, &HeaderName::from_static("x-ms-time-next-visible"), )?, - pop_receipt: headers - .get_as_string_or_err(&HeaderName::from_static("x-ms-popreceipt"))?, + pop_receipt: headers.get_string(&HeaderName::from_static("x-ms-popreceipt"))?, }) } } From 307aed492c1439bd6658559085998e5d39afd0c7 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Tue, 28 Jun 2022 12:07:29 +0200 Subject: [PATCH 2/2] Parse more headers --- sdk/core/src/models/etag.rs | 9 +++++++- sdk/storage/src/core/headers/mod.rs | 36 ++++++----------------------- sdk/storage/src/core/mod.rs | 20 +++++++++++++--- sdk/storage_blobs/src/blob/mod.rs | 25 ++++---------------- 4 files changed, 37 insertions(+), 53 deletions(-) diff --git a/sdk/core/src/models/etag.rs b/sdk/core/src/models/etag.rs index f9dabec255..50dfce7ebb 100644 --- a/sdk/core/src/models/etag.rs +++ b/sdk/core/src/models/etag.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use std::fmt; +use std::{fmt, str::FromStr}; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Etag(String); @@ -19,6 +19,13 @@ impl AsRef for Etag { } } +impl FromStr for Etag { + type Err = crate::error::Error; + fn from_str(s: &str) -> crate::Result { + Ok(Self(s.into())) + } +} + impl fmt::Display for Etag { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) diff --git a/sdk/storage/src/core/headers/mod.rs b/sdk/storage/src/core/headers/mod.rs index fbac8fa0cc..f181ea1b47 100644 --- a/sdk/storage/src/core/headers/mod.rs +++ b/sdk/storage/src/core/headers/mod.rs @@ -1,8 +1,8 @@ use crate::{ConsistencyCRC64, ConsistencyMD5}; -use azure_core::error::{Error, ErrorKind, ResultExt}; +use azure_core::error::Error; use azure_core::headers::{ - self, client_request_id_from_headers_optional, date_from_headers, request_id_from_headers, - server_from_headers, version_from_headers, HeaderName, Headers, + client_request_id_from_headers_optional, date_from_headers, request_id_from_headers, + server_from_headers, version_from_headers, HeaderName, Headers, CONTENT_MD5, }; use azure_core::RequestId; use chrono::{DateTime, Utc}; @@ -36,45 +36,23 @@ pub const COPY_ID: HeaderName = HeaderName::from_static("x-ms-copy-id"); pub const RENAME_SOURCE: HeaderName = HeaderName::from_static("x-ms-rename-source"); pub fn content_crc64_from_headers(headers: &Headers) -> azure_core::Result { - content_crc64_from_headers_optional(headers)?.ok_or_else(|| { - Error::with_message(ErrorKind::DataConversion, || { - format!("header not found: {:?}", CONTENT_CRC64) - }) - }) + headers.get_as(&CONTENT_CRC64) } pub fn content_crc64_from_headers_optional( headers: &Headers, ) -> azure_core::Result> { - headers - .get_optional_str(&CONTENT_CRC64) - .map(|content_crc64| { - ConsistencyCRC64::decode(content_crc64).with_context(ErrorKind::DataConversion, || { - format!("failed to decode content_crc64 from headers: {content_crc64}") - }) - }) - .transpose() + headers.get_optional_as(&CONTENT_CRC64) } pub fn content_md5_from_headers(headers: &Headers) -> azure_core::Result { - content_md5_from_headers_optional(headers)?.ok_or_else(|| { - Error::with_message(ErrorKind::DataConversion, || { - format!("header not found: {:?}", headers::CONTENT_MD5) - }) - }) + headers.get_as(&CONTENT_MD5) } pub fn content_md5_from_headers_optional( headers: &Headers, ) -> azure_core::Result> { - headers - .get_optional_str(&headers::CONTENT_MD5) - .map(|content_md5| { - ConsistencyMD5::decode(content_md5).with_context(ErrorKind::DataConversion, || { - format!("failed to decode content_md5 from headers: {content_md5}") - }) - }) - .transpose() + headers.get_optional_as(&CONTENT_MD5) } pub fn consistency_from_headers( diff --git a/sdk/storage/src/core/mod.rs b/sdk/storage/src/core/mod.rs index 5ff5739c62..a1d0c1c237 100644 --- a/sdk/storage/src/core/mod.rs +++ b/sdk/storage/src/core/mod.rs @@ -50,7 +50,7 @@ mod consistency { use azure_core::error::{Error, ErrorKind, ResultExt}; use bytes::Bytes; use serde::{Deserialize, Deserializer}; - use std::convert::TryInto; + use std::{convert::TryInto, str::FromStr}; #[derive(Debug, Clone, PartialEq)] pub struct ConsistencyCRC64(Bytes); @@ -99,13 +99,19 @@ mod consistency { } } + impl FromStr for ConsistencyCRC64 { + type Err = azure_core::error::Error; + + fn from_str(s: &str) -> Result { + Self::decode(s) + } + } + #[derive(Debug, Clone, PartialEq)] pub struct ConsistencyMD5(Bytes); const MD5_BYTE_LENGTH: usize = 16; - impl ConsistencyMD5 {} - impl ConsistencyMD5 { /// Decodes from base64 encoded input pub fn decode(input: impl AsRef<[u8]>) -> azure_core::Result { @@ -146,6 +152,14 @@ mod consistency { } } + impl FromStr for ConsistencyMD5 { + type Err = azure_core::error::Error; + + fn from_str(s: &str) -> Result { + Self::decode(s) + } + } + #[cfg(test)] mod test { use super::*; diff --git a/sdk/storage_blobs/src/blob/mod.rs b/sdk/storage_blobs/src/blob/mod.rs index cfb1348147..7110e4eed8 100644 --- a/sdk/storage_blobs/src/blob/mod.rs +++ b/sdk/storage_blobs/src/blob/mod.rs @@ -31,7 +31,7 @@ use std::collections::HashMap; #[cfg(feature = "azurite_workaround")] fn get_creation_time(h: &Headers) -> azure_core::Result>> { - if let Some(creation_time) = h.get_as_str(&headers::CREATION_TIME) { + if let Some(creation_time) = h.get_optional_str(&headers::CREATION_TIME) { // Check that the creation time is valid let creation_time = DateTime::parse_from_rfc2822(creation_time).map_kind(ErrorKind::DataConversion)?; @@ -211,30 +211,15 @@ impl Blob { .to_string(); let content_length = h.get_as(&headers::CONTENT_LENGTH)?; - - let last_modified = h.get_str(&headers::LAST_MODIFIED)?; - let last_modified = from_azure_time(last_modified)?; - - let etag = h.get_str(&headers::ETAG)?.into(); - + let last_modified = from_azure_time(h.get_str(&headers::LAST_MODIFIED)?)?; + let etag = h.get_as(&headers::ETAG)?; let blob_sequence_number = h.get_optional_as(&headers::BLOB_SEQUENCE_NUMBER)?; let blob_type = h.get_as(&headers::BLOB_TYPE)?; let access_tier = h.get_optional_as(&headers::BLOB_ACCESS_TIER)?; let content_encoding = h.get_optional_string(&headers::CONTENT_ENCODING); let content_language = h.get_optional_string(&headers::CONTENT_LANGUAGE); - - let content_md5 = h - .get_optional_str(&headers::CONTENT_MD5) - .map(|header| ConsistencyMD5::decode(header.as_bytes())) - .transpose() - .map_kind(ErrorKind::DataConversion)?; - - let content_crc64 = h - .get_optional_str(&azure_storage::headers::CONTENT_CRC64) - .map(|header| ConsistencyCRC64::decode(header.as_bytes())) - .transpose() - .map_kind(ErrorKind::DataConversion)?; - + let content_md5 = h.get_optional_as(&headers::CONTENT_MD5)?; + let content_crc64 = h.get_optional_as(&azure_storage::headers::CONTENT_CRC64)?; let cache_control = h.get_optional_string(&headers::CACHE_CONTROL); let content_disposition = h.get_optional_string(&headers::CONTENT_DISPOSITION); let lease_status = h.get_as(&headers::LEASE_STATUS)?;