new http client implementation SimpleHttp (avoid static HTTP_CLIENT)

This one will have proxy support.
This commit is contained in:
Dietmar Maurer 2021-04-21 13:17:00 +02:00 committed by Thomas Lamprecht
parent 17b3e4451f
commit 26153589ba
3 changed files with 83 additions and 63 deletions

View File

@ -7,7 +7,7 @@ use proxmox::api::{api, RpcEnvironment, RpcEnvironmentType, Permission};
use proxmox::api::router::{Router, SubdirMap};
use crate::server::WorkerTask;
use crate::tools::{apt, http, subscription};
use crate::tools::{apt, http::SimpleHttp, subscription};
use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
use crate::api2::types::{Authid, APTUpdateInfo, NODE_SCHEMA, UPID_SCHEMA};
@ -194,10 +194,12 @@ fn apt_get_changelog(
bail!("Package '{}' not found", name);
}
let mut client = SimpleHttp::new();
let changelog_url = &pkg_info[0].change_log_url;
// FIXME: use 'apt-get changelog' for proxmox packages as well, once repo supports it
if changelog_url.starts_with("http://download.proxmox.com/") {
let changelog = crate::tools::runtime::block_on(http::get_string(changelog_url, None))
let changelog = crate::tools::runtime::block_on(client.get_string(changelog_url, None))
.map_err(|err| format_err!("Error downloading changelog from '{}': {}", changelog_url, err))?;
Ok(json!(changelog))
@ -221,7 +223,7 @@ fn apt_get_changelog(
auth_header.insert("Authorization".to_owned(),
format!("Basic {}", base64::encode(format!("{}:{}", key, id))));
let changelog = crate::tools::runtime::block_on(http::get_string(changelog_url, Some(&auth_header)))
let changelog = crate::tools::runtime::block_on(client.get_string(changelog_url, Some(&auth_header)))
.map_err(|err| format_err!("Error downloading changelog from '{}': {}", changelog_url, err))?;
Ok(json!(changelog))

View File

@ -1,5 +1,4 @@
use anyhow::{Error, format_err, bail};
use lazy_static::lazy_static;
use std::task::{Context, Poll};
use std::os::unix::io::AsRawFd;
use std::collections::HashMap;
@ -21,50 +20,32 @@ use crate::tools::{
},
};
lazy_static! {
static ref HTTP_CLIENT: Client<HttpsConnector, Body> = {
let connector = SslConnector::builder(SslMethod::tls()).unwrap().build();
let httpc = HttpConnector::new();
let https = HttpsConnector::with_connector(httpc, connector);
Client::builder().build(https)
};
/// Asyncrounous HTTP client implementation
pub struct SimpleHttp {
client: Client<HttpsConnector, Body>,
}
pub async fn get_string(uri: &str, extra_headers: Option<&HashMap<String, String>>) -> Result<String, Error> {
let mut request = Request::builder()
.method("GET")
.uri(uri)
.header("User-Agent", "proxmox-backup-client/1.0");
impl SimpleHttp {
if let Some(hs) = extra_headers {
for (h, v) in hs.iter() {
request = request.header(h, v);
}
pub fn new() -> Self {
let ssl_connector = SslConnector::builder(SslMethod::tls()).unwrap().build();
Self::with_ssl_connector(ssl_connector)
}
let request = request.body(Body::empty())?;
let res = HTTP_CLIENT.request(request).await?;
let status = res.status();
if !status.is_success() {
bail!("Got bad status '{}' from server", status)
}
response_body_string(res).await
}
pub async fn response_body_string(res: Response<Body>) -> Result<String, Error> {
let buf = hyper::body::to_bytes(res).await?;
String::from_utf8(buf.to_vec())
.map_err(|err| format_err!("Error converting HTTP result data: {}", err))
pub fn with_ssl_connector(ssl_connector: SslConnector) -> Self {
let connector = HttpConnector::new();
let https = HttpsConnector::with_connector(connector, ssl_connector);
let client = Client::builder().build(https);
Self { client }
}
pub async fn post(
&mut self,
uri: &str,
body: Option<String>,
content_type: Option<&str>,
) -> Result<Response<Body>, Error> {
let body = if let Some(body) = body {
Body::from(body)
} else {
@ -79,12 +60,47 @@ pub async fn post(
.header(hyper::header::CONTENT_TYPE, content_type)
.body(body)?;
HTTP_CLIENT.request(request)
self.client.request(request)
.map_err(Error::from)
.await
}
pub async fn get_string(
&mut self,
uri: &str,
extra_headers: Option<&HashMap<String, String>>,
) -> Result<String, Error> {
let mut request = Request::builder()
.method("GET")
.uri(uri)
.header("User-Agent", "proxmox-backup-client/1.0");
if let Some(hs) = extra_headers {
for (h, v) in hs.iter() {
request = request.header(h, v);
}
}
let request = request.body(Body::empty())?;
let res = self.client.request(request).await?;
let status = res.status();
if !status.is_success() {
bail!("Got bad status '{}' from server", status)
}
Self::response_body_string(res).await
}
pub async fn response_body_string(res: Response<Body>) -> Result<String, Error> {
let buf = hyper::body::to_bytes(res).await?;
String::from_utf8(buf.to_vec())
.map_err(|err| format_err!("Error converting HTTP result data: {}", err))
}
}
#[derive(Clone)]
pub struct HttpsConnector {
http: HttpConnector,

View File

@ -6,8 +6,7 @@ use regex::Regex;
use proxmox::api::api;
use crate::tools;
use crate::tools::http;
use crate::tools::{self, http::SimpleHttp};
use proxmox::tools::fs::{replace_file, CreateOptions};
/// How long the local key is valid for in between remote checks
@ -102,10 +101,13 @@ async fn register_subscription(
"ip": "localhost",
"check_token": challenge,
});
let mut client = SimpleHttp::new();
let uri = "https://shop.maurer-it.com/modules/servers/licensing/verify.php";
let query = tools::json_object_to_query(params)?;
let response = http::post(uri, Some(query), Some("application/x-www-form-urlencoded")).await?;
let body = http::response_body_string(response).await?;
let response = client.post(uri, Some(query), Some("application/x-www-form-urlencoded")).await?;
let body = SimpleHttp::response_body_string(response).await?;
Ok((body, challenge))
}