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