reqwest/async_impl/
client.rs

1#[cfg(any(feature = "native-tls", feature = "__rustls",))]
2use std::any::Any;
3#[cfg(feature = "http2")]
4use std::error::Error;
5use std::future::Future;
6use std::net::IpAddr;
7use std::pin::Pin;
8use std::sync::Arc;
9use std::task::{Context, Poll};
10use std::time::Duration;
11use std::{collections::HashMap, convert::TryInto, net::SocketAddr};
12use std::{fmt, str};
13
14use super::decoder::Accepts;
15use super::request::{Request, RequestBuilder};
16use super::response::Response;
17use super::Body;
18#[cfg(feature = "http3")]
19use crate::async_impl::h3_client::connect::{H3ClientConfig, H3Connector};
20#[cfg(feature = "http3")]
21use crate::async_impl::h3_client::H3Client;
22use crate::config::{RequestConfig, RequestTimeout};
23use crate::connect::{
24    sealed::{Conn, Unnameable},
25    BoxedConnectorLayer, BoxedConnectorService, Connector, ConnectorBuilder,
26};
27#[cfg(feature = "cookies")]
28use crate::cookie;
29#[cfg(feature = "hickory-dns")]
30use crate::dns::hickory::HickoryDnsResolver;
31use crate::dns::{gai::GaiResolver, DnsResolverWithOverrides, DynResolver, Resolve};
32use crate::error::{self, BoxError};
33use crate::into_url::try_uri;
34use crate::proxy::Matcher as ProxyMatcher;
35use crate::redirect::{self, TowerRedirectPolicy};
36#[cfg(feature = "__rustls")]
37use crate::tls::CertificateRevocationList;
38#[cfg(feature = "__tls")]
39use crate::tls::{self, TlsBackend};
40#[cfg(feature = "__tls")]
41use crate::Certificate;
42#[cfg(any(feature = "native-tls", feature = "__rustls"))]
43use crate::Identity;
44use crate::{IntoUrl, Method, Proxy, Url};
45
46use bytes::Bytes;
47use http::header::{
48    Entry, HeaderMap, HeaderValue, ACCEPT, ACCEPT_ENCODING, PROXY_AUTHORIZATION, RANGE, USER_AGENT,
49};
50use http::uri::Scheme;
51use http::Uri;
52use hyper_util::client::legacy::connect::HttpConnector;
53#[cfg(feature = "default-tls")]
54use native_tls_crate::TlsConnector;
55use pin_project_lite::pin_project;
56#[cfg(feature = "http3")]
57use quinn::TransportConfig;
58#[cfg(feature = "http3")]
59use quinn::VarInt;
60use tokio::time::Sleep;
61use tower::util::BoxCloneSyncServiceLayer;
62use tower::{Layer, Service};
63use tower_http::follow_redirect::FollowRedirect;
64
65/// An asynchronous `Client` to make Requests with.
66///
67/// The Client has various configuration values to tweak, but the defaults
68/// are set to what is usually the most commonly desired value. To configure a
69/// `Client`, use `Client::builder()`.
70///
71/// The `Client` holds a connection pool internally, so it is advised that
72/// you create one and **reuse** it.
73///
74/// You do **not** have to wrap the `Client` in an [`Rc`] or [`Arc`] to **reuse** it,
75/// because it already uses an [`Arc`] internally.
76///
77/// [`Rc`]: std::rc::Rc
78#[derive(Clone)]
79pub struct Client {
80    inner: Arc<ClientRef>,
81}
82
83/// A `ClientBuilder` can be used to create a `Client` with custom configuration.
84#[must_use]
85pub struct ClientBuilder {
86    config: Config,
87}
88
89enum HttpVersionPref {
90    Http1,
91    #[cfg(feature = "http2")]
92    Http2,
93    #[cfg(feature = "http3")]
94    Http3,
95    All,
96}
97
98#[derive(Clone)]
99struct HyperService {
100    #[cfg(feature = "cookies")]
101    cookie_store: Option<Arc<dyn cookie::CookieStore>>,
102    hyper: HyperClient,
103}
104
105impl Service<hyper::Request<crate::async_impl::body::Body>> for HyperService {
106    type Error = crate::Error;
107    type Response = http::Response<hyper::body::Incoming>;
108    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send + Sync>>;
109
110    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
111        self.hyper.poll_ready(cx).map_err(crate::error::request)
112    }
113
114    #[cfg(not(feature = "cookies"))]
115    fn call(&mut self, req: hyper::Request<crate::async_impl::body::Body>) -> Self::Future {
116        let clone = self.hyper.clone();
117        let mut inner = std::mem::replace(&mut self.hyper, clone);
118        Box::pin(async move { inner.call(req).await.map_err(crate::error::request) })
119    }
120
121    #[cfg(feature = "cookies")]
122    fn call(&mut self, mut req: hyper::Request<crate::async_impl::body::Body>) -> Self::Future {
123        let clone = self.hyper.clone();
124        let mut inner = std::mem::replace(&mut self.hyper, clone);
125        let url = Url::parse(req.uri().to_string().as_str()).expect("invalid URL");
126
127        if let Some(cookie_store) = self.cookie_store.as_ref() {
128            if req.headers().get(crate::header::COOKIE).is_none() {
129                let headers = req.headers_mut();
130                crate::util::add_cookie_header(headers, &**cookie_store, &url);
131            }
132        }
133
134        let cookie_store = self.cookie_store.clone();
135        Box::pin(async move {
136            let res = inner.call(req).await.map_err(crate::error::request);
137
138            if let Some(ref cookie_store) = cookie_store {
139                if let Ok(res) = &res {
140                    let mut cookies =
141                        cookie::extract_response_cookie_headers(res.headers()).peekable();
142                    if cookies.peek().is_some() {
143                        cookie_store.set_cookies(&mut cookies, &url);
144                    }
145                }
146            }
147
148            res
149        })
150    }
151}
152
153struct Config {
154    // NOTE: When adding a new field, update `fmt::Debug for ClientBuilder`
155    accepts: Accepts,
156    headers: HeaderMap,
157    #[cfg(feature = "__tls")]
158    hostname_verification: bool,
159    #[cfg(feature = "__tls")]
160    certs_verification: bool,
161    #[cfg(feature = "__tls")]
162    tls_sni: bool,
163    connect_timeout: Option<Duration>,
164    connection_verbose: bool,
165    pool_idle_timeout: Option<Duration>,
166    pool_max_idle_per_host: usize,
167    tcp_keepalive: Option<Duration>,
168    tcp_keepalive_interval: Option<Duration>,
169    tcp_keepalive_retries: Option<u32>,
170    #[cfg(any(feature = "native-tls", feature = "__rustls"))]
171    identity: Option<Identity>,
172    proxies: Vec<ProxyMatcher>,
173    auto_sys_proxy: bool,
174    redirect_policy: redirect::Policy,
175    referer: bool,
176    read_timeout: Option<Duration>,
177    timeout: Option<Duration>,
178    #[cfg(feature = "__tls")]
179    root_certs: Vec<Certificate>,
180    #[cfg(feature = "__tls")]
181    tls_built_in_root_certs: bool,
182    #[cfg(feature = "rustls-tls-webpki-roots-no-provider")]
183    tls_built_in_certs_webpki: bool,
184    #[cfg(feature = "rustls-tls-native-roots-no-provider")]
185    tls_built_in_certs_native: bool,
186    #[cfg(feature = "__rustls")]
187    crls: Vec<CertificateRevocationList>,
188    #[cfg(feature = "__tls")]
189    min_tls_version: Option<tls::Version>,
190    #[cfg(feature = "__tls")]
191    max_tls_version: Option<tls::Version>,
192    #[cfg(feature = "__tls")]
193    tls_info: bool,
194    #[cfg(feature = "__tls")]
195    tls: TlsBackend,
196    connector_layers: Vec<BoxedConnectorLayer>,
197    http_version_pref: HttpVersionPref,
198    http09_responses: bool,
199    http1_title_case_headers: bool,
200    http1_allow_obsolete_multiline_headers_in_responses: bool,
201    http1_ignore_invalid_headers_in_responses: bool,
202    http1_allow_spaces_after_header_name_in_responses: bool,
203    #[cfg(feature = "http2")]
204    http2_initial_stream_window_size: Option<u32>,
205    #[cfg(feature = "http2")]
206    http2_initial_connection_window_size: Option<u32>,
207    #[cfg(feature = "http2")]
208    http2_adaptive_window: bool,
209    #[cfg(feature = "http2")]
210    http2_max_frame_size: Option<u32>,
211    #[cfg(feature = "http2")]
212    http2_max_header_list_size: Option<u32>,
213    #[cfg(feature = "http2")]
214    http2_keep_alive_interval: Option<Duration>,
215    #[cfg(feature = "http2")]
216    http2_keep_alive_timeout: Option<Duration>,
217    #[cfg(feature = "http2")]
218    http2_keep_alive_while_idle: bool,
219    local_address: Option<IpAddr>,
220    #[cfg(any(
221        target_os = "android",
222        target_os = "fuchsia",
223        target_os = "illumos",
224        target_os = "ios",
225        target_os = "linux",
226        target_os = "macos",
227        target_os = "solaris",
228        target_os = "tvos",
229        target_os = "visionos",
230        target_os = "watchos",
231    ))]
232    interface: Option<String>,
233    nodelay: bool,
234    #[cfg(feature = "cookies")]
235    cookie_store: Option<Arc<dyn cookie::CookieStore>>,
236    hickory_dns: bool,
237    error: Option<crate::Error>,
238    https_only: bool,
239    #[cfg(feature = "http3")]
240    tls_enable_early_data: bool,
241    #[cfg(feature = "http3")]
242    quic_max_idle_timeout: Option<Duration>,
243    #[cfg(feature = "http3")]
244    quic_stream_receive_window: Option<VarInt>,
245    #[cfg(feature = "http3")]
246    quic_receive_window: Option<VarInt>,
247    #[cfg(feature = "http3")]
248    quic_send_window: Option<u64>,
249    #[cfg(feature = "http3")]
250    quic_congestion_bbr: bool,
251    #[cfg(feature = "http3")]
252    h3_max_field_section_size: Option<u64>,
253    #[cfg(feature = "http3")]
254    h3_send_grease: Option<bool>,
255    dns_overrides: HashMap<String, Vec<SocketAddr>>,
256    dns_resolver: Option<Arc<dyn Resolve>>,
257}
258
259impl Default for ClientBuilder {
260    fn default() -> Self {
261        Self::new()
262    }
263}
264
265impl ClientBuilder {
266    /// Constructs a new `ClientBuilder`.
267    ///
268    /// This is the same as `Client::builder()`.
269    pub fn new() -> Self {
270        let mut headers: HeaderMap<HeaderValue> = HeaderMap::with_capacity(2);
271        headers.insert(ACCEPT, HeaderValue::from_static("*/*"));
272
273        ClientBuilder {
274            config: Config {
275                error: None,
276                accepts: Accepts::default(),
277                headers,
278                #[cfg(feature = "__tls")]
279                hostname_verification: true,
280                #[cfg(feature = "__tls")]
281                certs_verification: true,
282                #[cfg(feature = "__tls")]
283                tls_sni: true,
284                connect_timeout: None,
285                connection_verbose: false,
286                pool_idle_timeout: Some(Duration::from_secs(90)),
287                pool_max_idle_per_host: usize::MAX,
288                // TODO: Re-enable default duration once hyper's HttpConnector is fixed
289                // to no longer error when an option fails.
290                tcp_keepalive: None, //Some(Duration::from_secs(60)),
291                tcp_keepalive_interval: None,
292                tcp_keepalive_retries: None,
293                proxies: Vec::new(),
294                auto_sys_proxy: true,
295                redirect_policy: redirect::Policy::default(),
296                referer: true,
297                read_timeout: None,
298                timeout: None,
299                #[cfg(feature = "__tls")]
300                root_certs: Vec::new(),
301                #[cfg(feature = "__tls")]
302                tls_built_in_root_certs: true,
303                #[cfg(feature = "rustls-tls-webpki-roots-no-provider")]
304                tls_built_in_certs_webpki: true,
305                #[cfg(feature = "rustls-tls-native-roots-no-provider")]
306                tls_built_in_certs_native: true,
307                #[cfg(any(feature = "native-tls", feature = "__rustls"))]
308                identity: None,
309                #[cfg(feature = "__rustls")]
310                crls: vec![],
311                #[cfg(feature = "__tls")]
312                min_tls_version: None,
313                #[cfg(feature = "__tls")]
314                max_tls_version: None,
315                #[cfg(feature = "__tls")]
316                tls_info: false,
317                #[cfg(feature = "__tls")]
318                tls: TlsBackend::default(),
319                connector_layers: Vec::new(),
320                http_version_pref: HttpVersionPref::All,
321                http09_responses: false,
322                http1_title_case_headers: false,
323                http1_allow_obsolete_multiline_headers_in_responses: false,
324                http1_ignore_invalid_headers_in_responses: false,
325                http1_allow_spaces_after_header_name_in_responses: false,
326                #[cfg(feature = "http2")]
327                http2_initial_stream_window_size: None,
328                #[cfg(feature = "http2")]
329                http2_initial_connection_window_size: None,
330                #[cfg(feature = "http2")]
331                http2_adaptive_window: false,
332                #[cfg(feature = "http2")]
333                http2_max_frame_size: None,
334                #[cfg(feature = "http2")]
335                http2_max_header_list_size: None,
336                #[cfg(feature = "http2")]
337                http2_keep_alive_interval: None,
338                #[cfg(feature = "http2")]
339                http2_keep_alive_timeout: None,
340                #[cfg(feature = "http2")]
341                http2_keep_alive_while_idle: false,
342                local_address: None,
343                #[cfg(any(
344                    target_os = "android",
345                    target_os = "fuchsia",
346                    target_os = "illumos",
347                    target_os = "ios",
348                    target_os = "linux",
349                    target_os = "macos",
350                    target_os = "solaris",
351                    target_os = "tvos",
352                    target_os = "visionos",
353                    target_os = "watchos",
354                ))]
355                interface: None,
356                nodelay: true,
357                hickory_dns: cfg!(feature = "hickory-dns"),
358                #[cfg(feature = "cookies")]
359                cookie_store: None,
360                https_only: false,
361                dns_overrides: HashMap::new(),
362                #[cfg(feature = "http3")]
363                tls_enable_early_data: false,
364                #[cfg(feature = "http3")]
365                quic_max_idle_timeout: None,
366                #[cfg(feature = "http3")]
367                quic_stream_receive_window: None,
368                #[cfg(feature = "http3")]
369                quic_receive_window: None,
370                #[cfg(feature = "http3")]
371                quic_send_window: None,
372                #[cfg(feature = "http3")]
373                quic_congestion_bbr: false,
374                #[cfg(feature = "http3")]
375                h3_max_field_section_size: None,
376                #[cfg(feature = "http3")]
377                h3_send_grease: None,
378                dns_resolver: None,
379            },
380        }
381    }
382}
383
384impl ClientBuilder {
385    /// Returns a `Client` that uses this `ClientBuilder` configuration.
386    ///
387    /// # Errors
388    ///
389    /// This method fails if a TLS backend cannot be initialized, or the resolver
390    /// cannot load the system configuration.
391    pub fn build(self) -> crate::Result<Client> {
392        let config = self.config;
393
394        if let Some(err) = config.error {
395            return Err(err);
396        }
397
398        let mut proxies = config.proxies;
399        if config.auto_sys_proxy {
400            proxies.push(ProxyMatcher::system());
401        }
402        let proxies = Arc::new(proxies);
403
404        #[allow(unused)]
405        #[cfg(feature = "http3")]
406        let mut h3_connector = None;
407
408        let resolver = {
409            let mut resolver: Arc<dyn Resolve> = match config.hickory_dns {
410                false => Arc::new(GaiResolver::new()),
411                #[cfg(feature = "hickory-dns")]
412                true => Arc::new(HickoryDnsResolver::default()),
413                #[cfg(not(feature = "hickory-dns"))]
414                true => unreachable!("hickory-dns shouldn't be enabled unless the feature is"),
415            };
416            if let Some(dns_resolver) = config.dns_resolver {
417                resolver = dns_resolver;
418            }
419            if !config.dns_overrides.is_empty() {
420                resolver = Arc::new(DnsResolverWithOverrides::new(
421                    resolver,
422                    config.dns_overrides,
423                ));
424            }
425            DynResolver::new(resolver)
426        };
427
428        let mut connector_builder = {
429            #[cfg(feature = "__tls")]
430            fn user_agent(headers: &HeaderMap) -> Option<HeaderValue> {
431                headers.get(USER_AGENT).cloned()
432            }
433
434            let mut http = HttpConnector::new_with_resolver(resolver.clone());
435            http.set_connect_timeout(config.connect_timeout);
436
437            #[cfg(all(feature = "http3", feature = "__rustls"))]
438            let build_h3_connector =
439                |resolver,
440                 tls,
441                 quic_max_idle_timeout: Option<Duration>,
442                 quic_stream_receive_window,
443                 quic_receive_window,
444                 quic_send_window,
445                 quic_congestion_bbr,
446                 h3_max_field_section_size,
447                 h3_send_grease,
448                 local_address,
449                 http_version_pref: &HttpVersionPref| {
450                    let mut transport_config = TransportConfig::default();
451
452                    if let Some(max_idle_timeout) = quic_max_idle_timeout {
453                        transport_config.max_idle_timeout(Some(
454                            max_idle_timeout.try_into().map_err(error::builder)?,
455                        ));
456                    }
457
458                    if let Some(stream_receive_window) = quic_stream_receive_window {
459                        transport_config.stream_receive_window(stream_receive_window);
460                    }
461
462                    if let Some(receive_window) = quic_receive_window {
463                        transport_config.receive_window(receive_window);
464                    }
465
466                    if let Some(send_window) = quic_send_window {
467                        transport_config.send_window(send_window);
468                    }
469
470                    if quic_congestion_bbr {
471                        let factory = Arc::new(quinn::congestion::BbrConfig::default());
472                        transport_config.congestion_controller_factory(factory);
473                    }
474
475                    let mut h3_client_config = H3ClientConfig::default();
476
477                    if let Some(max_field_section_size) = h3_max_field_section_size {
478                        h3_client_config.max_field_section_size = Some(max_field_section_size);
479                    }
480
481                    if let Some(send_grease) = h3_send_grease {
482                        h3_client_config.send_grease = Some(send_grease);
483                    }
484
485                    let res = H3Connector::new(
486                        resolver,
487                        tls,
488                        local_address,
489                        transport_config,
490                        h3_client_config,
491                    );
492
493                    match res {
494                        Ok(connector) => Ok(Some(connector)),
495                        Err(err) => {
496                            if let HttpVersionPref::Http3 = http_version_pref {
497                                Err(error::builder(err))
498                            } else {
499                                Ok(None)
500                            }
501                        }
502                    }
503                };
504
505            #[cfg(feature = "__tls")]
506            match config.tls {
507                #[cfg(feature = "default-tls")]
508                TlsBackend::Default => {
509                    let mut tls = TlsConnector::builder();
510
511                    #[cfg(all(feature = "native-tls-alpn", not(feature = "http3")))]
512                    {
513                        match config.http_version_pref {
514                            HttpVersionPref::Http1 => {
515                                tls.request_alpns(&["http/1.1"]);
516                            }
517                            #[cfg(feature = "http2")]
518                            HttpVersionPref::Http2 => {
519                                tls.request_alpns(&["h2"]);
520                            }
521                            HttpVersionPref::All => {
522                                tls.request_alpns(&["h2", "http/1.1"]);
523                            }
524                        }
525                    }
526
527                    tls.danger_accept_invalid_hostnames(!config.hostname_verification);
528
529                    tls.danger_accept_invalid_certs(!config.certs_verification);
530
531                    tls.use_sni(config.tls_sni);
532
533                    tls.disable_built_in_roots(!config.tls_built_in_root_certs);
534
535                    for cert in config.root_certs {
536                        cert.add_to_native_tls(&mut tls);
537                    }
538
539                    #[cfg(feature = "native-tls")]
540                    {
541                        if let Some(id) = config.identity {
542                            id.add_to_native_tls(&mut tls)?;
543                        }
544                    }
545                    #[cfg(all(feature = "__rustls", not(feature = "native-tls")))]
546                    {
547                        // Default backend + rustls Identity doesn't work.
548                        if let Some(_id) = config.identity {
549                            return Err(crate::error::builder("incompatible TLS identity type"));
550                        }
551                    }
552
553                    if let Some(min_tls_version) = config.min_tls_version {
554                        let protocol = min_tls_version.to_native_tls().ok_or_else(|| {
555                            // TLS v1.3. This would be entirely reasonable,
556                            // native-tls just doesn't support it.
557                            // https://github.com/sfackler/rust-native-tls/issues/140
558                            crate::error::builder("invalid minimum TLS version for backend")
559                        })?;
560                        tls.min_protocol_version(Some(protocol));
561                    }
562
563                    if let Some(max_tls_version) = config.max_tls_version {
564                        let protocol = max_tls_version.to_native_tls().ok_or_else(|| {
565                            // TLS v1.3.
566                            // We could arguably do max_protocol_version(None), given
567                            // that 1.4 does not exist yet, but that'd get messy in the
568                            // future.
569                            crate::error::builder("invalid maximum TLS version for backend")
570                        })?;
571                        tls.max_protocol_version(Some(protocol));
572                    }
573
574                    ConnectorBuilder::new_default_tls(
575                        http,
576                        tls,
577                        proxies.clone(),
578                        user_agent(&config.headers),
579                        config.local_address,
580                        #[cfg(any(
581                            target_os = "android",
582                            target_os = "fuchsia",
583                            target_os = "illumos",
584                            target_os = "ios",
585                            target_os = "linux",
586                            target_os = "macos",
587                            target_os = "solaris",
588                            target_os = "tvos",
589                            target_os = "visionos",
590                            target_os = "watchos",
591                        ))]
592                        config.interface.as_deref(),
593                        config.nodelay,
594                        config.tls_info,
595                    )?
596                }
597                #[cfg(feature = "native-tls")]
598                TlsBackend::BuiltNativeTls(conn) => ConnectorBuilder::from_built_default_tls(
599                    http,
600                    conn,
601                    proxies.clone(),
602                    user_agent(&config.headers),
603                    config.local_address,
604                    #[cfg(any(
605                        target_os = "android",
606                        target_os = "fuchsia",
607                        target_os = "illumos",
608                        target_os = "ios",
609                        target_os = "linux",
610                        target_os = "macos",
611                        target_os = "solaris",
612                        target_os = "tvos",
613                        target_os = "visionos",
614                        target_os = "watchos",
615                    ))]
616                    config.interface.as_deref(),
617                    config.nodelay,
618                    config.tls_info,
619                ),
620                #[cfg(feature = "__rustls")]
621                TlsBackend::BuiltRustls(conn) => {
622                    #[cfg(feature = "http3")]
623                    {
624                        h3_connector = build_h3_connector(
625                            resolver.clone(),
626                            conn.clone(),
627                            config.quic_max_idle_timeout,
628                            config.quic_stream_receive_window,
629                            config.quic_receive_window,
630                            config.quic_send_window,
631                            config.quic_congestion_bbr,
632                            config.h3_max_field_section_size,
633                            config.h3_send_grease,
634                            config.local_address,
635                            &config.http_version_pref,
636                        )?;
637                    }
638
639                    ConnectorBuilder::new_rustls_tls(
640                        http,
641                        conn,
642                        proxies.clone(),
643                        user_agent(&config.headers),
644                        config.local_address,
645                        #[cfg(any(
646                            target_os = "android",
647                            target_os = "fuchsia",
648                            target_os = "illumos",
649                            target_os = "ios",
650                            target_os = "linux",
651                            target_os = "macos",
652                            target_os = "solaris",
653                            target_os = "tvos",
654                            target_os = "visionos",
655                            target_os = "watchos",
656                        ))]
657                        config.interface.as_deref(),
658                        config.nodelay,
659                        config.tls_info,
660                    )
661                }
662                #[cfg(feature = "__rustls")]
663                TlsBackend::Rustls => {
664                    use crate::tls::{IgnoreHostname, NoVerifier};
665
666                    // Set root certificates.
667                    let mut root_cert_store = rustls::RootCertStore::empty();
668                    for cert in config.root_certs {
669                        cert.add_to_rustls(&mut root_cert_store)?;
670                    }
671
672                    #[cfg(feature = "rustls-tls-webpki-roots-no-provider")]
673                    if config.tls_built_in_certs_webpki {
674                        root_cert_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
675                    }
676
677                    #[cfg(feature = "rustls-tls-native-roots-no-provider")]
678                    if config.tls_built_in_certs_native {
679                        let mut valid_count = 0;
680                        let mut invalid_count = 0;
681
682                        let load_results = rustls_native_certs::load_native_certs();
683                        for cert in load_results.certs {
684                            // Continue on parsing errors, as native stores often include ancient or syntactically
685                            // invalid certificates, like root certificates without any X509 extensions.
686                            // Inspiration: https://github.com/rustls/rustls/blob/633bf4ba9d9521a95f68766d04c22e2b01e68318/rustls/src/anchors.rs#L105-L112
687                            match root_cert_store.add(cert.into()) {
688                                Ok(_) => valid_count += 1,
689                                Err(err) => {
690                                    invalid_count += 1;
691                                    log::debug!("rustls failed to parse DER certificate: {err:?}");
692                                }
693                            }
694                        }
695                        if valid_count == 0 && invalid_count > 0 {
696                            let err = if load_results.errors.is_empty() {
697                                crate::error::builder(
698                                    "zero valid certificates found in native root store",
699                                )
700                            } else {
701                                use std::fmt::Write as _;
702                                let mut acc = String::new();
703                                for err in load_results.errors {
704                                    let _ = writeln!(&mut acc, "{err}");
705                                }
706
707                                crate::error::builder(acc)
708                            };
709
710                            return Err(err);
711                        }
712                    }
713
714                    // Set TLS versions.
715                    let mut versions = rustls::ALL_VERSIONS.to_vec();
716
717                    if let Some(min_tls_version) = config.min_tls_version {
718                        versions.retain(|&supported_version| {
719                            match tls::Version::from_rustls(supported_version.version) {
720                                Some(version) => version >= min_tls_version,
721                                // Assume it's so new we don't know about it, allow it
722                                // (as of writing this is unreachable)
723                                None => true,
724                            }
725                        });
726                    }
727
728                    if let Some(max_tls_version) = config.max_tls_version {
729                        versions.retain(|&supported_version| {
730                            match tls::Version::from_rustls(supported_version.version) {
731                                Some(version) => version <= max_tls_version,
732                                None => false,
733                            }
734                        });
735                    }
736
737                    if versions.is_empty() {
738                        return Err(crate::error::builder("empty supported tls versions"));
739                    }
740
741                    // Allow user to have installed a runtime default.
742                    // If not, we use ring.
743                    let provider = rustls::crypto::CryptoProvider::get_default()
744                        .map(|arc| arc.clone())
745                        .unwrap_or_else(|| {
746                            #[cfg(not(feature = "__rustls-ring"))]
747                            panic!("No provider set");
748
749                            #[cfg(feature = "__rustls-ring")]
750                            Arc::new(rustls::crypto::ring::default_provider())
751                        });
752
753                    // Build TLS config
754                    let signature_algorithms = provider.signature_verification_algorithms;
755                    let config_builder =
756                        rustls::ClientConfig::builder_with_provider(provider.clone())
757                            .with_protocol_versions(&versions)
758                            .map_err(|_| crate::error::builder("invalid TLS versions"))?;
759
760                    let config_builder = if !config.certs_verification {
761                        config_builder
762                            .dangerous()
763                            .with_custom_certificate_verifier(Arc::new(NoVerifier))
764                    } else if !config.hostname_verification {
765                        config_builder
766                            .dangerous()
767                            .with_custom_certificate_verifier(Arc::new(IgnoreHostname::new(
768                                root_cert_store,
769                                signature_algorithms,
770                            )))
771                    } else {
772                        if config.crls.is_empty() {
773                            config_builder.with_root_certificates(root_cert_store)
774                        } else {
775                            let crls = config
776                                .crls
777                                .iter()
778                                .map(|e| e.as_rustls_crl())
779                                .collect::<Vec<_>>();
780                            let verifier =
781                                rustls::client::WebPkiServerVerifier::builder_with_provider(
782                                    Arc::new(root_cert_store),
783                                    provider,
784                                )
785                                .with_crls(crls)
786                                .build()
787                                .map_err(|_| {
788                                    crate::error::builder("invalid TLS verification settings")
789                                })?;
790                            config_builder.with_webpki_verifier(verifier)
791                        }
792                    };
793
794                    // Finalize TLS config
795                    let mut tls = if let Some(id) = config.identity {
796                        id.add_to_rustls(config_builder)?
797                    } else {
798                        config_builder.with_no_client_auth()
799                    };
800
801                    tls.enable_sni = config.tls_sni;
802
803                    // ALPN protocol
804                    match config.http_version_pref {
805                        HttpVersionPref::Http1 => {
806                            tls.alpn_protocols = vec!["http/1.1".into()];
807                        }
808                        #[cfg(feature = "http2")]
809                        HttpVersionPref::Http2 => {
810                            tls.alpn_protocols = vec!["h2".into()];
811                        }
812                        #[cfg(feature = "http3")]
813                        HttpVersionPref::Http3 => {
814                            tls.alpn_protocols = vec!["h3".into()];
815                        }
816                        HttpVersionPref::All => {
817                            tls.alpn_protocols = vec![
818                                #[cfg(feature = "http2")]
819                                "h2".into(),
820                                "http/1.1".into(),
821                            ];
822                        }
823                    }
824
825                    #[cfg(feature = "http3")]
826                    {
827                        tls.enable_early_data = config.tls_enable_early_data;
828
829                        h3_connector = build_h3_connector(
830                            resolver.clone(),
831                            tls.clone(),
832                            config.quic_max_idle_timeout,
833                            config.quic_stream_receive_window,
834                            config.quic_receive_window,
835                            config.quic_send_window,
836                            config.quic_congestion_bbr,
837                            config.h3_max_field_section_size,
838                            config.h3_send_grease,
839                            config.local_address,
840                            &config.http_version_pref,
841                        )?;
842                    }
843
844                    ConnectorBuilder::new_rustls_tls(
845                        http,
846                        tls,
847                        proxies.clone(),
848                        user_agent(&config.headers),
849                        config.local_address,
850                        #[cfg(any(
851                            target_os = "android",
852                            target_os = "fuchsia",
853                            target_os = "illumos",
854                            target_os = "ios",
855                            target_os = "linux",
856                            target_os = "macos",
857                            target_os = "solaris",
858                            target_os = "tvos",
859                            target_os = "visionos",
860                            target_os = "watchos",
861                        ))]
862                        config.interface.as_deref(),
863                        config.nodelay,
864                        config.tls_info,
865                    )
866                }
867                #[cfg(any(feature = "native-tls", feature = "__rustls",))]
868                TlsBackend::UnknownPreconfigured => {
869                    return Err(crate::error::builder(
870                        "Unknown TLS backend passed to `use_preconfigured_tls`",
871                    ));
872                }
873            }
874
875            #[cfg(not(feature = "__tls"))]
876            ConnectorBuilder::new(
877                http,
878                proxies.clone(),
879                config.local_address,
880                #[cfg(any(
881                    target_os = "android",
882                    target_os = "fuchsia",
883                    target_os = "illumos",
884                    target_os = "ios",
885                    target_os = "linux",
886                    target_os = "macos",
887                    target_os = "solaris",
888                    target_os = "tvos",
889                    target_os = "visionos",
890                    target_os = "watchos",
891                ))]
892                config.interface.as_deref(),
893                config.nodelay,
894            )
895        };
896
897        connector_builder.set_timeout(config.connect_timeout);
898        connector_builder.set_verbose(config.connection_verbose);
899        connector_builder.set_keepalive(config.tcp_keepalive);
900        connector_builder.set_keepalive_interval(config.tcp_keepalive_interval);
901        connector_builder.set_keepalive_retries(config.tcp_keepalive_retries);
902
903        #[cfg(feature = "socks")]
904        connector_builder.set_socks_resolver(resolver);
905
906        let mut builder =
907            hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new());
908        #[cfg(feature = "http2")]
909        {
910            if matches!(config.http_version_pref, HttpVersionPref::Http2) {
911                builder.http2_only(true);
912            }
913
914            if let Some(http2_initial_stream_window_size) = config.http2_initial_stream_window_size
915            {
916                builder.http2_initial_stream_window_size(http2_initial_stream_window_size);
917            }
918            if let Some(http2_initial_connection_window_size) =
919                config.http2_initial_connection_window_size
920            {
921                builder.http2_initial_connection_window_size(http2_initial_connection_window_size);
922            }
923            if config.http2_adaptive_window {
924                builder.http2_adaptive_window(true);
925            }
926            if let Some(http2_max_frame_size) = config.http2_max_frame_size {
927                builder.http2_max_frame_size(http2_max_frame_size);
928            }
929            if let Some(http2_max_header_list_size) = config.http2_max_header_list_size {
930                builder.http2_max_header_list_size(http2_max_header_list_size);
931            }
932            if let Some(http2_keep_alive_interval) = config.http2_keep_alive_interval {
933                builder.http2_keep_alive_interval(http2_keep_alive_interval);
934            }
935            if let Some(http2_keep_alive_timeout) = config.http2_keep_alive_timeout {
936                builder.http2_keep_alive_timeout(http2_keep_alive_timeout);
937            }
938            if config.http2_keep_alive_while_idle {
939                builder.http2_keep_alive_while_idle(true);
940            }
941        }
942
943        builder.timer(hyper_util::rt::TokioTimer::new());
944        builder.pool_timer(hyper_util::rt::TokioTimer::new());
945        builder.pool_idle_timeout(config.pool_idle_timeout);
946        builder.pool_max_idle_per_host(config.pool_max_idle_per_host);
947
948        if config.http09_responses {
949            builder.http09_responses(true);
950        }
951
952        if config.http1_title_case_headers {
953            builder.http1_title_case_headers(true);
954        }
955
956        if config.http1_allow_obsolete_multiline_headers_in_responses {
957            builder.http1_allow_obsolete_multiline_headers_in_responses(true);
958        }
959
960        if config.http1_ignore_invalid_headers_in_responses {
961            builder.http1_ignore_invalid_headers_in_responses(true);
962        }
963
964        if config.http1_allow_spaces_after_header_name_in_responses {
965            builder.http1_allow_spaces_after_header_name_in_responses(true);
966        }
967
968        let proxies_maybe_http_auth = proxies.iter().any(|p| p.maybe_has_http_auth());
969        let proxies_maybe_http_custom_headers =
970            proxies.iter().any(|p| p.maybe_has_http_custom_headers());
971
972        let redirect_policy_desc = if config.redirect_policy.is_default() {
973            None
974        } else {
975            Some(format!("{:?}", &config.redirect_policy))
976        };
977
978        let hyper_client = builder.build(connector_builder.build(config.connector_layers));
979        let hyper_service = HyperService {
980            #[cfg(feature = "cookies")]
981            cookie_store: config.cookie_store.clone(),
982            hyper: hyper_client,
983        };
984
985        let policy = {
986            let mut p = TowerRedirectPolicy::new(config.redirect_policy);
987            p.with_referer(config.referer)
988                .with_https_only(config.https_only);
989            p
990        };
991
992        let hyper = FollowRedirect::with_policy(hyper_service, policy.clone());
993
994        Ok(Client {
995            inner: Arc::new(ClientRef {
996                accepts: config.accepts,
997                #[cfg(feature = "cookies")]
998                cookie_store: config.cookie_store.clone(),
999                // Use match instead of map since config is partially moved,
1000                // and it cannot be used in closure
1001                #[cfg(feature = "http3")]
1002                h3_client: match h3_connector {
1003                    Some(h3_connector) => {
1004                        #[cfg(not(feature = "cookies"))]
1005                        let h3_service = H3Client::new(h3_connector, config.pool_idle_timeout);
1006                        #[cfg(feature = "cookies")]
1007                        let h3_service = H3Client::new(
1008                            h3_connector,
1009                            config.pool_idle_timeout,
1010                            config.cookie_store,
1011                        );
1012                        Some(FollowRedirect::with_policy(h3_service, policy))
1013                    }
1014                    None => None,
1015                },
1016                headers: config.headers,
1017                referer: config.referer,
1018                read_timeout: config.read_timeout,
1019                request_timeout: RequestConfig::new(config.timeout),
1020                hyper,
1021                proxies,
1022                proxies_maybe_http_auth,
1023                proxies_maybe_http_custom_headers,
1024                https_only: config.https_only,
1025                redirect_policy_desc,
1026            }),
1027        })
1028    }
1029
1030    // Higher-level options
1031
1032    /// Sets the `User-Agent` header to be used by this client.
1033    ///
1034    /// # Example
1035    ///
1036    /// ```rust
1037    /// # async fn doc() -> Result<(), reqwest::Error> {
1038    /// // Name your user agent after your app?
1039    /// static APP_USER_AGENT: &str = concat!(
1040    ///     env!("CARGO_PKG_NAME"),
1041    ///     "/",
1042    ///     env!("CARGO_PKG_VERSION"),
1043    /// );
1044    ///
1045    /// let client = reqwest::Client::builder()
1046    ///     .user_agent(APP_USER_AGENT)
1047    ///     .build()?;
1048    /// let res = client.get("https://www.rust-lang.org").send().await?;
1049    /// # Ok(())
1050    /// # }
1051    /// ```
1052    pub fn user_agent<V>(mut self, value: V) -> ClientBuilder
1053    where
1054        V: TryInto<HeaderValue>,
1055        V::Error: Into<http::Error>,
1056    {
1057        match value.try_into() {
1058            Ok(value) => {
1059                self.config.headers.insert(USER_AGENT, value);
1060            }
1061            Err(e) => {
1062                self.config.error = Some(crate::error::builder(e.into()));
1063            }
1064        };
1065        self
1066    }
1067    /// Sets the default headers for every request.
1068    ///
1069    /// # Example
1070    ///
1071    /// ```rust
1072    /// use reqwest::header;
1073    /// # async fn doc() -> Result<(), reqwest::Error> {
1074    /// let mut headers = header::HeaderMap::new();
1075    /// headers.insert("X-MY-HEADER", header::HeaderValue::from_static("value"));
1076    ///
1077    /// // Consider marking security-sensitive headers with `set_sensitive`.
1078    /// let mut auth_value = header::HeaderValue::from_static("secret");
1079    /// auth_value.set_sensitive(true);
1080    /// headers.insert(header::AUTHORIZATION, auth_value);
1081    ///
1082    /// // get a client builder
1083    /// let client = reqwest::Client::builder()
1084    ///     .default_headers(headers)
1085    ///     .build()?;
1086    /// let res = client.get("https://www.rust-lang.org").send().await?;
1087    /// # Ok(())
1088    /// # }
1089    /// ```
1090    pub fn default_headers(mut self, headers: HeaderMap) -> ClientBuilder {
1091        for (key, value) in headers.iter() {
1092            self.config.headers.insert(key, value.clone());
1093        }
1094        self
1095    }
1096
1097    /// Enable a persistent cookie store for the client.
1098    ///
1099    /// Cookies received in responses will be preserved and included in
1100    /// additional requests.
1101    ///
1102    /// By default, no cookie store is used. Enabling the cookie store
1103    /// with `cookie_store(true)` will set the store to a default implementation.
1104    /// It is **not** necessary to call [cookie_store(true)](crate::ClientBuilder::cookie_store) if [cookie_provider(my_cookie_store)](crate::ClientBuilder::cookie_provider)
1105    /// is used; calling [cookie_store(true)](crate::ClientBuilder::cookie_store) _after_ [cookie_provider(my_cookie_store)](crate::ClientBuilder::cookie_provider) will result
1106    /// in the provided `my_cookie_store` being **overridden** with a default implementation.
1107    ///
1108    /// # Optional
1109    ///
1110    /// This requires the optional `cookies` feature to be enabled.
1111    #[cfg(feature = "cookies")]
1112    #[cfg_attr(docsrs, doc(cfg(feature = "cookies")))]
1113    pub fn cookie_store(mut self, enable: bool) -> ClientBuilder {
1114        if enable {
1115            self.cookie_provider(Arc::new(cookie::Jar::default()))
1116        } else {
1117            self.config.cookie_store = None;
1118            self
1119        }
1120    }
1121
1122    /// Set the persistent cookie store for the client.
1123    ///
1124    /// Cookies received in responses will be passed to this store, and
1125    /// additional requests will query this store for cookies.
1126    ///
1127    /// By default, no cookie store is used. It is **not** necessary to also call
1128    /// [cookie_store(true)](crate::ClientBuilder::cookie_store) if [cookie_provider(my_cookie_store)](crate::ClientBuilder::cookie_provider) is used; calling
1129    /// [cookie_store(true)](crate::ClientBuilder::cookie_store) _after_ [cookie_provider(my_cookie_store)](crate::ClientBuilder::cookie_provider) will result
1130    /// in the provided `my_cookie_store` being **overridden** with a default implementation.
1131    ///
1132    /// # Optional
1133    ///
1134    /// This requires the optional `cookies` feature to be enabled.
1135    #[cfg(feature = "cookies")]
1136    #[cfg_attr(docsrs, doc(cfg(feature = "cookies")))]
1137    pub fn cookie_provider<C: cookie::CookieStore + 'static>(
1138        mut self,
1139        cookie_store: Arc<C>,
1140    ) -> ClientBuilder {
1141        self.config.cookie_store = Some(cookie_store as _);
1142        self
1143    }
1144
1145    /// Enable auto gzip decompression by checking the `Content-Encoding` response header.
1146    ///
1147    /// If auto gzip decompression is turned on:
1148    ///
1149    /// - When sending a request and if the request's headers do not already contain
1150    ///   an `Accept-Encoding` **and** `Range` values, the `Accept-Encoding` header is set to `gzip`.
1151    ///   The request body is **not** automatically compressed.
1152    /// - When receiving a response, if its headers contain a `Content-Encoding` value of
1153    ///   `gzip`, both `Content-Encoding` and `Content-Length` are removed from the
1154    ///   headers' set. The response body is automatically decompressed.
1155    ///
1156    /// If the `gzip` feature is turned on, the default option is enabled.
1157    ///
1158    /// # Optional
1159    ///
1160    /// This requires the optional `gzip` feature to be enabled
1161    #[cfg(feature = "gzip")]
1162    #[cfg_attr(docsrs, doc(cfg(feature = "gzip")))]
1163    pub fn gzip(mut self, enable: bool) -> ClientBuilder {
1164        self.config.accepts.gzip = enable;
1165        self
1166    }
1167
1168    /// Enable auto brotli decompression by checking the `Content-Encoding` response header.
1169    ///
1170    /// If auto brotli decompression is turned on:
1171    ///
1172    /// - When sending a request and if the request's headers do not already contain
1173    ///   an `Accept-Encoding` **and** `Range` values, the `Accept-Encoding` header is set to `br`.
1174    ///   The request body is **not** automatically compressed.
1175    /// - When receiving a response, if its headers contain a `Content-Encoding` value of
1176    ///   `br`, both `Content-Encoding` and `Content-Length` are removed from the
1177    ///   headers' set. The response body is automatically decompressed.
1178    ///
1179    /// If the `brotli` feature is turned on, the default option is enabled.
1180    ///
1181    /// # Optional
1182    ///
1183    /// This requires the optional `brotli` feature to be enabled
1184    #[cfg(feature = "brotli")]
1185    #[cfg_attr(docsrs, doc(cfg(feature = "brotli")))]
1186    pub fn brotli(mut self, enable: bool) -> ClientBuilder {
1187        self.config.accepts.brotli = enable;
1188        self
1189    }
1190
1191    /// Enable auto zstd decompression by checking the `Content-Encoding` response header.
1192    ///
1193    /// If auto zstd decompression is turned on:
1194    ///
1195    /// - When sending a request and if the request's headers do not already contain
1196    ///   an `Accept-Encoding` **and** `Range` values, the `Accept-Encoding` header is set to `zstd`.
1197    ///   The request body is **not** automatically compressed.
1198    /// - When receiving a response, if its headers contain a `Content-Encoding` value of
1199    ///   `zstd`, both `Content-Encoding` and `Content-Length` are removed from the
1200    ///   headers' set. The response body is automatically decompressed.
1201    ///
1202    /// If the `zstd` feature is turned on, the default option is enabled.
1203    ///
1204    /// # Optional
1205    ///
1206    /// This requires the optional `zstd` feature to be enabled
1207    #[cfg(feature = "zstd")]
1208    #[cfg_attr(docsrs, doc(cfg(feature = "zstd")))]
1209    pub fn zstd(mut self, enable: bool) -> ClientBuilder {
1210        self.config.accepts.zstd = enable;
1211        self
1212    }
1213
1214    /// Enable auto deflate decompression by checking the `Content-Encoding` response header.
1215    ///
1216    /// If auto deflate decompression is turned on:
1217    ///
1218    /// - When sending a request and if the request's headers do not already contain
1219    ///   an `Accept-Encoding` **and** `Range` values, the `Accept-Encoding` header is set to `deflate`.
1220    ///   The request body is **not** automatically compressed.
1221    /// - When receiving a response, if it's headers contain a `Content-Encoding` value that
1222    ///   equals to `deflate`, both values `Content-Encoding` and `Content-Length` are removed from the
1223    ///   headers' set. The response body is automatically decompressed.
1224    ///
1225    /// If the `deflate` feature is turned on, the default option is enabled.
1226    ///
1227    /// # Optional
1228    ///
1229    /// This requires the optional `deflate` feature to be enabled
1230    #[cfg(feature = "deflate")]
1231    #[cfg_attr(docsrs, doc(cfg(feature = "deflate")))]
1232    pub fn deflate(mut self, enable: bool) -> ClientBuilder {
1233        self.config.accepts.deflate = enable;
1234        self
1235    }
1236
1237    /// Disable auto response body gzip decompression.
1238    ///
1239    /// This method exists even if the optional `gzip` feature is not enabled.
1240    /// This can be used to ensure a `Client` doesn't use gzip decompression
1241    /// even if another dependency were to enable the optional `gzip` feature.
1242    pub fn no_gzip(self) -> ClientBuilder {
1243        #[cfg(feature = "gzip")]
1244        {
1245            self.gzip(false)
1246        }
1247
1248        #[cfg(not(feature = "gzip"))]
1249        {
1250            self
1251        }
1252    }
1253
1254    /// Disable auto response body brotli decompression.
1255    ///
1256    /// This method exists even if the optional `brotli` feature is not enabled.
1257    /// This can be used to ensure a `Client` doesn't use brotli decompression
1258    /// even if another dependency were to enable the optional `brotli` feature.
1259    pub fn no_brotli(self) -> ClientBuilder {
1260        #[cfg(feature = "brotli")]
1261        {
1262            self.brotli(false)
1263        }
1264
1265        #[cfg(not(feature = "brotli"))]
1266        {
1267            self
1268        }
1269    }
1270
1271    /// Disable auto response body zstd decompression.
1272    ///
1273    /// This method exists even if the optional `zstd` feature is not enabled.
1274    /// This can be used to ensure a `Client` doesn't use zstd decompression
1275    /// even if another dependency were to enable the optional `zstd` feature.
1276    pub fn no_zstd(self) -> ClientBuilder {
1277        #[cfg(feature = "zstd")]
1278        {
1279            self.zstd(false)
1280        }
1281
1282        #[cfg(not(feature = "zstd"))]
1283        {
1284            self
1285        }
1286    }
1287
1288    /// Disable auto response body deflate decompression.
1289    ///
1290    /// This method exists even if the optional `deflate` feature is not enabled.
1291    /// This can be used to ensure a `Client` doesn't use deflate decompression
1292    /// even if another dependency were to enable the optional `deflate` feature.
1293    pub fn no_deflate(self) -> ClientBuilder {
1294        #[cfg(feature = "deflate")]
1295        {
1296            self.deflate(false)
1297        }
1298
1299        #[cfg(not(feature = "deflate"))]
1300        {
1301            self
1302        }
1303    }
1304
1305    // Redirect options
1306
1307    /// Set a `RedirectPolicy` for this client.
1308    ///
1309    /// Default will follow redirects up to a maximum of 10.
1310    pub fn redirect(mut self, policy: redirect::Policy) -> ClientBuilder {
1311        self.config.redirect_policy = policy;
1312        self
1313    }
1314
1315    /// Enable or disable automatic setting of the `Referer` header.
1316    ///
1317    /// Default is `true`.
1318    pub fn referer(mut self, enable: bool) -> ClientBuilder {
1319        self.config.referer = enable;
1320        self
1321    }
1322
1323    // Proxy options
1324
1325    /// Add a `Proxy` to the list of proxies the `Client` will use.
1326    ///
1327    /// # Note
1328    ///
1329    /// Adding a proxy will disable the automatic usage of the "system" proxy.
1330    pub fn proxy(mut self, proxy: Proxy) -> ClientBuilder {
1331        self.config.proxies.push(proxy.into_matcher());
1332        self.config.auto_sys_proxy = false;
1333        self
1334    }
1335
1336    /// Clear all `Proxies`, so `Client` will use no proxy anymore.
1337    ///
1338    /// # Note
1339    /// To add a proxy exclusion list, use [crate::proxy::Proxy::no_proxy()]
1340    /// on all desired proxies instead.
1341    ///
1342    /// This also disables the automatic usage of the "system" proxy.
1343    pub fn no_proxy(mut self) -> ClientBuilder {
1344        self.config.proxies.clear();
1345        self.config.auto_sys_proxy = false;
1346        self
1347    }
1348
1349    // Timeout options
1350
1351    /// Enables a total request timeout.
1352    ///
1353    /// The timeout is applied from when the request starts connecting until the
1354    /// response body has finished. Also considered a total deadline.
1355    ///
1356    /// Default is no timeout.
1357    pub fn timeout(mut self, timeout: Duration) -> ClientBuilder {
1358        self.config.timeout = Some(timeout);
1359        self
1360    }
1361
1362    /// Enables a read timeout.
1363    ///
1364    /// The timeout applies to each read operation, and resets after a
1365    /// successful read. This is more appropriate for detecting stalled
1366    /// connections when the size isn't known beforehand.
1367    ///
1368    /// Default is no timeout.
1369    pub fn read_timeout(mut self, timeout: Duration) -> ClientBuilder {
1370        self.config.read_timeout = Some(timeout);
1371        self
1372    }
1373
1374    /// Set a timeout for only the connect phase of a `Client`.
1375    ///
1376    /// Default is `None`.
1377    ///
1378    /// # Note
1379    ///
1380    /// This **requires** the futures be executed in a tokio runtime with
1381    /// a tokio timer enabled.
1382    pub fn connect_timeout(mut self, timeout: Duration) -> ClientBuilder {
1383        self.config.connect_timeout = Some(timeout);
1384        self
1385    }
1386
1387    /// Set whether connections should emit verbose logs.
1388    ///
1389    /// Enabling this option will emit [log][] messages at the `TRACE` level
1390    /// for read and write operations on connections.
1391    ///
1392    /// [log]: https://crates.io/crates/log
1393    pub fn connection_verbose(mut self, verbose: bool) -> ClientBuilder {
1394        self.config.connection_verbose = verbose;
1395        self
1396    }
1397
1398    // HTTP options
1399
1400    /// Set an optional timeout for idle sockets being kept-alive.
1401    ///
1402    /// Pass `None` to disable timeout.
1403    ///
1404    /// Default is 90 seconds.
1405    pub fn pool_idle_timeout<D>(mut self, val: D) -> ClientBuilder
1406    where
1407        D: Into<Option<Duration>>,
1408    {
1409        self.config.pool_idle_timeout = val.into();
1410        self
1411    }
1412
1413    /// Sets the maximum idle connection per host allowed in the pool.
1414    pub fn pool_max_idle_per_host(mut self, max: usize) -> ClientBuilder {
1415        self.config.pool_max_idle_per_host = max;
1416        self
1417    }
1418
1419    /// Send headers as title case instead of lowercase.
1420    pub fn http1_title_case_headers(mut self) -> ClientBuilder {
1421        self.config.http1_title_case_headers = true;
1422        self
1423    }
1424
1425    /// Set whether HTTP/1 connections will accept obsolete line folding for
1426    /// header values.
1427    ///
1428    /// Newline codepoints (`\r` and `\n`) will be transformed to spaces when
1429    /// parsing.
1430    pub fn http1_allow_obsolete_multiline_headers_in_responses(
1431        mut self,
1432        value: bool,
1433    ) -> ClientBuilder {
1434        self.config
1435            .http1_allow_obsolete_multiline_headers_in_responses = value;
1436        self
1437    }
1438
1439    /// Sets whether invalid header lines should be silently ignored in HTTP/1 responses.
1440    pub fn http1_ignore_invalid_headers_in_responses(mut self, value: bool) -> ClientBuilder {
1441        self.config.http1_ignore_invalid_headers_in_responses = value;
1442        self
1443    }
1444
1445    /// Set whether HTTP/1 connections will accept spaces between header
1446    /// names and the colon that follow them in responses.
1447    ///
1448    /// Newline codepoints (`\r` and `\n`) will be transformed to spaces when
1449    /// parsing.
1450    pub fn http1_allow_spaces_after_header_name_in_responses(
1451        mut self,
1452        value: bool,
1453    ) -> ClientBuilder {
1454        self.config
1455            .http1_allow_spaces_after_header_name_in_responses = value;
1456        self
1457    }
1458
1459    /// Only use HTTP/1.
1460    pub fn http1_only(mut self) -> ClientBuilder {
1461        self.config.http_version_pref = HttpVersionPref::Http1;
1462        self
1463    }
1464
1465    /// Allow HTTP/0.9 responses
1466    pub fn http09_responses(mut self) -> ClientBuilder {
1467        self.config.http09_responses = true;
1468        self
1469    }
1470
1471    /// Only use HTTP/2.
1472    #[cfg(feature = "http2")]
1473    #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
1474    pub fn http2_prior_knowledge(mut self) -> ClientBuilder {
1475        self.config.http_version_pref = HttpVersionPref::Http2;
1476        self
1477    }
1478
1479    /// Only use HTTP/3.
1480    #[cfg(feature = "http3")]
1481    #[cfg_attr(docsrs, doc(cfg(all(reqwest_unstable, feature = "http3",))))]
1482    pub fn http3_prior_knowledge(mut self) -> ClientBuilder {
1483        self.config.http_version_pref = HttpVersionPref::Http3;
1484        self
1485    }
1486
1487    /// Sets the `SETTINGS_INITIAL_WINDOW_SIZE` option for HTTP2 stream-level flow control.
1488    ///
1489    /// Default is currently 65,535 but may change internally to optimize for common uses.
1490    #[cfg(feature = "http2")]
1491    #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
1492    pub fn http2_initial_stream_window_size(mut self, sz: impl Into<Option<u32>>) -> ClientBuilder {
1493        self.config.http2_initial_stream_window_size = sz.into();
1494        self
1495    }
1496
1497    /// Sets the max connection-level flow control for HTTP2
1498    ///
1499    /// Default is currently 65,535 but may change internally to optimize for common uses.
1500    #[cfg(feature = "http2")]
1501    #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
1502    pub fn http2_initial_connection_window_size(
1503        mut self,
1504        sz: impl Into<Option<u32>>,
1505    ) -> ClientBuilder {
1506        self.config.http2_initial_connection_window_size = sz.into();
1507        self
1508    }
1509
1510    /// Sets whether to use an adaptive flow control.
1511    ///
1512    /// Enabling this will override the limits set in `http2_initial_stream_window_size` and
1513    /// `http2_initial_connection_window_size`.
1514    #[cfg(feature = "http2")]
1515    #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
1516    pub fn http2_adaptive_window(mut self, enabled: bool) -> ClientBuilder {
1517        self.config.http2_adaptive_window = enabled;
1518        self
1519    }
1520
1521    /// Sets the maximum frame size to use for HTTP2.
1522    ///
1523    /// Default is currently 16,384 but may change internally to optimize for common uses.
1524    #[cfg(feature = "http2")]
1525    #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
1526    pub fn http2_max_frame_size(mut self, sz: impl Into<Option<u32>>) -> ClientBuilder {
1527        self.config.http2_max_frame_size = sz.into();
1528        self
1529    }
1530
1531    /// Sets the maximum size of received header frames for HTTP2.
1532    ///
1533    /// Default is currently 16KB, but can change.
1534    #[cfg(feature = "http2")]
1535    #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
1536    pub fn http2_max_header_list_size(mut self, max_header_size_bytes: u32) -> ClientBuilder {
1537        self.config.http2_max_header_list_size = Some(max_header_size_bytes);
1538        self
1539    }
1540
1541    /// Sets an interval for HTTP2 Ping frames should be sent to keep a connection alive.
1542    ///
1543    /// Pass `None` to disable HTTP2 keep-alive.
1544    /// Default is currently disabled.
1545    #[cfg(feature = "http2")]
1546    #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
1547    pub fn http2_keep_alive_interval(
1548        mut self,
1549        interval: impl Into<Option<Duration>>,
1550    ) -> ClientBuilder {
1551        self.config.http2_keep_alive_interval = interval.into();
1552        self
1553    }
1554
1555    /// Sets a timeout for receiving an acknowledgement of the keep-alive ping.
1556    ///
1557    /// If the ping is not acknowledged within the timeout, the connection will be closed.
1558    /// Does nothing if `http2_keep_alive_interval` is disabled.
1559    /// Default is currently disabled.
1560    #[cfg(feature = "http2")]
1561    #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
1562    pub fn http2_keep_alive_timeout(mut self, timeout: Duration) -> ClientBuilder {
1563        self.config.http2_keep_alive_timeout = Some(timeout);
1564        self
1565    }
1566
1567    /// Sets whether HTTP2 keep-alive should apply while the connection is idle.
1568    ///
1569    /// If disabled, keep-alive pings are only sent while there are open request/responses streams.
1570    /// If enabled, pings are also sent when no streams are active.
1571    /// Does nothing if `http2_keep_alive_interval` is disabled.
1572    /// Default is `false`.
1573    #[cfg(feature = "http2")]
1574    #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
1575    pub fn http2_keep_alive_while_idle(mut self, enabled: bool) -> ClientBuilder {
1576        self.config.http2_keep_alive_while_idle = enabled;
1577        self
1578    }
1579
1580    // TCP options
1581
1582    /// Set whether sockets have `TCP_NODELAY` enabled.
1583    ///
1584    /// Default is `true`.
1585    pub fn tcp_nodelay(mut self, enabled: bool) -> ClientBuilder {
1586        self.config.nodelay = enabled;
1587        self
1588    }
1589
1590    /// Bind to a local IP Address.
1591    ///
1592    /// # Example
1593    ///
1594    /// ```
1595    /// # fn doc() -> Result<(), reqwest::Error> {
1596    /// use std::net::IpAddr;
1597    /// let local_addr = IpAddr::from([12, 4, 1, 8]);
1598    /// let client = reqwest::Client::builder()
1599    ///     .local_address(local_addr)
1600    ///     .build()?;
1601    /// # Ok(())
1602    /// # }
1603    /// ```
1604    pub fn local_address<T>(mut self, addr: T) -> ClientBuilder
1605    where
1606        T: Into<Option<IpAddr>>,
1607    {
1608        self.config.local_address = addr.into();
1609        self
1610    }
1611
1612    /// Bind connections only on the specified network interface.
1613    ///
1614    /// This option is only available on the following operating systems:
1615    ///
1616    /// - Android
1617    /// - Fuchsia
1618    /// - Linux,
1619    /// - macOS and macOS-like systems (iOS, tvOS, watchOS and visionOS)
1620    /// - Solaris and illumos
1621    ///
1622    /// On Android, Linux, and Fuchsia, this uses the
1623    /// [`SO_BINDTODEVICE`][man-7-socket] socket option. On macOS and macOS-like
1624    /// systems, Solaris, and illumos, this instead uses the [`IP_BOUND_IF` and
1625    /// `IPV6_BOUND_IF`][man-7p-ip] socket options (as appropriate).
1626    ///
1627    /// Note that connections will fail if the provided interface name is not a
1628    /// network interface that currently exists when a connection is established.
1629    ///
1630    /// # Example
1631    ///
1632    /// ```
1633    /// # fn doc() -> Result<(), reqwest::Error> {
1634    /// let interface = "lo";
1635    /// let client = reqwest::Client::builder()
1636    ///     .interface(interface)
1637    ///     .build()?;
1638    /// # Ok(())
1639    /// # }
1640    /// ```
1641    ///
1642    /// [man-7-socket]: https://man7.org/linux/man-pages/man7/socket.7.html
1643    /// [man-7p-ip]: https://docs.oracle.com/cd/E86824_01/html/E54777/ip-7p.html
1644    #[cfg(any(
1645        target_os = "android",
1646        target_os = "fuchsia",
1647        target_os = "illumos",
1648        target_os = "ios",
1649        target_os = "linux",
1650        target_os = "macos",
1651        target_os = "solaris",
1652        target_os = "tvos",
1653        target_os = "visionos",
1654        target_os = "watchos",
1655    ))]
1656    pub fn interface(mut self, interface: &str) -> ClientBuilder {
1657        self.config.interface = Some(interface.to_string());
1658        self
1659    }
1660
1661    /// Set that all sockets have `SO_KEEPALIVE` set with the supplied duration.
1662    ///
1663    /// If `None`, the option will not be set.
1664    pub fn tcp_keepalive<D>(mut self, val: D) -> ClientBuilder
1665    where
1666        D: Into<Option<Duration>>,
1667    {
1668        self.config.tcp_keepalive = val.into();
1669        self
1670    }
1671
1672    /// Set that all sockets have `SO_KEEPALIVE` set with the supplied interval.
1673    ///
1674    /// If `None`, the option will not be set.
1675    pub fn tcp_keepalive_interval<D>(mut self, val: D) -> ClientBuilder
1676    where
1677        D: Into<Option<Duration>>,
1678    {
1679        self.config.tcp_keepalive_interval = val.into();
1680        self
1681    }
1682
1683    /// Set that all sockets have `SO_KEEPALIVE` set with the supplied retry count.
1684    ///
1685    /// If `None`, the option will not be set.
1686    pub fn tcp_keepalive_retries<C>(mut self, retries: C) -> ClientBuilder
1687    where
1688        C: Into<Option<u32>>,
1689    {
1690        self.config.tcp_keepalive_retries = retries.into();
1691        self
1692    }
1693
1694    // TLS options
1695
1696    /// Add a custom root certificate.
1697    ///
1698    /// This can be used to connect to a server that has a self-signed
1699    /// certificate for example.
1700    ///
1701    /// # Optional
1702    ///
1703    /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
1704    /// feature to be enabled.
1705    #[cfg(feature = "__tls")]
1706    #[cfg_attr(
1707        docsrs,
1708        doc(cfg(any(
1709            feature = "default-tls",
1710            feature = "native-tls",
1711            feature = "rustls-tls"
1712        )))
1713    )]
1714    pub fn add_root_certificate(mut self, cert: Certificate) -> ClientBuilder {
1715        self.config.root_certs.push(cert);
1716        self
1717    }
1718
1719    /// Add a certificate revocation list.
1720    ///
1721    ///
1722    /// # Optional
1723    ///
1724    /// This requires the `rustls-tls(-...)` Cargo feature enabled.
1725    #[cfg(feature = "__rustls")]
1726    #[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls")))]
1727    pub fn add_crl(mut self, crl: CertificateRevocationList) -> ClientBuilder {
1728        self.config.crls.push(crl);
1729        self
1730    }
1731
1732    /// Add multiple certificate revocation lists.
1733    ///
1734    ///
1735    /// # Optional
1736    ///
1737    /// This requires the `rustls-tls(-...)` Cargo feature enabled.
1738    #[cfg(feature = "__rustls")]
1739    #[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls")))]
1740    pub fn add_crls(
1741        mut self,
1742        crls: impl IntoIterator<Item = CertificateRevocationList>,
1743    ) -> ClientBuilder {
1744        self.config.crls.extend(crls);
1745        self
1746    }
1747
1748    /// Controls the use of built-in/preloaded certificates during certificate validation.
1749    ///
1750    /// Defaults to `true` -- built-in system certs will be used.
1751    ///
1752    /// # Bulk Option
1753    ///
1754    /// If this value is `true`, _all_ enabled system certs configured with Cargo
1755    /// features will be loaded.
1756    ///
1757    /// You can set this to `false`, and enable only a specific source with
1758    /// individual methods. Do that will prevent other sources from being loaded
1759    /// even if their feature Cargo feature is enabled.
1760    ///
1761    /// # Optional
1762    ///
1763    /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
1764    /// feature to be enabled.
1765    #[cfg(feature = "__tls")]
1766    #[cfg_attr(
1767        docsrs,
1768        doc(cfg(any(
1769            feature = "default-tls",
1770            feature = "native-tls",
1771            feature = "rustls-tls"
1772        )))
1773    )]
1774    pub fn tls_built_in_root_certs(mut self, tls_built_in_root_certs: bool) -> ClientBuilder {
1775        self.config.tls_built_in_root_certs = tls_built_in_root_certs;
1776
1777        #[cfg(feature = "rustls-tls-webpki-roots-no-provider")]
1778        {
1779            self.config.tls_built_in_certs_webpki = tls_built_in_root_certs;
1780        }
1781
1782        #[cfg(feature = "rustls-tls-native-roots-no-provider")]
1783        {
1784            self.config.tls_built_in_certs_native = tls_built_in_root_certs;
1785        }
1786
1787        self
1788    }
1789
1790    /// Sets whether to load webpki root certs with rustls.
1791    ///
1792    /// If the feature is enabled, this value is `true` by default.
1793    #[cfg(feature = "rustls-tls-webpki-roots-no-provider")]
1794    #[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls-webpki-roots-no-provider")))]
1795    pub fn tls_built_in_webpki_certs(mut self, enabled: bool) -> ClientBuilder {
1796        self.config.tls_built_in_certs_webpki = enabled;
1797        self
1798    }
1799
1800    /// Sets whether to load native root certs with rustls.
1801    ///
1802    /// If the feature is enabled, this value is `true` by default.
1803    #[cfg(feature = "rustls-tls-native-roots-no-provider")]
1804    #[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls-native-roots-no-provider")))]
1805    pub fn tls_built_in_native_certs(mut self, enabled: bool) -> ClientBuilder {
1806        self.config.tls_built_in_certs_native = enabled;
1807        self
1808    }
1809
1810    /// Sets the identity to be used for client certificate authentication.
1811    ///
1812    /// # Optional
1813    ///
1814    /// This requires the optional `native-tls` or `rustls-tls(-...)` feature to be
1815    /// enabled.
1816    #[cfg(any(feature = "native-tls", feature = "__rustls"))]
1817    #[cfg_attr(docsrs, doc(cfg(any(feature = "native-tls", feature = "rustls-tls"))))]
1818    pub fn identity(mut self, identity: Identity) -> ClientBuilder {
1819        self.config.identity = Some(identity);
1820        self
1821    }
1822
1823    /// Controls the use of hostname verification.
1824    ///
1825    /// Defaults to `false`.
1826    ///
1827    /// # Warning
1828    ///
1829    /// You should think very carefully before you use this method. If
1830    /// hostname verification is not used, any valid certificate for any
1831    /// site will be trusted for use from any other. This introduces a
1832    /// significant vulnerability to man-in-the-middle attacks.
1833    ///
1834    /// # Optional
1835    ///
1836    /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
1837    /// feature to be enabled.
1838    #[cfg(feature = "__tls")]
1839    #[cfg_attr(
1840        docsrs,
1841        doc(cfg(any(
1842            feature = "default-tls",
1843            feature = "native-tls",
1844            feature = "rustls-tls"
1845        )))
1846    )]
1847    pub fn danger_accept_invalid_hostnames(
1848        mut self,
1849        accept_invalid_hostname: bool,
1850    ) -> ClientBuilder {
1851        self.config.hostname_verification = !accept_invalid_hostname;
1852        self
1853    }
1854
1855    /// Controls the use of certificate validation.
1856    ///
1857    /// Defaults to `false`.
1858    ///
1859    /// # Warning
1860    ///
1861    /// You should think very carefully before using this method. If
1862    /// invalid certificates are trusted, *any* certificate for *any* site
1863    /// will be trusted for use. This includes expired certificates. This
1864    /// introduces significant vulnerabilities, and should only be used
1865    /// as a last resort.
1866    ///
1867    /// # Optional
1868    ///
1869    /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
1870    /// feature to be enabled.
1871    #[cfg(feature = "__tls")]
1872    #[cfg_attr(
1873        docsrs,
1874        doc(cfg(any(
1875            feature = "default-tls",
1876            feature = "native-tls",
1877            feature = "rustls-tls"
1878        )))
1879    )]
1880    pub fn danger_accept_invalid_certs(mut self, accept_invalid_certs: bool) -> ClientBuilder {
1881        self.config.certs_verification = !accept_invalid_certs;
1882        self
1883    }
1884
1885    /// Controls the use of TLS server name indication.
1886    ///
1887    /// Defaults to `true`.
1888    ///
1889    /// # Optional
1890    ///
1891    /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
1892    /// feature to be enabled.
1893    #[cfg(feature = "__tls")]
1894    #[cfg_attr(
1895        docsrs,
1896        doc(cfg(any(
1897            feature = "default-tls",
1898            feature = "native-tls",
1899            feature = "rustls-tls"
1900        )))
1901    )]
1902    pub fn tls_sni(mut self, tls_sni: bool) -> ClientBuilder {
1903        self.config.tls_sni = tls_sni;
1904        self
1905    }
1906
1907    /// Set the minimum required TLS version for connections.
1908    ///
1909    /// By default, the TLS backend's own default is used.
1910    ///
1911    /// # Errors
1912    ///
1913    /// A value of `tls::Version::TLS_1_3` will cause an error with the
1914    /// `native-tls`/`default-tls` backend. This does not mean the version
1915    /// isn't supported, just that it can't be set as a minimum due to
1916    /// technical limitations.
1917    ///
1918    /// # Optional
1919    ///
1920    /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
1921    /// feature to be enabled.
1922    #[cfg(feature = "__tls")]
1923    #[cfg_attr(
1924        docsrs,
1925        doc(cfg(any(
1926            feature = "default-tls",
1927            feature = "native-tls",
1928            feature = "rustls-tls"
1929        )))
1930    )]
1931    pub fn min_tls_version(mut self, version: tls::Version) -> ClientBuilder {
1932        self.config.min_tls_version = Some(version);
1933        self
1934    }
1935
1936    /// Set the maximum allowed TLS version for connections.
1937    ///
1938    /// By default, there's no maximum.
1939    ///
1940    /// # Errors
1941    ///
1942    /// A value of `tls::Version::TLS_1_3` will cause an error with the
1943    /// `native-tls`/`default-tls` backend. This does not mean the version
1944    /// isn't supported, just that it can't be set as a maximum due to
1945    /// technical limitations.
1946    ///
1947    /// Cannot set a maximum outside the protocol versions supported by
1948    /// `rustls` with the `rustls-tls` backend.
1949    ///
1950    /// # Optional
1951    ///
1952    /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
1953    /// feature to be enabled.
1954    #[cfg(feature = "__tls")]
1955    #[cfg_attr(
1956        docsrs,
1957        doc(cfg(any(
1958            feature = "default-tls",
1959            feature = "native-tls",
1960            feature = "rustls-tls"
1961        )))
1962    )]
1963    pub fn max_tls_version(mut self, version: tls::Version) -> ClientBuilder {
1964        self.config.max_tls_version = Some(version);
1965        self
1966    }
1967
1968    /// Force using the native TLS backend.
1969    ///
1970    /// Since multiple TLS backends can be optionally enabled, this option will
1971    /// force the `native-tls` backend to be used for this `Client`.
1972    ///
1973    /// # Optional
1974    ///
1975    /// This requires the optional `native-tls` feature to be enabled.
1976    #[cfg(feature = "native-tls")]
1977    #[cfg_attr(docsrs, doc(cfg(feature = "native-tls")))]
1978    pub fn use_native_tls(mut self) -> ClientBuilder {
1979        self.config.tls = TlsBackend::Default;
1980        self
1981    }
1982
1983    /// Force using the Rustls TLS backend.
1984    ///
1985    /// Since multiple TLS backends can be optionally enabled, this option will
1986    /// force the `rustls` backend to be used for this `Client`.
1987    ///
1988    /// # Optional
1989    ///
1990    /// This requires the optional `rustls-tls(-...)` feature to be enabled.
1991    #[cfg(feature = "__rustls")]
1992    #[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls")))]
1993    pub fn use_rustls_tls(mut self) -> ClientBuilder {
1994        self.config.tls = TlsBackend::Rustls;
1995        self
1996    }
1997
1998    /// Use a preconfigured TLS backend.
1999    ///
2000    /// If the passed `Any` argument is not a TLS backend that reqwest
2001    /// understands, the `ClientBuilder` will error when calling `build`.
2002    ///
2003    /// # Advanced
2004    ///
2005    /// This is an advanced option, and can be somewhat brittle. Usage requires
2006    /// keeping the preconfigured TLS argument version in sync with reqwest,
2007    /// since version mismatches will result in an "unknown" TLS backend.
2008    ///
2009    /// If possible, it's preferable to use the methods on `ClientBuilder`
2010    /// to configure reqwest's TLS.
2011    ///
2012    /// # Optional
2013    ///
2014    /// This requires one of the optional features `native-tls` or
2015    /// `rustls-tls(-...)` to be enabled.
2016    #[cfg(any(feature = "native-tls", feature = "__rustls",))]
2017    #[cfg_attr(docsrs, doc(cfg(any(feature = "native-tls", feature = "rustls-tls"))))]
2018    pub fn use_preconfigured_tls(mut self, tls: impl Any) -> ClientBuilder {
2019        let mut tls = Some(tls);
2020        #[cfg(feature = "native-tls")]
2021        {
2022            if let Some(conn) = (&mut tls as &mut dyn Any).downcast_mut::<Option<TlsConnector>>() {
2023                let tls = conn.take().expect("is definitely Some");
2024                let tls = crate::tls::TlsBackend::BuiltNativeTls(tls);
2025                self.config.tls = tls;
2026                return self;
2027            }
2028        }
2029        #[cfg(feature = "__rustls")]
2030        {
2031            if let Some(conn) =
2032                (&mut tls as &mut dyn Any).downcast_mut::<Option<rustls::ClientConfig>>()
2033            {
2034                let tls = conn.take().expect("is definitely Some");
2035                let tls = crate::tls::TlsBackend::BuiltRustls(tls);
2036                self.config.tls = tls;
2037                return self;
2038            }
2039        }
2040
2041        // Otherwise, we don't recognize the TLS backend!
2042        self.config.tls = crate::tls::TlsBackend::UnknownPreconfigured;
2043        self
2044    }
2045
2046    /// Add TLS information as `TlsInfo` extension to responses.
2047    ///
2048    /// # Optional
2049    ///
2050    /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
2051    /// feature to be enabled.
2052    #[cfg(feature = "__tls")]
2053    #[cfg_attr(
2054        docsrs,
2055        doc(cfg(any(
2056            feature = "default-tls",
2057            feature = "native-tls",
2058            feature = "rustls-tls"
2059        )))
2060    )]
2061    pub fn tls_info(mut self, tls_info: bool) -> ClientBuilder {
2062        self.config.tls_info = tls_info;
2063        self
2064    }
2065
2066    /// Restrict the Client to be used with HTTPS only requests.
2067    ///
2068    /// Defaults to false.
2069    pub fn https_only(mut self, enabled: bool) -> ClientBuilder {
2070        self.config.https_only = enabled;
2071        self
2072    }
2073
2074    #[doc(hidden)]
2075    #[cfg(feature = "hickory-dns")]
2076    #[cfg_attr(docsrs, doc(cfg(feature = "hickory-dns")))]
2077    #[deprecated(note = "use `hickory_dns` instead")]
2078    pub fn trust_dns(mut self, enable: bool) -> ClientBuilder {
2079        self.config.hickory_dns = enable;
2080        self
2081    }
2082
2083    /// Enables the [hickory-dns](hickory_resolver) async resolver instead of a default threadpool
2084    /// using `getaddrinfo`.
2085    ///
2086    /// If the `hickory-dns` feature is turned on, the default option is enabled.
2087    ///
2088    /// # Optional
2089    ///
2090    /// This requires the optional `hickory-dns` feature to be enabled
2091    ///
2092    /// # Warning
2093    ///
2094    /// The hickory resolver does not work exactly the same, or on all the platforms
2095    /// that the default resolver does
2096    #[cfg(feature = "hickory-dns")]
2097    #[cfg_attr(docsrs, doc(cfg(feature = "hickory-dns")))]
2098    pub fn hickory_dns(mut self, enable: bool) -> ClientBuilder {
2099        self.config.hickory_dns = enable;
2100        self
2101    }
2102
2103    #[doc(hidden)]
2104    #[deprecated(note = "use `no_hickory_dns` instead")]
2105    pub fn no_trust_dns(self) -> ClientBuilder {
2106        self.no_hickory_dns()
2107    }
2108
2109    /// Disables the hickory-dns async resolver.
2110    ///
2111    /// This method exists even if the optional `hickory-dns` feature is not enabled.
2112    /// This can be used to ensure a `Client` doesn't use the hickory-dns async resolver
2113    /// even if another dependency were to enable the optional `hickory-dns` feature.
2114    pub fn no_hickory_dns(self) -> ClientBuilder {
2115        #[cfg(feature = "hickory-dns")]
2116        {
2117            self.hickory_dns(false)
2118        }
2119
2120        #[cfg(not(feature = "hickory-dns"))]
2121        {
2122            self
2123        }
2124    }
2125
2126    /// Override DNS resolution for specific domains to a particular IP address.
2127    ///
2128    /// Set the port to `0` to use the conventional port for the given scheme (e.g. 80 for http).
2129    /// Ports in the URL itself will always be used instead of the port in the overridden addr.
2130    pub fn resolve(self, domain: &str, addr: SocketAddr) -> ClientBuilder {
2131        self.resolve_to_addrs(domain, &[addr])
2132    }
2133
2134    /// Override DNS resolution for specific domains to particular IP addresses.
2135    ///
2136    /// Set the port to `0` to use the conventional port for the given scheme (e.g. 80 for http).
2137    /// Ports in the URL itself will always be used instead of the port in the overridden addr.
2138    pub fn resolve_to_addrs(mut self, domain: &str, addrs: &[SocketAddr]) -> ClientBuilder {
2139        self.config
2140            .dns_overrides
2141            .insert(domain.to_ascii_lowercase(), addrs.to_vec());
2142        self
2143    }
2144
2145    /// Override the DNS resolver implementation.
2146    ///
2147    /// Pass an `Arc` wrapping a trait object implementing `Resolve`.
2148    /// Overrides for specific names passed to `resolve` and `resolve_to_addrs` will
2149    /// still be applied on top of this resolver.
2150    pub fn dns_resolver<R: Resolve + 'static>(mut self, resolver: Arc<R>) -> ClientBuilder {
2151        self.config.dns_resolver = Some(resolver as _);
2152        self
2153    }
2154
2155    /// Whether to send data on the first flight ("early data") in TLS 1.3 handshakes
2156    /// for HTTP/3 connections.
2157    ///
2158    /// The default is false.
2159    #[cfg(feature = "http3")]
2160    #[cfg_attr(docsrs, doc(cfg(all(reqwest_unstable, feature = "http3",))))]
2161    pub fn tls_early_data(mut self, enabled: bool) -> ClientBuilder {
2162        self.config.tls_enable_early_data = enabled;
2163        self
2164    }
2165
2166    /// Maximum duration of inactivity to accept before timing out the QUIC connection.
2167    ///
2168    /// Please see docs in [`TransportConfig`] in [`quinn`].
2169    ///
2170    /// [`TransportConfig`]: https://docs.rs/quinn/latest/quinn/struct.TransportConfig.html
2171    #[cfg(feature = "http3")]
2172    #[cfg_attr(docsrs, doc(cfg(all(reqwest_unstable, feature = "http3",))))]
2173    pub fn http3_max_idle_timeout(mut self, value: Duration) -> ClientBuilder {
2174        self.config.quic_max_idle_timeout = Some(value);
2175        self
2176    }
2177
2178    /// Maximum number of bytes the peer may transmit without acknowledgement on any one stream
2179    /// before becoming blocked.
2180    ///
2181    /// Please see docs in [`TransportConfig`] in [`quinn`].
2182    ///
2183    /// [`TransportConfig`]: https://docs.rs/quinn/latest/quinn/struct.TransportConfig.html
2184    ///
2185    /// # Panics
2186    ///
2187    /// Panics if the value is over 2^62.
2188    #[cfg(feature = "http3")]
2189    #[cfg_attr(docsrs, doc(cfg(all(reqwest_unstable, feature = "http3",))))]
2190    pub fn http3_stream_receive_window(mut self, value: u64) -> ClientBuilder {
2191        self.config.quic_stream_receive_window = Some(value.try_into().unwrap());
2192        self
2193    }
2194
2195    /// Maximum number of bytes the peer may transmit across all streams of a connection before
2196    /// becoming blocked.
2197    ///
2198    /// Please see docs in [`TransportConfig`] in [`quinn`].
2199    ///
2200    /// [`TransportConfig`]: https://docs.rs/quinn/latest/quinn/struct.TransportConfig.html
2201    ///
2202    /// # Panics
2203    ///
2204    /// Panics if the value is over 2^62.
2205    #[cfg(feature = "http3")]
2206    #[cfg_attr(docsrs, doc(cfg(all(reqwest_unstable, feature = "http3",))))]
2207    pub fn http3_conn_receive_window(mut self, value: u64) -> ClientBuilder {
2208        self.config.quic_receive_window = Some(value.try_into().unwrap());
2209        self
2210    }
2211
2212    /// Maximum number of bytes to transmit to a peer without acknowledgment
2213    ///
2214    /// Please see docs in [`TransportConfig`] in [`quinn`].
2215    ///
2216    /// [`TransportConfig`]: https://docs.rs/quinn/latest/quinn/struct.TransportConfig.html
2217    #[cfg(feature = "http3")]
2218    #[cfg_attr(docsrs, doc(cfg(all(reqwest_unstable, feature = "http3",))))]
2219    pub fn http3_send_window(mut self, value: u64) -> ClientBuilder {
2220        self.config.quic_send_window = Some(value);
2221        self
2222    }
2223
2224    /// Override the default congestion control algorithm to use [BBR]
2225    ///
2226    /// The current default congestion control algorithm is [CUBIC]. This method overrides the
2227    /// default.
2228    ///
2229    /// [BBR]: https://datatracker.ietf.org/doc/html/draft-ietf-ccwg-bbr
2230    /// [CUBIC]: https://datatracker.ietf.org/doc/html/rfc8312
2231    #[cfg(feature = "http3")]
2232    #[cfg_attr(docsrs, doc(cfg(all(reqwest_unstable, feature = "http3",))))]
2233    pub fn http3_congestion_bbr(mut self) -> ClientBuilder {
2234        self.config.quic_congestion_bbr = true;
2235        self
2236    }
2237
2238    /// Set the maximum HTTP/3 header size this client is willing to accept.
2239    ///
2240    /// See [header size constraints] section of the specification for details.
2241    ///
2242    /// [header size constraints]: https://www.rfc-editor.org/rfc/rfc9114.html#name-header-size-constraints
2243    ///
2244    /// Please see docs in [`Builder`] in [`h3`].
2245    ///
2246    /// [`Builder`]: https://docs.rs/h3/latest/h3/client/struct.Builder.html#method.max_field_section_size
2247    #[cfg(feature = "http3")]
2248    #[cfg_attr(docsrs, doc(cfg(all(reqwest_unstable, feature = "http3",))))]
2249    pub fn http3_max_field_section_size(mut self, value: u64) -> ClientBuilder {
2250        self.config.h3_max_field_section_size = Some(value.try_into().unwrap());
2251        self
2252    }
2253
2254    /// Enable whether to send HTTP/3 protocol grease on the connections.
2255    ///
2256    /// HTTP/3 uses the concept of "grease"
2257    ///
2258    /// to prevent potential interoperability issues in the future.
2259    /// In HTTP/3, the concept of grease is used to ensure that the protocol can evolve
2260    /// and accommodate future changes without breaking existing implementations.
2261    ///
2262    /// Please see docs in [`Builder`] in [`h3`].
2263    ///
2264    /// [`Builder`]: https://docs.rs/h3/latest/h3/client/struct.Builder.html#method.send_grease
2265    #[cfg(feature = "http3")]
2266    #[cfg_attr(docsrs, doc(cfg(all(reqwest_unstable, feature = "http3",))))]
2267    pub fn http3_send_grease(mut self, enabled: bool) -> ClientBuilder {
2268        self.config.h3_send_grease = Some(enabled);
2269        self
2270    }
2271
2272    /// Adds a new Tower [`Layer`](https://docs.rs/tower/latest/tower/trait.Layer.html) to the
2273    /// base connector [`Service`](https://docs.rs/tower/latest/tower/trait.Service.html) which
2274    /// is responsible for connection establishment.
2275    ///
2276    /// Each subsequent invocation of this function will wrap previous layers.
2277    ///
2278    /// If configured, the `connect_timeout` will be the outermost layer.
2279    ///
2280    /// Example usage:
2281    /// ```
2282    /// use std::time::Duration;
2283    ///
2284    /// # #[cfg(not(feature = "rustls-tls-no-provider"))]
2285    /// let client = reqwest::Client::builder()
2286    ///                      // resolved to outermost layer, meaning while we are waiting on concurrency limit
2287    ///                      .connect_timeout(Duration::from_millis(200))
2288    ///                      // underneath the concurrency check, so only after concurrency limit lets us through
2289    ///                      .connector_layer(tower::timeout::TimeoutLayer::new(Duration::from_millis(50)))
2290    ///                      .connector_layer(tower::limit::concurrency::ConcurrencyLimitLayer::new(2))
2291    ///                      .build()
2292    ///                      .unwrap();
2293    /// ```
2294    ///
2295    pub fn connector_layer<L>(mut self, layer: L) -> ClientBuilder
2296    where
2297        L: Layer<BoxedConnectorService> + Clone + Send + Sync + 'static,
2298        L::Service:
2299            Service<Unnameable, Response = Conn, Error = BoxError> + Clone + Send + Sync + 'static,
2300        <L::Service as Service<Unnameable>>::Future: Send + 'static,
2301    {
2302        let layer = BoxCloneSyncServiceLayer::new(layer);
2303
2304        self.config.connector_layers.push(layer);
2305
2306        self
2307    }
2308}
2309
2310type HyperClient = hyper_util::client::legacy::Client<Connector, super::Body>;
2311
2312impl Default for Client {
2313    fn default() -> Self {
2314        Self::new()
2315    }
2316}
2317
2318impl Client {
2319    /// Constructs a new `Client`.
2320    ///
2321    /// # Panics
2322    ///
2323    /// This method panics if a TLS backend cannot be initialized, or the resolver
2324    /// cannot load the system configuration.
2325    ///
2326    /// Use `Client::builder()` if you wish to handle the failure as an `Error`
2327    /// instead of panicking.
2328    pub fn new() -> Client {
2329        ClientBuilder::new().build().expect("Client::new()")
2330    }
2331
2332    /// Creates a `ClientBuilder` to configure a `Client`.
2333    ///
2334    /// This is the same as `ClientBuilder::new()`.
2335    pub fn builder() -> ClientBuilder {
2336        ClientBuilder::new()
2337    }
2338
2339    /// Convenience method to make a `GET` request to a URL.
2340    ///
2341    /// # Errors
2342    ///
2343    /// This method fails whenever the supplied `Url` cannot be parsed.
2344    pub fn get<U: IntoUrl>(&self, url: U) -> RequestBuilder {
2345        self.request(Method::GET, url)
2346    }
2347
2348    /// Convenience method to make a `POST` request to a URL.
2349    ///
2350    /// # Errors
2351    ///
2352    /// This method fails whenever the supplied `Url` cannot be parsed.
2353    pub fn post<U: IntoUrl>(&self, url: U) -> RequestBuilder {
2354        self.request(Method::POST, url)
2355    }
2356
2357    /// Convenience method to make a `PUT` request to a URL.
2358    ///
2359    /// # Errors
2360    ///
2361    /// This method fails whenever the supplied `Url` cannot be parsed.
2362    pub fn put<U: IntoUrl>(&self, url: U) -> RequestBuilder {
2363        self.request(Method::PUT, url)
2364    }
2365
2366    /// Convenience method to make a `PATCH` request to a URL.
2367    ///
2368    /// # Errors
2369    ///
2370    /// This method fails whenever the supplied `Url` cannot be parsed.
2371    pub fn patch<U: IntoUrl>(&self, url: U) -> RequestBuilder {
2372        self.request(Method::PATCH, url)
2373    }
2374
2375    /// Convenience method to make a `DELETE` request to a URL.
2376    ///
2377    /// # Errors
2378    ///
2379    /// This method fails whenever the supplied `Url` cannot be parsed.
2380    pub fn delete<U: IntoUrl>(&self, url: U) -> RequestBuilder {
2381        self.request(Method::DELETE, url)
2382    }
2383
2384    /// Convenience method to make a `HEAD` request to a URL.
2385    ///
2386    /// # Errors
2387    ///
2388    /// This method fails whenever the supplied `Url` cannot be parsed.
2389    pub fn head<U: IntoUrl>(&self, url: U) -> RequestBuilder {
2390        self.request(Method::HEAD, url)
2391    }
2392
2393    /// Start building a `Request` with the `Method` and `Url`.
2394    ///
2395    /// Returns a `RequestBuilder`, which will allow setting headers and
2396    /// the request body before sending.
2397    ///
2398    /// # Errors
2399    ///
2400    /// This method fails whenever the supplied `Url` cannot be parsed.
2401    pub fn request<U: IntoUrl>(&self, method: Method, url: U) -> RequestBuilder {
2402        let req = url.into_url().map(move |url| Request::new(method, url));
2403        RequestBuilder::new(self.clone(), req)
2404    }
2405
2406    /// Executes a `Request`.
2407    ///
2408    /// A `Request` can be built manually with `Request::new()` or obtained
2409    /// from a RequestBuilder with `RequestBuilder::build()`.
2410    ///
2411    /// You should prefer to use the `RequestBuilder` and
2412    /// `RequestBuilder::send()`.
2413    ///
2414    /// # Errors
2415    ///
2416    /// This method fails if there was an error while sending request,
2417    /// redirect loop was detected or redirect limit was exhausted.
2418    pub fn execute(
2419        &self,
2420        request: Request,
2421    ) -> impl Future<Output = Result<Response, crate::Error>> {
2422        self.execute_request(request)
2423    }
2424
2425    pub(super) fn execute_request(&self, req: Request) -> Pending {
2426        let (method, url, mut headers, body, version, extensions) = req.pieces();
2427        if url.scheme() != "http" && url.scheme() != "https" {
2428            return Pending::new_err(error::url_bad_scheme(url));
2429        }
2430
2431        // check if we're in https_only mode and check the scheme of the current URL
2432        if self.inner.https_only && url.scheme() != "https" {
2433            return Pending::new_err(error::url_bad_scheme(url));
2434        }
2435
2436        // insert default headers in the request headers
2437        // without overwriting already appended headers.
2438        for (key, value) in &self.inner.headers {
2439            if let Entry::Vacant(entry) = headers.entry(key) {
2440                entry.insert(value.clone());
2441            }
2442        }
2443
2444        let accept_encoding = self.inner.accepts.as_str();
2445
2446        if let Some(accept_encoding) = accept_encoding {
2447            if !headers.contains_key(ACCEPT_ENCODING) && !headers.contains_key(RANGE) {
2448                headers.insert(ACCEPT_ENCODING, HeaderValue::from_static(accept_encoding));
2449            }
2450        }
2451
2452        let uri = match try_uri(&url) {
2453            Ok(uri) => uri,
2454            _ => return Pending::new_err(error::url_invalid_uri(url)),
2455        };
2456
2457        let (reusable, body) = match body {
2458            Some(body) => {
2459                let (reusable, body) = body.try_reuse();
2460                (Some(reusable), body)
2461            }
2462            None => (None, Body::empty()),
2463        };
2464
2465        self.proxy_auth(&uri, &mut headers);
2466        self.proxy_custom_headers(&uri, &mut headers);
2467
2468        let builder = hyper::Request::builder()
2469            .method(method.clone())
2470            .uri(uri)
2471            .version(version);
2472
2473        let in_flight = match version {
2474            #[cfg(feature = "http3")]
2475            http::Version::HTTP_3 if self.inner.h3_client.is_some() => {
2476                let mut req = builder.body(body).expect("valid request parts");
2477                *req.headers_mut() = headers.clone();
2478                let mut h3 = self.inner.h3_client.as_ref().unwrap().clone();
2479                ResponseFuture::H3(h3.call(req))
2480            }
2481            _ => {
2482                let mut req = builder.body(body).expect("valid request parts");
2483                *req.headers_mut() = headers.clone();
2484                let mut hyper = self.inner.hyper.clone();
2485                ResponseFuture::Default(hyper.call(req))
2486            }
2487        };
2488
2489        let total_timeout = self
2490            .inner
2491            .request_timeout
2492            .fetch(&extensions)
2493            .copied()
2494            .map(tokio::time::sleep)
2495            .map(Box::pin);
2496
2497        let read_timeout_fut = self
2498            .inner
2499            .read_timeout
2500            .map(tokio::time::sleep)
2501            .map(Box::pin);
2502
2503        Pending {
2504            inner: PendingInner::Request(PendingRequest {
2505                method,
2506                url,
2507                headers,
2508                body: reusable,
2509
2510                retry_count: 0,
2511
2512                client: self.inner.clone(),
2513
2514                in_flight,
2515                total_timeout,
2516                read_timeout_fut,
2517                read_timeout: self.inner.read_timeout,
2518            }),
2519        }
2520    }
2521
2522    fn proxy_auth(&self, dst: &Uri, headers: &mut HeaderMap) {
2523        if !self.inner.proxies_maybe_http_auth {
2524            return;
2525        }
2526
2527        // Only set the header here if the destination scheme is 'http',
2528        // since otherwise, the header will be included in the CONNECT tunnel
2529        // request instead.
2530        if dst.scheme() != Some(&Scheme::HTTP) {
2531            return;
2532        }
2533
2534        if headers.contains_key(PROXY_AUTHORIZATION) {
2535            return;
2536        }
2537
2538        for proxy in self.inner.proxies.iter() {
2539            if let Some(header) = proxy.http_non_tunnel_basic_auth(dst) {
2540                headers.insert(PROXY_AUTHORIZATION, header);
2541            }
2542
2543            break;
2544        }
2545    }
2546
2547    fn proxy_custom_headers(&self, dst: &Uri, headers: &mut HeaderMap) {
2548        if !self.inner.proxies_maybe_http_custom_headers {
2549            return;
2550        }
2551
2552        if dst.scheme() != Some(&Scheme::HTTP) {
2553            return;
2554        }
2555
2556        for proxy in self.inner.proxies.iter() {
2557            if let Some(iter) = proxy.http_non_tunnel_custom_headers(dst) {
2558                iter.iter().for_each(|(key, value)| {
2559                    headers.insert(key, value.clone());
2560                });
2561            }
2562
2563            break;
2564        }
2565    }
2566}
2567
2568impl fmt::Debug for Client {
2569    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2570        let mut builder = f.debug_struct("Client");
2571        self.inner.fmt_fields(&mut builder);
2572        builder.finish()
2573    }
2574}
2575
2576impl tower_service::Service<Request> for Client {
2577    type Response = Response;
2578    type Error = crate::Error;
2579    type Future = Pending;
2580
2581    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
2582        Poll::Ready(Ok(()))
2583    }
2584
2585    fn call(&mut self, req: Request) -> Self::Future {
2586        self.execute_request(req)
2587    }
2588}
2589
2590impl tower_service::Service<Request> for &'_ Client {
2591    type Response = Response;
2592    type Error = crate::Error;
2593    type Future = Pending;
2594
2595    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
2596        Poll::Ready(Ok(()))
2597    }
2598
2599    fn call(&mut self, req: Request) -> Self::Future {
2600        self.execute_request(req)
2601    }
2602}
2603
2604impl fmt::Debug for ClientBuilder {
2605    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2606        let mut builder = f.debug_struct("ClientBuilder");
2607        self.config.fmt_fields(&mut builder);
2608        builder.finish()
2609    }
2610}
2611
2612impl Config {
2613    fn fmt_fields(&self, f: &mut fmt::DebugStruct<'_, '_>) {
2614        // Instead of deriving Debug, only print fields when their output
2615        // would provide relevant or interesting data.
2616
2617        #[cfg(feature = "cookies")]
2618        {
2619            if let Some(_) = self.cookie_store {
2620                f.field("cookie_store", &true);
2621            }
2622        }
2623
2624        f.field("accepts", &self.accepts);
2625
2626        if !self.proxies.is_empty() {
2627            f.field("proxies", &self.proxies);
2628        }
2629
2630        if !self.redirect_policy.is_default() {
2631            f.field("redirect_policy", &self.redirect_policy);
2632        }
2633
2634        if self.referer {
2635            f.field("referer", &true);
2636        }
2637
2638        f.field("default_headers", &self.headers);
2639
2640        if self.http1_title_case_headers {
2641            f.field("http1_title_case_headers", &true);
2642        }
2643
2644        if self.http1_allow_obsolete_multiline_headers_in_responses {
2645            f.field("http1_allow_obsolete_multiline_headers_in_responses", &true);
2646        }
2647
2648        if self.http1_ignore_invalid_headers_in_responses {
2649            f.field("http1_ignore_invalid_headers_in_responses", &true);
2650        }
2651
2652        if self.http1_allow_spaces_after_header_name_in_responses {
2653            f.field("http1_allow_spaces_after_header_name_in_responses", &true);
2654        }
2655
2656        if matches!(self.http_version_pref, HttpVersionPref::Http1) {
2657            f.field("http1_only", &true);
2658        }
2659
2660        #[cfg(feature = "http2")]
2661        if matches!(self.http_version_pref, HttpVersionPref::Http2) {
2662            f.field("http2_prior_knowledge", &true);
2663        }
2664
2665        if let Some(ref d) = self.connect_timeout {
2666            f.field("connect_timeout", d);
2667        }
2668
2669        if let Some(ref d) = self.timeout {
2670            f.field("timeout", d);
2671        }
2672
2673        if let Some(ref v) = self.local_address {
2674            f.field("local_address", v);
2675        }
2676
2677        #[cfg(any(
2678            target_os = "android",
2679            target_os = "fuchsia",
2680            target_os = "illumos",
2681            target_os = "ios",
2682            target_os = "linux",
2683            target_os = "macos",
2684            target_os = "solaris",
2685            target_os = "tvos",
2686            target_os = "visionos",
2687            target_os = "watchos",
2688        ))]
2689        if let Some(ref v) = self.interface {
2690            f.field("interface", v);
2691        }
2692
2693        if self.nodelay {
2694            f.field("tcp_nodelay", &true);
2695        }
2696
2697        #[cfg(feature = "__tls")]
2698        {
2699            if !self.hostname_verification {
2700                f.field("danger_accept_invalid_hostnames", &true);
2701            }
2702        }
2703
2704        #[cfg(feature = "__tls")]
2705        {
2706            if !self.certs_verification {
2707                f.field("danger_accept_invalid_certs", &true);
2708            }
2709
2710            if let Some(ref min_tls_version) = self.min_tls_version {
2711                f.field("min_tls_version", min_tls_version);
2712            }
2713
2714            if let Some(ref max_tls_version) = self.max_tls_version {
2715                f.field("max_tls_version", max_tls_version);
2716            }
2717
2718            f.field("tls_sni", &self.tls_sni);
2719
2720            f.field("tls_info", &self.tls_info);
2721        }
2722
2723        #[cfg(all(feature = "default-tls", feature = "__rustls"))]
2724        {
2725            f.field("tls_backend", &self.tls);
2726        }
2727
2728        if !self.dns_overrides.is_empty() {
2729            f.field("dns_overrides", &self.dns_overrides);
2730        }
2731
2732        #[cfg(feature = "http3")]
2733        {
2734            if self.tls_enable_early_data {
2735                f.field("tls_enable_early_data", &true);
2736            }
2737        }
2738    }
2739}
2740
2741struct ClientRef {
2742    accepts: Accepts,
2743    #[cfg(feature = "cookies")]
2744    cookie_store: Option<Arc<dyn cookie::CookieStore>>,
2745    headers: HeaderMap,
2746    hyper: FollowRedirect<HyperService, TowerRedirectPolicy>,
2747    #[cfg(feature = "http3")]
2748    h3_client: Option<FollowRedirect<H3Client, TowerRedirectPolicy>>,
2749    referer: bool,
2750    request_timeout: RequestConfig<RequestTimeout>,
2751    read_timeout: Option<Duration>,
2752    proxies: Arc<Vec<ProxyMatcher>>,
2753    proxies_maybe_http_auth: bool,
2754    proxies_maybe_http_custom_headers: bool,
2755    https_only: bool,
2756    redirect_policy_desc: Option<String>,
2757}
2758
2759impl ClientRef {
2760    fn fmt_fields(&self, f: &mut fmt::DebugStruct<'_, '_>) {
2761        // Instead of deriving Debug, only print fields when their output
2762        // would provide relevant or interesting data.
2763
2764        #[cfg(feature = "cookies")]
2765        {
2766            if let Some(_) = self.cookie_store {
2767                f.field("cookie_store", &true);
2768            }
2769        }
2770
2771        f.field("accepts", &self.accepts);
2772
2773        if !self.proxies.is_empty() {
2774            f.field("proxies", &self.proxies);
2775        }
2776
2777        if let Some(s) = &self.redirect_policy_desc {
2778            f.field("redirect_policy", s);
2779        }
2780
2781        if self.referer {
2782            f.field("referer", &true);
2783        }
2784
2785        f.field("default_headers", &self.headers);
2786
2787        self.request_timeout.fmt_as_field(f);
2788
2789        if let Some(ref d) = self.read_timeout {
2790            f.field("read_timeout", d);
2791        }
2792    }
2793}
2794
2795pin_project! {
2796    pub struct Pending {
2797        #[pin]
2798        inner: PendingInner,
2799    }
2800}
2801
2802enum PendingInner {
2803    Request(PendingRequest),
2804    Error(Option<crate::Error>),
2805}
2806
2807pin_project! {
2808    struct PendingRequest {
2809        method: Method,
2810        url: Url,
2811        headers: HeaderMap,
2812        body: Option<Option<Bytes>>,
2813
2814        retry_count: usize,
2815
2816        client: Arc<ClientRef>,
2817
2818        #[pin]
2819        in_flight: ResponseFuture,
2820        #[pin]
2821        total_timeout: Option<Pin<Box<Sleep>>>,
2822        #[pin]
2823        read_timeout_fut: Option<Pin<Box<Sleep>>>,
2824        read_timeout: Option<Duration>,
2825    }
2826}
2827
2828enum ResponseFuture {
2829    Default(tower_http::follow_redirect::ResponseFuture<HyperService, Body, TowerRedirectPolicy>),
2830    #[cfg(feature = "http3")]
2831    H3(tower_http::follow_redirect::ResponseFuture<H3Client, Body, TowerRedirectPolicy>),
2832}
2833
2834impl PendingRequest {
2835    fn in_flight(self: Pin<&mut Self>) -> Pin<&mut ResponseFuture> {
2836        self.project().in_flight
2837    }
2838
2839    fn total_timeout(self: Pin<&mut Self>) -> Pin<&mut Option<Pin<Box<Sleep>>>> {
2840        self.project().total_timeout
2841    }
2842
2843    fn read_timeout(self: Pin<&mut Self>) -> Pin<&mut Option<Pin<Box<Sleep>>>> {
2844        self.project().read_timeout_fut
2845    }
2846
2847    #[cfg(any(feature = "http2", feature = "http3"))]
2848    fn retry_error(mut self: Pin<&mut Self>, err: &(dyn std::error::Error + 'static)) -> bool {
2849        use log::trace;
2850
2851        if !is_retryable_error(err) {
2852            return false;
2853        }
2854
2855        trace!("can retry {err:?}");
2856
2857        let body = match self.body {
2858            Some(Some(ref body)) => Body::reusable(body.clone()),
2859            Some(None) => {
2860                log::debug!("error was retryable, but body not reusable");
2861                return false;
2862            }
2863            None => Body::empty(),
2864        };
2865
2866        if self.retry_count >= 2 {
2867            trace!("retry count too high");
2868            return false;
2869        }
2870        self.retry_count += 1;
2871
2872        // If it parsed once, it should parse again
2873        let uri = try_uri(&self.url).expect("URL was already validated as URI");
2874
2875        *self.as_mut().in_flight().get_mut() = match *self.as_mut().in_flight().as_ref() {
2876            #[cfg(feature = "http3")]
2877            ResponseFuture::H3(_) => {
2878                let mut req = hyper::Request::builder()
2879                    .method(self.method.clone())
2880                    .uri(uri)
2881                    .body(body)
2882                    .expect("valid request parts");
2883                *req.headers_mut() = self.headers.clone();
2884                let mut h3 = self
2885                    .client
2886                    .h3_client
2887                    .as_ref()
2888                    .expect("H3 client must exists, otherwise we can't have a h3 request here")
2889                    .clone();
2890                ResponseFuture::H3(h3.call(req))
2891            }
2892            _ => {
2893                let mut req = hyper::Request::builder()
2894                    .method(self.method.clone())
2895                    .uri(uri)
2896                    .body(body)
2897                    .expect("valid request parts");
2898                *req.headers_mut() = self.headers.clone();
2899                let mut hyper = self.client.hyper.clone();
2900                ResponseFuture::Default(hyper.call(req))
2901            }
2902        };
2903
2904        true
2905    }
2906}
2907
2908#[cfg(any(feature = "http2", feature = "http3"))]
2909fn is_retryable_error(err: &(dyn std::error::Error + 'static)) -> bool {
2910    // pop the legacy::Error
2911    let err = if let Some(err) = err.source() {
2912        err
2913    } else {
2914        return false;
2915    };
2916
2917    #[cfg(feature = "http3")]
2918    if let Some(cause) = err.source() {
2919        if let Some(err) = cause.downcast_ref::<h3::error::ConnectionError>() {
2920            log::debug!("determining if HTTP/3 error {err} can be retried");
2921            // TODO: Does h3 provide an API for checking the error?
2922            return err.to_string().as_str() == "timeout";
2923        }
2924    }
2925
2926    #[cfg(feature = "http2")]
2927    if let Some(cause) = err.source() {
2928        if let Some(err) = cause.downcast_ref::<h2::Error>() {
2929            // They sent us a graceful shutdown, try with a new connection!
2930            if err.is_go_away() && err.is_remote() && err.reason() == Some(h2::Reason::NO_ERROR) {
2931                return true;
2932            }
2933
2934            // REFUSED_STREAM was sent from the server, which is safe to retry.
2935            // https://www.rfc-editor.org/rfc/rfc9113.html#section-8.7-3.2
2936            if err.is_reset() && err.is_remote() && err.reason() == Some(h2::Reason::REFUSED_STREAM)
2937            {
2938                return true;
2939            }
2940        }
2941    }
2942    false
2943}
2944
2945impl Pending {
2946    pub(super) fn new_err(err: crate::Error) -> Pending {
2947        Pending {
2948            inner: PendingInner::Error(Some(err)),
2949        }
2950    }
2951
2952    fn inner(self: Pin<&mut Self>) -> Pin<&mut PendingInner> {
2953        self.project().inner
2954    }
2955}
2956
2957impl Future for Pending {
2958    type Output = Result<Response, crate::Error>;
2959
2960    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
2961        let inner = self.inner();
2962        match inner.get_mut() {
2963            PendingInner::Request(ref mut req) => Pin::new(req).poll(cx),
2964            PendingInner::Error(ref mut err) => Poll::Ready(Err(err
2965                .take()
2966                .expect("Pending error polled more than once"))),
2967        }
2968    }
2969}
2970
2971impl Future for PendingRequest {
2972    type Output = Result<Response, crate::Error>;
2973
2974    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
2975        if let Some(delay) = self.as_mut().total_timeout().as_mut().as_pin_mut() {
2976            if let Poll::Ready(()) = delay.poll(cx) {
2977                return Poll::Ready(Err(
2978                    crate::error::request(crate::error::TimedOut).with_url(self.url.clone())
2979                ));
2980            }
2981        }
2982
2983        if let Some(delay) = self.as_mut().read_timeout().as_mut().as_pin_mut() {
2984            if let Poll::Ready(()) = delay.poll(cx) {
2985                return Poll::Ready(Err(
2986                    crate::error::request(crate::error::TimedOut).with_url(self.url.clone())
2987                ));
2988            }
2989        }
2990
2991        loop {
2992            let res = match self.as_mut().in_flight().get_mut() {
2993                ResponseFuture::Default(r) => match Pin::new(r).poll(cx) {
2994                    Poll::Ready(Err(e)) => {
2995                        #[cfg(feature = "http2")]
2996                        if e.is_request() {
2997                            if let Some(e) = e.source() {
2998                                if self.as_mut().retry_error(e) {
2999                                    continue;
3000                                }
3001                            }
3002                        }
3003
3004                        return Poll::Ready(Err(e));
3005                    }
3006                    Poll::Ready(Ok(res)) => res.map(super::body::boxed),
3007                    Poll::Pending => return Poll::Pending,
3008                },
3009                #[cfg(feature = "http3")]
3010                ResponseFuture::H3(r) => match Pin::new(r).poll(cx) {
3011                    Poll::Ready(Err(e)) => {
3012                        if self.as_mut().retry_error(&e) {
3013                            continue;
3014                        }
3015                        return Poll::Ready(Err(
3016                            crate::error::request(e).with_url(self.url.clone())
3017                        ));
3018                    }
3019                    Poll::Ready(Ok(res)) => res,
3020                    Poll::Pending => return Poll::Pending,
3021                },
3022            };
3023
3024            #[cfg(feature = "cookies")]
3025            {
3026                if let Some(ref cookie_store) = self.client.cookie_store {
3027                    let mut cookies =
3028                        cookie::extract_response_cookie_headers(res.headers()).peekable();
3029                    if cookies.peek().is_some() {
3030                        cookie_store.set_cookies(&mut cookies, &self.url);
3031                    }
3032                }
3033            }
3034            if let Some(url) = &res
3035                .extensions()
3036                .get::<tower_http::follow_redirect::RequestUri>()
3037            {
3038                self.url = match Url::parse(&url.0.to_string()) {
3039                    Ok(url) => url,
3040                    Err(e) => return Poll::Ready(Err(crate::error::decode(e))),
3041                }
3042            };
3043
3044            let res = Response::new(
3045                res,
3046                self.url.clone(),
3047                self.client.accepts,
3048                self.total_timeout.take(),
3049                self.read_timeout,
3050            );
3051            return Poll::Ready(Ok(res));
3052        }
3053    }
3054}
3055
3056impl fmt::Debug for Pending {
3057    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3058        match self.inner {
3059            PendingInner::Request(ref req) => f
3060                .debug_struct("Pending")
3061                .field("method", &req.method)
3062                .field("url", &req.url)
3063                .finish(),
3064            PendingInner::Error(ref err) => f.debug_struct("Pending").field("error", err).finish(),
3065        }
3066    }
3067}
3068
3069#[cfg(test)]
3070mod tests {
3071    #![cfg(not(feature = "rustls-tls-manual-roots-no-provider"))]
3072
3073    #[tokio::test]
3074    async fn execute_request_rejects_invalid_urls() {
3075        let url_str = "hxxps://www.rust-lang.org/";
3076        let url = url::Url::parse(url_str).unwrap();
3077        let result = crate::get(url.clone()).await;
3078
3079        assert!(result.is_err());
3080        let err = result.err().unwrap();
3081        assert!(err.is_builder());
3082        assert_eq!(url_str, err.url().unwrap().as_str());
3083    }
3084
3085    /// https://github.com/seanmonstar/reqwest/issues/668
3086    #[tokio::test]
3087    async fn execute_request_rejects_invalid_hostname() {
3088        let url_str = "https://{{hostname}}/";
3089        let url = url::Url::parse(url_str).unwrap();
3090        let result = crate::get(url.clone()).await;
3091
3092        assert!(result.is_err());
3093        let err = result.err().unwrap();
3094        assert!(err.is_builder());
3095        assert_eq!(url_str, err.url().unwrap().as_str());
3096    }
3097}