diff options
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/main.rs | 91 |
2 files changed, 44 insertions, 48 deletions
@@ -54,6 +54,7 @@ bytes = "1" atty = "0.2" rustls = { version = "0.19", optional = true } socket2 = "0.4" +get_if_addrs = "0.5" [features] default = ["tls"] diff --git a/src/main.rs b/src/main.rs index d34f0aa..9ea784b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ use std::io; use std::io::Write; -use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener}; +use std::net::{IpAddr, SocketAddr, TcpListener}; use std::thread; use std::time::Duration; @@ -102,23 +102,6 @@ async fn run(miniserve_config: MiniserveConfig) -> Result<(), ContextualError> { let inside_config = miniserve_config.clone(); - let interfaces = miniserve_config - .interfaces - .iter() - .map(|&interface| { - if interface == IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)) { - // If the interface is 0.0.0.0, we'll change it to 127.0.0.1 so that clicking the link will - // also work on Windows. Why can't Windows interpret 0.0.0.0? - "127.0.0.1".to_string() - } else if interface.is_ipv6() { - // If the interface is IPv6 then we'll print it with brackets so that it is clickable. - format!("[{}]", interface) - } else { - format!("{}", interface) - } - }) - .collect::<Vec<String>>(); - let canon_path = miniserve_config.path.canonicalize().map_err(|e| { ContextualError::IoError("Failed to resolve path to be served".to_string(), e) })?; @@ -164,37 +147,49 @@ async fn run(miniserve_config: MiniserveConfig) -> Result<(), ContextualError> { thread::sleep(Duration::from_millis(500)); } } - let mut addresses = String::new(); - for interface in &interfaces { - 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!( - "{protocol}://{interface}:{port}", - protocol = protocol, - interface = &interface, - port = miniserve_config.port - )) - .bold() - )); - - if let Some(random_route) = miniserve_config.clone().random_route { - addresses.push_str(&format!( - "{}", - Color::Green - .paint(format!("/{random_route}", random_route = random_route,)) - .bold() - )); + + let addresses = { + let (mut ifaces, wildcard): (Vec<_>, Vec<_>) = miniserve_config + .interfaces + .clone() + .into_iter() + .partition(|addr| !addr.is_unspecified()); + + // Replace wildcard addresses with local interface addresses + if !wildcard.is_empty() { + let all_ipv4 = wildcard.iter().any(|addr| addr.is_ipv4()); + let all_ipv6 = wildcard.iter().any(|addr| addr.is_ipv6()); + ifaces = get_if_addrs::get_if_addrs() + .unwrap_or_else(|e| { + error!("Failed to get local interface addresses: {}", e); + Default::default() + }) + .into_iter() + .map(|iface| iface.ip()) + .filter(|ip| (all_ipv4 && ip.is_ipv4()) || (all_ipv6 && ip.is_ipv6())) + .collect(); + ifaces.sort(); } - } + + let urls = ifaces + .into_iter() + .map(|addr| match addr { + IpAddr::V4(_) => format!("{}:{}", addr, miniserve_config.port), + IpAddr::V6(_) => format!("[{}]:{}", addr, miniserve_config.port), + }) + .map(|addr| match miniserve_config.tls_rustls_config { + Some(_) => format!("https://{}", addr), + None => format!("http://{}", addr), + }) + .map(|url| match miniserve_config.random_route { + Some(ref random_route) => format!("{}/{}", url, random_route), + None => url, + }) + .map(|url| Color::Green.paint(url).bold().to_string()) + .collect::<Vec<_>>(); + + urls.join(", ") + }; let socket_addresses = miniserve_config .interfaces |