1 use std::fmt;
2 use std::str::{FromStr};
3 use header::{Header, HttpDate, Raw};
4 use 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 /// use hyperx::header::{Headers, Warning};
39 ///
40 /// let mut headers = Headers::new();
41 /// headers.set(
42 ///     Warning{
43 ///         code: 299,
44 ///         agent: "api.hyper.rs".to_owned(),
45 ///         text: "Deprecated".to_owned(),
46 ///         date: None
47 ///     }
48 /// );
49 /// ```
50 ///
51 /// ```
52 /// use hyperx::header::{Headers, HttpDate, Warning};
53 ///
54 /// let mut headers = Headers::new();
55 /// headers.set(
56 ///     Warning{
57 ///         code: 299,
58 ///         agent: "api.hyper.rs".to_owned(),
59 ///         text: "Deprecated".to_owned(),
60 ///         date: "Tue, 15 Nov 1994 08:12:31 GMT".parse::<HttpDate>().ok()
61 ///     }
62 /// );
63 /// ```
64 ///
65 /// ```
66 /// use std::time::SystemTime;
67 /// use hyperx::header::{Headers, Warning};
68 ///
69 /// let mut headers = Headers::new();
70 /// headers.set(
71 ///     Warning{
72 ///         code: 199,
73 ///         agent: "api.hyper.rs".to_owned(),
74 ///         text: "Deprecated".to_owned(),
75 ///         date: Some(SystemTime::now().into())
76 ///     }
77 /// );
78 /// ```
79 #[derive(PartialEq, Clone, Debug)]
80 pub struct Warning {
81     /// The 3 digit warn code.
82     pub code: u16,
83     /// The name or pseudonym of the server adding this header.
84     pub agent: String,
85     /// The warning message describing the error.
86     pub text: String,
87     /// An optional warning date.
88     pub date: Option<HttpDate>
89 }
90 
91 impl Header for Warning {
header_name() -> &'static str92     fn header_name() -> &'static str {
93         static NAME: &'static str = "Warning";
94         NAME
95     }
96 
parse_header(raw: &Raw) -> ::Result<Warning>97     fn parse_header(raw: &Raw) -> ::Result<Warning> {
98         from_one_raw_str(raw)
99     }
100 
fmt_header(&self, f: &mut ::header::Formatter) -> fmt::Result101     fn fmt_header(&self, f: &mut ::header::Formatter) -> fmt::Result {
102         f.fmt_line(self)
103     }
104 }
105 
106 impl fmt::Display for Warning {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result107     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108         match self.date {
109             Some(date) => write!(f, "{:03} {} \"{}\" \"{}\"", self.code, self.agent, self.text, date),
110             None => write!(f, "{:03} {} \"{}\"", self.code, self.agent, self.text)
111         }
112     }
113 }
114 
115 impl FromStr for Warning {
116     type Err = ::Error;
117 
from_str(s: &str) -> ::Result<Warning>118     fn from_str(s: &str) -> ::Result<Warning> {
119         let mut warning_split = s.split_whitespace();
120         let code = match warning_split.next() {
121             Some(c) => match c.parse::<u16>() {
122                 Ok(c) => c,
123                 Err(..) => return Err(::Error::Header)
124             },
125             None => return Err(::Error::Header)
126         };
127         let agent = match warning_split.next() {
128             Some(a) => a.to_string(),
129             None => return Err(::Error::Header)
130         };
131 
132         let mut warning_split = s.split('"').skip(1);
133         let text = match warning_split.next() {
134             Some(t) => t.to_string(),
135             None => return Err(::Error::Header)
136         };
137         let date = match warning_split.skip(1).next() {
138             Some(d) => d.parse::<HttpDate>().ok(),
139             None => None // Optional
140         };
141 
142         Ok(Warning {
143             code: code,
144             agent: agent,
145             text: text,
146             date: date
147         })
148     }
149 }
150 
151 #[cfg(test)]
152 mod tests {
153     use super::Warning;
154     use header::{Header, HttpDate};
155 
156     #[test]
test_parsing()157     fn test_parsing() {
158         let warning = Header::parse_header(&vec![b"112 - \"network down\" \"Sat, 25 Aug 2012 23:34:45 GMT\"".to_vec()].into());
159         assert_eq!(warning.ok(), Some(Warning {
160             code: 112,
161             agent: "-".to_owned(),
162             text: "network down".to_owned(),
163             date: "Sat, 25 Aug 2012 23:34:45 GMT".parse::<HttpDate>().ok()
164         }));
165 
166         let warning = Header::parse_header(&vec![b"299 api.hyper.rs:8080 \"Deprecated API : use newapi.hyper.rs instead.\"".to_vec()].into());
167         assert_eq!(warning.ok(), Some(Warning {
168             code: 299,
169             agent: "api.hyper.rs:8080".to_owned(),
170             text: "Deprecated API : use newapi.hyper.rs instead.".to_owned(),
171             date: None
172         }));
173 
174         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());
175         assert_eq!(warning.ok(), Some(Warning {
176             code: 299,
177             agent: "api.hyper.rs:8080".to_owned(),
178             text: "Deprecated API : use newapi.hyper.rs instead.".to_owned(),
179             date: "Tue, 15 Nov 1994 08:12:31 GMT".parse::<HttpDate>().ok()
180         }));
181     }
182 }
183