rate_limits/
retry_after.rs1use std::str::FromStr;
5
6use time::{Date, format_description::well_known::Rfc2822};
7
8use crate::reset_time::{ResetTime, ResetTimeKind};
9
10use crate::error::{Error, Result};
11
12#[derive(Copy, Clone, Debug, PartialEq)]
14pub struct RateLimit {
15 pub reset: ResetTime,
17}
18
19impl RateLimit {
20 #[cfg(feature = "http")]
24 pub fn new(headers: &http::HeaderMap) -> std::result::Result<Self, Error> {
25 Self::extract(crate::convert::header_map_str_pairs(headers))
26 }
27
28 pub fn extract<'a, I>(headers: I) -> std::result::Result<Self, Error>
30 where
31 I: IntoIterator<Item = (&'a str, &'a str)>,
32 {
33 let mut retry_after_val = None;
34 for (k, v) in headers {
35 if k.eq_ignore_ascii_case("retry-after") {
36 retry_after_val = Some(v);
37 break;
38 }
39 }
40
41 let reset = match retry_after_val {
42 Some(retry_after_str) => {
43 if Date::parse(retry_after_str, &Rfc2822).is_ok() {
44 ResetTime::new(retry_after_str, ResetTimeKind::ImfFixdate)?
45 } else {
46 ResetTime::new(retry_after_str, ResetTimeKind::Seconds)?
47 }
48 }
49 None => return Err(Error::MissingRetryAfter),
50 };
51
52 Ok(RateLimit { reset })
53 }
54
55 #[must_use]
57 pub const fn reset(&self) -> ResetTime {
58 self.reset
59 }
60}
61
62impl FromStr for RateLimit {
63 type Err = Error;
64
65 fn from_str(map: &str) -> Result<Self> {
66 RateLimit::extract(crate::convert::parse_header_lines(map))
67 }
68}
69
70#[cfg(test)]
71mod tests {
72
73 use super::*;
74 use indoc::indoc;
75 use time::macros::datetime;
76
77 #[test]
78 fn retry_after_seconds() {
79 let headers = indoc! {"
80 Retry-After: 19
81 "};
82
83 let rate = RateLimit::from_str(headers).unwrap();
84 assert_eq!(rate.reset(), ResetTime::Seconds(19));
85 }
86
87 #[test]
88 fn retry_after_seconds_case_sensitive() {
89 let headers = indoc! {"
90 retry-after: 19
91 "};
92
93 let rate = RateLimit::from_str(headers).unwrap();
94 assert_eq!(rate.reset(), ResetTime::Seconds(19));
95 }
96
97 #[test]
98 fn retry_after_imf_fixdate() {
99 let headers = indoc! {"
100 Retry-After: Fri, 31 Dec 1999 23:59:59 GMT
101 "};
102
103 let rate = RateLimit::from_str(headers).unwrap();
104 assert_eq!(
105 rate.reset(),
106 ResetTime::DateTime(datetime!(1999-12-31 23:59:59 UTC))
107 );
108 }
109}