Skip to content

Commit aa06684

Browse files
committed
Make HeaderValue public
Signed-off-by: Ryan Levick <[email protected]>
1 parent b363229 commit aa06684

File tree

1 file changed

+79
-55
lines changed

1 file changed

+79
-55
lines changed

sdk/rust/src/http.rs

Lines changed: 79 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,75 @@ pub struct Request {
2828
body: Vec<u8>,
2929
}
3030

31-
enum HeaderValue {
31+
/// A header value.
32+
///
33+
/// Since header values do not have to be valid utf8, this allows for
34+
/// both utf8 strings and bags of bytes.
35+
#[derive(Debug, PartialEq, Eq, Clone)]
36+
pub struct HeaderValue {
37+
inner: HeaderValueRep,
38+
}
39+
40+
#[derive(Debug, PartialEq, Eq, Clone)]
41+
enum HeaderValueRep {
42+
/// Header value encoded as a utf8 string
3243
String(String),
44+
/// Header value as a bag of bytes
3345
Bytes(Vec<u8>),
3446
}
3547

3648
impl HeaderValue {
49+
/// Construct a `HeaderValue` from a string
50+
pub fn string(str: String) -> HeaderValue {
51+
HeaderValue {
52+
inner: HeaderValueRep::String(str),
53+
}
54+
}
55+
56+
/// Construct a `HeaderValue` from a bag of bytes
57+
pub fn bytes(bytes: Vec<u8>) -> HeaderValue {
58+
HeaderValue {
59+
inner: HeaderValueRep::Bytes(bytes),
60+
}
61+
}
62+
63+
/// Get the `HeaderValue` as a utf8 encoded string
64+
///
65+
/// Returns `None` if the value is a non utf8 encoded header value
66+
pub fn as_str(&self) -> Option<&str> {
67+
match &self.inner {
68+
HeaderValueRep::String(s) => Some(s),
69+
HeaderValueRep::Bytes(_) => None,
70+
}
71+
}
72+
73+
/// Get the `HeaderValue` as bytes
74+
pub fn as_bytes(&self) -> &[u8] {
75+
self.as_ref()
76+
}
77+
78+
/// Turn the `HeaderValue` into a String (in a lossy way if the `HeaderValue` is a bag of bytes)
79+
pub fn into_utf8_lossy(self) -> String {
80+
match self.inner {
81+
HeaderValueRep::String(s) => s,
82+
HeaderValueRep::Bytes(b) => String::from_utf8_lossy(&b).into_owned(),
83+
}
84+
}
85+
3786
/// Turn the `HeaderValue` into bytes
38-
fn into_bytes(self) -> Vec<u8> {
39-
match self {
40-
HeaderValue::String(s) => s.into_bytes(),
41-
HeaderValue::Bytes(b) => b,
87+
pub fn into_bytes(self) -> Vec<u8> {
88+
match self.inner {
89+
HeaderValueRep::String(s) => s.into_bytes(),
90+
HeaderValueRep::Bytes(b) => b,
91+
}
92+
}
93+
}
94+
95+
impl AsRef<[u8]> for HeaderValue {
96+
fn as_ref(&self) -> &[u8] {
97+
match &self.inner {
98+
HeaderValueRep::String(s) => s.as_bytes(),
99+
HeaderValueRep::Bytes(b) => b,
42100
}
43101
}
44102
}
@@ -78,33 +136,15 @@ impl Request {
78136
}
79137

80138
/// The request headers
81-
///
82-
/// This only returns headers that are utf8 encoded
83-
pub fn headers(&self) -> impl Iterator<Item = (&str, &str)> {
84-
self.headers.iter().filter_map(|(k, v)| match v {
85-
HeaderValue::String(v) => Some((k.as_str(), v.as_str())),
86-
HeaderValue::Bytes(_) => None,
87-
})
139+
pub fn headers(&self) -> impl Iterator<Item = (&str, &HeaderValue)> {
140+
self.headers.iter().map(|(k, v)| (k.as_str(), v))
88141
}
89142

90143
/// Return a header value
91144
///
92-
/// Will return `None` if the header does not exist or if it is not utf8
93-
pub fn header(&self, name: &str) -> Option<&str> {
94-
self.headers
95-
.get(&name.to_lowercase())
96-
.and_then(|v| match v {
97-
HeaderValue::String(s) => Some(s.as_str()),
98-
HeaderValue::Bytes(_) => None,
99-
})
100-
}
101-
102-
/// The request headers as bytes
103-
pub fn headers_raw(&self) -> impl Iterator<Item = (&str, &[u8])> {
104-
self.headers.iter().map(|(k, v)| match v {
105-
HeaderValue::String(v) => (k.as_str(), v.as_bytes()),
106-
HeaderValue::Bytes(v) => (k.as_str(), v.as_slice()),
107-
})
145+
/// Will return `None` if the header does not exist.
146+
pub fn header(&self, name: &str) -> Option<&HeaderValue> {
147+
self.headers.get(&name.to_lowercase())
108148
}
109149

110150
/// The request body
@@ -172,7 +212,7 @@ impl RequestBuilder {
172212
pub fn header(&mut self, key: impl Into<String>, value: impl Into<String>) -> &mut Self {
173213
self.request
174214
.headers
175-
.insert(key.into().to_lowercase(), HeaderValue::String(value.into()));
215+
.insert(key.into().to_lowercase(), HeaderValue::string(value.into()));
176216
self
177217
}
178218

@@ -216,32 +256,16 @@ impl Response {
216256
&self.status
217257
}
218258

219-
/// The response headers
220-
///
221-
/// This only returns headers that are utf8 encoded
222-
pub fn headers(&self) -> impl Iterator<Item = (&str, &str)> {
223-
self.headers.iter().filter_map(|(k, v)| match v {
224-
HeaderValue::String(v) => Some((k.as_str(), v.as_str())),
225-
HeaderValue::Bytes(_) => None,
226-
})
259+
/// The request headers
260+
pub fn headers(&self) -> impl Iterator<Item = (&str, &HeaderValue)> {
261+
self.headers.iter().map(|(k, v)| (k.as_str(), v))
227262
}
228263

229264
/// Return a header value
230265
///
231-
/// Will return `None` if the header does not exist or if it is not utf8
232-
pub fn header(&self, name: &str) -> Option<&str> {
233-
self.headers.get(name).and_then(|v| match v {
234-
HeaderValue::String(s) => Some(s.as_str()),
235-
HeaderValue::Bytes(_) => None,
236-
})
237-
}
238-
239-
/// The request headers as bytes
240-
pub fn headers_raw(&self) -> impl Iterator<Item = (&str, &[u8])> {
241-
self.headers.iter().map(|(k, v)| match v {
242-
HeaderValue::String(v) => (k.as_str(), v.as_bytes()),
243-
HeaderValue::Bytes(v) => (k.as_str(), v.as_slice()),
244-
})
266+
/// Will return `None` if the header does not exist.
267+
pub fn header(&self, name: &str) -> Option<&HeaderValue> {
268+
self.headers.get(&name.to_lowercase())
245269
}
246270

247271
/// The response body
@@ -293,7 +317,7 @@ impl ResponseBuilder {
293317
pub fn header(&mut self, key: impl Into<String>, value: impl Into<String>) -> &mut Self {
294318
self.response
295319
.headers
296-
.insert(key.into().to_lowercase(), HeaderValue::String(value.into()));
320+
.insert(key.into().to_lowercase(), HeaderValue::string(value.into()));
297321
self
298322
}
299323

@@ -315,9 +339,9 @@ fn into_header_rep(headers: impl conversions::IntoHeaders) -> HashMap<String, He
315339
.into_iter()
316340
.map(|(k, v)| {
317341
let v = String::from_utf8(v)
318-
.map(HeaderValue::String)
319-
.unwrap_or_else(|e| HeaderValue::Bytes(e.into_bytes()));
320-
(k.to_lowercase(), v)
342+
.map(HeaderValueRep::String)
343+
.unwrap_or_else(|e| HeaderValueRep::Bytes(e.into_bytes()));
344+
(k.to_lowercase(), HeaderValue { inner: v })
321345
})
322346
.collect()
323347
}

0 commit comments

Comments
 (0)