Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/knut

crates/knut-wasm-host/src/media.rs

//! Extension → content type. A small, honest table, and no fallback.
//!
//! The host never looks at a file *name* — `index.html`, `facet_wrapped.js` and
//! `facet_wrapped_bg.wasm` are a component library's business, not a byte server's.
//! It looks at the extension, and if the extension is not in this table it REFUSES.
//!
//! Two things a fallback would have bought, and why neither is worth it:
//!
//! * `application/octet-stream` is a lie a browser acts on — a `.wasm` served that
//!   way fails `WebAssembly.instantiateStreaming` with a message about MIME types
//!   that reads like a bug in the wasm.
//! * anything text-ish is a hole: a bundle directory is a directory, and a
//!   directory acquires files. Serving whatever turns up, typed by guess, is how a
//!   static route becomes an exfiltration route.

use std::path::Path;

/// Every extension this host will serve, and what it serves it as. A wasm bundle
/// ships the first four; wasm-bindgen can add the last two (a themed loader's CSS,
/// a source map).
pub const MEDIA_TYPES: [(&str, &str); 7] = [
    ("html", "text/html; charset=utf-8"),
    ("js", "text/javascript; charset=utf-8"),
    ("mjs", "text/javascript; charset=utf-8"),
    ("wasm", "application/wasm"),
    ("json", "application/json"),
    ("map", "application/json"),
    ("css", "text/css; charset=utf-8"),
];

/// The content type for `path`'s extension, or `None` — which the caller must turn
/// into a refusal, never into a guess.
///
/// A leading-dot name (`.env`) has no extension as far as `Path` is concerned, and
/// that is the right answer here too: it is a name, not a type.
#[must_use]
pub fn content_type(path: &Path) -> Option<&'static str> {
    let ext = path.extension()?.to_str()?;
    MEDIA_TYPES
        .iter()
        .find(|(e, _)| ext.eq_ignore_ascii_case(e))
        .map(|(_, ty)| *ty)
}

/// The servable extensions, comma-separated — for a refusal that says what the host
/// *would* have served.
#[must_use]
pub fn known_extensions() -> String {
    let mut seen: Vec<&str> = Vec::with_capacity(MEDIA_TYPES.len());
    for (ext, _) in MEDIA_TYPES {
        if !seen.contains(&ext) {
            seen.push(ext);
        }
    }
    seen.join(", ")
}