public inbox for pbs-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Dietmar Maurer <dietmar@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [RFC proxmox-backup 3/5] new http client implementation SimpleHttp (avoid static HTTP_CLIENT)
Date: Wed, 21 Apr 2021 13:17:00 +0200	[thread overview]
Message-ID: <20210421111702.19095-4-dietmar@proxmox.com> (raw)
In-Reply-To: <20210421111702.19095-1-dietmar@proxmox.com>

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<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?;
+    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<String>,
+        content_type: Option<&str>,
+    ) -> Result<Response<Body>, 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<String, String>>,
+    ) -> Result<String, Error> {
 
-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))
-}
+        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<String>,
-    content_type: Option<&str>,
-) -> Result<Response<Body>, 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<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)]
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




  parent reply	other threads:[~2021-04-21 11:17 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-04-21 11:16 [pbs-devel] [RFC proxmox-backup 0/5] proxy support for HttpsConnector Dietmar Maurer
2021-04-21 11:16 ` [pbs-devel] [RFC proxmox-backup 1/5] http: rename EitherStream to MaybeTlsStream Dietmar Maurer
2021-04-21 11:16 ` [pbs-devel] [RFC proxmox-backup 2/5] MaybeTlsStream: implement poll_write_vectored() Dietmar Maurer
2021-04-21 11:17 ` Dietmar Maurer [this message]
2021-04-21 11:17 ` [pbs-devel] [RFC proxmox-backup 4/5] HttpsConnector: code cleanup Dietmar Maurer
2021-04-21 11:17 ` [pbs-devel] [RFC proxmox-backup 5/5] HttpsConnector: add proxy support Dietmar Maurer
2021-04-21 12:12 ` [pbs-devel] [RFC proxmox-backup 0/5] proxy support for HttpsConnector Wolfgang Bumiller
2021-04-21 14:33 ` [pbs-devel] applied-series: " Thomas Lamprecht

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210421111702.19095-4-dietmar@proxmox.com \
    --to=dietmar@proxmox.com \
    --cc=pbs-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal