diff --git a/src/header/common/mod.rs b/src/header/common/mod.rs index 8ce40fdf8f..6a886fde23 100644 --- a/src/header/common/mod.rs +++ b/src/header/common/mod.rs @@ -58,6 +58,7 @@ pub use self::transfer_encoding::TransferEncoding; pub use self::upgrade::{Upgrade, Protocol, ProtocolName}; pub use self::user_agent::UserAgent; pub use self::vary::Vary; +pub use self::warning::Warning; #[doc(hidden)] #[macro_export] @@ -420,3 +421,4 @@ mod transfer_encoding; mod upgrade; mod user_agent; mod vary; +mod warning; \ No newline at end of file diff --git a/src/header/common/warning.rs b/src/header/common/warning.rs new file mode 100644 index 0000000000..8e9c94d1ba --- /dev/null +++ b/src/header/common/warning.rs @@ -0,0 +1,174 @@ +use std::fmt; +use std::str::{FromStr}; +use header::{Header, HttpDate, Raw}; +use header::parsing::from_one_raw_str; + +/// `Warning` header, defined in [RFC7234](https://tools.ietf.org/html/rfc7234#section-5.5) +/// +/// The `Warning` header field can be be used to carry additional information +/// about the status or transformation of a message that might not be reflected +/// in the status code. This header is sometimes used as backwards +/// compatible way to notify of a deprecated API. +/// +/// # ABNF +/// ```plain +/// Warning = 1#warning-value +/// warning-value = warn-code SP warn-agent SP warn-text +/// [ SP warn-date ] +/// warn-code = 3DIGIT +/// warn-agent = ( uri-host [ ":" port ] ) / pseudonym +/// ; the name or pseudonym of the server adding +/// ; the Warning header field, for use in debugging +/// ; a single "-" is recommended when agent unknown +/// warn-text = quoted-string +/// warn-date = DQUOTE HTTP-date DQUOTE +/// ``` +/// +/// # Example values +/// * `Warning: 112 - "network down" "Sat, 25 Aug 2012 23:34:45 GMT"` +/// * `Warning: 299 - "Deprecated API " "Tue, 15 Nov 1994 08:12:31 GMT"` +/// * `Warning: 299 api.hyper.rs:8080 "Deprecated API : use newapi.hyper.rs instead."` +/// * `Warning: 299 api.hyper.rs:8080 "Deprecated API : use newapi.hyper.rs instead." "Tue, 15 Nov 1994 08:12:31 GMT"` +/// +/// # Examples +/// ``` +/// use hyper::header::{Headers, Warning}; +/// +/// let mut headers = Headers::new(); +/// headers.set( +/// Warning{ +/// code: 299, +/// agent: "api.hyper.rs".to_owned(), +/// text: "Deprecated".to_owned(), +/// date: None +/// } +/// ); +/// ``` +/// ``` +/// use hyper::header::{Headers, HttpDate, Warning}; +/// +/// let mut headers = Headers::new(); +/// headers.set( +/// Warning{ +/// code: 299, +/// agent: "api.hyper.rs".to_owned(), +/// text: "Deprecated".to_owned(), +/// date: "Tue, 15 Nov 1994 08:12:31 GMT".parse::().ok() +/// } +/// ); +/// ``` +/// ``` +/// # extern crate hyper; +/// # extern crate time; +/// # fn main() { +/// use hyper::header::{Headers, HttpDate, Warning}; +/// +/// let mut headers = Headers::new(); +/// headers.set( +/// Warning{ +/// code: 199, +/// agent: "api.hyper.rs".to_owned(), +/// text: "Deprecated".to_owned(), +/// date: Some(HttpDate(time::now())) +/// } +/// ); +/// # } +/// ``` +#[derive(PartialEq, Clone, Debug)] +pub struct Warning { + /// The 3 digit warn code. + pub code: u16, + /// The name or pseudonym of the server adding this header. + pub agent: String, + /// The warning message describing the error. + pub text: String, + /// An optional warning date. + pub date: Option +} + +impl Header for Warning { + fn header_name() -> &'static str { + static NAME: &'static str = "Warning"; + NAME + } + + fn parse_header(raw: &Raw) -> ::Result { + from_one_raw_str(raw) + } + + fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.date { + Some(date) => write!(f, "{:03} {} \"{}\" \"{}\"", self.code, self.agent, self.text, date), + None => write!(f, "{:03} {} \"{}\"", self.code, self.agent, self.text) + } + } +} + +impl FromStr for Warning { + type Err = ::Error; + + fn from_str(s: &str) -> ::Result { + let mut warning_split = s.split_whitespace(); + let code = match warning_split.next() { + Some(c) => match c.parse::() { + Ok(c) => c, + Err(..) => return Err(::Error::Header) + }, + None => return Err(::Error::Header) + }; + let agent = match warning_split.next() { + Some(a) => a.to_string(), + None => return Err(::Error::Header) + }; + + let mut warning_split = s.split('"').skip(1); + let text = match warning_split.next() { + Some(t) => t.to_string(), + None => return Err(::Error::Header) + }; + let date = match warning_split.skip(1).next() { + Some(d) => d.parse::().ok(), + None => None // Optional + }; + + Ok(Warning { + code: code, + agent: agent, + text: text, + date: date + }) + } +} + +#[cfg(test)] +mod tests { + use super::Warning; + use header::{Header, HttpDate}; + + #[test] + fn test_parsing() { + let warning = Header::parse_header(&vec![b"112 - \"network down\" \"Sat, 25 Aug 2012 23:34:45 GMT\"".to_vec()].into()); + assert_eq!(warning.ok(), Some(Warning { + code: 112, + agent: "-".to_owned(), + text: "network down".to_owned(), + date: "Sat, 25 Aug 2012 23:34:45 GMT".parse::().ok() + })); + + let warning = Header::parse_header(&vec![b"299 api.hyper.rs:8080 \"Deprecated API : use newapi.hyper.rs instead.\"".to_vec()].into()); + assert_eq!(warning.ok(), Some(Warning { + code: 299, + agent: "api.hyper.rs:8080".to_owned(), + text: "Deprecated API : use newapi.hyper.rs instead.".to_owned(), + date: None + })); + + let warning = Header::parse_header(&vec![b"299 api.hyper.rs:8080 \"Deprecated API : use newapi.hyper.rs instead.\" \"Tue, 15 Nov 1994 08:12:31 GMT\"".to_vec()].into()); + assert_eq!(warning.ok(), Some(Warning { + code: 299, + agent: "api.hyper.rs:8080".to_owned(), + text: "Deprecated API : use newapi.hyper.rs instead.".to_owned(), + date: "Tue, 15 Nov 1994 08:12:31 GMT".parse::().ok() + })); + } +}