From 76d75a37f17acd23ad373b6804804acf8c41c616 Mon Sep 17 00:00:00 2001 From: imgurbot12 Date: Fri, 25 Jul 2025 18:54:32 -0700 Subject: [PATCH] feat(actix-files): support multiple fallback directory indexes --- actix-files/CHANGES.md | 1 + actix-files/src/files.rs | 16 ++++++++++------ actix-files/src/service.rs | 25 ++++++++++++++----------- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/actix-files/CHANGES.md b/actix-files/CHANGES.md index afb2d5d20..2d53687e5 100644 --- a/actix-files/CHANGES.md +++ b/actix-files/CHANGES.md @@ -2,6 +2,7 @@ ## Unreleased +- Option to supply multiple index fallbacks now supported. - Minimum supported Rust version (MSRV) is now 1.75. ## 0.6.6 diff --git a/actix-files/src/files.rs b/actix-files/src/files.rs index cfd3b9c22..8ea6aaace 100644 --- a/actix-files/src/files.rs +++ b/actix-files/src/files.rs @@ -38,7 +38,7 @@ use crate::{ pub struct Files { mount_path: String, directory: PathBuf, - index: Option, + indexes: Vec, show_index: bool, redirect_to_slash: bool, default: Rc>>>, @@ -61,7 +61,7 @@ impl Clone for Files { fn clone(&self) -> Self { Self { directory: self.directory.clone(), - index: self.index.clone(), + indexes: self.indexes.clone(), show_index: self.show_index, redirect_to_slash: self.redirect_to_slash, default: self.default.clone(), @@ -108,7 +108,7 @@ impl Files { Files { mount_path: mount_path.trim_end_matches('/').to_owned(), directory: dir, - index: None, + indexes: Vec::new(), show_index: false, redirect_to_slash: false, default: Rc::new(RefCell::new(None)), @@ -192,15 +192,19 @@ impl Files { self } - /// Set index file + /// Set an index file /// /// Shows specific index file for directories instead of /// showing files listing. /// + /// This function can be called multiple times to configure + /// a list of index fallbacks with their priority set to the + /// order of their addition. + /// /// If the index file is not found, files listing is shown as a fallback if /// [`Files::show_files_listing()`] is set. pub fn index_file>(mut self, index: T) -> Self { - self.index = Some(index.into()); + self.indexes.push(index.into()); self } @@ -357,7 +361,7 @@ impl ServiceFactory for Files { fn new_service(&self, _: ()) -> Self::Future { let mut inner = FilesServiceInner { directory: self.directory.clone(), - index: self.index.clone(), + indexes: self.indexes.clone(), show_index: self.show_index, redirect_to_slash: self.redirect_to_slash, default: None, diff --git a/actix-files/src/service.rs b/actix-files/src/service.rs index 393ad9244..c7d89f1c5 100644 --- a/actix-files/src/service.rs +++ b/actix-files/src/service.rs @@ -29,7 +29,7 @@ impl Deref for FilesService { pub struct FilesServiceInner { pub(crate) directory: PathBuf, - pub(crate) index: Option, + pub(crate) indexes: Vec, pub(crate) show_index: bool, pub(crate) redirect_to_slash: bool, pub(crate) default: Option, @@ -141,7 +141,7 @@ impl Service for FilesService { if path.is_dir() { if this.redirect_to_slash && !req.path().ends_with('/') - && (this.index.is_some() || this.show_index) + && (!this.indexes.is_empty() || this.show_index) { let redirect_to = format!("{}/", req.path()); @@ -152,15 +152,18 @@ impl Service for FilesService { )); } - match this.index { - Some(ref index) => { - let named_path = path.join(index); - match NamedFile::open_async(named_path).await { - Ok(named_file) => Ok(this.serve_named_file(req, named_file)), - Err(_) if this.show_index => Ok(this.show_index(req, path)), - Err(err) => this.handle_err(err, req).await, - } - } + let index = this + .indexes + .iter() + .map(|i| path.join(i)) + .find(|p| p.exists()); + + match index { + Some(ref named_path) => match NamedFile::open_async(named_path).await { + Ok(named_file) => Ok(this.serve_named_file(req, named_file)), + Err(_) if this.show_index => Ok(this.show_index(req, path)), + Err(err) => this.handle_err(err, req).await, + }, None if this.show_index => Ok(this.show_index(req, path)), None => Ok(ServiceResponse::from_err( FilesError::IsDirectory,