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}