From f3ddce5297fa168c6d4fcb0d46b07f34109d85d9 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Tue, 1 Feb 2022 08:09:44 +0100 Subject: [PATCH] use ureq (with native-tls) instead of curl Signed-off-by: Dietmar Maurer --- Cargo.toml | 5 +- debian/control | 14 ++++-- src/http_client.rs | 123 ++++++++++++++++++++------------------------- 3 files changed, 67 insertions(+), 75 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5f322a98..e13fe9b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,12 +16,13 @@ path = "src/lib.rs" [dependencies] anyhow = "1.0" -curl = { version = "0.4.33" } http = "0.2" nix = "0.19.1" -openidconnect = { version = "2.1", default-features = false, features = ["curl"] } +openidconnect = { version = "2.2", default-features = false, features = [] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +thiserror="1.0" +ureq = { version = "2.4", features = ["native-tls"] } url = "2.1" proxmox-time = "1" diff --git a/debian/control b/debian/control index f7748eb4..992dfed0 100644 --- a/debian/control +++ b/debian/control @@ -2,20 +2,22 @@ Source: rust-proxmox-openid Section: rust Priority: optional Build-Depends: debhelper (>= 12), - dh-cargo (>= 24), + dh-cargo (>= 25), cargo:native , rustc:native , libstd-rust-dev , librust-anyhow-1+default-dev , - librust-curl-0.4+default-dev (>= 0.4.33-~~) , librust-http-0.2+default-dev , librust-nix-0.19+default-dev (>= 0.19.1-~~) , - librust-openidconnect-2+curl-dev (>= 2.1-~~) , + librust-openidconnect-2-dev (>= 2.2-~~) , librust-proxmox-sys-0.2+default-dev , librust-proxmox-time-1+default-dev , librust-serde-1+default-dev , librust-serde-1+derive-dev , librust-serde-json-1+default-dev , + librust-thiserror-1+default-dev , + librust-ureq-2+default-dev (>= 2.4-~~) , + librust-ureq-2+native-tls-dev (>= 2.4-~~) , librust-url-2+default-dev (>= 2.1-~~) Maintainer: Proxmox Support Team Standards-Version: 4.5.1 @@ -29,15 +31,17 @@ Multi-Arch: same Depends: ${misc:Depends}, librust-anyhow-1+default-dev, - librust-curl-0.4+default-dev (>= 0.4.33-~~), librust-http-0.2+default-dev, librust-nix-0.19+default-dev (>= 0.19.1-~~), - librust-openidconnect-2+curl-dev (>= 2.1-~~), + librust-openidconnect-2-dev (>= 2.2-~~), librust-proxmox-sys-0.2+default-dev, librust-proxmox-time-1+default-dev, librust-serde-1+default-dev, librust-serde-1+derive-dev, librust-serde-json-1+default-dev, + librust-thiserror-1+default-dev, + librust-ureq-2+default-dev (>= 2.4-~~), + librust-ureq-2+native-tls-dev (>= 2.4-~~), librust-url-2+default-dev (>= 2.1-~~) Provides: librust-proxmox-openid+default-dev (= ${binary:Version}), diff --git a/src/http_client.rs b/src/http_client.rs index f07aed0d..89a720fb 100644 --- a/src/http_client.rs +++ b/src/http_client.rs @@ -1,6 +1,3 @@ -use std::io::Read; - -use curl::easy::Easy; use http::header::{HeaderMap, HeaderValue, CONTENT_TYPE}; use http::method::Method; use http::status::StatusCode; @@ -10,83 +7,73 @@ use openidconnect::{ HttpResponse, }; -/// Synchronous Curl HTTP client. +// Copied from OAuth2 create, because we want to use ureq with +// native-tls. But current OAuth2 crate pulls in rustls, so we cannot +// use their 'ureq' feature. + /// -/// Copied fron OAuth2 create, added fix https://github.com/ramosbugs/oauth2-rs/pull/147 -pub fn http_client(request: HttpRequest) -> Result { +/// Error type returned by failed ureq HTTP requests. +/// +#[derive(Debug, thiserror::Error)] +pub enum Error { + /// Non-ureq HTTP error. + #[error("HTTP error")] + Http(#[from] http::Error), + /// IO error + #[error("IO error")] + IO(#[from] std::io::Error), + /// Other error. + #[error("Other error: {}", _0)] + Other(String), + /// Error returned by ureq crate. + // boxed due to https://github.com/algesten/ureq/issues/296 + #[error("ureq request failed")] + Ureq(#[from] Box), +} - use openidconnect::curl::Error; - - let mut easy = Easy::new(); - easy.url(&request.url.to_string()[..]) - .map_err(Error::Curl)?; +/// +/// Synchronous HTTP client for ureq. +/// +pub fn http_client(request: HttpRequest) -> Result { + let mut req = if let Method::POST = request.method { + ureq::post(&request.url.to_string()) + } else { + ureq::get(&request.url.to_string()) + }; - let mut headers = curl::easy::List::new(); - request - .headers - .iter() - .map(|(name, value)| { - headers - .append(&format!( - "{}: {}", - name, - value.to_str().map_err(|_| Error::Other(format!( + for (name, value) in request.headers { + if let Some(name) = name { + req = req.set( + &name.to_string(), + value.to_str().map_err(|_| { + Error::Other(format!( "invalid {} header value {:?}", name, value.as_bytes() - )))? - )) - .map_err(Error::Curl) - }) - .collect::>()?; + )) + })?, + ); + } + } - easy.http_headers(headers).map_err(Error::Curl)?; - - if let Method::POST = request.method { - easy.post(true).map_err(Error::Curl)?; - easy.post_field_size(request.body.len() as u64) - .map_err(Error::Curl)?; + let response = if let Method::POST = request.method { + req.send(&*request.body) } else { - assert_eq!(request.method, Method::GET); + req.call() } + .map_err(Box::new)?; - let mut form_slice = &request.body[..]; - let mut data = Vec::new(); - { - let mut transfer = easy.transfer(); + let status_code = StatusCode::from_u16(response.status()) + .map_err(|err| Error::Http(err.into()))?; - transfer - .read_function(|buf| Ok(form_slice.read(buf).unwrap_or(0))) - .map_err(Error::Curl)?; - - transfer - .write_function(|new_data| { - data.extend_from_slice(new_data); - Ok(new_data.len()) - }) - .map_err(Error::Curl)?; - - transfer.perform().map_err(Error::Curl)?; - } - - let status_code = easy.response_code().map_err(Error::Curl)? as u16; + let content_type = HeaderValue::from_str(response.content_type()) + .map_err(|err| Error::Http(err.into()))?; Ok(HttpResponse { - status_code: StatusCode::from_u16(status_code).map_err(|err| Error::Http(err.into()))?, - headers: easy - .content_type() - .map_err(Error::Curl)? - .map(|content_type| { - Ok(vec![( - CONTENT_TYPE, - HeaderValue::from_str(content_type).map_err(|err| Error::Http(err.into()))?, - )] - .into_iter() - .collect::()) - }) - .transpose()? - .unwrap_or_else(HeaderMap::new), - body: data, + status_code, + headers: vec![(CONTENT_TYPE, content_type)] + .into_iter() + .collect::(), + body: response.into_string()?.as_bytes().into(), }) } -