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