mirror of
https://github.com/actix/actix-web.git
synced 2024-11-25 19:11:10 +00:00
improve typed header macro (#2481)
This commit is contained in:
parent
075d871e63
commit
2a72bdae09
29 changed files with 147 additions and 100 deletions
|
@ -7,7 +7,7 @@ use self::Charset::*;
|
||||||
/// The string representation is normalized to upper case.
|
/// The string representation is normalized to upper case.
|
||||||
///
|
///
|
||||||
/// See <http://www.iana.org/assignments/character-sets/character-sets.xhtml>.
|
/// 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)]
|
#[allow(non_camel_case_types)]
|
||||||
pub enum Charset {
|
pub enum Charset {
|
||||||
/// US ASCII
|
/// US ASCII
|
||||||
|
|
|
@ -31,7 +31,7 @@ pub struct ExtendedValue {
|
||||||
///
|
///
|
||||||
/// ## ABNF
|
/// ## ABNF
|
||||||
///
|
///
|
||||||
/// ```text
|
/// ```plain
|
||||||
/// ext-value = charset "'" [ language ] "'" value-chars
|
/// ext-value = charset "'" [ language ] "'" value-chars
|
||||||
/// ; like RFC 2231's <extended-initial-value>
|
/// ; like RFC 2231's <extended-initial-value>
|
||||||
/// ; (see [RFC 2231 §7])
|
/// ; (see [RFC 2231 §7])
|
||||||
|
|
|
@ -8,7 +8,7 @@ use crate::{
|
||||||
helpers::MutWriter,
|
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)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct HttpDate(SystemTime);
|
pub struct HttpDate(SystemTime);
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ const MAX_FLOAT_QUALITY: f32 = 1.0;
|
||||||
///
|
///
|
||||||
/// [RFC 7231 §5.3.1](https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.1) gives more
|
/// [RFC 7231 §5.3.1](https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.1) gives more
|
||||||
/// information on quality values in HTTP header fields.
|
/// 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);
|
pub struct Quality(u16);
|
||||||
|
|
||||||
impl Quality {
|
impl Quality {
|
||||||
|
@ -80,7 +80,7 @@ impl TryFrom<f32> for Quality {
|
||||||
|
|
||||||
/// Represents an item with a quality value as defined
|
/// Represents an item with a quality value as defined
|
||||||
/// in [RFC 7231 §5.3.1](https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.1).
|
/// in [RFC 7231 §5.3.1](https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.1).
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct QualityItem<T> {
|
pub struct QualityItem<T> {
|
||||||
/// The wrapped contents of the field.
|
/// The wrapped contents of the field.
|
||||||
pub item: T,
|
pub item: T,
|
||||||
|
|
|
@ -66,7 +66,7 @@ mod route;
|
||||||
/// Creates resource handler, allowing multiple HTTP method guards.
|
/// Creates resource handler, allowing multiple HTTP method guards.
|
||||||
///
|
///
|
||||||
/// # Syntax
|
/// # Syntax
|
||||||
/// ```text
|
/// ```plain
|
||||||
/// #[route("path", method="HTTP_METHOD"[, attributes])]
|
/// #[route("path", method="HTTP_METHOD"[, attributes])]
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
@ -112,7 +112,7 @@ concat!("
|
||||||
Creates route handler with `actix_web::guard::", stringify!($variant), "`.
|
Creates route handler with `actix_web::guard::", stringify!($variant), "`.
|
||||||
|
|
||||||
# Syntax
|
# Syntax
|
||||||
```text
|
```plain
|
||||||
#[", stringify!($method), r#"("path"[, attributes])]
|
#[", stringify!($method), r#"("path"[, attributes])]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ crate::http::header::common_header! {
|
||||||
/// in-line image
|
/// in-line image
|
||||||
///
|
///
|
||||||
/// # ABNF
|
/// # ABNF
|
||||||
/// ```text
|
/// ```plain
|
||||||
/// Accept = #( media-range [ accept-params ] )
|
/// Accept = #( media-range [ accept-params ] )
|
||||||
///
|
///
|
||||||
/// media-range = ( "*/*"
|
/// media-range = ( "*/*"
|
||||||
|
|
|
@ -12,7 +12,7 @@ crate::http::header::common_header! {
|
||||||
/// those charsets.
|
/// those charsets.
|
||||||
///
|
///
|
||||||
/// # ABNF
|
/// # ABNF
|
||||||
/// ```text
|
/// ```plain
|
||||||
/// Accept-Charset = 1#( ( charset / "*" ) [ weight ] )
|
/// Accept-Charset = 1#( ( charset / "*" ) [ weight ] )
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// TODO: reinstate module
|
||||||
|
|
||||||
use header::{Encoding, QualityItem};
|
use header::{Encoding, QualityItem};
|
||||||
|
|
||||||
header! {
|
header! {
|
||||||
|
@ -11,7 +13,7 @@ header! {
|
||||||
/// preferred.
|
/// preferred.
|
||||||
///
|
///
|
||||||
/// # ABNF
|
/// # ABNF
|
||||||
/// ```text
|
/// ```plain
|
||||||
/// Accept-Encoding = #( codings [ weight ] )
|
/// Accept-Encoding = #( codings [ weight ] )
|
||||||
/// codings = content-coding / "identity" / "*"
|
/// codings = content-coding / "identity" / "*"
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -59,15 +61,17 @@ header! {
|
||||||
/// ])
|
/// ])
|
||||||
/// );
|
/// );
|
||||||
/// ```
|
/// ```
|
||||||
(AcceptEncoding, "Accept-Encoding") => (QualityItem<Encoding>)*
|
(AcceptEncoding, header::ACCEPT_ENCODING) => (QualityItem<Encoding>)*
|
||||||
|
|
||||||
test_parse_and_format {
|
test_parse_and_format {
|
||||||
// From the RFC
|
// From the RFC
|
||||||
crate::http::header::common_header_test!(test1, vec![b"compress, gzip"]);
|
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!(test2, vec![b""], Some(AcceptEncoding(vec![])));
|
||||||
crate::http::header::common_header_test!(test3, vec![b"*"]);
|
crate::http::header::common_header_test!(test3, vec![b"*"]);
|
||||||
|
|
||||||
// Note: Removed quality 1 from gzip
|
// Note: Removed quality 1 from gzip
|
||||||
crate::http::header::common_header_test!(test4, vec![b"compress;q=0.5, gzip"]);
|
crate::http::header::common_header_test!(test4, vec![b"compress;q=0.5, gzip"]);
|
||||||
|
|
||||||
// Note: Removed quality 1 from gzip
|
// Note: Removed quality 1 from gzip
|
||||||
crate::http::header::common_header_test!(test5, vec![b"gzip, identity; q=0.5, *;q=0"]);
|
crate::http::header::common_header_test!(test5, vec![b"gzip, identity; q=0.5, *;q=0"]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ common_header! {
|
||||||
/// ranges defined in [RFC 4647 §2.1](https://datatracker.ietf.org/doc/html/rfc4647#section-2.1).
|
/// ranges defined in [RFC 4647 §2.1](https://datatracker.ietf.org/doc/html/rfc4647#section-2.1).
|
||||||
///
|
///
|
||||||
/// # ABNF
|
/// # ABNF
|
||||||
/// ```text
|
/// ```plain
|
||||||
/// Accept-Language = 1#( language-range [ weight ] )
|
/// Accept-Language = 1#( language-range [ weight ] )
|
||||||
/// language-range = (1*8ALPHA *("-" 1*8alphanum)) / "*"
|
/// language-range = (1*8ALPHA *("-" 1*8alphanum)) / "*"
|
||||||
/// alphanum = ALPHA / DIGIT
|
/// alphanum = ALPHA / DIGIT
|
||||||
|
@ -57,7 +57,7 @@ common_header! {
|
||||||
/// ```
|
/// ```
|
||||||
(AcceptLanguage, header::ACCEPT_LANGUAGE) => (QualityItem<Preference<LanguageTag>>)*
|
(AcceptLanguage, header::ACCEPT_LANGUAGE) => (QualityItem<Preference<LanguageTag>>)*
|
||||||
|
|
||||||
parse_and_fmt_tests {
|
test_parse_and_format {
|
||||||
common_header_test!(no_headers, vec![b""; 0], Some(AcceptLanguage(vec![])));
|
common_header_test!(no_headers, vec![b""; 0], Some(AcceptLanguage(vec![])));
|
||||||
|
|
||||||
common_header_test!(empty_header, vec![b""; 1], Some(AcceptLanguage(vec![])));
|
common_header_test!(empty_header, vec![b""; 1], Some(AcceptLanguage(vec![])));
|
||||||
|
|
|
@ -12,7 +12,7 @@ crate::http::header::common_header! {
|
||||||
/// with the resource.
|
/// with the resource.
|
||||||
///
|
///
|
||||||
/// # ABNF
|
/// # ABNF
|
||||||
/// ```text
|
/// ```plain
|
||||||
/// Allow = #method
|
/// Allow = #method
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
|
70
src/http/header/any_or_some.rs
Normal file
70
src/http/header/any_or_some.rs
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
use std::{
|
||||||
|
fmt::{self, Write as _},
|
||||||
|
str,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A wrapper for types used in header values where wildcard (`*`) items are allowed but the
|
||||||
|
/// underlying type does not support them.
|
||||||
|
///
|
||||||
|
/// For example, we use the `language-tags` crate for the [`AcceptLanguage`](super::AcceptLanguage)
|
||||||
|
/// typed header but it does parse `*` successfully. On the other hand, the `mime` crate, used for
|
||||||
|
/// [`Accept`](super::Accept), has first-party support for wildcard items so this wrapper is not
|
||||||
|
/// used in those header types.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Hash)]
|
||||||
|
pub enum AnyOrSome<T> {
|
||||||
|
/// A wildcard value.
|
||||||
|
Any,
|
||||||
|
|
||||||
|
/// A valid `T`.
|
||||||
|
Item(T),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> AnyOrSome<T> {
|
||||||
|
/// Returns true if item is wildcard (`*`) variant.
|
||||||
|
pub fn is_any(&self) -> bool {
|
||||||
|
matches!(self, Self::Any)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if item is a valid item (`T`) variant.
|
||||||
|
pub fn is_item(&self) -> bool {
|
||||||
|
matches!(self, Self::Item(_))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns reference to value in `Item` variant, if it is set.
|
||||||
|
pub fn item(&self) -> Option<&T> {
|
||||||
|
match self {
|
||||||
|
AnyOrSome::Item(ref item) => Some(item),
|
||||||
|
AnyOrSome::Any => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consumes the container, returning the value in the `Item` variant, if it is set.
|
||||||
|
pub fn into_item(self) -> Option<T> {
|
||||||
|
match self {
|
||||||
|
AnyOrSome::Item(item) => Some(item),
|
||||||
|
AnyOrSome::Any => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: fmt::Display> fmt::Display for AnyOrSome<T> {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
AnyOrSome::Any => f.write_char('*'),
|
||||||
|
AnyOrSome::Item(item) => fmt::Display::fmt(item, f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: str::FromStr> str::FromStr for AnyOrSome<T> {
|
||||||
|
type Err = T::Err;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s.trim() {
|
||||||
|
"*" => Ok(Self::Any),
|
||||||
|
other => other.parse().map(AnyOrSome::Item),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use derive_more::{Deref, DerefMut};
|
||||||
|
|
||||||
use super::{fmt_comma_delimited, from_comma_delimited, Header, IntoHeaderValue, Writer};
|
use super::{fmt_comma_delimited, from_comma_delimited, Header, IntoHeaderValue, Writer};
|
||||||
|
|
||||||
use crate::http::header;
|
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.
|
/// not imply that the same directive is to be given in the response.
|
||||||
///
|
///
|
||||||
/// # ABNF
|
/// # ABNF
|
||||||
/// ```text
|
/// ```plain
|
||||||
/// Cache-Control = 1#cache-directive
|
/// Cache-Control = 1#cache-directive
|
||||||
/// cache-directive = token [ "=" ( token / quoted-string ) ]
|
/// cache-directive = token [ "=" ( token / quoted-string ) ]
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -46,11 +48,9 @@ use crate::http::header;
|
||||||
/// CacheDirective::Extension("foo".to_owned(), Some("bar".to_owned())),
|
/// 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>);
|
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
|
// TODO: this could just be the crate::http::header::common_header! macro
|
||||||
impl Header for CacheControl {
|
impl Header for CacheControl {
|
||||||
fn name() -> header::HeaderName {
|
fn name() -> header::HeaderName {
|
||||||
|
@ -88,7 +88,7 @@ impl IntoHeaderValue for CacheControl {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `CacheControl` contains a list of these directives.
|
/// `CacheControl` contains a list of these directives.
|
||||||
#[derive(PartialEq, Clone, Debug)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum CacheDirective {
|
pub enum CacheDirective {
|
||||||
/// "no-cache"
|
/// "no-cache"
|
||||||
NoCache,
|
NoCache,
|
||||||
|
|
|
@ -220,7 +220,7 @@ impl DispositionParam {
|
||||||
/// itself, *Content-Disposition* has no effect.
|
/// itself, *Content-Disposition* has no effect.
|
||||||
///
|
///
|
||||||
/// # ABNF
|
/// # ABNF
|
||||||
/// ```text
|
/// ```plain
|
||||||
/// content-disposition = "Content-Disposition" ":"
|
/// content-disposition = "Content-Disposition" ":"
|
||||||
/// disposition-type *( ";" disposition-parm )
|
/// disposition-type *( ";" disposition-parm )
|
||||||
///
|
///
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use super::{QualityItem, CONTENT_LANGUAGE};
|
|
||||||
use language_tags::LanguageTag;
|
use language_tags::LanguageTag;
|
||||||
|
|
||||||
crate::http::header::common_header! {
|
use super::{common_header, QualityItem, CONTENT_LANGUAGE};
|
||||||
|
|
||||||
|
common_header! {
|
||||||
/// `Content-Language` header, defined
|
/// `Content-Language` header, defined
|
||||||
/// in [RFC 7231 §3.1.3.2](https://datatracker.ietf.org/doc/html/rfc7231#section-3.1.3.2)
|
/// 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.
|
/// representation.
|
||||||
///
|
///
|
||||||
/// # ABNF
|
/// # ABNF
|
||||||
/// ```text
|
/// ```plain
|
||||||
/// Content-Language = 1#language-tag
|
/// Content-Language = 1#language-tag
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
|
|
@ -75,7 +75,7 @@ crate::http::header::common_header! {
|
||||||
/// in [RFC 7233 §4.2](https://datatracker.ietf.org/doc/html/rfc7233#section-4.2)
|
/// in [RFC 7233 §4.2](https://datatracker.ietf.org/doc/html/rfc7233#section-4.2)
|
||||||
///
|
///
|
||||||
/// # ABNF
|
/// # ABNF
|
||||||
/// ```text
|
/// ```plain
|
||||||
/// Content-Range = byte-content-range
|
/// Content-Range = byte-content-range
|
||||||
/// / other-content-range
|
/// / other-content-range
|
||||||
///
|
///
|
||||||
|
@ -91,7 +91,7 @@ crate::http::header::common_header! {
|
||||||
/// other-content-range = other-range-unit SP other-range-resp
|
/// other-content-range = other-range-unit SP other-range-resp
|
||||||
/// other-range-resp = *CHAR
|
/// other-range-resp = *CHAR
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(PartialEq, Clone, Debug)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum ContentRangeSpec {
|
pub enum ContentRangeSpec {
|
||||||
/// Byte range
|
/// Byte range
|
||||||
Bytes {
|
Bytes {
|
||||||
|
|
|
@ -18,7 +18,7 @@ crate::http::header::common_header! {
|
||||||
/// this is an issue, it's possible to implement `Header` on a custom struct.
|
/// this is an issue, it's possible to implement `Header` on a custom struct.
|
||||||
///
|
///
|
||||||
/// # ABNF
|
/// # ABNF
|
||||||
/// ```text
|
/// ```plain
|
||||||
/// Content-Type = media-type
|
/// Content-Type = media-type
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
@ -110,5 +110,3 @@ impl ContentType {
|
||||||
ContentType(mime::APPLICATION_OCTET_STREAM)
|
ContentType(mime::APPLICATION_OCTET_STREAM)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for ContentType {}
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ crate::http::header::common_header! {
|
||||||
/// message was originated.
|
/// message was originated.
|
||||||
///
|
///
|
||||||
/// # ABNF
|
/// # ABNF
|
||||||
/// ```text
|
/// ```plain
|
||||||
/// Date = HTTP-date
|
/// Date = HTTP-date
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
|
|
@ -26,7 +26,7 @@ fn check_slice_validity(slice: &str) -> bool {
|
||||||
/// `W/"xyzzy"`.
|
/// `W/"xyzzy"`.
|
||||||
///
|
///
|
||||||
/// # ABNF
|
/// # ABNF
|
||||||
/// ```text
|
/// ```plain
|
||||||
/// entity-tag = [ weak ] opaque-tag
|
/// entity-tag = [ weak ] opaque-tag
|
||||||
/// weak = %x57.2F ; "W/", case-sensitive
|
/// weak = %x57.2F ; "W/", case-sensitive
|
||||||
/// opaque-tag = DQUOTE *etagc DQUOTE
|
/// opaque-tag = DQUOTE *etagc DQUOTE
|
||||||
|
|
|
@ -15,7 +15,7 @@ crate::http::header::common_header! {
|
||||||
/// prefixed by a weakness indicator.
|
/// prefixed by a weakness indicator.
|
||||||
///
|
///
|
||||||
/// # ABNF
|
/// # ABNF
|
||||||
/// ```text
|
/// ```plain
|
||||||
/// ETag = entity-tag
|
/// ETag = entity-tag
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
|
|
@ -12,7 +12,7 @@ crate::http::header::common_header! {
|
||||||
/// time.
|
/// time.
|
||||||
///
|
///
|
||||||
/// # ABNF
|
/// # ABNF
|
||||||
/// ```text
|
/// ```plain
|
||||||
/// Expires = HTTP-date
|
/// Expires = HTTP-date
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
|
|
@ -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
|
/// `If-Match` header, defined
|
||||||
/// in [RFC 7232 §3.1](https://datatracker.ietf.org/doc/html/rfc7232#section-3.1)
|
/// 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.
|
/// there have been any changes to the representation data.
|
||||||
///
|
///
|
||||||
/// # ABNF
|
/// # ABNF
|
||||||
/// ```text
|
/// ```plain
|
||||||
/// If-Match = "*" / 1#entity-tag
|
/// If-Match = "*" / 1#entity-tag
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
|
|
@ -11,7 +11,7 @@ crate::http::header::common_header! {
|
||||||
/// data has not changed.
|
/// data has not changed.
|
||||||
///
|
///
|
||||||
/// # ABNF
|
/// # ABNF
|
||||||
/// ```text
|
/// ```plain
|
||||||
/// If-Unmodified-Since = HTTP-date
|
/// If-Unmodified-Since = HTTP-date
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
|
|
@ -16,7 +16,7 @@ crate::http::header::common_header! {
|
||||||
/// the representation data.
|
/// the representation data.
|
||||||
///
|
///
|
||||||
/// # ABNF
|
/// # ABNF
|
||||||
/// ```text
|
/// ```plain
|
||||||
/// If-None-Match = "*" / 1#entity-tag
|
/// If-None-Match = "*" / 1#entity-tag
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
|
|
@ -25,7 +25,7 @@ use crate::HttpMessage;
|
||||||
/// in Range; otherwise, send me the entire representation.
|
/// in Range; otherwise, send me the entire representation.
|
||||||
///
|
///
|
||||||
/// # ABNF
|
/// # ABNF
|
||||||
/// ```text
|
/// ```plain
|
||||||
/// If-Range = entity-tag / HTTP-date
|
/// If-Range = entity-tag / HTTP-date
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
@ -107,10 +107,11 @@ impl IntoHeaderValue for IfRange {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test_if_range {
|
mod test_parse_and_format {
|
||||||
|
use std::str;
|
||||||
|
|
||||||
use super::IfRange as HeaderField;
|
use super::IfRange as HeaderField;
|
||||||
use crate::http::header::*;
|
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!(test1, vec![b"Sat, 29 Oct 1994 19:43:31 GMT"]);
|
||||||
crate::http::header::common_header_test!(test2, vec![b"\"abc\""]);
|
crate::http::header::common_header_test!(test2, vec![b"\"abc\""]);
|
||||||
|
|
|
@ -11,7 +11,7 @@ crate::http::header::common_header! {
|
||||||
/// the user agent does not have an entity-tag for the representation.
|
/// the user agent does not have an entity-tag for the representation.
|
||||||
///
|
///
|
||||||
/// # ABNF
|
/// # ABNF
|
||||||
/// ```text
|
/// ```plain
|
||||||
/// If-Unmodified-Since = HTTP-date
|
/// If-Unmodified-Since = HTTP-date
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
|
|
@ -10,7 +10,7 @@ crate::http::header::common_header! {
|
||||||
/// conclusion of handling the request.
|
/// conclusion of handling the request.
|
||||||
///
|
///
|
||||||
/// # ABNF
|
/// # ABNF
|
||||||
/// ```text
|
/// ```plain
|
||||||
/// Expires = HTTP-date
|
/// Expires = HTTP-date
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
|
|
@ -1,25 +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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets up a test module with some useful imports for use with [`common_header_test!`].
|
|
||||||
macro_rules! common_header_test_module {
|
macro_rules! common_header_test_module {
|
||||||
($id:ident, $tm:ident{$($tf:item)*}) => {
|
($id:ident, $tm:ident{$($tf:item)*}) => {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -87,10 +65,6 @@ macro_rules! common_header_test {
|
||||||
let val = HeaderField::parse(&req);
|
let val = HeaderField::parse(&req);
|
||||||
let exp: Option<HeaderField> = $exp;
|
let exp: Option<HeaderField> = $exp;
|
||||||
|
|
||||||
println!("req: {:?}", &req);
|
|
||||||
println!("val: {:?}", &val);
|
|
||||||
println!("exp: {:?}", &exp);
|
|
||||||
|
|
||||||
// test parsing
|
// test parsing
|
||||||
assert_eq!(val.ok(), exp);
|
assert_eq!(val.ok(), exp);
|
||||||
|
|
||||||
|
@ -114,17 +88,17 @@ macro_rules! common_header_test {
|
||||||
|
|
||||||
macro_rules! common_header {
|
macro_rules! common_header {
|
||||||
// TODO: these docs are wrong, there's no $n or $nn
|
// TODO: these docs are wrong, there's no $n or $nn
|
||||||
// $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
|
// $id:ident: Identifier of the header
|
||||||
// $n:expr: Lowercase name of the header
|
// $n:expr: Lowercase name of the header
|
||||||
// $nn:expr: Nice name of the header
|
// $nn:expr: Nice name of the header
|
||||||
|
|
||||||
// List header, zero or more items
|
// List header, zero or more items
|
||||||
($(#[$a:meta])*($id:ident, $name:expr) => ($item:ty)*) => {
|
($(#[$attrs:meta])*($id:ident, $name:expr) => ($item:ty)*) => {
|
||||||
$(#[$a])*
|
$(#[$attrs])*
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, Eq, ::derive_more::Deref, ::derive_more::DerefMut)]
|
||||||
pub struct $id(pub Vec<$item>);
|
pub struct $id(pub Vec<$item>);
|
||||||
crate::http::header::common_header_deref!($id => Vec<$item>);
|
|
||||||
impl $crate::http::header::Header for $id {
|
impl $crate::http::header::Header for $id {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn name() -> $crate::http::header::HeaderName {
|
fn name() -> $crate::http::header::HeaderName {
|
||||||
|
@ -158,13 +132,11 @@ macro_rules! common_header {
|
||||||
};
|
};
|
||||||
|
|
||||||
// List header, one or more items
|
// List header, one or more items
|
||||||
($(#[$a:meta])*($id:ident, $name:expr) => ($item:ty)+) => {
|
($(#[$attrs:meta])*($id:ident, $name:expr) => ($item:ty)+) => {
|
||||||
$(#[$a])*
|
$(#[$attrs])*
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, Eq, ::derive_more::Deref, ::derive_more::DerefMut)]
|
||||||
pub struct $id(pub Vec<$item>);
|
pub struct $id(pub Vec<$item>);
|
||||||
|
|
||||||
crate::http::header::common_header_deref!($id => Vec<$item>);
|
|
||||||
|
|
||||||
impl $crate::http::header::Header for $id {
|
impl $crate::http::header::Header for $id {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn name() -> $crate::http::header::HeaderName {
|
fn name() -> $crate::http::header::HeaderName {
|
||||||
|
@ -197,13 +169,11 @@ macro_rules! common_header {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Single value header
|
// Single value header
|
||||||
($(#[$a:meta])*($id:ident, $name:expr) => [$value:ty]) => {
|
($(#[$attrs:meta])*($id:ident, $name:expr) => [$value:ty]) => {
|
||||||
$(#[$a])*
|
$(#[$attrs])*
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, Eq, ::derive_more::Deref, ::derive_more::DerefMut)]
|
||||||
pub struct $id(pub $value);
|
pub struct $id(pub $value);
|
||||||
|
|
||||||
crate::http::header::common_header_deref!($id => $value);
|
|
||||||
|
|
||||||
impl $crate::http::header::Header for $id {
|
impl $crate::http::header::Header for $id {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn name() -> $crate::http::header::HeaderName {
|
fn name() -> $crate::http::header::HeaderName {
|
||||||
|
@ -234,8 +204,8 @@ macro_rules! common_header {
|
||||||
};
|
};
|
||||||
|
|
||||||
// List header, one or more items with "*" option
|
// List header, one or more items with "*" option
|
||||||
($(#[$a:meta])*($id:ident, $name:expr) => {Any / ($item:ty)+}) => {
|
($(#[$attrs:meta])*($id:ident, $name:expr) => {Any / ($item:ty)+}) => {
|
||||||
$(#[$a])*
|
$(#[$attrs])*
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum $id {
|
pub enum $id {
|
||||||
/// Any value is a match
|
/// Any value is a match
|
||||||
|
@ -291,32 +261,32 @@ macro_rules! common_header {
|
||||||
};
|
};
|
||||||
|
|
||||||
// optional test module
|
// 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! {
|
crate::http::header::common_header! {
|
||||||
$(#[$a])*
|
$(#[$attrs])*
|
||||||
($id, $name) => ($item)*
|
($id, $name) => ($item)*
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::http::header::common_header_test_module! { $id, $tm { $($tf)* }}
|
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! {
|
crate::http::header::common_header! {
|
||||||
$(#[$a])*
|
$(#[$attrs])*
|
||||||
($id, $n) => ($item)+
|
($id, $n) => ($item)+
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::http::header::common_header_test_module! { $id, $tm { $($tf)* }}
|
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! {
|
crate::http::header::common_header! {
|
||||||
$(#[$a])* ($id, $name) => [$item]
|
$(#[$attrs])* ($id, $name) => [$item]
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::http::header::common_header_test_module! { $id, $tm { $($tf)* }}
|
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! {
|
crate::http::header::common_header! {
|
||||||
$(#[$a])*
|
$(#[$attrs])*
|
||||||
($id, $name) => {Any / ($item)+}
|
($id, $name) => {Any / ($item)+}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,7 +294,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)]
|
#[cfg(test)]
|
||||||
pub(crate) use common_header_test;
|
pub(crate) use common_header_test;
|
||||||
|
|
|
@ -44,7 +44,7 @@ mod preference;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) use macros::common_header_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_charset::AcceptCharset;
|
||||||
//pub use self::accept_encoding::AcceptEncoding;
|
//pub use self::accept_encoding::AcceptEncoding;
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
use std::fmt::{self, Display};
|
// TODO: reinstate module
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
use super::parsing::from_one_raw_str;
|
use std::{
|
||||||
use super::{Header, Raw};
|
fmt::{self, Display},
|
||||||
|
str::FromStr,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{parsing::from_one_raw_str, Header, Raw};
|
||||||
|
|
||||||
/// `Range` header, defined
|
/// `Range` header, defined
|
||||||
/// in [RFC 7233 §3.1](https://datatracker.ietf.org/doc/html/rfc7233#section-3.1)
|
/// 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.
|
/// representation data.
|
||||||
///
|
///
|
||||||
/// # ABNF
|
/// # ABNF
|
||||||
/// ```text
|
/// ```plain
|
||||||
/// Range = byte-ranges-specifier / other-ranges-specifier
|
/// Range = byte-ranges-specifier / other-ranges-specifier
|
||||||
/// other-ranges-specifier = other-range-unit "=" other-range-set
|
/// other-ranges-specifier = other-range-unit "=" other-range-set
|
||||||
/// other-range-set = 1*VCHAR
|
/// other-range-set = 1*VCHAR
|
||||||
|
|
Loading…
Reference in a new issue