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