@@ -27,6 +27,7 @@ use nu_protocol::{
2727 } ,
2828} ;
2929use serde_json:: Value as JsonValue ;
30+ use std:: convert:: TryInto ;
3031use std:: {
3132 collections:: HashMap ,
3233 io:: { self , Cursor , Read } ,
@@ -37,7 +38,7 @@ use std::{
3738 time:: Duration ,
3839} ;
3940use 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) ]
12701319mod 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