Skip to main content

firebase_admin/core/
http.rs

1//! Shared HTTP client wrapper used by all service modules.
2
3use std::time::Duration;
4
5/// Thin wrapper around a [`reqwest::Client`], giving service modules a single
6/// seam for future cross-cutting concerns (retries, backoff, request tracing).
7#[derive(Debug, Clone)]
8pub struct HttpClient {
9    inner: reqwest::Client,
10}
11
12impl HttpClient {
13    /// Wraps an existing [`reqwest::Client`].
14    pub fn new(inner: reqwest::Client) -> Self {
15        Self { inner }
16    }
17
18    /// Returns the underlying [`reqwest::Client`].
19    pub fn inner(&self) -> &reqwest::Client {
20        &self.inner
21    }
22}
23
24impl Default for HttpClient {
25    fn default() -> Self {
26        Self::new(reqwest::Client::new())
27    }
28}
29
30/// Parses the `max-age` directive out of a `Cache-Control` header value.
31///
32/// Shared by every public-key cache in the crate (ID token JWKS, session
33/// cookie certs) so both respect Google's actual cache lifetime instead of
34/// each hardcoding their own guess.
35pub(crate) fn parse_cache_control_max_age(cache_control: &str) -> Option<Duration> {
36    cache_control.split(',').find_map(|part| {
37        let part = part.trim();
38        let value = part.strip_prefix("max-age=")?;
39        value.parse::<u64>().ok().map(Duration::from_secs)
40    })
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46
47    #[test]
48    fn parses_max_age_from_cache_control_header() {
49        assert_eq!(
50            parse_cache_control_max_age("public, max-age=21600, must-revalidate"),
51            Some(Duration::from_secs(21600))
52        );
53        assert_eq!(parse_cache_control_max_age("no-store"), None);
54        assert_eq!(parse_cache_control_max_age(""), None);
55    }
56}