embed_wasm/
lib.rs

1#![deny(warnings, missing_docs)]
2//! This crate provides utilities for serving 'cargo-web' build output
3//! (rust compiled as wasm and associated html/css/etc files) included in
4//! native binaries as HTTP responses
5//!
6//! Designed for use with the [`embed-wasm-build` crate](https://crates.io/crates/embed-wasm-build).
7//! See [embed-wasm-example](https://github.com/inanna-malick/embed-wasm-example) for a full example.
8
9use headers::HeaderMapExt;
10use hyper::{Body, Response};
11
12/// Enum controlling how requests with path '/' are handled
13#[non_exhaustive]
14#[derive(PartialEq, Eq)]
15pub enum IndexHandling {
16    /// map requests to '/' to 'index.html'
17    MapEmptyPathToIndex,
18    /// apply no special logic to requests to '/'
19    NoIndexHandling,
20}
21
22/// Wraps a hashmap of static content generated at compile time and provides convenience
23/// functions for resolving static content as 'hyper::Response' when given a path.
24pub struct StaticLookup {
25    /// Enum controlling how requests with path '/' are handled (only public for macro use)
26    #[doc(hidden)]
27    pub index_mode: IndexHandling,
28    /// Reference to the static map containing binary content (only public for macro use)
29    #[doc(hidden)]
30    pub wasm: &'static phf::Map<&'static str, &'static [u8]>,
31}
32
33impl StaticLookup {
34    /// Given a path ('/', '/css/tree.css', etc) attempt to construct a 'hyper::Response'
35    /// using the static hashmap generated at compile time. Infers MIME type from path.
36    ///
37    /// path expected as `let x: http::uri::PathAndQuery = ..; x.as_str()`, omiting type to simplify interface
38    pub fn get(&self, path: &str) -> Option<Response<Body>> {
39        // drop leading '/' from path
40        let path = &path[1..];
41
42        let path = if path.len() == 0 && self.index_mode == IndexHandling::MapEmptyPathToIndex {
43            "index.html"
44        } else {
45            path
46        };
47
48        match self.wasm.get(path).map(|p| *p) {
49            None => None,
50            Some(blob) => {
51                let body = hyper::Body::from(blob);
52                let mut resp = hyper::Response::new(body);
53
54                let mime_type = mime_guess::from_path(path).first_or_octet_stream();
55                resp.headers_mut()
56                    .typed_insert(headers::ContentType::from(mime_type));
57                resp.headers_mut()
58                    .typed_insert(headers::AcceptRanges::bytes());
59                resp.headers_mut()
60                    .typed_insert(headers::ContentLength(blob.len() as u64));
61
62                Some(resp)
63            }
64        }
65    }
66}
67
68/// Imports the generated static wasm blobs from the build output directory as
69/// generated by 'embed_wasm_build::compile_wasm'
70#[macro_export]
71macro_rules! include_wasm {
72    () => {
73        include!(concat!(env!("OUT_DIR"), "/wasm_blobs.rs"));
74
75        // FIXME: will fail if user aliases embed_wasm
76        pub static STATIC_LOOKUP: ::embed_wasm::StaticLookup = ::embed_wasm::StaticLookup {
77            index_mode: ::embed_wasm::IndexHandling::MapEmptyPathToIndex,
78            wasm: &WASM,
79        };
80    };
81}