1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-12-16 21:26:34 +00:00

improve typed header macro

This commit is contained in:
Rob Ede 2021-12-01 20:17:06 +00:00
parent 2f9c97461a
commit a75212695a
No known key found for this signature in database
GPG key ID: 97C636207D3EF933
28 changed files with 77 additions and 94 deletions

View file

@ -7,7 +7,7 @@ use self::Charset::*;
/// The string representation is normalized to upper case.
///
/// See <http://www.iana.org/assignments/character-sets/character-sets.xhtml>.
#[derive(Clone, Debug, PartialEq)]
#[derive(Debug, Clone, PartialEq, Eq)]
#[allow(non_camel_case_types)]
pub enum Charset {
/// US ASCII

View file

@ -31,7 +31,7 @@ pub struct ExtendedValue {
///
/// ## ABNF
///
/// ```text
/// ```plain
/// ext-value = charset "'" [ language ] "'" value-chars
/// ; like RFC 2231's <extended-initial-value>
/// ; (see [RFC 2231 §7])

View file

@ -8,7 +8,7 @@ use crate::{
helpers::MutWriter,
};
/// A timestamp with HTTP formatting and parsing.
/// A timestamp with HTTP-style formatting and parsing.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct HttpDate(SystemTime);

View file

@ -27,7 +27,7 @@ const MAX_FLOAT_QUALITY: f32 = 1.0;
///
/// [RFC7231 Section 5.3.1](https://tools.ietf.org/html/rfc7231#section-5.3.1)
/// gives more information on quality values in HTTP header fields.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Quality(u16);
impl Quality {
@ -80,7 +80,7 @@ impl TryFrom<f32> for Quality {
/// Represents an item with a quality value as defined in
/// [RFC 7231](https://tools.ietf.org/html/rfc7231#section-5.3.1).
#[derive(Clone, PartialEq, Debug)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct QualityItem<T> {
/// The wrapped contents of the field.
pub item: T,

View file

@ -66,7 +66,7 @@ mod route;
/// Creates resource handler, allowing multiple HTTP method guards.
///
/// # Syntax
/// ```text
/// ```plain
/// #[route("path", method="HTTP_METHOD"[, attributes])]
/// ```
///
@ -112,7 +112,7 @@ concat!("
Creates route handler with `actix_web::guard::", stringify!($variant), "`.
# Syntax
```text
```plain
#[", stringify!($method), r#"("path"[, attributes])]
```

View file

@ -16,7 +16,7 @@ crate::http::header::common_header! {
/// in-line image
///
/// # ABNF
/// ```text
/// ```plain
/// Accept = #( media-range [ accept-params ] )
///
/// media-range = ( "*/*"

View file

@ -12,7 +12,7 @@ crate::http::header::common_header! {
/// those charsets.
///
/// # ABNF
/// ```text
/// ```plain
/// Accept-Charset = 1#( ( charset / "*" ) [ weight ] )
/// ```
///

View file

@ -1,3 +1,5 @@
// TODO: reinstate module
use header::{Encoding, QualityItem};
header! {
@ -11,7 +13,7 @@ header! {
/// preferred.
///
/// # ABNF
/// ```text
/// ```plain
/// Accept-Encoding = #( codings [ weight ] )
/// codings = content-coding / "identity" / "*"
/// ```
@ -59,15 +61,17 @@ header! {
/// ])
/// );
/// ```
(AcceptEncoding, "Accept-Encoding") => (QualityItem<Encoding>)*
(AcceptEncoding, header::ACCEPT_ENCODING) => (QualityItem<Encoding>)*
test_parse_and_format {
// From the RFC
crate::http::header::common_header_test!(test1, vec![b"compress, gzip"]);
crate::http::header::common_header_test!(test2, vec![b""], Some(AcceptEncoding(vec![])));
crate::http::header::common_header_test!(test3, vec![b"*"]);
// Note: Removed quality 1 from gzip
crate::http::header::common_header_test!(test4, vec![b"compress;q=0.5, gzip"]);
// Note: Removed quality 1 from gzip
crate::http::header::common_header_test!(test5, vec![b"gzip, identity; q=0.5, *;q=0"]);
}

View file

@ -12,7 +12,7 @@ common_header! {
/// ranges defined in [RFC 4647 §2.1](https://datatracker.ietf.org/doc/html/rfc4647#section-2.1).
///
/// # ABNF
/// ```text
/// ```plain
/// Accept-Language = 1#( language-range [ weight ] )
/// language-range = (1*8ALPHA *("-" 1*8alphanum)) / "*"
/// alphanum = ALPHA / DIGIT
@ -54,7 +54,7 @@ common_header! {
/// ```
(AcceptLanguage, header::ACCEPT_LANGUAGE) => (QualityItem<AnyOrSome<LanguageTag>>)+
parse_and_fmt_tests {
test_parse_and_format {
common_header_test!(
example_from_rfc,
vec![b"da, en-gb;q=0.8, en;q=0.7"]

View file

@ -12,7 +12,7 @@ crate::http::header::common_header! {
/// with the resource.
///
/// # ABNF
/// ```text
/// ```plain
/// Allow = #method
/// ```
///

View file

@ -1,6 +1,8 @@
use std::fmt::{self, Write};
use std::str::FromStr;
use derive_more::{Deref, DerefMut};
use super::{fmt_comma_delimited, from_comma_delimited, Header, IntoHeaderValue, Writer};
use crate::http::header;
@ -14,7 +16,7 @@ use crate::http::header;
/// not imply that the same directive is to be given in the response.
///
/// # ABNF
/// ```text
/// ```plain
/// Cache-Control = 1#cache-directive
/// cache-directive = token [ "=" ( token / quoted-string ) ]
/// ```
@ -46,11 +48,9 @@ use crate::http::header;
/// CacheDirective::Extension("foo".to_owned(), Some("bar".to_owned())),
/// ]));
/// ```
#[derive(PartialEq, Clone, Debug)]
#[derive(Debug, Clone, PartialEq, Eq, Deref, DerefMut)]
pub struct CacheControl(pub Vec<CacheDirective>);
crate::http::header::common_header_deref!(CacheControl => Vec<CacheDirective>);
// TODO: this could just be the crate::http::header::common_header! macro
impl Header for CacheControl {
fn name() -> header::HeaderName {
@ -88,7 +88,7 @@ impl IntoHeaderValue for CacheControl {
}
/// `CacheControl` contains a list of these directives.
#[derive(PartialEq, Clone, Debug)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CacheDirective {
/// "no-cache"
NoCache,

View file

@ -220,7 +220,7 @@ impl DispositionParam {
/// itself, *Content-Disposition* has no effect.
///
/// # ABNF
/// ```text
/// ```plain
/// content-disposition = "Content-Disposition" ":"
/// disposition-type *( ";" disposition-parm )
///

View file

@ -1,7 +1,8 @@
use super::{QualityItem, CONTENT_LANGUAGE};
use language_tags::LanguageTag;
crate::http::header::common_header! {
use super::{common_header, QualityItem, CONTENT_LANGUAGE};
common_header! {
/// `Content-Language` header, defined
/// in [RFC 7231 §3.1.3.2](https://datatracker.ietf.org/doc/html/rfc7231#section-3.1.3.2)
///
@ -11,7 +12,7 @@ crate::http::header::common_header! {
/// representation.
///
/// # ABNF
/// ```text
/// ```plain
/// Content-Language = 1#language-tag
/// ```
///

View file

@ -74,7 +74,7 @@ crate::http::header::common_header! {
/// Content-Range, described in [RFC 7233](https://tools.ietf.org/html/rfc7233#section-4.2)
///
/// # ABNF
/// ```text
/// ```plain
/// Content-Range = byte-content-range
/// / other-content-range
///
@ -90,7 +90,7 @@ crate::http::header::common_header! {
/// other-content-range = other-range-unit SP other-range-resp
/// other-range-resp = *CHAR
/// ```
#[derive(PartialEq, Clone, Debug)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ContentRangeSpec {
/// Byte range
Bytes {

View file

@ -18,7 +18,7 @@ crate::http::header::common_header! {
/// this is an issue, it's possible to implement `Header` on a custom struct.
///
/// # ABNF
/// ```text
/// ```plain
/// Content-Type = media-type
/// ```
///
@ -110,5 +110,3 @@ impl ContentType {
ContentType(mime::APPLICATION_OCTET_STREAM)
}
}
impl Eq for ContentType {}

View file

@ -9,7 +9,7 @@ crate::http::header::common_header! {
/// message was originated.
///
/// # ABNF
/// ```text
/// ```plain
/// Date = HTTP-date
/// ```
///

View file

@ -26,7 +26,7 @@ fn check_slice_validity(slice: &str) -> bool {
/// `W/"xyzzy"`.
///
/// # ABNF
/// ```text
/// ```plain
/// entity-tag = [ weak ] opaque-tag
/// weak = %x57.2F ; "W/", case-sensitive
/// opaque-tag = DQUOTE *etagc DQUOTE

View file

@ -15,7 +15,7 @@ crate::http::header::common_header! {
/// prefixed by a weakness indicator.
///
/// # ABNF
/// ```text
/// ```plain
/// ETag = entity-tag
/// ```
///

View file

@ -12,7 +12,7 @@ crate::http::header::common_header! {
/// time.
///
/// # ABNF
/// ```text
/// ```plain
/// Expires = HTTP-date
/// ```
///

View file

@ -1,6 +1,6 @@
use super::{EntityTag, IF_MATCH};
use super::{common_header, EntityTag, IF_MATCH};
crate::http::header::common_header! {
common_header! {
/// `If-Match` header, defined
/// in [RFC 7232 §3.1](https://datatracker.ietf.org/doc/html/rfc7232#section-3.1)
///
@ -17,7 +17,7 @@ crate::http::header::common_header! {
/// there have been any changes to the representation data.
///
/// # ABNF
/// ```text
/// ```plain
/// If-Match = "*" / 1#entity-tag
/// ```
///

View file

@ -11,7 +11,7 @@ crate::http::header::common_header! {
/// data has not changed.
///
/// # ABNF
/// ```text
/// ```plain
/// If-Unmodified-Since = HTTP-date
/// ```
///

View file

@ -16,7 +16,7 @@ crate::http::header::common_header! {
/// the representation data.
///
/// # ABNF
/// ```text
/// ```plain
/// If-None-Match = "*" / 1#entity-tag
/// ```
///

View file

@ -25,7 +25,7 @@ use crate::HttpMessage;
/// in Range; otherwise, send me the entire representation.
///
/// # ABNF
/// ```text
/// ```plain
/// If-Range = entity-tag / HTTP-date
/// ```
///
@ -107,10 +107,11 @@ impl IntoHeaderValue for IfRange {
}
#[cfg(test)]
mod test_if_range {
mod test_parse_and_format {
use std::str;
use super::IfRange as HeaderField;
use crate::http::header::*;
use std::str;
crate::http::header::common_header_test!(test1, vec![b"Sat, 29 Oct 1994 19:43:31 GMT"]);
crate::http::header::common_header_test!(test2, vec![b"\"abc\""]);

View file

@ -11,7 +11,7 @@ crate::http::header::common_header! {
/// the user agent does not have an entity-tag for the representation.
///
/// # ABNF
/// ```text
/// ```plain
/// If-Unmodified-Since = HTTP-date
/// ```
///

View file

@ -10,7 +10,7 @@ crate::http::header::common_header! {
/// conclusion of handling the request.
///
/// # ABNF
/// ```text
/// ```plain
/// Expires = HTTP-date
/// ```
///

View file

@ -1,24 +1,3 @@
// TODO: replace with derive_more impl
macro_rules! common_header_deref {
($from:ty => $to:ty) => {
impl ::core::ops::Deref for $from {
type Target = $to;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl ::core::ops::DerefMut for $from {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
};
}
macro_rules! common_header_test_module {
($id:ident, $tm:ident{$($tf:item)*}) => {
#[allow(unused_imports)]
@ -105,17 +84,17 @@ macro_rules! common_header_test {
}
macro_rules! common_header {
// $a:meta: Attributes associated with the header item (usually docs)
// $attrs:meta: Attributes associated with the header item (usually docs)
// $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
($(#[$a:meta])*($id:ident, $name:expr) => ($item:ty)*) => {
$(#[$a])*
#[derive(Clone, Debug, PartialEq)]
($(#[$attrs:meta])*($id:ident, $name:expr) => ($item:ty)*) => {
$(#[$attrs])*
#[derive(Debug, Clone, PartialEq, Eq, ::derive_more::Deref, ::derive_more::DerefMut)]
pub struct $id(pub Vec<$item>);
crate::http::header::common_header_deref!($id => Vec<$item>);
impl $crate::http::header::Header for $id {
#[inline]
fn name() -> $crate::http::header::HeaderName {
@ -149,12 +128,11 @@ macro_rules! common_header {
};
// List header, one or more items
($(#[$a:meta])*($id:ident, $name:expr) => ($item:ty)+) => {
$(#[$a])*
#[derive(Clone, Debug, PartialEq)]
($(#[$attrs:meta])*($id:ident, $name:expr) => ($item:ty)+) => {
$(#[$attrs])*
#[derive(Debug, Clone, PartialEq, Eq, ::derive_more::Deref, ::derive_more::DerefMut)]
pub struct $id(pub Vec<$item>);
crate::http::header::common_header_deref!($id => Vec<$item>);
impl $crate::http::header::Header for $id {
#[inline]
@ -190,13 +168,11 @@ macro_rules! common_header {
};
// Single value header
($(#[$a:meta])*($id:ident, $name:expr) => [$value:ty]) => {
$(#[$a])*
#[derive(Clone, Debug, PartialEq)]
($(#[$attrs:meta])*($id:ident, $name:expr) => [$value:ty]) => {
$(#[$attrs])*
#[derive(Debug, Clone, PartialEq, Eq, ::derive_more::Deref, ::derive_more::DerefMut)]
pub struct $id(pub $value);
crate::http::header::common_header_deref!($id => $value);
impl $crate::http::header::Header for $id {
#[inline]
fn name() -> $crate::http::header::HeaderName {
@ -227,8 +203,8 @@ macro_rules! common_header {
};
// List header, one or more items with "*" option
($(#[$a:meta])*($id:ident, $name:expr) => {Any / ($item:ty)+}) => {
$(#[$a])*
($(#[$attrs:meta])*($id:ident, $name:expr) => {Any / ($item:ty)+}) => {
$(#[$attrs])*
#[derive(Clone, Debug, PartialEq)]
pub enum $id {
/// Any value is a match
@ -284,32 +260,32 @@ macro_rules! common_header {
};
// optional test module
($(#[$a:meta])*($id:ident, $name:expr) => ($item:ty)* $tm:ident{$($tf:item)*}) => {
($(#[$attrs:meta])*($id:ident, $name:expr) => ($item:ty)* $tm:ident{$($tf:item)*}) => {
crate::http::header::common_header! {
$(#[$a])*
$(#[$attrs])*
($id, $name) => ($item)*
}
crate::http::header::common_header_test_module! { $id, $tm { $($tf)* }}
};
($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)+ $tm:ident{$($tf:item)*}) => {
($(#[$attrs:meta])*($id:ident, $n:expr) => ($item:ty)+ $tm:ident{$($tf:item)*}) => {
crate::http::header::common_header! {
$(#[$a])*
$(#[$attrs])*
($id, $n) => ($item)+
}
crate::http::header::common_header_test_module! { $id, $tm { $($tf)* }}
};
($(#[$a:meta])*($id:ident, $name:expr) => [$item:ty] $tm:ident{$($tf:item)*}) => {
($(#[$attrs:meta])*($id:ident, $name:expr) => [$item:ty] $tm:ident{$($tf:item)*}) => {
crate::http::header::common_header! {
$(#[$a])* ($id, $name) => [$item]
$(#[$attrs])* ($id, $name) => [$item]
}
crate::http::header::common_header_test_module! { $id, $tm { $($tf)* }}
};
($(#[$a:meta])*($id:ident, $name:expr) => {Any / ($item:ty)+} $tm:ident{$($tf:item)*}) => {
($(#[$attrs:meta])*($id:ident, $name:expr) => {Any / ($item:ty)+} $tm:ident{$($tf:item)*}) => {
crate::http::header::common_header! {
$(#[$a])*
$(#[$attrs])*
($id, $name) => {Any / ($item)+}
}
@ -317,7 +293,7 @@ macro_rules! common_header {
};
}
pub(crate) use {common_header, common_header_deref, common_header_test_module};
pub(crate) use {common_header, common_header_test_module};
#[cfg(test)]
pub(crate) use common_header_test;

View file

@ -44,7 +44,7 @@ mod macros;
#[cfg(test)]
pub(crate) use macros::common_header_test;
pub(crate) use macros::{common_header, common_header_deref, common_header_test_module};
pub(crate) use macros::{common_header, common_header_test_module};
pub use self::accept_charset::AcceptCharset;
//pub use self::accept_encoding::AcceptEncoding;

View file

@ -1,8 +1,11 @@
use std::fmt::{self, Display};
use std::str::FromStr;
// TODO: reinstate module
use super::parsing::from_one_raw_str;
use super::{Header, Raw};
use std::{
fmt::{self, Display},
str::FromStr,
};
use super::{parsing::from_one_raw_str, Header, Raw};
/// `Range` header, defined
/// in [RFC 7233 §3.1](https://datatracker.ietf.org/doc/html/rfc7233#section-3.1)
@ -12,7 +15,7 @@ use super::{Header, Raw};
/// representation data.
///
/// # ABNF
/// ```text
/// ```plain
/// Range = byte-ranges-specifier / other-ranges-specifier
/// other-ranges-specifier = other-range-unit "=" other-range-set
/// other-range-set = 1*VCHAR