1use crate::{error::Error, Result};
2
3use std::{
4 iter::{FromIterator, Map},
5 result::Result as StdResult,
6 str::FromStr,
7};
8
9use http::{header::HeaderName, HeaderMap, HeaderValue};
10use js_sys::Array;
11use wasm_bindgen::JsValue;
12use worker_sys::ext::HeadersExt;
13
14pub struct Headers(pub web_sys::Headers);
17
18impl std::fmt::Debug for Headers {
19 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20 f.write_str("Headers {\n")?;
21 for (k, v) in self.entries() {
22 f.write_str(&format!("{k} = {v}\n"))?;
23 }
24 f.write_str("}\n")
25 }
26}
27
28impl Headers {
29 pub fn new() -> Self {
31 Default::default()
32 }
33
34 pub fn get(&self, name: &str) -> Result<Option<String>> {
37 self.0.get(name).map_err(Error::from)
38 }
39
40 pub fn is_empty(&self) -> bool {
42 self.keys().next().is_none()
43 }
44
45 pub fn has(&self, name: &str) -> Result<bool> {
48 self.0.has(name).map_err(Error::from)
49 }
50
51 pub fn append(&self, name: &str, value: &str) -> Result<()> {
53 self.0.append(name, value).map_err(Error::from)
54 }
55
56 pub fn set(&self, name: &str, value: &str) -> Result<()> {
59 self.0.set(name, value).map_err(Error::from)
60 }
61
62 pub fn delete(&self, name: &str) -> Result<()> {
66 self.0.delete(name).map_err(Error::from)
67 }
68
69 pub fn entries(&self) -> HeaderIterator {
71 self.0
72 .entries()
73 .into_iter()
74 .map((|a| a.unwrap().into()) as F1)
76 .map(|a: Array| (a.get(0).as_string().unwrap(), a.get(1).as_string().unwrap()))
78 }
79
80 pub fn keys(&self) -> impl Iterator<Item = String> {
83 self.0
84 .keys()
85 .into_iter()
86 .map(|a| a.unwrap().as_string().unwrap())
88 }
89
90 pub fn values(&self) -> impl Iterator<Item = String> {
93 self.0
94 .values()
95 .into_iter()
96 .map(|a| a.unwrap().as_string().unwrap())
98 }
99
100 pub fn get_all(&self, name: &str) -> Result<Vec<String>> {
102 let array = self.0.get_all(name);
103 array
104 .iter()
105 .map(|v| {
106 v.as_string()
107 .ok_or_else(|| Error::JsError("Invalid header value".into()))
108 })
109 .collect()
110 }
111}
112
113impl Default for Headers {
114 fn default() -> Self {
115 Headers(web_sys::Headers::new().unwrap())
117 }
118}
119
120type F1 = fn(StdResult<JsValue, JsValue>) -> Array;
121type HeaderIterator = Map<Map<js_sys::IntoIter, F1>, fn(Array) -> (String, String)>;
122
123impl IntoIterator for &Headers {
124 type Item = (String, String);
125
126 type IntoIter = HeaderIterator;
127
128 fn into_iter(self) -> Self::IntoIter {
129 self.entries()
130 }
131}
132
133impl<T: AsRef<str>> FromIterator<(T, T)> for Headers {
134 fn from_iter<U: IntoIterator<Item = (T, T)>>(iter: U) -> Self {
135 let headers = Headers::new();
136 iter.into_iter().for_each(|(name, value)| {
137 headers.append(name.as_ref(), value.as_ref()).ok();
138 });
139 headers
140 }
141}
142
143impl<'a, T: AsRef<str>> FromIterator<&'a (T, T)> for Headers {
144 fn from_iter<U: IntoIterator<Item = &'a (T, T)>>(iter: U) -> Self {
145 let headers = Headers::new();
146 iter.into_iter().for_each(|(name, value)| {
147 headers.append(name.as_ref(), value.as_ref()).ok();
148 });
149 headers
150 }
151}
152
153impl AsRef<JsValue> for Headers {
154 fn as_ref(&self) -> &JsValue {
155 &self.0
156 }
157}
158
159impl From<&HeaderMap> for Headers {
160 fn from(map: &HeaderMap) -> Self {
161 map.keys()
162 .flat_map(|name| {
163 map.get_all(name)
164 .into_iter()
165 .map(move |value| (name.to_string(), value.to_str().unwrap().to_owned()))
166 })
167 .collect()
168 }
169}
170
171impl From<HeaderMap> for Headers {
172 fn from(map: HeaderMap) -> Self {
173 (&map).into()
174 }
175}
176
177impl From<&Headers> for HeaderMap {
178 fn from(headers: &Headers) -> Self {
179 headers
180 .into_iter()
181 .map(|(name, value)| {
182 (
183 HeaderName::from_str(&name).unwrap(),
184 HeaderValue::from_str(&value).unwrap(),
185 )
186 })
187 .collect()
188 }
189}
190
191impl From<Headers> for HeaderMap {
192 fn from(headers: Headers) -> Self {
193 (&headers).into()
194 }
195}
196
197impl Clone for Headers {
198 fn clone(&self) -> Self {
199 Headers(web_sys::Headers::new_with_headers(&self.0).unwrap())
201 }
202}