1use std::borrow::Cow;
2use std::fmt;
3
4pub use http::header::{
5 AsHeaderName, HeaderName, HeaderValue, IntoHeaderName, InvalidHeaderValue,
6};
7
8#[cfg(feature = "json")]
9pub use serde_json::Error as JsonError;
10
11#[derive(Debug, Clone)]
17pub struct HeaderValues(http::HeaderMap<HeaderValue>);
18
19impl HeaderValues {
20 pub fn new() -> Self {
22 Self(http::HeaderMap::new())
23 }
24
25 pub fn from_inner(inner: http::HeaderMap<HeaderValue>) -> Self {
27 Self(inner)
28 }
29
30 pub fn insert<K, V>(&mut self, key: K, val: V) -> Option<HeaderValue>
38 where
39 K: IntoHeaderName,
40 V: TryInto<HeaderValue>,
41 V::Error: fmt::Debug,
42 {
43 let val = val.try_into().expect("invalid HeaderValue");
44 self.0.insert(key, val)
45 }
46
47 pub fn try_insert<K, V>(
53 &mut self,
54 key: K,
55 val: V,
56 ) -> Result<Option<HeaderValue>, InvalidHeaderValue>
57 where
58 K: IntoHeaderName,
59 V: TryInto<HeaderValue, Error = InvalidHeaderValue>,
60 {
61 Ok(self.0.insert(key, val.try_into()?))
62 }
63
64 pub fn encode_value<K, V>(&mut self, key: K, val: V) -> Option<HeaderValue>
67 where
68 K: IntoHeaderName,
69 V: IntoEncodedHeaderValue,
70 {
71 let val = val.into_encoded_header_value();
72 self.0.insert(key, val)
73 }
74
75 #[cfg(feature = "json")]
80 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
81 pub fn serialize_value<K, V>(
82 &mut self,
83 key: K,
84 val: &V,
85 ) -> Result<Option<HeaderValue>, JsonError>
86 where
87 K: IntoHeaderName,
88 V: serde::Serialize + ?Sized,
89 {
90 let v = serde_json::to_string(val)?;
91 Ok(self.encode_value(key, v))
92 }
93
94 pub fn get<K>(&self, key: K) -> Option<&HeaderValue>
96 where
97 K: AsHeaderName,
98 {
99 self.0.get(key)
100 }
101
102 pub fn get_mut<K>(&mut self, key: K) -> Option<&mut HeaderValue>
104 where
105 K: AsHeaderName,
106 {
107 self.0.get_mut(key)
108 }
109
110 pub fn get_str<K>(&self, key: K) -> Option<&str>
112 where
113 K: AsHeaderName,
114 {
115 self.get(key).and_then(|v| v.to_str().ok())
116 }
117
118 pub fn decode_value<K>(
120 &self,
121 key: K,
122 ) -> Option<Result<Cow<'_, str>, std::str::Utf8Error>>
123 where
124 K: AsHeaderName,
125 {
126 self.get(key).map(|v| {
127 percent_encoding::percent_decode(v.as_bytes()).decode_utf8()
128 })
129 }
130
131 #[cfg(feature = "json")]
134 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
135 pub fn deserialize_value<K, D>(
136 &self,
137 key: K,
138 ) -> Option<Result<D, serde_json::Error>>
139 where
140 K: AsHeaderName,
141 D: serde::de::DeserializeOwned,
142 {
143 self.get(key).map(|v| {
144 let s = percent_encoding::percent_decode(v.as_bytes())
145 .decode_utf8_lossy();
146 serde_json::from_str(s.as_ref())
147 })
148 }
149
150 pub fn into_inner(self) -> http::HeaderMap<HeaderValue> {
152 self.0
153 }
154}
155
156impl Default for HeaderValues {
157 fn default() -> Self {
158 Self::new()
159 }
160}
161
162fn encode_to_header_value(s: impl AsRef<[u8]>) -> HeaderValue {
163 let s: String = percent_encoding::percent_encode(
164 s.as_ref(),
165 percent_encoding::CONTROLS,
166 )
167 .collect();
168 let b: bytes::Bytes = s.into();
170 HeaderValue::from_maybe_shared(b).unwrap()
175}
176
177pub trait IntoEncodedHeaderValue {
179 fn into_encoded_header_value(self) -> HeaderValue;
180}
181
182macro_rules! impl_into_header_value {
183 ($(
184 $s:ty, $self:ident => $ex:expr
185 ),*) => ($(
186 impl IntoEncodedHeaderValue for $s {
187 #[inline]
188 fn into_encoded_header_value($self) -> HeaderValue { $ex }
189 }
190 )*);
191 (REF, $(
192 $s:ty, $self:ident => $ex:expr
193 ),*) => ($(
194 impl<'a> IntoEncodedHeaderValue for &'a $s {
195 #[inline]
196 fn into_encoded_header_value($self) -> HeaderValue { $ex }
197 }
198 )*);
199}
200
201impl_into_header_value! {
202 HeaderName, self => self.into(),
203 HeaderValue, self => self,
204 i16, self => self.into(),
205 i32, self => self.into(),
206 i64, self => self.into(),
207 isize, self => self.into(),
208 u16, self => self.into(),
209 u32, self => self.into(),
210 u64, self => self.into(),
211 usize, self => self.into(),
212 String, self => encode_to_header_value(self),
213 Vec<u8>, self => encode_to_header_value(self)
214}
215
216impl_into_header_value! { REF,
217 HeaderValue, self => self.clone(),
218 [u8], self => encode_to_header_value(self),
219 str, self => encode_to_header_value(self)
220}
221
222#[cfg(test)]
223mod tests {
224 #![allow(unused_imports)]
225
226 use super::*;
227 use serde::{Deserialize, Serialize};
228
229 #[test]
230 fn test_encdec() {
231 let mut values = HeaderValues::new();
232 values.encode_value("Rocket", "🚀 Rocket");
233 let s = values.get_str("Rocket").unwrap();
234 assert_eq!(s, "%F0%9F%9A%80 Rocket");
235
236 let s = values.decode_value("Rocket").unwrap().unwrap();
237 assert_eq!(s, "🚀 Rocket");
238 }
239
240 #[cfg(feature = "json")]
241 #[test]
242 fn test_serde() {
243 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
244 struct Value {
245 text: String,
246 number: usize,
247 }
248
249 let mut values = HeaderValues::new();
250 let val = Value {
251 text: "🚀 Rocket".into(),
252 number: 42,
253 };
254 values.serialize_value("Value", &val).unwrap();
255
256 let s = values.get_str("Value").unwrap();
257 assert_eq!(s, "{\"text\":\"%F0%9F%9A%80 Rocket\",\"number\":42}");
258
259 let n_val: Value = values.deserialize_value("Value").unwrap().unwrap();
260 assert_eq!(n_val, val);
261 }
262}