]> OzVa Git service - ozva-cloud/commitdiff
feat: add option --render-try-index (#47)
authorsigoden <sigoden@gmail.com>
Fri, 17 Jun 2022 00:41:01 +0000 (08:41 +0800)
committerGitHub <noreply@github.com>
Fri, 17 Jun 2022 00:41:01 +0000 (08:41 +0800)
close #46

README.md
src/args.rs
src/server.rs
tests/fixtures.rs
tests/render.rs

index 481d853be30b121c86718595ff8973fcbb134215..23362dc6502c2c5431dc83da56d9b216b9107eb6 100644 (file)
--- a/README.md
+++ b/README.md
@@ -49,21 +49,22 @@ ARGS:
     <path>    Path to a root directory for serving files [default: .]
 
 OPTIONS:
+    -b, --bind <addr>...        Specify bind address
+    -p, --port <port>           Specify port to listen on [default: 5000]
+        --path-prefix <path>    Specify an url path prefix
     -a, --auth <user:pass>      Use HTTP authentication
         --no-auth-access        Not required auth when access static files
     -A, --allow-all             Allow all operations
+        --allow-upload          Allow upload files/folders
         --allow-delete          Allow delete files/folders
         --allow-symlink         Allow symlink to files/folders outside root directory
-        --allow-upload          Allow upload files/folders
-    -b, --bind <address>...     Specify bind address
-        --cors                  Enable CORS, sets `Access-Control-Allow-Origin: *`
-    -h, --help                  Print help information
-    -p, --port <port>           Specify port to listen on [default: 5000]
-        --path-prefix <path>    Specify an url path prefix
         --render-index          Render index.html when requesting a directory
+        --render-try-index      Try rendering index.html when requesting a directory
         --render-spa            Render for single-page application
+        --cors                  Enable CORS, sets `Access-Control-Allow-Origin: *`
         --tls-cert <path>       Path to an SSL/TLS certificate to serve with HTTPS
         --tls-key <path>        Path to the SSL/TLS certificate's private key
+    -h, --help                  Print help information
     -V, --version               Print version information
 ```
 
index 17059a857d1337ee3270a20058dc7447bb1a13a3..270154047e430d4f864b0c632ceb5ced5408428a 100644 (file)
@@ -1,4 +1,4 @@
-use clap::{Arg, ArgMatches, Command};
+use clap::{AppSettings, Arg, ArgMatches, Command};
 use rustls::{Certificate, PrivateKey};
 use std::env;
 use std::net::IpAddr;
@@ -17,14 +17,15 @@ fn app() -> Command<'static> {
             " - ",
             env!("CARGO_PKG_REPOSITORY")
         ))
+        .global_setting(AppSettings::DeriveDisplayOrder)
         .arg(
-            Arg::new("address")
+            Arg::new("bind")
                 .short('b')
                 .long("bind")
                 .help("Specify bind address")
                 .multiple_values(true)
                 .multiple_occurrences(true)
-                .value_name("address"),
+                .value_name("addr"),
         )
         .arg(
             Arg::new("port")
@@ -46,6 +47,18 @@ fn app() -> Command<'static> {
                 .value_name("path")
                 .help("Specify an url path prefix"),
         )
+        .arg(
+            Arg::new("auth")
+                .short('a')
+                .long("auth")
+                .help("Use HTTP authentication")
+                .value_name("user:pass"),
+        )
+        .arg(
+            Arg::new("no-auth-access")
+                .long("no-auth-access")
+                .help("Not required auth when access static files"),
+        )
         .arg(
             Arg::new("allow-all")
                 .short('A')
@@ -72,25 +85,16 @@ fn app() -> Command<'static> {
                 .long("render-index")
                 .help("Render index.html when requesting a directory"),
         )
+        .arg(
+            Arg::new("render-try-index")
+                .long("render-try-index")
+                .help("Try rendering index.html when requesting a directory"),
+        )
         .arg(
             Arg::new("render-spa")
                 .long("render-spa")
                 .help("Render for single-page application"),
         )
-        .arg(
-            Arg::new("auth")
-                .short('a')
-                .display_order(1)
-                .long("auth")
-                .help("Use HTTP authentication")
-                .value_name("user:pass"),
-        )
-        .arg(
-            Arg::new("no-auth-access")
-                .display_order(1)
-                .long("no-auth-access")
-                .help("Not required auth when access static files"),
-        )
         .arg(
             Arg::new("cors")
                 .long("cors")
@@ -128,6 +132,7 @@ pub struct Args {
     pub allow_symlink: bool,
     pub render_index: bool,
     pub render_spa: bool,
+    pub render_index_fallback: bool,
     pub cors: bool,
     pub tls: Option<(Vec<Certificate>, PrivateKey)>,
 }
@@ -140,7 +145,7 @@ impl Args {
     pub fn parse(matches: ArgMatches) -> BoxResult<Args> {
         let port = matches.value_of_t::<u16>("port")?;
         let addrs = matches
-            .values_of("address")
+            .values_of("bind")
             .map(|v| v.collect())
             .unwrap_or_else(|| vec!["0.0.0.0", "::"]);
         let addrs: Vec<IpAddr> = Args::parse_addrs(&addrs)?;
@@ -163,7 +168,9 @@ impl Args {
         let allow_upload = matches.is_present("allow-all") || matches.is_present("allow-upload");
         let allow_delete = matches.is_present("allow-all") || matches.is_present("allow-delete");
         let allow_symlink = matches.is_present("allow-all") || matches.is_present("allow-symlink");
-        let render_index = matches.is_present("render-index");
+        let render_index =
+            matches.is_present("render-index") || matches.is_present("render-try-index");
+        let render_index_fallback = matches.is_present("render-try-index");
         let render_spa = matches.is_present("render-spa");
         let tls = match (matches.value_of("tls-cert"), matches.value_of("tls-key")) {
             (Some(certs_file), Some(key_file)) => {
@@ -187,6 +194,7 @@ impl Args {
             allow_upload,
             allow_symlink,
             render_index,
+            render_index_fallback,
             render_spa,
             tls,
         })
index 23b899b770de5a8c3cbc08fdf87103aa54ded230..18503a8398e804d463b8456c17cdc0f72dae7f11 100644 (file)
@@ -366,15 +366,17 @@ impl Server {
         head_only: bool,
         res: &mut Response,
     ) -> BoxResult<()> {
-        let path = path.join(INDEX_NAME);
-        if fs::metadata(&path)
+        let index_path = path.join(INDEX_NAME);
+        if fs::metadata(&index_path)
             .await
             .ok()
             .map(|v| v.is_file())
             .unwrap_or_default()
         {
-            self.handle_send_file(&path, headers, head_only, res)
+            self.handle_send_file(&index_path, headers, head_only, res)
                 .await?;
+        } else if self.args.render_index_fallback {
+            self.handle_ls_dir(path, true, head_only, res).await?;
         } else {
             status_not_found(res)
         }
index 2641ddf369dbd128161299609ff7f98fa29a774e..d581be318162f15d2f8fb5c73e0cf21ae50d633e 100644 (file)
@@ -29,7 +29,11 @@ pub static FILES: &[&str] = &[
     "foo\\bar.test",
 ];
 
-/// Directory names for testing purpose
+/// Directory names for testing diretory don't exist
+#[allow(dead_code)]
+pub static DIR_NO_FOUND: &str = "dir-no-found/";
+
+/// Directory names for testing diretory don't have index.html
 #[allow(dead_code)]
 pub static DIR_NO_INDEX: &str = "dir-no-index/";
 
@@ -55,7 +59,7 @@ pub fn tmpdir() -> TempDir {
     }
     for directory in DIRECTORIES {
         for file in FILES {
-            if *directory == DIR_NO_INDEX {
+            if *directory == DIR_NO_INDEX && *file == "index.html" {
                 continue;
             }
             tmpdir
index e666265073b8684b3c91654f9077e16df98a55b1..70f041bf9849f19e40aabf07c765cd7aafae8718 100644 (file)
@@ -1,6 +1,7 @@
 mod fixtures;
+mod utils;
 
-use fixtures::{server, Error, TestServer, DIR_NO_INDEX};
+use fixtures::{server, Error, TestServer, DIR_NO_FOUND, DIR_NO_INDEX};
 use rstest::rstest;
 
 #[rstest]
@@ -12,12 +13,32 @@ fn render_index(#[with(&["--render-index"])] server: TestServer) -> Result<(), E
 }
 
 #[rstest]
-fn render_index_404(#[with(&["--render-index"])] server: TestServer) -> Result<(), Error> {
-    let resp = reqwest::blocking::get(format!("{}/{}", server.url(), DIR_NO_INDEX))?;
+fn render_index2(#[with(&["--render-index"])] server: TestServer) -> Result<(), Error> {
+    let resp = reqwest::blocking::get(format!("{}{}", server.url(), DIR_NO_INDEX))?;
     assert_eq!(resp.status(), 404);
     Ok(())
 }
 
+#[rstest]
+fn render_try_index(#[with(&["--render-try-index"])] server: TestServer) -> Result<(), Error> {
+    let resp = reqwest::blocking::get(server.url())?;
+    let text = resp.text()?;
+    assert_eq!(text, "This is index.html");
+    Ok(())
+}
+
+#[rstest]
+fn render_try_index2(#[with(&["--render-try-index"])] server: TestServer) -> Result<(), Error> {
+    let resp = reqwest::blocking::get(format!("{}{}", server.url(), DIR_NO_INDEX))?;
+    let files: Vec<&str> = self::fixtures::FILES
+        .iter()
+        .filter(|v| **v != "index.html")
+        .cloned()
+        .collect();
+    assert_index_resp!(resp, files);
+    Ok(())
+}
+
 #[rstest]
 fn render_spa(#[with(&["--render-spa"])] server: TestServer) -> Result<(), Error> {
     let resp = reqwest::blocking::get(server.url())?;
@@ -27,8 +48,8 @@ fn render_spa(#[with(&["--render-spa"])] server: TestServer) -> Result<(), Error
 }
 
 #[rstest]
-fn render_spa_no_404(#[with(&["--render-spa"])] server: TestServer) -> Result<(), Error> {
-    let resp = reqwest::blocking::get(format!("{}/{}", server.url(), DIR_NO_INDEX))?;
+fn render_spa2(#[with(&["--render-spa"])] server: TestServer) -> Result<(), Error> {
+    let resp = reqwest::blocking::get(format!("{}{}", server.url(), DIR_NO_FOUND))?;
     let text = resp.text()?;
     assert_eq!(text, "This is index.html");
     Ok(())