use std::iter::FromIterator;
use std::net::SocketAddr;
use std::path::PathBuf;
use std::time::Duration;
pub(crate) trait SetOpt {
fn set_opt<H>(&self, easy: &mut curl::easy::Easy2<H>) -> Result<(), curl::Error>;
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RedirectPolicy {
None,
Follow,
Limit(u32),
}
impl Default for RedirectPolicy {
fn default() -> Self {
RedirectPolicy::None
}
}
impl SetOpt for RedirectPolicy {
fn set_opt<H>(&self, easy: &mut curl::easy::Easy2<H>) -> Result<(), curl::Error> {
match self {
RedirectPolicy::Follow => {
easy.follow_location(true)?;
}
RedirectPolicy::Limit(max) => {
easy.follow_location(true)?;
easy.max_redirections(*max)?;
}
RedirectPolicy::None => {
easy.follow_location(false)?;
}
}
Ok(())
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ClientCertificate {
PEM {
path: PathBuf,
private_key: Option<PrivateKey>,
},
DER {
path: PathBuf,
private_key: Option<PrivateKey>,
},
P12 {
path: PathBuf,
password: Option<String>,
},
}
impl SetOpt for ClientCertificate {
fn set_opt<H>(&self, easy: &mut curl::easy::Easy2<H>) -> Result<(), curl::Error> {
match self {
ClientCertificate::PEM { path, private_key } => {
easy.ssl_cert(path)?;
easy.ssl_cert_type("PEM")?;
if let Some(key) = private_key {
key.set_opt(easy)?;
}
}
ClientCertificate::DER { path, private_key } => {
easy.ssl_cert(path)?;
easy.ssl_cert_type("DER")?;
if let Some(key) = private_key {
key.set_opt(easy)?;
}
}
ClientCertificate::P12 { path, password } => {
easy.ssl_cert(path)?;
easy.ssl_cert_type("P12")?;
if let Some(password) = password {
easy.key_password(password)?;
}
}
}
Ok(())
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum PrivateKey {
PEM {
path: PathBuf,
password: Option<String>,
},
DER {
path: PathBuf,
password: Option<String>,
},
}
impl SetOpt for PrivateKey {
fn set_opt<H>(&self, easy: &mut curl::easy::Easy2<H>) -> Result<(), curl::Error> {
match self {
PrivateKey::PEM { path, password } => {
easy.ssl_key(path)?;
easy.ssl_key_type("PEM")?;
if let Some(password) = password {
easy.key_password(password)?;
}
}
PrivateKey::DER { path, password } => {
easy.ssl_key(path)?;
easy.ssl_key_type("DER")?;
if let Some(password) = password {
easy.key_password(password)?;
}
}
}
Ok(())
}
}
#[derive(Clone, Debug)]
pub(crate) struct Timeout(pub(crate) Duration);
impl SetOpt for Timeout {
fn set_opt<H>(&self, easy: &mut curl::easy::Easy2<H>) -> Result<(), curl::Error> {
easy.timeout(self.0)
}
}
#[derive(Clone, Debug)]
pub(crate) struct ConnectTimeout(pub(crate) Duration);
impl SetOpt for ConnectTimeout {
fn set_opt<H>(&self, easy: &mut curl::easy::Easy2<H>) -> Result<(), curl::Error> {
easy.connect_timeout(self.0)
}
}
#[derive(Clone, Debug)]
pub(crate) struct TcpKeepAlive(pub(crate) Duration);
impl SetOpt for TcpKeepAlive {
fn set_opt<H>(&self, easy: &mut curl::easy::Easy2<H>) -> Result<(), curl::Error> {
easy.tcp_keepalive(true)?;
easy.tcp_keepintvl(self.0)
}
}
#[derive(Clone, Debug)]
pub(crate) struct PreferredHttpVersion(pub(crate) http::Version);
impl SetOpt for PreferredHttpVersion {
fn set_opt<H>(&self, easy: &mut curl::easy::Easy2<H>) -> Result<(), curl::Error> {
easy.http_version(match self.0 {
http::Version::HTTP_10 => curl::easy::HttpVersion::V10,
http::Version::HTTP_11 => curl::easy::HttpVersion::V11,
http::Version::HTTP_2 => curl::easy::HttpVersion::V2,
_ => curl::easy::HttpVersion::Any,
})
}
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct TcpNoDelay;
impl SetOpt for TcpNoDelay {
fn set_opt<H>(&self, easy: &mut curl::easy::Easy2<H>) -> Result<(), curl::Error> {
easy.tcp_nodelay(true)
}
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct AutoReferer;
impl SetOpt for AutoReferer {
fn set_opt<H>(&self, easy: &mut curl::easy::Easy2<H>) -> Result<(), curl::Error> {
easy.autoreferer(true)
}
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct MaxUploadSpeed(pub(crate) u64);
impl SetOpt for MaxUploadSpeed {
fn set_opt<H>(&self, easy: &mut curl::easy::Easy2<H>) -> Result<(), curl::Error> {
easy.max_send_speed(self.0)
}
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct MaxDownloadSpeed(pub(crate) u64);
impl SetOpt for MaxDownloadSpeed {
fn set_opt<H>(&self, easy: &mut curl::easy::Easy2<H>) -> Result<(), curl::Error> {
easy.max_recv_speed(self.0)
}
}
#[derive(Clone, Debug)]
pub(crate) struct DnsServers(pub(crate) Vec<SocketAddr>);
impl FromIterator<SocketAddr> for DnsServers {
fn from_iter<I: IntoIterator<Item = SocketAddr>>(iter: I) -> Self {
DnsServers(Vec::from_iter(iter))
}
}
impl SetOpt for DnsServers {
fn set_opt<H>(&self, easy: &mut curl::easy::Easy2<H>) -> Result<(), curl::Error> {
let dns_string = self.0
.iter()
.map(ToString::to_string)
.collect::<Vec<_>>()
.join(",");
if let Err(e) = easy.dns_servers(&dns_string) {
log::warn!("DNS servers could not be configured: {}", e);
}
Ok(())
}
}
#[derive(Clone, Debug)]
pub enum DnsCache {
Disable,
Timeout(Duration),
Forever,
}
impl Default for DnsCache {
fn default() -> Self {
Duration::from_secs(60).into()
}
}
impl From<Duration> for DnsCache {
fn from(duration: Duration) -> Self {
DnsCache::Timeout(duration)
}
}
impl SetOpt for DnsCache {
#[allow(unsafe_code)]
fn set_opt<H>(&self, easy: &mut curl::easy::Easy2<H>) -> Result<(), curl::Error> {
let value = match self {
DnsCache::Disable => 0,
DnsCache::Timeout(duration) => duration.as_secs() as i64,
DnsCache::Forever => -1,
};
unsafe {
match curl_sys::curl_easy_setopt(easy.raw(), curl_sys::CURLOPT_DNS_CACHE_TIMEOUT, value) {
curl_sys::CURLE_OK => Ok(()),
code => Err(curl::Error::new(code)),
}
}
}
}
#[derive(Clone, Debug)]
pub(crate) struct Proxy(pub(crate) http::Uri);
impl SetOpt for Proxy {
fn set_opt<H>(&self, easy: &mut curl::easy::Easy2<H>) -> Result<(), curl::Error> {
easy.proxy(&format!("{}", self.0))
}
}
#[derive(Clone, Debug)]
pub(crate) struct SslCiphers(pub(crate) Vec<String>);
impl FromIterator<String> for SslCiphers {
fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> Self {
SslCiphers(Vec::from_iter(iter))
}
}
impl SetOpt for SslCiphers {
fn set_opt<H>(&self, easy: &mut curl::easy::Easy2<H>) -> Result<(), curl::Error> {
easy.ssl_cipher_list(&self.0.join(":"))
}
}
#[derive(Clone, Debug)]
pub(crate) struct AllowUnsafeSsl(pub(crate) bool);
impl SetOpt for AllowUnsafeSsl {
fn set_opt<H>(&self, easy: &mut curl::easy::Easy2<H>) -> Result<(), curl::Error> {
easy.ssl_verify_peer(!self.0)?;
easy.ssl_verify_host(!self.0)
}
}
#[derive(Clone, Debug)]
pub(crate) struct CloseConnection(pub(crate) bool);
impl SetOpt for CloseConnection {
fn set_opt<H>(&self, easy: &mut curl::easy::Easy2<H>) -> Result<(), curl::Error> {
easy.forbid_reuse(self.0)
}
}
#[derive(Clone, Debug)]
pub(crate) struct EnableMetrics(pub(crate) bool);
impl SetOpt for EnableMetrics {
fn set_opt<H>(&self, easy: &mut curl::easy::Easy2<H>) -> Result<(), curl::Error> {
easy.progress(self.0)
}
}