1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-05-19 16:58:14 +00:00
actix-web/actix-web/src/http/header/macros.rs

321 lines
11 KiB
Rust
Raw Normal View History

2021-06-25 11:25:50 +00:00
macro_rules! common_header_test_module {
2021-04-15 21:05:06 +00:00
($id:ident, $tm:ident{$($tf:item)*}) => {
#[cfg(test)]
mod $tm {
#![allow(unused_imports)]
use ::core::str;
use ::actix_http::{Method, test};
use ::mime::*;
use $crate::http::header::{self, *};
use super::{$id as HeaderField, *};
2021-04-15 21:05:06 +00:00
$($tf)*
}
}
}
2021-06-25 11:25:50 +00:00
#[cfg(test)]
macro_rules! common_header_test {
2021-04-15 21:05:06 +00:00
($id:ident, $raw:expr) => {
#[test]
fn $id() {
use ::actix_http::test;
2021-04-15 21:05:06 +00:00
let raw = $raw;
let headers = raw.iter().map(|x| x.to_vec()).collect::<Vec<_>>();
2021-04-15 21:05:06 +00:00
let mut req = test::TestRequest::default();
for item in headers {
req = req.append_header((HeaderField::name(), item)).take();
2021-04-15 21:05:06 +00:00
}
2021-04-15 21:05:06 +00:00
let req = req.finish();
let value = HeaderField::parse(&req);
2021-04-15 21:05:06 +00:00
let result = format!("{}", value.unwrap());
let expected = ::std::string::String::from_utf8(raw[0].to_vec()).unwrap();
2021-04-15 21:05:06 +00:00
let result_cmp: Vec<String> = result
.to_ascii_lowercase()
.split(' ')
.map(|x| x.to_owned())
.collect();
let expected_cmp: Vec<String> = expected
.to_ascii_lowercase()
.split(' ')
.map(|x| x.to_owned())
.collect();
2021-04-15 21:05:06 +00:00
assert_eq!(result_cmp.concat(), expected_cmp.concat());
}
};
($id:ident, $raw:expr, $exp:expr) => {
2021-04-15 21:05:06 +00:00
#[test]
fn $id() {
use actix_http::test;
let headers = $raw.iter().map(|x| x.to_vec()).collect::<Vec<_>>();
2021-04-15 21:05:06 +00:00
let mut req = test::TestRequest::default();
for item in headers {
req.append_header((HeaderField::name(), item));
2021-04-15 21:05:06 +00:00
}
2021-04-15 21:05:06 +00:00
let req = req.finish();
let val = HeaderField::parse(&req);
let exp: ::core::option::Option<HeaderField> = $exp;
// test parsing
assert_eq!(val.ok(), exp);
// test formatting
if let Some(exp) = exp {
2021-04-15 21:05:06 +00:00
let raw = &($raw)[..];
let mut iter = raw.iter().map(|b| str::from_utf8(&b[..]).unwrap());
let mut joined = String::new();
if let Some(s) = iter.next() {
2021-04-15 21:05:06 +00:00
joined.push_str(s);
for s in iter {
joined.push_str(", ");
joined.push_str(s);
}
2021-04-15 21:05:06 +00:00
}
assert_eq!(format!("{}", exp), joined);
2021-04-15 21:05:06 +00:00
}
}
};
}
2021-06-25 11:25:50 +00:00
macro_rules! common_header {
// TODO: these docs are wrong, there's no $n or $nn
2021-12-02 15:25:39 +00:00
// $attrs:meta: Attributes associated with the header item (usually docs)
2021-04-15 21:05:06 +00:00
// $id:ident: Identifier of the header
// $n:expr: Lowercase name of the header
// $nn:expr: Nice name of the header
// List header, zero or more items
2021-12-02 15:25:39 +00:00
($(#[$attrs:meta])*($id:ident, $name:expr) => ($item:ty)*) => {
$(#[$attrs])*
#[derive(Debug, Clone, PartialEq, Eq, ::derive_more::Deref, ::derive_more::DerefMut)]
2021-04-15 21:05:06 +00:00
pub struct $id(pub Vec<$item>);
2021-12-02 15:25:39 +00:00
2021-04-15 21:05:06 +00:00
impl $crate::http::header::Header for $id {
#[inline]
fn name() -> $crate::http::header::HeaderName {
$name
}
2021-04-15 21:05:06 +00:00
#[inline]
fn parse<M: $crate::HttpMessage>(msg: &M) -> Result<Self, $crate::error::ParseError> {
let headers = msg.headers().get_all(Self::name());
$crate::http::header::from_comma_delimited(headers).map($id)
2021-04-15 21:05:06 +00:00
}
}
impl ::core::fmt::Display for $id {
2021-04-15 21:05:06 +00:00
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
2021-04-15 21:05:06 +00:00
$crate::http::header::fmt_comma_delimited(f, &self.0[..])
}
}
impl $crate::http::header::TryIntoHeaderValue for $id {
2021-04-15 21:05:06 +00:00
type Error = $crate::http::header::InvalidHeaderValue;
#[inline]
2021-04-15 21:05:06 +00:00
fn try_into_value(self) -> Result<$crate::http::header::HeaderValue, Self::Error> {
use ::core::fmt::Write;
2021-04-15 21:05:06 +00:00
let mut writer = $crate::http::header::Writer::new();
let _ = write!(&mut writer, "{}", self);
$crate::http::header::HeaderValue::from_maybe_shared(writer.take())
}
}
};
2021-04-15 21:05:06 +00:00
// List header, one or more items
2021-12-02 15:25:39 +00:00
($(#[$attrs:meta])*($id:ident, $name:expr) => ($item:ty)+) => {
$(#[$attrs])*
#[derive(Debug, Clone, PartialEq, Eq, ::derive_more::Deref, ::derive_more::DerefMut)]
2021-04-15 21:05:06 +00:00
pub struct $id(pub Vec<$item>);
2021-04-15 21:05:06 +00:00
impl $crate::http::header::Header for $id {
#[inline]
fn name() -> $crate::http::header::HeaderName {
$name
}
2021-04-15 21:05:06 +00:00
#[inline]
fn parse<M: $crate::HttpMessage>(msg: &M) -> Result<Self, $crate::error::ParseError>{
let headers = msg.headers().get_all(Self::name());
$crate::http::header::from_comma_delimited(headers)
.and_then(|items| {
if items.is_empty() {
Err($crate::error::ParseError::Header)
} else {
Ok($id(items))
}
})
2021-04-15 21:05:06 +00:00
}
}
impl ::core::fmt::Display for $id {
2021-04-15 21:05:06 +00:00
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
2021-04-15 21:05:06 +00:00
$crate::http::header::fmt_comma_delimited(f, &self.0[..])
}
}
impl $crate::http::header::TryIntoHeaderValue for $id {
2021-04-15 21:05:06 +00:00
type Error = $crate::http::header::InvalidHeaderValue;
#[inline]
2021-04-15 21:05:06 +00:00
fn try_into_value(self) -> Result<$crate::http::header::HeaderValue, Self::Error> {
use ::core::fmt::Write;
2021-04-15 21:05:06 +00:00
let mut writer = $crate::http::header::Writer::new();
let _ = write!(&mut writer, "{}", self);
$crate::http::header::HeaderValue::from_maybe_shared(writer.take())
}
}
};
2021-04-15 21:05:06 +00:00
// Single value header
2021-12-02 15:25:39 +00:00
($(#[$attrs:meta])*($id:ident, $name:expr) => [$value:ty]) => {
$(#[$attrs])*
#[derive(Debug, Clone, PartialEq, Eq, ::derive_more::Deref, ::derive_more::DerefMut)]
2021-04-15 21:05:06 +00:00
pub struct $id(pub $value);
2021-04-15 21:05:06 +00:00
impl $crate::http::header::Header for $id {
#[inline]
fn name() -> $crate::http::header::HeaderName {
$name
}
2021-04-15 21:05:06 +00:00
#[inline]
fn parse<M: $crate::HttpMessage>(msg: &M) -> Result<Self, $crate::error::ParseError> {
let header = msg.headers().get(Self::name());
$crate::http::header::from_one_raw_str(header).map($id)
2021-04-15 21:05:06 +00:00
}
}
impl ::core::fmt::Display for $id {
2021-04-15 21:05:06 +00:00
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
::core::fmt::Display::fmt(&self.0, f)
2021-04-15 21:05:06 +00:00
}
}
impl $crate::http::header::TryIntoHeaderValue for $id {
2021-04-15 21:05:06 +00:00
type Error = $crate::http::header::InvalidHeaderValue;
#[inline]
2021-04-15 21:05:06 +00:00
fn try_into_value(self) -> Result<$crate::http::header::HeaderValue, Self::Error> {
self.0.try_into_value()
}
}
};
2021-04-15 21:05:06 +00:00
// List header, one or more items with "*" option
2021-12-02 15:25:39 +00:00
($(#[$attrs:meta])*($id:ident, $name:expr) => {Any / ($item:ty)+}) => {
$(#[$attrs])*
#[derive(Clone, Debug, PartialEq, Eq)]
2021-04-15 21:05:06 +00:00
pub enum $id {
/// Any value is a match
Any,
2021-04-15 21:05:06 +00:00
/// Only the listed items are a match
Items(Vec<$item>),
}
2021-04-15 21:05:06 +00:00
impl $crate::http::header::Header for $id {
#[inline]
fn name() -> $crate::http::header::HeaderName {
$name
}
2021-04-15 21:05:06 +00:00
#[inline]
fn parse<M: $crate::HttpMessage>(msg: &M) -> Result<Self, $crate::error::ParseError> {
let is_any = msg
.headers()
.get(Self::name())
.and_then(|hdr| hdr.to_str().ok())
.map(|hdr| hdr.trim() == "*");
2021-04-15 21:05:06 +00:00
if let Some(true) = is_any {
2021-04-15 21:05:06 +00:00
Ok($id::Any)
} else {
let headers = msg.headers().get_all(Self::name());
Ok($id::Items($crate::http::header::from_comma_delimited(headers)?))
2021-04-15 21:05:06 +00:00
}
}
}
impl ::core::fmt::Display for $id {
2021-04-15 21:05:06 +00:00
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
2021-04-15 21:05:06 +00:00
match *self {
$id::Any => f.write_str("*"),
$id::Items(ref fields) =>
$crate::http::header::fmt_comma_delimited(f, &fields[..])
2021-04-15 21:05:06 +00:00
}
}
}
impl $crate::http::header::TryIntoHeaderValue for $id {
2021-04-15 21:05:06 +00:00
type Error = $crate::http::header::InvalidHeaderValue;
#[inline]
2021-04-15 21:05:06 +00:00
fn try_into_value(self) -> Result<$crate::http::header::HeaderValue, Self::Error> {
use ::core::fmt::Write;
2021-04-15 21:05:06 +00:00
let mut writer = $crate::http::header::Writer::new();
let _ = write!(&mut writer, "{}", self);
$crate::http::header::HeaderValue::from_maybe_shared(writer.take())
}
}
};
// optional test module
2021-12-02 15:25:39 +00:00
($(#[$attrs:meta])*($id:ident, $name:expr) => ($item:ty)* $tm:ident{$($tf:item)*}) => {
2021-06-25 11:25:50 +00:00
crate::http::header::common_header! {
2021-12-02 15:25:39 +00:00
$(#[$attrs])*
2021-04-15 21:05:06 +00:00
($id, $name) => ($item)*
}
2021-06-25 11:25:50 +00:00
crate::http::header::common_header_test_module! { $id, $tm { $($tf)* }}
2021-04-15 21:05:06 +00:00
};
2021-12-02 15:25:39 +00:00
($(#[$attrs:meta])*($id:ident, $n:expr) => ($item:ty)+ $tm:ident{$($tf:item)*}) => {
2021-06-25 11:25:50 +00:00
crate::http::header::common_header! {
2021-12-02 15:25:39 +00:00
$(#[$attrs])*
2021-04-15 21:05:06 +00:00
($id, $n) => ($item)+
}
2021-06-25 11:25:50 +00:00
crate::http::header::common_header_test_module! { $id, $tm { $($tf)* }}
2021-04-15 21:05:06 +00:00
};
2021-12-02 15:25:39 +00:00
($(#[$attrs:meta])*($id:ident, $name:expr) => [$item:ty] $tm:ident{$($tf:item)*}) => {
2021-06-25 11:25:50 +00:00
crate::http::header::common_header! {
2021-12-02 15:25:39 +00:00
$(#[$attrs])* ($id, $name) => [$item]
2021-04-15 21:05:06 +00:00
}
2021-06-25 11:25:50 +00:00
crate::http::header::common_header_test_module! { $id, $tm { $($tf)* }}
2021-04-15 21:05:06 +00:00
};
2021-12-02 15:25:39 +00:00
($(#[$attrs:meta])*($id:ident, $name:expr) => {Any / ($item:ty)+} $tm:ident{$($tf:item)*}) => {
2021-06-25 11:25:50 +00:00
crate::http::header::common_header! {
2021-12-02 15:25:39 +00:00
$(#[$attrs])*
2021-04-15 21:05:06 +00:00
($id, $name) => {Any / ($item)+}
}
2021-06-25 11:25:50 +00:00
crate::http::header::common_header_test_module! { $id, $tm { $($tf)* }}
2021-04-15 21:05:06 +00:00
};
}
2021-06-25 11:25:50 +00:00
2023-07-17 01:38:12 +00:00
pub(crate) use common_header;
2021-06-25 11:25:50 +00:00
#[cfg(test)]
pub(crate) use common_header_test;
2023-07-17 01:38:12 +00:00
pub(crate) use common_header_test_module;