From a025ca2ec403297883d9758b6e10bc7c6f3a7df1 Mon Sep 17 00:00:00 2001 From: rattatwinko Date: Wed, 18 Mar 2026 09:52:13 +0100 Subject: [PATCH] Implement clap for command line argument parsing, and cleanup of path traversal logic, now readable --- Cargo.toml | 1 + src/main.rs | 46 +++++++++++++++++++++++++++++++++------------- src/router.rs | 15 ++++++++++++--- src/server.rs | 10 +++------- 4 files changed, 49 insertions(+), 23 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6de3a12..0caf2ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ author="rattatwinko" edition = "2024" [dependencies] +clap = {version = "4.5.55", features = ["derive"]} logger-rust = "0.2.12" mime_guess = "2.0.5" serde = { version = "1.0.228", features = ["derive"]} diff --git a/src/main.rs b/src/main.rs index 18356b0..4136c4a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,25 +6,45 @@ use std::path::PathBuf; use std::sync::Arc; use logger_rust::*; +use clap::Parser; + +// 1CA:b6e8ae4ca8acae66aa3dfd3f0a377e91d041e4d7 ; added clap as a parser, its way cleaner +#[derive(Parser, Debug)] +#[command(name = "http-rs")] +#[command(about = "http-rs webserver")] +struct Arguments { + /// port where we should serve on + #[arg(short, long, default_value_t = 8080)] + port : u16, + + /// where we should serve from + #[arg(short, long, default_value = ".")] + root: PathBuf, + + /// number of threads to run on + #[arg(short, long)] + threads: Option, +} + + fn main() { - let args: Vec = std::env::args().collect(); - - let port: u16 = args.get(1) - .and_then(|p| p.parse().ok()) - .unwrap_or(8080); - - let root = Arc::new( - PathBuf::from(args.get(2).map(|s| s.as_str()).unwrap_or(".")) - ); + let args = Arguments::parse(); + let root = Arc::new(args.root); if !root.exists() || !root.is_dir() { log_error!("Root {} isnt a valid directory", root.display()); std::process::exit(1); } + + // moved num_cpus from server.rs to main.rs + let threads = args.threads.unwrap_or_else(|| { + std::thread::available_parallelism() + .map(|n| n.get() * 2) + .unwrap_or(8) + }); - if let Err(_) = server::run(root, port) { - // shit out error if we have port already in use, - // prevents panic - log_error!("Port {} already in use!", port); + if let Err(_) = server::run(root, args.port, threads) { + log_error!("port {} in use!", args.port); } + } diff --git a/src/router.rs b/src/router.rs index ed4a45d..5c6708b 100644 --- a/src/router.rs +++ b/src/router.rs @@ -1,4 +1,5 @@ use std::path::{Path, PathBuf}; +use logger_rust::*; // Fixed from version a671182b07da0c22ed29e66f87faa3738fbdca64 // onwards @@ -17,6 +18,7 @@ pub fn resolve(root: &Path, url_path: &str) -> ResolveResult { let mut joined = root.join(rel); // if directory look for index + // this is shitty logic, TODO: Improve this snippet if joined.is_dir() { let html = joined.join("index.html"); let htm = joined.join("index.htm"); @@ -32,9 +34,16 @@ pub fn resolve(root: &Path, url_path: &str) -> ResolveResult { // nono no escape let canonical_root = root.canonicalize().ok(); let canonical_file = joined.canonicalize().ok(); - + + // cleanup 1CA:b6e8ae4ca8acae66aa3dfd3f0a377e91d041e4d7 match (canonical_root, canonical_file) { - (Some(root), Some(file)) if file.starts_with(&root) => ResolveResult::Found(file), - _ => ResolveResult::Traversal, + (Some(root), Some(file)) + if file.starts_with(&root) => { + ResolveResult::Found(file) + } + _ => { + log_warn!("ResolveResult::Traversal"); + ResolveResult::Traversal + } } } diff --git a/src/server.rs b/src/server.rs index 53dda15..3b83711 100644 --- a/src/server.rs +++ b/src/server.rs @@ -9,12 +9,13 @@ use crate::response; pub fn run( root: Arc, - port: u16 + port: u16, + threads: usize ) -> Result<(), Box> { let addr = format!("0.0.0.0:{}", port); let server = Arc::new(Server::http(&addr)?); - let pool = ThreadPool::new(num_cpus()); + let pool = ThreadPool::new(threads); log_info!("Serving '{}' on http://{}", root.display(), addr); @@ -46,8 +47,3 @@ pub fn run( Ok(()) } -fn num_cpus() -> usize { - std::thread::available_parallelism() - .map(|n| n.get()) - .unwrap_or(4) -}