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