aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven-Hendrik Haase <svenstaro@gmail.com>2021-10-25 11:07:11 +0000
committerGitHub <noreply@github.com>2021-10-25 11:07:11 +0000
commite1c5d470b5fdaff9acad1ad77ad49ffd9ca096da (patch)
treee9d3e9de0acd1495f07defe916ba3172a6902233
parentMerge pull request #621 from svenstaro/dependabot/cargo/reqwest-0.11.6 (diff)
parentUse Path instead of PathBuf for parameter (diff)
downloadminiserve-e1c5d470b5fdaff9acad1ad77ad49ffd9ca096da.tar.gz
miniserve-e1c5d470b5fdaff9acad1ad77ad49ffd9ca096da.zip
Merge pull request #515 from sinking-point/sinkingpoint/add-spa-index-option-474
Add --spa-index option
-rw-r--r--src/args.rs8
-rw-r--r--src/config.rs16
-rw-r--r--src/main.rs36
3 files changed, 49 insertions, 11 deletions
diff --git a/src/args.rs b/src/args.rs
index 449ea28..40d34e9 100644
--- a/src/args.rs
+++ b/src/args.rs
@@ -26,6 +26,14 @@ pub struct CliArgs {
#[clap(long, parse(from_os_str), name = "index_file", value_hint = ValueHint::FilePath)]
pub index: Option<PathBuf>,
+ /// 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<PathBuf>,
+
/// 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..e0d5ec5 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<std::path::PathBuf>,
+ /// 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<std::path::PathBuf>,
+
/// Enable QR code display
pub show_qrcode: bool,
@@ -169,6 +176,12 @@ 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 = match args.index {
+ Some(index) => Some(index),
+ None => args.spa_index.clone(),
+ };
+
Ok(MiniserveConfig {
verbose: args.verbose,
path: args.path.unwrap_or_else(|| PathBuf::from(".")),
@@ -183,7 +196,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 c43ac95..205fac5 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,9 +1,11 @@
use std::io;
use std::io::Write;
use std::net::{IpAddr, SocketAddr, TcpListener};
+use std::path::{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};
@@ -95,15 +97,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!(
@@ -268,6 +264,20 @@ async fn run(miniserve_config: MiniserveConfig) -> Result<(), ContextualError> {
.map_err(|e| ContextualError::IoError("".to_owned(), e))
}
+fn check_file_exists(canon_path: &Path, file_option: &Option<PathBuf>, option_name: &str) {
+ if let Some(file_path) = file_option {
+ 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.",
+ 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
@@ -300,6 +310,13 @@ 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) => 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 {
true => files.use_hidden_files(),
false => files,
@@ -309,7 +326,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() {