aboutsummaryrefslogtreecommitdiffstats
path: root/src/main.rs
diff options
context:
space:
mode:
authorSven-Hendrik Haase <svenstaro@gmail.com>2021-08-27 02:11:10 +0000
committerSven-Hendrik Haase <svenstaro@gmail.com>2021-08-27 02:11:10 +0000
commitaad1c0ae685865e7e65ef194f49d6020c5e9e65f (patch)
treee49a7a0930778acd38e19f2b716d2254336be4ea /src/main.rs
parentGolf tests a bit more (diff)
downloadminiserve-aad1c0ae685865e7e65ef194f49d6020c5e9e65f.tar.gz
miniserve-aad1c0ae685865e7e65ef194f49d6020c5e9e65f.zip
Add TLS support via rustls (fixes #18)
Diffstat (limited to '')
-rw-r--r--src/main.rs187
1 files changed, 29 insertions, 158 deletions
diff --git a/src/main.rs b/src/main.rs
index b6dd856..1432a1a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,8 +1,8 @@
use std::io;
-use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
+use std::io::Write;
+use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::thread;
use std::time::Duration;
-use std::{io::Write, path::PathBuf};
use actix_web::web;
use actix_web::{
@@ -11,7 +11,7 @@ use actix_web::{
};
use actix_web::{middleware, App, HttpRequest, HttpResponse};
use actix_web_httpauth::middleware::HttpAuthentication;
-use http::header::HeaderMap;
+use anyhow::Result;
use log::{error, warn};
use structopt::clap::crate_version;
use structopt::StructOpt;
@@ -20,174 +20,31 @@ use yansi::{Color, Paint};
mod archive;
mod args;
mod auth;
+mod config;
mod errors;
mod file_upload;
mod listing;
mod pipe;
mod renderer;
+use crate::config::MiniserveConfig;
use crate::errors::ContextualError;
-/// Possible characters for random routes
-const ROUTE_ALPHABET: [char; 16] = [
- '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e', 'f',
-];
-
-#[derive(Clone)]
-/// Configuration of the Miniserve application
-pub struct MiniserveConfig {
- /// Enable verbose mode
- pub verbose: bool,
-
- /// Path to be served by miniserve
- pub path: std::path::PathBuf,
-
- /// Port on which miniserve will be listening
- pub port: u16,
-
- /// IP address(es) on which miniserve will be available
- pub interfaces: Vec<IpAddr>,
-
- /// Enable HTTP basic authentication
- pub auth: Vec<auth::RequiredAuth>,
-
- /// If false, miniserve will serve the current working directory
- pub path_explicitly_chosen: bool,
-
- /// Enable symlink resolution
- pub no_symlinks: bool,
-
- /// Show hidden files
- pub show_hidden: bool,
-
- /// Enable random route generation
- pub random_route: Option<String>,
-
- /// Randomly generated favicon route
- pub favicon_route: String,
-
- /// Randomly generated css route
- pub css_route: String,
-
- /// Default color scheme
- pub default_color_scheme: String,
-
- /// Default dark mode color scheme
- pub default_color_scheme_dark: String,
-
- /// The name of a directory index file to serve, like "index.html"
- ///
- /// Normally, when miniserve serves a directory, it creates a listing for that directory.
- /// However, if a directory contains this file, miniserve will serve that file instead.
- pub index: Option<std::path::PathBuf>,
-
- /// Enable QR code display
- pub show_qrcode: bool,
-
- /// Enable file upload
- pub file_upload: bool,
-
- /// Enable upload to override existing files
- pub overwrite_files: bool,
-
- /// If false, creation of uncompressed tar archives is disabled
- pub tar_enabled: bool,
-
- /// If false, creation of gz-compressed tar archives is disabled
- pub tar_gz_enabled: bool,
-
- /// If false, creation of zip archives is disabled
- pub zip_enabled: bool,
-
- /// If enabled, directories are listed first
- pub dirs_first: bool,
-
- /// Shown instead of host in page title and heading
- pub title: Option<String>,
-
- /// If specified, header will be added
- pub header: Vec<HeaderMap>,
-
- /// If enabled, version footer is hidden
- pub hide_version_footer: bool,
-}
-
-impl MiniserveConfig {
- /// Parses the command line arguments
- fn from_args(args: args::CliArgs) -> Self {
- let interfaces = if !args.interfaces.is_empty() {
- args.interfaces
- } else {
- vec![
- IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)),
- IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
- ]
- };
-
- let random_route = if args.random_route {
- Some(nanoid::nanoid!(6, &ROUTE_ALPHABET))
- } else {
- None
- };
-
- // Generate some random routes for the favicon and css so that they are very unlikely to conflict with
- // real files.
- let favicon_route = nanoid::nanoid!(10, &ROUTE_ALPHABET);
- let css_route = nanoid::nanoid!(10, &ROUTE_ALPHABET);
-
- let default_color_scheme = args.color_scheme;
- let default_color_scheme_dark = args.color_scheme_dark;
-
- let path_explicitly_chosen = args.path.is_some() || args.index.is_some();
-
- let port = match args.port {
- 0 => port_check::free_local_port().expect("no free ports available"),
- _ => args.port,
- };
-
- crate::MiniserveConfig {
- verbose: args.verbose,
- path: args.path.unwrap_or_else(|| PathBuf::from(".")),
- port,
- interfaces,
- auth: args.auth,
- path_explicitly_chosen,
- no_symlinks: args.no_symlinks,
- show_hidden: args.hidden,
- random_route,
- favicon_route,
- css_route,
- default_color_scheme,
- default_color_scheme_dark,
- index: args.index,
- overwrite_files: args.overwrite_files,
- show_qrcode: args.qrcode,
- file_upload: args.file_upload,
- tar_enabled: args.enable_tar,
- tar_gz_enabled: args.enable_tar_gz,
- zip_enabled: args.enable_zip,
- dirs_first: args.dirs_first,
- title: args.title,
- header: args.header,
- hide_version_footer: args.hide_version_footer,
- }
- }
-}
-
-fn main() {
+fn main() -> Result<()> {
let args = args::CliArgs::from_args();
if let Some(shell) = args.print_completions {
args::CliArgs::clap().gen_completions_to("miniserve", shell, &mut std::io::stdout());
- return;
+ return Ok(());
}
- let miniserve_config = MiniserveConfig::from_args(args);
+ let miniserve_config = MiniserveConfig::try_from_args(args)?;
match run(miniserve_config) {
Ok(()) => (),
Err(e) => errors::log_error_chain(e.to_string()),
}
+ Ok(())
}
#[actix_web::main(miniserve)]
@@ -300,11 +157,17 @@ async fn run(miniserve_config: MiniserveConfig) -> Result<(), ContextualError> {
if !addresses.is_empty() {
addresses.push_str(", ");
}
+ let protocol = if miniserve_config.tls_rustls_config.is_some() {
+ "https"
+ } else {
+ "http"
+ };
addresses.push_str(&format!(
"{}",
Color::Green
.paint(format!(
- "http://{interface}:{port}",
+ "{protocol}://{interface}:{port}",
+ protocol = protocol,
interface = &interface,
port = miniserve_config.port
))
@@ -362,11 +225,19 @@ async fn run(miniserve_config: MiniserveConfig) -> Result<(), ContextualError> {
.route(&format!("/{}", inside_config.css_route), web::get().to(css))
.configure(|c| configure_app(c, &inside_config))
.default_service(web::get().to(error_404))
- })
- .bind(socket_addresses.as_slice())
- .map_err(|e| ContextualError::IoError("Failed to bind server".to_string(), e))?
- .shutdown_timeout(0)
- .run();
+ });
+
+ let srv = if let Some(tls_config) = miniserve_config.tls_rustls_config {
+ srv.bind_rustls(socket_addresses.as_slice(), tls_config)
+ .map_err(|e| ContextualError::IoError("Failed to bind server".to_string(), e))?
+ .shutdown_timeout(0)
+ .run()
+ } else {
+ srv.bind(socket_addresses.as_slice())
+ .map_err(|e| ContextualError::IoError("Failed to bind server".to_string(), e))?
+ .shutdown_timeout(0)
+ .run()
+ };
println!(
"Serving path {path} at {addresses}",