actix_web/http/header/
macros.rs1macro_rules! common_header_test_module {
2 ($id:ident, $tm:ident{$($tf:item)*}) => {
3 #[cfg(test)]
4 mod $tm {
5 #![allow(unused_imports)]
6
7 use ::core::str;
8
9 use ::actix_http::{Method, test};
10 use ::mime::*;
11
12 use $crate::http::header::{self, *};
13 use super::{$id as HeaderField, *};
14
15 $($tf)*
16 }
17 }
18}
19
20#[cfg(test)]
21macro_rules! common_header_test {
22 ($id:ident, $raw:expr) => {
23 #[test]
24 fn $id() {
25 use ::actix_http::test;
26
27 let raw = $raw;
28 let headers = raw.iter().map(|x| x.to_vec()).collect::<Vec<_>>();
29
30 let mut req = test::TestRequest::default();
31
32 for item in headers {
33 req = req.append_header((HeaderField::name(), item)).take();
34 }
35
36 let req = req.finish();
37 let value = HeaderField::parse(&req);
38
39 let result = format!("{}", value.unwrap());
40 let expected = ::std::string::String::from_utf8(raw[0].to_vec()).unwrap();
41
42 let result_cmp: Vec<String> = result
43 .to_ascii_lowercase()
44 .split(' ')
45 .map(|x| x.to_owned())
46 .collect();
47 let expected_cmp: Vec<String> = expected
48 .to_ascii_lowercase()
49 .split(' ')
50 .map(|x| x.to_owned())
51 .collect();
52
53 assert_eq!(result_cmp.concat(), expected_cmp.concat());
54 }
55 };
56
57 ($id:ident, $raw:expr, $exp:expr) => {
58 #[test]
59 fn $id() {
60 use actix_http::test;
61
62 let headers = $raw.iter().map(|x| x.to_vec()).collect::<Vec<_>>();
63 let mut req = test::TestRequest::default();
64
65 for item in headers {
66 req.append_header((HeaderField::name(), item));
67 }
68
69 let req = req.finish();
70 let val = HeaderField::parse(&req);
71
72 let exp: ::core::option::Option<HeaderField> = $exp;
73
74 assert_eq!(val.ok(), exp);
76
77 if let Some(exp) = exp {
79 let raw = &($raw)[..];
80 let mut iter = raw.iter().map(|b| str::from_utf8(&b[..]).unwrap());
81 let mut joined = String::new();
82 if let Some(s) = iter.next() {
83 joined.push_str(s);
84 for s in iter {
85 joined.push_str(", ");
86 joined.push_str(s);
87 }
88 }
89 assert_eq!(format!("{}", exp), joined);
90 }
91 }
92 };
93}
94
95macro_rules! common_header {
96 ($(#[$attrs:meta])*($id:ident, $name:expr) => ($item:ty)*) => {
104 $(#[$attrs])*
105 #[derive(Debug, Clone, PartialEq, Eq, ::derive_more::Deref, ::derive_more::DerefMut)]
106 pub struct $id(pub Vec<$item>);
107
108 impl $crate::http::header::Header for $id {
109 #[inline]
110 fn name() -> $crate::http::header::HeaderName {
111 $name
112 }
113
114 #[inline]
115 fn parse<M: $crate::HttpMessage>(msg: &M) -> Result<Self, $crate::error::ParseError> {
116 let headers = msg.headers().get_all(Self::name());
117 $crate::http::header::from_comma_delimited(headers).map($id)
118 }
119 }
120
121 impl ::core::fmt::Display for $id {
122 #[inline]
123 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
124 $crate::http::header::fmt_comma_delimited(f, &self.0[..])
125 }
126 }
127
128 impl $crate::http::header::TryIntoHeaderValue for $id {
129 type Error = $crate::http::header::InvalidHeaderValue;
130
131 #[inline]
132 fn try_into_value(self) -> Result<$crate::http::header::HeaderValue, Self::Error> {
133 use ::core::fmt::Write;
134 let mut writer = $crate::http::header::Writer::new();
135 let _ = write!(&mut writer, "{}", self);
136 $crate::http::header::HeaderValue::from_maybe_shared(writer.take())
137 }
138 }
139 };
140
141 ($(#[$attrs:meta])*($id:ident, $name:expr) => ($item:ty)+) => {
143 $(#[$attrs])*
144 #[derive(Debug, Clone, PartialEq, Eq, ::derive_more::Deref, ::derive_more::DerefMut)]
145 pub struct $id(pub Vec<$item>);
146
147 impl $crate::http::header::Header for $id {
148 #[inline]
149 fn name() -> $crate::http::header::HeaderName {
150 $name
151 }
152
153 #[inline]
154 fn parse<M: $crate::HttpMessage>(msg: &M) -> Result<Self, $crate::error::ParseError>{
155 let headers = msg.headers().get_all(Self::name());
156
157 $crate::http::header::from_comma_delimited(headers)
158 .and_then(|items| {
159 if items.is_empty() {
160 Err($crate::error::ParseError::Header)
161 } else {
162 Ok($id(items))
163 }
164 })
165 }
166 }
167
168 impl ::core::fmt::Display for $id {
169 #[inline]
170 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
171 $crate::http::header::fmt_comma_delimited(f, &self.0[..])
172 }
173 }
174
175 impl $crate::http::header::TryIntoHeaderValue for $id {
176 type Error = $crate::http::header::InvalidHeaderValue;
177
178 #[inline]
179 fn try_into_value(self) -> Result<$crate::http::header::HeaderValue, Self::Error> {
180 use ::core::fmt::Write;
181 let mut writer = $crate::http::header::Writer::new();
182 let _ = write!(&mut writer, "{}", self);
183 $crate::http::header::HeaderValue::from_maybe_shared(writer.take())
184 }
185 }
186 };
187
188 ($(#[$attrs:meta])*($id:ident, $name:expr) => [$value:ty]) => {
190 $(#[$attrs])*
191 #[derive(Debug, Clone, PartialEq, Eq, ::derive_more::Deref, ::derive_more::DerefMut)]
192 pub struct $id(pub $value);
193
194 impl $crate::http::header::Header for $id {
195 #[inline]
196 fn name() -> $crate::http::header::HeaderName {
197 $name
198 }
199
200 #[inline]
201 fn parse<M: $crate::HttpMessage>(msg: &M) -> Result<Self, $crate::error::ParseError> {
202 let header = msg.headers().get(Self::name());
203 $crate::http::header::from_one_raw_str(header).map($id)
204 }
205 }
206
207 impl ::core::fmt::Display for $id {
208 #[inline]
209 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
210 ::core::fmt::Display::fmt(&self.0, f)
211 }
212 }
213
214 impl $crate::http::header::TryIntoHeaderValue for $id {
215 type Error = $crate::http::header::InvalidHeaderValue;
216
217 #[inline]
218 fn try_into_value(self) -> Result<$crate::http::header::HeaderValue, Self::Error> {
219 self.0.try_into_value()
220 }
221 }
222 };
223
224 ($(#[$attrs:meta])*($id:ident, $name:expr) => {Any / ($item:ty)+}) => {
226 $(#[$attrs])*
227 #[derive(Clone, Debug, PartialEq, Eq)]
228 pub enum $id {
229 Any,
231
232 Items(Vec<$item>),
234 }
235
236 impl $crate::http::header::Header for $id {
237 #[inline]
238 fn name() -> $crate::http::header::HeaderName {
239 $name
240 }
241
242 #[inline]
243 fn parse<M: $crate::HttpMessage>(msg: &M) -> Result<Self, $crate::error::ParseError> {
244 let is_any = msg
245 .headers()
246 .get(Self::name())
247 .and_then(|hdr| hdr.to_str().ok())
248 .map(|hdr| hdr.trim() == "*");
249
250 if let Some(true) = is_any {
251 Ok($id::Any)
252 } else {
253 let headers = msg.headers().get_all(Self::name());
254 Ok($id::Items($crate::http::header::from_comma_delimited(headers)?))
255 }
256 }
257 }
258
259 impl ::core::fmt::Display for $id {
260 #[inline]
261 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
262 match *self {
263 $id::Any => f.write_str("*"),
264 $id::Items(ref fields) =>
265 $crate::http::header::fmt_comma_delimited(f, &fields[..])
266 }
267 }
268 }
269
270 impl $crate::http::header::TryIntoHeaderValue for $id {
271 type Error = $crate::http::header::InvalidHeaderValue;
272
273 #[inline]
274 fn try_into_value(self) -> Result<$crate::http::header::HeaderValue, Self::Error> {
275 use ::core::fmt::Write;
276 let mut writer = $crate::http::header::Writer::new();
277 let _ = write!(&mut writer, "{}", self);
278 $crate::http::header::HeaderValue::from_maybe_shared(writer.take())
279 }
280 }
281 };
282
283 ($(#[$attrs:meta])*($id:ident, $name:expr) => ($item:ty)* $tm:ident{$($tf:item)*}) => {
285 crate::http::header::common_header! {
286 $(#[$attrs])*
287 ($id, $name) => ($item)*
288 }
289
290 crate::http::header::common_header_test_module! { $id, $tm { $($tf)* }}
291 };
292 ($(#[$attrs:meta])*($id:ident, $n:expr) => ($item:ty)+ $tm:ident{$($tf:item)*}) => {
293 crate::http::header::common_header! {
294 $(#[$attrs])*
295 ($id, $n) => ($item)+
296 }
297
298 crate::http::header::common_header_test_module! { $id, $tm { $($tf)* }}
299 };
300 ($(#[$attrs:meta])*($id:ident, $name:expr) => [$item:ty] $tm:ident{$($tf:item)*}) => {
301 crate::http::header::common_header! {
302 $(#[$attrs])* ($id, $name) => [$item]
303 }
304
305 crate::http::header::common_header_test_module! { $id, $tm { $($tf)* }}
306 };
307 ($(#[$attrs:meta])*($id:ident, $name:expr) => {Any / ($item:ty)+} $tm:ident{$($tf:item)*}) => {
308 crate::http::header::common_header! {
309 $(#[$attrs])*
310 ($id, $name) => {Any / ($item)+}
311 }
312
313 crate::http::header::common_header_test_module! { $id, $tm { $($tf)* }}
314 };
315}
316
317pub(crate) use common_header;
318#[cfg(test)]
319pub(crate) use common_header_test;
320pub(crate) use common_header_test_module;