Skip to content

Commit ea38642

Browse files
authored
Respecting $env.NO_PROXY (#16730)
1 parent e0f7423 commit ea38642

1 file changed

Lines changed: 78 additions & 2 deletions

File tree

‎crates/nu-command/src/network/http/client.rs‎

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use nu_protocol::{
2727
},
2828
};
2929
use serde_json::Value as JsonValue;
30+
use std::convert::TryInto;
3031
use std::{
3132
collections::HashMap,
3233
io::{self, Cursor, Read},
@@ -37,7 +38,7 @@ use std::{
3738
time::Duration,
3839
};
3940
use ureq::{
40-
Agent, Body, Error, RequestBuilder, ResponseExt, SendBody,
41+
Agent, Body, Error, Proxy, ProxyBuilder, ProxyProtocol, RequestBuilder, ResponseExt, SendBody,
4142
typestate::{WithBody, WithoutBody},
4243
unversioned::transport::{ConnectProxyConnector, Connector, SocksConnector},
4344
};
@@ -208,7 +209,8 @@ pub fn http_client(
208209
}
209210

210211
if let Some(http_proxy) = retrieve_http_proxy_from_env(engine_state, stack)
211-
&& let Ok(proxy) = ureq::Proxy::new(&http_proxy)
212+
&& let Some(proxy) = proxy_builder_from_env(http_proxy, engine_state, stack)
213+
.and_then(|builder| builder.build().ok())
212214
{
213215
config_builder = config_builder.proxy(Some(proxy));
214216
};
@@ -1266,10 +1268,84 @@ fn retrieve_http_proxy_from_env(engine_state: &EngineState, stack: &mut Stack) -
12661268
.and_then(|proxy| proxy.coerce_into_string().ok())
12671269
}
12681270

1271+
fn proxy_builder_from_env(
1272+
http_proxy: String,
1273+
engine_state: &EngineState,
1274+
stack: &mut Stack,
1275+
) -> Option<ProxyBuilder> {
1276+
let uri = http_proxy.parse::<http::Uri>().ok()?;
1277+
let authority = uri.authority()?;
1278+
let scheme = uri.scheme_str().unwrap_or("http");
1279+
let proto: ProxyProtocol = scheme.try_into().ok()?;
1280+
1281+
let mut builder = Proxy::builder(proto).host(authority.host());
1282+
1283+
if let Some(port) = uri.port() {
1284+
builder = builder.port(port.as_u16());
1285+
}
1286+
1287+
let (username, password) = retrieve_credential_from_authority(authority);
1288+
if let Some(username) = username {
1289+
builder = builder.username(username);
1290+
if let Some(password) = password {
1291+
builder = builder.password(password);
1292+
}
1293+
}
1294+
1295+
if let Some(val) = stack
1296+
.get_env_var(engine_state, "no_proxy")
1297+
.or(stack.get_env_var(engine_state, "NO_PROXY"))
1298+
&& let Ok(no_proxy) = val.as_str()
1299+
{
1300+
for proxy in no_proxy.split(',') {
1301+
builder = builder.no_proxy(proxy.trim());
1302+
}
1303+
}
1304+
1305+
Some(builder)
1306+
}
1307+
1308+
fn retrieve_credential_from_authority(
1309+
authority: &http::uri::Authority,
1310+
) -> (Option<&str>, Option<&str>) {
1311+
let s = authority.as_str();
1312+
let user_info = s.rfind('@').map(|i| &s[..i]);
1313+
let username = user_info.map(|a| a.rfind(':').map(|i| &a[..i]).unwrap_or(a));
1314+
let password = user_info.and_then(|a| a.rfind(':').map(|i| &a[i + 1..]));
1315+
(username, password)
1316+
}
1317+
12691318
#[cfg(test)]
12701319
mod test {
12711320
use super::*;
12721321

1322+
#[test]
1323+
fn test_retrieving_credentials_from_authority() {
1324+
// user and password
1325+
let uri = "http://user:pass@host/path".parse::<http::Uri>().unwrap();
1326+
let authority = uri.authority().unwrap();
1327+
let (user, pass) = retrieve_credential_from_authority(authority);
1328+
assert_eq!((user, pass), (Some("user"), Some("pass")));
1329+
1330+
// user and empty password
1331+
let uri = "http://user:@host/path".parse::<http::Uri>().unwrap();
1332+
let authority = uri.authority().unwrap();
1333+
let (user, pass) = retrieve_credential_from_authority(authority);
1334+
assert_eq!((user, pass), (Some("user"), Some("")));
1335+
1336+
// user only, no password
1337+
let uri = "http://user@host/path".parse::<http::Uri>().unwrap();
1338+
let authority = uri.authority().unwrap();
1339+
let (user, pass) = retrieve_credential_from_authority(authority);
1340+
assert_eq!((user, pass), (Some("user"), None));
1341+
1342+
// no user, no password
1343+
let uri = "http://host/path".parse::<http::Uri>().unwrap();
1344+
let authority = uri.authority().unwrap();
1345+
let (user, pass) = retrieve_credential_from_authority(authority);
1346+
assert_eq!((user, pass), (None, None));
1347+
}
1348+
12731349
#[test]
12741350
fn test_body_type_from_content_type() {
12751351
let json = Some("application/json".to_string());

0 commit comments

Comments
 (0)