Rocket

A web framework for Rust. https://rocket.rs (mirror)
git clone git://git.thc420.xyz/Rocket
Log | Files | Refs | README

commit dbcb0a75b9556763ac3ab708f40c8f8ed75f1a1e
parent 23f5ebcc4f89d67bbd4c24d2766746e1ff5ea2f6
Author: Sergio Benitez <sb@sergio.bz>
Date:   Thu, 16 May 2019 16:54:35 -0700

Allow setting a custom rank on 'StaticFiles'.

Resolves #965.

Diffstat:
Mcontrib/lib/src/serve.rs | 42++++++++++++++++++++++++++++++++----------
Mcontrib/lib/tests/static_files.rs | 22++++++++++++++++++++--
2 files changed, 52 insertions(+), 12 deletions(-)

diff --git a/contrib/lib/src/serve.rs b/contrib/lib/src/serve.rs @@ -29,14 +29,16 @@ use rocket::outcome::IntoOutcome; /// * [`Options::None`] - Return only present, visible files. /// * [`Options::DotFiles`] - In addition to visible files, return dotfiles. /// * [`Options::Index`] - Render `index.html` pages for directory requests. +/// * [`Options::Rank(n)`](Options::Rank) - Mount the static files route(s) +/// with rank `n`. /// -/// Two `Options` structures can be `or`d together to slect two or more options. +/// `Options` structures can be `or`d together to select two or more options. /// For instance, to request that both dot files and index pages be returned, /// use `Options::DotFiles | Options::Index`. #[derive(Debug, Clone, Copy)] -pub struct Options(u8); +pub struct Options(u32); -#[allow(non_upper_case_globals)] +#[allow(non_upper_case_globals, non_snake_case)] impl Options { /// `Options` representing the empty set. No dotfiles or index pages are /// rendered. This is different than the _default_, which enables `Index`. @@ -54,6 +56,17 @@ impl Options { /// directories beginning with `.`. This is _not_ enabled by default. pub const DotFiles: Options = Options(0b0010); + /// `Options` setting a rank of `rank` on the [`StaticFiles`] route(s). By + /// default, the rank is set to `10`. + pub const fn Rank(rank: i16) -> Options { + Options((rank as u32) << 16) + } + + /// Return the rank set in `self`. + fn rank(self) -> isize { + ((self.0 >> 16) as i16) as isize + } + /// Returns `true` if `self` is a superset of `other`. In other words, /// returns `true` if all of the options in `other` are also in `self`. /// @@ -80,6 +93,12 @@ impl Options { } } +impl Default for Options { + fn default() -> Self { + Options::Index | Options::Rank(10) + } +} + impl ::std::ops::BitOr for Options { type Output = Self; @@ -154,8 +173,9 @@ pub struct StaticFiles { impl StaticFiles { /// Constructs a new `StaticFiles` that serves files from the file system - /// `path`. By default, [`Options::Index`] is enabled. To serve static files - /// with other options, use [`StaticFiles::new()`]. + /// `path`. By default, [`Options::Index`] and + /// [`Options::Rank(10)`](Options::Rank) are set. To serve static files with + /// other options, use [`StaticFiles::new()`]. /// /// # Example /// @@ -176,7 +196,7 @@ impl StaticFiles { /// } /// ``` pub fn from<P: AsRef<Path>>(path: P) -> Self { - StaticFiles::new(path, Options::Index) + StaticFiles::new(path, Options::default()) } /// Constructs a new `StaticFiles` that serves files from the file system @@ -186,7 +206,8 @@ impl StaticFiles { /// /// Serve the static files in the `/www/public` local directory on path /// `/static` without serving index files or dot files. Additionally, serve - /// the same files on `/pub` while also seriving index files and dot files. + /// the same files on `/pub` with a route rank of -1 while also serving + /// index files and dot files. /// /// ```rust /// # extern crate rocket; @@ -195,7 +216,7 @@ impl StaticFiles { /// /// fn main() { /// # if false { - /// let options = Options::Index | Options::DotFiles; + /// let options = Options::Index | Options::DotFiles | Options::Rank(-1); /// rocket::ignite() /// .mount("/static", StaticFiles::from("/www/public")) /// .mount("/pub", StaticFiles::new("/www/public", options)) @@ -210,9 +231,10 @@ impl StaticFiles { impl Into<Vec<Route>> for StaticFiles { fn into(self) -> Vec<Route> { - let non_index = Route::ranked(10, Method::Get, "/<path..>", self.clone()); + let rank = self.options.rank(); + let non_index = Route::ranked(rank, Method::Get, "/<path..>", self.clone()); if self.options.contains(Options::Index) { - let index = Route::ranked(10, Method::Get, "/", self); + let index = Route::ranked(rank, Method::Get, "/", self); vec![index, non_index] } else { vec![non_index] diff --git a/contrib/lib/tests/static_files.rs b/contrib/lib/tests/static_files.rs @@ -3,12 +3,12 @@ extern crate rocket; extern crate rocket_contrib; -#[cfg(feature = "static")] +#[cfg(feature = "serve")] mod static_tests { use std::{io::Read, fs::File}; use std::path::{Path, PathBuf}; - use rocket::{self, Rocket}; + use rocket::{self, Rocket, Route}; use rocket_contrib::serve::{StaticFiles, Options}; use rocket::http::Status; use rocket::local::Client; @@ -105,4 +105,22 @@ mod static_tests { assert_all(&client, "both", HIDDEN_FILES, true); assert_all(&client, "both", INDEXED_DIRECTORIES, true); } + + #[test] + fn test_ranking() { + let root = static_root(); + for rank in (-128..127).chain([-32768, 32767].iter().cloned()) { + let opt_rank = Options::Rank(rank as i16); + let a = StaticFiles::new(&root, opt_rank); + let b = StaticFiles::new(&root, Options::None | opt_rank); + let c = StaticFiles::new(&root, Options::Index | opt_rank); + let d = StaticFiles::new(&root, Options::DotFiles | opt_rank); + let e = StaticFiles::new(&root, Options::Index | Options::DotFiles | opt_rank); + + for handler in vec![a, b, c, d, e] { + let routes: Vec<Route> = handler.into(); + assert!(routes.iter().all(|route| route.rank == rank), "{}", rank); + } + } + } }