Merge pull request #503 from pyfisch/nice2
refactor(headers): Improve docs, fix nits, make formatting faster
This commit is contained in:
@@ -48,7 +48,9 @@ header! {
|
|||||||
Some(HeaderField(vec![
|
Some(HeaderField(vec![
|
||||||
QualityItem::new(Mime(TopLevel::Text, SubLevel::Plain, vec![]), Quality(500)),
|
QualityItem::new(Mime(TopLevel::Text, SubLevel::Plain, vec![]), Quality(500)),
|
||||||
qitem(Mime(TopLevel::Text, SubLevel::Html, vec![])),
|
qitem(Mime(TopLevel::Text, SubLevel::Html, vec![])),
|
||||||
QualityItem::new(Mime(TopLevel::Text, SubLevel::Ext("x-dvi".to_string()), vec![]), Quality(800)),
|
QualityItem::new(
|
||||||
|
Mime(TopLevel::Text, SubLevel::Ext("x-dvi".to_string()), vec![]),
|
||||||
|
Quality(800)),
|
||||||
qitem(Mime(TopLevel::Text, SubLevel::Ext("x-c".to_string()), vec![])),
|
qitem(Mime(TopLevel::Text, SubLevel::Ext("x-c".to_string()), vec![])),
|
||||||
])));
|
])));
|
||||||
// Custom tests
|
// Custom tests
|
||||||
@@ -62,7 +64,9 @@ header! {
|
|||||||
test4,
|
test4,
|
||||||
vec![b"text/plain; charset=utf-8; q=0.5"],
|
vec![b"text/plain; charset=utf-8; q=0.5"],
|
||||||
Some(Accept(vec![
|
Some(Accept(vec![
|
||||||
QualityItem::new(Mime(TopLevel::Text, SubLevel::Plain, vec![(Attr::Charset, Value::Utf8)]), Quality(500)),
|
QualityItem::new(Mime(TopLevel::Text,
|
||||||
|
SubLevel::Plain, vec![(Attr::Charset, Value::Utf8)]),
|
||||||
|
Quality(500)),
|
||||||
])));
|
])));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use unicase::UniCase;
|
|||||||
|
|
||||||
header! {
|
header! {
|
||||||
#[doc="`Access-Control-Allow-Headers` header, part of"]
|
#[doc="`Access-Control-Allow-Headers` header, part of"]
|
||||||
#[doc="[CORS](www.w3.org/TR/cors/#access-control-allow-headers-response-header)"]
|
#[doc="[CORS](http://www.w3.org/TR/cors/#access-control-allow-headers-response-header)"]
|
||||||
#[doc=""]
|
#[doc=""]
|
||||||
#[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"]
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use method::Method;
|
|||||||
|
|
||||||
header! {
|
header! {
|
||||||
#[doc="`Access-Control-Allow-Methods` header, part of"]
|
#[doc="`Access-Control-Allow-Methods` header, part of"]
|
||||||
#[doc="[CORS](www.w3.org/TR/cors/#access-control-allow-methods-response-header)"]
|
#[doc="[CORS](http://www.w3.org/TR/cors/#access-control-allow-methods-response-header)"]
|
||||||
#[doc=""]
|
#[doc=""]
|
||||||
#[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"]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
header! {
|
header! {
|
||||||
#[doc="`Access-Control-Max-Age` header, part of"]
|
#[doc="`Access-Control-Max-Age` header, part of"]
|
||||||
#[doc="[CORS](www.w3.org/TR/cors/#access-control-max-age-response-header)"]
|
#[doc="[CORS](http://www.w3.org/TR/cors/#access-control-max-age-response-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."]
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use unicase::UniCase;
|
|||||||
|
|
||||||
header! {
|
header! {
|
||||||
#[doc="`Access-Control-Request-Headers` header, part of"]
|
#[doc="`Access-Control-Request-Headers` header, part of"]
|
||||||
#[doc="[CORS](www.w3.org/TR/cors/#access-control-request-headers-request-header)"]
|
#[doc="[CORS](http://www.w3.org/TR/cors/#access-control-request-headers-request-header)"]
|
||||||
#[doc=""]
|
#[doc=""]
|
||||||
#[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."]
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use method::Method;
|
|||||||
|
|
||||||
header! {
|
header! {
|
||||||
#[doc="`Access-Control-Request-Method` header, part of"]
|
#[doc="`Access-Control-Request-Method` header, part of"]
|
||||||
#[doc="[CORS](www.w3.org/TR/cors/#access-control-request-method-request-header)"]
|
#[doc="[CORS](http://www.w3.org/TR/cors/#access-control-request-method-request-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."]
|
||||||
|
|||||||
@@ -47,4 +47,5 @@ header! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bench_header!(bench, Allow, { vec![b"OPTIONS,GET,PUT,POST,DELETE,HEAD,TRACE,CONNECT,PATCH,fOObAr".to_vec()] });
|
bench_header!(bench,
|
||||||
|
Allow, { vec![b"OPTIONS,GET,PUT,POST,DELETE,HEAD,TRACE,CONNECT,PATCH,fOObAr".to_vec()] });
|
||||||
|
|||||||
@@ -1,11 +1,25 @@
|
|||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::fmt;
|
use std::fmt::{self, Display};
|
||||||
use std::str::{FromStr, from_utf8};
|
use std::str::{FromStr, from_utf8};
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use serialize::base64::{ToBase64, FromBase64, Standard, Config, Newline};
|
use serialize::base64::{ToBase64, FromBase64, Standard, Config, Newline};
|
||||||
use header::{Header, HeaderFormat};
|
use header::{Header, HeaderFormat};
|
||||||
|
|
||||||
/// The `Authorization` header field.
|
/// `Authorization` header, defined in [RFC7235](https://tools.ietf.org/html/rfc7235#section-4.2)
|
||||||
|
///
|
||||||
|
/// The `Authorization` header field allows a user agent to authenticate
|
||||||
|
/// itself with an origin server -- usually, but not necessarily, after
|
||||||
|
/// receiving a 401 (Unauthorized) response. Its value consists of
|
||||||
|
/// credentials containing the authentication information of the user
|
||||||
|
/// agent for the realm of the resource being requested.
|
||||||
|
///
|
||||||
|
/// # ABNF
|
||||||
|
/// ```plain
|
||||||
|
/// Authorization = credentials
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Example values
|
||||||
|
/// * `Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==`
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub struct Authorization<S: Scheme>(pub S);
|
pub struct Authorization<S: Scheme>(pub S);
|
||||||
|
|
||||||
@@ -69,7 +83,7 @@ impl Scheme for String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn fmt_scheme(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt_scheme(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt::Display::fmt(self, f)
|
Display::fmt(self, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,12 +111,12 @@ impl Scheme for Basic {
|
|||||||
if let Some(ref pass) = self.password {
|
if let Some(ref pass) = self.password {
|
||||||
text.push_str(&pass[..]);
|
text.push_str(&pass[..]);
|
||||||
}
|
}
|
||||||
write!(f, "{}", text.as_bytes().to_base64(Config {
|
f.write_str(&text.as_bytes().to_base64(Config {
|
||||||
char_set: Standard,
|
char_set: Standard,
|
||||||
newline: Newline::CRLF,
|
newline: Newline::CRLF,
|
||||||
pad: true,
|
pad: true,
|
||||||
line_length: None
|
line_length: None
|
||||||
}))
|
})[..])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,15 +167,19 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_raw_auth_parse() {
|
fn test_raw_auth_parse() {
|
||||||
let header: Authorization<String> = Header::parse_header(&[b"foo bar baz".to_vec()]).unwrap();
|
let header: Authorization<String> = Header::parse_header(
|
||||||
|
&[b"foo bar baz".to_vec()]).unwrap();
|
||||||
assert_eq!(header.0, "foo bar baz");
|
assert_eq!(header.0, "foo bar baz");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_basic_auth() {
|
fn test_basic_auth() {
|
||||||
let mut headers = Headers::new();
|
let mut headers = Headers::new();
|
||||||
headers.set(Authorization(Basic { username: "Aladdin".to_string(), password: Some("open sesame".to_string()) }));
|
headers.set(Authorization(
|
||||||
assert_eq!(headers.to_string(), "Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==\r\n".to_string());
|
Basic { username: "Aladdin".to_string(), password: Some("open sesame".to_string()) }));
|
||||||
|
assert_eq!(
|
||||||
|
headers.to_string(),
|
||||||
|
"Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==\r\n".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -173,14 +191,16 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_basic_auth_parse() {
|
fn test_basic_auth_parse() {
|
||||||
let auth: Authorization<Basic> = Header::parse_header(&[b"Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==".to_vec()]).unwrap();
|
let auth: Authorization<Basic> = Header::parse_header(
|
||||||
|
&[b"Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==".to_vec()]).unwrap();
|
||||||
assert_eq!(auth.0.username, "Aladdin");
|
assert_eq!(auth.0.username, "Aladdin");
|
||||||
assert_eq!(auth.0.password, Some("open sesame".to_string()));
|
assert_eq!(auth.0.password, Some("open sesame".to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_basic_auth_parse_no_password() {
|
fn test_basic_auth_parse_no_password() {
|
||||||
let auth: Authorization<Basic> = Header::parse_header(&[b"Basic QWxhZGRpbjo=".to_vec()]).unwrap();
|
let auth: Authorization<Basic> = Header::parse_header(
|
||||||
|
&[b"Basic QWxhZGRpbjo=".to_vec()]).unwrap();
|
||||||
assert_eq!(auth.0.username, "Aladdin");
|
assert_eq!(auth.0.username, "Aladdin");
|
||||||
assert_eq!(auth.0.password, Some("".to_string()));
|
assert_eq!(auth.0.password, Some("".to_string()));
|
||||||
}
|
}
|
||||||
@@ -188,4 +208,4 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bench_header!(raw, Authorization<String>, { vec![b"foo bar baz".to_vec()] });
|
bench_header!(raw, Authorization<String>, { vec![b"foo bar baz".to_vec()] });
|
||||||
bench_header!(basic, Authorization<Basic>, { vec![b"Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==".to_vec()] });
|
bench_header!(basic, Authorization<Basic>, { vec![b"Basic QWxhZGRpbjpuIHNlc2FtZQ==".to_vec()] });
|
||||||
|
|||||||
@@ -3,7 +3,23 @@ use std::str::FromStr;
|
|||||||
use header::{Header, HeaderFormat};
|
use header::{Header, HeaderFormat};
|
||||||
use header::parsing::{from_one_comma_delimited, fmt_comma_delimited};
|
use header::parsing::{from_one_comma_delimited, fmt_comma_delimited};
|
||||||
|
|
||||||
/// The Cache-Control header.
|
/// `Cache-Control` header, defined in [RFC7234](https://tools.ietf.org/html/rfc7234#section-5.2)
|
||||||
|
///
|
||||||
|
/// The `Cache-Control` header field is used to specify directives for
|
||||||
|
/// caches along the request/response chain. Such cache directives are
|
||||||
|
/// unidirectional in that the presence of a directive in a request does
|
||||||
|
/// not imply that the same directive is to be given in the response.
|
||||||
|
///
|
||||||
|
/// # ABNF
|
||||||
|
/// ```plain
|
||||||
|
/// Cache-Control = 1#cache-directive
|
||||||
|
/// cache-directive = token [ "=" ( token / quoted-string ) ]
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Example values
|
||||||
|
/// * `no-cache`
|
||||||
|
/// * `private, community="UCI"`
|
||||||
|
/// * `max-age=30`
|
||||||
#[derive(PartialEq, Clone, Debug)]
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
pub struct CacheControl(pub Vec<CacheDirective>);
|
pub struct CacheControl(pub Vec<CacheDirective>);
|
||||||
|
|
||||||
@@ -28,8 +44,8 @@ impl Header for CacheControl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl HeaderFormat for CacheControl {
|
impl HeaderFormat for CacheControl {
|
||||||
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt_comma_delimited(fmt, &self[..])
|
fmt_comma_delimited(f, &self[..])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,8 +168,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_parse_extension() {
|
fn test_parse_extension() {
|
||||||
let cache = Header::parse_header(&[b"foo, bar=baz".to_vec()]);
|
let cache = Header::parse_header(&[b"foo, bar=baz".to_vec()]);
|
||||||
assert_eq!(cache, Some(CacheControl(vec![CacheDirective::Extension("foo".to_string(), None),
|
assert_eq!(cache, Some(CacheControl(vec![
|
||||||
CacheDirective::Extension("bar".to_string(), Some("baz".to_string()))])))
|
CacheDirective::Extension("foo".to_string(), None),
|
||||||
|
CacheDirective::Extension("bar".to_string(), Some("baz".to_string()))])))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -163,4 +180,5 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bench_header!(normal, CacheControl, { vec![b"no-cache, private".to_vec(), b"max-age=100".to_vec()] });
|
bench_header!(normal,
|
||||||
|
CacheControl, { vec![b"no-cache, private".to_vec(), b"max-age=100".to_vec()] });
|
||||||
|
|||||||
@@ -1,12 +1,29 @@
|
|||||||
use header::{Header, HeaderFormat};
|
use header::{Header, HeaderFormat};
|
||||||
use std::fmt;
|
use std::fmt::{self, Display};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use header::parsing::{from_comma_delimited, fmt_comma_delimited};
|
use header::parsing::{from_comma_delimited, fmt_comma_delimited};
|
||||||
use unicase::UniCase;
|
use unicase::UniCase;
|
||||||
|
|
||||||
pub use self::ConnectionOption::{KeepAlive, Close, ConnectionHeader};
|
pub use self::ConnectionOption::{KeepAlive, Close, ConnectionHeader};
|
||||||
|
|
||||||
/// The `Connection` header.
|
/// `Connection` header, defined in [RFC7230](https://tools.ietf.org/html/rfc7230#section-6.1)
|
||||||
|
///
|
||||||
|
/// The `Connection` header field allows the sender to indicate desired
|
||||||
|
/// control options for the current connection. In order to avoid
|
||||||
|
/// confusing downstream recipients, a proxy or gateway MUST remove or
|
||||||
|
/// replace any received connection options before forwarding the
|
||||||
|
/// message.
|
||||||
|
///
|
||||||
|
/// # ABNF
|
||||||
|
/// ```plain
|
||||||
|
/// Connection = 1#connection-option
|
||||||
|
/// connection-option = token
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Example values
|
||||||
|
/// * `close`
|
||||||
|
/// * `upgrade`
|
||||||
|
/// * `keep-alive`
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub struct Connection(pub Vec<ConnectionOption>);
|
pub struct Connection(pub Vec<ConnectionOption>);
|
||||||
|
|
||||||
@@ -33,20 +50,20 @@ pub enum ConnectionOption {
|
|||||||
impl FromStr for ConnectionOption {
|
impl FromStr for ConnectionOption {
|
||||||
type Err = ();
|
type Err = ();
|
||||||
fn from_str(s: &str) -> Result<ConnectionOption, ()> {
|
fn from_str(s: &str) -> Result<ConnectionOption, ()> {
|
||||||
match s {
|
Ok(match s {
|
||||||
"keep-alive" => Ok(KeepAlive),
|
"keep-alive" => KeepAlive,
|
||||||
"close" => Ok(Close),
|
"close" => Close,
|
||||||
s => Ok(ConnectionHeader(UniCase(s.to_string())))
|
s => ConnectionHeader(UniCase(s.to_string())),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ConnectionOption {
|
impl Display for ConnectionOption {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(fmt, "{}", match *self {
|
f.write_str(match *self {
|
||||||
KeepAlive => "keep-alive",
|
KeepAlive => "keep-alive",
|
||||||
Close => "close",
|
Close => "close",
|
||||||
ConnectionHeader(UniCase(ref s)) => s.as_ref()
|
ConnectionHeader(UniCase(ref s)) => s,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,13 +79,12 @@ impl Header for Connection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl HeaderFormat for Connection {
|
impl HeaderFormat for Connection {
|
||||||
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let Connection(ref parts) = *self;
|
let Connection(ref parts) = *self;
|
||||||
fmt_comma_delimited(fmt, &parts[..])
|
fmt_comma_delimited(f, &parts[..])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bench_header!(close, Connection, { vec![b"close".to_vec()] });
|
bench_header!(close, Connection, { vec![b"close".to_vec()] });
|
||||||
bench_header!(keep_alive, Connection, { vec![b"keep-alive".to_vec()] });
|
bench_header!(keep_alive, Connection, { vec![b"keep-alive".to_vec()] });
|
||||||
bench_header!(header, Connection, { vec![b"authorization".to_vec()] });
|
bench_header!(header, Connection, { vec![b"authorization".to_vec()] });
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,10 @@ header! {
|
|||||||
// FIXME: Should be b"text/html; charset=ISO-8859-4" but mime crate lowercases
|
// FIXME: Should be b"text/html; charset=ISO-8859-4" but mime crate lowercases
|
||||||
// the whole value so parsing and formatting the value gives a different result
|
// the whole value so parsing and formatting the value gives a different result
|
||||||
vec![b"text/html; charset=iso-8859-4"],
|
vec![b"text/html; charset=iso-8859-4"],
|
||||||
Some(HeaderField(Mime(TopLevel::Text, SubLevel::Html, vec![(Attr::Charset, Value::Ext("iso-8859-4".to_string()))]))));
|
Some(HeaderField(Mime(
|
||||||
|
TopLevel::Text,
|
||||||
|
SubLevel::Html,
|
||||||
|
vec![(Attr::Charset, Value::Ext("iso-8859-4".to_string()))]))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,22 @@
|
|||||||
use header::{Header, HeaderFormat};
|
use header::{Header, HeaderFormat};
|
||||||
use std::fmt;
|
use std::fmt::{self, Display};
|
||||||
use std::str::from_utf8;
|
use std::str::from_utf8;
|
||||||
|
|
||||||
use cookie::Cookie as CookiePair;
|
use cookie::Cookie as CookiePair;
|
||||||
use cookie::CookieJar;
|
use cookie::CookieJar;
|
||||||
|
|
||||||
/// The `Cookie` header. Defined in [RFC6265](tools.ietf.org/html/rfc6265#section-5.4):
|
/// `Cookie` header, defined in [RFC6265](http://tools.ietf.org/html/rfc6265#section-5.4)
|
||||||
///
|
///
|
||||||
/// > If the user agent does attach a Cookie header field to an HTTP
|
/// If the user agent does attach a Cookie header field to an HTTP
|
||||||
/// > request, the user agent must send the cookie-string
|
/// request, the user agent must send the cookie-string
|
||||||
/// > as the value of the header field.
|
/// as the value of the header field.
|
||||||
///
|
///
|
||||||
/// > When the user agent generates an HTTP request, the user agent MUST NOT
|
/// When the user agent generates an HTTP request, the user agent MUST NOT
|
||||||
/// > attach more than one Cookie header field.
|
/// attach more than one Cookie header field.
|
||||||
|
///
|
||||||
|
/// # Example values
|
||||||
|
/// * `SID=31d4d96e407aad42`
|
||||||
|
/// * `SID=31d4d96e407aad42; lang=en-US`
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub struct Cookie(pub Vec<CookiePair>);
|
pub struct Cookie(pub Vec<CookiePair>);
|
||||||
|
|
||||||
@@ -48,13 +52,13 @@ impl Header for Cookie {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl HeaderFormat for Cookie {
|
impl HeaderFormat for Cookie {
|
||||||
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let cookies = &self.0;
|
let cookies = &self.0;
|
||||||
for (i, cookie) in cookies.iter().enumerate() {
|
for (i, cookie) in cookies.iter().enumerate() {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
try!(fmt.write_str("; "));
|
try!(f.write_str("; "));
|
||||||
}
|
}
|
||||||
try!(write!(fmt, "{}", cookie.pair()));
|
try!(Display::fmt(&cookie.pair(), f));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -94,7 +98,9 @@ fn test_fmt() {
|
|||||||
let mut cookie_pair = CookiePair::new("foo".to_string(), "bar".to_string());
|
let mut cookie_pair = CookiePair::new("foo".to_string(), "bar".to_string());
|
||||||
cookie_pair.httponly = true;
|
cookie_pair.httponly = true;
|
||||||
cookie_pair.path = Some("/p".to_string());
|
cookie_pair.path = Some("/p".to_string());
|
||||||
let cookie_header = Cookie(vec![cookie_pair, CookiePair::new("baz".to_string(), "quux".to_string())]);
|
let cookie_header = Cookie(vec![
|
||||||
|
cookie_pair,
|
||||||
|
CookiePair::new("baz".to_string(),"quux".to_string())]);
|
||||||
let mut headers = Headers::new();
|
let mut headers = Headers::new();
|
||||||
headers.set(cookie_header);
|
headers.set(cookie_header);
|
||||||
|
|
||||||
|
|||||||
@@ -26,21 +26,49 @@ header! {
|
|||||||
|
|
||||||
test_etag {
|
test_etag {
|
||||||
// From the RFC
|
// From the RFC
|
||||||
test_header!(test1, vec![b"\"xyzzy\""], Some(ETag(EntityTag::new(false, "xyzzy".to_string()))));
|
test_header!(test1,
|
||||||
test_header!(test2, vec![b"W/\"xyzzy\""], Some(ETag(EntityTag::new(true, "xyzzy".to_string()))));
|
vec![b"\"xyzzy\""],
|
||||||
test_header!(test3, vec![b"\"\""], Some(ETag(EntityTag::new(false, "".to_string()))));
|
Some(ETag(EntityTag::new(false, "xyzzy".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
|
// Own tests
|
||||||
test_header!(test4, vec![b"\"foobar\""], Some(ETag(EntityTag::new(false, "foobar".to_string()))));
|
test_header!(test4,
|
||||||
test_header!(test5, vec![b"\"\""], Some(ETag(EntityTag::new(false, "".to_string()))));
|
vec![b"\"foobar\""],
|
||||||
test_header!(test6, vec![b"W/\"weak-etag\""], Some(ETag(EntityTag::new(true, "weak-etag".to_string()))));
|
Some(ETag(EntityTag::new(false, "foobar".to_string()))));
|
||||||
test_header!(test7, vec![b"W/\"\x65\x62\""], Some(ETag(EntityTag::new(true, "\u{0065}\u{0062}".to_string()))));
|
test_header!(test5,
|
||||||
test_header!(test8, vec![b"W/\"\""], Some(ETag(EntityTag::new(true, "".to_string()))));
|
vec![b"\"\""],
|
||||||
test_header!(test9, vec![b"no-dquotes"], None::<ETag>);
|
Some(ETag(EntityTag::new(false, "".to_string()))));
|
||||||
test_header!(test10, vec![b"w/\"the-first-w-is-case-sensitive\""], None::<ETag>);
|
test_header!(test6,
|
||||||
test_header!(test11, vec![b""], None::<ETag>);
|
vec![b"W/\"weak-etag\""],
|
||||||
test_header!(test12, vec![b"\"unmatched-dquotes1"], None::<ETag>);
|
Some(ETag(EntityTag::new(true, "weak-etag".to_string()))));
|
||||||
test_header!(test13, vec![b"unmatched-dquotes2\""], None::<ETag>);
|
test_header!(test7,
|
||||||
test_header!(test14, vec![b"matched-\"dquotes\""], None::<ETag>);
|
vec![b"W/\"\x65\x62\""],
|
||||||
|
Some(ETag(EntityTag::new(true, "\u{0065}\u{0062}".to_string()))));
|
||||||
|
test_header!(test8,
|
||||||
|
vec![b"W/\"\""],
|
||||||
|
Some(ETag(EntityTag::new(true, "".to_string()))));
|
||||||
|
test_header!(test9,
|
||||||
|
vec![b"no-dquotes"],
|
||||||
|
None::<ETag>);
|
||||||
|
test_header!(test10,
|
||||||
|
vec![b"w/\"the-first-w-is-case-sensitive\""],
|
||||||
|
None::<ETag>);
|
||||||
|
test_header!(test11,
|
||||||
|
vec![b""],
|
||||||
|
None::<ETag>);
|
||||||
|
test_header!(test12,
|
||||||
|
vec![b"\"unmatched-dquotes1"],
|
||||||
|
None::<ETag>);
|
||||||
|
test_header!(test13,
|
||||||
|
vec![b"unmatched-dquotes2\""],
|
||||||
|
None::<ETag>);
|
||||||
|
test_header!(test14,
|
||||||
|
vec![b"matched-\"dquotes\""],
|
||||||
|
None::<ETag>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,10 +65,10 @@ impl Header for Host {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl HeaderFormat for Host {
|
impl HeaderFormat for Host {
|
||||||
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self.port {
|
match self.port {
|
||||||
None | Some(80) | Some(443) => write!(fmt, "{}", self.hostname),
|
None | Some(80) | Some(443) => f.write_str(&self.hostname[..]),
|
||||||
Some(port) => write!(fmt, "{}:{}", self.hostname, port)
|
Some(port) => write!(f, "{}:{}", self.hostname, port)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,4 +97,3 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bench_header!(bench, Host, { vec![b"foo.com:3000".to_vec()] });
|
bench_header!(bench, Host, { vec![b"foo.com:3000".to_vec()] });
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use header::{self, EntityTag, HttpDate};
|
use std::fmt::{self, Display};
|
||||||
|
use header::{self, Header, HeaderFormat, EntityTag, HttpDate};
|
||||||
|
|
||||||
/// `If-Range` header, defined in [RFC7233](http://tools.ietf.org/html/rfc7233#section-3.2)
|
/// `If-Range` header, defined in [RFC7233](http://tools.ietf.org/html/rfc7233#section-3.2)
|
||||||
///
|
///
|
||||||
@@ -31,7 +32,7 @@ pub enum IfRange {
|
|||||||
Date(HttpDate),
|
Date(HttpDate),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl header::Header for IfRange {
|
impl Header for IfRange {
|
||||||
fn header_name() -> &'static str {
|
fn header_name() -> &'static str {
|
||||||
"If-Range"
|
"If-Range"
|
||||||
}
|
}
|
||||||
@@ -48,18 +49,17 @@ impl header::Header for IfRange {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl header::HeaderFormat for IfRange {
|
impl HeaderFormat for IfRange {
|
||||||
fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
&IfRange::EntityTag(ref x) => write!(f, "{}", x),
|
&IfRange::EntityTag(ref x) => Display::fmt(x, f),
|
||||||
&IfRange::Date(ref x) => write!(f, "{}", x),
|
&IfRange::Date(ref x) => Display::fmt(x, f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::fmt::Display for IfRange {
|
impl Display for IfRange {
|
||||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
use header::HeaderFormat;
|
|
||||||
self.fmt_header(f)
|
self.fmt_header(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
use header::HttpDate;
|
use header::HttpDate;
|
||||||
|
|
||||||
header! {
|
header! {
|
||||||
#[doc="`Last-Modified` header, defined in [RFC7232](http://tools.ietf.org/html/rfc7232#section-2.2)"]
|
#[doc="`Last-Modified` header, defined in"]
|
||||||
|
#[doc="[RFC7232](http://tools.ietf.org/html/rfc7232#section-2.2)"]
|
||||||
#[doc=""]
|
#[doc=""]
|
||||||
#[doc="The `Last-Modified` header field in a response provides a timestamp"]
|
#[doc="The `Last-Modified` header field in a response provides a timestamp"]
|
||||||
#[doc="indicating the date and time at which the origin server believes the"]
|
#[doc="indicating the date and time at which the origin server believes the"]
|
||||||
|
|||||||
@@ -124,8 +124,16 @@ macro_rules! test_header {
|
|||||||
let value = HeaderField::parse_header(&a[..]);
|
let value = HeaderField::parse_header(&a[..]);
|
||||||
let result = format!("{}", value.unwrap());
|
let result = format!("{}", value.unwrap());
|
||||||
let expected = String::from_utf8(raw[0].to_vec()).unwrap();
|
let expected = String::from_utf8(raw[0].to_vec()).unwrap();
|
||||||
let result_cmp: Vec<String> = result.to_ascii_lowercase().split(' ').map(|x| x.to_string()).collect();
|
let result_cmp: Vec<String> = result
|
||||||
let expected_cmp: Vec<String> = expected.to_ascii_lowercase().split(' ').map(|x| x.to_string()).collect();
|
.to_ascii_lowercase()
|
||||||
|
.split(' ')
|
||||||
|
.map(|x| x.to_string())
|
||||||
|
.collect();
|
||||||
|
let expected_cmp: Vec<String> = expected
|
||||||
|
.to_ascii_lowercase()
|
||||||
|
.split(' ')
|
||||||
|
.map(|x| x.to_string())
|
||||||
|
.collect();
|
||||||
assert_eq!(result_cmp.concat(), expected_cmp.concat());
|
assert_eq!(result_cmp.concat(), expected_cmp.concat());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -258,8 +266,9 @@ macro_rules! header {
|
|||||||
impl $crate::header::HeaderFormat for $id {
|
impl $crate::header::HeaderFormat for $id {
|
||||||
fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
$id::Any => write!(f, "*"),
|
$id::Any => f.write_str("*"),
|
||||||
$id::Items(ref fields) => $crate::header::parsing::fmt_comma_delimited(f, &fields[..])
|
$id::Items(ref fields) => $crate::header::parsing::fmt_comma_delimited(
|
||||||
|
f, &fields[..])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,10 +42,10 @@ impl Header for Pragma {
|
|||||||
|
|
||||||
impl HeaderFormat for Pragma {
|
impl HeaderFormat for Pragma {
|
||||||
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
f.write_str(match *self {
|
||||||
Pragma::NoCache => write!(f, "no-cache"),
|
Pragma::NoCache => "no-cache",
|
||||||
Pragma::Ext(ref string) => write!(f, "{}", string),
|
Pragma::Ext(ref string) => &string[..],
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,59 @@
|
|||||||
use header::{Header, HeaderFormat};
|
use header::{Header, HeaderFormat};
|
||||||
use std::fmt;
|
use std::fmt::{self, Display};
|
||||||
use std::str::from_utf8;
|
use std::str::from_utf8;
|
||||||
|
|
||||||
use cookie::Cookie;
|
use cookie::Cookie;
|
||||||
use cookie::CookieJar;
|
use cookie::CookieJar;
|
||||||
|
|
||||||
/// The `Set-Cookie` header
|
/// `Set-Cookie` header, defined [RFC6265](http://tools.ietf.org/html/rfc6265#section-4.1)
|
||||||
|
///
|
||||||
|
/// The Set-Cookie HTTP response header is used to send cookies from the
|
||||||
|
/// server to the user agent.
|
||||||
///
|
///
|
||||||
/// Informally, the Set-Cookie response header contains the header name
|
/// Informally, the Set-Cookie response header contains the header name
|
||||||
/// "Set-Cookie" followed by a ":" and a cookie. Each cookie begins with
|
/// "Set-Cookie" followed by a ":" and a cookie. Each cookie begins with
|
||||||
/// a name-value-pair, followed by zero or more attribute-value pairs.
|
/// a name-value-pair, followed by zero or more attribute-value pairs.
|
||||||
|
///
|
||||||
|
/// # ABNF
|
||||||
|
/// ```plain
|
||||||
|
/// set-cookie-header = "Set-Cookie:" SP set-cookie-string
|
||||||
|
/// set-cookie-string = cookie-pair *( ";" SP cookie-av )
|
||||||
|
/// cookie-pair = cookie-name "=" cookie-value
|
||||||
|
/// cookie-name = token
|
||||||
|
/// cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
|
||||||
|
/// cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
|
||||||
|
/// ; US-ASCII characters excluding CTLs,
|
||||||
|
/// ; whitespace DQUOTE, comma, semicolon,
|
||||||
|
/// ; and backslash
|
||||||
|
/// token = <token, defined in [RFC2616], Section 2.2>
|
||||||
|
///
|
||||||
|
/// cookie-av = expires-av / max-age-av / domain-av /
|
||||||
|
/// path-av / secure-av / httponly-av /
|
||||||
|
/// extension-av
|
||||||
|
/// expires-av = "Expires=" sane-cookie-date
|
||||||
|
/// sane-cookie-date = <rfc1123-date, defined in [RFC2616], Section 3.3.1>
|
||||||
|
/// max-age-av = "Max-Age=" non-zero-digit *DIGIT
|
||||||
|
/// ; In practice, both expires-av and max-age-av
|
||||||
|
/// ; are limited to dates representable by the
|
||||||
|
/// ; user agent.
|
||||||
|
/// non-zero-digit = %x31-39
|
||||||
|
/// ; digits 1 through 9
|
||||||
|
/// domain-av = "Domain=" domain-value
|
||||||
|
/// domain-value = <subdomain>
|
||||||
|
/// ; defined in [RFC1034], Section 3.5, as
|
||||||
|
/// ; enhanced by [RFC1123], Section 2.1
|
||||||
|
/// path-av = "Path=" path-value
|
||||||
|
/// path-value = <any CHAR except CTLs or ";">
|
||||||
|
/// secure-av = "Secure"
|
||||||
|
/// httponly-av = "HttpOnly"
|
||||||
|
/// extension-av = <any CHAR except CTLs or ";">
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Example values
|
||||||
|
/// * `SID=31d4d96e407aad42`
|
||||||
|
/// * `lang=en-US; Expires=Wed, 09 Jun 2021 10:18:14 GMT`
|
||||||
|
/// * `lang=; Expires=Sun, 06 Nov 1994 08:49:37 GMT`
|
||||||
|
/// * `lang=en-US; Path=/; Domain=example.com`
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub struct SetCookie(pub Vec<Cookie>);
|
pub struct SetCookie(pub Vec<Cookie>);
|
||||||
|
|
||||||
@@ -46,7 +90,7 @@ impl HeaderFormat for SetCookie {
|
|||||||
if i != 0 {
|
if i != 0 {
|
||||||
try!(f.write_str("\r\nSet-Cookie: "));
|
try!(f.write_str("\r\nSet-Cookie: "));
|
||||||
}
|
}
|
||||||
try!(write!(f, "{}", cookie));
|
try!(Display::fmt(cookie, f));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -90,7 +134,9 @@ fn test_fmt() {
|
|||||||
let mut headers = Headers::new();
|
let mut headers = Headers::new();
|
||||||
headers.set(cookies);
|
headers.set(cookies);
|
||||||
|
|
||||||
assert_eq!(&headers.to_string()[..], "Set-Cookie: foo=bar; HttpOnly; Path=/p\r\nSet-Cookie: baz=quux; Path=/\r\n");
|
assert_eq!(
|
||||||
|
&headers.to_string()[..],
|
||||||
|
"Set-Cookie: foo=bar; HttpOnly; Path=/p\r\nSet-Cookie: baz=quux; Path=/\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -94,12 +94,12 @@ fn parse<H: Header + HeaderFormat>(raw: &Vec<Vec<u8>>) -> Option<Box<HeaderForma
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Item {
|
impl fmt::Display for Item {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self.raw {
|
match *self.raw {
|
||||||
Some(ref raw) => {
|
Some(ref raw) => {
|
||||||
for part in raw.iter() {
|
for part in raw.iter() {
|
||||||
match from_utf8(&part[..]) {
|
match from_utf8(&part[..]) {
|
||||||
Ok(s) => try!(fmt.write_str(s)),
|
Ok(s) => try!(f.write_str(s)),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("raw header value is not utf8. header={:?}, error={:?}", part, e);
|
error!("raw header value is not utf8. header={:?}, error={:?}", part, e);
|
||||||
return Err(fmt::Error);
|
return Err(fmt::Error);
|
||||||
@@ -108,7 +108,7 @@ impl fmt::Display for Item {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
None => fmt::Display::fmt(&unsafe { self.typed.one() }, fmt)
|
None => fmt::Display::fmt(&unsafe { self.typed.one() }, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ pub trait HeaderFormat: fmt::Debug + HeaderClone + Any + Typeable + Send + Sync
|
|||||||
///
|
///
|
||||||
/// This method is not allowed to introduce an Err not produced
|
/// This method is not allowed to introduce an Err not produced
|
||||||
/// by the passed-in Formatter.
|
/// by the passed-in Formatter.
|
||||||
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result;
|
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,8 +94,7 @@ impl Clone for Box<HeaderFormat + Send + Sync> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn header_name<T: Header>() -> &'static str {
|
fn header_name<T: Header>() -> &'static str {
|
||||||
let name = <T as Header>::header_name();
|
<T as Header>::header_name()
|
||||||
name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A map of header fields on requests and responses.
|
/// A map of header fields on requests and responses.
|
||||||
@@ -224,21 +223,21 @@ impl Headers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Headers {
|
impl fmt::Display for Headers {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
for header in self.iter() {
|
for header in self.iter() {
|
||||||
try!(write!(fmt, "{}\r\n", header));
|
try!(write!(f, "{}\r\n", header));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Headers {
|
impl fmt::Debug for Headers {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
try!(fmt.write_str("Headers { "));
|
try!(f.write_str("Headers { "));
|
||||||
for header in self.iter() {
|
for header in self.iter() {
|
||||||
try!(write!(fmt, "{:?}, ", header));
|
try!(write!(f, "{:?}, ", header));
|
||||||
}
|
}
|
||||||
try!(fmt.write_str("}"));
|
try!(f.write_str("}"));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -292,8 +291,8 @@ impl<'a> fmt::Display for HeaderView<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> fmt::Debug for HeaderView<'a> {
|
impl<'a> fmt::Debug for HeaderView<'a> {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt::Display::fmt(self, fmt)
|
fmt::Display::fmt(self, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,8 +314,8 @@ impl<'a> FromIterator<HeaderView<'a>> for Headers {
|
|||||||
|
|
||||||
impl<'a> fmt::Display for &'a (HeaderFormat + Send + Sync) {
|
impl<'a> fmt::Display for &'a (HeaderFormat + Send + Sync) {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
(**self).fmt_header(fmt)
|
(**self).fmt_header(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,14 +352,14 @@ impl Deref for CowStr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for CowStr {
|
impl fmt::Debug for CowStr {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt::Debug::fmt(&self.0, fmt)
|
fmt::Debug::fmt(&self.0, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for CowStr {
|
impl fmt::Display for CowStr {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt::Display::fmt(&self.0, fmt)
|
fmt::Display::fmt(&self.0, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,9 +459,9 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl HeaderFormat for CrazyLength {
|
impl HeaderFormat for CrazyLength {
|
||||||
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let CrazyLength(ref opt, ref value) = *self;
|
let CrazyLength(ref opt, ref value) = *self;
|
||||||
write!(fmt, "{:?}, {:?}", opt, value)
|
write!(f, "{:?}, {:?}", opt, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
//! Utility functions for Header implementations.
|
//! Utility functions for Header implementations.
|
||||||
|
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::fmt;
|
use std::fmt::{self, Display};
|
||||||
|
|
||||||
/// Reads a single raw string when parsing a header
|
/// Reads a single raw string when parsing a header
|
||||||
pub fn from_one_raw_str<T: str::FromStr>(raw: &[Vec<u8>]) -> Option<T> {
|
pub fn from_one_raw_str<T: str::FromStr>(raw: &[Vec<u8>]) -> Option<T> {
|
||||||
@@ -9,7 +9,7 @@ pub fn from_one_raw_str<T: str::FromStr>(raw: &[Vec<u8>]) -> Option<T> {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
// we JUST checked that raw.len() == 1, so raw[0] WILL exist.
|
// we JUST checked that raw.len() == 1, so raw[0] WILL exist.
|
||||||
if let Ok(s) = str::from_utf8(&raw[0][..]) {
|
if let Ok(s) = str::from_utf8(& unsafe { raw.get_unchecked(0) }[..]) {
|
||||||
if s != "" {
|
if s != "" {
|
||||||
return str::FromStr::from_str(s).ok();
|
return str::FromStr::from_str(s).ok();
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,7 @@ pub fn from_comma_delimited<T: str::FromStr>(raw: &[Vec<u8>]) -> Option<Vec<T>>
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
// we JUST checked that raw.len() == 1, so raw[0] WILL exist.
|
// we JUST checked that raw.len() == 1, so raw[0] WILL exist.
|
||||||
from_one_comma_delimited(&raw[0][..])
|
from_one_comma_delimited(& unsafe { raw.get_unchecked(0) }[..])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads a comma-delimited raw string into a Vec.
|
/// Reads a comma-delimited raw string into a Vec.
|
||||||
@@ -45,12 +45,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>(f: &mut fmt::Formatter, parts: &[T]) -> fmt::Result {
|
pub fn fmt_comma_delimited<T: Display>(f: &mut fmt::Formatter, parts: &[T]) -> fmt::Result {
|
||||||
for (i, part) in parts.iter().enumerate() {
|
for (i, part) in parts.iter().enumerate() {
|
||||||
if i > 0 {
|
if i != 0 {
|
||||||
try!(write!(f, ", "));
|
try!(f.write_str(", "));
|
||||||
}
|
}
|
||||||
try!(write!(f, "{}", part));
|
try!(Display::fmt(part, f));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,8 +97,8 @@ impl Charset {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Charset {
|
impl Display for Charset {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(fmt, "{}", self.name())
|
f.write_str(self.name())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ pub enum Encoding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Encoding {
|
impl fmt::Display for Encoding {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt.write_str(match *self {
|
f.write_str(match *self {
|
||||||
Chunked => "chunked",
|
Chunked => "chunked",
|
||||||
Gzip => "gzip",
|
Gzip => "gzip",
|
||||||
Deflate => "deflate",
|
Deflate => "deflate",
|
||||||
|
|||||||
@@ -103,10 +103,10 @@ impl EntityTag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Display for EntityTag {
|
impl Display for EntityTag {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self.weak {
|
match self.weak {
|
||||||
true => write!(fmt, "W/\"{}\"", self.tag),
|
true => write!(f, "W/\"{}\"", self.tag),
|
||||||
false => write!(fmt, "\"{}\"", self.tag),
|
false => write!(f, "\"{}\"", self.tag),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,10 +116,8 @@ impl FromStr for EntityTag {
|
|||||||
fn from_str(s: &str) -> Result<EntityTag, ()> {
|
fn from_str(s: &str) -> Result<EntityTag, ()> {
|
||||||
let length: usize = s.len();
|
let length: usize = s.len();
|
||||||
let slice = &s[..];
|
let slice = &s[..];
|
||||||
// Early exits:
|
// Early exits if it doesn't terminate in a DQUOTE.
|
||||||
// 1. The string is empty, or,
|
if !slice.ends_with('"') {
|
||||||
// 2. it doesn't terminate in a DQUOTE.
|
|
||||||
if slice.is_empty() || !slice.ends_with('"') {
|
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
// The etag is weak if its first char is not a DQUOTE.
|
// The etag is weak if its first char is not a DQUOTE.
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ impl FromStr for Language {
|
|||||||
|
|
||||||
impl fmt::Display for Language {
|
impl fmt::Display for Language {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
try!(write!(f, "{}", self.primary));
|
try!(f.write_str(&self.primary[..]));
|
||||||
match self.sub {
|
match self.sub {
|
||||||
Some(ref s) => write!(f, "-{}", s),
|
Some(ref s) => write!(f, "-{}", s),
|
||||||
None => Ok(())
|
None => Ok(())
|
||||||
|
|||||||
Reference in New Issue
Block a user