Implement clap for command line argument parsing, and cleanup of path traversal logic, now readable
This commit is contained in:
@@ -5,6 +5,7 @@ author="rattatwinko"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
clap = {version = "4.5.55", features = ["derive"]}
|
||||||
logger-rust = "0.2.12"
|
logger-rust = "0.2.12"
|
||||||
mime_guess = "2.0.5"
|
mime_guess = "2.0.5"
|
||||||
serde = { version = "1.0.228", features = ["derive"]}
|
serde = { version = "1.0.228", features = ["derive"]}
|
||||||
|
|||||||
46
src/main.rs
46
src/main.rs
@@ -6,25 +6,45 @@ use std::path::PathBuf;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use logger_rust::*;
|
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<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args: Vec<String> = std::env::args().collect();
|
let args = Arguments::parse();
|
||||||
|
let root = Arc::new(args.root);
|
||||||
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("."))
|
|
||||||
);
|
|
||||||
|
|
||||||
if !root.exists() || !root.is_dir() {
|
if !root.exists() || !root.is_dir() {
|
||||||
log_error!("Root {} isnt a valid directory", root.display());
|
log_error!("Root {} isnt a valid directory", root.display());
|
||||||
std::process::exit(1);
|
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) {
|
if let Err(_) = server::run(root, args.port, threads) {
|
||||||
// shit out error if we have port already in use,
|
log_error!("port {} in use!", args.port);
|
||||||
// prevents panic
|
|
||||||
log_error!("Port {} already in use!", port);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use logger_rust::*;
|
||||||
|
|
||||||
// Fixed from version a671182b07da0c22ed29e66f87faa3738fbdca64
|
// Fixed from version a671182b07da0c22ed29e66f87faa3738fbdca64
|
||||||
// onwards
|
// onwards
|
||||||
@@ -17,6 +18,7 @@ pub fn resolve(root: &Path, url_path: &str) -> ResolveResult {
|
|||||||
let mut joined = root.join(rel);
|
let mut joined = root.join(rel);
|
||||||
|
|
||||||
// if directory look for index
|
// if directory look for index
|
||||||
|
// this is shitty logic, TODO: Improve this snippet
|
||||||
if joined.is_dir() {
|
if joined.is_dir() {
|
||||||
let html = joined.join("index.html");
|
let html = joined.join("index.html");
|
||||||
let htm = joined.join("index.htm");
|
let htm = joined.join("index.htm");
|
||||||
@@ -32,9 +34,16 @@ pub fn resolve(root: &Path, url_path: &str) -> ResolveResult {
|
|||||||
// nono no escape
|
// nono no escape
|
||||||
let canonical_root = root.canonicalize().ok();
|
let canonical_root = root.canonicalize().ok();
|
||||||
let canonical_file = joined.canonicalize().ok();
|
let canonical_file = joined.canonicalize().ok();
|
||||||
|
|
||||||
|
// cleanup 1CA:b6e8ae4ca8acae66aa3dfd3f0a377e91d041e4d7
|
||||||
match (canonical_root, canonical_file) {
|
match (canonical_root, canonical_file) {
|
||||||
(Some(root), Some(file)) if file.starts_with(&root) => ResolveResult::Found(file),
|
(Some(root), Some(file))
|
||||||
_ => ResolveResult::Traversal,
|
if file.starts_with(&root) => {
|
||||||
|
ResolveResult::Found(file)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
log_warn!("ResolveResult::Traversal");
|
||||||
|
ResolveResult::Traversal
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,12 +9,13 @@ use crate::response;
|
|||||||
|
|
||||||
pub fn run(
|
pub fn run(
|
||||||
root: Arc<PathBuf>,
|
root: Arc<PathBuf>,
|
||||||
port: u16
|
port: u16,
|
||||||
|
threads: usize
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
|
|
||||||
let addr = format!("0.0.0.0:{}", port);
|
let addr = format!("0.0.0.0:{}", port);
|
||||||
let server = Arc::new(Server::http(&addr)?);
|
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);
|
log_info!("Serving '{}' on http://{}", root.display(), addr);
|
||||||
|
|
||||||
@@ -46,8 +47,3 @@ pub fn run(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn num_cpus() -> usize {
|
|
||||||
std::thread::available_parallelism()
|
|
||||||
.map(|n| n.get())
|
|
||||||
.unwrap_or(4)
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user