diff --git a/src/client/http/mod.rs b/src/client/http/mod.rs index e032e29d2..46b655260 100644 --- a/src/client/http/mod.rs +++ b/src/client/http/mod.rs @@ -733,10 +733,7 @@ impl ClientBuilder { /// /// # Example /// ``` - /// use wreq::{ - /// Client, - /// Proxy, - /// }; + /// use wreq::{Client, Proxy}; /// /// let proxy = Proxy::http("http://proxy:8080").unwrap(); /// let client = Client::builder().proxy(proxy).build().unwrap(); @@ -977,6 +974,18 @@ impl ClientBuilder { /// Set that all sockets are bound to the configured IPv4 or IPv6 address (depending on host's /// preferences) before connection. + /// + /// # Example + /// /// + /// ``` + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// let ipv4 = Ipv4Addr::new(127, 0, 0, 1); + /// let ipv6 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + /// let client = wreq::Client::builder() + /// .local_addresses(ipv4, ipv6) + /// .build() + /// .unwrap(); + /// ``` #[inline] pub fn local_addresses(mut self, ipv4: V4, ipv6: V6) -> ClientBuilder where @@ -990,30 +999,38 @@ impl ClientBuilder { self } - /// Bind to an interface by `SO_BINDTODEVICE`. + /// Bind connections only on the specified network interface. + /// + /// This option is only available on the following operating systems: + /// + /// - Android + /// - Fuchsia + /// - Linux, + /// - macOS and macOS-like systems (iOS, tvOS, watchOS and visionOS) + /// - Solaris and illumos + /// + /// On Android, Linux, and Fuchsia, this uses the + /// [`SO_BINDTODEVICE`][man-7-socket] socket option. On macOS and macOS-like + /// systems, Solaris, and illumos, this instead uses the [`IP_BOUND_IF` and + /// `IPV6_BOUND_IF`][man-7p-ip] socket options (as appropriate). + /// + /// Note that connections will fail if the provided interface name is not a + /// network interface that currently exists when a connection is established. /// /// # Example /// /// ``` + /// # fn doc() -> Result<(), wreq::Error> { /// let interface = "lo"; /// let client = wreq::Client::builder() /// .interface(interface) - /// .build() - /// .unwrap(); + /// .build()?; + /// # Ok(()) + /// # } /// ``` - #[inline] - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "solaris", - target_os = "tvos", - target_os = "visionos", - target_os = "watchos", - ))] + /// + /// [man-7-socket]: https://man7.org/linux/man-pages/man7/socket.7.html + /// [man-7p-ip]: https://docs.oracle.com/cd/E86824_01/html/E54777/ip-7p.html pub fn interface(mut self, interface: T) -> ClientBuilder where T: Into>, @@ -1025,6 +1042,8 @@ impl ClientBuilder { self } + // TLS options + /// Sets the identity to be used for client certificate authentication. #[inline] pub fn identity(mut self, identity: Identity) -> ClientBuilder { @@ -1032,6 +1051,16 @@ impl ClientBuilder { self } + /// Sets the verify certificate store for the client. + /// + /// This method allows you to specify a custom verify certificate store to be used + /// for TLS connections. By default, the system's verify certificate store is used. + #[inline] + pub fn cert_store(mut self, store: CertStore) -> ClientBuilder { + self.config.tls_cert_store = store; + self + } + /// Controls the use of certificate validation. /// /// Defaults to `true`. @@ -1049,25 +1078,17 @@ impl ClientBuilder { self } - /// Sets the verify certificate store for the client. - /// - /// This method allows you to specify a custom verify certificate store to be used - /// for TLS connections. By default, the system's verify certificate store is used. - /// - /// # Parameters - /// - /// - `store`: The verify certificate store to use. This can be a custom implementation of the - /// `IntoCertStore` trait or one of the predefined options. + /// Configures the use of hostname verification when connecting. /// - /// # Notes + /// Defaults to `true`. + /// # Warning /// - /// - Using a custom verify certificate store can be useful in scenarios where you need to trust - /// specific certificates that are not included in the system's default store. - /// - Ensure that the provided verify certificate store is properly configured to avoid - /// potential security risks. + /// You should think very carefully before you use this method. If hostname verification is not + /// used, *any* valid certificate for *any* site will be trusted for use from any other. This + /// introduces a significant vulnerability to man-in-the-middle attacks. #[inline] - pub fn cert_store(mut self, store: CertStore) -> ClientBuilder { - self.config.tls_cert_store = store; + pub fn verify_hostname(mut self, verify_hostname: bool) -> ClientBuilder { + self.config.tls_verify_hostname = verify_hostname; self } @@ -1087,20 +1108,6 @@ impl ClientBuilder { self } - /// Configures the use of hostname verification when connecting. - /// - /// Defaults to `true`. - /// # Warning - /// - /// You should think very carefully before you use this method. If hostname verification is not - /// used, *any* valid certificate for *any* site will be trusted for use from any other. This - /// introduces a significant vulnerability to man-in-the-middle attacks. - #[inline] - pub fn verify_hostname(mut self, verify_hostname: bool) -> ClientBuilder { - self.config.tls_verify_hostname = verify_hostname; - self - } - /// Set the minimum required TLS version for connections. /// /// By default the TLS backend's own default is used. diff --git a/src/client/request.rs b/src/client/request.rs index 7e2537a4f..e5e855cdf 100644 --- a/src/client/request.rs +++ b/src/client/request.rs @@ -15,7 +15,7 @@ use serde::Serialize; feature = "brotli", feature = "deflate", ))] -use super::layer::{config::RequestAcceptEncoding, decoder::AcceptEncoding}; +use super::layer::config::RequestAcceptEncoding; #[cfg(feature = "multipart")] use super::multipart; use super::{ @@ -29,14 +29,13 @@ use super::{ use crate::{ EmulationFactory, Error, Method, OriginalHeaders, Proxy, Url, core::{ - client::{connect::TcpConnectOptions, options::TransportOptions}, + client::options::TransportOptions, ext::{ - RequestConfig, RequestEnforcedHttpVersion, RequestOriginalHeaders, RequestProxyMatcher, - RequestTcpConnectOptions, RequestTransportOptions, + RequestConfig, RequestConfigValue, RequestEnforcedHttpVersion, RequestOriginalHeaders, + RequestProxyMatcher, RequestTcpConnectOptions, RequestTransportOptions, }, }, header::{CONTENT_TYPE, HeaderMap, HeaderName, HeaderValue}, - proxy::Matcher as ProxyMatcher, redirect, }; @@ -107,18 +106,6 @@ impl Request { &mut self.headers } - /// Get a mutable reference to the original headers. - #[inline] - pub fn original_headers_mut(&mut self) -> &mut Option { - RequestConfig::::get_mut(&mut self.extensions) - } - - /// Get a mutable reference to the redirect policy. - #[inline] - pub fn redirect_mut(&mut self) -> &mut Option { - RequestConfig::::get_mut(&mut self.extensions) - } - /// Get the body. #[inline] pub fn body(&self) -> Option<&Body> { @@ -140,55 +127,13 @@ impl Request { /// Get a mutable reference to the http version. #[inline] pub fn version_mut(&mut self) -> &mut Option { - RequestConfig::::get_mut(&mut self.extensions) - } - - /// Get a mutable reference to the timeout. - #[inline] - pub fn timeout_mut(&mut self) -> &mut Option { - RequestConfig::::get_mut(&mut self.extensions) - } - - /// Get a mutable reference to the read timeout. - #[inline] - pub fn read_timeout_mut(&mut self) -> &mut Option { - RequestConfig::::get_mut(&mut self.extensions) - } - - /// Get a mutable reference to the tcp connect options. - #[inline] - pub(crate) fn tcp_connect_options_mut(&mut self) -> &mut Option { - RequestConfig::::get_mut(&mut self.extensions) - } - - /// Get a mutable reference to the proxy matcher. - #[inline] - pub(crate) fn proxy_matcher_mut(&mut self) -> &mut Option { - RequestConfig::::get_mut(&mut self.extensions) - } - - /// Get the accepts encoding. - #[cfg(any( - feature = "gzip", - feature = "zstd", - feature = "brotli", - feature = "deflate", - ))] - #[inline] - pub(crate) fn accpet_encoding_mut(&mut self) -> &mut Option { - RequestConfig::::get_mut(&mut self.extensions) - } - - /// Skip client default headers. - #[inline] - pub(crate) fn default_headers_mut(&mut self) -> &mut Option { - RequestConfig::::get_mut(&mut self.extensions) + self.config_mut::() } - // Get a mutable reference to the transport options. + /// Get a mutable reference to the request config value. #[inline] - pub(crate) fn transport_options_mut(&mut self) -> &mut Option { - RequestConfig::::get_mut(&mut self.extensions) + pub(crate) fn config_mut(&mut self) -> &mut Option { + RequestConfig::::get_mut(&mut self.extensions) } /// Get the extensions. @@ -336,7 +281,7 @@ impl RequestBuilder { /// Set the original headers for this request. pub fn original_headers(mut self, original_headers: OriginalHeaders) -> RequestBuilder { if let Ok(ref mut req) = self.request { - *req.original_headers_mut() = Some(original_headers); + *req.config_mut::() = Some(original_headers); } self } @@ -344,7 +289,7 @@ impl RequestBuilder { /// Set skip client default headers for this request. pub fn default_headers(mut self, skip: bool) -> RequestBuilder { if let Ok(ref mut req) = self.request { - *req.default_headers_mut() = Some(skip); + *req.config_mut::() = Some(skip); } self } @@ -419,7 +364,7 @@ impl RequestBuilder { /// the timeout configured using `ClientBuilder::timeout()`. pub fn timeout(mut self, timeout: Duration) -> RequestBuilder { if let Ok(ref mut req) = self.request { - *req.timeout_mut() = Some(timeout); + *req.config_mut::() = Some(timeout); } self } @@ -431,7 +376,7 @@ impl RequestBuilder { /// overrides the read timeout configured using `ClientBuilder::read_timeout()`. pub fn read_timeout(mut self, timeout: Duration) -> RequestBuilder { if let Ok(ref mut req) = self.request { - *req.read_timeout_mut() = Some(timeout); + *req.config_mut::() = Some(timeout); } self } @@ -524,7 +469,7 @@ impl RequestBuilder { /// Set the redirect policy for this request. pub fn redirect(mut self, policy: redirect::Policy) -> RequestBuilder { if let Ok(ref mut req) = self.request { - *req.redirect_mut() = Some(policy); + *req.config_mut::() = Some(policy); } self } @@ -533,8 +478,9 @@ impl RequestBuilder { #[cfg(feature = "gzip")] pub fn gzip(mut self, gzip: bool) -> RequestBuilder { if let Ok(ref mut req) = self.request { - let accept_encoding = req.accpet_encoding_mut().get_or_insert_default(); - accept_encoding.gzip(gzip); + req.config_mut::() + .get_or_insert_default() + .gzip(gzip); } self } @@ -543,8 +489,9 @@ impl RequestBuilder { #[cfg(feature = "brotli")] pub fn brotli(mut self, brotli: bool) -> RequestBuilder { if let Ok(ref mut req) = self.request { - let accept_encoding = req.accpet_encoding_mut().get_or_insert_default(); - accept_encoding.brotli(brotli); + req.config_mut::() + .get_or_insert_default() + .brotli(brotli); } self } @@ -553,8 +500,9 @@ impl RequestBuilder { #[cfg(feature = "deflate")] pub fn deflate(mut self, deflate: bool) -> RequestBuilder { if let Ok(ref mut req) = self.request { - let accept_encoding = req.accpet_encoding_mut().get_or_insert_default(); - accept_encoding.deflate(deflate); + req.config_mut::() + .get_or_insert_default() + .deflate(deflate); } self } @@ -563,8 +511,9 @@ impl RequestBuilder { #[cfg(feature = "zstd")] pub fn zstd(mut self, zstd: bool) -> RequestBuilder { if let Ok(ref mut req) = self.request { - let accept_encoding = req.accpet_encoding_mut().get_or_insert_default(); - accept_encoding.zstd(zstd); + req.config_mut::() + .get_or_insert_default() + .zstd(zstd); } self } @@ -590,7 +539,7 @@ impl RequestBuilder { /// ``` pub fn proxy(mut self, proxy: Proxy) -> RequestBuilder { if let Ok(ref mut req) = self.request { - *req.proxy_matcher_mut() = Some(proxy.into_matcher()); + *req.config_mut::() = Some(proxy.into_matcher()); } self } @@ -601,8 +550,9 @@ impl RequestBuilder { V: Into>, { if let Ok(ref mut req) = self.request { - let tcp_connect_options = req.tcp_connect_options_mut().get_or_insert_default(); - tcp_connect_options.set_local_address(local_address.into()); + req.config_mut::() + .get_or_insert_default() + .set_local_address(local_address.into()); } self } @@ -614,8 +564,9 @@ impl RequestBuilder { V6: Into>, { if let Ok(ref mut req) = self.request { - let tcp_connect_options = req.tcp_connect_options_mut().get_or_insert_default(); - tcp_connect_options.set_local_addresses(ipv4.into(), ipv6.into()); + req.config_mut::() + .get_or_insert_default() + .set_local_addresses(ipv4.into(), ipv6.into()); } self } @@ -638,8 +589,9 @@ impl RequestBuilder { I: Into>, { if let Ok(ref mut req) = self.request { - let tcp_connect_options = req.tcp_connect_options_mut().get_or_insert_default(); - tcp_connect_options.set_interface(interface.into()); + req.config_mut::() + .get_or_insert_default() + .set_interface(interface.into()); } self } @@ -661,7 +613,7 @@ impl RequestBuilder { if let Some((tls_opts, http1_opts, http2_opts)) = transport_opts.map(TransportOptions::into_parts) { - req.transport_options_mut() + req.config_mut::() .get_or_insert_default() .http1_options(http1_opts) .http2_options(http2_opts)