Skip to content

Commit cd89ca1

Browse files
authored
migrate SDKs from http::Request to azure_core::Request (#833)
1 parent 99be8f0 commit cd89ca1

File tree

192 files changed

+1438
-2510
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

192 files changed

+1438
-2510
lines changed

sdk/core/src/error/http_error.rs

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@ impl HttpError {
2020
let mut error_code = get_error_code_from_header(&response);
2121
let mut headers = HashMap::new();
2222

23-
for (name, value) in response.headers() {
24-
let value = String::from_utf8_lossy(value.as_bytes()).to_string();
25-
headers.insert(name.to_string(), value);
23+
for (name, value) in response.headers().iter() {
24+
headers.insert(name.as_str().to_string(), value.as_str().to_string());
2625
}
2726

2827
let body = response.into_body().await;
@@ -73,14 +72,7 @@ impl std::error::Error for HttpError {}
7372
///
7473
/// For more info, see [here](https://github.com/microsoft/api-guidelines/blob/vNext/azure/Guidelines.md#handling-errors)
7574
fn get_error_code_from_header(response: &Response) -> Option<String> {
76-
Some(
77-
response
78-
.headers()
79-
.get(http::header::HeaderName::from_static("x-ms-error-code"))?
80-
.to_str()
81-
.ok()?
82-
.to_owned(),
83-
)
75+
response.headers().get_as_string("x-ms-error-code")
8476
}
8577

8678
/// Gets the error code if it's present in the body

sdk/core/src/headers/mod.rs

Lines changed: 82 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
//! Azure HTTP headers.
22
mod utilities;
33

4+
use crate::error::{Error, ErrorKind, ResultExt};
5+
use std::{collections::HashMap, fmt::Debug, str::FromStr};
46
pub use utilities::*;
57

6-
use http::request::Builder;
7-
use std::collections::HashMap;
8-
98
/// A trait for converting a type into request headers
109
pub trait AsHeaders {
1110
type Iter: Iterator<Item = (HeaderName, HeaderValue)>;
@@ -52,7 +51,7 @@ pub trait Header {
5251
}
5352

5453
/// A collection of headers
55-
#[derive(Clone, Debug)]
54+
#[derive(Clone, Debug, PartialEq)]
5655
pub struct Headers(std::collections::HashMap<HeaderName, HeaderValue>);
5756

5857
impl Headers {
@@ -65,6 +64,80 @@ impl Headers {
6564
self.0.get(&key.into())
6665
}
6766

67+
/// Get a header value or error if it is not found
68+
pub fn get_or_err<T: Into<HeaderName>>(&self, key: T) -> crate::Result<&HeaderValue> {
69+
let key: &HeaderName = &key.into();
70+
let value = self.0.get(key);
71+
value.ok_or_else(|| {
72+
Error::with_message(ErrorKind::Other, || {
73+
format!("header not found {}", key.as_str())
74+
})
75+
})
76+
}
77+
78+
/// Get a header value as a str
79+
pub fn get_as_str<T: Into<HeaderName>>(&self, key: T) -> Option<&str> {
80+
self.get(key).map(|v| v.as_str())
81+
}
82+
83+
/// Get a header value as a str or error if it is not found
84+
pub fn get_as_str_or_err<T: Into<HeaderName>>(&self, key: T) -> crate::Result<&str> {
85+
self.get_or_err(key).map(|v| v.as_str())
86+
}
87+
88+
/// Get a header value as a String
89+
pub fn get_as_string<T: Into<HeaderName>>(&self, key: T) -> Option<String> {
90+
self.get(key).map(|v| v.as_str().to_string())
91+
}
92+
93+
/// Get a header value as a String or error if it is not found
94+
pub fn get_as_string_or_err<T: Into<HeaderName>>(&self, key: T) -> crate::Result<String> {
95+
self.get_or_err(key).map(|v| v.as_str().to_string())
96+
}
97+
98+
/// Get a header value as a u64
99+
pub fn get_as_u64<T: Into<HeaderName>>(&self, key: T) -> crate::Result<Option<u64>> {
100+
let key = key.into();
101+
self.get(key.clone())
102+
.map(|v: &HeaderValue| {
103+
let v = v.as_str();
104+
v.parse::<u64>()
105+
.with_context(ErrorKind::DataConversion, || {
106+
format!("unable to parse header into u64 {key:?}: {v}")
107+
})
108+
})
109+
.transpose()
110+
}
111+
112+
/// Get a header value as a u64 or error if it is not found
113+
pub fn get_as_u64_or_err<T: Into<HeaderName>>(&self, key: T) -> crate::Result<u64> {
114+
let key = key.into();
115+
let v = self.get_or_err(key.clone())?;
116+
let v = v.as_str();
117+
v.parse::<u64>()
118+
.with_context(ErrorKind::DataConversion, || {
119+
format!("unable to parse header into u64 {key:?}: {v}")
120+
})
121+
}
122+
123+
pub fn get_as_enum<T: Into<HeaderName>, V: FromStr<Err = E>, E>(
124+
&self,
125+
key: T,
126+
) -> crate::Result<Option<V>>
127+
where
128+
E: std::error::Error + Send + Sync + 'static,
129+
{
130+
let key = key.into();
131+
self.get(key.clone())
132+
.map(|v: &HeaderValue| {
133+
let v = v.as_str();
134+
v.parse::<V>().with_context(ErrorKind::DataConversion, || {
135+
format!("unable to parse header into enum {key:?}: {v}")
136+
})
137+
})
138+
.transpose()
139+
}
140+
68141
/// Insert a header name/value pair
69142
pub fn insert<K, V>(&mut self, key: K, value: V)
70143
where
@@ -96,16 +169,16 @@ impl From<std::collections::HashMap<HeaderName, HeaderValue>> for Headers {
96169
}
97170
}
98171

99-
impl From<http::HeaderMap> for Headers {
100-
fn from(map: http::HeaderMap) -> Self {
172+
impl From<&http::HeaderMap> for Headers {
173+
fn from(map: &http::HeaderMap) -> Self {
101174
let map = map
102175
.into_iter()
103-
.filter_map(|(k, v)| {
104-
let key = k?.as_str().to_owned();
176+
.map(|(k, v)| {
177+
let key = k.as_str().to_owned();
105178
let value = std::str::from_utf8(v.as_bytes())
106179
.expect("non-UTF8 header value")
107180
.to_owned();
108-
Some((key.into(), value.into()))
181+
(key.into(), value.into())
109182
})
110183
.collect::<HashMap<HeaderName, HeaderValue>>();
111184
Self(map)
@@ -188,27 +261,6 @@ impl From<&HeaderValue> for http::header::HeaderValue {
188261
}
189262
}
190263

191-
#[must_use]
192-
pub fn add_optional_header_ref<T: Header>(item: &Option<&T>, mut builder: Builder) -> Builder {
193-
if let Some(item) = item {
194-
builder = builder.header(item.name().as_str(), item.value().as_str())
195-
}
196-
builder
197-
}
198-
199-
#[must_use]
200-
pub fn add_optional_header<T: Header>(item: &Option<T>, mut builder: Builder) -> Builder {
201-
if let Some(item) = item {
202-
builder = builder.header(item.name().as_str(), item.value().as_str())
203-
}
204-
builder
205-
}
206-
207-
#[must_use]
208-
pub fn add_mandatory_header<T: Header>(item: &T, builder: Builder) -> Builder {
209-
builder.header(item.name().as_str(), item.value().as_str())
210-
}
211-
212264
// headers are case insensitive
213265
// we are using all lowercase values
214266
// same as https://github.com/hyperium/http/blob/master/util/src/main.rs

sdk/core/src/headers/utilities.rs

Lines changed: 28 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,35 +5,28 @@ use crate::{RequestId, SessionToken};
55

66
use chrono::{DateTime, FixedOffset, Utc};
77
use http::header::{DATE, ETAG, LAST_MODIFIED, SERVER};
8-
use http::HeaderMap;
98
use std::str::FromStr;
109

1110
pub fn get_option_str_from_headers<'a>(
12-
headers: &'a HeaderMap,
11+
headers: &'a Headers,
1312
key: &str,
1413
) -> crate::Result<Option<&'a str>> {
15-
let h = match headers.get(key) {
14+
let h = match headers.get(key.to_owned()) {
1615
Some(h) => h,
1716
None => return Ok(None),
1817
};
19-
Ok(Some(h.to_str().map_err(|e| {
20-
Error::full(
21-
ErrorKind::DataConversion,
22-
e,
23-
format!("could not convert header '{key}' to string"),
24-
)
25-
})?))
18+
Ok(Some(h.as_str()))
2619
}
2720

28-
pub fn get_str_from_headers<'a>(headers: &'a HeaderMap, key: &str) -> crate::Result<&'a str> {
21+
pub fn get_str_from_headers<'a>(headers: &'a Headers, key: &str) -> crate::Result<&'a str> {
2922
get_option_str_from_headers(headers, key)?.ok_or_else(|| {
3023
Error::with_message(ErrorKind::DataConversion, || {
3124
format!("could not find '{key}' in headers")
3225
})
3326
})
3427
}
3528

36-
pub fn get_option_from_headers<T>(headers: &HeaderMap, key: &str) -> crate::Result<Option<T>>
29+
pub fn get_option_from_headers<T>(headers: &Headers, key: &str) -> crate::Result<Option<T>>
3730
where
3831
T: std::str::FromStr + 'static,
3932
T::Err: std::error::Error + Send + Sync,
@@ -56,7 +49,7 @@ where
5649
})?))
5750
}
5851

59-
pub fn get_from_headers<T>(headers: &HeaderMap, key: &str) -> crate::Result<T>
52+
pub fn get_from_headers<T>(headers: &Headers, key: &str) -> crate::Result<T>
6053
where
6154
T: std::str::FromStr + 'static,
6255
T::Err: std::error::Error + Send + Sync,
@@ -110,36 +103,36 @@ where
110103
})
111104
}
112105

113-
pub fn lease_id_from_headers(headers: &HeaderMap) -> crate::Result<LeaseId> {
106+
pub fn lease_id_from_headers(headers: &Headers) -> crate::Result<LeaseId> {
114107
get_from_headers(headers, LEASE_ID)
115108
}
116109

117-
pub fn request_id_from_headers(headers: &HeaderMap) -> crate::Result<RequestId> {
110+
pub fn request_id_from_headers(headers: &Headers) -> crate::Result<RequestId> {
118111
get_from_headers(headers, REQUEST_ID)
119112
}
120113

121-
pub fn client_request_id_from_headers_optional(headers: &HeaderMap) -> Option<String> {
114+
pub fn client_request_id_from_headers_optional(headers: &Headers) -> Option<String> {
122115
get_option_from_headers(headers, CLIENT_REQUEST_ID)
123116
.ok()
124117
.flatten()
125118
}
126119

127120
pub fn last_modified_from_headers_optional(
128-
headers: &HeaderMap,
121+
headers: &Headers,
129122
) -> crate::Result<Option<DateTime<Utc>>> {
130123
get_option_from_headers(headers, LAST_MODIFIED.as_str())
131124
}
132125

133-
pub fn date_from_headers(headers: &HeaderMap) -> crate::Result<DateTime<Utc>> {
126+
pub fn date_from_headers(headers: &Headers) -> crate::Result<DateTime<Utc>> {
134127
rfc2822_from_headers_mandatory(headers, DATE.as_str())
135128
}
136129

137-
pub fn last_modified_from_headers(headers: &HeaderMap) -> crate::Result<DateTime<Utc>> {
130+
pub fn last_modified_from_headers(headers: &Headers) -> crate::Result<DateTime<Utc>> {
138131
rfc2822_from_headers_mandatory(headers, LAST_MODIFIED.as_str())
139132
}
140133

141134
pub fn rfc2822_from_headers_mandatory(
142-
headers: &HeaderMap,
135+
headers: &Headers,
143136
header_name: &str,
144137
) -> crate::Result<DateTime<Utc>> {
145138
let date = get_str_from_headers(headers, header_name)?;
@@ -152,65 +145,65 @@ pub fn utc_date_from_rfc2822(date: &str) -> crate::Result<DateTime<Utc>> {
152145
}
153146

154147
pub fn continuation_token_from_headers_optional(
155-
headers: &HeaderMap,
148+
headers: &Headers,
156149
) -> crate::Result<Option<String>> {
157150
Ok(get_option_str_from_headers(headers, CONTINUATION)?.map(String::from))
158151
}
159152

160-
pub fn sku_name_from_headers(headers: &HeaderMap) -> crate::Result<String> {
153+
pub fn sku_name_from_headers(headers: &Headers) -> crate::Result<String> {
161154
Ok(get_str_from_headers(headers, SKU_NAME)?.to_owned())
162155
}
163156

164-
pub fn account_kind_from_headers(headers: &HeaderMap) -> crate::Result<String> {
157+
pub fn account_kind_from_headers(headers: &Headers) -> crate::Result<String> {
165158
Ok(get_str_from_headers(headers, ACCOUNT_KIND)?.to_owned())
166159
}
167160

168-
pub fn etag_from_headers_optional(headers: &HeaderMap) -> crate::Result<Option<String>> {
161+
pub fn etag_from_headers_optional(headers: &Headers) -> crate::Result<Option<String>> {
169162
Ok(get_option_str_from_headers(headers, ETAG.as_str())?.map(String::from))
170163
}
171164

172-
pub fn etag_from_headers(headers: &HeaderMap) -> crate::Result<String> {
165+
pub fn etag_from_headers(headers: &Headers) -> crate::Result<String> {
173166
Ok(get_str_from_headers(headers, ETAG.as_str())?.to_owned())
174167
}
175168

176-
pub fn lease_time_from_headers(headers: &HeaderMap) -> crate::Result<u8> {
169+
pub fn lease_time_from_headers(headers: &Headers) -> crate::Result<u8> {
177170
get_from_headers(headers, LEASE_TIME)
178171
}
179172

180173
#[cfg(not(feature = "azurite_workaround"))]
181-
pub fn delete_type_permanent_from_headers(headers: &HeaderMap) -> crate::Result<bool> {
174+
pub fn delete_type_permanent_from_headers(headers: &Headers) -> crate::Result<bool> {
182175
get_from_headers(headers, DELETE_TYPE_PERMANENT)
183176
}
184177

185178
#[cfg(feature = "azurite_workaround")]
186-
pub fn delete_type_permanent_from_headers(headers: &HeaderMap) -> crate::Result<Option<bool>> {
179+
pub fn delete_type_permanent_from_headers(headers: &Headers) -> crate::Result<Option<bool>> {
187180
get_option_from_headers(headers, DELETE_TYPE_PERMANENT)
188181
}
189182

190-
pub fn sequence_number_from_headers(headers: &HeaderMap) -> crate::Result<u64> {
183+
pub fn sequence_number_from_headers(headers: &Headers) -> crate::Result<u64> {
191184
get_from_headers(headers, BLOB_SEQUENCE_NUMBER)
192185
}
193186

194-
pub fn session_token_from_headers(headers: &HeaderMap) -> crate::Result<SessionToken> {
187+
pub fn session_token_from_headers(headers: &Headers) -> crate::Result<SessionToken> {
195188
get_str_from_headers(headers, SESSION_TOKEN).map(ToOwned::to_owned)
196189
}
197190

198-
pub fn server_from_headers(headers: &HeaderMap) -> crate::Result<&str> {
191+
pub fn server_from_headers(headers: &Headers) -> crate::Result<&str> {
199192
get_str_from_headers(headers, SERVER.as_str())
200193
}
201194

202-
pub fn version_from_headers(headers: &HeaderMap) -> crate::Result<&str> {
195+
pub fn version_from_headers(headers: &Headers) -> crate::Result<&str> {
203196
get_str_from_headers(headers, VERSION)
204197
}
205198

206-
pub fn request_server_encrypted_from_headers(headers: &HeaderMap) -> crate::Result<bool> {
199+
pub fn request_server_encrypted_from_headers(headers: &Headers) -> crate::Result<bool> {
207200
get_from_headers(headers, REQUEST_SERVER_ENCRYPTED)
208201
}
209202

210-
pub fn content_type_from_headers(headers: &HeaderMap) -> crate::Result<&str> {
203+
pub fn content_type_from_headers(headers: &Headers) -> crate::Result<&str> {
211204
get_str_from_headers(headers, http::header::CONTENT_TYPE.as_str())
212205
}
213206

214-
pub fn item_count_from_headers(headers: &HeaderMap) -> crate::Result<u32> {
207+
pub fn item_count_from_headers(headers: &Headers) -> crate::Result<u32> {
215208
get_from_headers(headers, ITEM_COUNT)
216209
}

0 commit comments

Comments
 (0)