http_tunnel_common/utils/
headers.rs1use http::{HeaderMap, HeaderName, HeaderValue};
2use std::collections::HashMap;
3
4pub fn headers_to_map(headers: &HeaderMap) -> HashMap<String, Vec<String>> {
7 let mut map: HashMap<String, Vec<String>> = HashMap::new();
8
9 for (name, value) in headers.iter() {
10 let key = name.as_str().to_string();
11 let val = value.to_str().unwrap_or("").to_string();
12
13 map.entry(key).or_default().push(val);
14 }
15
16 map
17}
18
19pub fn map_to_headers(map: &HashMap<String, Vec<String>>) -> HeaderMap {
21 let mut headers = HeaderMap::new();
22
23 for (name, values) in map.iter() {
24 if let Ok(header_name) = HeaderName::from_bytes(name.as_bytes()) {
25 for value in values {
26 if let Ok(header_value) = HeaderValue::from_str(value) {
27 headers.append(header_name.clone(), header_value);
28 }
29 }
30 }
31 }
32
33 headers
34}
35
36#[cfg(test)]
37mod tests {
38 use super::*;
39
40 #[test]
41 fn test_headers_to_map_empty() {
42 let headers = HeaderMap::new();
43 let map = headers_to_map(&headers);
44 assert!(map.is_empty());
45 }
46
47 #[test]
48 fn test_headers_to_map_single() {
49 let mut headers = HeaderMap::new();
50 headers.insert("content-type", "application/json".parse().unwrap());
51
52 let map = headers_to_map(&headers);
53 assert_eq!(map.len(), 1);
54 assert_eq!(map.get("content-type").unwrap(), &vec!["application/json"]);
55 }
56
57 #[test]
58 fn test_headers_to_map_multiple() {
59 let mut headers = HeaderMap::new();
60 headers.insert("content-type", "application/json".parse().unwrap());
61 headers.insert("authorization", "Bearer token123".parse().unwrap());
62 headers.insert("x-custom-header", "custom-value".parse().unwrap());
63
64 let map = headers_to_map(&headers);
65 assert_eq!(map.len(), 3);
66 assert_eq!(map.get("content-type").unwrap(), &vec!["application/json"]);
67 assert_eq!(map.get("authorization").unwrap(), &vec!["Bearer token123"]);
68 assert_eq!(map.get("x-custom-header").unwrap(), &vec!["custom-value"]);
69 }
70
71 #[test]
72 fn test_headers_to_map_multiple_values() {
73 let mut headers = HeaderMap::new();
74 headers.insert("set-cookie", "session=abc".parse().unwrap());
75 headers.append("set-cookie", "token=xyz".parse().unwrap());
76
77 let map = headers_to_map(&headers);
78 assert_eq!(map.len(), 1);
79
80 let cookies = map.get("set-cookie").unwrap();
81 assert_eq!(cookies.len(), 2);
82 assert!(cookies.contains(&"session=abc".to_string()));
83 assert!(cookies.contains(&"token=xyz".to_string()));
84 }
85
86 #[test]
87 fn test_map_to_headers_empty() {
88 let map: HashMap<String, Vec<String>> = HashMap::new();
89 let headers = map_to_headers(&map);
90 assert!(headers.is_empty());
91 }
92
93 #[test]
94 fn test_map_to_headers_single() {
95 let mut map = HashMap::new();
96 map.insert(
97 "content-type".to_string(),
98 vec!["application/json".to_string()],
99 );
100
101 let headers = map_to_headers(&map);
102 assert_eq!(headers.len(), 1);
103 assert_eq!(headers.get("content-type").unwrap(), "application/json");
104 }
105
106 #[test]
107 fn test_map_to_headers_multiple() {
108 let mut map = HashMap::new();
109 map.insert("content-type".to_string(), vec!["text/plain".to_string()]);
110 map.insert("host".to_string(), vec!["example.com".to_string()]);
111 map.insert("user-agent".to_string(), vec!["test-agent".to_string()]);
112
113 let headers = map_to_headers(&map);
114 assert_eq!(headers.len(), 3);
115 assert_eq!(headers.get("content-type").unwrap(), "text/plain");
116 assert_eq!(headers.get("host").unwrap(), "example.com");
117 assert_eq!(headers.get("user-agent").unwrap(), "test-agent");
118 }
119
120 #[test]
121 fn test_map_to_headers_multiple_values() {
122 let mut map = HashMap::new();
123 map.insert(
124 "set-cookie".to_string(),
125 vec!["session=abc".to_string(), "token=xyz".to_string()],
126 );
127
128 let headers = map_to_headers(&map);
129
130 let cookies: Vec<_> = headers
132 .get_all("set-cookie")
133 .iter()
134 .map(|v| v.to_str().unwrap())
135 .collect();
136
137 assert_eq!(cookies.len(), 2);
138 assert!(cookies.contains(&"session=abc"));
139 assert!(cookies.contains(&"token=xyz"));
140 }
141
142 #[test]
143 fn test_roundtrip_conversion() {
144 let mut original = HeaderMap::new();
145 original.insert("content-type", "application/json".parse().unwrap());
146 original.insert("authorization", "Bearer token".parse().unwrap());
147 original.insert("x-request-id", "req-123".parse().unwrap());
148
149 let map = headers_to_map(&original);
151 let converted = map_to_headers(&map);
152
153 assert_eq!(converted.len(), original.len());
155 assert_eq!(
156 converted.get("content-type").unwrap(),
157 original.get("content-type").unwrap()
158 );
159 assert_eq!(
160 converted.get("authorization").unwrap(),
161 original.get("authorization").unwrap()
162 );
163 assert_eq!(
164 converted.get("x-request-id").unwrap(),
165 original.get("x-request-id").unwrap()
166 );
167 }
168
169 #[test]
170 fn test_roundtrip_with_multiple_values() {
171 let mut original = HeaderMap::new();
172 original.insert("accept", "text/html".parse().unwrap());
173 original.append("accept", "application/json".parse().unwrap());
174 original.insert("cookie", "session=abc".parse().unwrap());
175 original.append("cookie", "token=xyz".parse().unwrap());
176
177 let map = headers_to_map(&original);
178 let converted = map_to_headers(&map);
179
180 let accept_values: Vec<_> = converted
182 .get_all("accept")
183 .iter()
184 .map(|v| v.to_str().unwrap())
185 .collect();
186 assert_eq!(accept_values.len(), 2);
187 assert!(accept_values.contains(&"text/html"));
188 assert!(accept_values.contains(&"application/json"));
189
190 let cookie_values: Vec<_> = converted
192 .get_all("cookie")
193 .iter()
194 .map(|v| v.to_str().unwrap())
195 .collect();
196 assert_eq!(cookie_values.len(), 2);
197 assert!(cookie_values.contains(&"session=abc"));
198 assert!(cookie_values.contains(&"token=xyz"));
199 }
200
201 #[test]
202 fn test_map_to_headers_invalid_header_name() {
203 let mut map = HashMap::new();
204 map.insert("valid-header".to_string(), vec!["value".to_string()]);
205 map.insert("invalid header".to_string(), vec!["value".to_string()]); let headers = map_to_headers(&map);
208
209 assert_eq!(headers.len(), 1);
211 assert!(headers.get("valid-header").is_some());
212 assert!(headers.get("invalid header").is_none());
213 }
214
215 #[test]
216 fn test_headers_to_map_non_utf8_handling() {
217 let mut headers = HeaderMap::new();
218 headers.insert("content-type", "application/json".parse().unwrap());
219
220 let non_utf8_value = HeaderValue::from_bytes(&[0xFF, 0xFE]).unwrap();
223 headers.insert("x-binary-header", non_utf8_value);
224
225 let map = headers_to_map(&headers);
226
227 assert_eq!(map.get("x-binary-header").unwrap(), &vec![""]);
229 assert_eq!(map.get("content-type").unwrap(), &vec!["application/json"]);
230 }
231}