use std::time::Duration;
#[derive(Debug, Clone, Default)]
pub struct HttpClientConfig {
pub proxy: Option<String>,
pub insecure_tls: bool,
pub timeout: Option<Duration>,
pub ua_suffix: Option<String>,
}
impl HttpClientConfig {
pub fn effective_proxy(&self) -> Option<String> {
if let Some(p) = &self.proxy {
return Some(p.clone());
}
if let Ok(p) = std::env::var("KEYHOG_PROXY") {
if !p.is_empty() {
return Some(p);
}
}
None
}
pub fn effective_insecure_tls(&self) -> bool {
if self.insecure_tls {
return true;
}
matches!(
std::env::var("KEYHOG_INSECURE_TLS").as_deref(),
Ok("1") | Ok("true") | Ok("TRUE")
)
}
}
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
const REDIRECT_LIMIT: usize = 5;
pub(crate) fn user_agent(suffix: Option<&str>) -> String {
let base = concat!("keyhog/", env!("CARGO_PKG_VERSION"));
match suffix {
Some(s) if !s.is_empty() => format!("{base} ({s})"),
_ => base.to_string(),
}
}
#[cfg(any(feature = "web", feature = "github", feature = "slack", feature = "s3"))]
pub fn blocking_client_builder(
cfg: &HttpClientConfig,
) -> Result<reqwest::blocking::ClientBuilder, String> {
let mut builder = reqwest::blocking::Client::builder()
.timeout(cfg.timeout.unwrap_or(DEFAULT_TIMEOUT))
.redirect(reqwest::redirect::Policy::limited(REDIRECT_LIMIT))
.user_agent(user_agent(cfg.ua_suffix.as_deref()))
.no_gzip()
.no_brotli()
.no_deflate()
.danger_accept_invalid_certs(cfg.effective_insecure_tls());
match cfg.effective_proxy().as_deref() {
Some("off") | Some("none") | Some("") => {
builder = builder.no_proxy();
}
Some(url) => {
let proxy = reqwest::Proxy::all(url)
.map_err(|e| format!("invalid --proxy / KEYHOG_PROXY URL {url:?}: {e}"))?;
builder = builder.proxy(proxy);
}
None => {
}
}
Ok(builder)
}
#[cfg(any(feature = "web", feature = "github", feature = "slack", feature = "s3"))]
pub fn async_client_builder(cfg: &HttpClientConfig) -> Result<reqwest::ClientBuilder, String> {
let mut builder = reqwest::Client::builder()
.timeout(cfg.timeout.unwrap_or(DEFAULT_TIMEOUT))
.redirect(reqwest::redirect::Policy::limited(REDIRECT_LIMIT))
.user_agent(user_agent(cfg.ua_suffix.as_deref()))
.danger_accept_invalid_certs(cfg.effective_insecure_tls());
match cfg.effective_proxy().as_deref() {
Some("off") | Some("none") | Some("") => {
builder = builder.no_proxy();
}
Some(url) => {
let proxy = reqwest::Proxy::all(url)
.map_err(|e| format!("invalid --proxy / KEYHOG_PROXY URL {url:?}: {e}"))?;
builder = builder.proxy(proxy);
}
None => {}
}
Ok(builder)
}