use std::time::{Duration, SystemTime};
use http::header::RETRY_AFTER;
use http::{HeaderMap, Method, StatusCode};
use httpdate::parse_http_date;
use url::Url;
#[derive(Debug, Clone)]
pub struct HttpResponseMeta {
pub status: StatusCode,
pub headers: HeaderMap,
pub url: Url,
pub method: Method,
}
impl HttpResponseMeta {
pub fn new(status: StatusCode, headers: HeaderMap, url: Url, method: Method) -> Self {
Self {
status,
headers,
url,
method,
}
}
pub fn retry_after_hint(&self) -> Option<Duration> {
if !is_retry_after_applicable_status(self.status) {
return None;
}
self.headers
.get(RETRY_AFTER)
.and_then(|value| value.to_str().ok())
.and_then(parse_retry_after_value)
}
}
fn is_retry_after_applicable_status(status: StatusCode) -> bool {
status == StatusCode::TOO_MANY_REQUESTS || status.is_server_error()
}
fn parse_retry_after_value(value: &str) -> Option<Duration> {
let trimmed = value.trim();
if trimmed.is_empty() {
return None;
}
if let Ok(seconds) = trimmed.parse::<u64>() {
return Some(Duration::from_secs(seconds));
}
let retry_at = parse_http_date(trimmed).ok()?;
let now = SystemTime::now();
Some(
retry_at
.duration_since(now)
.unwrap_or_else(|_| Duration::from_secs(0)),
)
}