Add ClientBuilder::local_address option to bind to a local IP address (#451)
Closes #414
This commit is contained in:
		
				
					committed by
					
						 Sean McArthur
						Sean McArthur
					
				
			
			
				
	
			
			
			
						parent
						
							8ed9e60351
						
					
				
				
					commit
					4dc679d535
				
			| @@ -1,6 +1,7 @@ | ||||
| use std::{fmt, str}; | ||||
| use std::sync::Arc; | ||||
| use std::time::Duration; | ||||
| use std::net::IpAddr; | ||||
|  | ||||
| use bytes::Bytes; | ||||
| use futures::{Async, Future, Poll}; | ||||
| @@ -76,6 +77,7 @@ struct Config { | ||||
|     #[cfg(feature = "tls")] | ||||
|     tls: TlsBackend, | ||||
|     http2_only: bool, | ||||
|     local_address: Option<IpAddr>, | ||||
| } | ||||
|  | ||||
| impl ClientBuilder { | ||||
| @@ -106,6 +108,7 @@ impl ClientBuilder { | ||||
|                 #[cfg(feature = "tls")] | ||||
|                 tls: TlsBackend::default(), | ||||
|                 http2_only: false, | ||||
|                 local_address: None, | ||||
|             }, | ||||
|         } | ||||
|     } | ||||
| @@ -137,7 +140,7 @@ impl ClientBuilder { | ||||
|                         id.add_to_native_tls(&mut tls)?; | ||||
|                     } | ||||
|  | ||||
|                     Connector::new_default_tls(tls, proxies.clone())? | ||||
|                     Connector::new_default_tls(tls, proxies.clone(), config.local_address)? | ||||
|                 }, | ||||
|                 #[cfg(feature = "rustls-tls")] | ||||
|                 TlsBackend::Rustls => { | ||||
| @@ -166,18 +169,19 @@ impl ClientBuilder { | ||||
|                         id.add_to_rustls(&mut tls)?; | ||||
|                     } | ||||
|  | ||||
|                     Connector::new_rustls_tls(tls, proxies.clone())? | ||||
|                     Connector::new_rustls_tls(tls, proxies.clone(), config.local_address)? | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             #[cfg(not(feature = "tls"))] | ||||
|             Connector::new(proxies.clone())? | ||||
|             Connector::new(proxies.clone(), config.local_address)? | ||||
|         }; | ||||
|  | ||||
|         let mut builder = ::hyper::Client::builder(); | ||||
|         if config.http2_only { | ||||
|             builder.http2_only(true); | ||||
|         } | ||||
|  | ||||
|         let hyper_client = builder.build(connector); | ||||
|  | ||||
|         let proxies_maybe_http_auth = proxies | ||||
| @@ -325,6 +329,15 @@ impl ClientBuilder { | ||||
|     pub fn dns_threads(self, _threads: usize) -> ClientBuilder { | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     /// Bind to a local IP Address | ||||
|     pub fn local_address<T>(mut self, addr: T) -> ClientBuilder | ||||
|     where | ||||
|         T: Into<Option<IpAddr>>, | ||||
|     { | ||||
|         self.config.local_address = addr.into(); | ||||
|         self | ||||
|     } | ||||
| } | ||||
|  | ||||
| type HyperClient = ::hyper::Client<Connector>; | ||||
|   | ||||
| @@ -2,6 +2,7 @@ use std::fmt; | ||||
| use std::sync::Arc; | ||||
| use std::time::Duration; | ||||
| use std::thread; | ||||
| use std::net::IpAddr; | ||||
|  | ||||
| use futures::{Async, Future, Stream}; | ||||
| use futures::future::{self, Either}; | ||||
| @@ -306,6 +307,24 @@ impl ClientBuilder { | ||||
|     pub fn h2_prior_knowledge(self) -> ClientBuilder { | ||||
|         self.with_inner(|inner| inner.h2_prior_knowledge()) | ||||
|     } | ||||
|  | ||||
|     /// Bind to a local IP Address | ||||
|     /// | ||||
|     /// # Example | ||||
|     /// | ||||
|     /// ``` | ||||
|     /// use std::net::IpAddr; | ||||
|     /// let local_addr = IpAddr::from([12, 4, 1, 8]); | ||||
|     /// let client = reqwest::Client::builder() | ||||
|     ///     .local_address(local_addr) | ||||
|     ///     .build().unwrap(); | ||||
|     /// ``` | ||||
|     pub fn local_address<T>(self, addr: T) -> ClientBuilder | ||||
|     where | ||||
|         T: Into<Option<IpAddr>>, | ||||
|     { | ||||
|         self.with_inner(move |inner| inner.local_address(addr)) | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -3,6 +3,7 @@ use http::uri::Scheme; | ||||
| use hyper::client::connect::{Connect, Connected, Destination}; | ||||
| use tokio_io::{AsyncRead, AsyncWrite}; | ||||
|  | ||||
|  | ||||
| #[cfg(feature = "default-tls")] | ||||
| use native_tls::{TlsConnector, TlsConnectorBuilder}; | ||||
| #[cfg(feature = "tls")] | ||||
| @@ -12,6 +13,7 @@ use bytes::BufMut; | ||||
|  | ||||
| use std::io; | ||||
| use std::sync::Arc; | ||||
| use std::net::IpAddr; | ||||
|  | ||||
| #[cfg(feature = "trust-dns")] | ||||
| use dns::TrustDnsResolver; | ||||
| @@ -39,8 +41,13 @@ enum Inner { | ||||
|  | ||||
| impl Connector { | ||||
|     #[cfg(not(feature = "tls"))] | ||||
|     pub(crate) fn new(proxies: Arc<Vec<Proxy>>) -> ::Result<Connector> { | ||||
|         let http = http_connector()?; | ||||
|     pub(crate) fn new<T>(proxies: Arc<Vec<Proxy>>, local_addr: T) -> ::Result<Connector> | ||||
|     where | ||||
|         T: Into<Option<IpAddr>> | ||||
|     { | ||||
|  | ||||
|         let mut http = http_connector()?; | ||||
|         http.set_local_address(local_addr.into()); | ||||
|         Ok(Connector { | ||||
|             proxies, | ||||
|             inner: Inner::Http(http) | ||||
| @@ -48,10 +55,17 @@ impl Connector { | ||||
|     } | ||||
|  | ||||
|     #[cfg(feature = "default-tls")] | ||||
|     pub(crate) fn new_default_tls(tls: TlsConnectorBuilder, proxies: Arc<Vec<Proxy>>) -> ::Result<Connector> { | ||||
|     pub(crate) fn new_default_tls<T>( | ||||
|         tls: TlsConnectorBuilder, | ||||
|         proxies: Arc<Vec<Proxy>>, | ||||
|         local_addr: T) -> ::Result<Connector> | ||||
|         where | ||||
|             T: Into<Option<IpAddr>>, | ||||
|     { | ||||
|         let tls = try_!(tls.build()); | ||||
|  | ||||
|         let mut http = http_connector()?; | ||||
|         http.set_local_address(local_addr.into()); | ||||
|         http.enforce_http(false); | ||||
|         let http = ::hyper_tls::HttpsConnector::from((http, tls.clone())); | ||||
|  | ||||
| @@ -62,8 +76,15 @@ impl Connector { | ||||
|     } | ||||
|  | ||||
|     #[cfg(feature = "rustls-tls")] | ||||
|     pub(crate) fn new_rustls_tls(tls: rustls::ClientConfig, proxies: Arc<Vec<Proxy>>) -> ::Result<Connector> { | ||||
|     pub(crate) fn new_rustls_tls<T>( | ||||
|         tls: rustls::ClientConfig, | ||||
|         proxies: Arc<Vec<Proxy>>, | ||||
|         local_addr: T) -> ::Result<Connector> | ||||
|         where | ||||
|             T: Into<Option<IpAddr>>, | ||||
|     { | ||||
|         let mut http = http_connector()?; | ||||
|         http.set_local_address(local_addr.into()); | ||||
|         http.enforce_http(false); | ||||
|         let http = ::hyper_rustls::HttpsConnector::from((http, tls.clone())); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user