dusks_reqwest/blocking/
client.rs

1#[cfg(any(feature = "native-tls", feature = "__rustls",))]
2use std::any::Any;
3use std::convert::TryInto;
4use std::fmt;
5use std::future::Future;
6use std::net::IpAddr;
7use std::net::SocketAddr;
8use std::sync::Arc;
9use std::thread;
10use std::time::Duration;
11
12use http::header::HeaderValue;
13use log::{error, trace};
14use tokio::sync::{mpsc, oneshot};
15
16use super::request::{Request, RequestBuilder};
17use super::response::Response;
18use super::wait;
19use crate::dns::Resolve;
20#[cfg(feature = "__tls")]
21use crate::tls;
22#[cfg(feature = "__tls")]
23use crate::Certificate;
24#[cfg(any(feature = "native-tls", feature = "__rustls"))]
25use crate::Identity;
26use crate::{async_impl, header, redirect, IntoUrl, Method, Proxy};
27
28/// A `Client` to make Requests with.
29///
30/// The Client has various configuration values to tweak, but the defaults
31/// are set to what is usually the most commonly desired value. To configure a
32/// `Client`, use `Client::builder()`.
33///
34/// The `Client` holds a connection pool internally, so it is advised that
35/// you create one and **reuse** it.
36///
37/// # Examples
38///
39/// ```rust
40/// use reqwest::blocking::Client;
41/// #
42/// # fn run() -> Result<(), reqwest::Error> {
43/// let client = Client::new();
44/// let resp = client.get("http://httpbin.org/").send()?;
45/// #   drop(resp);
46/// #   Ok(())
47/// # }
48///
49/// ```
50#[derive(Clone)]
51pub struct Client {
52    inner: ClientHandle,
53}
54
55/// A `ClientBuilder` can be used to create a `Client` with  custom configuration.
56///
57/// # Example
58///
59/// ```
60/// # fn run() -> Result<(), reqwest::Error> {
61/// use std::time::Duration;
62///
63/// let client = reqwest::blocking::Client::builder()
64///     .timeout(Duration::from_secs(10))
65///     .build()?;
66/// # Ok(())
67/// # }
68/// ```
69#[must_use]
70pub struct ClientBuilder {
71    inner: async_impl::ClientBuilder,
72    timeout: Timeout,
73}
74
75impl Default for ClientBuilder {
76    fn default() -> Self {
77        Self::new()
78    }
79}
80
81impl ClientBuilder {
82    /// Constructs a new `ClientBuilder`.
83    ///
84    /// This is the same as `Client::builder()`.
85    pub fn new() -> ClientBuilder {
86        ClientBuilder {
87            inner: async_impl::ClientBuilder::new(),
88            timeout: Timeout::default(),
89        }
90    }
91
92    /// Returns a `Client` that uses this `ClientBuilder` configuration.
93    ///
94    /// # Errors
95    ///
96    /// This method fails if TLS backend cannot be initialized, or the resolver
97    /// cannot load the system configuration.
98    ///
99    /// # Panics
100    ///
101    /// This method panics if called from within an async runtime. See docs on
102    /// [`reqwest::blocking`][crate::blocking] for details.
103    pub fn build(self) -> crate::Result<Client> {
104        ClientHandle::new(self).map(|handle| Client { inner: handle })
105    }
106
107    // Higher-level options
108
109    /// Sets the `User-Agent` header to be used by this client.
110    ///
111    /// # Example
112    ///
113    /// ```rust
114    /// # fn doc() -> Result<(), reqwest::Error> {
115    /// // Name your user agent after your app?
116    /// static APP_USER_AGENT: &str = concat!(
117    ///     env!("CARGO_PKG_NAME"),
118    ///     "/",
119    ///     env!("CARGO_PKG_VERSION"),
120    /// );
121    ///
122    /// let client = reqwest::blocking::Client::builder()
123    ///     .user_agent(APP_USER_AGENT)
124    ///     .build()?;
125    /// let res = client.get("https://www.rust-lang.org").send()?;
126    /// # Ok(())
127    /// # }
128    /// ```
129    pub fn user_agent<V>(self, value: V) -> ClientBuilder
130    where
131        V: TryInto<HeaderValue>,
132        V::Error: Into<http::Error>,
133    {
134        self.with_inner(move |inner| inner.user_agent(value))
135    }
136
137    /// Sets the default headers for every request.
138    ///
139    /// # Example
140    ///
141    /// ```rust
142    /// use reqwest::header;
143    /// # fn build_client() -> Result<(), reqwest::Error> {
144    /// let mut headers = header::HeaderMap::new();
145    /// headers.insert("X-MY-HEADER", header::HeaderValue::from_static("value"));
146    /// headers.insert(header::AUTHORIZATION, header::HeaderValue::from_static("secret"));
147    ///
148    /// // Consider marking security-sensitive headers with `set_sensitive`.
149    /// let mut auth_value = header::HeaderValue::from_static("secret");
150    /// auth_value.set_sensitive(true);
151    /// headers.insert(header::AUTHORIZATION, auth_value);
152    ///
153    /// // get a client builder
154    /// let client = reqwest::blocking::Client::builder()
155    ///     .default_headers(headers)
156    ///     .build()?;
157    /// let res = client.get("https://www.rust-lang.org").send()?;
158    /// # Ok(())
159    /// # }
160    /// ```
161    pub fn default_headers(self, headers: header::HeaderMap) -> ClientBuilder {
162        self.with_inner(move |inner| inner.default_headers(headers))
163    }
164
165    /// Enable a persistent cookie store for the client.
166    ///
167    /// Cookies received in responses will be preserved and included in
168    /// additional requests.
169    ///
170    /// By default, no cookie store is used.
171    ///
172    /// # Optional
173    ///
174    /// This requires the optional `cookies` feature to be enabled.
175    #[cfg(feature = "cookies")]
176    #[cfg_attr(docsrs, doc(cfg(feature = "cookies")))]
177    pub fn cookie_store(self, enable: bool) -> ClientBuilder {
178        self.with_inner(|inner| inner.cookie_store(enable))
179    }
180
181    /// Set the persistent cookie store for the client.
182    ///
183    /// Cookies received in responses will be passed to this store, and
184    /// additional requests will query this store for cookies.
185    ///
186    /// By default, no cookie store is used.
187    ///
188    /// # Optional
189    ///
190    /// This requires the optional `cookies` feature to be enabled.
191    #[cfg(feature = "cookies")]
192    #[cfg_attr(docsrs, doc(cfg(feature = "cookies")))]
193    pub fn cookie_provider<C: crate::cookie::CookieStore + 'static>(
194        self,
195        cookie_store: Arc<C>,
196    ) -> ClientBuilder {
197        self.with_inner(|inner| inner.cookie_provider(cookie_store))
198    }
199
200    /// Enable auto gzip decompression by checking the `Content-Encoding` response header.
201    ///
202    /// If auto gzip decompresson is turned on:
203    ///
204    /// - When sending a request and if the request's headers do not already contain
205    ///   an `Accept-Encoding` **and** `Range` values, the `Accept-Encoding` header is set to `gzip`.
206    ///   The request body is **not** automatically compressed.
207    /// - When receiving a response, if it's headers contain a `Content-Encoding` value that
208    ///   equals to `gzip`, both values `Content-Encoding` and `Content-Length` are removed from the
209    ///   headers' set. The response body is automatically decompressed.
210    ///
211    /// If the `gzip` feature is turned on, the default option is enabled.
212    ///
213    /// # Optional
214    ///
215    /// This requires the optional `gzip` feature to be enabled
216    #[cfg(feature = "gzip")]
217    #[cfg_attr(docsrs, doc(cfg(feature = "gzip")))]
218    pub fn gzip(self, enable: bool) -> ClientBuilder {
219        self.with_inner(|inner| inner.gzip(enable))
220    }
221
222    /// Enable auto brotli decompression by checking the `Content-Encoding` response header.
223    ///
224    /// If auto brotli decompression is turned on:
225    ///
226    /// - When sending a request and if the request's headers do not already contain
227    ///   an `Accept-Encoding` **and** `Range` values, the `Accept-Encoding` header is set to `br`.
228    ///   The request body is **not** automatically compressed.
229    /// - When receiving a response, if it's headers contain a `Content-Encoding` value that
230    ///   equals to `br`, both values `Content-Encoding` and `Content-Length` are removed from the
231    ///   headers' set. The response body is automatically decompressed.
232    ///
233    /// If the `brotli` feature is turned on, the default option is enabled.
234    ///
235    /// # Optional
236    ///
237    /// This requires the optional `brotli` feature to be enabled
238    #[cfg(feature = "brotli")]
239    #[cfg_attr(docsrs, doc(cfg(feature = "brotli")))]
240    pub fn brotli(self, enable: bool) -> ClientBuilder {
241        self.with_inner(|inner| inner.brotli(enable))
242    }
243
244    /// Enable auto zstd decompression by checking the `Content-Encoding` response header.
245    ///
246    /// If auto zstd decompression is turned on:
247    ///
248    /// - When sending a request and if the request's headers do not already contain
249    ///   an `Accept-Encoding` **and** `Range` values, the `Accept-Encoding` header is set to `zstd`.
250    ///   The request body is **not** automatically compressed.
251    /// - When receiving a response, if its headers contain a `Content-Encoding` value of
252    ///   `zstd`, both `Content-Encoding` and `Content-Length` are removed from the
253    ///   headers' set. The response body is automatically decompressed.
254    ///
255    /// If the `zstd` feature is turned on, the default option is enabled.
256    ///
257    /// # Optional
258    ///
259    /// This requires the optional `zstd` feature to be enabled
260    #[cfg(feature = "zstd")]
261    #[cfg_attr(docsrs, doc(cfg(feature = "zstd")))]
262    pub fn zstd(self, enable: bool) -> ClientBuilder {
263        self.with_inner(|inner| inner.zstd(enable))
264    }
265
266    /// Enable auto deflate decompression by checking the `Content-Encoding` response header.
267    ///
268    /// If auto deflate decompresson is turned on:
269    ///
270    /// - When sending a request and if the request's headers do not already contain
271    ///   an `Accept-Encoding` **and** `Range` values, the `Accept-Encoding` header is set to `deflate`.
272    ///   The request body is **not** automatically compressed.
273    /// - When receiving a response, if it's headers contain a `Content-Encoding` value that
274    ///   equals to `deflate`, both values `Content-Encoding` and `Content-Length` are removed from the
275    ///   headers' set. The response body is automatically decompressed.
276    ///
277    /// If the `deflate` feature is turned on, the default option is enabled.
278    ///
279    /// # Optional
280    ///
281    /// This requires the optional `deflate` feature to be enabled
282    #[cfg(feature = "deflate")]
283    #[cfg_attr(docsrs, doc(cfg(feature = "deflate")))]
284    pub fn deflate(self, enable: bool) -> ClientBuilder {
285        self.with_inner(|inner| inner.deflate(enable))
286    }
287
288    /// Disable auto response body gzip decompression.
289    ///
290    /// This method exists even if the optional `gzip` feature is not enabled.
291    /// This can be used to ensure a `Client` doesn't use gzip decompression
292    /// even if another dependency were to enable the optional `gzip` feature.
293    pub fn no_gzip(self) -> ClientBuilder {
294        self.with_inner(|inner| inner.no_gzip())
295    }
296
297    /// Disable auto response body brotli decompression.
298    ///
299    /// This method exists even if the optional `brotli` feature is not enabled.
300    /// This can be used to ensure a `Client` doesn't use brotli decompression
301    /// even if another dependency were to enable the optional `brotli` feature.
302    pub fn no_brotli(self) -> ClientBuilder {
303        self.with_inner(|inner| inner.no_brotli())
304    }
305
306    /// Disable auto response body zstd decompression.
307    ///
308    /// This method exists even if the optional `zstd` feature is not enabled.
309    /// This can be used to ensure a `Client` doesn't use zstd decompression
310    /// even if another dependency were to enable the optional `zstd` feature.
311    pub fn no_zstd(self) -> ClientBuilder {
312        self.with_inner(|inner| inner.no_zstd())
313    }
314
315    /// Disable auto response body deflate decompression.
316    ///
317    /// This method exists even if the optional `deflate` feature is not enabled.
318    /// This can be used to ensure a `Client` doesn't use deflate decompression
319    /// even if another dependency were to enable the optional `deflate` feature.
320    pub fn no_deflate(self) -> ClientBuilder {
321        self.with_inner(|inner| inner.no_deflate())
322    }
323
324    // Redirect options
325
326    /// Set a `redirect::Policy` for this client.
327    ///
328    /// Default will follow redirects up to a maximum of 10.
329    pub fn redirect(self, policy: redirect::Policy) -> ClientBuilder {
330        self.with_inner(move |inner| inner.redirect(policy))
331    }
332
333    /// Enable or disable automatic setting of the `Referer` header.
334    ///
335    /// Default is `true`.
336    pub fn referer(self, enable: bool) -> ClientBuilder {
337        self.with_inner(|inner| inner.referer(enable))
338    }
339
340    // Proxy options
341
342    /// Add a `Proxy` to the list of proxies the `Client` will use.
343    ///
344    /// # Note
345    ///
346    /// Adding a proxy will disable the automatic usage of the "system" proxy.
347    pub fn proxy(self, proxy: Proxy) -> ClientBuilder {
348        self.with_inner(move |inner| inner.proxy(proxy))
349    }
350
351    /// Clear all `Proxies`, so `Client` will use no proxy anymore.
352    ///
353    /// # Note
354    /// To add a proxy exclusion list, use [crate::proxy::Proxy::no_proxy()]
355    /// on all desired proxies instead.
356    ///
357    /// This also disables the automatic usage of the "system" proxy.
358    pub fn no_proxy(self) -> ClientBuilder {
359        self.with_inner(move |inner| inner.no_proxy())
360    }
361
362    // Timeout options
363
364    /// Set a timeout for connect, read and write operations of a `Client`.
365    ///
366    /// Default is 30 seconds.
367    ///
368    /// Pass `None` to disable timeout.
369    pub fn timeout<T>(mut self, timeout: T) -> ClientBuilder
370    where
371        T: Into<Option<Duration>>,
372    {
373        self.timeout = Timeout(timeout.into());
374        self
375    }
376
377    /// Set a timeout for only the connect phase of a `Client`.
378    ///
379    /// Default is `None`.
380    pub fn connect_timeout<T>(self, timeout: T) -> ClientBuilder
381    where
382        T: Into<Option<Duration>>,
383    {
384        let timeout = timeout.into();
385        if let Some(dur) = timeout {
386            self.with_inner(|inner| inner.connect_timeout(dur))
387        } else {
388            self
389        }
390    }
391
392    /// Set whether connections should emit verbose logs.
393    ///
394    /// Enabling this option will emit [log][] messages at the `TRACE` level
395    /// for read and write operations on connections.
396    ///
397    /// [log]: https://crates.io/crates/log
398    pub fn connection_verbose(self, verbose: bool) -> ClientBuilder {
399        self.with_inner(move |inner| inner.connection_verbose(verbose))
400    }
401
402    // HTTP options
403
404    /// Set an optional timeout for idle sockets being kept-alive.
405    ///
406    /// Pass `None` to disable timeout.
407    ///
408    /// Default is 90 seconds.
409    pub fn pool_idle_timeout<D>(self, val: D) -> ClientBuilder
410    where
411        D: Into<Option<Duration>>,
412    {
413        self.with_inner(|inner| inner.pool_idle_timeout(val))
414    }
415
416    /// Sets the maximum idle connection per host allowed in the pool.
417    pub fn pool_max_idle_per_host(self, max: usize) -> ClientBuilder {
418        self.with_inner(move |inner| inner.pool_max_idle_per_host(max))
419    }
420
421    /// Send headers as title case instead of lowercase.
422    pub fn http1_title_case_headers(self) -> ClientBuilder {
423        self.with_inner(|inner| inner.http1_title_case_headers())
424    }
425
426    /// Set whether HTTP/1 connections will accept obsolete line folding for
427    /// header values.
428    ///
429    /// Newline codepoints (`\r` and `\n`) will be transformed to spaces when
430    /// parsing.
431    pub fn http1_allow_obsolete_multiline_headers_in_responses(self, value: bool) -> ClientBuilder {
432        self.with_inner(|inner| inner.http1_allow_obsolete_multiline_headers_in_responses(value))
433    }
434
435    /// Sets whether invalid header lines should be silently ignored in HTTP/1 responses.
436    pub fn http1_ignore_invalid_headers_in_responses(self, value: bool) -> ClientBuilder {
437        self.with_inner(|inner| inner.http1_ignore_invalid_headers_in_responses(value))
438    }
439
440    /// Set whether HTTP/1 connections will accept spaces between header
441    /// names and the colon that follow them in responses.
442    ///
443    /// Newline codepoints (\r and \n) will be transformed to spaces when
444    /// parsing.
445    pub fn http1_allow_spaces_after_header_name_in_responses(self, value: bool) -> ClientBuilder {
446        self.with_inner(|inner| inner.http1_allow_spaces_after_header_name_in_responses(value))
447    }
448
449    /// Only use HTTP/1.
450    pub fn http1_only(self) -> ClientBuilder {
451        self.with_inner(|inner| inner.http1_only())
452    }
453
454    /// Allow HTTP/0.9 responses
455    pub fn http09_responses(self) -> ClientBuilder {
456        self.with_inner(|inner| inner.http09_responses())
457    }
458
459    /// Only use HTTP/2.
460    #[cfg(feature = "http2")]
461    #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
462    pub fn http2_prior_knowledge(self) -> ClientBuilder {
463        self.with_inner(|inner| inner.http2_prior_knowledge())
464    }
465
466    /// Sets the `SETTINGS_INITIAL_WINDOW_SIZE` option for HTTP2 stream-level flow control.
467    ///
468    /// Default is currently 65,535 but may change internally to optimize for common uses.
469    #[cfg(feature = "http2")]
470    #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
471    pub fn http2_initial_stream_window_size(self, sz: impl Into<Option<u32>>) -> ClientBuilder {
472        self.with_inner(|inner| inner.http2_initial_stream_window_size(sz))
473    }
474
475    /// Sets the max connection-level flow control for HTTP2
476    ///
477    /// Default is currently 65,535 but may change internally to optimize for common uses.
478    #[cfg(feature = "http2")]
479    #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
480    pub fn http2_initial_connection_window_size(self, sz: impl Into<Option<u32>>) -> ClientBuilder {
481        self.with_inner(|inner| inner.http2_initial_connection_window_size(sz))
482    }
483
484    /// Sets whether to use an adaptive flow control.
485    ///
486    /// Enabling this will override the limits set in `http2_initial_stream_window_size` and
487    /// `http2_initial_connection_window_size`.
488    #[cfg(feature = "http2")]
489    #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
490    pub fn http2_adaptive_window(self, enabled: bool) -> ClientBuilder {
491        self.with_inner(|inner| inner.http2_adaptive_window(enabled))
492    }
493
494    /// Sets the maximum frame size to use for HTTP2.
495    ///
496    /// Default is currently 16,384 but may change internally to optimize for common uses.
497    #[cfg(feature = "http2")]
498    #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
499    pub fn http2_max_frame_size(self, sz: impl Into<Option<u32>>) -> ClientBuilder {
500        self.with_inner(|inner| inner.http2_max_frame_size(sz))
501    }
502
503    /// This requires the optional `http3` feature to be
504    /// enabled.
505    #[cfg(feature = "http3")]
506    #[cfg_attr(docsrs, doc(cfg(feature = "http3")))]
507    pub fn http3_prior_knowledge(self) -> ClientBuilder {
508        self.with_inner(|inner| inner.http3_prior_knowledge())
509    }
510
511    // TCP options
512
513    /// Set whether sockets have `TCP_NODELAY` enabled.
514    ///
515    /// Default is `true`.
516    pub fn tcp_nodelay(self, enabled: bool) -> ClientBuilder {
517        self.with_inner(move |inner| inner.tcp_nodelay(enabled))
518    }
519
520    /// Bind to a local IP Address.
521    ///
522    /// # Example
523    ///
524    /// ```
525    /// use std::net::IpAddr;
526    /// let local_addr = IpAddr::from([12, 4, 1, 8]);
527    /// let client = reqwest::blocking::Client::builder()
528    ///     .local_address(local_addr)
529    ///     .build().unwrap();
530    /// ```
531    pub fn local_address<T>(self, addr: T) -> ClientBuilder
532    where
533        T: Into<Option<IpAddr>>,
534    {
535        self.with_inner(move |inner| inner.local_address(addr))
536    }
537
538    /// Bind to an interface by `SO_BINDTODEVICE`.
539    ///
540    /// # Example
541    ///
542    /// ```
543    /// let interface = "lo";
544    /// let client = reqwest::blocking::Client::builder()
545    ///     .interface(interface)
546    ///     .build().unwrap();
547    /// ```
548    #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
549    pub fn interface(self, interface: &str) -> ClientBuilder {
550        self.with_inner(move |inner| inner.interface(interface))
551    }
552
553    /// Set that all sockets have `SO_KEEPALIVE` set with the supplied duration.
554    ///
555    /// If `None`, the option will not be set.
556    pub fn tcp_keepalive<D>(self, val: D) -> ClientBuilder
557    where
558        D: Into<Option<Duration>>,
559    {
560        self.with_inner(move |inner| inner.tcp_keepalive(val))
561    }
562
563    // TLS options
564
565    /// Add a custom root certificate.
566    ///
567    /// This allows connecting to a server that has a self-signed
568    /// certificate for example. This **does not** replace the existing
569    /// trusted store.
570    ///
571    /// # Example
572    ///
573    /// ```
574    /// # use std::fs::File;
575    /// # use std::io::Read;
576    /// # fn build_client() -> Result<(), Box<dyn std::error::Error>> {
577    /// // read a local binary DER encoded certificate
578    /// let der = std::fs::read("my-cert.der")?;
579    ///
580    /// // create a certificate
581    /// let cert = reqwest::Certificate::from_der(&der)?;
582    ///
583    /// // get a client builder
584    /// let client = reqwest::blocking::Client::builder()
585    ///     .add_root_certificate(cert)
586    ///     .build()?;
587    /// # drop(client);
588    /// # Ok(())
589    /// # }
590    /// ```
591    ///
592    /// # Optional
593    ///
594    /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
595    /// feature to be enabled.
596    #[cfg(feature = "__tls")]
597    #[cfg_attr(
598        docsrs,
599        doc(cfg(any(
600            feature = "default-tls",
601            feature = "native-tls",
602            feature = "rustls-tls"
603        )))
604    )]
605    pub fn add_root_certificate(self, cert: Certificate) -> ClientBuilder {
606        self.with_inner(move |inner| inner.add_root_certificate(cert))
607    }
608
609    /// Controls the use of built-in system certificates during certificate validation.
610    ///
611    /// Defaults to `true` -- built-in system certs will be used.
612    ///
613    /// # Optional
614    ///
615    /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
616    /// feature to be enabled.
617    #[cfg(feature = "__tls")]
618    #[cfg_attr(
619        docsrs,
620        doc(cfg(any(
621            feature = "default-tls",
622            feature = "native-tls",
623            feature = "rustls-tls"
624        )))
625    )]
626    pub fn tls_built_in_root_certs(self, tls_built_in_root_certs: bool) -> ClientBuilder {
627        self.with_inner(move |inner| inner.tls_built_in_root_certs(tls_built_in_root_certs))
628    }
629
630    /// Sets whether to load webpki root certs with rustls.
631    ///
632    /// If the feature is enabled, this value is `true` by default.
633    #[cfg(feature = "rustls-tls-webpki-roots")]
634    #[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls-webpki-roots")))]
635    pub fn tls_built_in_webpki_certs(self, enabled: bool) -> ClientBuilder {
636        self.with_inner(move |inner| inner.tls_built_in_webpki_certs(enabled))
637    }
638
639    /// Sets whether to load native root certs with rustls.
640    ///
641    /// If the feature is enabled, this value is `true` by default.
642    #[cfg(feature = "rustls-tls-native-roots")]
643    #[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls-native-roots")))]
644    pub fn tls_built_in_native_certs(self, enabled: bool) -> ClientBuilder {
645        self.with_inner(move |inner| inner.tls_built_in_native_certs(enabled))
646    }
647
648    /// Sets the identity to be used for client certificate authentication.
649    ///
650    /// # Optional
651    ///
652    /// This requires the optional `native-tls` or `rustls-tls(-...)` feature to be
653    /// enabled.
654    #[cfg(any(feature = "native-tls", feature = "__rustls"))]
655    #[cfg_attr(docsrs, doc(cfg(any(feature = "native-tls", feature = "rustls-tls"))))]
656    pub fn identity(self, identity: Identity) -> ClientBuilder {
657        self.with_inner(move |inner| inner.identity(identity))
658    }
659
660    /// Controls the use of hostname verification.
661    ///
662    /// Defaults to `false`.
663    ///
664    /// # Warning
665    ///
666    /// You should think very carefully before you use this method. If
667    /// hostname verification is not used, any valid certificate for any
668    /// site will be trusted for use from any other. This introduces a
669    /// significant vulnerability to man-in-the-middle attacks.
670    ///
671    /// # Optional
672    ///
673    /// This requires the optional `native-tls` feature to be enabled.
674    #[cfg(feature = "native-tls")]
675    #[cfg_attr(docsrs, doc(cfg(feature = "native-tls")))]
676    pub fn danger_accept_invalid_hostnames(self, accept_invalid_hostname: bool) -> ClientBuilder {
677        self.with_inner(|inner| inner.danger_accept_invalid_hostnames(accept_invalid_hostname))
678    }
679
680    /// Controls the use of certificate validation.
681    ///
682    /// Defaults to `false`.
683    ///
684    /// # Warning
685    ///
686    /// You should think very carefully before using this method. If
687    /// invalid certificates are trusted, *any* certificate for *any* site
688    /// will be trusted for use. This includes expired certificates. This
689    /// introduces significant vulnerabilities, and should only be used
690    /// as a last resort.
691    #[cfg(feature = "__tls")]
692    #[cfg_attr(
693        docsrs,
694        doc(cfg(any(
695            feature = "default-tls",
696            feature = "native-tls",
697            feature = "rustls-tls"
698        )))
699    )]
700    pub fn danger_accept_invalid_certs(self, accept_invalid_certs: bool) -> ClientBuilder {
701        self.with_inner(|inner| inner.danger_accept_invalid_certs(accept_invalid_certs))
702    }
703
704    /// Controls the use of TLS server name indication.
705    ///
706    /// Defaults to `true`.
707    #[cfg(feature = "__tls")]
708    #[cfg_attr(
709        docsrs,
710        doc(cfg(any(
711            feature = "default-tls",
712            feature = "native-tls",
713            feature = "rustls-tls"
714        )))
715    )]
716    pub fn tls_sni(self, tls_sni: bool) -> ClientBuilder {
717        self.with_inner(|inner| inner.tls_sni(tls_sni))
718    }
719
720    /// Set the minimum required TLS version for connections.
721    ///
722    /// By default the TLS backend's own default is used.
723    ///
724    /// # Errors
725    ///
726    /// A value of `tls::Version::TLS_1_3` will cause an error with the
727    /// `native-tls`/`default-tls` backend. This does not mean the version
728    /// isn't supported, just that it can't be set as a minimum due to
729    /// technical limitations.
730    ///
731    /// # Optional
732    ///
733    /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
734    /// feature to be enabled.
735    #[cfg(feature = "__tls")]
736    #[cfg_attr(
737        docsrs,
738        doc(cfg(any(
739            feature = "default-tls",
740            feature = "native-tls",
741            feature = "rustls-tls"
742        )))
743    )]
744    pub fn min_tls_version(self, version: tls::Version) -> ClientBuilder {
745        self.with_inner(|inner| inner.min_tls_version(version))
746    }
747
748    /// Set the maximum allowed TLS version for connections.
749    ///
750    /// By default there's no maximum.
751    ///
752    /// # Errors
753    ///
754    /// A value of `tls::Version::TLS_1_3` will cause an error with the
755    /// `native-tls`/`default-tls` backend. This does not mean the version
756    /// isn't supported, just that it can't be set as a maximum due to
757    /// technical limitations.
758    ///
759    /// # Optional
760    ///
761    /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
762    /// feature to be enabled.
763    #[cfg(feature = "__tls")]
764    #[cfg_attr(
765        docsrs,
766        doc(cfg(any(
767            feature = "default-tls",
768            feature = "native-tls",
769            feature = "rustls-tls"
770        )))
771    )]
772    pub fn max_tls_version(self, version: tls::Version) -> ClientBuilder {
773        self.with_inner(|inner| inner.max_tls_version(version))
774    }
775
776    /// Force using the native TLS backend.
777    ///
778    /// Since multiple TLS backends can be optionally enabled, this option will
779    /// force the `native-tls` backend to be used for this `Client`.
780    ///
781    /// # Optional
782    ///
783    /// This requires the optional `native-tls` feature to be enabled.
784    #[cfg(feature = "native-tls")]
785    #[cfg_attr(docsrs, doc(cfg(feature = "native-tls")))]
786    pub fn use_native_tls(self) -> ClientBuilder {
787        self.with_inner(move |inner| inner.use_native_tls())
788    }
789
790    /// Force using the Rustls TLS backend.
791    ///
792    /// Since multiple TLS backends can be optionally enabled, this option will
793    /// force the `rustls` backend to be used for this `Client`.
794    ///
795    /// # Optional
796    ///
797    /// This requires the optional `rustls-tls(-...)` feature to be enabled.
798    #[cfg(feature = "__rustls")]
799    #[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls")))]
800    pub fn use_rustls_tls(self) -> ClientBuilder {
801        self.with_inner(move |inner| inner.use_rustls_tls())
802    }
803
804    /// Add TLS information as `TlsInfo` extension to responses.
805    ///
806    /// # Optional
807    ///
808    /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
809    /// feature to be enabled.
810    #[cfg(feature = "__tls")]
811    #[cfg_attr(
812        docsrs,
813        doc(cfg(any(
814            feature = "default-tls",
815            feature = "native-tls",
816            feature = "rustls-tls"
817        )))
818    )]
819    pub fn tls_info(self, tls_info: bool) -> ClientBuilder {
820        self.with_inner(|inner| inner.tls_info(tls_info))
821    }
822
823    /// Use a preconfigured TLS backend.
824    ///
825    /// If the passed `Any` argument is not a TLS backend that reqwest
826    /// understands, the `ClientBuilder` will error when calling `build`.
827    ///
828    /// # Advanced
829    ///
830    /// This is an advanced option, and can be somewhat brittle. Usage requires
831    /// keeping the preconfigured TLS argument version in sync with reqwest,
832    /// since version mismatches will result in an "unknown" TLS backend.
833    ///
834    /// If possible, it's preferable to use the methods on `ClientBuilder`
835    /// to configure reqwest's TLS.
836    ///
837    /// # Optional
838    ///
839    /// This requires one of the optional features `native-tls` or
840    /// `rustls-tls(-...)` to be enabled.
841    #[cfg(any(feature = "native-tls", feature = "__rustls",))]
842    #[cfg_attr(docsrs, doc(cfg(any(feature = "native-tls", feature = "rustls-tls"))))]
843    pub fn use_preconfigured_tls(self, tls: impl Any) -> ClientBuilder {
844        self.with_inner(move |inner| inner.use_preconfigured_tls(tls))
845    }
846
847    /// Enables the [hickory-dns](hickory_resolver) async resolver instead of a default threadpool using `getaddrinfo`.
848    ///
849    /// If the `hickory-dns` feature is turned on, the default option is enabled.
850    ///
851    /// # Optional
852    ///
853    /// This requires the optional `hickory-dns` feature to be enabled
854    #[cfg(feature = "hickory-dns")]
855    #[cfg_attr(docsrs, doc(cfg(feature = "hickory-dns")))]
856    #[deprecated(note = "use `hickory_dns` instead", since = "0.12.0")]
857    pub fn trust_dns(self, enable: bool) -> ClientBuilder {
858        self.with_inner(|inner| inner.hickory_dns(enable))
859    }
860
861    /// Enables the [hickory-dns](hickory_resolver) async resolver instead of a default threadpool using `getaddrinfo`.
862    ///
863    /// If the `hickory-dns` feature is turned on, the default option is enabled.
864    ///
865    /// # Optional
866    ///
867    /// This requires the optional `hickory-dns` feature to be enabled
868    #[cfg(feature = "hickory-dns")]
869    #[cfg_attr(docsrs, doc(cfg(feature = "hickory-dns")))]
870    pub fn hickory_dns(self, enable: bool) -> ClientBuilder {
871        self.with_inner(|inner| inner.hickory_dns(enable))
872    }
873
874    /// Disables the hickory-dns async resolver.
875    ///
876    /// This method exists even if the optional `hickory-dns` feature is not enabled.
877    /// This can be used to ensure a `Client` doesn't use the hickory-dns async resolver
878    /// even if another dependency were to enable the optional `hickory-dns` feature.
879    #[deprecated(note = "use `no_hickory_dns` instead", since = "0.12.0")]
880    pub fn no_trust_dns(self) -> ClientBuilder {
881        self.with_inner(|inner| inner.no_hickory_dns())
882    }
883
884    /// Disables the hickory-dns async resolver.
885    ///
886    /// This method exists even if the optional `hickory-dns` feature is not enabled.
887    /// This can be used to ensure a `Client` doesn't use the hickory-dns async resolver
888    /// even if another dependency were to enable the optional `hickory-dns` feature.
889    pub fn no_hickory_dns(self) -> ClientBuilder {
890        self.with_inner(|inner| inner.no_hickory_dns())
891    }
892
893    /// Restrict the Client to be used with HTTPS only requests.
894    ///
895    /// Defaults to false.
896    pub fn https_only(self, enabled: bool) -> ClientBuilder {
897        self.with_inner(|inner| inner.https_only(enabled))
898    }
899
900    /// Override DNS resolution for specific domains to a particular IP address.
901    ///
902    /// Warning
903    ///
904    /// Since the DNS protocol has no notion of ports, if you wish to send
905    /// traffic to a particular port you must include this port in the URL
906    /// itself, any port in the overridden addr will be ignored and traffic sent
907    /// to the conventional port for the given scheme (e.g. 80 for http).
908    pub fn resolve(self, domain: &str, addr: SocketAddr) -> ClientBuilder {
909        self.resolve_to_addrs(domain, &[addr])
910    }
911
912    /// Override DNS resolution for specific domains to particular IP addresses.
913    ///
914    /// Warning
915    ///
916    /// Since the DNS protocol has no notion of ports, if you wish to send
917    /// traffic to a particular port you must include this port in the URL
918    /// itself, any port in the overridden addresses will be ignored and traffic sent
919    /// to the conventional port for the given scheme (e.g. 80 for http).
920    pub fn resolve_to_addrs(self, domain: &str, addrs: &[SocketAddr]) -> ClientBuilder {
921        self.with_inner(|inner| inner.resolve_to_addrs(domain, addrs))
922    }
923
924    /// Override the DNS resolver implementation.
925    ///
926    /// Pass an `Arc` wrapping a trait object implementing `Resolve`.
927    /// Overrides for specific names passed to `resolve` and `resolve_to_addrs` will
928    /// still be applied on top of this resolver.
929    pub fn dns_resolver<R: Resolve + 'static>(self, resolver: Arc<R>) -> ClientBuilder {
930        self.with_inner(|inner| inner.dns_resolver(resolver))
931    }
932
933    // private
934
935    fn with_inner<F>(mut self, func: F) -> ClientBuilder
936    where
937        F: FnOnce(async_impl::ClientBuilder) -> async_impl::ClientBuilder,
938    {
939        self.inner = func(self.inner);
940        self
941    }
942}
943
944impl From<async_impl::ClientBuilder> for ClientBuilder {
945    fn from(builder: async_impl::ClientBuilder) -> Self {
946        Self {
947            inner: builder,
948            timeout: Timeout::default(),
949        }
950    }
951}
952
953impl Default for Client {
954    fn default() -> Self {
955        Self::new()
956    }
957}
958
959impl Client {
960    /// Constructs a new `Client`.
961    ///
962    /// # Panic
963    ///
964    /// This method panics if TLS backend cannot be initialized, or the resolver
965    /// cannot load the system configuration.
966    ///
967    /// Use `Client::builder()` if you wish to handle the failure as an `Error`
968    /// instead of panicking.
969    ///
970    /// This method also panics if called from within an async runtime. See docs
971    /// on [`reqwest::blocking`][crate::blocking] for details.
972    pub fn new() -> Client {
973        ClientBuilder::new().build().expect("Client::new()")
974    }
975
976    /// Creates a `ClientBuilder` to configure a `Client`.
977    ///
978    /// This is the same as `ClientBuilder::new()`.
979    pub fn builder() -> ClientBuilder {
980        ClientBuilder::new()
981    }
982
983    /// Convenience method to make a `GET` request to a URL.
984    ///
985    /// # Errors
986    ///
987    /// This method fails whenever supplied `Url` cannot be parsed.
988    pub fn get<U: IntoUrl>(&self, url: U) -> RequestBuilder {
989        self.request(Method::GET, url)
990    }
991
992    /// Convenience method to make a `POST` request to a URL.
993    ///
994    /// # Errors
995    ///
996    /// This method fails whenever supplied `Url` cannot be parsed.
997    pub fn post<U: IntoUrl>(&self, url: U) -> RequestBuilder {
998        self.request(Method::POST, url)
999    }
1000
1001    /// Convenience method to make a `PUT` request to a URL.
1002    ///
1003    /// # Errors
1004    ///
1005    /// This method fails whenever supplied `Url` cannot be parsed.
1006    pub fn put<U: IntoUrl>(&self, url: U) -> RequestBuilder {
1007        self.request(Method::PUT, url)
1008    }
1009
1010    /// Convenience method to make a `PATCH` request to a URL.
1011    ///
1012    /// # Errors
1013    ///
1014    /// This method fails whenever supplied `Url` cannot be parsed.
1015    pub fn patch<U: IntoUrl>(&self, url: U) -> RequestBuilder {
1016        self.request(Method::PATCH, url)
1017    }
1018
1019    /// Convenience method to make a `DELETE` request to a URL.
1020    ///
1021    /// # Errors
1022    ///
1023    /// This method fails whenever supplied `Url` cannot be parsed.
1024    pub fn delete<U: IntoUrl>(&self, url: U) -> RequestBuilder {
1025        self.request(Method::DELETE, url)
1026    }
1027
1028    /// Convenience method to make a `HEAD` request to a URL.
1029    ///
1030    /// # Errors
1031    ///
1032    /// This method fails whenever supplied `Url` cannot be parsed.
1033    pub fn head<U: IntoUrl>(&self, url: U) -> RequestBuilder {
1034        self.request(Method::HEAD, url)
1035    }
1036
1037    /// Start building a `Request` with the `Method` and `Url`.
1038    ///
1039    /// Returns a `RequestBuilder`, which will allow setting headers and
1040    /// request body before sending.
1041    ///
1042    /// # Errors
1043    ///
1044    /// This method fails whenever supplied `Url` cannot be parsed.
1045    pub fn request<U: IntoUrl>(&self, method: Method, url: U) -> RequestBuilder {
1046        let req = url.into_url().map(move |url| Request::new(method, url));
1047        RequestBuilder::new(self.clone(), req)
1048    }
1049
1050    /// Executes a `Request`.
1051    ///
1052    /// A `Request` can be built manually with `Request::new()` or obtained
1053    /// from a RequestBuilder with `RequestBuilder::build()`.
1054    ///
1055    /// You should prefer to use the `RequestBuilder` and
1056    /// `RequestBuilder::send()`.
1057    ///
1058    /// # Errors
1059    ///
1060    /// This method fails if there was an error while sending request,
1061    /// or redirect limit was exhausted.
1062    pub fn execute(&self, request: Request) -> crate::Result<Response> {
1063        self.inner.execute_request(request)
1064    }
1065}
1066
1067impl fmt::Debug for Client {
1068    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1069        f.debug_struct("Client")
1070            //.field("gzip", &self.inner.gzip)
1071            //.field("redirect_policy", &self.inner.redirect_policy)
1072            //.field("referer", &self.inner.referer)
1073            .finish()
1074    }
1075}
1076
1077impl fmt::Debug for ClientBuilder {
1078    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1079        self.inner.fmt(f)
1080    }
1081}
1082
1083#[derive(Clone)]
1084struct ClientHandle {
1085    timeout: Timeout,
1086    inner: Arc<InnerClientHandle>,
1087}
1088
1089type OneshotResponse = oneshot::Sender<crate::Result<async_impl::Response>>;
1090type ThreadSender = mpsc::UnboundedSender<(async_impl::Request, OneshotResponse)>;
1091
1092struct InnerClientHandle {
1093    tx: Option<ThreadSender>,
1094    thread: Option<thread::JoinHandle<()>>,
1095}
1096
1097impl Drop for InnerClientHandle {
1098    fn drop(&mut self) {
1099        let id = self
1100            .thread
1101            .as_ref()
1102            .map(|h| h.thread().id())
1103            .expect("thread not dropped yet");
1104
1105        trace!("closing runtime thread ({id:?})");
1106        self.tx.take();
1107        trace!("signaled close for runtime thread ({id:?})");
1108        self.thread.take().map(|h| h.join());
1109        trace!("closed runtime thread ({id:?})");
1110    }
1111}
1112
1113impl ClientHandle {
1114    fn new(builder: ClientBuilder) -> crate::Result<ClientHandle> {
1115        let timeout = builder.timeout;
1116        let builder = builder.inner;
1117        let (tx, rx) = mpsc::unbounded_channel::<(async_impl::Request, OneshotResponse)>();
1118        let (spawn_tx, spawn_rx) = oneshot::channel::<crate::Result<()>>();
1119        let handle = thread::Builder::new()
1120            .name("reqwest-internal-sync-runtime".into())
1121            .spawn(move || {
1122                use tokio::runtime;
1123                let rt = match runtime::Builder::new_current_thread()
1124                    .enable_all()
1125                    .build()
1126                    .map_err(crate::error::builder)
1127                {
1128                    Err(e) => {
1129                        if let Err(e) = spawn_tx.send(Err(e)) {
1130                            error!("Failed to communicate runtime creation failure: {e:?}");
1131                        }
1132                        return;
1133                    }
1134                    Ok(v) => v,
1135                };
1136
1137                let f = async move {
1138                    let client = match builder.build() {
1139                        Err(e) => {
1140                            if let Err(e) = spawn_tx.send(Err(e)) {
1141                                error!("Failed to communicate client creation failure: {e:?}");
1142                            }
1143                            return;
1144                        }
1145                        Ok(v) => v,
1146                    };
1147                    if let Err(e) = spawn_tx.send(Ok(())) {
1148                        error!("Failed to communicate successful startup: {e:?}");
1149                        return;
1150                    }
1151
1152                    let mut rx = rx;
1153
1154                    while let Some((req, req_tx)) = rx.recv().await {
1155                        let req_fut = client.execute(req);
1156                        tokio::spawn(forward(req_fut, req_tx));
1157                    }
1158
1159                    trace!("({:?}) Receiver is shutdown", thread::current().id());
1160                };
1161
1162                trace!("({:?}) start runtime::block_on", thread::current().id());
1163                rt.block_on(f);
1164                trace!("({:?}) end runtime::block_on", thread::current().id());
1165                drop(rt);
1166                trace!("({:?}) finished", thread::current().id());
1167            })
1168            .map_err(crate::error::builder)?;
1169
1170        // Wait for the runtime thread to start up...
1171        match wait::timeout(spawn_rx, None) {
1172            Ok(Ok(())) => (),
1173            Ok(Err(err)) => return Err(err),
1174            Err(_canceled) => event_loop_panicked(),
1175        }
1176
1177        let inner_handle = Arc::new(InnerClientHandle {
1178            tx: Some(tx),
1179            thread: Some(handle),
1180        });
1181
1182        Ok(ClientHandle {
1183            timeout,
1184            inner: inner_handle,
1185        })
1186    }
1187
1188    fn execute_request(&self, req: Request) -> crate::Result<Response> {
1189        let (tx, rx) = oneshot::channel();
1190        let (req, body) = req.into_async();
1191        let url = req.url().clone();
1192        let timeout = req.timeout().copied().or(self.timeout.0);
1193
1194        self.inner
1195            .tx
1196            .as_ref()
1197            .expect("core thread exited early")
1198            .send((req, tx))
1199            .expect("core thread panicked");
1200
1201        let result: Result<crate::Result<async_impl::Response>, wait::Waited<crate::Error>> =
1202            if let Some(body) = body {
1203                let f = async move {
1204                    body.send().await?;
1205                    rx.await.map_err(|_canceled| event_loop_panicked())
1206                };
1207                wait::timeout(f, timeout)
1208            } else {
1209                let f = async move { rx.await.map_err(|_canceled| event_loop_panicked()) };
1210                wait::timeout(f, timeout)
1211            };
1212
1213        match result {
1214            Ok(Err(err)) => Err(err.with_url(url)),
1215            Ok(Ok(res)) => Ok(Response::new(
1216                res,
1217                timeout,
1218                KeepCoreThreadAlive(Some(self.inner.clone())),
1219            )),
1220            Err(wait::Waited::TimedOut(e)) => Err(crate::error::request(e).with_url(url)),
1221            Err(wait::Waited::Inner(err)) => Err(err.with_url(url)),
1222        }
1223    }
1224}
1225
1226async fn forward<F>(fut: F, mut tx: OneshotResponse)
1227where
1228    F: Future<Output = crate::Result<async_impl::Response>>,
1229{
1230    use std::task::Poll;
1231
1232    futures_util::pin_mut!(fut);
1233
1234    // "select" on the sender being canceled, and the future completing
1235    let res = futures_util::future::poll_fn(|cx| {
1236        match fut.as_mut().poll(cx) {
1237            Poll::Ready(val) => Poll::Ready(Some(val)),
1238            Poll::Pending => {
1239                // check if the callback is canceled
1240                futures_core::ready!(tx.poll_closed(cx));
1241                Poll::Ready(None)
1242            }
1243        }
1244    })
1245    .await;
1246
1247    if let Some(res) = res {
1248        let _ = tx.send(res);
1249    }
1250    // else request is canceled
1251}
1252
1253#[derive(Clone, Copy)]
1254struct Timeout(Option<Duration>);
1255
1256impl Default for Timeout {
1257    fn default() -> Timeout {
1258        // default mentioned in ClientBuilder::timeout() doc comment
1259        Timeout(Some(Duration::from_secs(30)))
1260    }
1261}
1262
1263pub(crate) struct KeepCoreThreadAlive(#[allow(dead_code)] Option<Arc<InnerClientHandle>>);
1264
1265impl KeepCoreThreadAlive {
1266    pub(crate) fn empty() -> KeepCoreThreadAlive {
1267        KeepCoreThreadAlive(None)
1268    }
1269}
1270
1271#[cold]
1272#[inline(never)]
1273fn event_loop_panicked() -> ! {
1274    // The only possible reason there would be a Canceled error
1275    // is if the thread running the event loop panicked. We could return
1276    // an Err here, like a BrokenPipe, but the Client is not
1277    // recoverable. Additionally, the panic in the other thread
1278    // is not normal, and should likely be propagated.
1279    panic!("event loop thread panicked");
1280}