use std::{fmt, sync::Arc};
use base64::Engine as _;
use http::Uri;
use hyper_util::client::proxy::matcher::{self, Matcher};
pub type Intercept = matcher::Intercept;
#[must_use]
pub fn credentials(intercept: &Intercept) -> Option<(String, String)> {
if let Some((user, password)) = intercept.raw_auth() {
return Some((user.to_owned(), password.to_owned()));
}
let header = intercept.basic_auth()?.to_str().ok()?;
let decoded = base64::engine::general_purpose::STANDARD
.decode(header.strip_prefix("Basic ")?)
.ok()?;
let text = String::from_utf8(decoded).ok()?;
let (user, password) = text
.split_once(':')
.map_or((text.as_str(), ""), |(user, password)| (user, password));
Some((user.to_owned(), password.to_owned()))
}
#[derive(Clone)]
pub struct Proxy {
inner: Arc<Inner>,
}
struct Inner {
matcher: Matcher,
source: Source,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Source {
System,
Explicit,
}
impl Proxy {
#[must_use]
pub fn system() -> Self {
Self::new(Matcher::from_system(), Source::System)
}
#[must_use]
pub fn env() -> Self {
Self::new(Matcher::from_env(), Source::Explicit)
}
#[must_use]
pub fn none() -> Self {
Self::new(Matcher::builder().build(), Source::Explicit)
}
#[must_use]
pub fn builder() -> ProxyBuilder {
ProxyBuilder {
inner: Matcher::builder(),
}
}
fn new(matcher: Matcher, source: Source) -> Self {
Self {
inner: Arc::new(Inner { matcher, source }),
}
}
#[must_use]
pub fn intercept(&self, destination: &Uri) -> Option<Intercept> {
self.inner.matcher.intercept(destination)
}
#[must_use]
pub fn source(&self) -> Source {
self.inner.source
}
}
impl fmt::Debug for Proxy {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Proxy")
.field("source", &self.inner.source)
.field("rules", &self.inner.matcher)
.finish()
}
}
#[derive(Default)]
pub struct ProxyBuilder {
inner: matcher::Builder,
}
impl fmt::Debug for ProxyBuilder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ProxyBuilder").finish_non_exhaustive()
}
}
impl ProxyBuilder {
#[must_use]
pub fn all(mut self, proxy_uri: impl Into<String>) -> Self {
self.inner = self.inner.all(proxy_uri.into());
self
}
#[must_use]
pub fn http(mut self, proxy_uri: impl Into<String>) -> Self {
self.inner = self.inner.http(proxy_uri.into());
self
}
#[must_use]
pub fn https(mut self, proxy_uri: impl Into<String>) -> Self {
self.inner = self.inner.https(proxy_uri.into());
self
}
#[must_use]
pub fn no_proxy(mut self, list: impl Into<String>) -> Self {
self.inner = self.inner.no(list.into());
self
}
#[must_use]
pub fn build(self) -> Proxy {
Proxy::new(self.inner.build(), Source::Explicit)
}
}