Skip to content

Commit fc34e10

Browse files
Stefan ZwanenburgStefan Zwanenburg
Stefan Zwanenburg
authored and
Stefan Zwanenburg
committed
Add --noproxy argument to ignore proxy for hosts or IP addresses.
Related issue: ducaale#296
1 parent 9f98ad6 commit fc34e10

File tree

4 files changed

+79
-6
lines changed

4 files changed

+79
-6
lines changed

src/cli.rs

+26
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,14 @@ Example: --print=Hb"
295295
#[clap(long, value_name = "PROTOCOL:URL", number_of_values = 1)]
296296
pub proxy: Vec<Proxy>,
297297

298+
/// Comma-separated list of hosts for which not to use a proxy, if one is specified.
299+
///
300+
/// - A '*' matches all hosts, and effectively disables proxies altogether.
301+
/// - IP addresses are allowed, as are subnets (in CIDR notation, i.e.: '127.0.0.0/8').
302+
/// - Any other entry in the list is assumed to be a hostname.
303+
#[clap(long, value_name = "no-proxy-list", value_delimiter = ',')]
304+
pub noproxy: Vec<String>,
305+
298306
/// If "no", skip SSL verification. If a file path, use it as a CA bundle.
299307
///
300308
/// Specifying a CA bundle will disable the system's built-in root certificates.
@@ -1087,6 +1095,24 @@ impl FromStr for Proxy {
10871095
}
10881096
}
10891097

1098+
impl Proxy {
1099+
pub fn into_reqwest_proxy(self, noproxy: &[String]) -> anyhow::Result<reqwest::Proxy> {
1100+
let proxy = match self {
1101+
Proxy::Http(url) => reqwest::Proxy::http(url),
1102+
Proxy::Https(url) => reqwest::Proxy::https(url),
1103+
Proxy::All(url) => reqwest::Proxy::all(url),
1104+
}?;
1105+
1106+
let mut noproxy_comma_delimited = noproxy.join(",");
1107+
if noproxy.contains(&"*".to_string()) {
1108+
// reqwest's NoProxy wildcard doesn't apply to IP addresses, while curl's does
1109+
noproxy_comma_delimited.push_str(",0.0.0.0/0,::/0");
1110+
}
1111+
1112+
Ok(proxy.no_proxy(reqwest::NoProxy::from_string(&noproxy_comma_delimited)))
1113+
}
1114+
}
1115+
10901116
#[derive(Debug, Clone)]
10911117
pub struct Resolve {
10921118
pub domain: String,

src/main.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ use utils::reason_phrase;
4141

4242
use crate::auth::{Auth, DigestAuthMiddleware};
4343
use crate::buffer::Buffer;
44-
use crate::cli::{Cli, FormatOptions, HttpVersion, Print, Proxy, Verify};
44+
use crate::cli::{Cli, FormatOptions, HttpVersion, Print, Verify};
4545
use crate::download::{download_file, get_file_size};
4646
use crate::middleware::ClientWithMiddleware;
4747
use crate::printer::Printer;
@@ -274,11 +274,7 @@ fn run(args: Cli) -> Result<i32> {
274274
}
275275

276276
for proxy in args.proxy.into_iter().rev() {
277-
client = client.proxy(match proxy {
278-
Proxy::Http(url) => reqwest::Proxy::http(url),
279-
Proxy::Https(url) => reqwest::Proxy::https(url),
280-
Proxy::All(url) => reqwest::Proxy::all(url),
281-
}?);
277+
client = client.proxy(proxy.into_reqwest_proxy(&args.noproxy)?);
282278
}
283279

284280
client = match args.http_version {

src/to_curl.rs

+4
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,10 @@ pub fn translate(args: Cli) -> Result<Command> {
233233
}
234234
}
235235
}
236+
if !args.noproxy.is_empty() {
237+
cmd.arg("--noproxy");
238+
cmd.arg(args.noproxy.join(","));
239+
}
236240
if let Some(timeout) = args.timeout.and_then(|t| t.as_duration()) {
237241
cmd.arg("--max-time");
238242
cmd.arg(timeout.as_secs_f64().to_string());

tests/cli.rs

+47
Original file line numberDiff line numberDiff line change
@@ -1136,6 +1136,53 @@ fn proxy_multiple_valid_proxies() {
11361136
cmd.assert().success();
11371137
}
11381138

1139+
fn noproxy_test(noproxy_arg: &str) {
1140+
let mut proxy_server = server::http(|_| async move {
1141+
hyper::Response::builder()
1142+
.status(200)
1143+
.body("Proxy shouldn't have been used.".into())
1144+
.unwrap()
1145+
});
1146+
let actual_server = server::http(|_| async move {
1147+
hyper::Response::builder()
1148+
.status(200)
1149+
.body("".into())
1150+
.unwrap()
1151+
});
1152+
1153+
get_command()
1154+
.arg(format!("--proxy=http:{}", proxy_server.base_url()))
1155+
.arg(format!("--noproxy={}", noproxy_arg))
1156+
.arg("GET")
1157+
.arg(actual_server.base_url().as_str())
1158+
.assert()
1159+
.success();
1160+
1161+
proxy_server.disable_hit_checks();
1162+
proxy_server.assert_hits(0);
1163+
actual_server.assert_hits(1);
1164+
}
1165+
1166+
#[test]
1167+
fn noproxy_wildcard() {
1168+
noproxy_test("*");
1169+
}
1170+
1171+
#[test]
1172+
fn noproxy_ip() {
1173+
noproxy_test("127.0.0.1");
1174+
}
1175+
1176+
#[test]
1177+
fn noproxy_ip_cidr() {
1178+
noproxy_test("127.0.0.0/8");
1179+
}
1180+
1181+
#[test]
1182+
fn noproxy_multiple() {
1183+
noproxy_test("127.0.0.2,127.0.0.1");
1184+
}
1185+
11391186
// temporarily disabled for builds not using rustls
11401187
#[cfg(all(feature = "online-tests", feature = "rustls"))]
11411188
#[ignore = "endpoint is randomly timing out"]

0 commit comments

Comments
 (0)