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 has(&self, name: &str) -> Result<bool> {
43 self.0.has(name).map_err(Error::from)
44 }
45
46 pub fn append(&self, name: &str, value: &str) -> Result<()> {
48 self.0.append(name, value).map_err(Error::from)
49 }
50
51 pub fn set(&self, name: &str, value: &str) -> Result<()> {
54 self.0.set(name, value).map_err(Error::from)
55 }
56
57 pub fn delete(&self, name: &str) -> Result<()> {
61 self.0.delete(name).map_err(Error::from)
62 }
63
64 pub fn entries(&self) -> HeaderIterator {
66 self.0
67 .entries()
68 .into_iter()
69 .map((|a| a.unwrap().into()) as F1)
71 .map(|a: Array| (a.get(0).as_string().unwrap(), a.get(1).as_string().unwrap()))
73 }
74
75 pub fn keys(&self) -> impl Iterator<Item = String> {
78 self.0
79 .keys()
80 .into_iter()
81 .map(|a| a.unwrap().as_string().unwrap())
83 }
84
85 pub fn values(&self) -> impl Iterator<Item = String> {
88 self.0
89 .values()
90 .into_iter()
91 .map(|a| a.unwrap().as_string().unwrap())
93 }
94
95 pub fn get_all(&self, name: &str) -> Result<Vec<String>> {
97 let array = self.0.get_all(name);
98 array
99 .iter()
100 .map(|v| {
101 v.as_string()
102 .ok_or_else(|| Error::JsError("Invalid header value".into()))
103 })
104 .collect()
105 }
106}
107
108impl Default for Headers {
109 fn default() -> Self {
110 Headers(web_sys::Headers::new().unwrap())
112 }
113}
114
115type F1 = fn(StdResult<JsValue, JsValue>) -> Array;
116type HeaderIterator = Map<Map<js_sys::IntoIter, F1>, fn(Array) -> (String, String)>;
117
118impl IntoIterator for &Headers {
119 type Item = (String, String);
120
121 type IntoIter = HeaderIterator;
122
123 fn into_iter(self) -> Self::IntoIter {
124 self.entries()
125 }
126}
127
128impl<T: AsRef<str>> FromIterator<(T, T)> for Headers {
129 fn from_iter<U: IntoIterator<Item = (T, T)>>(iter: U) -> Self {
130 let headers = Headers::new();
131 iter.into_iter().for_each(|(name, value)| {
132 headers.append(name.as_ref(), value.as_ref()).ok();
133 });
134 headers
135 }
136}
137
138impl<'a, T: AsRef<str>> FromIterator<&'a (T, T)> for Headers {
139 fn from_iter<U: IntoIterator<Item = &'a (T, T)>>(iter: U) -> Self {
140 let headers = Headers::new();
141 iter.into_iter().for_each(|(name, value)| {
142 headers.append(name.as_ref(), value.as_ref()).ok();
143 });
144 headers
145 }
146}
147
148impl AsRef<JsValue> for Headers {
149 fn as_ref(&self) -> &JsValue {
150 &self.0
151 }
152}
153
154impl From<&HeaderMap> for Headers {
155 fn from(map: &HeaderMap) -> Self {
156 map.keys()
157 .flat_map(|name| {
158 map.get_all(name)
159 .into_iter()
160 .map(move |value| (name.to_string(), value.to_str().unwrap().to_owned()))
161 })
162 .collect()
163 }
164}
165
166impl From<HeaderMap> for Headers {
167 fn from(map: HeaderMap) -> Self {
168 (&map).into()
169 }
170}
171
172impl From<&Headers> for HeaderMap {
173 fn from(headers: &Headers) -> Self {
174 headers
175 .into_iter()
176 .map(|(name, value)| {
177 (
178 HeaderName::from_str(&name).unwrap(),
179 HeaderValue::from_str(&value).unwrap(),
180 )
181 })
182 .collect()
183 }
184}
185
186impl From<Headers> for HeaderMap {
187 fn from(headers: Headers) -> Self {
188 (&headers).into()
189 }
190}
191
192impl Clone for Headers {
193 fn clone(&self) -> Self {
194 Headers(web_sys::Headers::new_with_headers(&self.0).unwrap())
196 }
197}