orinium_browser/platform/network/
cache.rs1use std::collections::HashMap;
4use std::sync::{Arc, RwLock};
5use std::time::{Duration, SystemTime};
6use url::Url;
7
8#[allow(dead_code)]
9#[derive(Debug, Clone)]
10pub struct CachedResponse {
11 pub body: Vec<u8>,
12 pub headers: Vec<(String, String)>,
13 pub cached_at: SystemTime,
14 pub expires_at: Option<SystemTime>,
15}
16
17#[derive(Debug, Clone)]
18pub struct Cache {
19 store: Arc<RwLock<HashMap<String, CachedResponse>>>,
20}
21
22#[allow(dead_code)]
23impl Default for Cache {
24 fn default() -> Self {
25 Self::new()
26 }
27}
28
29impl Cache {
30 pub fn new() -> Self {
31 Self {
32 store: Arc::new(RwLock::new(HashMap::new())),
33 }
34 }
35
36 pub fn get(&self, url: &Url) -> Option<CachedResponse> {
37 let store = self.store.read().ok()?;
38 let key = url.as_str();
39
40 if let Some(entry) = store.get(key) {
41 if let Some(exp) = entry.expires_at
42 && SystemTime::now() > exp
43 {
44 return None;
45 }
46 return Some(entry.clone());
47 }
48 None
49 }
50
51 pub fn set(&self, url: &Url, body: Vec<u8>, headers: Vec<(String, String)>) {
52 let mut store = self.store.write().expect("RwLock poisoned");
53 let key = url.as_str().to_string();
54
55 let mut expires = None;
56 if let Some((_, cc)) = headers
57 .iter()
58 .find(|(n, _)| n.eq_ignore_ascii_case("cache-control"))
59 && let Some(pos) = cc.find("max-age=")
60 && let Ok(max_age) = cc[pos + 8..]
61 .split(|c: char| !c.is_ascii_digit())
62 .next()
63 .unwrap_or("0")
64 .parse::<u64>()
65 {
66 expires = Some(SystemTime::now() + Duration::from_secs(max_age));
67 }
68
69 store.insert(
70 key,
71 CachedResponse {
72 body,
73 headers,
74 cached_at: SystemTime::now(),
75 expires_at: expires,
76 },
77 );
78 }
79
80 pub fn clear(&self) {
81 let mut store = self.store.write().expect("RwLock poisoned");
82 store.clear();
83 }
84}