1use std::convert::Infallible;
4
5use anyhow::{anyhow, Result};
6use http::{
7 header::{AsHeaderName, InvalidHeaderValue},
8 HeaderMap, HeaderName, HeaderValue,
9};
10use macro_toolset::{
11 b64_decode, b64_encode,
12 string::{base64::Base64EncoderT, StringExtT},
13 wrapper,
14};
15
16pub trait HeaderKeyT {
18 fn as_str_ext(&self) -> &str;
20
21 fn to_header_name(self) -> HeaderName;
23
24 fn default_header_value(&self) -> Option<HeaderValue> {
28 None
29 }
30}
31
32pub trait HeaderAsciiKeyT: HeaderKeyT {}
36
37pub trait HeaderBinaryKeyT: HeaderKeyT {}
41
42impl HeaderKeyT for &'static str {
43 #[inline]
44 fn as_str_ext(&self) -> &str {
45 self
46 }
47
48 #[inline]
49 fn to_header_name(self) -> HeaderName {
50 HeaderName::from_static(self)
51 }
52}
53
54impl HeaderAsciiKeyT for &'static str {}
55
56impl HeaderKeyT for HeaderName {
57 #[inline]
58 fn as_str_ext(&self) -> &str {
59 self.as_str()
60 }
61
62 #[inline]
63 fn to_header_name(self) -> HeaderName {
64 self
65 }
66}
67
68impl HeaderAsciiKeyT for HeaderName {}
69
70wrapper! {
71 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
72 pub BinaryKeyWrapper<T>(pub T)
78}
79
80impl<T: HeaderKeyT> HeaderKeyT for BinaryKeyWrapper<T> {
81 #[inline]
82 fn as_str_ext(&self) -> &str {
83 self.inner.as_str_ext()
84 }
85
86 #[inline]
87 fn to_header_name(self) -> HeaderName {
88 debug_assert!(self.as_str_ext().ends_with("-bin"));
89
90 self.inner.to_header_name()
91 }
92
93 #[inline]
94 fn default_header_value(&self) -> Option<HeaderValue> {
95 debug_assert!(self.as_str_ext().ends_with("-bin"));
96
97 self.inner.default_header_value()
98 }
99}
100
101impl<T: HeaderKeyT> HeaderBinaryKeyT for BinaryKeyWrapper<T> {}
102
103pub trait HeaderMapExtT {
107 #[inline]
108 fn get_ascii<K>(&self, key: K) -> Option<&str>
116 where
117 K: HeaderAsciiKeyT,
118 {
119 self.get_maybe_ascii(key)
120 }
121
122 #[doc(hidden)]
123 #[inline]
124 fn get_maybe_ascii<K>(&self, key: K) -> Option<&str>
126 where
127 K: HeaderKeyT,
128 {
129 self.get_exact(key.to_header_name()).and_then(|v| {
130 v.to_str()
131 .inspect_err(|_e| {
132 #[cfg(feature = "feat-tracing")]
133 tracing::warn!("Invalid header value [{v:?}]: {_e:?}");
134 })
135 .ok()
136 })
137 }
138
139 #[inline]
140 fn get_bin<K>(&self, key: K) -> Result<Option<Vec<u8>>>
147 where
148 K: HeaderBinaryKeyT,
149 {
150 if let Some(b64_str) = self.get_maybe_ascii(key) {
151 let decoded_bytes = b64_decode!(STANDARD_NO_PAD: b64_str)
152 .map_err(|e| anyhow!(e).context(b64_str.to_string()))?;
153 Ok(Some(decoded_bytes))
154 } else {
155 Ok(None)
156 }
157 }
158
159 #[inline]
160 fn get_bin_to_buffer<K>(&self, key: K, buffer: &mut Vec<u8>) -> Result<()>
167 where
168 K: HeaderBinaryKeyT,
169 {
170 if let Some(b64_str) = self.get_maybe_ascii(key) {
171 b64_decode!(STANDARD_NO_PAD: b64_str, buffer)?;
172 }
173
174 Ok(())
175 }
176
177 #[inline]
178 fn get_bin_struct<K, T>(&self, key: K) -> Result<Option<T>>
186 where
187 K: HeaderBinaryKeyT,
188 T: prost::Message + Default,
189 {
190 if let Some(bin) = self.get_bin(key)? {
191 Ok(Some(T::decode(bin.as_slice())?))
192 } else {
193 Ok(None)
194 }
195 }
196
197 #[inline]
198 fn get_bin_struct_or_default<K, T>(&self, key: K) -> Result<T>
206 where
207 K: HeaderBinaryKeyT,
208 T: prost::Message + Default,
209 {
210 if let Some(bin) = self.get_bin(key)? {
211 Ok(T::decode(bin.as_slice())?)
212 } else {
213 Ok(T::default())
214 }
215 }
216
217 #[inline]
227 fn insert_ascii<K, V>(&mut self, key: K, value: V) -> Result<&mut Self, InvalidHeaderValue>
228 where
229 K: HeaderAsciiKeyT,
230 V: TryInto<HeaderValue, Error = InvalidHeaderValue>,
231 {
232 self.insert_maybe_ascii(key, value)
233 }
234
235 #[doc(hidden)]
236 #[inline]
238 fn insert_maybe_ascii<K, V>(
239 &mut self,
240 key: K,
241 value: V,
242 ) -> Result<&mut Self, InvalidHeaderValue>
243 where
244 K: HeaderKeyT,
245 V: TryInto<HeaderValue, Error = InvalidHeaderValue>,
246 {
247 self.insert_exact(key.to_header_name(), value.try_into()?);
248 Ok(self)
249 }
250
251 #[inline]
263 fn insert_ascii_any<K, V>(&mut self, key: K, value: V) -> Result<&mut Self, InvalidHeaderValue>
264 where
265 K: HeaderAsciiKeyT,
266 V: StringExtT,
267 {
268 self.insert_exact(key.to_header_name(), value.to_http_header_value()?);
269 Ok(self)
270 }
271
272 #[inline]
277 fn insert_ascii_infallible<K, V>(&mut self, key: K, value: V) -> &mut Self
278 where
279 K: HeaderAsciiKeyT,
280 V: TryInto<HeaderValue, Error = Infallible>,
281 {
282 self.insert_exact(key.to_header_name(), value.try_into().unwrap());
283 self
284 }
285
286 #[inline]
291 fn insert_ascii_static<K>(&mut self, key: K, value: &'static str) -> &mut Self
292 where
293 K: HeaderAsciiKeyT,
294 {
295 self.insert_exact(key.to_header_name(), HeaderValue::from_static(value));
296 self
297 }
298
299 #[inline]
308 fn insert_bin<K, V>(&mut self, key: K, value: V) -> &mut Self
309 where
310 K: HeaderBinaryKeyT,
311 V: TryInto<HeaderValue, Error = InvalidHeaderValue>,
312 {
313 self.insert_maybe_ascii(key, value)
314 .expect("Base64 string should be valid header value")
315 }
316
317 #[inline]
328 fn insert_bin_any<K, V>(&mut self, key: K, value: V) -> &mut Self
329 where
330 K: HeaderBinaryKeyT,
331 V: Base64EncoderT,
332 {
333 self.insert_exact(
334 key.to_header_name(),
335 value
336 .to_http_header_value()
337 .expect("Base64 string should be valid header value"),
338 )
339 }
340
341 #[inline]
350 fn insert_bin_byte<K, V>(&mut self, key: K, value: V) -> &mut Self
351 where
352 K: HeaderBinaryKeyT,
353 V: AsRef<[u8]>,
354 {
355 let value = HeaderValue::from_maybe_shared(
358 b64_encode!(STANDARD_NO_PAD: value.as_ref() => BYTES).freeze(),
359 )
360 .expect("Base64 string should be valid header value");
361 self.insert_exact(key.to_header_name(), value);
362
363 self
364 }
365
366 #[inline]
379 fn insert_bin_struct<K, V>(&mut self, key: K, value: V) -> Result<&mut Self, prost::EncodeError>
380 where
381 K: HeaderBinaryKeyT,
382 V: prost::Message + Default,
383 {
384 let mut buf = Vec::with_capacity(64);
385 value.encode(&mut buf)?;
386
387 let value =
390 HeaderValue::from_maybe_shared(b64_encode!(STANDARD_NO_PAD: buf => BYTES).freeze())
391 .expect("Base64 string should be valid header value");
392 self.insert_exact(key.to_header_name(), value);
393
394 Ok(self)
395 }
396
397 #[inline]
401 fn insert_bin_static<K>(&mut self, key: K, value: &'static str) -> &mut Self
402 where
403 K: HeaderBinaryKeyT,
404 {
405 self.insert_exact(key.to_header_name(), HeaderValue::from_static(value));
406 self
407 }
408
409 #[inline]
413 fn insert_default(&mut self, key: impl HeaderKeyT) -> &mut Self {
414 if let Some(v) = key.default_header_value() {
415 self.insert_exact(key.to_header_name(), v);
416 }
417 self
418 }
419
420 fn contains_headerkey(&self, key: impl HeaderKeyT) -> bool;
422
423 fn get_exact<K>(&self, key: K) -> Option<&HeaderValue>
429 where
430 K: AsHeaderName;
431
432 fn insert_exact(&mut self, key: HeaderName, value: HeaderValue) -> &mut Self;
434}
435
436impl<T> HeaderMapExtT for &mut T
438where
439 T: HeaderMapExtT,
440{
441 #[inline]
442 fn contains_headerkey(&self, key: impl HeaderKeyT) -> bool {
443 (**self).contains_headerkey(key)
444 }
445
446 #[inline]
447 fn get_exact<K>(&self, key: K) -> Option<&HeaderValue>
448 where
449 K: AsHeaderName,
450 {
451 (**self).get_exact(key)
452 }
453
454 #[inline]
455 fn insert_exact(&mut self, key: HeaderName, value: HeaderValue) -> &mut Self {
456 (**self).insert_exact(key, value);
457 self
458 }
459}
460
461impl HeaderMapExtT for HeaderMap {
462 #[inline]
463 fn contains_headerkey(&self, key: impl HeaderKeyT) -> bool {
464 self.contains_key(key.to_header_name())
465 }
466
467 #[inline]
468 fn get_exact<K>(&self, key: K) -> Option<&HeaderValue>
469 where
470 K: AsHeaderName,
471 {
472 self.get(key)
473 }
474
475 #[inline]
476 fn insert_exact(&mut self, key: HeaderName, value: HeaderValue) -> &mut Self {
477 self.insert(key, value);
478 self
479 }
480}