1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#![forbid(unsafe_code)]
#![deny(
    clippy::dbg_macro,
    missing_copy_implementations,
    rustdoc::missing_crate_level_docs,
    missing_debug_implementations,
    missing_docs,
    nonstandard_style,
    unused_qualifications
)]

/*!
Serves static file assets from the file system.

```
# #[cfg(not(unix))] fn main() {}
# #[cfg(unix)] fn main() {
use trillium_static::{StaticFileHandler, crate_relative_path};

let mut handler = StaticFileHandler::new(crate_relative_path!("examples/files"))
    .with_index_file("index.html");


// given the following directory layout
//
// examples/files
// ├── index.html
// ├── subdir
// │  └── index.html
// └── subdir_with_no_index
//    └── plaintext.txt
//


use trillium_testing::prelude::*;

init(&mut handler);

assert_ok!(
    get("/").on(&handler),
    "<h1>hello world</h1>",
    "content-type" => "text/html; charset=utf-8"
);
assert_not_handled!(get("/file_that_does_not_exist.txt").on(&handler));
assert_ok!(get("/index.html").on(&handler));
assert_ok!(get("/subdir/index.html").on(&handler), "subdir index.html");
assert_ok!(get("/subdir").on(&handler), "subdir index.html");
assert_not_handled!(get("/subdir_with_no_index").on(&handler));
assert_ok!(
    get("/subdir_with_no_index/plaintext.txt").on(&handler),
    "plaintext file",
    "content-type" => "text/plain; charset=utf-8"
);


// with a different index file
let plaintext_index = StaticFileHandler::new(crate_relative_path!("examples/files"))
    .with_index_file("plaintext.txt");

assert_not_handled!(get("/").on(&plaintext_index));
assert_not_handled!(get("/subdir").on(&plaintext_index));
assert_ok!(
    get("/subdir_with_no_index").on(&plaintext_index),
    "plaintext file",
    "content-type" => "text/plain; charset=utf-8"
);
# }
```


## ❗IMPORTANT❗

this crate has three features currently: `smol`, `async-std`, and
`tokio`.

You **must** enable one of these in order to use the crate. This
is intended to be a temporary situation, and eventually you will not
need to specify the runtime through feature flags.

## stability note

Please note that this crate is fairly incomplete, while functional. It
does not include any notion of range requests or cache headers. It
serves all files from disk every time, with no in-memory caching.
*/

cfg_if::cfg_if! {
   if #[cfg(any(feature = "smol", feature = "tokio", feature = "async-std"))] {
       mod fs_shims;
       mod handler;
       mod options;
       mod static_conn_ext;

       pub use handler::StaticFileHandler;
       pub use relative_path;
       pub use static_conn_ext::StaticConnExt;

       /// a convenient helper macro to build a str relative to the crate root
       #[macro_export]
       macro_rules! crate_relative_path {
           ($path:literal) => {
               $crate::relative_path::RelativePath::new($path).to_logical_path(env!("CARGO_MANIFEST_DIR"))
           };
       }

       /// convenience alias for [`StaticFileHandler::new`]
       pub fn files(fs_root: impl AsRef<std::path::Path>) -> StaticFileHandler {
           StaticFileHandler::new(fs_root)
       }
   } else {
        compile_error!("trillium-static:
You must enable one of the three runtime feature flags
to use this crate:

* tokio
* async-std
* smol

This is a temporary constraint, and hopefully soon this
will not require the use of cargo feature flags."
);
   }
}