use super::{OriginProxy, system::Configuration};
use alloc::{boxed::Box, sync::Arc, vec::Vec};
use reqwest::{ClientBuilder, NoProxy, Proxy};
impl OriginProxy {
pub fn configure_reqwest(
&self,
builder: ClientBuilder,
) -> Result<ClientBuilder, reqwest::Error> {
apply(builder, &self.configuration)
}
}
pub(super) fn apply(
builder: ClientBuilder,
configuration: &Configuration,
) -> Result<ClientBuilder, reqwest::Error> {
let builder = builder
.no_proxy()
.redirect(reqwest::redirect::Policy::none());
if super::bypasses_all(&configuration.no_proxy) {
return Ok(builder);
}
Ok(match &configuration.proxy {
Some(proxy) => {
let builder = if proxy.scheme() == "socks4" {
builder.dns_resolver(Arc::new(Socks4Resolver))
} else {
builder
};
builder.proxy(
Proxy::all(proxy.clone())?.no_proxy(NoProxy::from_string(&configuration.no_proxy)),
)
},
None => builder,
})
}
struct Socks4Resolver;
impl reqwest::dns::Resolve for Socks4Resolver {
fn resolve(&self, name: reqwest::dns::Name) -> reqwest::dns::Resolving {
Box::pin(async move {
use std::net::ToSocketAddrs;
let mut addresses = tokio::task::spawn_blocking(move || {
(name.as_str(), 0)
.to_socket_addrs()
.map(|addresses| addresses.collect::<Vec<_>>())
})
.await??;
addresses.sort_by_key(|address| address.is_ipv6());
Ok(Box::new(addresses.into_iter()) as reqwest::dns::Addrs)
})
}
}
#[cfg(test)]
mod tests;