rama_http_headers/common/
retry_after.rs1use std::time::SystemTime;
2
3use rama_core::error::BoxError;
4use rama_core::telemetry::tracing;
5use rama_http_types::HeaderValue;
6
7use crate::Error;
8use crate::util::{HttpDate, Seconds, TryFromValues};
9
10#[derive(Debug, Copy, Clone, PartialEq, Eq)]
31pub struct RetryAfter(After);
32
33impl crate::TypedHeader for RetryAfter {
34 fn name() -> &'static ::rama_http_types::header::HeaderName {
35 &::rama_http_types::header::RETRY_AFTER
36 }
37}
38
39impl crate::HeaderDecode for RetryAfter {
40 fn decode<'i, I>(values: &mut I) -> Result<Self, crate::Error>
41 where
42 I: Iterator<Item = &'i ::rama_http_types::header::HeaderValue>,
43 {
44 crate::util::TryFromValues::try_from_values(values).map(RetryAfter)
45 }
46}
47
48impl crate::HeaderEncode for RetryAfter {
49 fn encode<E: Extend<HeaderValue>>(&self, values: &mut E) {
50 match HeaderValue::try_from(&self.0) {
51 Ok(value) => values.extend(::std::iter::once(value)),
52 Err(err) => {
53 tracing::debug!("failed to encode retry-after value as header: {err}");
54 }
55 }
56 }
57}
58
59#[derive(Debug, Copy, Clone, PartialEq, Eq)]
60pub enum After {
61 DateTime(HttpDate),
63 Delay(Seconds),
65}
66
67impl RetryAfter {
68 #[must_use]
70 pub fn date(time: SystemTime) -> Self {
71 Self(After::DateTime(time.into()))
72 }
73
74 #[must_use]
76 pub fn delay(seconds: Seconds) -> Self {
77 Self(After::Delay(seconds))
78 }
79
80 #[must_use]
81 pub fn after(&self) -> After {
82 self.0
83 }
84}
85
86impl TryFromValues for After {
87 fn try_from_values<'i, I>(values: &mut I) -> Result<Self, Error>
88 where
89 I: Iterator<Item = &'i HeaderValue>,
90 {
91 values
92 .next()
93 .and_then(|val| {
94 if let Some(delay) = Seconds::try_from_val(val) {
95 return Some(Self::Delay(delay));
96 }
97
98 let date = HttpDate::from_val(val)?;
99 Some(Self::DateTime(date))
100 })
101 .ok_or_else(Error::invalid)
102 }
103}
104
105impl<'a> TryFrom<&'a After> for HeaderValue {
106 type Error = BoxError;
107
108 fn try_from(after: &'a After) -> Result<Self, Self::Error> {
109 match *after {
110 After::Delay(ref delay) => Ok(delay.into()),
111 After::DateTime(ref date) => date.try_into(),
112 }
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::super::test_decode;
119 use super::{RetryAfter, Seconds};
120 use crate::util::HttpDate;
121
122 #[test]
123 fn delay_decode() {
124 let r: RetryAfter = test_decode(&["1234"]).unwrap();
125 assert_eq!(r, RetryAfter::delay(Seconds::new(1234)));
126 }
127
128 macro_rules! test_retry_after_datetime {
129 ($name:ident, $s:expr) => {
130 #[test]
131 fn $name() {
132 let r: RetryAfter = test_decode(&[$s]).unwrap();
133 let dt = "Sun, 06 Nov 1994 08:49:37 GMT".parse::<HttpDate>().unwrap();
134
135 assert_eq!(r, RetryAfter(super::After::DateTime(dt)));
136 }
137 };
138 }
139
140 test_retry_after_datetime!(date_decode_rfc1123, "Sun, 06 Nov 1994 08:49:37 GMT");
141 test_retry_after_datetime!(date_decode_rfc850, "Sunday, 06-Nov-94 08:49:37 GMT");
142 test_retry_after_datetime!(date_decode_asctime, "Sun Nov 6 08:49:37 1994");
143}