@@ -15,27 +15,38 @@ use crate::fs::rewrite::*;
15
15
///
16
16
/// This handler makes is simple to serve static files from a directory on the
17
17
/// local file system. To use it, construct a `FileServer` using
18
- /// [`FileServer::new()`], then simply `mount` the handler. When mounted, the
19
- /// handler serves files from the specified directory. If the file is not found,
20
- /// the handler _forwards_ the request. By default, `FileServer` has a rank of
21
- /// `10`. Use [`FileServer::new()`] to create a handler with a custom rank.
18
+ /// [`FileServer::new()`], then `mount` the handler.
22
19
///
23
- /// # Customization
20
+ /// ```rust,no_run
21
+ /// # #[macro_use] extern crate rocket;
22
+ /// use rocket::fs::FileServer;
24
23
///
25
- /// How `FileServer` responds to specific requests can be customized through
26
- /// the use of [`Rewriter`]s. See [`Rewriter`] for more detailed documentation
27
- /// on how to take full advantage of `FileServer`'s extensibility.
24
+ /// #[launch]
25
+ /// fn rocket() -> _ {
26
+ /// rocket::build()
27
+ /// .mount("/", FileServer::new("/www/static"))
28
+ /// }
29
+ /// ```
30
+ ///
31
+ /// When mounted, the handler serves files from the specified path. If a
32
+ /// requested file does not exist, the handler _forwards_ the request with a
33
+ /// `404` status.
34
+ ///
35
+ /// By default, the route has a rank of `10` which can be changed with
36
+ /// [`FileServer::rank()`].
28
37
///
29
- /// [`FileServer::new()`] construct a `FileServer`
30
- /// with common rewrites: they filter out dotfiles, redirect requests to
31
- /// directories to include a trailing slash, and use `index.html` to respond to
32
- /// requests for a directory. If you want to customize or replace these default
33
- /// rewrites, see [`FileServer::empty()`].
38
+ /// # Customization
39
+ ///
40
+ /// `FileServer` works through a pipeline of _rewrites_ in which a requested
41
+ /// path is transformed into a `PathBuf` via [`Segments::to_path_buf()`] and
42
+ /// piped through a series of [`Rewriter`]s to obtain a final [`Rewrite`] which
43
+ /// is then used to generate a final response. See [`Rewriter`] for complete
44
+ /// details on implementing your own `Rewriter`s.
34
45
///
35
46
/// # Example
36
47
///
37
48
/// Serve files from the `/static` directory on the local file system at the
38
- /// `/public` path, with the default rewrites.
49
+ /// `/public` path:
39
50
///
40
51
/// ```rust,no_run
41
52
/// # #[macro_use] extern crate rocket;
@@ -68,6 +79,8 @@ use crate::fs::rewrite::*;
68
79
/// rocket::build().mount("/", FileServer::new(relative!("static")))
69
80
/// }
70
81
/// ```
82
+ ///
83
+ /// [`relative!`]: crate::fs::relative!
71
84
#[ derive( Clone ) ]
72
85
pub struct FileServer {
73
86
rewrites : Vec < Arc < dyn Rewriter > > ,
@@ -79,50 +92,53 @@ impl FileServer {
79
92
const DEFAULT_RANK : isize = 10 ;
80
93
81
94
/// Constructs a new `FileServer` that serves files from the file system
82
- /// `path` with a default rank.
95
+ /// `path` with the following rewrites:
83
96
///
84
- /// Adds a set of default rewrites:
85
- /// - `|f, _| f.is_visible()`: Hides all dotfiles.
86
- /// - [`Prefix::checked(path)`]: Applies the root path.
87
- /// - [`TrailingDirs`]: Normalizes directories to have a trailing slash.
88
- /// - [`DirIndex::unconditional("index.html")`](DirIndex::unconditional):
89
- /// Appends `index.html` to directory requests.
97
+ /// - `|f, _| f.is_visible()`: Serve only visible files (hide dotfiles).
98
+ /// - [`Prefix::checked(path)`]: Prefix requests with `path`.
99
+ /// - [`TrailingDirs`]: Ensure directory have a trailing slash.
100
+ /// - [`DirIndex::unconditional("index.html")`]: Serve `$dir/index.html` for
101
+ /// requests to directory `$dir`.
90
102
///
91
- /// If you don't want to serve requests for directories, or want to
92
- /// customize what files are served when a directory is requested, see
93
- /// [`Self::new_without_index`].
94
- ///
95
- /// If you need to allow requests for dotfiles, or make any other changes
96
- /// to the default rewrites, see [`Self::empty`].
103
+ /// If you don't want to serve index files or want a different index file,
104
+ /// use [`Self::without_index`]. To customize the entire request to file
105
+ /// path rewrite pipeline, use [`Self::identity`].
97
106
///
98
107
/// [`Prefix::checked(path)`]: crate::fs::rewrite::Prefix::checked
99
108
/// [`TrailingDirs`]: crate::fs::rewrite::TrailingDirs
100
- /// [`DirIndex::unconditional`]: crate::fs::DirIndex::unconditional
109
+ /// [`DirIndex::unconditional("index.html")`]: DirIndex::unconditional()
110
+ ///
111
+ /// # Example
112
+ ///
113
+ /// ```rust,no_run
114
+ /// # #[macro_use] extern crate rocket;
115
+ /// use rocket::fs::FileServer;
116
+ ///
117
+ /// #[launch]
118
+ /// fn rocket() -> _ {
119
+ /// rocket::build()
120
+ /// .mount("/", FileServer::new("/www/static"))
121
+ /// }
122
+ /// ```
101
123
pub fn new < P : AsRef < Path > > ( path : P ) -> Self {
102
- Self :: empty ( )
124
+ Self :: identity ( )
103
125
. filter ( |f, _| f. is_visible ( ) )
104
126
. rewrite ( Prefix :: checked ( path) )
105
127
. rewrite ( TrailingDirs )
106
128
. rewrite ( DirIndex :: unconditional ( "index.html" ) )
107
129
}
108
130
109
- /// Constructs a new `FileServer` that serves files from the file system
110
- /// `path` with a default rank. This variant does not add a default
111
- /// directory index option.
131
+ /// Exactly like [`FileServer::new()`] except it _does not_ serve directory
132
+ /// index files via [`DirIndex`]. It rewrites with the following:
112
133
///
113
- /// Adds a set of default rewrites:
114
- /// - `|f, _| f.is_visible()`: Hides all dotfiles.
115
- /// - [`Prefix::checked(path)`]: Applies the root path.
116
- /// - [`TrailingDirs`]: Normalizes directories to have a trailing slash.
117
- ///
118
- /// In most cases, [`Self::new`] is good enough. However, if you do not want
119
- /// to automatically respond to requests for directories with `index.html`,
120
- /// this method is provided.
134
+ /// - `|f, _| f.is_visible()`: Serve only visible files (hide dotfiles).
135
+ /// - [`Prefix::checked(path)`]: Prefix requests with `path`.
136
+ /// - [`TrailingDirs`]: Ensure directory have a trailing slash.
121
137
///
122
138
/// # Example
123
139
///
124
- /// Constructs a default file server to server files from `./static`, but
125
- /// uses `index.txt` if `index.html` doesn't exist.
140
+ /// Constructs a default file server to serve files from `./static` using
141
+ /// `index.txt` as the index file if `index.html` doesn't exist.
126
142
///
127
143
/// ```rust,no_run
128
144
/// # #[macro_use] extern crate rocket;
@@ -141,15 +157,43 @@ impl FileServer {
141
157
///
142
158
/// [`Prefix::checked(path)`]: crate::fs::rewrite::Prefix::checked
143
159
/// [`TrailingDirs`]: crate::fs::rewrite::TrailingDirs
144
- pub fn new_without_index < P : AsRef < Path > > ( path : P ) -> Self {
145
- Self :: empty ( )
160
+ pub fn without_index < P : AsRef < Path > > ( path : P ) -> Self {
161
+ Self :: identity ( )
146
162
. filter ( |f, _| f. is_visible ( ) )
147
163
. rewrite ( Prefix :: checked ( path) )
148
164
. rewrite ( TrailingDirs )
149
165
}
150
166
151
- /// Constructs a new `FileServer`, with default rank, and no rewrites.
152
- pub fn empty ( ) -> Self {
167
+ /// Constructs a new `FileServer` with no rewrites.
168
+ ///
169
+ /// Without any rewrites, a `FileServer` will try to serve the requested
170
+ /// file from the current working directory. In other words, it represents
171
+ /// the identity rewrite. For example, a request `GET /foo/bar` will be
172
+ /// passed through unmodified and thus `./foo/bar` will be served. This is
173
+ /// very unlikely to be what you want.
174
+ ///
175
+ /// Prefer to use [`FileServer::new()`] or [`FileServer::without_index()`]
176
+ /// whenever possible and otherwise use one or more of the rewrites in
177
+ /// [`rocket::fs::rewrite`] or your own custom rewrites.
178
+ ///
179
+ /// # Example
180
+ ///
181
+ /// ```rust,no_run
182
+ /// # #[macro_use] extern crate rocket;
183
+ /// use rocket::fs::{FileServer, rewrite};
184
+ ///
185
+ /// #[launch]
186
+ /// fn rocket() -> _ {
187
+ /// // A file server that serves exactly one file: /www/foo.html. The
188
+ /// // file is served irrespective of what's requested.
189
+ /// let server = FileServer::identity()
190
+ /// .rewrite(rewrite::File::checked("/www/foo.html"));
191
+ ///
192
+ /// rocket::build()
193
+ /// .mount("/", server)
194
+ /// }
195
+ /// ```
196
+ pub fn identity ( ) -> Self {
153
197
Self {
154
198
rewrites : vec ! [ ] ,
155
199
rank : Self :: DEFAULT_RANK
@@ -163,34 +207,34 @@ impl FileServer {
163
207
/// ```rust,no_run
164
208
/// # use rocket::fs::FileServer;
165
209
/// # fn make_server() -> FileServer {
166
- /// FileServer::empty ()
210
+ /// FileServer::identity ()
167
211
/// .rank(5)
168
212
/// # }
169
213
pub fn rank ( mut self , rank : isize ) -> Self {
170
214
self . rank = rank;
171
215
self
172
216
}
173
217
174
- /// Generic rewrite to transform one Rewrite to another .
218
+ /// Add `rewriter` to the rewrite pipeline .
175
219
///
176
220
/// # Example
177
221
///
178
- /// Redirects all requests that have been filtered to the root of the `FileServer `.
222
+ /// Redirect filtered requests (`None`) to `/ `.
179
223
///
180
224
/// ```rust,no_run
181
- /// # use rocket::fs::{FileServer, rewrite::Rewrite};
182
- /// # use rocket::{response::Redirect, uri, Build, Rocket, Request};
225
+ /// # #[macro_use] extern crate rocket;
226
+ /// use rocket::fs::{FileServer, rewrite::Rewrite};
227
+ /// use rocket::{request::Request, response::Redirect};
228
+ ///
183
229
/// fn redir_missing<'r>(p: Option<Rewrite<'r>>, _req: &Request<'_>) -> Option<Rewrite<'r>> {
184
- /// match p {
185
- /// None => Redirect::temporary(uri!("/")).into(),
186
- /// p => p,
187
- /// }
230
+ /// Some(p.unwrap_or_else(|| Redirect::temporary(uri!("/")).into()))
188
231
/// }
189
232
///
190
- /// # fn launch() -> Rocket<Build> {
191
- /// rocket::build()
192
- /// .mount("/", FileServer::new("static").rewrite(redir_missing))
193
- /// # }
233
+ /// #[launch]
234
+ /// fn rocket() -> _ {
235
+ /// rocket::build()
236
+ /// .mount("/", FileServer::new("static").rewrite(redir_missing))
237
+ /// }
194
238
/// ```
195
239
///
196
240
/// Note that `redir_missing` is not a closure in this example. Making it a closure
@@ -200,11 +244,13 @@ impl FileServer {
200
244
self
201
245
}
202
246
203
- /// Filter what files this `FileServer` will respond with
247
+ /// Adds a rewriter to the pipeline that returns `Some` only when the
248
+ /// function `f` returns `true`, filtering out all other files.
204
249
///
205
250
/// # Example
206
251
///
207
- /// Filter out all paths with a filename of `hidden`.
252
+ /// Allow all files that don't have a file name or have a file name other
253
+ /// than "hidden".
208
254
///
209
255
/// ```rust,no_run
210
256
/// # #[macro_use] extern crate rocket;
@@ -238,7 +284,9 @@ impl FileServer {
238
284
self . rewrite ( Filter ( f) )
239
285
}
240
286
241
- /// Change what files this `FileServer` will respond with
287
+ /// Adds a rewriter to the pipeline that maps the current `File` to another
288
+ /// `Rewrite` using `f`. If the current `Rewrite` is a `Redirect`, it is
289
+ /// passed through without calling `f`.
242
290
///
243
291
/// # Example
244
292
///
0 commit comments