diff --git a/src/async_impl/client.rs b/src/async_impl/client.rs index 244fece38..910e7e6b1 100644 --- a/src/async_impl/client.rs +++ b/src/async_impl/client.rs @@ -142,6 +142,8 @@ struct Config { #[cfg(feature = "http2")] http2_keep_alive_while_idle: bool, local_address: Option, + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + interface: Option, nodelay: bool, #[cfg(feature = "cookies")] cookie_store: Option>, @@ -234,6 +236,8 @@ impl ClientBuilder { #[cfg(feature = "http2")] http2_keep_alive_while_idle: false, local_address: None, + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + interface: None, nodelay: true, hickory_dns: cfg!(feature = "hickory-dns"), #[cfg(feature = "cookies")] @@ -430,6 +434,12 @@ impl ClientBuilder { proxies.clone(), user_agent(&config.headers), config.local_address, + #[cfg(any( + target_os = "android", + target_os = "fuchsia", + target_os = "linux" + ))] + config.interface.as_deref(), config.nodelay, config.tls_info, )? @@ -441,6 +451,8 @@ impl ClientBuilder { proxies.clone(), user_agent(&config.headers), config.local_address, + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + config.interface.as_deref(), config.nodelay, config.tls_info, ), @@ -456,6 +468,12 @@ impl ClientBuilder { config.quic_receive_window, config.quic_send_window, config.local_address, + #[cfg(any( + target_os = "android", + target_os = "fuchsia", + target_os = "linux" + ))] + config.interface.as_deref(), &config.http_version_pref, )?; } @@ -466,6 +484,12 @@ impl ClientBuilder { proxies.clone(), user_agent(&config.headers), config.local_address, + #[cfg(any( + target_os = "android", + target_os = "fuchsia", + target_os = "linux" + ))] + config.interface.as_deref(), config.nodelay, config.tls_info, ) @@ -592,6 +616,12 @@ impl ClientBuilder { proxies.clone(), user_agent(&config.headers), config.local_address, + #[cfg(any( + target_os = "android", + target_os = "fuchsia", + target_os = "linux" + ))] + config.interface.as_deref(), config.nodelay, config.tls_info, ) @@ -1237,6 +1267,22 @@ impl ClientBuilder { self } + /// Bind to an interface by `SO_BINDTODEVICE`. + /// + /// # Example + /// + /// ``` + /// let interface = "lo"; + /// let client = reqwest::Client::builder() + /// .interface(interface) + /// .build().unwrap(); + /// ``` + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + pub fn interface(mut self, interface: &str) -> ClientBuilder { + self.config.interface = Some(interface.to_string()); + self + } + /// Set that all sockets have `SO_KEEPALIVE` set with the supplied duration. /// /// If `None`, the option will not be set. @@ -2062,6 +2108,11 @@ impl Config { f.field("local_address", v); } + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + if let Some(ref v) = self.interface { + f.field("interface", v); + } + if self.nodelay { f.field("tcp_nodelay", &true); } diff --git a/src/blocking/client.rs b/src/blocking/client.rs index 7b2816ba7..5b861cb3e 100644 --- a/src/blocking/client.rs +++ b/src/blocking/client.rs @@ -523,6 +523,21 @@ impl ClientBuilder { self.with_inner(move |inner| inner.local_address(addr)) } + /// Bind to an interface by `SO_BINDTODEVICE`. + /// + /// # Example + /// + /// ``` + /// let interface = "lo"; + /// let client = reqwest::blocking::Client::builder() + /// .interface(interface) + /// .build().unwrap(); + /// ``` + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + pub fn interface(self, interface: &str) -> ClientBuilder { + self.with_inner(move |inner| inner.interface(interface)) + } + /// Set that all sockets have `SO_KEEPALIVE` set with the supplied duration. /// /// If `None`, the option will not be set. diff --git a/src/connect.rs b/src/connect.rs index 3ad374021..68ef26924 100644 --- a/src/connect.rs +++ b/src/connect.rs @@ -86,6 +86,8 @@ impl Connector { proxies: Arc>, user_agent: Option, local_addr: T, + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + interface: Option<&str>, nodelay: bool, tls_info: bool, ) -> crate::Result @@ -94,7 +96,15 @@ impl Connector { { let tls = tls.build().map_err(crate::error::builder)?; Ok(Self::from_built_default_tls( - http, tls, proxies, user_agent, local_addr, nodelay, tls_info, + http, + tls, + proxies, + user_agent, + local_addr, + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + interface, + nodelay, + tls_info, )) } @@ -105,6 +115,8 @@ impl Connector { proxies: Arc>, user_agent: Option, local_addr: T, + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + interface: Option<&str>, nodelay: bool, tls_info: bool, ) -> Connector @@ -112,6 +124,10 @@ impl Connector { T: Into>, { http.set_local_address(local_addr.into()); + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + if let Some(interface) = interface { + http.set_interface(interface); + } http.set_nodelay(nodelay); http.enforce_http(false); @@ -133,6 +149,8 @@ impl Connector { proxies: Arc>, user_agent: Option, local_addr: T, + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + interface: Option<&str>, nodelay: bool, tls_info: bool, ) -> Connector @@ -140,6 +158,10 @@ impl Connector { T: Into>, { http.set_local_address(local_addr.into()); + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + if let Some(interface) = interface { + http.set_interface(interface.to_owned()); + } http.set_nodelay(nodelay); http.enforce_http(false);