diff --git a/src/header/common/mod.rs b/src/header/common/mod.rs index 87b4f863..f26f6fb1 100644 --- a/src/header/common/mod.rs +++ b/src/header/common/mod.rs @@ -24,6 +24,7 @@ pub use self::location::Location; pub use self::transfer_encoding::TransferEncoding; pub use self::upgrade::Upgrade; pub use self::user_agent::UserAgent; +pub use self::vary::Vary; pub use self::server::Server; pub use self::set_cookie::SetCookie; @@ -132,4 +133,7 @@ pub mod upgrade; /// Exposes the UserAgent header. pub mod user_agent; +/// Exposes the Vary header. +pub mod vary; + pub mod util; diff --git a/src/header/common/vary.rs b/src/header/common/vary.rs new file mode 100644 index 00000000..9b548189 --- /dev/null +++ b/src/header/common/vary.rs @@ -0,0 +1,59 @@ +use header::{Header, HeaderFormat, CaseInsensitive}; +use std::fmt::{mod}; +use super::util::{from_comma_delimited, fmt_comma_delimited, from_one_raw_str}; + +/// The `Allow` header. +/// See also https://tools.ietf.org/html/rfc7231#section-7.1.4 + +#[deriving(Clone, PartialEq, Show)] +pub enum Vary { + /// This corresponds to '*'. + Any, + /// The header field names which will influence the response representation. + Headers(Vec), +} + +impl Header for Vary { + fn header_name(_: Option) -> &'static str { + "Vary" + } + + fn parse_header(raw: &[Vec]) -> Option { + from_one_raw_str(raw).and_then(|s: String| { + let slice = s[]; + match slice { + "" => None, + "*" => Some(Vary::Any), + _ => from_comma_delimited(raw).map(|vec| Vary::Headers(vec)), + } + }) + } +} + +impl HeaderFormat for Vary { + fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self { + Vary::Any => { write!(fmt, "*") } + Vary::Headers(ref fields) => { fmt_comma_delimited(fmt, fields[]) } + } + } +} + +#[cfg(test)] +mod tests { + use super::Vary; + use header::{Header, CaseInsensitive}; + + #[test] + fn test_vary() { + let mut vary: Option; + + vary = Header::parse_header([b"*".to_vec()].as_slice()); + assert_eq!(vary, Some(Vary::Any)); + + vary = Header::parse_header([b"etag,cookie,allow".to_vec()].as_slice()); + assert_eq!(vary, Some(Vary::Headers(vec![from_str::("eTag").unwrap(), + from_str::("cookIE").unwrap(), + from_str::("AlLOw").unwrap(),]))); + } +} diff --git a/src/header/mod.rs b/src/header/mod.rs index 440d55b2..3327f790 100644 --- a/src/header/mod.rs +++ b/src/header/mod.rs @@ -10,7 +10,7 @@ use std::borrow::Cow::{Borrowed, Owned}; use std::fmt::{mod, Show}; use std::intrinsics::TypeId; use std::raw::TraitObject; -use std::str::SendStr; +use std::str::{SendStr, FromStr}; use std::collections::HashMap; use std::collections::hash_map::{Entries, Occupied, Vacant}; use std::{hash, mem}; @@ -446,8 +446,15 @@ impl fmt::Show for Box { } } +/// Case-insensitive string. //#[deriving(Clone)] -struct CaseInsensitive(SendStr); +pub struct CaseInsensitive(SendStr); + +impl FromStr for CaseInsensitive { + fn from_str(s: &str) -> Option { + Some(CaseInsensitive(Owned(s.to_string()))) + } +} impl Clone for CaseInsensitive { fn clone(&self) -> CaseInsensitive {