reqwest/async_impl/
client.rs

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