1#![allow(dead_code, clippy::useless_conversion)]
2
3mod charset;
4mod common;
5mod content_disposition;
6mod entity;
7pub(crate) mod error;
8mod http_date;
9pub(crate) mod method;
10pub(crate) mod parsing;
11mod raw;
12
13pub use charset::Charset;
14pub use common::*;
15pub use content_disposition::*;
16pub use entity::EntityTag;
17use http::HeaderValue;
18pub use http_date::HttpDate;
19pub use raw::{Raw, RawLike};
20
21use self::sealed::HeaderClone;
22
23pub trait Header: 'static + HeaderClone + Send + Sync {
28 fn header_name() -> &'static str
32 where
33 Self: Sized;
34
35 fn parse_header<'a, T>(raw: &'a T) -> error::Result<Self>
43 where
44 T: RawLike<'a>,
45 Self: Sized;
46
47 fn fmt_header(&self, f: &mut Formatter) -> std::fmt::Result;
61}
62
63mod sealed {
64 use super::Header;
65
66 #[doc(hidden)]
67 pub trait HeaderClone {
68 fn clone_box(&self) -> Box<dyn Header + Send + Sync>;
69 }
70
71 impl<T: Header + Clone> HeaderClone for T {
72 #[inline]
73 fn clone_box(&self) -> Box<dyn Header + Send + Sync> {
74 Box::new(self.clone())
75 }
76 }
77}
78
79#[allow(missing_debug_implementations)]
81pub struct Formatter<'a, 'b: 'a>(Multi<'a, 'b>);
82
83#[allow(unused)]
84enum Multi<'a, 'b: 'a> {
85 Line(&'a str, &'a mut std::fmt::Formatter<'b>),
86 Join(bool, &'a mut std::fmt::Formatter<'b>),
87 Raw(&'a mut raw::Raw),
88}
89
90impl<'a, 'b> Formatter<'a, 'b> {
91 pub fn fmt_line(&mut self, line: &dyn std::fmt::Display) -> std::fmt::Result {
103 use std::fmt::Write;
104 match self.0 {
105 Multi::Line(name, ref mut f) => {
106 f.write_str(name)?;
107 f.write_str(": ")?;
108 write!(NewlineReplacer(*f), "{}", line)?;
109 f.write_str("\r\n")
110 }
111 Multi::Join(ref mut first, ref mut f) => {
112 if !*first {
113 f.write_str(", ")?;
114 } else {
115 *first = false;
116 }
117 write!(NewlineReplacer(*f), "{}", line)
118 }
119 Multi::Raw(ref mut raw) => {
120 let mut s = String::new();
121 write!(NewlineReplacer(&mut s), "{}", line)?;
122 raw.push(s);
123 Ok(())
124 }
125 }
126 }
127
128 fn danger_fmt_line_without_newline_replacer<T: std::fmt::Display>(
129 &mut self,
130 line: &T,
131 ) -> std::fmt::Result {
132 use std::fmt::Write;
133 match self.0 {
134 Multi::Line(name, ref mut f) => {
135 f.write_str(name)?;
136 f.write_str(": ")?;
137 std::fmt::Display::fmt(line, f)?;
138 f.write_str("\r\n")
139 }
140 Multi::Join(ref mut first, ref mut f) => {
141 if !*first {
142 f.write_str(", ")?;
143 } else {
144 *first = false;
145 }
146 std::fmt::Display::fmt(line, f)
147 }
148 Multi::Raw(ref mut raw) => {
149 let mut s = String::new();
150 write!(s, "{}", line)?;
151 raw.push(s);
152 Ok(())
153 }
154 }
155 }
156}
157
158struct NewlineReplacer<'a, F: std::fmt::Write + 'a>(&'a mut F);
159
160impl<'a, F: std::fmt::Write + 'a> std::fmt::Write for NewlineReplacer<'a, F> {
161 #[inline]
162 fn write_str(&mut self, s: &str) -> std::fmt::Result {
163 let mut since = 0;
164 for (i, &byte) in s.as_bytes().iter().enumerate() {
165 if byte == b'\r' || byte == b'\n' {
166 self.0.write_str(&s[since..i])?;
167 self.0.write_str(" ")?;
168 since = i + 1;
169 }
170 }
171 if since < s.len() { self.0.write_str(&s[since..]) } else { Ok(()) }
172 }
173
174 #[inline]
175 fn write_fmt(&mut self, args: std::fmt::Arguments) -> std::fmt::Result {
176 std::fmt::write(self, args)
177 }
178}
179
180pub trait StandardHeader: Header + Sized {
183 fn http_header_name() -> ::http::header::HeaderName;
185}
186
187impl<'a> RawLike<'a> for &'a HeaderValue {
188 type IntoIter = ::std::iter::Once<&'a [u8]>;
189
190 fn len(&'a self) -> usize {
191 1
192 }
193
194 fn one(&'a self) -> Option<&'a [u8]> {
195 Some(self.as_bytes())
196 }
197
198 fn iter(&'a self) -> Self::IntoIter {
199 ::std::iter::once(self.as_bytes())
200 }
201}
202
203#[doc(hidden)]
204#[macro_export]
205macro_rules! standard_header {
206 ($local:ident, $hname:ident) => {
207 impl $crate::header::StandardHeader for $local {
208 #[inline]
209 fn http_header_name() -> ::http::header::HeaderName {
210 ::http::header::$hname
211 }
212 }
213 };
214}
215
216#[doc(hidden)]
217#[macro_export]
218macro_rules! __deref__ {
219 ($from:ty => $to:ty) => {
220 impl ::std::ops::Deref for $from {
221 type Target = $to;
222
223 #[inline]
224 fn deref(&self) -> &$to {
225 &self.0
226 }
227 }
228
229 impl ::std::ops::DerefMut for $from {
230 #[inline]
231 fn deref_mut(&mut self) -> &mut $to {
232 &mut self.0
233 }
234 }
235 };
236}
237
238#[doc(hidden)]
239#[macro_export]
240macro_rules! __tm__ {
241 ($id:ident, $tm:ident{$($tf:item)*}) => {
242 #[allow(unused_imports)]
243 #[cfg(test)]
244 mod $tm{
245 use std::str;
246 use $crate::header::*;
247 use mime::*;
248 use $crate::method::Method;
249 use super::$id as HeaderField;
250 $($tf)*
251 }
252
253 }
254}
255
256#[macro_export]
258macro_rules! header {
259 ($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)*) => {
266 $(#[$a])*
267 #[derive(Clone, Debug, PartialEq)]
268 pub struct $id(pub Vec<$item>);
269 $crate::__deref__!($id => Vec<$item>);
270 impl $crate::header::Header for $id {
271 fn header_name() -> &'static str {
272 static NAME: &'static str = $n;
273 NAME
274 }
275 #[inline]
276 fn parse_header<'a, T>(raw: &'a T) -> $crate::Result<Self>
277 where T: $crate::header::RawLike<'a>
278 {
279 $crate::header::parsing::from_comma_delimited(raw).map($id)
280 }
281 #[inline]
282 fn fmt_header(&self, f: &mut $crate::header::Formatter) -> ::std::fmt::Result {
283 f.fmt_line(self)
284 }
285 }
286 impl ::std::fmt::Display for $id {
287 #[inline]
288 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
289 $crate::header::parsing::fmt_comma_delimited(f, &self.0[..])
290 }
291 }
292 };
293 ($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)+) => {
295 $(#[$a])*
296 #[derive(Clone, Debug, PartialEq)]
297 pub struct $id(pub Vec<$item>);
298 $crate::__deref__!($id => Vec<$item>);
299 impl $crate::header::Header for $id {
300 #[inline]
301 fn header_name() -> &'static str {
302 static NAME: &'static str = $n;
303 NAME
304 }
305 #[inline]
306 fn parse_header<'a, T>(raw: &'a T) -> $crate::Result<Self>
307 where T: $crate::header::RawLike<'a>
308 {
309 $crate::header::parsing::from_comma_delimited(raw).map($id)
310 }
311 #[inline]
312 fn fmt_header(&self, f: &mut $crate::header::Formatter) -> ::std::fmt::Result {
313 f.fmt_line(self)
314 }
315 }
316 impl ::std::fmt::Display for $id {
317 #[inline]
318 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
319 $crate::header::parsing::fmt_comma_delimited(f, &self.0[..])
320 }
321 }
322 };
323 ($(#[$a:meta])*($id:ident, $n:expr) => [$value:ty]) => {
325 $(#[$a])*
326 #[derive(Clone, Debug, PartialEq)]
327 pub struct $id(pub $value);
328 $crate::__deref__!($id => $value);
329 impl $crate::header::Header for $id {
330 #[inline]
331 fn header_name() -> &'static str {
332 static NAME: &'static str = $n;
333 NAME
334 }
335 #[inline]
336 fn parse_header<'a, T>(raw: &'a T) -> $crate::header::error::Result<Self>
337 where T: $crate::header::RawLike<'a>
338 {
339 $crate::header::parsing::from_one_raw_str(raw).map($id)
340 }
341 #[inline]
342 fn fmt_header(&self, f: &mut $crate::header::Formatter) -> ::std::fmt::Result {
343 f.fmt_line(self)
344 }
345 }
346 impl ::std::fmt::Display for $id {
347 #[inline]
348 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
349 ::std::fmt::Display::fmt(&self.0, f)
350 }
351 }
352 };
353 ($(#[$a:meta])*($id:ident, $n:expr) => danger [$value:ty]) => {
355 $(#[$a])*
356 #[derive(Clone, Debug, PartialEq)]
357 pub struct $id(pub $value);
358 $crate::__deref__!($id => $value);
359 impl $crate::header::Header for $id {
360 #[inline]
361 fn header_name() -> &'static str {
362 static NAME: &'static str = $n;
363 NAME
364 }
365 #[inline]
366 fn parse_header<'a, T>(raw: &'a T) -> $crate::Result<Self>
367 where T: $crate::header::RawLike<'a>
368 {
369 $crate::header::parsing::from_one_raw_str(raw).map($id)
370 }
371 #[inline]
372 fn fmt_header(&self, f: &mut $crate::header::Formatter) -> ::std::fmt::Result {
373 f.danger_fmt_line_without_newline_replacer(self)
374 }
375 }
376 impl ::std::fmt::Display for $id {
377 #[inline]
378 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
379 ::std::fmt::Display::fmt(&self.0, f)
380 }
381 }
382 };
383 ($(#[$a:meta])*($id:ident, $n:expr) => Cow[$value:ty]) => {
385 $(#[$a])*
386 #[derive(Clone, Debug, PartialEq)]
387 pub struct $id(::std::borrow::Cow<'static,$value>);
388 impl $id {
389 pub fn new<I: Into<::std::borrow::Cow<'static,$value>>>(value: I) -> Self {
391 $id(value.into())
392 }
393 }
394 impl ::std::ops::Deref for $id {
395 type Target = $value;
396 #[inline]
397 fn deref(&self) -> &Self::Target {
398 &(self.0)
399 }
400 }
401 impl $crate::header::Header for $id {
402 #[inline]
403 fn header_name() -> &'static str {
404 static NAME: &'static str = $n;
405 NAME
406 }
407 #[inline]
408 fn parse_header<'a, T>(raw: &'a T) -> $crate::Result<Self>
409 where T: $crate::header::RawLike<'a>
410 {
411 $crate::header::parsing::from_one_raw_str::<_, <$value as ::std::borrow::ToOwned>::Owned>(raw).map($id::new)
412 }
413 #[inline]
414 fn fmt_header(&self, f: &mut $crate::header::Formatter) -> ::std::fmt::Result {
415 f.fmt_line(self)
416 }
417 }
418 impl ::std::fmt::Display for $id {
419 #[inline]
420 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
421 ::std::fmt::Display::fmt(&self.0, f)
422 }
423 }
424 };
425 ($(#[$a:meta])*($id:ident, $n:expr) => {Any / ($item:ty)+}) => {
427 $(#[$a])*
428 #[derive(Clone, Debug, PartialEq)]
429 pub enum $id {
430 Any,
432 Items(Vec<$item>),
434 }
435 impl $crate::header::Header for $id {
436 #[inline]
437 fn header_name() -> &'static str {
438 static NAME: &'static str = $n;
439 NAME
440 }
441 #[inline]
442 fn parse_header<'a, T>(raw: &'a T) -> $crate::header::error::Result<Self>
443 where T: $crate::header::RawLike<'a>
444 {
445 if let Some(l) = raw.one() {
447 if l == b"*" {
448 return Ok($id::Any)
449 }
450 }
451 $crate::header::parsing::from_comma_delimited(raw).map($id::Items)
452 }
453 #[inline]
454 fn fmt_header(&self, f: &mut $crate::header::Formatter) -> ::std::fmt::Result {
455 f.fmt_line(self)
456 }
457 }
458 impl ::std::fmt::Display for $id {
459 #[inline]
460 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
461 match *self {
462 $id::Any => f.write_str("*"),
463 $id::Items(ref fields) => $crate::header::parsing::fmt_comma_delimited(
464 f, &fields[..])
465 }
466 }
467 }
468 };
469
470 ($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)* $tm:ident{$($tf:item)*}) => {
472 header! {
473 $(#[$a])*
474 ($id, $n) => ($item)*
475 }
476
477 $crate::__tm__! { $id, $tm { $($tf)* }}
478 };
479 ($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)+ $tm:ident{$($tf:item)*}) => {
480 header! {
481 $(#[$a])*
482 ($id, $n) => ($item)+
483 }
484
485 $crate::__tm__! { $id, $tm { $($tf)* }}
486 };
487 ($(#[$a:meta])*($id:ident, $n:expr) => [$item:ty] $tm:ident{$($tf:item)*}) => {
488 header! {
489 $(#[$a])*
490 ($id, $n) => [$item]
491 }
492
493 $crate::__tm__! { $id, $tm { $($tf)* }}
494 };
495 ($(#[$a:meta])*($id:ident, $n:expr) => danger [$item:ty] $tm:ident{$($tf:item)*}) => {
496 header! {
497 $(#[$a])*
498 ($id, $n) => danger [$item]
499 }
500
501 $crate::__tm__! { $id, $tm { $($tf)* }}
502 };
503 ($(#[$a:meta])*($id:ident, $n:expr) => Cow[$item:ty] $tm:ident{$($tf:item)*}) => {
504 header! {
505 $(#[$a])*
506 ($id, $n) => Cow[$item]
507 }
508
509 $crate::__tm__! { $id, $tm { $($tf)* }}
510 };
511 ($(#[$a:meta])*($id:ident, $n:expr) => {Any / ($item:ty)+} $tm:ident{$($tf:item)*}) => {
512 header! {
513 $(#[$a])*
514 ($id, $n) => {Any / ($item)+}
515 }
516
517 $crate::__tm__! { $id, $tm { $($tf)* }}
518 };
519}