cleanup: split SimpleHttp client into extra file

This commit is contained in:
Dietmar Maurer 2021-05-06 10:20:53 +02:00
parent b7b9a57425
commit e5ef69ecf7
6 changed files with 147 additions and 135 deletions

View File

@ -19,7 +19,7 @@ use proxmox_acme_rs::{Account, Authorization, Challenge, Directory, Error, Error
use crate::api2::types::AcmeAccountName; use crate::api2::types::AcmeAccountName;
use crate::config::acme::account_path; use crate::config::acme::account_path;
use crate::tools::http::SimpleHttp; use crate::tools::SimpleHttp;
/// Our on-disk format inherited from PVE's proxmox-acme code. /// Our on-disk format inherited from PVE's proxmox-acme code.
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]

View File

@ -7,7 +7,7 @@ use proxmox::api::{api, RpcEnvironment, RpcEnvironmentType, Permission};
use proxmox::api::router::{Router, SubdirMap}; use proxmox::api::router::{Router, SubdirMap};
use crate::server::WorkerTask; use crate::server::WorkerTask;
use crate::tools::{apt, http::SimpleHttp, subscription}; use crate::tools::{apt, SimpleHttp, subscription};
use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY}; use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
use crate::api2::types::{Authid, APTUpdateInfo, NODE_SCHEMA, UPID_SCHEMA}; use crate::api2::types::{Authid, APTUpdateInfo, NODE_SCHEMA, UPID_SCHEMA};

View File

@ -32,6 +32,10 @@ pub mod format;
pub mod fs; pub mod fs;
pub mod fuse_loop; pub mod fuse_loop;
pub mod http; pub mod http;
mod simple_http_client;
pub use simple_http_client::SimpleHttp;
pub mod json; pub mod json;
pub mod logrotate; pub mod logrotate;
pub mod loopdev; pub mod loopdev;

View File

@ -1,14 +1,12 @@
use anyhow::{Error, format_err, bail}; use anyhow::{Error, format_err, bail};
use std::task::{Context, Poll}; use std::task::{Context, Poll};
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
use std::collections::HashMap;
use std::pin::Pin; use std::pin::Pin;
use std::sync::Arc; use std::sync::Arc;
use hyper::Body; use hyper::client::HttpConnector;
use hyper::client::{Client, HttpConnector}; use http::{Uri, uri::Authority};
use http::{Uri, uri::Authority, Request, Response, HeaderValue}; use openssl::ssl::SslConnector;
use openssl::ssl::{SslConnector, SslMethod};
use futures::*; use futures::*;
use tokio::{ use tokio::{
io::{ io::{
@ -111,133 +109,6 @@ impl ProxyConfig {
} }
} }
/// Asyncrounous HTTP client implementation
pub struct SimpleHttp {
client: Client<HttpsConnector, Body>,
proxy_authorization: Option<String>, // Proxy-Authorization header value
user_agent: Option<String>,
}
impl SimpleHttp {
pub const DEFAULT_USER_AGENT_STRING: &'static str = "proxmox-backup-client/1.0";
pub fn new(proxy_config: Option<ProxyConfig>) -> Self {
let ssl_connector = SslConnector::builder(SslMethod::tls()).unwrap().build();
Self::with_ssl_connector(ssl_connector, proxy_config)
}
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, proxy_authorization, user_agent: None }
}
pub fn set_user_agent(&mut self, user_agent: &str) -> Result<(), Error> {
self.user_agent = Some(user_agent.to_owned());
Ok(())
}
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, mut request: Request<Body>) -> Result<Response<Body>, Error> {
let user_agent = if let Some(ref user_agent) = self.user_agent {
HeaderValue::from_str(&user_agent)?
} else {
HeaderValue::from_str(Self::DEFAULT_USER_AGENT_STRING)?
};
request.headers_mut().insert(hyper::header::USER_AGENT, user_agent);
self.add_proxy_headers(&mut request)?;
self.client.request(request)
.map_err(Error::from)
.await
}
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(hyper::header::CONTENT_TYPE, content_type)
.body(body)?;
self.request(request).await
}
pub async fn get_string(
&mut self,
uri: &str,
extra_headers: Option<&HashMap<String, String>>,
) -> Result<String, Error> {
let mut request = Request::builder()
.method("GET")
.uri(uri);
if let Some(hs) = extra_headers {
for (h, v) in hs.iter() {
request = request.header(h, v);
}
}
let request = request.body(Body::empty())?;
let res = self.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)] #[derive(Clone)]
pub struct HttpsConnector { pub struct HttpsConnector {
connector: HttpConnector, connector: HttpConnector,

View File

@ -0,0 +1,137 @@
use anyhow::{Error, format_err, bail};
use std::collections::HashMap;
use hyper::Body;
use hyper::client::{Client, HttpConnector};
use http::{Request, Response, HeaderValue};
use openssl::ssl::{SslConnector, SslMethod};
use futures::*;
use crate::tools::http::{HttpsConnector, ProxyConfig};
/// Asyncrounous HTTP client implementation
pub struct SimpleHttp {
client: Client<HttpsConnector, Body>,
proxy_authorization: Option<String>, // Proxy-Authorization header value
user_agent: Option<String>,
}
impl SimpleHttp {
pub const DEFAULT_USER_AGENT_STRING: &'static str = "proxmox-backup-client/1.0";
pub fn new(proxy_config: Option<ProxyConfig>) -> Self {
let ssl_connector = SslConnector::builder(SslMethod::tls()).unwrap().build();
Self::with_ssl_connector(ssl_connector, proxy_config)
}
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, proxy_authorization, user_agent: None }
}
pub fn set_user_agent(&mut self, user_agent: &str) -> Result<(), Error> {
self.user_agent = Some(user_agent.to_owned());
Ok(())
}
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, mut request: Request<Body>) -> Result<Response<Body>, Error> {
let user_agent = if let Some(ref user_agent) = self.user_agent {
HeaderValue::from_str(&user_agent)?
} else {
HeaderValue::from_str(Self::DEFAULT_USER_AGENT_STRING)?
};
request.headers_mut().insert(hyper::header::USER_AGENT, user_agent);
self.add_proxy_headers(&mut request)?;
self.client.request(request)
.map_err(Error::from)
.await
}
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(hyper::header::CONTENT_TYPE, content_type)
.body(body)?;
self.request(request).await
}
pub async fn get_string(
&mut self,
uri: &str,
extra_headers: Option<&HashMap<String, String>>,
) -> Result<String, Error> {
let mut request = Request::builder()
.method("GET")
.uri(uri);
if let Some(hs) = extra_headers {
for (h, v) in hs.iter() {
request = request.header(h, v);
}
}
let request = request.body(Body::empty())?;
let res = self.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))
}
}

View File

@ -6,7 +6,7 @@ use regex::Regex;
use proxmox::api::api; use proxmox::api::api;
use crate::tools::{self, http::SimpleHttp}; use crate::tools::{self, SimpleHttp};
use proxmox::tools::fs::{replace_file, CreateOptions}; use proxmox::tools::fs::{replace_file, CreateOptions};
/// How long the local key is valid for in between remote checks /// How long the local key is valid for in between remote checks