asset.rsannotatedasset.rssource146 lines · 6.0 KB · raw

The files a Jev site's pages load, embedded in the binary and named by their content, so a Worker serves them from itself and a page never asks another site for anything.

A site mounts find as a fallback route and answers with the asset's content_type and cache_control. href gives the address a page links to: the stable path with ?v=<hash of the bytes>, so a long cache never serves an old stylesheet after the crate moves.

One embedded file.

11#[derive(Clone, Copy, Debug)]
12pub struct Asset {

Where it is served from, with no query: /ui.css.

14    pub path: &'static str,
15    pub content_type: &'static str,
16    pub body: &'static [u8],
17}
19pub const CSS: Asset = Asset { path: "/ui.css", content_type: "text/css; charset=utf-8", body: include_bytes!("../assets/ui.css") };
20pub const JS: Asset = Asset { path: "/ui.js", content_type: "text/javascript; charset=utf-8", body: include_bytes!("../assets/ui.js") };

Datastar v1.0.4, upstream's own release build. It is not edited here.

22pub const DATASTAR: Asset =
23    Asset { path: "/datastar.js", content_type: "text/javascript; charset=utf-8", body: include_bytes!("../assets/datastar.js") };
25const INTER_TIGHT: Asset = Asset { path: "/fonts/inter-tight-500.woff2", content_type: "font/woff2", body: include_bytes!("../assets/fonts/inter-tight-500.woff2") };
26const JETBRAINS_MONO: Asset = Asset { path: "/fonts/jetbrains-mono.woff2", content_type: "font/woff2", body: include_bytes!("../assets/fonts/jetbrains-mono.woff2") };
27const VT323: Asset = Asset { path: "/fonts/vt323.woff2", content_type: "font/woff2", body: include_bytes!("../assets/fonts/vt323.woff2") };

SerenityOS's pixel emoji, four of them (components::PixelEmoji). Not preloaded: a page that shows none never fetches it.

30const PIXEL_EMOJI: Asset = Asset { path: "/fonts/pixel-emoji.woff2", content_type: "font/woff2", body: include_bytes!("../assets/fonts/pixel-emoji.woff2") };

The fonts every page uses, which the head preloads.

33pub const FONTS: [Asset; 3] = [INTER_TIGHT, JETBRAINS_MONO, VT323];

Every asset, by path. The one list: find reads it, and a test holds it to what the stylesheet asks for.

37pub const ALL: [Asset; 7] = [CSS, JS, DATASTAR, INTER_TIGHT, JETBRAINS_MONO, VT323, PIXEL_EMOJI];

The asset served at path (no query), if there is one.

40pub fn find(path: &str) -> Option<&'static Asset> {
41    ALL.iter().find(|asset| asset.path == path)
42}

FNV-1a over bytes, as eight hex digits: a name for the content, not a secret.

46pub fn hash(bytes: &[u8]) -> String {
47    let hash = bytes.iter().fold(0x811c_9dc5_u32, |hash, &byte| (hash ^ u32::from(byte)).wrapping_mul(0x0100_0193));
48    format!("{hash:08x}")
49}
51impl Asset {

The hash of its bytes.

53    pub fn version(&self) -> String {
54        hash(self.body)
55    }

What a page links to: /ui.css?v=1a2b3c4d.

58    pub fn href(&self) -> String {
59        format!("{}?v={}", self.path, self.version())
60    }

The Cache-Control to answer with. A request that carries the right ?v= names exactly these bytes, so it never changes; one without is for a day.

65    pub fn cache_control(&self, query: Option<&str>) -> &'static str {
66        let want = format!("v={}", self.version());
67        if query.is_some_and(|query| query.split('&').any(|part| part == want)) {
68            "public, max-age=31536000, immutable"
69        } else {
70            "public, max-age=86400"
71        }
72    }
74    pub fn text(&self) -> &'static str {
75        std::str::from_utf8(self.body).expect("the text assets are UTF-8")
76    }
77}

A stable name for a stylesheet or script a site makes itself (the demo's cat motion, say): href and hash, so it is cached the way the shared files are.

82pub fn versioned_href(path: &str, content: &str) -> String {
83    format!("{path}?v={}", hash(content.as_bytes()))
84}
86#[cfg(test)]
87mod tests {
88    use super::*;
89
90    #[test]
91    fn every_path_is_unique_and_absolute_without_a_query() {
92        for (i, a) in ALL.iter().enumerate() {
93            assert!(a.path.starts_with('/') && !a.path.contains('?'), "{}", a.path);
94            assert!(!a.body.is_empty(), "{}", a.path);
95            assert!(ALL.iter().skip(i + 1).all(|b| b.path != a.path), "{}", a.path);
96        }
97    }
98
99    #[test]
100    fn find_answers_by_path() {
101        assert_eq!(find("/ui.css").unwrap().path, "/ui.css");
102        assert!(find("/ui.css?v=1").is_none(), "a path has no query");
103        assert!(find("/nope").is_none());
104    }
105
106    #[test]
107    fn the_stylesheet_asks_only_for_fonts_this_crate_serves() {
108        let css = CSS.text();
109        let mut asked = 0;
110        for part in css.split("url(\"").skip(1) {
111            let url = part.split('"').next().unwrap();
112            asked += 1;
113            assert!(find(url).is_some(), "{url}");
114        }
115        // The preloaded fonts, and the pixel emoji that are fetched only when a glyph is drawn.
116        assert_eq!(asked, FONTS.len() + 1);
117        for font in FONTS.iter().chain([&PIXEL_EMOJI]) {
118            assert!(css.contains(font.path), "{}", font.path);
119        }
120        assert!(!css.contains("://") && !css.contains("@import"), "nothing is fetched from another site");
121    }
122
123    #[test]
124    fn the_version_names_the_bytes() {
125        assert_eq!(hash(b""), "811c9dc5");
126        assert_eq!(CSS.version().len(), 8);
127        assert_ne!(CSS.version(), JS.version());
128        assert!(CSS.href().starts_with("/ui.css?v="));
129    }
130
131    #[test]
132    fn a_matching_version_is_cached_for_good_and_a_bare_path_for_a_day() {
133        let own = format!("v={}", CSS.version());
134        assert!(CSS.cache_control(Some(&own)).contains("immutable"));
135        assert!(!CSS.cache_control(Some("v=00000000")).contains("immutable"));
136        assert!(!CSS.cache_control(None).contains("immutable"));
137    }
138
139    #[test]
140    fn the_page_script_fetches_nothing() {
141        let js = JS.text();
142        for banned in ["fetch(", "XMLHttpRequest", "sendBeacon", "WebSocket", "import("] {
143            assert!(!js.contains(banned), "{banned}");
144        }
145    }
146}