fix: cache immutable blobs served from /files

Page and cover blobs are content-addressed by unguessable, immutable keys,
but /files sent no Cache-Control, so the browser refetched on every reader
open — defeating the whole-chapter and next-chapter preloading (and re-
proxying every byte through the node server in prod). Send
`Cache-Control: public, max-age=31536000, immutable`.

Bump to 0.124.3.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-07-07 20:30:03 +02:00
parent 379224bee4
commit b0500e8e48
5 changed files with 20 additions and 3 deletions

2
backend/Cargo.lock generated
View File

@@ -1558,7 +1558,7 @@ checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
[[package]] [[package]]
name = "mangalord" name = "mangalord"
version = "0.124.2" version = "0.124.3"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"argon2", "argon2",

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "mangalord" name = "mangalord"
version = "0.124.2" version = "0.124.3"
edition = "2021" edition = "2021"
default-run = "mangalord" default-run = "mangalord"

View File

@@ -49,6 +49,16 @@ async fn serve(State(state): State<AppState>, Path(key): Path<String>) -> AppRes
HeaderName::from_static("x-content-type-options"), HeaderName::from_static("x-content-type-options"),
"nosniff".to_string(), "nosniff".to_string(),
), ),
// Blobs are content-addressed by unguessable, immutable keys (a
// re-upload mints new UUIDs), so a fetched page/cover never changes.
// Cache it for a year and mark it `immutable` so browsers skip
// revalidation entirely — this is what lets the reader's page and
// next-chapter preloading hit cache instead of re-downloading (and
// re-proxying every byte through the SvelteKit node server in prod).
(
header::CACHE_CONTROL,
"public, max-age=31536000, immutable".to_string(),
),
]; ];
Ok((headers, Body::from_stream(file.stream)).into_response()) Ok((headers, Body::from_stream(file.stream)).into_response())
} }

View File

@@ -172,6 +172,13 @@ async fn files_endpoint_streams_in_multiple_frames(pool: PgPool) {
resp.headers().get("x-content-type-options").unwrap(), resp.headers().get("x-content-type-options").unwrap(),
"nosniff" "nosniff"
); );
// Blobs are content-addressed by unguessable, immutable keys, so they're
// safe to cache forever — this is what makes the reader's page + next-
// chapter preloading actually hit cache instead of re-downloading.
assert_eq!(
resp.headers().get(header::CACHE_CONTROL).unwrap(),
"public, max-age=31536000, immutable"
);
let mut body = resp.into_body(); let mut body = resp.into_body();
let mut frames = 0usize; let mut frames = 0usize;

View File

@@ -1,6 +1,6 @@
{ {
"name": "mangalord-frontend", "name": "mangalord-frontend",
"version": "0.124.2", "version": "0.124.3",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {