hyperx/header/common/
warning.rs

1use std::fmt;
2use std::str::{FromStr};
3use header::{Header, HttpDate, RawLike};
4use header::parsing::from_one_raw_str;
5
6/// `Warning` header, defined in [RFC7234](https://tools.ietf.org/html/rfc7234#section-5.5)
7///
8/// The `Warning` header field can be be used to carry additional information
9/// about the status or transformation of a message that might not be reflected
10/// in the status code. This header is sometimes used as backwards
11/// compatible way to notify of a deprecated API.
12///
13/// # ABNF
14///
15/// ```text
16/// Warning       = 1#warning-value
17/// warning-value = warn-code SP warn-agent SP warn-text
18///                                       [ SP warn-date ]
19/// warn-code  = 3DIGIT
20/// warn-agent = ( uri-host [ ":" port ] ) / pseudonym
21///                 ; the name or pseudonym of the server adding
22///                 ; the Warning header field, for use in debugging
23///                 ; a single "-" is recommended when agent unknown
24/// warn-text  = quoted-string
25/// warn-date  = DQUOTE HTTP-date DQUOTE
26/// ```
27///
28/// # Example values
29///
30/// * `Warning: 112 - "network down" "Sat, 25 Aug 2012 23:34:45 GMT"`
31/// * `Warning: 299 - "Deprecated API " "Tue, 15 Nov 1994 08:12:31 GMT"`
32/// * `Warning: 299 api.hyper.rs:8080 "Deprecated API : use newapi.hyper.rs instead."`
33/// * `Warning: 299 api.hyper.rs:8080 "Deprecated API : use newapi.hyper.rs instead." "Tue, 15 Nov 1994 08:12:31 GMT"`
34///
35/// # Examples
36///
37/// ```
38/// # extern crate http;
39/// use hyperx::header::{TypedHeaders, Warning};
40///
41/// let mut headers = http::HeaderMap::new();
42/// headers.encode(
43///     &Warning {
44///         code: 299,
45///         agent: "api.hyper.rs".to_owned(),
46///         text: "Deprecated".to_owned(),
47///         date: None
48///     }
49/// );
50/// ```
51///
52/// ```
53/// # extern crate http;
54/// use hyperx::header::{TypedHeaders, HttpDate, Warning};
55///
56/// let mut headers = http::HeaderMap::new();
57/// headers.encode(
58///     &Warning {
59///         code: 299,
60///         agent: "api.hyper.rs".to_owned(),
61///         text: "Deprecated".to_owned(),
62///         date: "Tue, 15 Nov 1994 08:12:31 GMT".parse::<HttpDate>().ok()
63///     }
64/// );
65/// ```
66///
67/// ```
68/// # extern crate http;
69/// use std::time::SystemTime;
70/// use hyperx::header::{TypedHeaders, Warning};
71///
72/// let mut headers = http::HeaderMap::new();
73/// headers.encode(
74///     &Warning {
75///         code: 199,
76///         agent: "api.hyper.rs".to_owned(),
77///         text: "Deprecated".to_owned(),
78///         date: Some(SystemTime::now().into())
79///     }
80/// );
81/// ```
82#[derive(PartialEq, Clone, Debug)]
83pub struct Warning {
84    /// The 3 digit warn code.
85    pub code: u16,
86    /// The name or pseudonym of the server adding this header.
87    pub agent: String,
88    /// The warning message describing the error.
89    pub text: String,
90    /// An optional warning date.
91    pub date: Option<HttpDate>
92}
93
94impl Header for Warning {
95    fn header_name() -> &'static str {
96        static NAME: &'static str = "Warning";
97        NAME
98    }
99
100    fn parse_header<'a, T>(raw: &'a T) -> ::Result<Warning>
101    where T: RawLike<'a>
102    {
103        from_one_raw_str(raw)
104    }
105
106    fn fmt_header(&self, f: &mut ::header::Formatter) -> fmt::Result {
107        f.fmt_line(self)
108    }
109}
110
111impl fmt::Display for Warning {
112    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
113        match self.date {
114            Some(date) => write!(f, "{:03} {} \"{}\" \"{}\"", self.code, self.agent, self.text, date),
115            None => write!(f, "{:03} {} \"{}\"", self.code, self.agent, self.text)
116        }
117    }
118}
119
120impl FromStr for Warning {
121    type Err = ::Error;
122
123    fn from_str(s: &str) -> ::Result<Warning> {
124        let mut warning_split = s.split_whitespace();
125        let code = match warning_split.next() {
126            Some(c) => match c.parse::<u16>() {
127                Ok(c) => c,
128                Err(..) => return Err(::Error::Header)
129            },
130            None => return Err(::Error::Header)
131        };
132        let agent = match warning_split.next() {
133            Some(a) => a.to_string(),
134            None => return Err(::Error::Header)
135        };
136
137        let mut warning_split = s.split('"').skip(1);
138        let text = match warning_split.next() {
139            Some(t) => t.to_string(),
140            None => return Err(::Error::Header)
141        };
142        let date = match warning_split.skip(1).next() {
143            Some(d) => d.parse::<HttpDate>().ok(),
144            None => None // Optional
145        };
146
147        Ok(Warning {
148            code: code,
149            agent: agent,
150            text: text,
151            date: date
152        })
153    }
154}
155
156#[cfg(test)]
157mod tests {
158    use super::Warning;
159    use header::{Header, HttpDate, Raw};
160
161    #[test]
162    fn test_parsing() {
163        let r: Raw = vec![
164            b"112 - \"network down\" \"Sat, 25 Aug 2012 23:34:45 GMT\"".to_vec()
165        ].into();
166        let warning = Header::parse_header(&r);
167        assert_eq!(warning.ok(), Some(Warning {
168            code: 112,
169            agent: "-".to_owned(),
170            text: "network down".to_owned(),
171            date: "Sat, 25 Aug 2012 23:34:45 GMT".parse::<HttpDate>().ok()
172        }));
173
174        let r: Raw = vec![
175            b"299 api.hyper.rs:8080 \"Deprecated API : \
176              use newapi.hyper.rs instead.\"".to_vec()
177        ].into();
178        let warning = Header::parse_header(&r);
179        assert_eq!(warning.ok(), Some(Warning {
180            code: 299,
181            agent: "api.hyper.rs:8080".to_owned(),
182            text: "Deprecated API : use newapi.hyper.rs instead.".to_owned(),
183            date: None
184        }));
185
186        let r: Raw = vec![
187            b"299 api.hyper.rs:8080 \"Deprecated API : \
188              use newapi.hyper.rs instead.\" \
189              \"Tue, 15 Nov 1994 08:12:31 GMT\"".to_vec()
190        ].into();
191        let warning = Header::parse_header(&r);
192        assert_eq!(warning.ok(), Some(Warning {
193            code: 299,
194            agent: "api.hyper.rs:8080".to_owned(),
195            text: "Deprecated API : use newapi.hyper.rs instead.".to_owned(),
196            date: "Tue, 15 Nov 1994 08:12:31 GMT".parse::<HttpDate>().ok()
197        }));
198    }
199}
200
201standard_header!(Warning, WARNING);