axol_http/header/map.rs
1use std::{borrow::Cow, ops::Index};
2
3use http::{header::ToStrError, HeaderName, HeaderValue};
4use smallvec::SmallVec;
5use thiserror::Error;
6
7use super::{header_name, TypedHeader};
8
9/// This is a multimap representing HTTP headers.
10/// Not that this is not a true hashmap, as the count of headers is generally too small to be worth representing as a map.
11#[derive(Default, Clone, Debug, PartialEq, Eq)]
12pub struct HeaderMap {
13 items: Vec<(Cow<'static, str>, Cow<'static, str>)>,
14}
15
16#[cfg(feature = "otel")]
17impl opentelemetry_api::propagation::Extractor for &HeaderMap {
18 /// Get a value for a key from the HeaderMap. If the value is not valid ASCII, returns None.
19 fn get(&self, key: &str) -> Option<&str> {
20 (&**self).get(key)
21 }
22
23 /// Collect all the keys from the HeaderMap.
24 fn keys(&self) -> Vec<&str> {
25 self.iter().map(|x| x.0).collect()
26 }
27}
28
29#[cfg(feature = "otel")]
30impl opentelemetry_api::propagation::Injector for &mut HeaderMap {
31 fn set(&mut self, key: &str, value: String) {
32 self.append(key, value);
33 }
34}
35
36impl HeaderMap {
37 /// Create an empty `HeaderMap`.
38 ///
39 /// The map will be created without any capacity. This function will not
40 /// allocate.
41 ///
42 /// # Examples
43 ///
44 /// ```
45 /// # use axol_http::HeaderMap;
46 /// let map = HeaderMap::new();
47 ///
48 /// assert!(map.is_empty());
49 /// assert_eq!(0, map.capacity());
50 /// ```
51 pub fn new() -> Self {
52 Default::default()
53 }
54
55 /// Create an empty `HeaderMap` with the specified capacity.
56 ///
57 /// The returned map will allocate internal storage in order to hold about
58 /// `capacity` elements without reallocating. However, this is a "best
59 /// effort" as there are usage patterns that could cause additional
60 /// allocations before `capacity` headers are stored in the map.
61 ///
62 /// More capacity than requested may be allocated.
63 ///
64 /// # Examples
65 ///
66 /// ```
67 /// # use axol_http::HeaderMap;
68 /// let map: HeaderMap<u32> = HeaderMap::with_capacity(10);
69 ///
70 /// assert!(map.is_empty());
71 /// assert_eq!(12, map.capacity());
72 /// ```
73 pub fn with_capacity(capacity: usize) -> Self {
74 Self {
75 items: Vec::with_capacity(capacity),
76 }
77 }
78
79 /// Returns the number of headers the map can hold without reallocating.
80 ///
81 /// This number is an approximation as certain usage patterns could cause
82 /// additional allocations before the returned capacity is filled.
83 ///
84 /// # Examples
85 ///
86 /// ```
87 /// # use axol_http::HeaderMap;
88 /// # use axol_http::header::HOST;
89 /// let mut map = HeaderMap::new();
90 ///
91 /// assert_eq!(0, map.capacity());
92 ///
93 /// map.insert(HOST, "hello.world".parse().unwrap());
94 /// assert_eq!(6, map.capacity());
95 /// ```
96 pub fn capacity(&self) -> usize {
97 self.items.capacity()
98 }
99
100 /// Reserves capacity for at least `additional` more headers to be inserted
101 /// into the `HeaderMap`.
102 ///
103 /// The header map may reserve more space to avoid frequent reallocations.
104 /// Like with `with_capacity`, this will be a "best effort" to avoid
105 /// allocations until `additional` more headers are inserted. Certain usage
106 /// patterns could cause additional allocations before the number is
107 /// reached.
108 ///
109 /// # Panics
110 ///
111 /// Panics if the new allocation size overflows `usize`.
112 ///
113 /// # Examples
114 ///
115 /// ```
116 /// # use axol_http::HeaderMap;
117 /// # use axol_http::header::HOST;
118 /// let mut map = HeaderMap::new();
119 /// map.reserve(10);
120 /// # map.insert(HOST, "bar".parse().unwrap());
121 /// ```
122 pub fn reserve(&mut self, additional: usize) {
123 self.items.reserve(additional);
124 }
125
126 /// Clears the map, removing all key-value pairs. Keeps the allocated memory
127 /// for reuse.
128 ///
129 /// # Examples
130 ///
131 /// ```
132 /// # use axol_http::HeaderMap;
133 /// # use axol_http::header::HOST;
134 /// let mut map = HeaderMap::new();
135 /// map.insert(HOST, "hello.world".parse().unwrap());
136 ///
137 /// map.clear();
138 /// assert!(map.is_empty());
139 /// assert!(map.capacity() > 0);
140 /// ```
141 pub fn clear(&mut self) {
142 self.items.clear();
143 }
144
145 /// Returns true if the map contains no elements.
146 ///
147 /// # Examples
148 ///
149 /// ```
150 /// # use axol_http::HeaderMap;
151 /// # use axol_http::header::HOST;
152 /// let mut map = HeaderMap::new();
153 ///
154 /// assert!(map.is_empty());
155 ///
156 /// map.insert(HOST, "hello.world".parse().unwrap());
157 ///
158 /// assert!(!map.is_empty());
159 /// ```
160 pub fn is_empty(&self) -> bool {
161 self.items.len() == 0
162 }
163
164 /// Returns the number of headers stored in the map.
165 ///
166 /// This number represents the total number of **values** stored in the map.
167 /// This number can be greater than or equal to the number of **keys**
168 /// stored given that a single key may have more than one associated value.
169 ///
170 /// # Examples
171 ///
172 /// ```
173 /// # use axol_http::HeaderMap;
174 /// # use axol_http::header::{ACCEPT, HOST};
175 /// let mut map = HeaderMap::new();
176 ///
177 /// assert_eq!(0, map.len());
178 ///
179 /// map.insert(ACCEPT, "text/plain".parse().unwrap());
180 /// map.insert(HOST, "localhost".parse().unwrap());
181 ///
182 /// assert_eq!(2, map.len());
183 ///
184 /// map.append(ACCEPT, "text/html".parse().unwrap());
185 ///
186 /// assert_eq!(3, map.len());
187 /// ```
188 pub fn len(&self) -> usize {
189 self.items.len()
190 }
191
192 /// Appends a key-value pair into the map.
193 ///
194 /// If the map did have this key present, the new value is pushed to the end
195 /// of the list of values currently associated with the key. The key is not
196 /// updated, though; this matters for types that can be `==` without being
197 /// identical.
198 ///
199 /// # Examples
200 ///
201 /// ```
202 /// # use axol_http::HeaderMap;
203 /// # use axol_http::header::HOST;
204 /// let mut map = HeaderMap::new();
205 /// assert!(map.insert(HOST, "world".parse().unwrap()).is_none());
206 /// assert!(!map.is_empty());
207 ///
208 /// map.append(HOST, "earth".parse().unwrap());
209 ///
210 /// let values = map.get_all("host");
211 /// let mut i = values.iter();
212 /// assert_eq!("world", *i.next().unwrap());
213 /// assert_eq!("earth", *i.next().unwrap());
214 /// ```
215 pub fn append(&mut self, name: impl AsRef<str>, value: impl Into<String>) {
216 let name = header_name(name.as_ref());
217 self.items.push((name, Cow::Owned(value.into())));
218 }
219
220 /// Appends a key-value pair into the map with a static value.
221 ///
222 /// If the map did have this key present, the new value is pushed to the end
223 /// of the list of values currently associated with the key. The key is not
224 /// updated, though; this matters for types that can be `==` without being
225 /// identical.
226 ///
227 /// # Examples
228 ///
229 /// ```
230 /// # use axol_http::HeaderMap;
231 /// # use axol_http::header::HOST;
232 /// let mut map = HeaderMap::new();
233 /// assert!(map.insert(HOST, "world".parse().unwrap()).is_none());
234 /// assert!(!map.is_empty());
235 ///
236 /// map.append(HOST, "earth".parse().unwrap());
237 ///
238 /// let values = map.get_all("host");
239 /// let mut i = values.iter();
240 /// assert_eq!("world", *i.next().unwrap());
241 /// assert_eq!("earth", *i.next().unwrap());
242 /// ```
243 pub fn append_static(&mut self, name: impl AsRef<str>, value: impl Into<&'static str>) {
244 let name = header_name(name.as_ref());
245 self.items.push((name, Cow::Borrowed(value.into())));
246 }
247
248 /// Appends a typed key-value pair into the map.
249 ///
250 /// If the map did have this key present, the new value is pushed to the end
251 /// of the list of values currently associated with the key. The key is not
252 /// updated, though; this matters for types that can be `==` without being
253 /// identical.
254 ///
255 /// # Examples
256 ///
257 /// ```
258 /// # use axol_http::HeaderMap;
259 /// # use axol_http::header::HOST;
260 /// let mut map = HeaderMap::new();
261 /// assert!(map.insert(HOST, "world".parse().unwrap()).is_none());
262 /// assert!(!map.is_empty());
263 ///
264 /// map.append(HOST, "earth".parse().unwrap());
265 ///
266 /// let values = map.get_all("host");
267 /// let mut i = values.iter();
268 /// assert_eq!("world", *i.next().unwrap());
269 /// assert_eq!("earth", *i.next().unwrap());
270 /// ```
271 pub fn append_typed<H: TypedHeader>(&mut self, header: &H) {
272 header.encode(self);
273 }
274
275 /// Inserts a key-value pair into the map.
276 ///
277 /// If the map did have this key present, the new value is associated with
278 /// the key and all previous values are removed. **Note** that only a single
279 /// one of the previous values is returned. If there are multiple values
280 /// that have been previously associated with the key, then the first one is
281 /// returned. See `insert_mult` on `OccupiedEntry` for an API that returns
282 /// all values.
283 ///
284 /// The key is not updated, though; this matters for types that can be `==`
285 /// without being identical.
286 ///
287 /// # Examples
288 ///
289 /// ```
290 /// # use axol_http::HeaderMap;
291 /// # use axol_http::header::HOST;
292 /// let mut map = HeaderMap::new();
293 /// assert!(map.insert(HOST, "world".parse().unwrap()).is_none());
294 /// assert!(!map.is_empty());
295 ///
296 /// let mut prev = map.insert(HOST, "earth".parse().unwrap()).unwrap();
297 /// assert_eq!("world", prev);
298 /// ```
299 pub fn insert(
300 &mut self,
301 name: impl AsRef<str>,
302 value: impl Into<String>,
303 ) -> Option<Cow<'static, str>> {
304 let name = header_name(name.as_ref());
305 match self.get_mut(&name) {
306 Some(old) => Some(std::mem::replace(old, Cow::Owned(value.into()))),
307 None => {
308 self.items.push((name, Cow::Owned(value.into())));
309 None
310 }
311 }
312 }
313
314 /// Inserts a key-value pair into the map with a static value.
315 ///
316 /// If the map did have this key present, the new value is associated with
317 /// the key and all previous values are removed. **Note** that only a single
318 /// one of the previous values is returned. If there are multiple values
319 /// that have been previously associated with the key, then the first one is
320 /// returned. See `insert_mult` on `OccupiedEntry` for an API that returns
321 /// all values.
322 ///
323 /// The key is not updated, though; this matters for types that can be `==`
324 /// without being identical.
325 ///
326 /// # Examples
327 ///
328 /// ```
329 /// # use axol_http::HeaderMap;
330 /// # use axol_http::header::HOST;
331 /// let mut map = HeaderMap::new();
332 /// assert!(map.insert(HOST, "world".parse().unwrap()).is_none());
333 /// assert!(!map.is_empty());
334 ///
335 /// let mut prev = map.insert(HOST, "earth".parse().unwrap()).unwrap();
336 /// assert_eq!("world", prev);
337 /// ```
338 pub fn insert_static(
339 &mut self,
340 name: impl AsRef<str>,
341 value: impl Into<&'static str>,
342 ) -> Option<Cow<'static, str>> {
343 let name = header_name(name.as_ref());
344 match self.get_mut(&name) {
345 Some(old) => Some(std::mem::replace(old, Cow::Borrowed(value.into()))),
346 None => {
347 self.items.push((name, Cow::Borrowed(value.into())));
348 None
349 }
350 }
351 }
352
353 /// Inserts a typed key-value pair into the map.
354 ///
355 /// Note that if the header is a TypedHeader with multiple values returned, only the last value is used.
356 ///
357 /// If the map did have this key present, the new value is associated with
358 /// the key and all previous values are removed. **Note** that only a single
359 /// one of the previous values is returned. If there are multiple values
360 /// that have been previously associated with the key, then the first one is
361 /// returned. See `insert_mult` on `OccupiedEntry` for an API that returns
362 /// all values.
363 ///
364 /// The key is not updated, though; this matters for types that can be `==`
365 /// without being identical.
366 ///
367 /// # Examples
368 ///
369 /// ```
370 /// # use axol_http::HeaderMap;
371 /// # use axol_http::header::HOST;
372 /// let mut map = HeaderMap::new();
373 /// assert!(map.insert(HOST, "world".parse().unwrap()).is_none());
374 /// assert!(!map.is_empty());
375 ///
376 /// let mut prev = map.insert(HOST, "earth".parse().unwrap()).unwrap();
377 /// assert_eq!("world", prev);
378 /// ```
379 pub fn insert_typed<H: TypedHeader>(&mut self, header: &H) -> Option<Cow<'static, str>> {
380 let name = H::name();
381 let value = header
382 .encode_to_string()
383 .into_iter()
384 .rev()
385 .next()
386 .expect("header encoded to empty value");
387 match self.get_mut(name) {
388 Some(old) => Some(std::mem::replace(old, Cow::Owned(value))),
389 None => {
390 self.items.push((Cow::Borrowed(name), Cow::Owned(value)));
391 None
392 }
393 }
394 }
395
396 /// Returns true if the map contains a value for the specified key.
397 ///
398 /// # Examples
399 ///
400 /// ```
401 /// # use axol_http::HeaderMap;
402 /// # use axol_http::header::HOST;
403 /// let mut map = HeaderMap::new();
404 /// assert!(!map.contains_key(HOST));
405 ///
406 /// map.insert(HOST, "world".parse().unwrap());
407 /// assert!(map.contains_key("host"));
408 /// ```
409 pub fn contains_key(&self, name: &str) -> bool {
410 self.get_all(name).next().is_some()
411 }
412
413 /// Returns a reference to the value associated with the key.
414 ///
415 /// If there are multiple values associated with the key, then the first one
416 /// is returned. Use `get_all` to get all values associated with a given
417 /// key. Returns `None` if there are no values associated with the key.
418 ///
419 /// # Examples
420 ///
421 /// ```
422 /// # use axol_http::HeaderMap;
423 /// # use axol_http::header::HOST;
424 /// let mut map = HeaderMap::new();
425 /// assert!(map.get("host").is_none());
426 ///
427 /// map.insert(HOST, "hello".parse().unwrap());
428 /// assert_eq!(map.get(HOST).unwrap(), &"hello");
429 /// assert_eq!(map.get("host").unwrap(), &"hello");
430 ///
431 /// map.append(HOST, "world".parse().unwrap());
432 /// assert_eq!(map.get("host").unwrap(), &"hello");
433 /// ```
434 pub fn get(&self, name: &str) -> Option<&str> {
435 self.items
436 .iter()
437 .find(|(entry_name, _)| entry_name.eq_ignore_ascii_case(name))
438 .map(|x| &*x.1)
439 }
440
441 /// Returns a reference to the value associated with the key.
442 ///
443 /// The key is defined with an associated type referenced a TypedHeader.
444 /// If the header is malformed, None is transparently returned
445 ///
446 /// Note that this causes an allocation depending on the implementation of the TypedHeader.
447 ///
448 /// If there are multiple values associated with the key, then the first one
449 /// is returned. Use `get_all` to get all values associated with a given
450 /// key. Returns `None` if there are no values associated with the key.
451 ///
452 /// # Examples
453 ///
454 /// ```
455 /// # use axol_http::HeaderMap;
456 /// # use axol_http::header::HOST;
457 /// let mut map = HeaderMap::new();
458 /// assert!(map.get::<Host>().is_none());
459 ///
460 /// map.insert(HOST, "hello".parse().unwrap());
461 /// assert_eq!(map.get::<Host>().unwrap(), &"hello");
462 ///
463 /// map.append(HOST, "world".parse().unwrap());
464 /// assert_eq!(map.get::<Host>().unwrap(), &"hello");
465 /// ```
466 pub fn get_typed<H: TypedHeader>(&self) -> Option<H> {
467 let raw = self.get(H::name())?;
468 H::decode(raw).ok()
469 }
470
471 /// Returns a view of all values associated with a key.
472 ///
473 /// The returned view does not incur any allocations and allows iterating
474 /// the values associated with the key. See [`GetAll`] for more details.
475 /// Returns `None` if there are no values associated with the key.
476 ///
477 /// # Examples
478 ///
479 /// ```
480 /// # use axol_http::HeaderMap;
481 /// # use axol_http::header::HOST;
482 /// let mut map = HeaderMap::new();
483 ///
484 /// map.insert(HOST, "hello".parse().unwrap());
485 /// map.append(HOST, "goodbye".parse().unwrap());
486 ///
487 /// let view = map.get_all("host");
488 ///
489 /// let mut iter = view.iter();
490 /// assert_eq!(&"hello", iter.next().unwrap());
491 /// assert_eq!(&"goodbye", iter.next().unwrap());
492 /// assert!(iter.next().is_none());
493 /// ```
494 pub fn get_all<'a>(&'a self, name: &'a str) -> impl Iterator<Item = &'a str> {
495 self.items
496 .iter()
497 .filter(|(entry_name, _)| entry_name.eq_ignore_ascii_case(name))
498 .map(|x| &*x.1)
499 }
500
501 /// Returns a view of all values associated with a key.
502 ///
503 /// The key is defined with an associated type referenced a TypedHeader.
504 /// If the header is malformed, it is skipped.
505 ///
506 /// Note that this causes an allocation for each header value returned depending on the implementation of the TypedHeader.
507 ///
508 /// The returned view does not incur any allocations and allows iterating
509 /// the values associated with the key. See [`GetAll`] for more details.
510 /// Returns `None` if there are no values associated with the key.
511 ///
512 /// # Examples
513 ///
514 /// ```
515 /// # use axol_http::HeaderMap;
516 /// # use axol_http::header::HOST;
517 /// let mut map = HeaderMap::new();
518 ///
519 /// map.insert(HOST, "hello".parse().unwrap());
520 /// map.append(HOST, "goodbye".parse().unwrap());
521 ///
522 /// let view = map.get_all("host");
523 ///
524 /// let mut iter = view.iter();
525 /// assert_eq!(&"hello", iter.next().unwrap());
526 /// assert_eq!(&"goodbye", iter.next().unwrap());
527 /// assert!(iter.next().is_none());
528 /// ```
529 pub fn get_all_typed<'a, H: TypedHeader>(&'a self) -> impl Iterator<Item = H> + 'a {
530 let name = H::name();
531 self.items
532 .iter()
533 .filter(|(entry_name, _)| entry_name.eq_ignore_ascii_case(name))
534 .filter_map(|x| H::decode(&*x.1).ok())
535 }
536
537 /// Returns a mutable reference to the value associated with the key.
538 ///
539 /// If there are multiple values associated with the key, then the first one
540 /// is returned. Use `entry` to get all values associated with a given
541 /// key. Returns `None` if there are no values associated with the key.
542 ///
543 /// # Examples
544 ///
545 /// ```
546 /// # use axol_http::HeaderMap;
547 /// # use axol_http::header::HOST;
548 /// let mut map = HeaderMap::default();
549 /// map.insert(HOST, "hello".to_string());
550 /// map.get_mut("host").unwrap().push_str("-world");
551 ///
552 /// assert_eq!(map.get(HOST).unwrap(), &"hello-world");
553 /// ```
554 pub fn get_mut(&mut self, name: &str) -> Option<&mut Cow<'static, str>> {
555 self.items
556 .iter_mut()
557 .find(|(entry_name, _)| entry_name.eq_ignore_ascii_case(name))
558 .map(|x| &mut x.1)
559 }
560
561 /// Removes a key from the map, returning the value associated with the key.
562 ///
563 /// Returns an empty vec if the map does not contain the key. If there are
564 /// multiple values associated with the key, then all are returned.
565 ///
566 /// # Examples
567 ///
568 /// ```
569 /// # use axol_http::HeaderMap;
570 /// # use axol_http::header::HOST;
571 /// let mut map = HeaderMap::new();
572 /// map.insert(HOST, "hello.world".parse().unwrap());
573 ///
574 /// let prev = map.remove(HOST);
575 /// assert_eq!("hello.world", &prev[0]);
576 ///
577 /// assert!(map.remove(HOST).is_empty());
578 /// ```
579 pub fn remove(&mut self, name: impl AsRef<str>) -> Vec<Cow<'static, str>> {
580 let name = name.as_ref();
581 let mut out = vec![];
582 self.items.retain_mut(|(entry_name, value)| {
583 if entry_name.eq_ignore_ascii_case(name) {
584 out.push(std::mem::take(value));
585 false
586 } else {
587 true
588 }
589 });
590 out
591 }
592
593 /// An iterator visiting all key-value pairs.
594 ///
595 /// The iteration order is in insertion order.
596 ///
597 /// # Examples
598 ///
599 /// ```
600 /// # use axol_http::HeaderMap;
601 /// # use axol_http::header::{CONTENT_LENGTH, HOST};
602 /// let mut map = HeaderMap::new();
603 ///
604 /// map.insert(HOST, "hello".parse().unwrap());
605 /// map.append(HOST, "goodbye".parse().unwrap());
606 /// map.insert(CONTENT_LENGTH, "123".parse().unwrap());
607 ///
608 /// for (key, value) in map.iter() {
609 /// println!("{:?}: {:?}", key, value);
610 /// }
611 /// ```
612 pub fn iter(&self) -> impl Iterator<Item = (&str, &str)> {
613 self.items.iter().map(|(name, value)| (&**name, &**value))
614 }
615
616 pub fn grouped(&self) -> Vec<(&str, SmallVec<[&str; 2]>)> {
617 let mut names = self.iter().collect::<Vec<_>>();
618 names.sort_by_key(|x| x.0);
619 let mut out: Vec<(&str, SmallVec<[&str; 2]>)> = vec![];
620 for (name, value) in names {
621 if out.last().map(|x| x.0) == Some(name) {
622 out.last_mut().unwrap().1.push(value);
623 } else {
624 out.push((name, smallvec::smallvec![value]))
625 }
626 }
627
628 out
629 }
630}
631
632impl<K: Into<Cow<'static, str>>, V: Into<String>> Extend<(K, V)> for HeaderMap {
633 fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
634 let iter = iter.into_iter();
635 self.reserve(iter.size_hint().0);
636 for (name, value) in iter {
637 let name = name.into();
638 self.append(name, value);
639 }
640 }
641}
642
643impl<K: Into<Cow<'static, str>>, V: Into<String>> FromIterator<(K, V)> for HeaderMap {
644 fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
645 let mut out = Self::default();
646 out.extend(iter);
647 out
648 }
649}
650
651impl<K: Into<Cow<'static, str>>> Index<K> for HeaderMap {
652 type Output = str;
653
654 fn index(&self, index: K) -> &Self::Output {
655 self.get(index.into().as_ref()).expect("header missing")
656 }
657}
658
659impl IntoIterator for HeaderMap {
660 type Item = (Cow<'static, str>, Cow<'static, str>);
661
662 type IntoIter = std::vec::IntoIter<Self::Item>;
663
664 fn into_iter(self) -> Self::IntoIter {
665 self.items.into_iter()
666 }
667}
668
669impl<'a> IntoIterator for &'a HeaderMap {
670 type Item = &'a (Cow<'static, str>, Cow<'static, str>);
671
672 type IntoIter = std::slice::Iter<'a, (Cow<'static, str>, Cow<'static, str>)>;
673
674 fn into_iter(self) -> Self::IntoIter {
675 self.items.iter()
676 }
677}
678
679impl<'a> IntoIterator for &'a mut HeaderMap {
680 type Item = &'a mut (Cow<'static, str>, Cow<'static, str>);
681
682 type IntoIter = std::slice::IterMut<'a, (Cow<'static, str>, Cow<'static, str>)>;
683
684 fn into_iter(self) -> Self::IntoIter {
685 self.items.iter_mut()
686 }
687}
688
689#[derive(Error, Debug)]
690pub enum HeaderMapConvertError {
691 #[error("header value not utf8: '{0}'")]
692 Utf8(#[from] ToStrError),
693}
694
695impl TryFrom<http::HeaderMap> for HeaderMap {
696 type Error = HeaderMapConvertError;
697
698 fn try_from(value: http::HeaderMap) -> Result<Self, Self::Error> {
699 let mut out = Self::with_capacity(value.len());
700 let mut last_header_name = None::<http::HeaderName>;
701 for (name, value) in value.into_iter() {
702 let name_ref = match &name {
703 Some(x) => x,
704 None => last_header_name.as_ref().unwrap(),
705 };
706
707 out.append(name_ref.as_str(), value.to_str()?);
708
709 if let Some(name) = name {
710 last_header_name = Some(name);
711 }
712 }
713 Ok(out)
714 }
715}
716
717impl Into<http::HeaderMap> for HeaderMap {
718 fn into(self) -> http::HeaderMap {
719 self.into_iter()
720 .map(|(name, value)| {
721 (
722 match name {
723 Cow::Borrowed(x) => HeaderName::from_static(x),
724 Cow::Owned(x) => {
725 HeaderName::from_bytes(x.as_bytes()).expect("invalid header name")
726 }
727 },
728 match value {
729 Cow::Borrowed(x) => HeaderValue::from_static(x),
730 Cow::Owned(x) => {
731 HeaderValue::from_bytes(x.as_bytes()).expect("invalid header value")
732 }
733 },
734 )
735 })
736 .collect()
737 }
738}