public inbox for pbs-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [pbs-devel] [PATCH proxmox-backup 1/2] HttpsConnector: add proxy authorization support
@ 2021-04-28  8:26 Dietmar Maurer
  2021-04-28  8:26 ` [pbs-devel] [PATCH proxmox-backup 2/2] http: add helper to parse proxy configuration Dietmar Maurer
  0 siblings, 1 reply; 2+ messages in thread
From: Dietmar Maurer @ 2021-04-28  8:26 UTC (permalink / raw)
  To: pbs-devel

---
 src/tools/http.rs | 49 +++++++++++++++++++++++++++++++++++------------
 1 file changed, 37 insertions(+), 12 deletions(-)

diff --git a/src/tools/http.rs b/src/tools/http.rs
index 016d7673..e36e6c51 100644
--- a/src/tools/http.rs
+++ b/src/tools/http.rs
@@ -7,7 +7,7 @@ use std::sync::Arc;
 
 use hyper::{Uri, Body};
 use hyper::client::{Client, HttpConnector};
-use http::{Request, Response};
+use http::{Request, Response, HeaderValue};
 use openssl::ssl::{SslConnector, SslMethod};
 use futures::*;
 use tokio::{
@@ -33,12 +33,14 @@ use crate::tools::{
 pub struct ProxyConfig {
     pub host: String,
     pub port: u16,
+    pub authorization: Option<String>, // Proxy-Authorization header value
     pub force_connect: bool,
 }
 
 /// Asyncrounous HTTP client implementation
 pub struct SimpleHttp {
     client: Client<HttpsConnector, Body>,
+    proxy_authorization: Option<String>, // Proxy-Authorization header value
 }
 
 impl SimpleHttp {
@@ -49,16 +51,39 @@ impl SimpleHttp {
     }
 
     pub fn with_ssl_connector(ssl_connector: SslConnector, proxy_config: Option<ProxyConfig>) -> Self {
+
+        let mut proxy_authorization = None;
+        if let Some(ref proxy_config) = proxy_config {
+            if !proxy_config.force_connect {
+               proxy_authorization = proxy_config.authorization.clone();
+            }
+        }
+
         let connector = HttpConnector::new();
         let mut https = HttpsConnector::with_connector(connector, ssl_connector);
         if let Some(proxy_config) = proxy_config {
             https.set_proxy(proxy_config);
         }
         let client = Client::builder().build(https);
-        Self { client }
+        Self { client, proxy_authorization}
+    }
+
+    fn add_proxy_headers(&self, request: &mut Request<Body>) -> Result<(), Error> {
+        if request.uri().scheme() != Some(&http::uri::Scheme::HTTPS) {
+            if let Some(ref authorization) = self.proxy_authorization {
+                request
+                    .headers_mut()
+                    .insert(
+                        http::header::PROXY_AUTHORIZATION,
+                        HeaderValue::from_str(authorization)?,
+                    );
+            }
+        }
+        Ok(())
     }
 
-    pub async fn request(&self, request: Request<Body>) -> Result<Response<Body>, Error> {
+    pub async fn request(&self, mut request: Request<Body>) -> Result<Response<Body>, Error> {
+        self.add_proxy_headers(&mut request)?;
         self.client.request(request)
             .map_err(Error::from)
             .await
@@ -85,9 +110,7 @@ impl SimpleHttp {
             .header(hyper::header::CONTENT_TYPE, content_type)
             .body(body)?;
 
-        self.client.request(request)
-            .map_err(Error::from)
-            .await
+        self.request(request).await
     }
 
     pub async fn get_string(
@@ -109,7 +132,7 @@ impl SimpleHttp {
 
         let request = request.body(Body::empty())?;
 
-        let res = self.client.request(request).await?;
+        let res = self.request(request).await?;
 
         let status = res.status();
         if !status.is_success() {
@@ -240,6 +263,8 @@ impl hyper::service::Service<Uri> for HttpsConnector {
                 Err(err) => return futures::future::err(err.into()).boxed(),
             };
 
+            let authorization = proxy.authorization.clone();
+
             if use_connect {
                 async move {
 
@@ -250,11 +275,11 @@ impl hyper::service::Service<Uri> for HttpsConnector {
 
                     let _ = set_tcp_keepalive(tcp_stream.as_raw_fd(), PROXMOX_BACKUP_TCP_KEEPALIVE_TIME);
 
-                    let connect_request = format!(
-                        "CONNECT {0}:{1} HTTP/1.1\r\n\
-                         Host: {0}:{1}\r\n\r\n",
-                        host, port,
-                    );
+                    let mut connect_request = format!("CONNECT {0}:{1} HTTP/1.1\r\n", host, port);
+                    if let Some(authorization) = authorization {
+                        connect_request.push_str(&format!("Proxy-Authorization: {}\r\n", authorization));
+                    }
+                    connect_request.push_str(&format!("Host: {0}:{1}\r\n\r\n", host, port));
 
                     tcp_stream.write_all(connect_request.as_bytes()).await?;
                     tcp_stream.flush().await?;
-- 
2.20.1




^ permalink raw reply	[flat|nested] 2+ messages in thread

* [pbs-devel] [PATCH proxmox-backup 2/2] http: add helper to parse proxy configuration
  2021-04-28  8:26 [pbs-devel] [PATCH proxmox-backup 1/2] HttpsConnector: add proxy authorization support Dietmar Maurer
@ 2021-04-28  8:26 ` Dietmar Maurer
  0 siblings, 0 replies; 2+ messages in thread
From: Dietmar Maurer @ 2021-04-28  8:26 UTC (permalink / raw)
  To: pbs-devel

---
 src/tools/http.rs | 62 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)

diff --git a/src/tools/http.rs b/src/tools/http.rs
index e36e6c51..f4ccefc9 100644
--- a/src/tools/http.rs
+++ b/src/tools/http.rs
@@ -37,6 +37,68 @@ pub struct ProxyConfig {
     pub force_connect: bool,
 }
 
+impl ProxyConfig {
+
+    /// Parse proxy config from ALL_PROXY environment var
+    pub fn from_proxy_env() -> Result<Option<ProxyConfig>, Error> {
+
+        // We only support/use ALL_PROXY environment
+
+        match std::env::var_os("ALL_PROXY") {
+            None => return Ok(None),
+            Some(all_proxy) => {
+                let all_proxy = match all_proxy.to_str() {
+                    Some(s) => String::from(s),
+                    None => bail!("non UTF-8 content in env ALL_PROXY"),
+                };
+                if all_proxy.is_empty() {
+                    return Ok(None);
+                }
+                let config = Self::parse_proxy_url(&all_proxy)?;
+                Ok(Some(config))
+            }
+        }
+    }
+
+    /// Parse proxy configuration string [http://]<host>[:port]
+    ///
+    /// Default port is 1080 (like curl)
+    pub fn parse_proxy_url(http_proxy: &str) -> Result<ProxyConfig, Error> {
+        proxmox::try_block!({
+            let proxy_uri: Uri = http_proxy.parse()?;
+            let proxy_authority = match proxy_uri.authority() {
+                Some(authority) => authority,
+                None => bail!("missing proxy authority"),
+            };
+            let host = proxy_authority.host().to_owned();
+            let port = match proxy_uri.port() {
+                Some(port) => port.as_u16(),
+                None => 1080, // CURL default port
+            };
+
+            match proxy_uri.scheme_str() {
+                Some("http") => { /* Ok */ }
+                Some(scheme) => bail!("unsupported proxy scheme '{}'", scheme),
+                None => { /* assume HTTP */ }
+            }
+
+            let authority_vec: Vec<&str> = proxy_authority.as_str().rsplitn(2, '@').collect();
+            let authorization = if authority_vec.len() == 2 {
+                Some(format!("Basic {}", base64::encode(authority_vec[1])))
+            } else {
+                None
+            };
+
+            Ok(ProxyConfig {
+                host,
+                port,
+                authorization,
+                force_connect: false,
+            })
+        }).map_err(|err| format_err!("parse_proxy_url failed: {}", err))
+    }
+}
+
 /// Asyncrounous HTTP client implementation
 pub struct SimpleHttp {
     client: Client<HttpsConnector, Body>,
-- 
2.20.1




^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2021-04-28  8:26 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-28  8:26 [pbs-devel] [PATCH proxmox-backup 1/2] HttpsConnector: add proxy authorization support Dietmar Maurer
2021-04-28  8:26 ` [pbs-devel] [PATCH proxmox-backup 2/2] http: add helper to parse proxy configuration Dietmar Maurer

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