#![allow(dead_code, clippy::useless_conversion)]
mod charset;
mod common;
mod content_disposition;
mod entity;
pub(crate) mod error;
mod http_date;
pub(crate) mod method;
pub(crate) mod parsing;
mod raw;
pub use charset::Charset;
pub use common::*;
pub use content_disposition::*;
pub use entity::EntityTag;
use http::HeaderValue;
pub use http_date::HttpDate;
pub use raw::{Raw, RawLike};
use self::sealed::HeaderClone;
pub trait Header: 'static + HeaderClone + Send + Sync {
fn header_name() -> &'static str
where
Self: Sized;
fn parse_header<'a, T>(raw: &'a T) -> error::Result<Self>
where
T: RawLike<'a>,
Self: Sized;
fn fmt_header(&self, f: &mut Formatter) -> std::fmt::Result;
}
mod sealed {
use super::Header;
#[doc(hidden)]
pub trait HeaderClone {
fn clone_box(&self) -> Box<dyn Header + Send + Sync>;
}
impl<T: Header + Clone> HeaderClone for T {
#[inline]
fn clone_box(&self) -> Box<dyn Header + Send + Sync> {
Box::new(self.clone())
}
}
}
#[allow(missing_debug_implementations)]
pub struct Formatter<'a, 'b: 'a>(Multi<'a, 'b>);
#[allow(unused)]
enum Multi<'a, 'b: 'a> {
Line(&'a str, &'a mut std::fmt::Formatter<'b>),
Join(bool, &'a mut std::fmt::Formatter<'b>),
Raw(&'a mut raw::Raw),
}
impl<'a, 'b> Formatter<'a, 'b> {
pub fn fmt_line(&mut self, line: &dyn std::fmt::Display) -> std::fmt::Result {
use std::fmt::Write;
match self.0 {
Multi::Line(name, ref mut f) => {
f.write_str(name)?;
f.write_str(": ")?;
write!(NewlineReplacer(*f), "{}", line)?;
f.write_str("\r\n")
}
Multi::Join(ref mut first, ref mut f) => {
if !*first {
f.write_str(", ")?;
} else {
*first = false;
}
write!(NewlineReplacer(*f), "{}", line)
}
Multi::Raw(ref mut raw) => {
let mut s = String::new();
write!(NewlineReplacer(&mut s), "{}", line)?;
raw.push(s);
Ok(())
}
}
}
fn danger_fmt_line_without_newline_replacer<T: std::fmt::Display>(
&mut self,
line: &T,
) -> std::fmt::Result {
use std::fmt::Write;
match self.0 {
Multi::Line(name, ref mut f) => {
f.write_str(name)?;
f.write_str(": ")?;
std::fmt::Display::fmt(line, f)?;
f.write_str("\r\n")
}
Multi::Join(ref mut first, ref mut f) => {
if !*first {
f.write_str(", ")?;
} else {
*first = false;
}
std::fmt::Display::fmt(line, f)
}
Multi::Raw(ref mut raw) => {
let mut s = String::new();
write!(s, "{}", line)?;
raw.push(s);
Ok(())
}
}
}
}
struct NewlineReplacer<'a, F: std::fmt::Write + 'a>(&'a mut F);
impl<'a, F: std::fmt::Write + 'a> std::fmt::Write for NewlineReplacer<'a, F> {
#[inline]
fn write_str(&mut self, s: &str) -> std::fmt::Result {
let mut since = 0;
for (i, &byte) in s.as_bytes().iter().enumerate() {
if byte == b'\r' || byte == b'\n' {
self.0.write_str(&s[since..i])?;
self.0.write_str(" ")?;
since = i + 1;
}
}
if since < s.len() { self.0.write_str(&s[since..]) } else { Ok(()) }
}
#[inline]
fn write_fmt(&mut self, args: std::fmt::Arguments) -> std::fmt::Result {
std::fmt::write(self, args)
}
}
pub trait StandardHeader: Header + Sized {
fn http_header_name() -> ::http::header::HeaderName;
}
impl<'a> RawLike<'a> for &'a HeaderValue {
type IntoIter = ::std::iter::Once<&'a [u8]>;
fn len(&'a self) -> usize {
1
}
fn one(&'a self) -> Option<&'a [u8]> {
Some(self.as_bytes())
}
fn iter(&'a self) -> Self::IntoIter {
::std::iter::once(self.as_bytes())
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! standard_header {
($local:ident, $hname:ident) => {
impl $crate::header::StandardHeader for $local {
#[inline]
fn http_header_name() -> ::http::header::HeaderName {
::http::header::$hname
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __deref__ {
($from:ty => $to:ty) => {
impl ::std::ops::Deref for $from {
type Target = $to;
#[inline]
fn deref(&self) -> &$to {
&self.0
}
}
impl ::std::ops::DerefMut for $from {
#[inline]
fn deref_mut(&mut self) -> &mut $to {
&mut self.0
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __tm__ {
($id:ident, $tm:ident{$($tf:item)*}) => {
#[allow(unused_imports)]
#[cfg(test)]
mod $tm{
use std::str;
use $crate::header::*;
use mime::*;
use $crate::method::Method;
use super::$id as HeaderField;
$($tf)*
}
}
}
#[macro_export]
macro_rules! header {
($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)*) => {
$(#[$a])*
#[derive(Clone, Debug, PartialEq)]
pub struct $id(pub Vec<$item>);
$crate::__deref__!($id => Vec<$item>);
impl $crate::header::Header for $id {
fn header_name() -> &'static str {
static NAME: &'static str = $n;
NAME
}
#[inline]
fn parse_header<'a, T>(raw: &'a T) -> $crate::Result<Self>
where T: $crate::header::RawLike<'a>
{
$crate::header::parsing::from_comma_delimited(raw).map($id)
}
#[inline]
fn fmt_header(&self, f: &mut $crate::header::Formatter) -> ::std::fmt::Result {
f.fmt_line(self)
}
}
impl ::std::fmt::Display for $id {
#[inline]
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
$crate::header::parsing::fmt_comma_delimited(f, &self.0[..])
}
}
};
($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)+) => {
$(#[$a])*
#[derive(Clone, Debug, PartialEq)]
pub struct $id(pub Vec<$item>);
$crate::__deref__!($id => Vec<$item>);
impl $crate::header::Header for $id {
#[inline]
fn header_name() -> &'static str {
static NAME: &'static str = $n;
NAME
}
#[inline]
fn parse_header<'a, T>(raw: &'a T) -> $crate::Result<Self>
where T: $crate::header::RawLike<'a>
{
$crate::header::parsing::from_comma_delimited(raw).map($id)
}
#[inline]
fn fmt_header(&self, f: &mut $crate::header::Formatter) -> ::std::fmt::Result {
f.fmt_line(self)
}
}
impl ::std::fmt::Display for $id {
#[inline]
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
$crate::header::parsing::fmt_comma_delimited(f, &self.0[..])
}
}
};
($(#[$a:meta])*($id:ident, $n:expr) => [$value:ty]) => {
$(#[$a])*
#[derive(Clone, Debug, PartialEq)]
pub struct $id(pub $value);
$crate::__deref__!($id => $value);
impl $crate::header::Header for $id {
#[inline]
fn header_name() -> &'static str {
static NAME: &'static str = $n;
NAME
}
#[inline]
fn parse_header<'a, T>(raw: &'a T) -> $crate::header::error::Result<Self>
where T: $crate::header::RawLike<'a>
{
$crate::header::parsing::from_one_raw_str(raw).map($id)
}
#[inline]
fn fmt_header(&self, f: &mut $crate::header::Formatter) -> ::std::fmt::Result {
f.fmt_line(self)
}
}
impl ::std::fmt::Display for $id {
#[inline]
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
::std::fmt::Display::fmt(&self.0, f)
}
}
};
($(#[$a:meta])*($id:ident, $n:expr) => danger [$value:ty]) => {
$(#[$a])*
#[derive(Clone, Debug, PartialEq)]
pub struct $id(pub $value);
$crate::__deref__!($id => $value);
impl $crate::header::Header for $id {
#[inline]
fn header_name() -> &'static str {
static NAME: &'static str = $n;
NAME
}
#[inline]
fn parse_header<'a, T>(raw: &'a T) -> $crate::Result<Self>
where T: $crate::header::RawLike<'a>
{
$crate::header::parsing::from_one_raw_str(raw).map($id)
}
#[inline]
fn fmt_header(&self, f: &mut $crate::header::Formatter) -> ::std::fmt::Result {
f.danger_fmt_line_without_newline_replacer(self)
}
}
impl ::std::fmt::Display for $id {
#[inline]
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
::std::fmt::Display::fmt(&self.0, f)
}
}
};
($(#[$a:meta])*($id:ident, $n:expr) => Cow[$value:ty]) => {
$(#[$a])*
#[derive(Clone, Debug, PartialEq)]
pub struct $id(::std::borrow::Cow<'static,$value>);
impl $id {
pub fn new<I: Into<::std::borrow::Cow<'static,$value>>>(value: I) -> Self {
$id(value.into())
}
}
impl ::std::ops::Deref for $id {
type Target = $value;
#[inline]
fn deref(&self) -> &Self::Target {
&(self.0)
}
}
impl $crate::header::Header for $id {
#[inline]
fn header_name() -> &'static str {
static NAME: &'static str = $n;
NAME
}
#[inline]
fn parse_header<'a, T>(raw: &'a T) -> $crate::Result<Self>
where T: $crate::header::RawLike<'a>
{
$crate::header::parsing::from_one_raw_str::<_, <$value as ::std::borrow::ToOwned>::Owned>(raw).map($id::new)
}
#[inline]
fn fmt_header(&self, f: &mut $crate::header::Formatter) -> ::std::fmt::Result {
f.fmt_line(self)
}
}
impl ::std::fmt::Display for $id {
#[inline]
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
::std::fmt::Display::fmt(&self.0, f)
}
}
};
($(#[$a:meta])*($id:ident, $n:expr) => {Any / ($item:ty)+}) => {
$(#[$a])*
#[derive(Clone, Debug, PartialEq)]
pub enum $id {
Any,
Items(Vec<$item>),
}
impl $crate::header::Header for $id {
#[inline]
fn header_name() -> &'static str {
static NAME: &'static str = $n;
NAME
}
#[inline]
fn parse_header<'a, T>(raw: &'a T) -> $crate::header::error::Result<Self>
where T: $crate::header::RawLike<'a>
{
if let Some(l) = raw.one() {
if l == b"*" {
return Ok($id::Any)
}
}
$crate::header::parsing::from_comma_delimited(raw).map($id::Items)
}
#[inline]
fn fmt_header(&self, f: &mut $crate::header::Formatter) -> ::std::fmt::Result {
f.fmt_line(self)
}
}
impl ::std::fmt::Display for $id {
#[inline]
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
match *self {
$id::Any => f.write_str("*"),
$id::Items(ref fields) => $crate::header::parsing::fmt_comma_delimited(
f, &fields[..])
}
}
}
};
($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)* $tm:ident{$($tf:item)*}) => {
header! {
$(#[$a])*
($id, $n) => ($item)*
}
$crate::__tm__! { $id, $tm { $($tf)* }}
};
($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)+ $tm:ident{$($tf:item)*}) => {
header! {
$(#[$a])*
($id, $n) => ($item)+
}
$crate::__tm__! { $id, $tm { $($tf)* }}
};
($(#[$a:meta])*($id:ident, $n:expr) => [$item:ty] $tm:ident{$($tf:item)*}) => {
header! {
$(#[$a])*
($id, $n) => [$item]
}
$crate::__tm__! { $id, $tm { $($tf)* }}
};
($(#[$a:meta])*($id:ident, $n:expr) => danger [$item:ty] $tm:ident{$($tf:item)*}) => {
header! {
$(#[$a])*
($id, $n) => danger [$item]
}
$crate::__tm__! { $id, $tm { $($tf)* }}
};
($(#[$a:meta])*($id:ident, $n:expr) => Cow[$item:ty] $tm:ident{$($tf:item)*}) => {
header! {
$(#[$a])*
($id, $n) => Cow[$item]
}
$crate::__tm__! { $id, $tm { $($tf)* }}
};
($(#[$a:meta])*($id:ident, $n:expr) => {Any / ($item:ty)+} $tm:ident{$($tf:item)*}) => {
header! {
$(#[$a])*
($id, $n) => {Any / ($item)+}
}
$crate::__tm__! { $id, $tm { $($tf)* }}
};
}