Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(proxy): Enhanced client proxy options #534

Merged
merged 2 commits into from
Mar 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions src/client/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use crate::dns::hickory::{HickoryDnsResolver, LookupIpStrategy};
use crate::dns::{DnsResolverWithOverrides, DynResolver, Resolve, gai::GaiResolver};
use crate::error::{BoxError, Error};
use crate::into_url::try_uri;
use crate::proxy::IntoProxy;
use crate::util::{
self,
client::{
Expand Down Expand Up @@ -617,9 +618,30 @@ impl ClientBuilder {
/// # Note
///
/// Adding a proxy will disable the automatic usage of the "system" proxy.
pub fn proxy(mut self, proxy: Proxy) -> ClientBuilder {
self.config.proxies.push(proxy);
self.config.auto_sys_proxy = false;
///
/// # Example
/// ```
/// use reqwest::Client;
/// use reqwest::Proxy;
///
/// let proxy = Proxy::http("http://proxy:8080").unwrap();
/// let client = Client::builder().proxy(proxy).build().unwrap();
///
/// let client = Client::builder().proxy("http://proxy2:8080").build().unwrap();
/// ```
pub fn proxy<P>(mut self, proxy: P) -> ClientBuilder
where
P: IntoProxy,
{
match proxy.into_proxy() {
Ok(proxy) => {
self.config.proxies.push(proxy);
self.config.auto_sys_proxy = false;
}
Err(e) => {
self.config.error = Some(e);
}
}
self
}

Expand Down
42 changes: 33 additions & 9 deletions src/client/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ use super::http::{Client, Pending};
use super::multipart;
use super::response::Response;
use crate::header::{CONTENT_TYPE, HeaderMap, HeaderName, HeaderValue};
use crate::proxy::IntoProxy;
use crate::util::client::{NetworkScheme, NetworkSchemeBuilder};
use crate::{IntoUrl, Method, Proxy, Url, redirect};
use crate::{Method, Url, redirect};

/// A request which can be executed with `Client::execute()`.
pub struct Request {
Expand Down Expand Up @@ -499,15 +500,38 @@ impl RequestBuilder {
}

/// Set the proxy for this request.
pub fn proxy<U: IntoUrl>(mut self, proxy: U) -> RequestBuilder {
///
/// # Examples
///
/// ```
/// use rquest::Client;
/// use rquest::Proxy;
///
/// let client = Client::new();
/// let proxy = Proxy::all("http://hyper.rs/prox")?.basic_auth("Aladdin", "open sesame");
///
/// let resp = client
/// .get("https://tls.peet.ws/api/all")
/// .proxy(proxy)
/// .send()
/// .await?;
///
/// let resp = client
/// .get("https://tls.peet.ws/api/all")
/// .proxy("http://hyper.rs/prox")
/// .send()
/// .await?;
/// ```
pub fn proxy<P>(mut self, proxy: P) -> RequestBuilder
where
P: IntoProxy,
{
if let Ok(ref mut req) = self.request {
match proxy
.into_url()
.and_then(Proxy::all)
.map(|proxy| proxy.intercept(req.url()))
{
Ok(proxy_scheme) => {
req.network_scheme.proxy_scheme(proxy_scheme);
match proxy.into_proxy() {
Ok(proxy) => {
if let Some(proxy_scheme) = proxy.intercept(req.url()) {
req.network_scheme.proxy_scheme(proxy_scheme);
}
}
Err(err) => {
self.request = Err(crate::error::builder(err));
Expand Down
34 changes: 30 additions & 4 deletions src/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,34 @@ impl<S: IntoUrl> IntoProxyScheme for S {
}
}

impl IntoProxyScheme for ProxyScheme {
#[inline(always)]
fn into_proxy_scheme(self) -> crate::Result<ProxyScheme> {
Ok(self)
}
}

/// Trait used for converting into a proxy. This trait supports
/// parsing from a URL-like type, whilst also supporting proxy
/// built directly using the factory methods.
pub trait IntoProxy {
fn into_proxy(self) -> crate::Result<Proxy>;
}

impl<S: IntoProxyScheme> IntoProxy for S {
#[inline(always)]
fn into_proxy(self) -> crate::Result<Proxy> {
self.into_proxy_scheme().and_then(Proxy::all)
}
}

impl IntoProxy for Proxy {
#[inline(always)]
fn into_proxy(self) -> crate::Result<Proxy> {
Ok(self)
}
}

// These bounds are accidentally leaked by the blanket impl of IntoProxyScheme
// for all types that implement IntoUrl. So, this function exists to detect
// if we were to break those bounds for a user.
Expand All @@ -264,11 +292,9 @@ fn _implied_bounds() {
fn url<T: IntoUrl>(t: T) {
prox(t);
}
}

impl IntoProxyScheme for ProxyScheme {
fn into_proxy_scheme(self) -> crate::Result<ProxyScheme> {
Ok(self)
fn prox2<T: IntoProxy + IntoProxyScheme>(t: T) {
prox(t);
}
}

Expand Down
Loading