pub mod backoff;
#[cfg(test)]
pub mod mock_server;
#[cfg(any(feature = "aws", feature = "gcp", feature = "azure"))]
pub mod pagination;
pub mod retry;
#[cfg(any(feature = "aws", feature = "gcp", feature = "azure"))]
pub mod token;
use reqwest::header::{HeaderMap, HeaderValue};
use reqwest::{Client, ClientBuilder, Proxy};
use std::collections::HashMap;
use std::time::Duration;
use crate::path::Path;
fn map_client_error(e: reqwest::Error) -> super::Error {
super::Error::Generic {
store: "HTTP client",
source: Box::new(e),
}
}
static DEFAULT_USER_AGENT: &str =
concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),);
#[derive(Debug, Clone, Default)]
pub struct ClientOptions {
user_agent: Option<HeaderValue>,
content_type_map: HashMap<String, String>,
default_content_type: Option<String>,
default_headers: Option<HeaderMap>,
proxy_url: Option<String>,
allow_http: bool,
allow_insecure: bool,
timeout: Option<Duration>,
connect_timeout: Option<Duration>,
pool_idle_timeout: Option<Duration>,
pool_max_idle_per_host: Option<usize>,
http2_keep_alive_interval: Option<Duration>,
http2_keep_alive_timeout: Option<Duration>,
http2_keep_alive_while_idle: bool,
http1_only: bool,
http2_only: bool,
}
impl ClientOptions {
pub fn new() -> Self {
Default::default()
}
pub fn with_user_agent(mut self, agent: HeaderValue) -> Self {
self.user_agent = Some(agent);
self
}
pub fn with_default_content_type(mut self, mime: impl Into<String>) -> Self {
self.default_content_type = Some(mime.into());
self
}
pub fn with_content_type_for_suffix(
mut self,
extension: impl Into<String>,
mime: impl Into<String>,
) -> Self {
self.content_type_map.insert(extension.into(), mime.into());
self
}
pub fn with_default_headers(mut self, headers: HeaderMap) -> Self {
self.default_headers = Some(headers);
self
}
pub fn with_allow_http(mut self, allow_http: bool) -> Self {
self.allow_http = allow_http;
self
}
pub fn with_allow_invalid_certificates(mut self, allow_insecure: bool) -> Self {
self.allow_insecure = allow_insecure;
self
}
pub fn with_http1_only(mut self) -> Self {
self.http1_only = true;
self
}
pub fn with_http2_only(mut self) -> Self {
self.http2_only = true;
self
}
pub fn with_proxy_url(mut self, proxy_url: impl Into<String>) -> Self {
self.proxy_url = Some(proxy_url.into());
self
}
pub fn with_timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}
pub fn with_connect_timeout(mut self, timeout: Duration) -> Self {
self.connect_timeout = Some(timeout);
self
}
pub fn with_pool_idle_timeout(mut self, timeout: Duration) -> Self {
self.pool_idle_timeout = Some(timeout);
self
}
pub fn with_pool_max_idle_per_host(mut self, max: usize) -> Self {
self.pool_max_idle_per_host = Some(max);
self
}
pub fn with_http2_keep_alive_interval(mut self, interval: Duration) -> Self {
self.http2_keep_alive_interval = Some(interval);
self
}
pub fn with_http2_keep_alive_timeout(mut self, interval: Duration) -> Self {
self.http2_keep_alive_timeout = Some(interval);
self
}
pub fn with_http2_keep_alive_while_idle(mut self) -> Self {
self.http2_keep_alive_while_idle = true;
self
}
pub fn get_content_type(&self, path: &Path) -> Option<&str> {
match path.extension() {
Some(extension) => match self.content_type_map.get(extension) {
Some(ct) => Some(ct.as_str()),
None => self.default_content_type.as_deref(),
},
None => self.default_content_type.as_deref(),
}
}
pub(crate) fn client(&self) -> super::Result<Client> {
let mut builder = ClientBuilder::new();
match &self.user_agent {
Some(user_agent) => builder = builder.user_agent(user_agent),
None => builder = builder.user_agent(DEFAULT_USER_AGENT),
}
if let Some(headers) = &self.default_headers {
builder = builder.default_headers(headers.clone())
}
if let Some(proxy) = &self.proxy_url {
let proxy = Proxy::all(proxy).map_err(map_client_error)?;
builder = builder.proxy(proxy);
}
if let Some(timeout) = self.timeout {
builder = builder.timeout(timeout)
}
if let Some(timeout) = self.connect_timeout {
builder = builder.connect_timeout(timeout)
}
if let Some(timeout) = self.pool_idle_timeout {
builder = builder.pool_idle_timeout(timeout)
}
if let Some(max) = self.pool_max_idle_per_host {
builder = builder.pool_max_idle_per_host(max)
}
if let Some(interval) = self.http2_keep_alive_interval {
builder = builder.http2_keep_alive_interval(interval)
}
if let Some(interval) = self.http2_keep_alive_timeout {
builder = builder.http2_keep_alive_timeout(interval)
}
if self.http2_keep_alive_while_idle {
builder = builder.http2_keep_alive_while_idle(true)
}
if self.http1_only {
builder = builder.http1_only()
}
if self.http2_only {
builder = builder.http2_prior_knowledge()
}
if self.allow_insecure {
builder = builder.danger_accept_invalid_certs(self.allow_insecure)
}
builder
.https_only(!self.allow_http)
.build()
.map_err(map_client_error)
}
}