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 request level proxy options #533

Merged
merged 1 commit 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
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