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