1use core::{fmt, ops::Deref};
4
5use crate::{
6 body::ResponseBody,
7 context::WebContext,
8 error::{Error, HeaderNotFound},
9 handler::{FromRequest, Responder},
10 http::{
11 WebResponse,
12 header::{self, HeaderMap, HeaderName, HeaderValue},
13 },
14};
15
16macro_rules! const_header_name {
17 ($n:expr ;) => {};
18 ($n:expr ; $i: ident $(, $rest:ident)*) => {
19 pub const $i: usize = $n;
20 const_header_name!($n + 1; $($rest),*);
21 };
22 ($($i:ident), +) => { const_header_name!(0; $($i),*); };
23}
24
25macro_rules! map_to_header_name {
26 ($($i:ident), +) => {
27 const fn map_to_header_name<const HEADER_NAME: usize>() -> header::HeaderName {
28 match HEADER_NAME {
29 $(
30 $i => header::$i,
31 )*
32 _ => unreachable!()
33 }
34 }
35 }
36}
37
38macro_rules! const_header_name_impl {
39 ($($i:ident), +) => {
40 const_header_name!($($i), +);
41 map_to_header_name!($($i), +);
42 }
43}
44
45const_header_name_impl!(
46 ACCEPT,
48 ACCEPT_ENCODING,
49 ACCEPT_LANGUAGE,
50 AUTHORIZATION,
51 CACHE_CONTROL,
52 CONNECTION,
53 CONTENT_TYPE,
54 CONTENT_LENGTH,
55 COOKIE,
56 DATE,
57 HOST,
58 ORIGIN,
59 REFERER,
60 USER_AGENT,
61 RANGE,
63 IF_MATCH,
64 IF_NONE_MATCH,
65 IF_MODIFIED_SINCE,
66 IF_UNMODIFIED_SINCE,
67 IF_RANGE,
68 CONTENT_DISPOSITION,
70 CONTENT_ENCODING,
71 CONTENT_LANGUAGE,
72 CONTENT_RANGE,
73 TRANSFER_ENCODING,
74 TE,
75 EXPECT,
76 UPGRADE,
78 SEC_WEBSOCKET_KEY,
79 SEC_WEBSOCKET_VERSION,
80 SEC_WEBSOCKET_PROTOCOL,
81 SEC_WEBSOCKET_EXTENSIONS,
82 FORWARDED,
84 VIA,
85 PROXY_AUTHORIZATION,
86 MAX_FORWARDS,
87 FROM,
88 PRAGMA,
89 DNT,
90 UPGRADE_INSECURE_REQUESTS,
91 ACCESS_CONTROL_REQUEST_METHOD,
92 ACCESS_CONTROL_REQUEST_HEADERS
93);
94
95pub struct HeaderRef<'a, const HEADER_NAME: usize>(&'a HeaderValue);
126
127impl<const HEADER_NAME: usize> fmt::Debug for HeaderRef<'_, HEADER_NAME> {
128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129 f.debug_struct("Header")
130 .field("name", &map_to_header_name::<HEADER_NAME>())
131 .field("value", &self.0)
132 .finish()
133 }
134}
135
136impl<const HEADER_NAME: usize> Deref for HeaderRef<'_, HEADER_NAME> {
137 type Target = HeaderValue;
138
139 fn deref(&self) -> &Self::Target {
140 self.0
141 }
142}
143
144impl<'a, 'r, C, B, const HEADER_NAME: usize> FromRequest<'a, WebContext<'r, C, B>> for HeaderRef<'a, HEADER_NAME> {
145 type Type<'b> = HeaderRef<'b, HEADER_NAME>;
146 type Error = Error;
147
148 #[inline]
149 async fn from_request(ctx: &'a WebContext<'r, C, B>) -> Result<Self, Self::Error> {
150 let name = map_to_header_name::<HEADER_NAME>();
151 ctx.req()
152 .headers()
153 .get(&name)
154 .map(HeaderRef)
155 .ok_or_else(|| Error::from_service(HeaderNotFound(name)))
156 }
157}
158
159impl<'a, 'r, C, B> FromRequest<'a, WebContext<'r, C, B>> for &'a HeaderMap {
160 type Type<'b> = &'b HeaderMap;
161 type Error = Error;
162
163 #[inline]
164 async fn from_request(ctx: &'a WebContext<'r, C, B>) -> Result<Self, Self::Error> {
165 Ok(ctx.req().headers())
166 }
167}
168
169impl<'a, 'r, C, B> FromRequest<'a, WebContext<'r, C, B>> for HeaderMap {
170 type Type<'b> = HeaderMap;
171 type Error = Error;
172
173 #[inline]
174 async fn from_request(ctx: &'a WebContext<'r, C, B>) -> Result<Self, Self::Error> {
175 Ok(ctx.req().headers().clone())
176 }
177}
178
179impl<'r, C, B> Responder<WebContext<'r, C, B>> for (HeaderName, HeaderValue) {
180 type Response = WebResponse;
181 type Error = Error;
182
183 async fn respond(self, ctx: WebContext<'r, C, B>) -> Result<Self::Response, Self::Error> {
184 let res = ctx.into_response(ResponseBody::empty());
185 Responder::<WebContext<'r, C, B>>::map(self, res)
186 }
187
188 fn map(self, mut res: Self::Response) -> Result<Self::Response, Self::Error> {
189 res.headers_mut().append(self.0, self.1);
190 Ok(res)
191 }
192}
193
194impl<'r, C, B, const N: usize> Responder<WebContext<'r, C, B>> for [(HeaderName, HeaderValue); N] {
195 type Response = WebResponse;
196 type Error = Error;
197
198 async fn respond(self, ctx: WebContext<'r, C, B>) -> Result<Self::Response, Self::Error> {
199 let res = ctx.into_response(ResponseBody::empty());
200 Responder::<WebContext<'r, C, B>>::map(self, res)
201 }
202
203 fn map(self, mut res: Self::Response) -> Result<Self::Response, Self::Error> {
204 for (k, v) in self {
205 res.headers_mut().append(k, v);
206 }
207 Ok(res)
208 }
209}
210
211impl<'r, C, B> Responder<WebContext<'r, C, B>> for Vec<(HeaderName, HeaderValue)> {
212 type Response = WebResponse;
213 type Error = Error;
214
215 async fn respond(self, ctx: WebContext<'r, C, B>) -> Result<Self::Response, Self::Error> {
216 let res = ctx.into_response(ResponseBody::empty());
217 Responder::<WebContext<'r, C, B>>::map(self, res)
218 }
219
220 fn map(self, mut res: Self::Response) -> Result<Self::Response, Self::Error> {
221 for (k, v) in self {
222 res.headers_mut().append(k, v);
223 }
224 Ok(res)
225 }
226}
227
228impl<'r, C, B> Responder<WebContext<'r, C, B>> for HeaderMap {
229 type Response = WebResponse;
230 type Error = Error;
231
232 async fn respond(self, ctx: WebContext<'r, C, B>) -> Result<Self::Response, Self::Error> {
233 let res = ctx.into_response(ResponseBody::empty());
234 Responder::<WebContext<'r, C, B>>::map(self, res)
235 }
236
237 fn map(self, mut res: Self::Response) -> Result<Self::Response, Self::Error> {
238 res.headers_mut().extend(self);
239 Ok(res)
240 }
241}
242
243#[cfg(test)]
244mod test {
245 use xitca_unsafe_collection::futures::NowOrPanic;
246
247 use super::*;
248
249 #[test]
250 fn extract_header() {
251 let mut req = WebContext::new_test(());
252 let mut req = req.as_web_ctx();
253 req.req_mut()
254 .headers_mut()
255 .insert(header::HOST, header::HeaderValue::from_static("996"));
256 req.req_mut()
257 .headers_mut()
258 .insert(header::ACCEPT_ENCODING, header::HeaderValue::from_static("251"));
259
260 assert_eq!(
261 HeaderRef::<'_, { super::ACCEPT_ENCODING }>::from_request(&req)
262 .now_or_panic()
263 .unwrap()
264 .deref(),
265 &header::HeaderValue::from_static("251")
266 );
267 assert_eq!(
268 HeaderRef::<'_, { super::HOST }>::from_request(&req)
269 .now_or_panic()
270 .unwrap()
271 .deref(),
272 &header::HeaderValue::from_static("996")
273 );
274 }
275}