MCPcopy Create free account
hub / github.com/chatmail/core / http_cache_get

Function http_cache_get

src/net/http.rs:183–244  ·  view source on GitHub ↗
(context: &Context, url: &str)

Source from the content-addressed store, hash-verified

181/// Also returns if the response is stale and should be revalidated in the background.
182#[expect(clippy::arithmetic_side_effects)]
183async fn http_cache_get(context: &Context, url: &str) -> Result<Option<(Response, bool)>> {
184 let now = time();
185 let Some((blob_name, mimetype, encoding, stale_timestamp)) = context
186 .sql
187 .query_row_optional(
188 "SELECT blobname, mimetype, encoding, stale
189 FROM http_cache WHERE url=? AND expires > ?",
190 (url, now),
191 |row| {
192 let blob_name: String = row.get(0)?;
193 let mimetype: Option<String> = Some(row.get(1)?).filter(|s: &String| !s.is_empty());
194 let encoding: Option<String> = Some(row.get(2)?).filter(|s: &String| !s.is_empty());
195 let stale_timestamp: i64 = row.get(3)?;
196 Ok((blob_name, mimetype, encoding, stale_timestamp))
197 },
198 )
199 .await?
200 else {
201 return Ok(None);
202 };
203 let is_stale = now > stale_timestamp;
204
205 let blob_object = BlobObject::from_name(context, &blob_name)?;
206 let blob_abs_path = blob_object.to_abs_path();
207 let blob = match fs::read(blob_abs_path)
208 .await
209 .with_context(|| format!("Failed to read blob for {url:?} cache entry."))
210 {
211 Ok(blob) => blob,
212 Err(err) => {
213 // This should not happen, but user may go into the blobdir and remove files,
214 // antivirus may delete the file or there may be a bug in housekeeping.
215 warn!(context, "{err:?}.");
216 return Ok(None);
217 }
218 };
219
220 let (expires, _stale) = http_url_cache_timestamps(url, mimetype.as_deref());
221 let response = Response {
222 blob,
223 mimetype,
224 encoding,
225 };
226
227 // Update expiration timestamp
228 // to prevent deletion of the file still in use.
229 //
230 // If the response is stale, the caller should revalidate it in the background, so update
231 // `stale` timestamp to avoid revalidating too frequently (and have many parallel revalidation
232 // tasks) if revalidation fails or the HTTP request takes some time. The stale period >= 1 hour,
233 // so 1 more minute won't be a problem.
234 let stale_timestamp = if is_stale { now + 60 } else { stale_timestamp };
235 context
236 .sql
237 .execute(
238 "UPDATE http_cache SET expires=?, stale=? WHERE url=?",
239 (expires, stale_timestamp, url),
240 )

Callers 2

read_url_blob_with_tlsFunction · 0.85
test_http_cacheFunction · 0.85

Calls 8

timeFunction · 0.85
query_row_optionalMethod · 0.80
to_abs_pathMethod · 0.80
executeMethod · 0.80
getMethod · 0.45
filterMethod · 0.45
is_emptyMethod · 0.45

Tested by 1

test_http_cacheFunction · 0.68