1use http::header::{self, HeaderMap, HeaderValue};
2use std::error;
3use std::fmt::{self, Write};
4use std::str::FromStr;
5
6use crate::{Error, Header, HeaderMapExt, ToValues};
7
8#[inline]
9pub fn is_token(s: &str) -> bool {
10 if s.is_empty() {
11 return false;
12 }
13
14 s.as_bytes().iter().all(|b| match *b {
15 b'a'..=b'z'
16 | b'A'..=b'Z'
17 | b'0'..=b'9'
18 | b'!'
19 | b'#'
20 | b'$'
21 | b'%'
22 | b'&'
23 | b'\''
24 | b'*'
25 | b'+'
26 | b'-'
27 | b'.'
28 | b'^'
29 | b'_'
30 | b'`'
31 | b'|'
32 | b'~' => true,
33 _ => false,
34 })
35}
36
37pub fn parse_single_value<T>(
38 values: &mut header::ValueIter<HeaderValue>,
39) -> Result<Option<T>, Error>
40where
41 T: FromStr,
42 T::Err: Into<Box<dyn error::Error + Sync + Send>>,
43{
44 match values.next() {
45 Some(value) => {
46 let value = value
47 .to_str()
48 .map_err(|_| Error::invalid_value())?
49 .trim()
50 .parse()
51 .map_err(|_| Error::invalid_value())?;
52 Ok(Some(value))
53 }
54 None => Ok(None),
55 }
56}
57
58pub fn encode_single_value<T>(value: &T, values: &mut ToValues)
59where
60 T: fmt::Display,
61{
62 let value = value.to_string();
63 let value = HeaderValue::from_str(&value).expect("failed to encode header");
64 values.append(value);
65}
66
67pub fn parse_comma_delimited<T>(
68 values: &mut header::ValueIter<HeaderValue>,
69) -> Result<Option<Vec<T>>, Error>
70where
71 T: FromStr,
72 T::Err: Into<Box<dyn error::Error + Sync + Send>>,
73{
74 let mut out = vec![];
75 let mut empty = true;
76 for value in values {
77 empty = false;
78
79 let value = value.to_str().map_err(|_| Error::invalid_value())?;
80 for elem in value.split(',') {
81 let elem = elem.trim();
82 if elem.is_empty() {
83 continue;
84 }
85
86 let elem = elem.parse().map_err(|_| Error::invalid_value())?;
87 out.push(elem);
88 }
89 }
90
91 if empty {
92 Ok(None)
93 } else {
94 Ok(Some(out))
95 }
96}
97
98pub fn encode_comma_delimited<I>(elements: I, values: &mut ToValues)
99where
100 I: IntoIterator,
101 I::Item: fmt::Display,
102{
103 let mut out = String::new();
104 let mut it = elements.into_iter();
105 if let Some(elem) = it.next() {
106 write!(out, "{}", elem).unwrap();
107
108 for elem in it {
109 write!(out, ", {}", elem).unwrap();
110 }
111 }
112 let value = HeaderValue::from_str(&out).expect("failed to encode header");
113 values.append(value);
114}
115
116pub fn test_decode<H>(values: &[&str], expected: &H)
117where
118 H: Header + PartialEq + fmt::Debug,
119{
120 let mut map = HeaderMap::new();
121 for value in values {
122 let value = HeaderValue::from_str(value).unwrap();
123 map.append(H::name().clone(), value);
124 }
125
126 let header = map.typed_get::<H>().unwrap().unwrap();
127 assert_eq!(&header, expected);
128}
129
130pub fn test_encode<H>(header: &H, expected: &[&str])
131where
132 H: Header,
133{
134 let mut map = HeaderMap::new();
135 map.typed_insert(header);
136
137 let values = map.get_all(H::name()).iter().collect::<Vec<_>>();
138 assert_eq!(values.len(), expected.len());
139 for (value, expected) in values.iter().zip(expected) {
140 assert_eq!(value, expected);
141 }
142}
143
144pub fn test_round_trip<H>(header: &H, expected: &[&str])
145where
146 H: Header + PartialEq + fmt::Debug,
147{
148 let mut map = HeaderMap::new();
149 map.typed_insert(header);
150
151 let values = map.get_all(H::name()).iter().collect::<Vec<_>>();
152 assert_eq!(values.len(), expected.len());
153 for (value, expected) in values.iter().zip(expected) {
154 assert_eq!(value, expected);
155 }
156
157 let actual = map.typed_get::<H>().unwrap().unwrap();
158 assert_eq!(header, &actual);
159}