1 use std::time::{Duration, SystemTime}; 2 3 use util::{HttpDate, Seconds, TryFromValues}; 4 use HeaderValue; 5 6 /// The `Retry-After` header. 7 /// 8 /// The `Retry-After` response-header field can be used with a 503 (Service 9 /// Unavailable) response to indicate how long the service is expected to be 10 /// unavailable to the requesting client. This field MAY also be used with any 11 /// 3xx (Redirection) response to indicate the minimum time the user-agent is 12 /// asked wait before issuing the redirected request. The value of this field 13 /// can be either an HTTP-date or an integer number of seconds (in decimal) 14 /// after the time of the response. 15 /// 16 /// # Examples 17 /// ``` 18 /// # extern crate headers; 19 /// use std::time::{Duration, SystemTime}; 20 /// use headers::RetryAfter; 21 /// 22 /// let delay = RetryAfter::delay(Duration::from_secs(300)); 23 /// let date = RetryAfter::date(SystemTime::now()); 24 /// ``` 25 26 /// Retry-After header, defined in [RFC7231](http://tools.ietf.org/html/rfc7231#section-7.1.3) 27 #[derive(Debug, Clone, PartialEq, Eq)] 28 pub struct RetryAfter(After); 29 30 derive_header! { 31 RetryAfter(_), 32 name: RETRY_AFTER 33 } 34 35 #[derive(Debug, Clone, PartialEq, Eq)] 36 enum After { 37 /// Retry after the given DateTime 38 DateTime(HttpDate), 39 /// Retry after this duration has elapsed 40 Delay(Seconds), 41 } 42 43 impl RetryAfter { 44 /// Create an `RetryAfter` header with a date value. date(time: SystemTime) -> RetryAfter45 pub fn date(time: SystemTime) -> RetryAfter { 46 RetryAfter(After::DateTime(time.into())) 47 } 48 49 /// Create an `RetryAfter` header with a date value. delay(dur: Duration) -> RetryAfter50 pub fn delay(dur: Duration) -> RetryAfter { 51 RetryAfter(After::Delay(dur.into())) 52 } 53 } 54 55 impl TryFromValues for After { try_from_values<'i, I>(values: &mut I) -> Result<Self, ::Error> where I: Iterator<Item = &'i HeaderValue>,56 fn try_from_values<'i, I>(values: &mut I) -> Result<Self, ::Error> 57 where 58 I: Iterator<Item = &'i HeaderValue>, 59 { 60 values 61 .next() 62 .and_then(|val| { 63 if let Some(delay) = Seconds::from_val(val) { 64 return Some(After::Delay(delay)); 65 } 66 67 let date = HttpDate::from_val(val)?; 68 Some(After::DateTime(date)) 69 }) 70 .ok_or_else(::Error::invalid) 71 } 72 } 73 74 impl<'a> From<&'a After> for HeaderValue { from(after: &'a After) -> HeaderValue75 fn from(after: &'a After) -> HeaderValue { 76 match *after { 77 After::Delay(ref delay) => delay.into(), 78 After::DateTime(ref date) => date.into(), 79 } 80 } 81 } 82 83 #[cfg(test)] 84 mod tests { 85 use super::super::test_decode; 86 use super::RetryAfter; 87 use std::time::Duration; 88 use util::HttpDate; 89 90 #[test] delay_decode()91 fn delay_decode() { 92 let r: RetryAfter = test_decode(&["1234"]).unwrap(); 93 assert_eq!(r, RetryAfter::delay(Duration::from_secs(1234)),); 94 } 95 96 macro_rules! test_retry_after_datetime { 97 ($name:ident, $s:expr) => { 98 #[test] 99 fn $name() { 100 let r: RetryAfter = test_decode(&[$s]).unwrap(); 101 let dt = "Sun, 06 Nov 1994 08:49:37 GMT".parse::<HttpDate>().unwrap(); 102 103 assert_eq!(r, RetryAfter(super::After::DateTime(dt))); 104 } 105 }; 106 } 107 108 test_retry_after_datetime!(date_decode_rfc1123, "Sun, 06 Nov 1994 08:49:37 GMT"); 109 test_retry_after_datetime!(date_decode_rfc850, "Sunday, 06-Nov-94 08:49:37 GMT"); 110 test_retry_after_datetime!(date_decode_asctime, "Sun Nov 6 08:49:37 1994"); 111 } 112