diff options
Diffstat (limited to 'cli/args/flags_net.rs')
-rw-r--r-- | cli/args/flags_net.rs | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/cli/args/flags_net.rs b/cli/args/flags_net.rs new file mode 100644 index 000000000..9f8a6b9f9 --- /dev/null +++ b/cli/args/flags_net.rs @@ -0,0 +1,202 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. + +use deno_core::url::Url; +use std::net::IpAddr; +use std::str::FromStr; + +#[derive(Debug, PartialEq, Eq)] +pub struct ParsePortError(String); + +#[derive(Debug, PartialEq, Eq)] +pub struct BarePort(u16); + +impl FromStr for BarePort { + type Err = ParsePortError; + fn from_str(s: &str) -> Result<BarePort, ParsePortError> { + if s.starts_with(':') { + match s.split_at(1).1.parse::<u16>() { + Ok(port) => Ok(BarePort(port)), + Err(e) => Err(ParsePortError(e.to_string())), + } + } else { + Err(ParsePortError( + "Bare Port doesn't start with ':'".to_string(), + )) + } + } +} + +pub fn validator(host_and_port: &str) -> Result<String, String> { + if Url::parse(&format!("internal://{host_and_port}")).is_ok() + || host_and_port.parse::<IpAddr>().is_ok() + || host_and_port.parse::<BarePort>().is_ok() + { + Ok(host_and_port.to_string()) + } else { + Err(format!("Bad host:port pair: {host_and_port}")) + } +} + +/// Expands "bare port" paths (eg. ":8080") into full paths with hosts. It +/// expands to such paths into 3 paths with following hosts: `0.0.0.0:port`, +/// `127.0.0.1:port` and `localhost:port`. +pub fn parse(paths: Vec<String>) -> clap::error::Result<Vec<String>> { + let mut out: Vec<String> = vec![]; + for host_and_port in paths.iter() { + if Url::parse(&format!("internal://{host_and_port}")).is_ok() + || host_and_port.parse::<IpAddr>().is_ok() + { + out.push(host_and_port.to_owned()) + } else if let Ok(port) = host_and_port.parse::<BarePort>() { + // we got bare port, let's add default hosts + for host in ["0.0.0.0", "127.0.0.1", "localhost"].iter() { + out.push(format!("{}:{}", host, port.0)); + } + } else { + return Err(clap::Error::raw( + clap::error::ErrorKind::InvalidValue, + format!("Bad host:port pair: {host_and_port}"), + )); + } + } + Ok(out) +} + +#[cfg(test)] +mod bare_port_tests { + use super::BarePort; + use super::ParsePortError; + + #[test] + fn bare_port_parsed() { + let expected = BarePort(8080); + let actual = ":8080".parse::<BarePort>(); + assert_eq!(actual, Ok(expected)); + } + + #[test] + fn bare_port_parse_error1() { + let expected = + ParsePortError("Bare Port doesn't start with ':'".to_string()); + let actual = "8080".parse::<BarePort>(); + assert_eq!(actual, Err(expected)); + } + + #[test] + fn bare_port_parse_error2() { + let actual = ":65536".parse::<BarePort>(); + assert!(actual.is_err()); + } + + #[test] + fn bare_port_parse_error3() { + let actual = ":14u16".parse::<BarePort>(); + assert!(actual.is_err()); + } + + #[test] + fn bare_port_parse_error4() { + let actual = "Deno".parse::<BarePort>(); + assert!(actual.is_err()); + } + + #[test] + fn bare_port_parse_error5() { + let actual = "deno.land:8080".parse::<BarePort>(); + assert!(actual.is_err()); + } +} + +#[cfg(test)] +mod tests { + use super::parse; + + // Creates vector of strings, Vec<String> + macro_rules! svec { + ($($x:expr),*) => (vec![$($x.to_string()),*]); + } + + #[test] + fn parse_net_args_() { + let entries = svec![ + "deno.land", + "deno.land:80", + "::", + "::1", + "127.0.0.1", + "[::1]", + "1.2.3.4:5678", + "0.0.0.0:5678", + "127.0.0.1:5678", + "[::]:5678", + "[::1]:5678", + "localhost:5678", + "[::1]:8080", + "[::]:8000", + "[::1]:8000", + "localhost:8000", + "0.0.0.0:4545", + "127.0.0.1:4545", + "999.0.88.1:80" + ]; + let expected = svec![ + "deno.land", + "deno.land:80", + "::", + "::1", + "127.0.0.1", + "[::1]", + "1.2.3.4:5678", + "0.0.0.0:5678", + "127.0.0.1:5678", + "[::]:5678", + "[::1]:5678", + "localhost:5678", + "[::1]:8080", + "[::]:8000", + "[::1]:8000", + "localhost:8000", + "0.0.0.0:4545", + "127.0.0.1:4545", + "999.0.88.1:80" + ]; + let actual = parse(entries).unwrap(); + assert_eq!(actual, expected); + } + + #[test] + fn parse_net_args_expansion() { + let entries = svec![":8080"]; + let expected = svec!["0.0.0.0:8080", "127.0.0.1:8080", "localhost:8080"]; + let actual = parse(entries).unwrap(); + assert_eq!(actual, expected); + } + + #[test] + fn parse_net_args_ipv6() { + let entries = + svec!["::", "::1", "[::1]", "[::]:5678", "[::1]:5678", "::cafe"]; + let expected = + svec!["::", "::1", "[::1]", "[::]:5678", "[::1]:5678", "::cafe"]; + let actual = parse(entries).unwrap(); + assert_eq!(actual, expected); + } + + #[test] + fn parse_net_args_ipv6_error1() { + let entries = svec![":::"]; + assert!(parse(entries).is_err()); + } + + #[test] + fn parse_net_args_ipv6_error2() { + let entries = svec!["0123:4567:890a:bcde:fg::"]; + assert!(parse(entries).is_err()); + } + + #[test] + fn parse_net_args_ipv6_error3() { + let entries = svec!["[::q]:8080"]; + assert!(parse(entries).is_err()); + } +} |