trillium_static/
lib.rs

1#![forbid(unsafe_code)]
2#![deny(
3    clippy::dbg_macro,
4    missing_copy_implementations,
5    rustdoc::missing_crate_level_docs,
6    missing_debug_implementations,
7    missing_docs,
8    nonstandard_style,
9    unused_qualifications
10)]
11
12/*!
13Serves static file assets from the file system.
14
15```
16# #[cfg(not(unix))] fn main() {}
17# #[cfg(unix)] fn main() {
18use trillium_static::{StaticFileHandler, crate_relative_path};
19
20# trillium_testing::block_on(async {
21
22let mut handler = StaticFileHandler::new(crate_relative_path!("examples/files"))
23    .with_index_file("index.html");
24
25
26// given the following directory layout
27//
28// examples/files
29// ├── index.html
30// ├── subdir
31// │  └── index.html
32// └── subdir_with_no_index
33//    └── plaintext.txt
34//
35
36
37use trillium_testing::prelude::*;
38# use trillium::Handler;
39
40handler.init(&mut "testing".into()).await;
41
42assert_ok!(
43    get("/").run_async(&handler).await,
44    "<h1>hello world</h1>",
45    "content-type" => "text/html; charset=utf-8"
46);
47assert_not_handled!(get("/file_that_does_not_exist.txt").run_async(&handler).await);
48assert_ok!(get("/index.html").run_async(&handler).await);
49assert_ok!(get("/subdir/index.html").run_async(&handler).await, "subdir index.html");
50assert_ok!(get("/subdir").run_async(&handler).await, "subdir index.html");
51assert_not_handled!(get("/subdir_with_no_index").run_async(&handler).await);
52assert_ok!(
53    get("/subdir_with_no_index/plaintext.txt").run_async(&handler).await,
54    "plaintext file",
55    "content-type" => "text/plain; charset=utf-8"
56);
57
58
59// with a different index file
60let plaintext_index = StaticFileHandler::new(crate_relative_path!("examples/files"))
61    .with_index_file("plaintext.txt");
62
63assert_not_handled!(get("/").run_async(&plaintext_index).await);
64assert_not_handled!(get("/subdir").run_async(&plaintext_index).await);
65assert_ok!(
66    get("/subdir_with_no_index").run_async(&plaintext_index).await,
67    "plaintext file",
68    "content-type" => "text/plain; charset=utf-8"
69);
70# }); }
71```
72
73
74## ❗IMPORTANT❗
75
76this crate has three features currently: `smol`, `async-std`, and
77`tokio`.
78
79You **must** enable one of these in order to use the crate. This
80is intended to be a temporary situation, and eventually you will not
81need to specify the runtime through feature flags.
82
83## stability note
84
85Please note that this crate is fairly incomplete, while functional. It
86does not include any notion of range requests or cache headers. It
87serves all files from disk every time, with no in-memory caching.
88*/
89
90mod fs_shims;
91mod handler;
92mod options;
93mod static_conn_ext;
94
95pub use handler::StaticFileHandler;
96pub use relative_path;
97pub use static_conn_ext::StaticConnExt;
98
99/// a convenient helper macro to build a str relative to the crate root
100#[macro_export]
101macro_rules! crate_relative_path {
102    ($path:literal) => {
103        $crate::relative_path::RelativePath::new($path).to_logical_path(env!("CARGO_MANIFEST_DIR"))
104    };
105}
106
107/// convenience alias for [`StaticFileHandler::new`]
108pub fn files(fs_root: impl AsRef<std::path::Path>) -> StaticFileHandler {
109    StaticFileHandler::new(fs_root)
110}