use reqwest::Client;
use std::collections::HashMap;
use std::time::Duration;
pub(crate) const REQUEST_TIMEOUT: Duration = Duration::from_secs(120);
const CONNECT_TIMEOUT: Duration = Duration::from_secs(30);
const TCP_KEEPALIVE: Duration = Duration::from_secs(30);
const POOL_MAX_IDLE_PER_HOST: usize = 32;
pub(crate) fn build_http_client(
request_timeout: Option<Duration>,
custom_headers: Option<&HashMap<String, String>>,
) -> Client {
let mut builder = Client::builder()
.no_proxy()
.connect_timeout(CONNECT_TIMEOUT)
.pool_max_idle_per_host(POOL_MAX_IDLE_PER_HOST)
.tcp_keepalive(TCP_KEEPALIVE);
if let Some(timeout) = request_timeout {
builder = builder.timeout(timeout);
}
let mut default_headers = reqwest::header::HeaderMap::new();
if let Some(headers) = custom_headers {
for (k, v) in headers {
let name = match reqwest::header::HeaderName::from_bytes(k.as_bytes()) {
Ok(n) => n,
Err(_) => {
tracing::warn!(header = %k, "skipping invalid custom header name");
continue;
}
};
let val = match reqwest::header::HeaderValue::from_str(v) {
Ok(v) => v,
Err(_) => {
tracing::warn!(header = %k, "skipping custom header with invalid value");
continue;
}
};
default_headers.insert(name, val);
}
}
builder = builder.default_headers(default_headers);
builder.build().unwrap_or_else(|_| Client::new())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn builds_hosted_client_with_overall_timeout() {
let _ = build_http_client(Some(REQUEST_TIMEOUT), None);
}
#[test]
fn builds_local_client_without_overall_timeout() {
let _ = build_http_client(None, None);
}
}