qubit_http/response/
http_response_meta.rs1use std::time::{Duration, SystemTime};
12
13use http::header::RETRY_AFTER;
14use http::{HeaderMap, Method, StatusCode};
15use httpdate::parse_http_date;
16use url::Url;
17
18#[derive(Debug, Clone)]
20pub struct HttpResponseMeta {
21 pub status: StatusCode,
23 pub headers: HeaderMap,
25 pub url: Url,
27 pub method: Method,
29}
30
31impl HttpResponseMeta {
32 pub fn new(status: StatusCode, headers: HeaderMap, url: Url, method: Method) -> Self {
34 Self {
35 status,
36 headers,
37 url,
38 method,
39 }
40 }
41
42 pub fn retry_after_hint(&self) -> Option<Duration> {
47 if !is_retry_after_applicable_status(self.status) {
48 return None;
49 }
50 self.headers
51 .get(RETRY_AFTER)
52 .and_then(|value| value.to_str().ok())
53 .and_then(parse_retry_after_value)
54 }
55}
56
57fn is_retry_after_applicable_status(status: StatusCode) -> bool {
58 status == StatusCode::TOO_MANY_REQUESTS || status.is_server_error()
59}
60
61fn parse_retry_after_value(value: &str) -> Option<Duration> {
62 let trimmed = value.trim();
63 if trimmed.is_empty() {
64 return None;
65 }
66 if let Ok(seconds) = trimmed.parse::<u64>() {
67 return Some(Duration::from_secs(seconds));
68 }
69 let retry_at = parse_http_date(trimmed).ok()?;
70 let now = SystemTime::now();
71 Some(
72 retry_at
73 .duration_since(now)
74 .unwrap_or_else(|_| Duration::from_secs(0)),
75 )
76}