[pbs-devel] [PATCH proxmox-backup 2/6] pbs-client: adapt http client to hyper/http 1.0

Fabian Grünbichler f.gruenbichler at proxmox.com
Wed Mar 26 16:23:23 CET 2025


similar changes to proxmox-http:
- Body to Incoming for incoming requests
- Body to proxmox-http's Body for everything else
- switch to "legacy" pooling client from hyper-util

Signed-off-by: Fabian Grünbichler <f.gruenbichler at proxmox.com>
---
 Cargo.toml                    |  8 ++++++--
 pbs-client/Cargo.toml         |  4 +++-
 pbs-client/src/http_client.rs | 30 +++++++++++++++++-------------
 3 files changed, 26 insertions(+), 16 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index d52566809..c30bad4fc 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -127,7 +127,9 @@ futures = "0.3"
 h2 = { version = "0.4", features = [ "stream" ] }
 handlebars = "3.0"
 hex = "0.4.3"
-hyper = { version = "0.14", features = [ "backports", "deprecated", "full" ] }
+http-body-util = "0.1"
+hyper-util = "0.1"
+hyper = { version = "1", features = [ "full" ] }
 libc = "0.2"
 log = "0.4.17"
 nix = "0.26.1"
@@ -172,7 +174,9 @@ endian_trait.workspace = true
 futures.workspace = true
 h2.workspace = true
 hex.workspace = true
+http-body-util.workspace = true
 hyper.workspace = true
+hyper-util = { workspace = true, features = ["server", "server-auto", "server-graceful"] }
 libc.workspace = true
 log.workspace = true
 nix.workspace = true
@@ -208,7 +212,7 @@ proxmox-auth-api = { workspace = true, features = [ "api", "pam-authenticator" ]
 proxmox-compression.workspace = true
 proxmox-config-digest.workspace = true
 proxmox-daemon.workspace = true
-proxmox-http = { workspace = true, features = [ "client-trait", "proxmox-async", "rate-limited-stream" ] } # pbs-client doesn't use these
+proxmox-http = { workspace = true, features = [ "body", "client-trait", "proxmox-async", "rate-limited-stream" ] } # pbs-client doesn't use these
 proxmox-human-byte.workspace = true
 proxmox-io.workspace = true
 proxmox-lang.workspace = true
diff --git a/pbs-client/Cargo.toml b/pbs-client/Cargo.toml
index c28fe87ca..84e73e7af 100644
--- a/pbs-client/Cargo.toml
+++ b/pbs-client/Cargo.toml
@@ -12,6 +12,8 @@ bytes.workspace = true
 futures.workspace = true
 h2.workspace = true
 hex.workspace = true
+http-body-util.workspace = true
+hyper-util = { workspace = true, features = ["client", "client-legacy", "http1", "http2", "tokio" ]}
 hyper.workspace = true
 libc.workspace = true
 nix.workspace = true
@@ -33,7 +35,7 @@ pathpatterns.workspace = true
 proxmox-async.workspace = true
 proxmox-auth-api.workspace = true
 proxmox-compression.workspace = true
-proxmox-http = { workspace = true, features = [ "rate-limiter" ] }
+proxmox-http = { workspace = true, features = [ "body", "rate-limiter" ] }
 proxmox-human-byte.workspace = true
 proxmox-io = { workspace = true, features = [ "tokio" ] }
 proxmox-log = { workspace = true }
diff --git a/pbs-client/src/http_client.rs b/pbs-client/src/http_client.rs
index 612e3b303..848575bb9 100644
--- a/pbs-client/src/http_client.rs
+++ b/pbs-client/src/http_client.rs
@@ -3,12 +3,15 @@ use std::sync::{Arc, Mutex, RwLock};
 use std::time::Duration;
 
 use anyhow::{bail, format_err, Error};
+use bytes::Bytes;
 use futures::*;
-use hyper::client::{Client, HttpConnector};
+use http_body_util::{BodyDataStream, BodyExt};
+use hyper::body::Incoming;
 use hyper::http::header::HeaderValue;
 use hyper::http::Uri;
 use hyper::http::{Request, Response};
-use hyper::{body::HttpBody, Body};
+use hyper_util::client::legacy::{connect::HttpConnector, Client};
+use hyper_util::rt::{TokioExecutor, TokioIo};
 use openssl::{
     ssl::{SslConnector, SslMethod},
     x509::X509StoreContextRef,
@@ -24,6 +27,7 @@ use proxmox_sys::linux::tty;
 use proxmox_async::broadcast_future::BroadcastFuture;
 use proxmox_http::client::HttpsConnector;
 use proxmox_http::uri::{build_authority, json_object_to_query};
+use proxmox_http::Body;
 use proxmox_http::{ProxyConfig, RateLimiter};
 use proxmox_log::{error, info, warn};
 
@@ -134,7 +138,7 @@ impl Default for HttpClientOptions {
 
 /// HTTP(S) API client
 pub struct HttpClient {
-    client: Client<HttpsConnector>,
+    client: Client<HttpsConnector, Body>,
     server: String,
     port: u16,
     fingerprint: Arc<Mutex<Option<String>>>,
@@ -398,7 +402,7 @@ impl HttpClient {
             https.set_proxy(config);
         }
 
-        let client = Client::builder()
+        let client = Client::builder(TokioExecutor::new())
             //.http2_initial_stream_window_size( (1 << 31) - 2)
             //.http2_initial_connection_window_size( (1 << 31) - 2)
             .build::<_, Body>(https);
@@ -706,7 +710,7 @@ impl HttpClient {
                 .map(|_| Err(format_err!("unknown error")))
                 .await?
         } else {
-            futures::TryStreamExt::map_err(resp.into_body(), Error::from)
+            futures::TryStreamExt::map_err(BodyDataStream::new(resp.into_body()), Error::from)
                 .try_fold(output, move |acc, chunk| async move {
                     acc.write_all(&chunk)?;
                     Ok::<_, Error>(acc)
@@ -786,7 +790,7 @@ impl HttpClient {
             bail!("unknown error");
         }
 
-        let upgraded = hyper::upgrade::on(resp).await?;
+        let upgraded = TokioIo::new(hyper::upgrade::on(resp).await?);
 
         let max_window_size = (1 << 31) - 2;
 
@@ -814,7 +818,7 @@ impl HttpClient {
     }
 
     async fn credentials(
-        client: Client<HttpsConnector>,
+        client: Client<HttpsConnector, Body>,
         server: String,
         port: u16,
         username: Userid,
@@ -841,9 +845,9 @@ impl HttpClient {
         Ok(auth)
     }
 
-    async fn api_response(response: Response<Body>) -> Result<Value, Error> {
+    async fn api_response(response: Response<Incoming>) -> Result<Value, Error> {
         let status = response.status();
-        let data = HttpBody::collect(response.into_body()).await?.to_bytes();
+        let data = response.into_body().collect().await?.to_bytes();
 
         let text = String::from_utf8(data.to_vec()).unwrap();
         if status.is_success() {
@@ -859,7 +863,7 @@ impl HttpClient {
     }
 
     async fn api_request(
-        client: Client<HttpsConnector>,
+        client: Client<HttpsConnector, Body>,
         req: Request<Body>,
     ) -> Result<Value, Error> {
         Self::api_response(
@@ -894,7 +898,7 @@ impl HttpClient {
                     .uri(url)
                     .header("User-Agent", "proxmox-backup-client/1.0")
                     .header(hyper::header::CONTENT_TYPE, "application/json")
-                    .body(Body::from(data.to_string()))?;
+                    .body(data.to_string().into())?;
                 Ok(request)
             } else {
                 let query = json_object_to_query(data)?;
@@ -935,11 +939,11 @@ impl Drop for HttpClient {
 
 #[derive(Clone)]
 pub struct H2Client {
-    h2: h2::client::SendRequest<bytes::Bytes>,
+    h2: h2::client::SendRequest<Bytes>,
 }
 
 impl H2Client {
-    pub fn new(h2: h2::client::SendRequest<bytes::Bytes>) -> Self {
+    pub fn new(h2: h2::client::SendRequest<Bytes>) -> Self {
         Self { h2 }
     }
 
-- 
2.39.5





More information about the pbs-devel mailing list