From aa503c46c384c13fb02bf0cc98438336a161fcd4 Mon Sep 17 00:00:00 2001 From: Isaac Parker Date: Sun, 28 Jun 2020 14:03:31 -0600 Subject: Bind to random port when port 0 specified --- Cargo.lock | 1 + Cargo.toml | 2 ++ src/args.rs | 8 +++++++- tests/serve_request.rs | 26 ++++++++++++++++++++++++++ 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index ddcdb74..96fe95f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1753,6 +1753,7 @@ dependencies = [ "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "port_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)", "rstest 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "select 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 909ec59..a975fa8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ actix-web = "0.7" simplelog = "0.8" base64 = "0.12" percent-encoding = "2.1" +port_check = "0.1" htmlescape = "0.3.1" bytesize = "1.0.0" nanoid = "0.3" @@ -55,5 +56,6 @@ assert_fs = "1.0" select = "0.4" port_check = "0.1" rstest = "0.6" +regex = "1.3.9" pretty_assertions = "0.6" url = "2.1" diff --git a/src/args.rs b/src/args.rs index 7e30ee1..a5bcfea 100644 --- a/src/args.rs +++ b/src/args.rs @@ -1,6 +1,7 @@ use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use std::path::PathBuf; use structopt::StructOpt; +use port_check::free_local_port; use crate::auth; use crate::errors::ContextualError; @@ -170,10 +171,15 @@ pub fn parse_args() -> crate::MiniserveConfig { let path_explicitly_chosen = args.path.is_some(); + let port = match args.port { + 0 => free_local_port().expect("no free ports available"), + _ => args.port, + }; + crate::MiniserveConfig { verbose: args.verbose, path: args.path.unwrap_or_else(|| PathBuf::from(".")), - port: args.port, + port, interfaces, auth: args.auth, path_explicitly_chosen, diff --git a/tests/serve_request.rs b/tests/serve_request.rs index 5761a65..918bb98 100644 --- a/tests/serve_request.rs +++ b/tests/serve_request.rs @@ -9,6 +9,7 @@ use select::node::Node; use std::process::{Command, Stdio}; use std::thread::sleep; use std::time::Duration; +use regex::{Regex}; #[rstest] fn serves_requests_with_no_options(tmpdir: TempDir) -> Result<(), Error> { @@ -69,6 +70,31 @@ fn serves_requests_with_non_default_port(tmpdir: TempDir, port: u16) -> Result<( Ok(()) } +#[rstest] +fn serves_requests_with_randomly_assigned_port(tmpdir: TempDir) -> Result<(), Error> { + let mut child = Command::cargo_bin("miniserve")? + .arg(tmpdir.path()) + .arg("-p") + .arg("0".to_string()) + .stdout(Stdio::piped()) + .spawn()?; + + sleep(Duration::from_secs(1)); + child.kill()?; + + let output = child.wait_with_output().expect("Failed to read stdout"); + let all_text = String::from_utf8(output.stdout)?; + + let re = Regex::new(r"http://127.0.0.1:(\d+)").unwrap(); + let caps = re.captures(all_text.as_str()).unwrap(); + let port_num = caps.get(1).unwrap().as_str().parse::().unwrap(); + + assert!(port_num > 0); + assert!(port_num <= 65535); + + Ok(()) +} + #[rstest] fn serves_requests_custom_index_notice(tmpdir: TempDir, port: u16) -> Result<(), Error> { let mut child = Command::cargo_bin("miniserve")? -- cgit v1.2.3