ferro-bundle
In-memory immutable byte-blob serving with content-hashed URLs for the Ferro framework.
The crate exposes a single Bundle type that registers compile-time-included bytes (include_bytes!) at boot, exposes a content-hashed URL of the form /bundles/{name}.{sha8}.{ext}, and serves the bytes with a one-year Cache-Control: public, max-age=31536000, immutable header plus a strong SHA-256 ETag and 304 fast-path on If-None-Match exact match. A .with_alias("/path") mechanism registers stable plain URLs that 301-redirect to the current hashed URL.
Features
- SHA-256 content hashing (first 8 hex chars in the URL, full 64-hex digest in the ETag)
- One-year immutable
Cache-Controlheaders withimmutabledirective (RFC 8246) - Strong, quoted ETag per RFC 7232 with 304 fast-path on
If-None-Matchexact match - Stable alias URLs that 301-redirect to the current hashed URL
Usage
use Bundle;
// At boot, register a compile-time-embedded SDK bundle.
let sdk = new
.content_type
.with_alias;
// The hashed URL is deterministic per byte contents.
assert!;
// Inside a request handler mounted on `/bundles/{filename}` (and on each
// registered alias path), dispatch via Bundle::serve.
// ferro-bundle does not own routing; the consumer wires the handler.
async
Bundle vs filesystem static files
ferro-bundle and the framework's filesystem static-file handler at ferro_rs::static_files are two parallel asset-serving paths. They target different freshness models and are intentionally not folded into one.
| Path | Freshness model | Cache lifetime | Use for |
|---|---|---|---|
ferro-bundle |
content hash in URL | one year, immutable |
SDK bundles, embedded fonts, versioned static assets included via include_bytes! |
ferro_rs::static_files |
bust_asset_urls timestamp query param |
shorter, revalidated | tenant-customizable CSS, theme assets, on-disk user uploads |
Do not fold these — they target different freshness models. A content-hashed URL is a stable handle to an immutable blob; a timestamp-busted URL is a freshness marker on a mutable file. Collapsing the two paths erodes both contracts (do not fold these paths into one).
Security note
The caller provides content_type at registration. Serving caller-supplied bytes as text/html from a cookie-authenticated origin can introduce an XSS vector if the bundle bytes are themselves user-controlled. The locked &'static [u8] API restricts bytes to compile-time inclusion, which mitigates this; downstream consumers should keep that invariant when extending the crate in future phases.
License
MIT — see the ferro workspace README for documentation links (https://docs.rs/ferro-bundle).