diff --git a/src/client/http_client.rs b/src/client/http_client.rs index 62aa9571..a43ff3e9 100644 --- a/src/client/http_client.rs +++ b/src/client/http_client.rs @@ -127,9 +127,7 @@ impl HttpClient { bail!("no password input mechanism available"); } - fn run_request( - request: Request, - ) -> Result { + fn build_client() -> Result>, Error> { let mut builder = native_tls::TlsConnector::builder(); // FIXME: We need a CLI option for this! builder.danger_accept_invalid_certs(true); @@ -139,6 +137,13 @@ impl HttpClient { let mut https = hyper_tls::HttpsConnector::from((httpc, tlsconnector)); https.https_only(true); // force it! let client = Client::builder().build::<_, Body>(https); + Ok(client) + } + + fn run_request( + request: Request, + ) -> Result { + let client = Self::build_client()?; let (tx, rx) = std::sync::mpsc::channel(); @@ -178,6 +183,61 @@ impl HttpClient { rx.recv().unwrap() } + fn run_download( + request: Request, + mut output: Box, + ) -> Result<(), Error> { + let client = Self::build_client()?; + + let (tx, rx) = std::sync::mpsc::channel(); + + let future = client + .request(request) + .map_err(Error::from) + .and_then(move |resp| { + + let status = resp.status(); + + resp.into_body() + .map_err(Error::from) + .for_each(move |chunk| { + output.write_all(&chunk)?; + Ok(()) + }) + + }) + .then(move |res| { + tx.send(res).unwrap(); + Ok(()) + }); + + // drop client, else client keeps connectioon open (keep-alive feature) + drop(client); + + rt::run(future); + + rx.recv().unwrap() + } + + pub fn download(&mut self, path: &str, output: Box) -> Result<(), Error> { + + let path = path.trim_matches('/'); + let url: Uri = format!("https://{}:8007/{}", self.server, path).parse()?; + + let (ticket, _token) = self.login()?; + + let enc_ticket = percent_encode(ticket.as_bytes(), DEFAULT_ENCODE_SET).to_string(); + + let request = Request::builder() + .method("GET") + .uri(url) + .header("User-Agent", "proxmox-backup-client/1.0") + .header("Cookie", format!("PBSAuthCookie={}", enc_ticket)) + .body(Body::empty())?; + + Self::run_download(request, output) + } + pub fn get(&mut self, path: &str) -> Result { let path = path.trim_matches('/');