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