diff --git a/src/main.rs b/src/main.rs index 988f0c2..85d0c43 100644 --- a/src/main.rs +++ b/src/main.rs @@ -65,7 +65,8 @@ fn run() -> Result<()> { info!("root dir: {}", config.root_dir.display()); info!("extensions: {}", config.use_extensions); - let server = Server::bind(&config.addr) + let server = Server::try_bind(&config.addr) + .map_err(|e| translate_bind_error(e, config.addr))? .serve(move || { let config = config.clone(); service_fn(move |req| { @@ -114,6 +115,19 @@ pub struct Config { use_extensions: bool, } +/// Translate a hyper error into our error for binding +fn translate_bind_error(e: hyper::Error, addr: SocketAddr) -> Error { + if let Some(os_error) = e + .source() + .and_then(|source| source.downcast_ref::()) + { + if os_error.kind() == io::ErrorKind::AddrInUse { + return Error::AddrInUse(addr); + } + } + Error::BindWithHyper(e) +} + /// The function that returns a future of an HTTP response for each hyper /// Request that is received. Errors are turned into an Error response (404 or /// 500), and never propagated upward for hyper to deal with. @@ -413,6 +427,12 @@ pub enum Error { #[display(fmt = "failed to parse IP address")] AddrParse(std::net::AddrParseError), + #[display(fmt = "the address \"{}\" is already in use", _0)] + AddrInUse(SocketAddr), + + #[display(fmt = "failed to bind server to socket")] + BindWithHyper(hyper::Error), + #[display(fmt = "markdown is not UTF-8")] MarkdownUtf8, @@ -437,6 +457,8 @@ impl StdError for Error { Http(e) => Some(e), Io(e) => Some(e), AddrParse(e) => Some(e), + AddrInUse(_) => None, + BindWithHyper(e) => Some(e), MarkdownUtf8 => None, StripPrefixInDirList(e) => Some(e), TemplateRender(e) => Some(e),