]> git.proxmox.com Git - proxmox-backup.git/blame - src/tools/simple_http_client.rs
HttpsConnector: make keepalive configurable
[proxmox-backup.git] / src / tools / simple_http_client.rs
CommitLineData
e5ef69ec
DM
1use anyhow::{Error, format_err, bail};
2use std::collections::HashMap;
3
4use hyper::Body;
5use hyper::client::{Client, HttpConnector};
6use http::{Request, Response, HeaderValue};
7use openssl::ssl::{SslConnector, SslMethod};
8use futures::*;
9
3ed7e875 10use crate::tools::PROXMOX_BACKUP_TCP_KEEPALIVE_TIME;
e5ef69ec
DM
11use crate::tools::http::{HttpsConnector, ProxyConfig};
12
13/// Asyncrounous HTTP client implementation
14pub struct SimpleHttp {
15 client: Client<HttpsConnector, Body>,
16 proxy_authorization: Option<String>, // Proxy-Authorization header value
17 user_agent: Option<String>,
18}
19
20impl SimpleHttp {
21
22 pub const DEFAULT_USER_AGENT_STRING: &'static str = "proxmox-backup-client/1.0";
23
24 pub fn new(proxy_config: Option<ProxyConfig>) -> Self {
25 let ssl_connector = SslConnector::builder(SslMethod::tls()).unwrap().build();
26 Self::with_ssl_connector(ssl_connector, proxy_config)
27 }
28
29 pub fn with_ssl_connector(ssl_connector: SslConnector, proxy_config: Option<ProxyConfig>) -> Self {
30
31 let mut proxy_authorization = None;
32 if let Some(ref proxy_config) = proxy_config {
33 if !proxy_config.force_connect {
34 proxy_authorization = proxy_config.authorization.clone();
35 }
36 }
37
38 let connector = HttpConnector::new();
3ed7e875 39 let mut https = HttpsConnector::with_connector(connector, ssl_connector, PROXMOX_BACKUP_TCP_KEEPALIVE_TIME);
e5ef69ec
DM
40 if let Some(proxy_config) = proxy_config {
41 https.set_proxy(proxy_config);
42 }
43 let client = Client::builder().build(https);
44 Self { client, proxy_authorization, user_agent: None }
45 }
46
47 pub fn set_user_agent(&mut self, user_agent: &str) -> Result<(), Error> {
48 self.user_agent = Some(user_agent.to_owned());
49 Ok(())
50 }
51
52 fn add_proxy_headers(&self, request: &mut Request<Body>) -> Result<(), Error> {
53 if request.uri().scheme() != Some(&http::uri::Scheme::HTTPS) {
54 if let Some(ref authorization) = self.proxy_authorization {
55 request
56 .headers_mut()
57 .insert(
58 http::header::PROXY_AUTHORIZATION,
59 HeaderValue::from_str(authorization)?,
60 );
61 }
62 }
63 Ok(())
64 }
65
66 pub async fn request(&self, mut request: Request<Body>) -> Result<Response<Body>, Error> {
67 let user_agent = if let Some(ref user_agent) = self.user_agent {
68 HeaderValue::from_str(&user_agent)?
69 } else {
70 HeaderValue::from_str(Self::DEFAULT_USER_AGENT_STRING)?
71 };
72
73 request.headers_mut().insert(hyper::header::USER_AGENT, user_agent);
74
75 self.add_proxy_headers(&mut request)?;
76
77 self.client.request(request)
78 .map_err(Error::from)
79 .await
80 }
81
82 pub async fn post(
83 &mut self,
84 uri: &str,
85 body: Option<String>,
86 content_type: Option<&str>,
87 ) -> Result<Response<Body>, Error> {
88
89 let body = if let Some(body) = body {
90 Body::from(body)
91 } else {
92 Body::empty()
93 };
94 let content_type = content_type.unwrap_or("application/json");
95
96 let request = Request::builder()
97 .method("POST")
98 .uri(uri)
99 .header(hyper::header::CONTENT_TYPE, content_type)
100 .body(body)?;
101
102 self.request(request).await
103 }
104
105 pub async fn get_string(
106 &mut self,
107 uri: &str,
108 extra_headers: Option<&HashMap<String, String>>,
109 ) -> Result<String, Error> {
110
111 let mut request = Request::builder()
112 .method("GET")
113 .uri(uri);
114
115 if let Some(hs) = extra_headers {
116 for (h, v) in hs.iter() {
117 request = request.header(h, v);
118 }
119 }
120
121 let request = request.body(Body::empty())?;
122
123 let res = self.request(request).await?;
124
125 let status = res.status();
126 if !status.is_success() {
127 bail!("Got bad status '{}' from server", status)
128 }
129
130 Self::response_body_string(res).await
131 }
132
133 pub async fn response_body_string(res: Response<Body>) -> Result<String, Error> {
134 let buf = hyper::body::to_bytes(res).await?;
135 String::from_utf8(buf.to_vec())
136 .map_err(|err| format_err!("Error converting HTTP result data: {}", err))
137 }
138}