]> git.proxmox.com Git - proxmox-backup.git/blame - src/client/http_client.rs
src/client/http_client.rs: try to login
[proxmox-backup.git] / src / client / http_client.rs
CommitLineData
597641fd
DM
1use failure::*;
2
3use http::Uri;
4use hyper::Body;
5use hyper::client::Client;
6use hyper::rt::{self, Future};
7
1fdb4c6f
DM
8use http::Request;
9use futures::stream::Stream;
10
11use serde_json::{Value};
0dffe3f9 12use url::percent_encoding::{percent_encode, DEFAULT_ENCODE_SET};
1fdb4c6f 13
597641fd 14pub struct HttpClient {
0dffe3f9 15 username: String,
597641fd
DM
16 server: String,
17}
18
19impl HttpClient {
20
0dffe3f9 21 pub fn new(server: &str, username: &str) -> Self {
597641fd
DM
22 Self {
23 server: String::from(server),
0dffe3f9 24 username: String::from(username),
597641fd
DM
25 }
26 }
27
4a3f6517
WB
28 fn run_request(
29 request: Request<Body>,
30 ) -> Result<Value, Error> {
31 let mut builder = native_tls::TlsConnector::builder();
32 // FIXME: We need a CLI option for this!
33 builder.danger_accept_invalid_certs(true);
34 let tlsconnector = builder.build()?;
35 let mut httpc = hyper::client::HttpConnector::new(1);
36 httpc.enforce_http(false); // we want https...
37 let mut https = hyper_tls::HttpsConnector::from((httpc, tlsconnector));
38 https.https_only(true); // force it!
39 let client = Client::builder().build::<_, Body>(https);
597641fd 40
1adb353d 41 let (tx, rx) = std::sync::mpsc::channel();
597641fd
DM
42
43 let future = client
44 .request(request)
45 .map_err(|e| Error::from(e))
46 .and_then(|resp| {
47
48 let status = resp.status();
49
50 resp.into_body().concat2().map_err(|e| Error::from(e))
51 .and_then(move |data| {
52
53 let text = String::from_utf8(data.to_vec()).unwrap();
54 if status.is_success() {
1fdb4c6f
DM
55 if text.len() > 0 {
56 let value: Value = serde_json::from_str(&text)?;
57 Ok(value)
58 } else {
59 Ok(Value::Null)
60 }
597641fd 61 } else {
1fdb4c6f 62 bail!("HTTP Error {}: {}", status, text);
597641fd 63 }
597641fd
DM
64 })
65 })
1adb353d
DM
66 .then(move |res| {
67 tx.send(res).unwrap();
68 Ok(())
597641fd
DM
69 });
70
71 // drop client, else client keeps connectioon open (keep-alive feature)
72 drop(client);
73
74 rt::run(future);
75
1adb353d 76 rx.recv().unwrap()
1fdb4c6f
DM
77 }
78
79 pub fn get(&self, path: &str) -> Result<Value, Error> {
80
4a3f6517 81 let url: Uri = format!("https://{}:8007/{}", self.server, path).parse()?;
1fdb4c6f 82
0dffe3f9
DM
83 let ticket = self.login()?;
84
85 let enc_ticket = percent_encode(ticket.as_bytes(), DEFAULT_ENCODE_SET).to_string();
86
1fdb4c6f
DM
87 let request = Request::builder()
88 .method("GET")
89 .uri(url)
90 .header("User-Agent", "proxmox-backup-client/1.0")
0dffe3f9 91 .header("Cookie", format!("PBSAuthCookie={}", enc_ticket))
1fdb4c6f
DM
92 .body(Body::empty())?;
93
94 Self::run_request(request)
95 }
96
0dffe3f9
DM
97 fn login(&self) -> Result<String, Error> {
98
99 let url: Uri = format!("https://{}:8007/{}", self.server, "/api2/json/access/ticket").parse()?;
100
101 let password = match std::env::var("PBS_PASSWORD") {
102 Ok(p) => p,
103 Err(err) => bail!("missing passphrase - {}", err),
104 };
105
106 let query = url::form_urlencoded::Serializer::new(String::new())
107 .append_pair("username", &self.username)
108 .append_pair("password", &password)
109 .finish();
110
111 let request = Request::builder()
112 .method("POST")
113 .uri(url)
114 .header("User-Agent", "proxmox-backup-client/1.0")
115 .header("Content-Type", "application/x-www-form-urlencoded")
116 .body(Body::from(query))?;
117
118 let auth_res = Self::run_request(request)?;
119
120 let ticket = match auth_res["data"]["ticket"].as_str() {
121 Some(t) => t,
122 None => bail!("got unexpected respose for login request."),
123 };
124
125 Ok(ticket.to_owned())
126 }
127
1fdb4c6f
DM
128 pub fn upload(&self, content_type: &str, body: Body, path: &str) -> Result<Value, Error> {
129
4a3f6517 130 let url: Uri = format!("https://{}:8007/{}", self.server, path).parse()?;
1fdb4c6f 131
0dffe3f9
DM
132 let ticket = self.login()?;
133
134 let enc_ticket = percent_encode(ticket.as_bytes(), DEFAULT_ENCODE_SET).to_string();
135
1fdb4c6f
DM
136 let request = Request::builder()
137 .method("POST")
138 .uri(url)
139 .header("User-Agent", "proxmox-backup-client/1.0")
0dffe3f9 140 .header("Cookie", format!("PBSAuthCookie={}", enc_ticket))
1fdb4c6f
DM
141 .header("Content-Type", content_type)
142 .body(body)?;
143
144 Self::run_request(request)
597641fd
DM
145 }
146}