From 7ed7b0398ee0c3faf1ce553e8345b92d1fdedebc Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Sun, 5 Mar 2023 12:05:58 -0800 Subject: [PATCH] feat: add support for .html prefixing when request path doesn't exist (#180) * Added support for path serving with html wrapping * Elide explicit 'a lifetime --------- Co-authored-by: Jose Quintana --- src/static_files.rs | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/static_files.rs b/src/static_files.rs index d8fbed4..7c915fb 100644 --- a/src/static_files.rs +++ b/src/static_files.rs @@ -138,11 +138,32 @@ pub async fn handle<'a>(opts: &HandleOpts<'a>) -> Result<(Response, bool), Ok((resp, is_precompressed)) } +/// Returns the result of trying to append `.html` to the file path. +/// * If the prefixed html path exists, it mutates the path to the prefixed one and returns the Metadata +/// * If the prefixed html path doesn't exist, it reverts the path to it's original value +fn prefix_file_html_metadata(file_path: &mut PathBuf) -> (&mut PathBuf, Option) { + tracing::debug!("file: appending .html to the path"); + if let Some(filename) = file_path.file_name() { + let owned_filename = filename.to_os_string(); + let mut owned_filename_with_html = owned_filename.clone(); + owned_filename_with_html.push(".html"); + file_path.set_file_name(owned_filename_with_html); + if let Ok(meta_res) = file_metadata(file_path.as_ref()) { + let (meta, _) = meta_res; + return (file_path, Some(meta)); + } else { + // We roll-back to the previous filename + file_path.set_file_name(owned_filename); + } + } + (file_path, None) +} + /// Returns the final composed metadata information (tuple) containing /// the Arc `PathBuf` reference wrapper for the current `file_path` with its file metadata /// as well as its optional pre-compressed variant. async fn composed_file_metadata<'a>( - file_path: &'a mut PathBuf, + mut file_path: &'a mut PathBuf, headers: &'a HeaderMap, compression_static: bool, ) -> Result<(&'a PathBuf, Metadata, bool, Option<(PathBuf, &'a str)>), StatusCode> { @@ -170,12 +191,33 @@ async fn composed_file_metadata<'a>( // Also noting that it's still a directory request if let Ok(meta_res) = file_metadata(file_path.as_ref()) { (meta, _) = meta_res + } else { + // We remove the appended index.html + file_path.pop(); + let new_meta: Option; + (file_path, new_meta) = prefix_file_html_metadata(file_path); + if let Some(new_meta) = new_meta { + meta = new_meta; + } else { + // We append the index.html to preserve previous behavior + file_path.push("index.html"); + } } } Ok((file_path, meta, is_dir, None)) } Err(err) => { + if err == StatusCode::NOT_FOUND { + // If the file path doesn't exist, we try to find the path suffixed with `.html`. + // For example: `/posts/article` will fallback to `/posts/article.html` + let new_meta: Option; + (file_path, new_meta) = prefix_file_html_metadata(file_path); + if let Some(new_meta) = new_meta { + return Ok((file_path, new_meta, false, None)); + } + } + // Second pre-compressed variant check for the given file path if compression_static && !tried_precompressed { if let Some((path, meta, ext)) = -- libgit2 1.7.2