Skip to content

Commit

Permalink
Add prepend_path option
Browse files Browse the repository at this point in the history
  • Loading branch information
maxi0604 committed Apr 27, 2024
1 parent bb0d1b2 commit e5249a2
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 2 deletions.
20 changes: 20 additions & 0 deletions tower-http/src/services/fs/serve_dir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const DEFAULT_CAPACITY: usize = 65536;
#[derive(Clone, Debug)]
pub struct ServeDir<F = DefaultServeDirFallback> {
base: PathBuf,
prepend_path: String,
buf_chunk_size: usize,
precompressed_variants: Option<PrecompressedVariants>,
// This is used to specialise implementation for
Expand All @@ -72,6 +73,7 @@ impl ServeDir<DefaultServeDirFallback> {

Self {
base,
prepend_path: "".to_string(),
buf_chunk_size: DEFAULT_CAPACITY,
precompressed_variants: None,
variant: ServeVariant::Directory {
Expand All @@ -88,6 +90,7 @@ impl ServeDir<DefaultServeDirFallback> {
{
Self {
base: path.as_ref().to_owned(),
prepend_path: "".to_string(),
buf_chunk_size: DEFAULT_CAPACITY,
precompressed_variants: None,
variant: ServeVariant::SingleFile { mime },
Expand Down Expand Up @@ -115,6 +118,19 @@ impl<F> ServeDir<F> {
}
}

/// Sets a path to be prepended when performing a trailing slash redirect.
///
/// This is useful when you want to serve the files at another location than "/", for example
/// when you are using multiple services and want this instance to handle `/static/<path>`.
/// In that example, you should pass in "/static" so that a trailing slash redirect does not
/// redirect to `/<path>/` but instead to `/static/<path>/`
///
/// The default is the empty string.
pub fn prepend_path(mut self, path: String) -> Self {
self.prepend_path = path;
self
}

/// Set a specific read buffer chunk size.
///
/// The default capacity is 64kb.
Expand Down Expand Up @@ -211,6 +227,7 @@ impl<F> ServeDir<F> {
/// ```
pub fn fallback<F2>(self, new_fallback: F2) -> ServeDir<F2> {
ServeDir {
prepend_path: "".to_string(),
base: self.base,
buf_chunk_size: self.buf_chunk_size,
precompressed_variants: self.precompressed_variants,
Expand Down Expand Up @@ -358,6 +375,8 @@ impl<F> ServeDir<F> {
}
};

let prepend_path = self.prepend_path.clone();

let buf_chunk_size = self.buf_chunk_size;
let range_header = req
.headers()
Expand All @@ -375,6 +394,7 @@ impl<F> ServeDir<F> {

let open_file_future = Box::pin(open_file::open_file(
variant,
prepend_path,
path_to_file,
req,
negotiated_encodings,
Expand Down
9 changes: 7 additions & 2 deletions tower-http/src/services/fs/serve_dir/open_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ pub(super) enum FileRequestExtent {

pub(super) async fn open_file(
variant: ServeVariant,
prepend_path: String,
mut path_to_file: PathBuf,
req: Request<Empty<Bytes>>,
negotiated_encodings: Vec<(Encoding, QValue)>,
Expand All @@ -64,6 +65,7 @@ pub(super) async fn open_file(
// returned which corresponds to a Some(output). Otherwise the path might be
// modified and proceed to the open file/metadata future.
if let Some(output) = maybe_redirect_or_append_path(
&prepend_path,
&mut path_to_file,
req.uri(),
append_index_html_on_directories,
Expand Down Expand Up @@ -251,6 +253,7 @@ async fn file_metadata_with_fallback(
}

async fn maybe_redirect_or_append_path(
prepend_path: &str,
path_to_file: &mut PathBuf,
uri: &Uri,
append_index_html_on_directories: bool,
Expand All @@ -267,8 +270,10 @@ async fn maybe_redirect_or_append_path(
path_to_file.push("index.html");
None
} else {
let location =
HeaderValue::from_str(&append_slash_on_path(uri.clone()).to_string()).unwrap();
let location_string = format!("{prepend_path}{}", append_slash_on_path(uri.clone()));

let location = HeaderValue::from_str(&location_string).unwrap();

Some(OpenFileOutput::Redirect { location })
}
}
Expand Down
13 changes: 13 additions & 0 deletions tower-http/src/services/fs/serve_dir/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,19 @@ async fn redirect_to_trailing_slash_on_dir() {
assert_eq!(location, "/src/");
}

#[tokio::test]
async fn redirect_to_trailing_slash_with_prepend_path() {
let svc = ServeDir::new(".").prepend_path("/foo".to_string());

let req = Request::builder().uri("/src").body(Body::empty()).unwrap();
let res = svc.oneshot(req).await.unwrap();

assert_eq!(res.status(), StatusCode::TEMPORARY_REDIRECT);

let location = &res.headers()[http::header::LOCATION];
assert_eq!(location, "/foo/src/");
}

#[tokio::test]
async fn empty_directory_without_index() {
let svc = ServeDir::new(".").append_index_html_on_directories(false);
Expand Down

0 comments on commit e5249a2

Please sign in to comment.