From 6dfe4d1c9b08b108ad71945a60ba24256b61ba26 Mon Sep 17 00:00:00 2001 From: Billy Bradley Date: Sat, 1 May 2021 21:36:55 +0000 Subject: Add --spa-index option --- src/args.rs | 8 ++++++++ src/config.rs | 13 ++++++++++++- src/main.rs | 47 +++++++++++++++++++++++++++++++++++++---------- 3 files changed, 57 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/args.rs b/src/args.rs index c610bbe..5595bea 100644 --- a/src/args.rs +++ b/src/args.rs @@ -32,6 +32,14 @@ pub struct CliArgs { #[clap(long, parse(from_os_str), name = "index_file", value_hint = ValueHint::FilePath)] pub index: Option, + /// The index file of a single page application + /// + /// If this option is set, miniserve will serve the specified file instead of a 404 page when + /// a non-existent path is requested. This is intended for single-page applications where + /// routing takes place on the client side. + #[clap(long, parse(from_os_str), name = "spa_index_file", value_hint = ValueHint::FilePath)] + pub spa_index: Option, + /// Port to use #[clap(short = 'p', long = "port", default_value = "8080")] pub port: u16, diff --git a/src/config.rs b/src/config.rs index ce4e5d7..0af19a6 100644 --- a/src/config.rs +++ b/src/config.rs @@ -68,6 +68,13 @@ pub struct MiniserveConfig { /// However, if a directory contains this file, miniserve will serve that file instead. pub index: Option, + /// The index file of a single page application + /// + /// If this option is set, miniserve will serve the specified file instead of a 404 page when + /// a non-existent path is requested. This is intended for single-page applications where + /// routing takes place on the client side. + pub spa_index: Option, + /// Enable QR code display pub show_qrcode: bool, @@ -169,6 +176,9 @@ impl MiniserveConfig { #[cfg(not(feature = "tls"))] let tls_rustls_server_config = None; + // If spa_index is set but index is unset, copy the former into the latter + let index = args.index.or(args.spa_index.clone()); + Ok(MiniserveConfig { verbose: args.verbose, path: args.path.unwrap_or_else(|| PathBuf::from(".")), @@ -183,7 +193,8 @@ impl MiniserveConfig { css_route, default_color_scheme, default_color_scheme_dark, - index: args.index, + index, + spa_index: args.spa_index, overwrite_files: args.overwrite_files, show_qrcode: args.qrcode, file_upload: args.file_upload, diff --git a/src/main.rs b/src/main.rs index 133f320..f3dc18a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ use std::io; use std::io::Write; use std::net::{IpAddr, SocketAddr, TcpListener}; +use std::path::PathBuf; use std::thread; use std::time::Duration; @@ -105,15 +106,9 @@ async fn run(miniserve_config: MiniserveConfig) -> Result<(), ContextualError> { ContextualError::IoError("Failed to resolve path to be served".to_string(), e) })?; - if let Some(index_path) = &miniserve_config.index { - let has_index: std::path::PathBuf = [&canon_path, index_path].iter().collect(); - if !has_index.exists() { - error!( - "The file '{}' provided for option --index could not be found.", - index_path.to_string_lossy() - ); - } - } + check_file_exists(&canon_path, &miniserve_config.index, "index"); + check_file_exists(&canon_path, &miniserve_config.spa_index, "spa-index"); + let path_string = canon_path.to_string_lossy(); println!( @@ -279,6 +274,19 @@ async fn run(miniserve_config: MiniserveConfig) -> Result<(), ContextualError> { .map_err(|e| ContextualError::IoError("".to_owned(), e)) } +fn check_file_exists(canon_path: &PathBuf, file_option: &Option, option_name: &str) { + if let Some(file_path) = file_option { + let has_file: std::path::PathBuf = [&canon_path, file_path].iter().collect(); + if !has_file.exists() { + error!( + "The file '{}' provided for option --{} could not be found.", + file_path.to_string_lossy(), + option_name, + ); + } + } +} + /// Allows us to set low-level socket options /// /// This mainly used to set `set_only_v6` socket option @@ -311,6 +319,26 @@ fn configure_app(app: &mut web::ServiceConfig, conf: &MiniserveConfig) { Some(index_file) => files.index_file(index_file.to_string_lossy()), None => files, }; + let files = match &conf.spa_index { + Some(spa_index_file) => { + let spa_index_full = &conf.path.join(spa_index_file); + let spa_index_string: String = spa_index_full.to_string_lossy().into(); + + files.default_handler(move |req: actix_web::dev::ServiceRequest| { + let (request, _payload) = req.into_parts(); + let spa_index_string = spa_index_string.clone(); + + async move { + let response = actix_files::NamedFile::open( + &spa_index_string + )? + .into_response(&request); + Ok(actix_web::dev::ServiceResponse::new(request, response)) + } + }) + }, + None => files.default_handler(web::to(error_404)), + }; let files = match conf.show_hidden { true => files.use_hidden_files(), false => files, @@ -320,7 +348,6 @@ fn configure_app(app: &mut web::ServiceConfig, conf: &MiniserveConfig) { .files_listing_renderer(listing::directory_listing) .prefer_utf8(true) .redirect_to_slash_directory() - .default_handler(web::to(error_404)) }; if !conf.path.is_file() { -- cgit v1.2.3 From 9772505ccb2499a8f533d649b8334fd9bf765631 Mon Sep 17 00:00:00 2001 From: Billy Bradley Date: Sun, 10 Oct 2021 14:13:43 +0100 Subject: Use NamedFile as default handler to simplify --spa-index option implementation --- src/main.rs | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index f3dc18a..7420888 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,7 @@ use std::path::PathBuf; use std::thread; use std::time::Duration; +use actix_files::NamedFile; use actix_web::web; use actix_web::{http::header::ContentType, Responder}; use actix_web::{middleware, App, HttpRequest, HttpResponse}; @@ -320,23 +321,10 @@ fn configure_app(app: &mut web::ServiceConfig, conf: &MiniserveConfig) { None => files, }; let files = match &conf.spa_index { - Some(spa_index_file) => { - let spa_index_full = &conf.path.join(spa_index_file); - let spa_index_string: String = spa_index_full.to_string_lossy().into(); - - files.default_handler(move |req: actix_web::dev::ServiceRequest| { - let (request, _payload) = req.into_parts(); - let spa_index_string = spa_index_string.clone(); - - async move { - let response = actix_files::NamedFile::open( - &spa_index_string - )? - .into_response(&request); - Ok(actix_web::dev::ServiceResponse::new(request, response)) - } - }) - }, + Some(spa_index_file) => files.default_handler( + NamedFile::open(&conf.path.join(spa_index_file)) + .expect("Cant open SPA index file.") + ), None => files.default_handler(web::to(error_404)), }; let files = match conf.show_hidden { -- cgit v1.2.3 From 6090cd5e297c5b54ee385b0039794607e809e029 Mon Sep 17 00:00:00 2001 From: Billy Bradley Date: Thu, 14 Oct 2021 12:46:51 +0100 Subject: Fix formatting --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 7420888..32fcdec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -323,7 +323,7 @@ fn configure_app(app: &mut web::ServiceConfig, conf: &MiniserveConfig) { let files = match &conf.spa_index { Some(spa_index_file) => files.default_handler( NamedFile::open(&conf.path.join(spa_index_file)) - .expect("Cant open SPA index file.") + .expect("Cant open SPA index file."), ), None => files.default_handler(web::to(error_404)), }; -- cgit v1.2.3 From 784e1e073b65e195844b7bb14e34a5cf68c2f5a4 Mon Sep 17 00:00:00 2001 From: Billy Bradley Date: Fri, 15 Oct 2021 16:37:13 +0100 Subject: Only clone spa_index when necessary --- src/config.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/config.rs b/src/config.rs index 0af19a6..e0d5ec5 100644 --- a/src/config.rs +++ b/src/config.rs @@ -177,7 +177,10 @@ impl MiniserveConfig { let tls_rustls_server_config = None; // If spa_index is set but index is unset, copy the former into the latter - let index = args.index.or(args.spa_index.clone()); + let index = match args.index { + Some(index) => Some(index), + None => args.spa_index.clone(), + }; Ok(MiniserveConfig { verbose: args.verbose, -- cgit v1.2.3 From 26e89415f34cc17d8621b21e5802738eefcb3535 Mon Sep 17 00:00:00 2001 From: Billy Bradley Date: Mon, 18 Oct 2021 15:00:15 +0100 Subject: Use Path instead of PathBuf for parameter --- src/main.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 32fcdec..eb159a2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use std::io; use std::io::Write; use std::net::{IpAddr, SocketAddr, TcpListener}; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::thread; use std::time::Duration; @@ -275,9 +275,10 @@ async fn run(miniserve_config: MiniserveConfig) -> Result<(), ContextualError> { .map_err(|e| ContextualError::IoError("".to_owned(), e)) } -fn check_file_exists(canon_path: &PathBuf, file_option: &Option, option_name: &str) { +fn check_file_exists(canon_path: &Path, file_option: &Option, option_name: &str) { if let Some(file_path) = file_option { - let has_file: std::path::PathBuf = [&canon_path, file_path].iter().collect(); + let file_path: &Path = file_path.as_ref(); + let has_file: std::path::PathBuf = [canon_path, file_path].iter().collect(); if !has_file.exists() { error!( "The file '{}' provided for option --{} could not be found.", -- cgit v1.2.3