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