瀏覽代碼

Add URL/host parsing and URL building, add quit with error message

timvisee 7 年之前
父節點
當前提交
8ffea0410d
共有 7 個文件被更改,包括 59 次插入7 次删除
  1. 1 0
      Cargo.lock
  2. 1 0
      Cargo.toml
  3. 1 1
      src/app.rs
  4. 29 2
      src/cmd/cmd_upload.rs
  5. 5 3
      src/main.rs
  6. 11 1
      src/send/file.rs
  7. 11 0
      src/util.rs

+ 1 - 0
Cargo.lock

@@ -195,6 +195,7 @@ dependencies = [
  "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "sha2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "sha2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "version-compare 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "version-compare 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 ]
 
 

+ 1 - 0
Cargo.toml

@@ -19,4 +19,5 @@ serde = "1.0"
 serde_derive = "1.0"
 serde_derive = "1.0"
 serde_json = "1.0"
 serde_json = "1.0"
 sha2 = "0.7"
 sha2 = "0.7"
+url = "1.7"
 version-compare = "0.0"
 version-compare = "0.0"

+ 1 - 1
src/app.rs

@@ -11,4 +11,4 @@ pub const APP_AUTHOR: &'static str = "Tim Visee <timvisee@gmail.com>";
 pub const APP_ABOUT: &'static str = "A simple Firefox Send CLI client.";
 pub const APP_ABOUT: &'static str = "A simple Firefox Send CLI client.";
 
 
 /// The default Send host to use.
 /// The default Send host to use.
-pub const SEND_DEF_HOST: &'static str = "localhost:8080";
+pub const SEND_DEF_HOST: &'static str = "http://localhost:8080/";

+ 29 - 2
src/cmd/cmd_upload.rs

@@ -1,6 +1,9 @@
+use super::super::url::{ParseError, Url};
+
 use super::clap::{App, Arg, ArgMatches, SubCommand};
 use super::clap::{App, Arg, ArgMatches, SubCommand};
 
 
 use app::SEND_DEF_HOST;
 use app::SEND_DEF_HOST;
+use util::quit_error;
 
 
 /// The upload command.
 /// The upload command.
 pub struct CmdUpload<'a> {
 pub struct CmdUpload<'a> {
@@ -48,7 +51,31 @@ impl<'a: 'b, 'b> CmdUpload<'a> {
     }
     }
 
 
     /// Get the host to upload to.
     /// Get the host to upload to.
-    pub fn host(&'a self) -> &'a str {
-        self.matches.value_of("host").unwrap()
+    ///
+    /// This method parses the host into an `Url`.
+    /// If the given host is invalid,
+    /// the program will quit with an error message.
+    pub fn host(&'a self) -> Url {
+        // Get the host
+        let host = self.matches.value_of("host")
+            .expect("missing host");
+
+        // Parse the URL
+        match Url::parse(host) {
+            Ok(url) => url,
+            Err(ParseError::EmptyHost) =>
+                quit_error("emtpy host given"),
+            Err(ParseError::InvalidPort) =>
+                quit_error("invalid host port"),
+            Err(ParseError::InvalidIpv4Address) =>
+                quit_error("invalid IPv4 address in host"),
+            Err(ParseError::InvalidIpv6Address) =>
+                quit_error("invalid IPv6 address in host"),
+            Err(ParseError::InvalidDomainCharacter) =>
+                quit_error("host domains contains an invalid character"),
+            Err(ParseError::RelativeUrlWithoutBase) =>
+                quit_error("host domain doesn't contain a host"),
+            _ => quit_error("the given host is invalid"),
+        }
     }
     }
 }
 }

+ 5 - 3
src/main.rs

@@ -7,6 +7,7 @@ extern crate rand;
 extern crate reqwest;
 extern crate reqwest;
 #[macro_use]
 #[macro_use]
 extern crate serde_derive;
 extern crate serde_derive;
+extern crate url;
 
 
 mod action;
 mod action;
 mod app;
 mod app;
@@ -16,6 +17,7 @@ mod crypto;
 mod metadata;
 mod metadata;
 mod reader;
 mod reader;
 mod send;
 mod send;
+mod util;
 
 
 use std::fs::File;
 use std::fs::File;
 use std::io::BufReader;
 use std::io::BufReader;
@@ -134,8 +136,8 @@ fn action_upload(cmd_upload: &CmdUpload) {
 
 
     // Make the request
     // Make the request
     // TODO: properly format an URL here
     // TODO: properly format an URL here
-    let url = format!("{}/api/upload", host);
-    let mut res = client.post(&url)
+    let url = host.join("api/upload").expect("invalid host");
+    let mut res = client.post(url.as_str())
         .header(Authorization(format!("send-v1 {}", b64::encode(&auth_key))))
         .header(Authorization(format!("send-v1 {}", b64::encode(&auth_key))))
         .header(XFileMetadata::from(&metadata))
         .header(XFileMetadata::from(&metadata))
         .multipart(form)
         .multipart(form)
@@ -146,7 +148,7 @@ fn action_upload(cmd_upload: &CmdUpload) {
     let upload_res: UploadResponse = res.json().unwrap();
     let upload_res: UploadResponse = res.json().unwrap();
 
 
     // Print the response
     // Print the response
-    let file = upload_res.into_file(host.to_owned(), secret.to_vec());
+    let file = upload_res.into_file(host.into_string(), secret.to_vec());
     let url = file.download_url();
     let url = file.download_url();
     println!("File: {:#?}", file);
     println!("File: {:#?}", file);
     println!("Secret key: {}", b64::encode(&secret));
     println!("Secret key: {}", b64::encode(&secret));

+ 11 - 1
src/send/file.rs

@@ -67,8 +67,18 @@ impl File {
         )
         )
     }
     }
 
 
+    /// Get the raw secret.
+    pub fn secret_raw(&self) -> &Vec<u8> {
+        &self.secret
+    }
+
+    /// Get the secret as base64 encoded string.
+    pub fn secret(&self) -> String {
+        b64::encode(self.secret_raw())
+    }
+
     /// Get the download URL of the file, with the secret key included.
     /// Get the download URL of the file, with the secret key included.
     pub fn download_url(&self) -> String {
     pub fn download_url(&self) -> String {
-        format!("{}#{}", self.url, b64::encode(&self.secret))
+        format!("{}#{}", self.url, self.secret())
     }
     }
 }
 }

+ 11 - 0
src/util.rs

@@ -0,0 +1,11 @@
+use std::process::exit;
+
+/// Quit the application with an error code,
+/// and print the given error message.
+pub fn quit_error<S: AsRef<str>>(err: S) -> ! {
+    // Print the error message
+    eprintln!("error: {}", err.as_ref());
+
+    // Quit
+    exit(1);
+}