Merge pull request #487 from pyfisch/headertests2
Bugfixes, tests and documentation for headers
This commit is contained in:
@@ -23,6 +23,10 @@ header! {
|
|||||||
#[doc="accept-ext = OWS \";\" OWS token [ \"=\" ( token / quoted-string ) ]"]
|
#[doc="accept-ext = OWS \";\" OWS token [ \"=\" ( token / quoted-string ) ]"]
|
||||||
#[doc="```"]
|
#[doc="```"]
|
||||||
#[doc=""]
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `audio/*; q=0.2, audio/basic` (`*` value won't parse correctly)"]
|
||||||
|
#[doc="* `text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c`"]
|
||||||
|
#[doc=""]
|
||||||
#[doc="# Notes"]
|
#[doc="# Notes"]
|
||||||
#[doc="* Using always Mime types to represent `media-range` differs from the ABNF."]
|
#[doc="* Using always Mime types to represent `media-range` differs from the ABNF."]
|
||||||
#[doc="* **FIXME**: `accept-ext` is not supported."]
|
#[doc="* **FIXME**: `accept-ext` is not supported."]
|
||||||
|
|||||||
@@ -15,9 +15,13 @@ header! {
|
|||||||
#[doc="```plain"]
|
#[doc="```plain"]
|
||||||
#[doc="Accept-Charset = 1#( ( charset / \"*\" ) [ weight ] )"]
|
#[doc="Accept-Charset = 1#( ( charset / \"*\" ) [ weight ] )"]
|
||||||
#[doc="```"]
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `iso-8859-5, unicode-1-1;q=0.8`"]
|
||||||
(AcceptCharset, "Accept-Charset") => (QualityItem<Charset>)+
|
(AcceptCharset, "Accept-Charset") => (QualityItem<Charset>)+
|
||||||
|
|
||||||
test_accept_charset {
|
test_accept_charset {
|
||||||
|
/// Testcase from RFC
|
||||||
test_header!(test1, vec![b"iso-8859-5, unicode-1-1;q=0.8"]);
|
test_header!(test1, vec![b"iso-8859-5, unicode-1-1;q=0.8"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,33 +15,23 @@ header! {
|
|||||||
#[doc="Accept-Encoding = #( codings [ weight ] )"]
|
#[doc="Accept-Encoding = #( codings [ weight ] )"]
|
||||||
#[doc="codings = content-coding / \"identity\" / \"*\""]
|
#[doc="codings = content-coding / \"identity\" / \"*\""]
|
||||||
#[doc="```"]
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `compress, gzip`"]
|
||||||
|
#[doc="* ``"]
|
||||||
|
#[doc="* `*`"]
|
||||||
|
#[doc="* `compress;q=0.5, gzip;q=1`"]
|
||||||
|
#[doc="* `gzip;q=1.0, identity; q=0.5, *;q=0`"]
|
||||||
(AcceptEncoding, "Accept-Encoding") => (QualityItem<Encoding>)*
|
(AcceptEncoding, "Accept-Encoding") => (QualityItem<Encoding>)*
|
||||||
|
|
||||||
test_accept_encoding {
|
test_accept_encoding {
|
||||||
// From the RFC
|
// From the RFC
|
||||||
test_header!(test1, vec![b"compress, gzip"]);
|
test_header!(test1, vec![b"compress, gzip"]);
|
||||||
test_header!(test2, vec![b""]);
|
test_header!(test2, vec![b""], Some(AcceptEncoding(vec![])));
|
||||||
test_header!(test3, vec![b"*"]);
|
test_header!(test3, vec![b"*"]);
|
||||||
// Note: Removed quality 1 from gzip
|
// Note: Removed quality 1 from gzip
|
||||||
test_header!(test4, vec![b"compress;q=0.5, gzip"]);
|
test_header!(test4, vec![b"compress;q=0.5, gzip"]);
|
||||||
// FIXME: Formatting of 0 as quality value
|
// Note: Removed quality 1 from gzip
|
||||||
// test_header!(test5, vec![b"gzip;q=1.0, identity; q=0.5, *;q=0"]);
|
test_header!(test5, vec![b"gzip, identity; q=0.5, *;q=0"]);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use header::{Encoding, Header, qitem, Quality, QualityItem};
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_parse_header() {
|
|
||||||
let a: AcceptEncoding = Header::parse_header([b"gzip;q=1.0, identity; q=0.5".to_vec()].as_ref()).unwrap();
|
|
||||||
let b = AcceptEncoding(vec![
|
|
||||||
qitem(Encoding::Gzip),
|
|
||||||
QualityItem::new(Encoding::Identity, Quality(500)),
|
|
||||||
]);
|
|
||||||
assert_eq!(a, b);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,49 +13,23 @@ header! {
|
|||||||
#[doc="Accept-Language = 1#( language-range [ weight ] )"]
|
#[doc="Accept-Language = 1#( language-range [ weight ] )"]
|
||||||
#[doc="language-range = <language-range, see [RFC4647], Section 2.1>"]
|
#[doc="language-range = <language-range, see [RFC4647], Section 2.1>"]
|
||||||
#[doc="```"]
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `da, en-gb;q=0.8, en;q=0.7`"]
|
||||||
|
#[doc="* `en-us;q=1.0, en;q=0.5, fr`"]
|
||||||
(AcceptLanguage, "Accept-Language") => (QualityItem<Language>)+
|
(AcceptLanguage, "Accept-Language") => (QualityItem<Language>)+
|
||||||
|
|
||||||
test_accept_language {
|
test_accept_language {
|
||||||
|
// From the RFC
|
||||||
test_header!(test1, vec![b"da, en-gb;q=0.8, en;q=0.7"]);
|
test_header!(test1, vec![b"da, en-gb;q=0.8, en;q=0.7"]);
|
||||||
}
|
// Own test
|
||||||
}
|
test_header!(
|
||||||
|
test2, vec![b"en-us, en; q=0.5, fr"],
|
||||||
#[cfg(test)]
|
Some(AcceptLanguage(vec![
|
||||||
mod tests {
|
|
||||||
use header::{Header, Language, qitem, Quality, QualityItem};
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_parse_header() {
|
|
||||||
let a: AcceptLanguage = Header::parse_header(
|
|
||||||
[b"en-us;q=1.0, en;q=0.5, fr".to_vec()].as_ref()).unwrap();
|
|
||||||
let b = AcceptLanguage(vec![
|
|
||||||
qitem(Language {primary: "en".to_string(), sub: Some("us".to_string())}),
|
qitem(Language {primary: "en".to_string(), sub: Some("us".to_string())}),
|
||||||
QualityItem::new(Language{primary: "en".to_string(), sub: None},
|
QualityItem::new(Language{primary: "en".to_string(), sub: None}, Quality(500)),
|
||||||
Quality(500)),
|
|
||||||
qitem(Language {primary: "fr".to_string(), sub: None}),
|
qitem(Language {primary: "fr".to_string(), sub: None}),
|
||||||
]);
|
])));
|
||||||
assert_eq!(format!("{}", a), format!("{}", b));
|
|
||||||
assert_eq!(a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_display() {
|
|
||||||
assert_eq!("en".to_string(),
|
|
||||||
format!("{}", Language{primary: "en".to_string(),
|
|
||||||
sub: None}));
|
|
||||||
assert_eq!("en-us".to_string(),
|
|
||||||
format!("{}", Language{primary: "en".to_string(),
|
|
||||||
sub: Some("us".to_string())}));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_from_str() {
|
|
||||||
assert_eq!(Language { primary: "en".to_string(), sub: None },
|
|
||||||
"en".parse().unwrap());
|
|
||||||
assert_eq!(Language { primary: "en".to_string(),
|
|
||||||
sub: Some("us".to_string()) },
|
|
||||||
"en-us".parse().unwrap());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,17 @@ header! {
|
|||||||
#[doc="The `Access-Control-Allow-Headers` header indicates, as part of the"]
|
#[doc="The `Access-Control-Allow-Headers` header indicates, as part of the"]
|
||||||
#[doc="response to a preflight request, which header field names can be used"]
|
#[doc="response to a preflight request, which header field names can be used"]
|
||||||
#[doc="during the actual request."]
|
#[doc="during the actual request."]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# ABNF"]
|
||||||
|
#[doc="```plain"]
|
||||||
|
#[doc="Access-Control-Allow-Headers: \"Access-Control-Allow-Headers\" \":\" #field-name"]
|
||||||
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `accept-language, date`"]
|
||||||
(AccessControlAllowHeaders, "Access-Control-Allow-Headers") => (UniCase<String>)*
|
(AccessControlAllowHeaders, "Access-Control-Allow-Headers") => (UniCase<String>)*
|
||||||
|
|
||||||
test_access_control_allow_headers {}
|
test_access_control_allow_headers {
|
||||||
|
test_header!(test1, vec![b"accept-language, date"]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,17 @@ header! {
|
|||||||
#[doc="The `Access-Control-Allow-Methods` header indicates, as part of the"]
|
#[doc="The `Access-Control-Allow-Methods` header indicates, as part of the"]
|
||||||
#[doc="response to a preflight request, which methods can be used during the"]
|
#[doc="response to a preflight request, which methods can be used during the"]
|
||||||
#[doc="actual request."]
|
#[doc="actual request."]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# ABNF"]
|
||||||
|
#[doc="```plain"]
|
||||||
|
#[doc="Access-Control-Allow-Methods: \"Access-Control-Allow-Methods\" \":\" #Method"]
|
||||||
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `PUT, DELETE, XMODIFY`"]
|
||||||
(AccessControlAllowMethods, "Access-Control-Allow-Methods") => (Method)*
|
(AccessControlAllowMethods, "Access-Control-Allow-Methods") => (Method)*
|
||||||
|
|
||||||
test_access_control_allow_methods {}
|
test_access_control_allow_methods {
|
||||||
|
test_header!(test1, vec![b"PUT, DELETE, XMODIFY"]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,22 @@
|
|||||||
use std::fmt::{self};
|
use std::fmt;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use header;
|
use header;
|
||||||
|
|
||||||
/// The `Access-Control-Allow-Origin` response header,
|
/// The `Access-Control-Allow-Origin` response header,
|
||||||
/// part of [CORS](http://www.w3.org/TR/cors/).
|
/// part of [CORS](www.w3.org/TR/cors/#access-control-allow-origin-response-header)
|
||||||
///
|
///
|
||||||
/// > The `Access-Control-Allow-Origin` header indicates whether a resource
|
/// The `Access-Control-Allow-Origin` header indicates whether a resource
|
||||||
/// > can be shared based by returning the value of the Origin request header,
|
/// can be shared based by returning the value of the Origin request header,
|
||||||
/// > "*", or "null" in the response.
|
/// "*", or "null" in the response.
|
||||||
///
|
///
|
||||||
/// Spec: www.w3.org/TR/cors/#access-control-allow-origin-response-header
|
/// # ABNF
|
||||||
|
/// ```plain
|
||||||
|
/// Access-Control-Allow-Origin = "Access-Control-Allow-Origin" ":" origin-list-or-null | "*"
|
||||||
|
/// ```
|
||||||
|
// FIXME: The documentation says differently (missing "null" value, "*" not used in practice,
|
||||||
|
// orgin list no list but single value)
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub enum AccessControlAllowOrigin {
|
pub enum AccessControlAllowOrigin {
|
||||||
/// Allow all origins
|
/// Allow all origins
|
||||||
|
|||||||
@@ -4,7 +4,17 @@ header! {
|
|||||||
#[doc=""]
|
#[doc=""]
|
||||||
#[doc="The `Access-Control-Max-Age` header indicates how long the results of a"]
|
#[doc="The `Access-Control-Max-Age` header indicates how long the results of a"]
|
||||||
#[doc="preflight request can be cached in a preflight result cache."]
|
#[doc="preflight request can be cached in a preflight result cache."]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# ABNF"]
|
||||||
|
#[doc="```plain"]
|
||||||
|
#[doc="Access-Control-Max-Age = \"Access-Control-Max-Age\" \":\" delta-seconds"]
|
||||||
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `531`"]
|
||||||
(AccessControlMaxAge, "Access-Control-Max-Age") => [u32]
|
(AccessControlMaxAge, "Access-Control-Max-Age") => [u32]
|
||||||
|
|
||||||
test_access_control_max_age {}
|
test_access_control_max_age {
|
||||||
|
test_header!(test1, vec![b"531"]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,17 @@ header! {
|
|||||||
#[doc="The `Access-Control-Request-Headers` header indicates which headers will"]
|
#[doc="The `Access-Control-Request-Headers` header indicates which headers will"]
|
||||||
#[doc="be used in the actual request as part of the preflight request."]
|
#[doc="be used in the actual request as part of the preflight request."]
|
||||||
#[doc="during the actual request."]
|
#[doc="during the actual request."]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# ABNF"]
|
||||||
|
#[doc="```plain"]
|
||||||
|
#[doc="Access-Control-Allow-Headers: \"Access-Control-Allow-Headers\" \":\" #field-name"]
|
||||||
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `accept-language, date`"]
|
||||||
(AccessControlRequestHeaders, "Access-Control-Request-Headers") => (UniCase<String>)*
|
(AccessControlRequestHeaders, "Access-Control-Request-Headers") => (UniCase<String>)*
|
||||||
|
|
||||||
test_access_control_request_headers {}
|
test_access_control_request_headers {
|
||||||
|
test_header!(test1, vec![b"accept-language, date"]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,16 @@ header! {
|
|||||||
#[doc=""]
|
#[doc=""]
|
||||||
#[doc="The `Access-Control-Request-Method` header indicates which method will be"]
|
#[doc="The `Access-Control-Request-Method` header indicates which method will be"]
|
||||||
#[doc="used in the actual request as part of the preflight request."]
|
#[doc="used in the actual request as part of the preflight request."]
|
||||||
|
#[doc="# ABNF"]
|
||||||
|
#[doc="```plain"]
|
||||||
|
#[doc="Access-Control-Request-Method: \"Access-Control-Request-Method\" \":\" Method"]
|
||||||
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `GET`"]
|
||||||
(AccessControlRequestMethod, "Access-Control-Request-Method") => [Method]
|
(AccessControlRequestMethod, "Access-Control-Request-Method") => [Method]
|
||||||
|
|
||||||
test_access_control_request_method {}
|
test_access_control_request_method {
|
||||||
|
test_header!(test1, vec![b"GET"]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,11 @@ header! {
|
|||||||
#[doc="```plain"]
|
#[doc="```plain"]
|
||||||
#[doc="Allow = #method"]
|
#[doc="Allow = #method"]
|
||||||
#[doc="```"]
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `GET, HEAD, PUT`"]
|
||||||
|
#[doc="* `OPTIONS, GET, PUT, POST, DELETE, HEAD, TRACE, CONNECT, PATCH, fOObAr`"]
|
||||||
|
#[doc="* ``"]
|
||||||
(Allow, "Allow") => (Method)*
|
(Allow, "Allow") => (Method)*
|
||||||
|
|
||||||
test_allow {
|
test_allow {
|
||||||
@@ -35,11 +40,10 @@ header! {
|
|||||||
Method::Connect,
|
Method::Connect,
|
||||||
Method::Patch,
|
Method::Patch,
|
||||||
Method::Extension("fOObAr".to_string())])));
|
Method::Extension("fOObAr".to_string())])));
|
||||||
// FIXME: Formatting fails
|
test_header!(
|
||||||
// test_header!(
|
test3,
|
||||||
// test3,
|
vec![b""],
|
||||||
// vec![b""],
|
Some(HeaderField(Vec::<Method>::new())));
|
||||||
// Some(HeaderField(Vec::<Method>::new())));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,9 +16,15 @@ header! {
|
|||||||
#[doc="```plain"]
|
#[doc="```plain"]
|
||||||
#[doc="Content-Encoding = 1#content-coding"]
|
#[doc="Content-Encoding = 1#content-coding"]
|
||||||
#[doc="```"]
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `gzip`"]
|
||||||
(ContentEncoding, "Content-Encoding") => (Encoding)+
|
(ContentEncoding, "Content-Encoding") => (Encoding)+
|
||||||
|
|
||||||
test_content_encoding {}
|
test_content_encoding {
|
||||||
|
/// Testcase from the RFC
|
||||||
|
test_header!(test1, vec![b"gzip"], Some(ContentEncoding(vec![Encoding::Gzip])));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bench_header!(single, ContentEncoding, { vec![b"gzip".to_vec()] });
|
bench_header!(single, ContentEncoding, { vec![b"gzip".to_vec()] });
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ header! {
|
|||||||
#[doc="```plain"]
|
#[doc="```plain"]
|
||||||
#[doc="Content-Language = 1#language-tag"]
|
#[doc="Content-Language = 1#language-tag"]
|
||||||
#[doc="```"]
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `da`"]
|
||||||
|
#[doc="* `mi, en`"]
|
||||||
(ContentLanguage, "Content-Language") => (QualityItem<Language>)+
|
(ContentLanguage, "Content-Language") => (QualityItem<Language>)+
|
||||||
|
|
||||||
test_content_language {
|
test_content_language {
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ header! {
|
|||||||
#[doc="```plain"]
|
#[doc="```plain"]
|
||||||
#[doc="Content-Length = 1*DIGIT"]
|
#[doc="Content-Length = 1*DIGIT"]
|
||||||
#[doc="```"]
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `3495`"]
|
||||||
(ContentLength, "Content-Length") => [u64]
|
(ContentLength, "Content-Length") => [u64]
|
||||||
|
|
||||||
test_content_length {
|
test_content_length {
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ header! {
|
|||||||
#[doc="```plain"]
|
#[doc="```plain"]
|
||||||
#[doc="Content-Type = media-type"]
|
#[doc="Content-Type = media-type"]
|
||||||
#[doc="```"]
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `text/html; charset=ISO-8859-4`"]
|
||||||
(ContentType, "Content-Type") => [Mime]
|
(ContentType, "Content-Type") => [Mime]
|
||||||
|
|
||||||
test_content_type {
|
test_content_type {
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ header! {
|
|||||||
#[doc="```plain"]
|
#[doc="```plain"]
|
||||||
#[doc="Date = HTTP-date"]
|
#[doc="Date = HTTP-date"]
|
||||||
#[doc="```"]
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `Tue, 15 Nov 1994 08:12:31 GMT`"]
|
||||||
(Date, "Date") => [HttpDate]
|
(Date, "Date") => [HttpDate]
|
||||||
|
|
||||||
test_date {
|
test_date {
|
||||||
|
|||||||
@@ -17,63 +17,30 @@ header! {
|
|||||||
#[doc="```plain"]
|
#[doc="```plain"]
|
||||||
#[doc="ETag = entity-tag"]
|
#[doc="ETag = entity-tag"]
|
||||||
#[doc="```"]
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `\"xyzzy\"`"]
|
||||||
|
#[doc="* `W/\"xyzzy\"`"]
|
||||||
|
#[doc="* `\"\"`"]
|
||||||
(ETag, "ETag") => [EntityTag]
|
(ETag, "ETag") => [EntityTag]
|
||||||
|
|
||||||
test_etag {
|
test_etag {
|
||||||
test_header!(test1, vec![b"\"xyzzy\""], Some(HeaderField(EntityTag::new(false, "xyzzy".to_string()))));
|
// From the RFC
|
||||||
test_header!(test2, vec![b"W/\"xyzzy\""], Some(HeaderField(EntityTag::new(true, "xyzzy".to_string()))));
|
test_header!(test1, vec![b"\"xyzzy\""], Some(ETag(EntityTag::new(false, "xyzzy".to_string()))));
|
||||||
test_header!(test3, vec![b"\"\""], Some(HeaderField(EntityTag::new(false, "".to_string()))));
|
test_header!(test2, vec![b"W/\"xyzzy\""], Some(ETag(EntityTag::new(true, "xyzzy".to_string()))));
|
||||||
}
|
test_header!(test3, vec![b"\"\""], Some(ETag(EntityTag::new(false, "".to_string()))));
|
||||||
}
|
// Own tests
|
||||||
|
test_header!(test4, vec![b"\"foobar\""], Some(ETag(EntityTag::new(false, "foobar".to_string()))));
|
||||||
#[cfg(test)]
|
test_header!(test5, vec![b"\"\""], Some(ETag(EntityTag::new(false, "".to_string()))));
|
||||||
mod tests {
|
test_header!(test6, vec![b"W/\"weak-etag\""], Some(ETag(EntityTag::new(true, "weak-etag".to_string()))));
|
||||||
use super::ETag;
|
test_header!(test7, vec![b"W/\"\x65\x62\""], Some(ETag(EntityTag::new(true, "\u{0065}\u{0062}".to_string()))));
|
||||||
use header::{Header,EntityTag};
|
test_header!(test8, vec![b"W/\"\""], Some(ETag(EntityTag::new(true, "".to_string()))));
|
||||||
|
test_header!(test9, vec![b"no-dquotes"], None::<ETag>);
|
||||||
#[test]
|
test_header!(test10, vec![b"w/\"the-first-w-is-case-sensitive\""], None::<ETag>);
|
||||||
fn test_etag_successes() {
|
test_header!(test11, vec![b""], None::<ETag>);
|
||||||
// Expected successes
|
test_header!(test12, vec![b"\"unmatched-dquotes1"], None::<ETag>);
|
||||||
let mut etag: Option<ETag>;
|
test_header!(test13, vec![b"unmatched-dquotes2\""], None::<ETag>);
|
||||||
|
test_header!(test14, vec![b"matched-\"dquotes\""], None::<ETag>);
|
||||||
etag = Header::parse_header([b"\"foobar\"".to_vec()].as_ref());
|
|
||||||
assert_eq!(etag, Some(ETag(EntityTag::new(false, "foobar".to_string()))));
|
|
||||||
|
|
||||||
etag = Header::parse_header([b"\"\"".to_vec()].as_ref());
|
|
||||||
assert_eq!(etag, Some(ETag(EntityTag::new(false, "".to_string()))));
|
|
||||||
|
|
||||||
etag = Header::parse_header([b"W/\"weak-etag\"".to_vec()].as_ref());
|
|
||||||
assert_eq!(etag, Some(ETag(EntityTag::new(true, "weak-etag".to_string()))));
|
|
||||||
|
|
||||||
etag = Header::parse_header([b"W/\"\x65\x62\"".to_vec()].as_ref());
|
|
||||||
assert_eq!(etag, Some(ETag(EntityTag::new(true, "\u{0065}\u{0062}".to_string()))));
|
|
||||||
|
|
||||||
etag = Header::parse_header([b"W/\"\"".to_vec()].as_ref());
|
|
||||||
assert_eq!(etag, Some(ETag(EntityTag::new(true, "".to_string()))));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_etag_failures() {
|
|
||||||
// Expected failures
|
|
||||||
let mut etag: Option<ETag>;
|
|
||||||
|
|
||||||
etag = Header::parse_header([b"no-dquotes".to_vec()].as_ref());
|
|
||||||
assert_eq!(etag, None);
|
|
||||||
|
|
||||||
etag = Header::parse_header([b"w/\"the-first-w-is-case-sensitive\"".to_vec()].as_ref());
|
|
||||||
assert_eq!(etag, None);
|
|
||||||
|
|
||||||
etag = Header::parse_header([b"".to_vec()].as_ref());
|
|
||||||
assert_eq!(etag, None);
|
|
||||||
|
|
||||||
etag = Header::parse_header([b"\"unmatched-dquotes1".to_vec()].as_ref());
|
|
||||||
assert_eq!(etag, None);
|
|
||||||
|
|
||||||
etag = Header::parse_header([b"unmatched-dquotes2\"".to_vec()].as_ref());
|
|
||||||
assert_eq!(etag, None);
|
|
||||||
|
|
||||||
etag = Header::parse_header([b"matched-\"dquotes\"".to_vec()].as_ref());
|
|
||||||
assert_eq!(etag, None);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ header! {
|
|||||||
#[doc="```plain"]
|
#[doc="```plain"]
|
||||||
#[doc="Expires = HTTP-date"]
|
#[doc="Expires = HTTP-date"]
|
||||||
#[doc="```"]
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `Thu, 01 Dec 1994 16:00:00 GMT`"]
|
||||||
(Expires, "Expires") => [HttpDate]
|
(Expires, "Expires") => [HttpDate]
|
||||||
|
|
||||||
test_expires {
|
test_expires {
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ header! {
|
|||||||
#[doc="```plain"]
|
#[doc="```plain"]
|
||||||
#[doc="If-Match = \"*\" / 1#entity-tag"]
|
#[doc="If-Match = \"*\" / 1#entity-tag"]
|
||||||
#[doc="```"]
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `\"xyzzy\"`"]
|
||||||
|
#[doc="* \"xyzzy\", \"r2d2xxxx\", \"c3piozzzz\""]
|
||||||
(IfMatch, "If-Match") => {Any / (EntityTag)+}
|
(IfMatch, "If-Match") => {Any / (EntityTag)+}
|
||||||
|
|
||||||
test_if_match {
|
test_if_match {
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ header! {
|
|||||||
#[doc="```plain"]
|
#[doc="```plain"]
|
||||||
#[doc="If-Unmodified-Since = HTTP-date"]
|
#[doc="If-Unmodified-Since = HTTP-date"]
|
||||||
#[doc="```"]
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `Sat, 29 Oct 1994 19:43:31 GMT`"]
|
||||||
(IfModifiedSince, "If-Modified-Since") => [HttpDate]
|
(IfModifiedSince, "If-Modified-Since") => [HttpDate]
|
||||||
|
|
||||||
test_if_modified_since {
|
test_if_modified_since {
|
||||||
|
|||||||
@@ -19,6 +19,13 @@ header! {
|
|||||||
#[doc="```plain"]
|
#[doc="```plain"]
|
||||||
#[doc="If-None-Match = \"*\" / 1#entity-tag"]
|
#[doc="If-None-Match = \"*\" / 1#entity-tag"]
|
||||||
#[doc="```"]
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `\"xyzzy\"`"]
|
||||||
|
#[doc="* `W/\"xyzzy\"`"]
|
||||||
|
#[doc="* `\"xyzzy\", \"r2d2xxxx\", \"c3piozzzz\"`"]
|
||||||
|
#[doc="* `W/\"xyzzy\", W/\"r2d2xxxx\", W/\"c3piozzzz\"`"]
|
||||||
|
#[doc="* `*`"]
|
||||||
(IfNoneMatch, "If-None-Match") => {Any / (EntityTag)+}
|
(IfNoneMatch, "If-None-Match") => {Any / (EntityTag)+}
|
||||||
|
|
||||||
test_if_none_match {
|
test_if_none_match {
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ header! {
|
|||||||
#[doc="```plain"]
|
#[doc="```plain"]
|
||||||
#[doc="If-Unmodified-Since = HTTP-date"]
|
#[doc="If-Unmodified-Since = HTTP-date"]
|
||||||
#[doc="```"]
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `Sat, 29 Oct 1994 19:43:31 GMT`"]
|
||||||
(IfUnmodifiedSince, "If-Unmodified-Since") => [HttpDate]
|
(IfUnmodifiedSince, "If-Unmodified-Since") => [HttpDate]
|
||||||
|
|
||||||
test_if_unmodified_since {
|
test_if_unmodified_since {
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ header! {
|
|||||||
#[doc="```plain"]
|
#[doc="```plain"]
|
||||||
#[doc="Expires = HTTP-date"]
|
#[doc="Expires = HTTP-date"]
|
||||||
#[doc="```"]
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `Sat, 29 Oct 1994 19:43:31 GMT`"]
|
||||||
(LastModified, "Last-Modified") => [HttpDate]
|
(LastModified, "Last-Modified") => [HttpDate]
|
||||||
|
|
||||||
test_last_modified {
|
test_last_modified {
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ header! {
|
|||||||
#[doc="```plain"]
|
#[doc="```plain"]
|
||||||
#[doc="Location = URI-reference"]
|
#[doc="Location = URI-reference"]
|
||||||
#[doc="```"]
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `/People.html#tim`"]
|
||||||
|
#[doc="* `http://www.example.net/index.html`"]
|
||||||
// TODO: Use URL
|
// TODO: Use URL
|
||||||
(Location, "Location") => [String]
|
(Location, "Location") => [String]
|
||||||
|
|
||||||
|
|||||||
@@ -118,11 +118,13 @@ macro_rules! test_header {
|
|||||||
// Test parsing
|
// Test parsing
|
||||||
assert_eq!(val, $typed);
|
assert_eq!(val, $typed);
|
||||||
// Test formatting
|
// Test formatting
|
||||||
|
if $typed != None {
|
||||||
let res: &str = str::from_utf8($raw[0]).unwrap();
|
let res: &str = str::from_utf8($raw[0]).unwrap();
|
||||||
assert_eq!(format!("{}", $typed.unwrap()), res);
|
assert_eq!(format!("{}", $typed.unwrap()), res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! header {
|
macro_rules! header {
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ header! {
|
|||||||
#[doc="```plain"]
|
#[doc="```plain"]
|
||||||
#[doc="Referer = absolute-URI / partial-URI"]
|
#[doc="Referer = absolute-URI / partial-URI"]
|
||||||
#[doc="```"]
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `http://www.example.org/hypertext/Overview.html`"]
|
||||||
// TODO: Use URL
|
// TODO: Use URL
|
||||||
(Referer, "Referer") => [String]
|
(Referer, "Referer") => [String]
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ header! {
|
|||||||
#[doc="```plain"]
|
#[doc="```plain"]
|
||||||
#[doc="Server = product *( RWS ( product / comment ) )"]
|
#[doc="Server = product *( RWS ( product / comment ) )"]
|
||||||
#[doc="```"]
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `CERN/3.0 libwww/2.17`"]
|
||||||
// TODO: Maybe parse as defined in the spec?
|
// TODO: Maybe parse as defined in the spec?
|
||||||
(Server, "Server") => [String]
|
(Server, "Server") => [String]
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ header! {
|
|||||||
#[doc="```plain"]
|
#[doc="```plain"]
|
||||||
#[doc="Transfer-Encoding = 1#transfer-coding"]
|
#[doc="Transfer-Encoding = 1#transfer-coding"]
|
||||||
#[doc="```"]
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `gzip, chunked`"]
|
||||||
(TransferEncoding, "Transfer-Encoding") => (Encoding)+
|
(TransferEncoding, "Transfer-Encoding") => (Encoding)+
|
||||||
|
|
||||||
transfer_encoding {
|
transfer_encoding {
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ header! {
|
|||||||
#[doc="protocol-name = token"]
|
#[doc="protocol-name = token"]
|
||||||
#[doc="protocol-version = token"]
|
#[doc="protocol-version = token"]
|
||||||
#[doc="```"]
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11`"]
|
||||||
(Upgrade, "Upgrade") => (Protocol)+
|
(Upgrade, "Upgrade") => (Protocol)+
|
||||||
|
|
||||||
test_upgrade {
|
test_upgrade {
|
||||||
@@ -41,6 +44,7 @@ header! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Protocol values that can appear in the Upgrade header.
|
/// Protocol values that can appear in the Upgrade header.
|
||||||
|
// TODO: Parse version part seperately
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub enum Protocol {
|
pub enum Protocol {
|
||||||
/// The websocket protocol.
|
/// The websocket protocol.
|
||||||
|
|||||||
@@ -16,19 +16,19 @@ header! {
|
|||||||
#[doc="product = token [\"/\" product-version]"]
|
#[doc="product = token [\"/\" product-version]"]
|
||||||
#[doc="product-version = token"]
|
#[doc="product-version = token"]
|
||||||
#[doc="```"]
|
#[doc="```"]
|
||||||
// TODO: Maybe write parsing according to the spec? (Split the String)
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `CERN-LineMode/2.15 libwww/2.17b3`"]
|
||||||
|
#[doc="* `Bunnies`"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Notes"]
|
||||||
|
#[doc="* The parser does not split the value"]
|
||||||
(UserAgent, "User-Agent") => [String]
|
(UserAgent, "User-Agent") => [String]
|
||||||
|
|
||||||
test_user_agent {
|
test_user_agent {
|
||||||
// Testcase from RFC
|
// Testcase from RFC
|
||||||
test_header!(test1, vec![b"CERN-LineMode/2.15 libwww/2.17b3"]);
|
test_header!(test1, vec![b"CERN-LineMode/2.15 libwww/2.17b3"]);
|
||||||
|
// Own testcase
|
||||||
|
test_header!(test2, vec![b"Bunnies"], Some(UserAgent("Bunnies".to_string())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test] fn test_format() {
|
|
||||||
use std::borrow::ToOwned;
|
|
||||||
use header::Headers;
|
|
||||||
let mut head = Headers::new();
|
|
||||||
head.set(UserAgent("Bunnies".to_owned()));
|
|
||||||
assert!(head.to_string() == "User-Agent: Bunnies\r\n".to_owned());
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -14,20 +14,16 @@ header! {
|
|||||||
#[doc="```plain"]
|
#[doc="```plain"]
|
||||||
#[doc="Vary = \"*\" / 1#field-name"]
|
#[doc="Vary = \"*\" / 1#field-name"]
|
||||||
#[doc="```"]
|
#[doc="```"]
|
||||||
|
#[doc=""]
|
||||||
|
#[doc="# Example values"]
|
||||||
|
#[doc="* `accept-encoding, accept-language`"]
|
||||||
(Vary, "Vary") => {Any / (UniCase<String>)+}
|
(Vary, "Vary") => {Any / (UniCase<String>)+}
|
||||||
|
|
||||||
test_vary {
|
test_vary {
|
||||||
test_header!(test1, vec![b"accept-encoding, accept-language"]);
|
test_header!(test1, vec![b"accept-encoding, accept-language"]);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::Vary;
|
|
||||||
use header::Header;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_vary() {
|
fn test2() {
|
||||||
let mut vary: Option<Vary>;
|
let mut vary: Option<Vary>;
|
||||||
|
|
||||||
vary = Header::parse_header([b"*".to_vec()].as_ref());
|
vary = Header::parse_header([b"*".to_vec()].as_ref());
|
||||||
@@ -39,3 +35,4 @@ mod tests {
|
|||||||
"AlLOw".parse().unwrap(),])));
|
"AlLOw".parse().unwrap(),])));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -31,7 +31,10 @@ pub fn from_one_comma_delimited<T: str::FromStr>(raw: &[u8]) -> Option<Vec<T>> {
|
|||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
Some(s
|
Some(s
|
||||||
.split(',')
|
.split(',')
|
||||||
.map(|x| x.trim())
|
.filter_map(|x| match x.trim() {
|
||||||
|
"" => None,
|
||||||
|
y => Some(y)
|
||||||
|
})
|
||||||
.filter_map(|x| x.parse().ok())
|
.filter_map(|x| x.parse().ok())
|
||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
@@ -40,13 +43,12 @@ pub fn from_one_comma_delimited<T: str::FromStr>(raw: &[u8]) -> Option<Vec<T>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Format an array into a comma-delimited string.
|
/// Format an array into a comma-delimited string.
|
||||||
pub fn fmt_comma_delimited<T: fmt::Display>(fmt: &mut fmt::Formatter, parts: &[T]) -> fmt::Result {
|
pub fn fmt_comma_delimited<T: fmt::Display>(f: &mut fmt::Formatter, parts: &[T]) -> fmt::Result {
|
||||||
let last = parts.len() - 1;
|
|
||||||
for (i, part) in parts.iter().enumerate() {
|
for (i, part) in parts.iter().enumerate() {
|
||||||
try!(write!(fmt, "{}", part));
|
if i > 0 {
|
||||||
if i < last {
|
try!(write!(f, ", "));
|
||||||
try!(write!(fmt, ", "));
|
|
||||||
}
|
}
|
||||||
|
try!(write!(f, "{}", part));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ pub struct Quality(pub u16);
|
|||||||
|
|
||||||
impl fmt::Display for Quality {
|
impl fmt::Display for Quality {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
if self.0 == 1000 {
|
match self.0 {
|
||||||
write!(f, "")
|
1000 => Ok(()),
|
||||||
} else {
|
0 => f.write_str("; q=0"),
|
||||||
write!(f, "; q=0.{}", format!("{:03}", self.0).trim_right_matches('0'))
|
x => write!(f, "; q=0.{}", format!("{:03}", x).trim_right_matches('0'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,6 +196,11 @@ mod tests {
|
|||||||
assert_eq!(q(0.5), Quality(500));
|
assert_eq!(q(0.5), Quality(500));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_quality2() {
|
||||||
|
assert_eq!(format!("{}", q(0.0)), "; q=0");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn test_quality_invalid() {
|
fn test_quality_invalid() {
|
||||||
|
|||||||
Reference in New Issue
Block a user