1use std::time::{Duration, SystemTime};
23use util::{HttpDate, Seconds, TryFromValues};
4use HeaderValue;
56/// 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/// ```
2526/// Retry-After header, defined in [RFC7231](http://tools.ietf.org/html/rfc7231#section-7.1.3)
27#[derive(Debug, Clone, PartialEq, Eq)]
28pub struct RetryAfter(After);
2930derive_header! {
31 RetryAfter(_),
32 name: RETRY_AFTER
33}
3435#[derive(Debug, Clone, PartialEq, Eq)]
36enum After {
37/// Retry after the given DateTime
38DateTime(HttpDate),
39/// Retry after this duration has elapsed
40Delay(Seconds),
41}
4243impl RetryAfter {
44/// Create an `RetryAfter` header with a date value.
45pub fn date(time: SystemTime) -> RetryAfter {
46 RetryAfter(After::DateTime(time.into()))
47 }
4849/// Create an `RetryAfter` header with a date value.
50pub fn delay(dur: Duration) -> RetryAfter {
51 RetryAfter(After::Delay(dur.into()))
52 }
53}
5455impl TryFromValues for After {
56fn try_from_values<'i, I>(values: &mut I) -> Result<Self, ::Error>
57where
58I: Iterator<Item = &'i HeaderValue>,
59 {
60 values
61 .next()
62 .and_then(|val| {
63if let Some(delay) = Seconds::from_val(val) {
64return Some(After::Delay(delay));
65 }
6667let date = HttpDate::from_val(val)?;
68Some(After::DateTime(date))
69 })
70 .ok_or_else(::Error::invalid)
71 }
72}
7374impl<'a> From<&'a After> for HeaderValue {
75fn from(after: &'a After) -> HeaderValue {
76match *after {
77 After::Delay(ref delay) => delay.into(),
78 After::DateTime(ref date) => date.into(),
79 }
80 }
81}
8283#[cfg(test)]
84mod tests {
85use super::super::test_decode;
86use super::RetryAfter;
87use std::time::Duration;
88use util::HttpDate;
8990#[test]
91fn delay_decode() {
92let r: RetryAfter = test_decode(&["1234"]).unwrap();
93assert_eq!(r, RetryAfter::delay(Duration::from_secs(1234)),);
94 }
9596macro_rules! test_retry_after_datetime {
97 ($name:ident, $s:expr) => {
98#[test]
99fn $name() {
100let r: RetryAfter = test_decode(&[$s]).unwrap();
101let dt = "Sun, 06 Nov 1994 08:49:37 GMT".parse::<HttpDate>().unwrap();
102103assert_eq!(r, RetryAfter(super::After::DateTime(dt)));
104 }
105 };
106 }
107108test_retry_after_datetime!(date_decode_rfc1123, "Sun, 06 Nov 1994 08:49:37 GMT");
109test_retry_after_datetime!(date_decode_rfc850, "Sunday, 06-Nov-94 08:49:37 GMT");
110test_retry_after_datetime!(date_decode_asctime, "Sun Nov 6 08:49:37 1994");
111}