From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 4267B751BA for ; Wed, 21 Apr 2021 13:17:08 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 36E1BDC81 for ; Wed, 21 Apr 2021 13:17:08 +0200 (CEST) Received: from elsa.proxmox.com (unknown [94.136.29.99]) by firstgate.proxmox.com (Proxmox) with ESMTP id 97875DC66 for ; Wed, 21 Apr 2021 13:17:04 +0200 (CEST) Received: by elsa.proxmox.com (Postfix, from userid 0) id 80D6AAEB09B; Wed, 21 Apr 2021 13:17:04 +0200 (CEST) From: Dietmar Maurer To: pbs-devel@lists.proxmox.com Date: Wed, 21 Apr 2021 13:17:00 +0200 Message-Id: <20210421111702.19095-4-dietmar@proxmox.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210421111702.19095-1-dietmar@proxmox.com> References: <20210421111702.19095-1-dietmar@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 1 AWL -0.027 Adjusted score from AWL reputation of From: address KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment RDNS_NONE 1.274 Delivered to internal network by a host with no rDNS SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [apt.rs, maurer-it.com, http.rs, proxmox.com, subscription.rs] Subject: [pbs-devel] [RFC proxmox-backup 3/5] new http client implementation SimpleHttp (avoid static HTTP_CLIENT) X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 21 Apr 2021 11:17:08 -0000 This one will have proxy support. --- src/api2/node/apt.rs | 8 ++- src/tools/http.rs | 122 +++++++++++++++++++++----------------- src/tools/subscription.rs | 10 ++-- 3 files changed, 80 insertions(+), 60 deletions(-) diff --git a/src/api2/node/apt.rs b/src/api2/node/apt.rs index e77b89fa..dbdb2019 100644 --- a/src/api2/node/apt.rs +++ b/src/api2/node/apt.rs @@ -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)) diff --git a/src/tools/http.rs b/src/tools/http.rs index 3cd3af4e..f19d6527 100644 --- a/src/tools/http.rs +++ b/src/tools/http.rs @@ -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,68 +20,85 @@ use crate::tools::{ }, }; -lazy_static! { - static ref HTTP_CLIENT: Client = { - 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, } -pub async fn get_string(uri: &str, extra_headers: Option<&HashMap>) -> Result { - 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?; + 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 } + } - let status = res.status(); - if !status.is_success() { - bail!("Got bad status '{}' from server", status) + pub async fn post( + &mut self, + uri: &str, + body: Option, + content_type: Option<&str>, + ) -> Result, Error> { + + let body = if let Some(body) = body { + Body::from(body) + } else { + Body::empty() + }; + let content_type = content_type.unwrap_or("application/json"); + + let request = Request::builder() + .method("POST") + .uri(uri) + .header("User-Agent", "proxmox-backup-client/1.0") + .header(hyper::header::CONTENT_TYPE, content_type) + .body(body)?; + + self.client.request(request) + .map_err(Error::from) + .await } - response_body_string(res).await -} + pub async fn get_string( + &mut self, + uri: &str, + extra_headers: Option<&HashMap>, + ) -> Result { -pub async fn response_body_string(res: Response) -> Result { - 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)) -} + 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); + } + } -pub async fn post( - uri: &str, - body: Option, - content_type: Option<&str>, -) -> Result, Error> { - let body = if let Some(body) = body { - Body::from(body) - } else { - Body::empty() - }; - let content_type = content_type.unwrap_or("application/json"); - - let request = Request::builder() - .method("POST") - .uri(uri) - .header("User-Agent", "proxmox-backup-client/1.0") - .header(hyper::header::CONTENT_TYPE, content_type) - .body(body)?; - - - HTTP_CLIENT.request(request) - .map_err(Error::from) - .await + 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) -> Result { + 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)] diff --git a/src/tools/subscription.rs b/src/tools/subscription.rs index 9b9534ac..9a920aee 100644 --- a/src/tools/subscription.rs +++ b/src/tools/subscription.rs @@ -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)) } -- 2.20.1