浏览代码

Properly parse host/share URLs centrally, with error reporting

timvisee 7 年之前
父节点
当前提交
8e4feb379e
共有 5 个文件被更改,包括 79 次插入64 次删除
  1. 1 0
      ROADMAP.md
  2. 9 32
      cli/src/cmd/arg/host.rs
  3. 9 32
      cli/src/cmd/arg/url.rs
  4. 59 0
      cli/src/host.rs
  5. 1 0
      cli/src/main.rs

+ 1 - 0
ROADMAP.md

@@ -13,6 +13,7 @@
 - Check all TODOs, solve them when possible
 
 # Future releases
+- Implement verbose logging with `-v`
 - Box errors
 - A status command, to check the server status using `/__version__` and
   heartbeat endpoints

+ 9 - 32
cli/src/cmd/arg/host.rs

@@ -1,9 +1,11 @@
 use clap::{Arg, ArgMatches};
-use ffsend_api::url::{ParseError, Url};
+use failure::Fail;
+use ffsend_api::url::Url;
 
 use app::SEND_DEF_HOST;
+use host::parse_host;
 use super::{CmdArg, CmdArgOption};
-use util::{ErrorHints, quit_error_msg};
+use util::{ErrorHints, quit_error};
 
 /// The host argument.
 pub struct ArgHost { }
@@ -32,37 +34,12 @@ impl<'a> CmdArgOption<'a> for ArgHost {
         let url = Self::value_raw(matches).expect("missing host");
 
         // Parse the URL
-        // TODO: improve these error messages
-        match Url::parse(url) {
+        match parse_host(&url) {
             Ok(url) => url,
-            Err(ParseError::EmptyHost) =>
-                quit_error_msg("Emtpy host given", ErrorHints::default()),
-            Err(ParseError::InvalidPort) =>
-                quit_error_msg("Invalid host port", ErrorHints::default()),
-            Err(ParseError::InvalidIpv4Address) =>
-                quit_error_msg(
-                    "Invalid IPv4 address in host",
-                    ErrorHints::default(),
-                ),
-            Err(ParseError::InvalidIpv6Address) =>
-                quit_error_msg(
-                    "Invalid IPv6 address in host",
-                    ErrorHints::default(),
-                ),
-            Err(ParseError::InvalidDomainCharacter) =>
-                quit_error_msg(
-                    "Host domains contains an invalid character",
-                    ErrorHints::default(),
-                ),
-            Err(ParseError::RelativeUrlWithoutBase) =>
-                quit_error_msg(
-                    "Host domain doesn't contain a host",
-                    ErrorHints::default(),
-                ),
-            _ => quit_error_msg(
-                    "The given host is invalid",
-                    ErrorHints::default(),
-                ),
+            Err(err) => quit_error(
+                err.context("Failed to parse the given host"),
+                ErrorHints::default(),
+            ),
         }
     }
 }

+ 9 - 32
cli/src/cmd/arg/url.rs

@@ -1,8 +1,10 @@
 use clap::{Arg, ArgMatches};
-use ffsend_api::url::{ParseError, Url};
+use failure::Fail;
+use ffsend_api::url::Url;
 
+use host::parse_host;
 use super::{CmdArg, CmdArgOption};
-use util::{ErrorHints, quit_error_msg};
+use util::{ErrorHints, quit_error};
 
 /// The URL argument.
 pub struct ArgUrl { }
@@ -28,37 +30,12 @@ impl<'a> CmdArgOption<'a> for ArgUrl {
         let url = Self::value_raw(matches).expect("missing URL");
 
         // Parse the URL
-        // TODO: improve these error messages
-        match Url::parse(url) {
+        match parse_host(&url) {
             Ok(url) => url,
-            Err(ParseError::EmptyHost) =>
-                quit_error_msg("Emtpy host given", ErrorHints::default()),
-            Err(ParseError::InvalidPort) =>
-                quit_error_msg("Invalid host port", ErrorHints::default()),
-            Err(ParseError::InvalidIpv4Address) =>
-                quit_error_msg(
-                    "Invalid IPv4 address in host",
-                    ErrorHints::default(),
-                ),
-            Err(ParseError::InvalidIpv6Address) =>
-                quit_error_msg(
-                    "Invalid IPv6 address in host",
-                    ErrorHints::default(),
-                ),
-            Err(ParseError::InvalidDomainCharacter) =>
-                quit_error_msg(
-                    "Host domains contains an invalid character",
-                    ErrorHints::default(),
-                ),
-            Err(ParseError::RelativeUrlWithoutBase) =>
-                quit_error_msg(
-                    "Host domain doesn't contain a host",
-                    ErrorHints::default(),
-                ),
-            _ => quit_error_msg(
-                    "The given host is invalid",
-                    ErrorHints::default(),
-                ),
+            Err(err) => quit_error(
+                err.context("Failed to parse the given share URL"),
+                ErrorHints::default(),
+            ),
         }
     }
 }

+ 59 - 0
cli/src/host.rs

@@ -0,0 +1,59 @@
+use ffsend_api::url::{ParseError, Url};
+
+/// Parse the given host string, into an URL.
+pub fn parse_host(host: &str) -> Result<Url, HostError> {
+    // Trim
+    let host = host.trim();
+
+    // Make sure a valid scheme is prefixed
+    if !host.starts_with("https://") && !host.starts_with("http://") {
+        return Err(HostError::Scheme);
+    }
+
+    // Parse the URL, and map the errors
+    Url::parse(host).map_err(|err| match err {
+        ParseError::EmptyHost => HostError::Empty,
+        ParseError::InvalidPort => HostError::Port,
+        ParseError::InvalidIpv4Address => HostError::Ipv4,
+        ParseError::InvalidIpv6Address => HostError::Ipv6,
+        ParseError::InvalidDomainCharacter => HostError::DomainCharacter,
+        ParseError::RelativeUrlWithoutBase => HostError::NoBase,
+        err => HostError::Other(err),
+    })
+}
+
+/// An error that has occurred while parsing a host.
+#[derive(Debug, Fail)]
+pub enum HostError {
+    /// The URL scheme is missing or invalid.
+    #[fail(display = "The URL must have the 'https://' or 'http://' scheme")]
+    Scheme,
+
+    /// The host address is empty.
+    #[fail(display = "Empty host address")]
+    Empty,
+
+    /// The port number is invalid.
+    #[fail(display = "Invalid port")]
+    Port,
+
+    /// The given IPv4 styled address is invalid.
+    #[fail(display = "Invalid IPv4 address in the host")]
+    Ipv4,
+
+    /// The given IPv6 styled address is invalid.
+    #[fail(display = "Invalid IPv6 address in the host")]
+    Ipv6,
+
+    /// The domain contains an invalid character.
+    #[fail(display = "Invalid character in the domain")]
+    DomainCharacter,
+
+    /// The base host is missing from the host URL.
+    #[fail(display = "Missing host in the host URL")]
+    NoBase,
+
+    /// Failed to parse the host URL due to another reason.
+    #[fail(display = "Could not parse host URL")]
+    Other(#[cause] ParseError),
+}

+ 1 - 0
cli/src/main.rs

@@ -11,6 +11,7 @@ mod action;
 mod app;
 mod cmd;
 mod error;
+mod host;
 mod progress;
 mod util;