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        #[cfg(feature = "gzip")]
1027        let hyper = hyper.gzip(config.accepts.gzip);
1028        #[cfg(feature = "brotli")]
1029        let hyper = hyper.br(config.accepts.brotli);
1030        #[cfg(feature = "zstd")]
1031        let hyper = hyper.zstd(config.accepts.zstd);
1032        #[cfg(feature = "deflate")]
1033        let hyper = hyper.deflate(config.accepts.deflate);
1034
1035        Ok(Client {
1036            inner: Arc::new(ClientRef {
1037                accepts: config.accepts,
1038                #[cfg(feature = "cookies")]
1039                cookie_store: config.cookie_store.clone(),
1040                // Use match instead of map since config is partially moved,
1041                // and it cannot be used in closure
1042                #[cfg(feature = "http3")]
1043                h3_client: match h3_connector {
1044                    Some(h3_connector) => {
1045                        let h3_service = H3Client::new(h3_connector, config.pool_idle_timeout);
1046                        let svc = tower::retry::Retry::new(retry_policy, h3_service);
1047                        #[cfg(feature = "cookies")]
1048                        let svc = CookieService::new(svc, config.cookie_store);
1049                        let svc = FollowRedirect::with_policy(svc, redirect_policy);
1050                        #[cfg(any(
1051                            feature = "gzip",
1052                            feature = "brotli",
1053                            feature = "zstd",
1054                            feature = "deflate"
1055                        ))]
1056                        let svc = Decompression::new(svc);
1057                        #[cfg(feature = "gzip")]
1058                        let svc = svc.gzip(config.accepts.gzip);
1059                        #[cfg(feature = "brotli")]
1060                        let svc = svc.br(config.accepts.brotli);
1061                        #[cfg(feature = "zstd")]
1062                        let svc = svc.zstd(config.accepts.zstd);
1063                        #[cfg(feature = "deflate")]
1064                        let svc = svc.deflate(config.accepts.deflate);
1065                        Some(svc)
1066                    }
1067                    None => None,
1068                },
1069                headers: config.headers,
1070                referer: config.referer,
1071                read_timeout: config.read_timeout,
1072                total_timeout: RequestConfig::new(config.timeout),
1073                hyper,
1074                proxies,
1075                proxies_maybe_http_auth,
1076                proxies_maybe_http_custom_headers,
1077                https_only: config.https_only,
1078                redirect_policy_desc,
1079            }),
1080        })
1081    }
1082
1083    // Higher-level options
1084
1085    /// Sets the `User-Agent` header to be used by this client.
1086    ///
1087    /// # Example
1088    ///
1089    /// ```rust
1090    /// # async fn doc() -> Result<(), reqwest::Error> {
1091    /// // Name your user agent after your app?
1092    /// static APP_USER_AGENT: &str = concat!(
1093    ///     env!("CARGO_PKG_NAME"),
1094    ///     "/",
1095    ///     env!("CARGO_PKG_VERSION"),
1096    /// );
1097    ///
1098    /// let client = reqwest::Client::builder()
1099    ///     .user_agent(APP_USER_AGENT)
1100    ///     .build()?;
1101    /// let res = client.get("https://www.rust-lang.org").send().await?;
1102    /// # Ok(())
1103    /// # }
1104    /// ```
1105    pub fn user_agent<V>(mut self, value: V) -> ClientBuilder
1106    where
1107        V: TryInto<HeaderValue>,
1108        V::Error: Into<http::Error>,
1109    {
1110        match value.try_into() {
1111            Ok(value) => {
1112                self.config.headers.insert(USER_AGENT, value);
1113            }
1114            Err(e) => {
1115                self.config.error = Some(crate::error::builder(e.into()));
1116            }
1117        };
1118        self
1119    }
1120    /// Sets the default headers for every request.
1121    ///
1122    /// # Example
1123    ///
1124    /// ```rust
1125    /// use reqwest::header;
1126    /// # async fn doc() -> Result<(), reqwest::Error> {
1127    /// let mut headers = header::HeaderMap::new();
1128    /// headers.insert("X-MY-HEADER", header::HeaderValue::from_static("value"));
1129    ///
1130    /// // Consider marking security-sensitive headers with `set_sensitive`.
1131    /// let mut auth_value = header::HeaderValue::from_static("secret");
1132    /// auth_value.set_sensitive(true);
1133    /// headers.insert(header::AUTHORIZATION, auth_value);
1134    ///
1135    /// // get a client builder
1136    /// let client = reqwest::Client::builder()
1137    ///     .default_headers(headers)
1138    ///     .build()?;
1139    /// let res = client.get("https://www.rust-lang.org").send().await?;
1140    /// # Ok(())
1141    /// # }
1142    /// ```
1143    pub fn default_headers(mut self, headers: HeaderMap) -> ClientBuilder {
1144        for (key, value) in headers.iter() {
1145            self.config.headers.insert(key, value.clone());
1146        }
1147        self
1148    }
1149
1150    /// Enable a persistent cookie store for the client.
1151    ///
1152    /// Cookies received in responses will be preserved and included in
1153    /// additional requests.
1154    ///
1155    /// By default, no cookie store is used. Enabling the cookie store
1156    /// with `cookie_store(true)` will set the store to a default implementation.
1157    /// It is **not** necessary to call [cookie_store(true)](crate::ClientBuilder::cookie_store) if [cookie_provider(my_cookie_store)](crate::ClientBuilder::cookie_provider)
1158    /// is used; calling [cookie_store(true)](crate::ClientBuilder::cookie_store) _after_ [cookie_provider(my_cookie_store)](crate::ClientBuilder::cookie_provider) will result
1159    /// in the provided `my_cookie_store` being **overridden** with a default implementation.
1160    ///
1161    /// # Optional
1162    ///
1163    /// This requires the optional `cookies` feature to be enabled.
1164    #[cfg(feature = "cookies")]
1165    #[cfg_attr(docsrs, doc(cfg(feature = "cookies")))]
1166    pub fn cookie_store(mut self, enable: bool) -> ClientBuilder {
1167        if enable {
1168            self.cookie_provider(Arc::new(cookie::Jar::default()))
1169        } else {
1170            self.config.cookie_store = None;
1171            self
1172        }
1173    }
1174
1175    /// Set the persistent cookie store for the client.
1176    ///
1177    /// Cookies received in responses will be passed to this store, and
1178    /// additional requests will query this store for cookies.
1179    ///
1180    /// By default, no cookie store is used. It is **not** necessary to also call
1181    /// [cookie_store(true)](crate::ClientBuilder::cookie_store) if [cookie_provider(my_cookie_store)](crate::ClientBuilder::cookie_provider) is used; calling
1182    /// [cookie_store(true)](crate::ClientBuilder::cookie_store) _after_ [cookie_provider(my_cookie_store)](crate::ClientBuilder::cookie_provider) will result
1183    /// in the provided `my_cookie_store` being **overridden** with a default implementation.
1184    ///
1185    /// # Optional
1186    ///
1187    /// This requires the optional `cookies` feature to be enabled.
1188    #[cfg(feature = "cookies")]
1189    #[cfg_attr(docsrs, doc(cfg(feature = "cookies")))]
1190    pub fn cookie_provider<C: cookie::CookieStore + 'static>(
1191        mut self,
1192        cookie_store: Arc<C>,
1193    ) -> ClientBuilder {
1194        self.config.cookie_store = Some(cookie_store as _);
1195        self
1196    }
1197
1198    /// Enable auto gzip decompression by checking the `Content-Encoding` response header.
1199    ///
1200    /// If auto gzip decompression is turned on:
1201    ///
1202    /// - When sending a request and if the request's headers do not already contain
1203    ///   an `Accept-Encoding` **and** `Range` values, the `Accept-Encoding` header is set to `gzip`.
1204    ///   The request body is **not** automatically compressed.
1205    /// - When receiving a response, if its headers contain a `Content-Encoding` value of
1206    ///   `gzip`, both `Content-Encoding` and `Content-Length` are removed from the
1207    ///   headers' set. The response body is automatically decompressed.
1208    ///
1209    /// If the `gzip` feature is turned on, the default option is enabled.
1210    ///
1211    /// # Optional
1212    ///
1213    /// This requires the optional `gzip` feature to be enabled
1214    #[cfg(feature = "gzip")]
1215    #[cfg_attr(docsrs, doc(cfg(feature = "gzip")))]
1216    pub fn gzip(mut self, enable: bool) -> ClientBuilder {
1217        self.config.accepts.gzip = enable;
1218        self
1219    }
1220
1221    /// Enable auto brotli decompression by checking the `Content-Encoding` response header.
1222    ///
1223    /// If auto brotli decompression is turned on:
1224    ///
1225    /// - When sending a request and if the request's headers do not already contain
1226    ///   an `Accept-Encoding` **and** `Range` values, the `Accept-Encoding` header is set to `br`.
1227    ///   The request body is **not** automatically compressed.
1228    /// - When receiving a response, if its headers contain a `Content-Encoding` value of
1229    ///   `br`, both `Content-Encoding` and `Content-Length` are removed from the
1230    ///   headers' set. The response body is automatically decompressed.
1231    ///
1232    /// If the `brotli` feature is turned on, the default option is enabled.
1233    ///
1234    /// # Optional
1235    ///
1236    /// This requires the optional `brotli` feature to be enabled
1237    #[cfg(feature = "brotli")]
1238    #[cfg_attr(docsrs, doc(cfg(feature = "brotli")))]
1239    pub fn brotli(mut self, enable: bool) -> ClientBuilder {
1240        self.config.accepts.brotli = enable;
1241        self
1242    }
1243
1244    /// Enable auto zstd decompression by checking the `Content-Encoding` response header.
1245    ///
1246    /// If auto zstd decompression is turned on:
1247    ///
1248    /// - When sending a request and if the request's headers do not already contain
1249    ///   an `Accept-Encoding` **and** `Range` values, the `Accept-Encoding` header is set to `zstd`.
1250    ///   The request body is **not** automatically compressed.
1251    /// - When receiving a response, if its headers contain a `Content-Encoding` value of
1252    ///   `zstd`, both `Content-Encoding` and `Content-Length` are removed from the
1253    ///   headers' set. The response body is automatically decompressed.
1254    ///
1255    /// If the `zstd` feature is turned on, the default option is enabled.
1256    ///
1257    /// # Optional
1258    ///
1259    /// This requires the optional `zstd` feature to be enabled
1260    #[cfg(feature = "zstd")]
1261    #[cfg_attr(docsrs, doc(cfg(feature = "zstd")))]
1262    pub fn zstd(mut self, enable: bool) -> ClientBuilder {
1263        self.config.accepts.zstd = enable;
1264        self
1265    }
1266
1267    /// Enable auto deflate decompression by checking the `Content-Encoding` response header.
1268    ///
1269    /// If auto deflate decompression is turned on:
1270    ///
1271    /// - When sending a request and if the request's headers do not already contain
1272    ///   an `Accept-Encoding` **and** `Range` values, the `Accept-Encoding` header is set to `deflate`.
1273    ///   The request body is **not** automatically compressed.
1274    /// - When receiving a response, if it's headers contain a `Content-Encoding` value that
1275    ///   equals to `deflate`, both values `Content-Encoding` and `Content-Length` are removed from the
1276    ///   headers' set. The response body is automatically decompressed.
1277    ///
1278    /// If the `deflate` feature is turned on, the default option is enabled.
1279    ///
1280    /// # Optional
1281    ///
1282    /// This requires the optional `deflate` feature to be enabled
1283    #[cfg(feature = "deflate")]
1284    #[cfg_attr(docsrs, doc(cfg(feature = "deflate")))]
1285    pub fn deflate(mut self, enable: bool) -> ClientBuilder {
1286        self.config.accepts.deflate = enable;
1287        self
1288    }
1289
1290    /// Disable auto response body gzip decompression.
1291    ///
1292    /// This method exists even if the optional `gzip` feature is not enabled.
1293    /// This can be used to ensure a `Client` doesn't use gzip decompression
1294    /// even if another dependency were to enable the optional `gzip` feature.
1295    pub fn no_gzip(self) -> ClientBuilder {
1296        #[cfg(feature = "gzip")]
1297        {
1298            self.gzip(false)
1299        }
1300
1301        #[cfg(not(feature = "gzip"))]
1302        {
1303            self
1304        }
1305    }
1306
1307    /// Disable auto response body brotli decompression.
1308    ///
1309    /// This method exists even if the optional `brotli` feature is not enabled.
1310    /// This can be used to ensure a `Client` doesn't use brotli decompression
1311    /// even if another dependency were to enable the optional `brotli` feature.
1312    pub fn no_brotli(self) -> ClientBuilder {
1313        #[cfg(feature = "brotli")]
1314        {
1315            self.brotli(false)
1316        }
1317
1318        #[cfg(not(feature = "brotli"))]
1319        {
1320            self
1321        }
1322    }
1323
1324    /// Disable auto response body zstd decompression.
1325    ///
1326    /// This method exists even if the optional `zstd` feature is not enabled.
1327    /// This can be used to ensure a `Client` doesn't use zstd decompression
1328    /// even if another dependency were to enable the optional `zstd` feature.
1329    pub fn no_zstd(self) -> ClientBuilder {
1330        #[cfg(feature = "zstd")]
1331        {
1332            self.zstd(false)
1333        }
1334
1335        #[cfg(not(feature = "zstd"))]
1336        {
1337            self
1338        }
1339    }
1340
1341    /// Disable auto response body deflate decompression.
1342    ///
1343    /// This method exists even if the optional `deflate` feature is not enabled.
1344    /// This can be used to ensure a `Client` doesn't use deflate decompression
1345    /// even if another dependency were to enable the optional `deflate` feature.
1346    pub fn no_deflate(self) -> ClientBuilder {
1347        #[cfg(feature = "deflate")]
1348        {
1349            self.deflate(false)
1350        }
1351
1352        #[cfg(not(feature = "deflate"))]
1353        {
1354            self
1355        }
1356    }
1357
1358    // Redirect options
1359
1360    /// Set a `RedirectPolicy` for this client.
1361    ///
1362    /// Default will follow redirects up to a maximum of 10.
1363    pub fn redirect(mut self, policy: redirect::Policy) -> ClientBuilder {
1364        self.config.redirect_policy = policy;
1365        self
1366    }
1367
1368    /// Enable or disable automatic setting of the `Referer` header.
1369    ///
1370    /// Default is `true`.
1371    pub fn referer(mut self, enable: bool) -> ClientBuilder {
1372        self.config.referer = enable;
1373        self
1374    }
1375
1376    // Retry options
1377
1378    /// Set a request retry policy.
1379    ///
1380    /// Default behavior is to retry protocol NACKs.
1381    // XXX: accept an `impl retry::IntoPolicy` instead?
1382    pub fn retry(mut self, policy: crate::retry::Builder) -> ClientBuilder {
1383        self.config.retry_policy = policy;
1384        self
1385    }
1386
1387    // Proxy options
1388
1389    /// Add a `Proxy` to the list of proxies the `Client` will use.
1390    ///
1391    /// # Note
1392    ///
1393    /// Adding a proxy will disable the automatic usage of the "system" proxy.
1394    pub fn proxy(mut self, proxy: Proxy) -> ClientBuilder {
1395        self.config.proxies.push(proxy.into_matcher());
1396        self.config.auto_sys_proxy = false;
1397        self
1398    }
1399
1400    /// Clear all `Proxies`, so `Client` will use no proxy anymore.
1401    ///
1402    /// # Note
1403    /// To add a proxy exclusion list, use [crate::proxy::Proxy::no_proxy()]
1404    /// on all desired proxies instead.
1405    ///
1406    /// This also disables the automatic usage of the "system" proxy.
1407    pub fn no_proxy(mut self) -> ClientBuilder {
1408        self.config.proxies.clear();
1409        self.config.auto_sys_proxy = false;
1410        self
1411    }
1412
1413    // Timeout options
1414
1415    /// Enables a total request timeout.
1416    ///
1417    /// The timeout is applied from when the request starts connecting until the
1418    /// response body has finished. Also considered a total deadline.
1419    ///
1420    /// Default is no timeout.
1421    pub fn timeout(mut self, timeout: Duration) -> ClientBuilder {
1422        self.config.timeout = Some(timeout);
1423        self
1424    }
1425
1426    /// Enables a read timeout.
1427    ///
1428    /// The timeout applies to each read operation, and resets after a
1429    /// successful read. This is more appropriate for detecting stalled
1430    /// connections when the size isn't known beforehand.
1431    ///
1432    /// Default is no timeout.
1433    pub fn read_timeout(mut self, timeout: Duration) -> ClientBuilder {
1434        self.config.read_timeout = Some(timeout);
1435        self
1436    }
1437
1438    /// Set a timeout for only the connect phase of a `Client`.
1439    ///
1440    /// Default is `None`.
1441    ///
1442    /// # Note
1443    ///
1444    /// This **requires** the futures be executed in a tokio runtime with
1445    /// a tokio timer enabled.
1446    pub fn connect_timeout(mut self, timeout: Duration) -> ClientBuilder {
1447        self.config.connect_timeout = Some(timeout);
1448        self
1449    }
1450
1451    /// Set whether connections should emit verbose logs.
1452    ///
1453    /// Enabling this option will emit [log][] messages at the `TRACE` level
1454    /// for read and write operations on connections.
1455    ///
1456    /// [log]: https://crates.io/crates/log
1457    pub fn connection_verbose(mut self, verbose: bool) -> ClientBuilder {
1458        self.config.connection_verbose = verbose;
1459        self
1460    }
1461
1462    // HTTP options
1463
1464    /// Set an optional timeout for idle sockets being kept-alive.
1465    ///
1466    /// Pass `None` to disable timeout.
1467    ///
1468    /// Default is 90 seconds.
1469    pub fn pool_idle_timeout<D>(mut self, val: D) -> ClientBuilder
1470    where
1471        D: Into<Option<Duration>>,
1472    {
1473        self.config.pool_idle_timeout = val.into();
1474        self
1475    }
1476
1477    /// Sets the maximum idle connection per host allowed in the pool.
1478    ///
1479    /// Default is `usize::MAX` (no limit).
1480    pub fn pool_max_idle_per_host(mut self, max: usize) -> ClientBuilder {
1481        self.config.pool_max_idle_per_host = max;
1482        self
1483    }
1484
1485    /// Send headers as title case instead of lowercase.
1486    pub fn http1_title_case_headers(mut self) -> ClientBuilder {
1487        self.config.http1_title_case_headers = true;
1488        self
1489    }
1490
1491    /// Set whether HTTP/1 connections will accept obsolete line folding for
1492    /// header values.
1493    ///
1494    /// Newline codepoints (`\r` and `\n`) will be transformed to spaces when
1495    /// parsing.
1496    pub fn http1_allow_obsolete_multiline_headers_in_responses(
1497        mut self,
1498        value: bool,
1499    ) -> ClientBuilder {
1500        self.config
1501            .http1_allow_obsolete_multiline_headers_in_responses = value;
1502        self
1503    }
1504
1505    /// Sets whether invalid header lines should be silently ignored in HTTP/1 responses.
1506    pub fn http1_ignore_invalid_headers_in_responses(mut self, value: bool) -> ClientBuilder {
1507        self.config.http1_ignore_invalid_headers_in_responses = value;
1508        self
1509    }
1510
1511    /// Set whether HTTP/1 connections will accept spaces between header
1512    /// names and the colon that follow them in responses.
1513    ///
1514    /// Newline codepoints (`\r` and `\n`) will be transformed to spaces when
1515    /// parsing.
1516    pub fn http1_allow_spaces_after_header_name_in_responses(
1517        mut self,
1518        value: bool,
1519    ) -> ClientBuilder {
1520        self.config
1521            .http1_allow_spaces_after_header_name_in_responses = value;
1522        self
1523    }
1524
1525    /// Only use HTTP/1.
1526    pub fn http1_only(mut self) -> ClientBuilder {
1527        self.config.http_version_pref = HttpVersionPref::Http1;
1528        self
1529    }
1530
1531    /// Allow HTTP/0.9 responses
1532    pub fn http09_responses(mut self) -> ClientBuilder {
1533        self.config.http09_responses = true;
1534        self
1535    }
1536
1537    /// Only use HTTP/2.
1538    #[cfg(feature = "http2")]
1539    #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
1540    pub fn http2_prior_knowledge(mut self) -> ClientBuilder {
1541        self.config.http_version_pref = HttpVersionPref::Http2;
1542        self
1543    }
1544
1545    /// Only use HTTP/3.
1546    #[cfg(feature = "http3")]
1547    #[cfg_attr(docsrs, doc(cfg(all(reqwest_unstable, feature = "http3",))))]
1548    pub fn http3_prior_knowledge(mut self) -> ClientBuilder {
1549        self.config.http_version_pref = HttpVersionPref::Http3;
1550        self
1551    }
1552
1553    /// Sets the `SETTINGS_INITIAL_WINDOW_SIZE` option for HTTP2 stream-level flow control.
1554    ///
1555    /// Default is currently 65,535 but may change internally to optimize for common uses.
1556    #[cfg(feature = "http2")]
1557    #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
1558    pub fn http2_initial_stream_window_size(mut self, sz: impl Into<Option<u32>>) -> ClientBuilder {
1559        self.config.http2_initial_stream_window_size = sz.into();
1560        self
1561    }
1562
1563    /// Sets the max connection-level flow control for HTTP2
1564    ///
1565    /// Default is currently 65,535 but may change internally to optimize for common uses.
1566    #[cfg(feature = "http2")]
1567    #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
1568    pub fn http2_initial_connection_window_size(
1569        mut self,
1570        sz: impl Into<Option<u32>>,
1571    ) -> ClientBuilder {
1572        self.config.http2_initial_connection_window_size = sz.into();
1573        self
1574    }
1575
1576    /// Sets whether to use an adaptive flow control.
1577    ///
1578    /// Enabling this will override the limits set in `http2_initial_stream_window_size` and
1579    /// `http2_initial_connection_window_size`.
1580    #[cfg(feature = "http2")]
1581    #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
1582    pub fn http2_adaptive_window(mut self, enabled: bool) -> ClientBuilder {
1583        self.config.http2_adaptive_window = enabled;
1584        self
1585    }
1586
1587    /// Sets the maximum frame size to use for HTTP2.
1588    ///
1589    /// Default is currently 16,384 but may change internally to optimize for common uses.
1590    #[cfg(feature = "http2")]
1591    #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
1592    pub fn http2_max_frame_size(mut self, sz: impl Into<Option<u32>>) -> ClientBuilder {
1593        self.config.http2_max_frame_size = sz.into();
1594        self
1595    }
1596
1597    /// Sets the maximum size of received header frames for HTTP2.
1598    ///
1599    /// Default is currently 16KB, but can change.
1600    #[cfg(feature = "http2")]
1601    #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
1602    pub fn http2_max_header_list_size(mut self, max_header_size_bytes: u32) -> ClientBuilder {
1603        self.config.http2_max_header_list_size = Some(max_header_size_bytes);
1604        self
1605    }
1606
1607    /// Sets an interval for HTTP2 Ping frames should be sent to keep a connection alive.
1608    ///
1609    /// Pass `None` to disable HTTP2 keep-alive.
1610    /// Default is currently disabled.
1611    #[cfg(feature = "http2")]
1612    #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
1613    pub fn http2_keep_alive_interval(
1614        mut self,
1615        interval: impl Into<Option<Duration>>,
1616    ) -> ClientBuilder {
1617        self.config.http2_keep_alive_interval = interval.into();
1618        self
1619    }
1620
1621    /// Sets a timeout for receiving an acknowledgement of the keep-alive ping.
1622    ///
1623    /// If the ping is not acknowledged within the timeout, the connection will be closed.
1624    /// Does nothing if `http2_keep_alive_interval` is disabled.
1625    /// Default is currently disabled.
1626    #[cfg(feature = "http2")]
1627    #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
1628    pub fn http2_keep_alive_timeout(mut self, timeout: Duration) -> ClientBuilder {
1629        self.config.http2_keep_alive_timeout = Some(timeout);
1630        self
1631    }
1632
1633    /// Sets whether HTTP2 keep-alive should apply while the connection is idle.
1634    ///
1635    /// If disabled, keep-alive pings are only sent while there are open request/responses streams.
1636    /// If enabled, pings are also sent when no streams are active.
1637    /// Does nothing if `http2_keep_alive_interval` is disabled.
1638    /// Default is `false`.
1639    #[cfg(feature = "http2")]
1640    #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
1641    pub fn http2_keep_alive_while_idle(mut self, enabled: bool) -> ClientBuilder {
1642        self.config.http2_keep_alive_while_idle = enabled;
1643        self
1644    }
1645
1646    // TCP options
1647
1648    /// Set whether sockets have `TCP_NODELAY` enabled.
1649    ///
1650    /// Default is `true`.
1651    pub fn tcp_nodelay(mut self, enabled: bool) -> ClientBuilder {
1652        self.config.nodelay = enabled;
1653        self
1654    }
1655
1656    /// Bind to a local IP Address.
1657    ///
1658    /// # Example
1659    ///
1660    /// ```
1661    /// # fn doc() -> Result<(), reqwest::Error> {
1662    /// use std::net::IpAddr;
1663    /// let local_addr = IpAddr::from([12, 4, 1, 8]);
1664    /// let client = reqwest::Client::builder()
1665    ///     .local_address(local_addr)
1666    ///     .build()?;
1667    /// # Ok(())
1668    /// # }
1669    /// ```
1670    pub fn local_address<T>(mut self, addr: T) -> ClientBuilder
1671    where
1672        T: Into<Option<IpAddr>>,
1673    {
1674        self.config.local_address = addr.into();
1675        self
1676    }
1677
1678    /// Bind connections only on the specified network interface.
1679    ///
1680    /// This option is only available on the following operating systems:
1681    ///
1682    /// - Android
1683    /// - Fuchsia
1684    /// - Linux,
1685    /// - macOS and macOS-like systems (iOS, tvOS, watchOS and visionOS)
1686    /// - Solaris and illumos
1687    ///
1688    /// On Android, Linux, and Fuchsia, this uses the
1689    /// [`SO_BINDTODEVICE`][man-7-socket] socket option. On macOS and macOS-like
1690    /// systems, Solaris, and illumos, this instead uses the [`IP_BOUND_IF` and
1691    /// `IPV6_BOUND_IF`][man-7p-ip] socket options (as appropriate).
1692    ///
1693    /// Note that connections will fail if the provided interface name is not a
1694    /// network interface that currently exists when a connection is established.
1695    ///
1696    /// # Example
1697    ///
1698    /// ```
1699    /// # fn doc() -> Result<(), reqwest::Error> {
1700    /// let interface = "lo";
1701    /// let client = reqwest::Client::builder()
1702    ///     .interface(interface)
1703    ///     .build()?;
1704    /// # Ok(())
1705    /// # }
1706    /// ```
1707    ///
1708    /// [man-7-socket]: https://man7.org/linux/man-pages/man7/socket.7.html
1709    /// [man-7p-ip]: https://docs.oracle.com/cd/E86824_01/html/E54777/ip-7p.html
1710    #[cfg(any(
1711        target_os = "android",
1712        target_os = "fuchsia",
1713        target_os = "illumos",
1714        target_os = "ios",
1715        target_os = "linux",
1716        target_os = "macos",
1717        target_os = "solaris",
1718        target_os = "tvos",
1719        target_os = "visionos",
1720        target_os = "watchos",
1721    ))]
1722    pub fn interface(mut self, interface: &str) -> ClientBuilder {
1723        self.config.interface = Some(interface.to_string());
1724        self
1725    }
1726
1727    /// Set that all sockets have `SO_KEEPALIVE` set with the supplied duration.
1728    ///
1729    /// If `None`, the option will not be set.
1730    pub fn tcp_keepalive<D>(mut self, val: D) -> ClientBuilder
1731    where
1732        D: Into<Option<Duration>>,
1733    {
1734        self.config.tcp_keepalive = val.into();
1735        self
1736    }
1737
1738    /// Set that all sockets have `SO_KEEPALIVE` set with the supplied interval.
1739    ///
1740    /// If `None`, the option will not be set.
1741    pub fn tcp_keepalive_interval<D>(mut self, val: D) -> ClientBuilder
1742    where
1743        D: Into<Option<Duration>>,
1744    {
1745        self.config.tcp_keepalive_interval = val.into();
1746        self
1747    }
1748
1749    /// Set that all sockets have `SO_KEEPALIVE` set with the supplied retry count.
1750    ///
1751    /// If `None`, the option will not be set.
1752    pub fn tcp_keepalive_retries<C>(mut self, retries: C) -> ClientBuilder
1753    where
1754        C: Into<Option<u32>>,
1755    {
1756        self.config.tcp_keepalive_retries = retries.into();
1757        self
1758    }
1759
1760    /// Set that all sockets have `TCP_USER_TIMEOUT` set with the supplied duration.
1761    ///
1762    /// This option controls how long transmitted data may remain unacknowledged before
1763    /// the connection is force-closed.
1764    ///
1765    /// If `None`, the option will not be set.
1766    #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
1767    pub fn tcp_user_timeout<D>(mut self, val: D) -> ClientBuilder
1768    where
1769        D: Into<Option<Duration>>,
1770    {
1771        self.config.tcp_user_timeout = val.into();
1772        self
1773    }
1774
1775    // Alt Transports
1776
1777    /// Set that all connections will use this Unix socket.
1778    ///
1779    /// If a request URI uses the `https` scheme, TLS will still be used over
1780    /// the Unix socket.
1781    ///
1782    /// # Note
1783    ///
1784    /// This option is not compatible with any of the TCP or Proxy options.
1785    /// Setting this will ignore all those options previously set.
1786    ///
1787    /// Likewise, DNS resolution will not be done on the domain name.
1788    #[cfg(unix)]
1789    pub fn unix_socket(mut self, path: impl UnixSocketProvider) -> ClientBuilder {
1790        self.config.unix_socket = Some(path.reqwest_uds_path(crate::connect::uds::Internal).into());
1791        self
1792    }
1793
1794    // TLS options
1795
1796    /// Add a custom root certificate.
1797    ///
1798    /// This can be used to connect to a server that has a self-signed
1799    /// certificate for example.
1800    ///
1801    /// # Optional
1802    ///
1803    /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
1804    /// feature to be enabled.
1805    #[cfg(feature = "__tls")]
1806    #[cfg_attr(
1807        docsrs,
1808        doc(cfg(any(
1809            feature = "default-tls",
1810            feature = "native-tls",
1811            feature = "rustls-tls"
1812        )))
1813    )]
1814    pub fn add_root_certificate(mut self, cert: Certificate) -> ClientBuilder {
1815        self.config.root_certs.push(cert);
1816        self
1817    }
1818
1819    /// Add a certificate revocation list.
1820    ///
1821    ///
1822    /// # Optional
1823    ///
1824    /// This requires the `rustls-tls(-...)` Cargo feature enabled.
1825    #[cfg(feature = "__rustls")]
1826    #[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls")))]
1827    pub fn add_crl(mut self, crl: CertificateRevocationList) -> ClientBuilder {
1828        self.config.crls.push(crl);
1829        self
1830    }
1831
1832    /// Add multiple certificate revocation lists.
1833    ///
1834    ///
1835    /// # Optional
1836    ///
1837    /// This requires the `rustls-tls(-...)` Cargo feature enabled.
1838    #[cfg(feature = "__rustls")]
1839    #[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls")))]
1840    pub fn add_crls(
1841        mut self,
1842        crls: impl IntoIterator<Item = CertificateRevocationList>,
1843    ) -> ClientBuilder {
1844        self.config.crls.extend(crls);
1845        self
1846    }
1847
1848    /// Controls the use of built-in/preloaded certificates during certificate validation.
1849    ///
1850    /// Defaults to `true` -- built-in system certs will be used.
1851    ///
1852    /// # Bulk Option
1853    ///
1854    /// If this value is `true`, _all_ enabled system certs configured with Cargo
1855    /// features will be loaded.
1856    ///
1857    /// You can set this to `false`, and enable only a specific source with
1858    /// individual methods. Do that will prevent other sources from being loaded
1859    /// even if their feature Cargo feature is enabled.
1860    ///
1861    /// # Optional
1862    ///
1863    /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
1864    /// feature to be enabled.
1865    #[cfg(feature = "__tls")]
1866    #[cfg_attr(
1867        docsrs,
1868        doc(cfg(any(
1869            feature = "default-tls",
1870            feature = "native-tls",
1871            feature = "rustls-tls"
1872        )))
1873    )]
1874    pub fn tls_built_in_root_certs(mut self, tls_built_in_root_certs: bool) -> ClientBuilder {
1875        self.config.tls_built_in_root_certs = tls_built_in_root_certs;
1876
1877        #[cfg(feature = "rustls-tls-webpki-roots-no-provider")]
1878        {
1879            self.config.tls_built_in_certs_webpki = tls_built_in_root_certs;
1880        }
1881
1882        #[cfg(feature = "rustls-tls-native-roots-no-provider")]
1883        {
1884            self.config.tls_built_in_certs_native = tls_built_in_root_certs;
1885        }
1886
1887        self
1888    }
1889
1890    /// Sets whether to load webpki root certs with rustls.
1891    ///
1892    /// If the feature is enabled, this value is `true` by default.
1893    #[cfg(feature = "rustls-tls-webpki-roots-no-provider")]
1894    #[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls-webpki-roots-no-provider")))]
1895    pub fn tls_built_in_webpki_certs(mut self, enabled: bool) -> ClientBuilder {
1896        self.config.tls_built_in_certs_webpki = enabled;
1897        self
1898    }
1899
1900    /// Sets whether to load native root certs with rustls.
1901    ///
1902    /// If the feature is enabled, this value is `true` by default.
1903    #[cfg(feature = "rustls-tls-native-roots-no-provider")]
1904    #[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls-native-roots-no-provider")))]
1905    pub fn tls_built_in_native_certs(mut self, enabled: bool) -> ClientBuilder {
1906        self.config.tls_built_in_certs_native = enabled;
1907        self
1908    }
1909
1910    /// Sets the identity to be used for client certificate authentication.
1911    ///
1912    /// # Optional
1913    ///
1914    /// This requires the optional `native-tls` or `rustls-tls(-...)` feature to be
1915    /// enabled.
1916    #[cfg(any(feature = "native-tls", feature = "__rustls"))]
1917    #[cfg_attr(docsrs, doc(cfg(any(feature = "native-tls", feature = "rustls-tls"))))]
1918    pub fn identity(mut self, identity: Identity) -> ClientBuilder {
1919        self.config.identity = Some(identity);
1920        self
1921    }
1922
1923    /// Controls the use of hostname verification.
1924    ///
1925    /// Defaults to `false`.
1926    ///
1927    /// # Warning
1928    ///
1929    /// You should think very carefully before you use this method. If
1930    /// hostname verification is not used, any valid certificate for any
1931    /// site will be trusted for use from any other. This introduces a
1932    /// significant vulnerability to man-in-the-middle attacks.
1933    ///
1934    /// # Optional
1935    ///
1936    /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
1937    /// feature to be enabled.
1938    #[cfg(feature = "__tls")]
1939    #[cfg_attr(
1940        docsrs,
1941        doc(cfg(any(
1942            feature = "default-tls",
1943            feature = "native-tls",
1944            feature = "rustls-tls"
1945        )))
1946    )]
1947    pub fn danger_accept_invalid_hostnames(
1948        mut self,
1949        accept_invalid_hostname: bool,
1950    ) -> ClientBuilder {
1951        self.config.hostname_verification = !accept_invalid_hostname;
1952        self
1953    }
1954
1955    /// Controls the use of certificate validation.
1956    ///
1957    /// Defaults to `false`.
1958    ///
1959    /// # Warning
1960    ///
1961    /// You should think very carefully before using this method. If
1962    /// invalid certificates are trusted, *any* certificate for *any* site
1963    /// will be trusted for use. This includes expired certificates. This
1964    /// introduces significant vulnerabilities, and should only be used
1965    /// as a last resort.
1966    ///
1967    /// # Optional
1968    ///
1969    /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
1970    /// feature to be enabled.
1971    #[cfg(feature = "__tls")]
1972    #[cfg_attr(
1973        docsrs,
1974        doc(cfg(any(
1975            feature = "default-tls",
1976            feature = "native-tls",
1977            feature = "rustls-tls"
1978        )))
1979    )]
1980    pub fn danger_accept_invalid_certs(mut self, accept_invalid_certs: bool) -> ClientBuilder {
1981        self.config.certs_verification = !accept_invalid_certs;
1982        self
1983    }
1984
1985    /// Controls the use of TLS server name indication.
1986    ///
1987    /// Defaults to `true`.
1988    ///
1989    /// # Optional
1990    ///
1991    /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
1992    /// feature to be enabled.
1993    #[cfg(feature = "__tls")]
1994    #[cfg_attr(
1995        docsrs,
1996        doc(cfg(any(
1997            feature = "default-tls",
1998            feature = "native-tls",
1999            feature = "rustls-tls"
2000        )))
2001    )]
2002    pub fn tls_sni(mut self, tls_sni: bool) -> ClientBuilder {
2003        self.config.tls_sni = tls_sni;
2004        self
2005    }
2006
2007    /// Set the minimum required TLS version for connections.
2008    ///
2009    /// By default, the TLS backend's own default is used.
2010    ///
2011    /// # Errors
2012    ///
2013    /// A value of `tls::Version::TLS_1_3` will cause an error with the
2014    /// `native-tls`/`default-tls` backend. This does not mean the version
2015    /// isn't supported, just that it can't be set as a minimum due to
2016    /// technical limitations.
2017    ///
2018    /// # Optional
2019    ///
2020    /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
2021    /// feature to be enabled.
2022    #[cfg(feature = "__tls")]
2023    #[cfg_attr(
2024        docsrs,
2025        doc(cfg(any(
2026            feature = "default-tls",
2027            feature = "native-tls",
2028            feature = "rustls-tls"
2029        )))
2030    )]
2031    pub fn min_tls_version(mut self, version: tls::Version) -> ClientBuilder {
2032        self.config.min_tls_version = Some(version);
2033        self
2034    }
2035
2036    /// Set the maximum allowed TLS version for connections.
2037    ///
2038    /// By default, there's no maximum.
2039    ///
2040    /// # Errors
2041    ///
2042    /// A value of `tls::Version::TLS_1_3` will cause an error with the
2043    /// `native-tls`/`default-tls` backend. This does not mean the version
2044    /// isn't supported, just that it can't be set as a maximum due to
2045    /// technical limitations.
2046    ///
2047    /// Cannot set a maximum outside the protocol versions supported by
2048    /// `rustls` with the `rustls-tls` backend.
2049    ///
2050    /// # Optional
2051    ///
2052    /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
2053    /// feature to be enabled.
2054    #[cfg(feature = "__tls")]
2055    #[cfg_attr(
2056        docsrs,
2057        doc(cfg(any(
2058            feature = "default-tls",
2059            feature = "native-tls",
2060            feature = "rustls-tls"
2061        )))
2062    )]
2063    pub fn max_tls_version(mut self, version: tls::Version) -> ClientBuilder {
2064        self.config.max_tls_version = Some(version);
2065        self
2066    }
2067
2068    /// Force using the native TLS backend.
2069    ///
2070    /// Since multiple TLS backends can be optionally enabled, this option will
2071    /// force the `native-tls` backend to be used for this `Client`.
2072    ///
2073    /// # Optional
2074    ///
2075    /// This requires the optional `native-tls` feature to be enabled.
2076    #[cfg(feature = "native-tls")]
2077    #[cfg_attr(docsrs, doc(cfg(feature = "native-tls")))]
2078    pub fn use_native_tls(mut self) -> ClientBuilder {
2079        self.config.tls = TlsBackend::Default;
2080        self
2081    }
2082
2083    /// Force using the Rustls TLS backend.
2084    ///
2085    /// Since multiple TLS backends can be optionally enabled, this option will
2086    /// force the `rustls` backend to be used for this `Client`.
2087    ///
2088    /// # Optional
2089    ///
2090    /// This requires the optional `rustls-tls(-...)` feature to be enabled.
2091    #[cfg(feature = "__rustls")]
2092    #[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls")))]
2093    pub fn use_rustls_tls(mut self) -> ClientBuilder {
2094        self.config.tls = TlsBackend::Rustls;
2095        self
2096    }
2097
2098    /// Use a preconfigured TLS backend.
2099    ///
2100    /// If the passed `Any` argument is not a TLS backend that reqwest
2101    /// understands, the `ClientBuilder` will error when calling `build`.
2102    ///
2103    /// # Advanced
2104    ///
2105    /// This is an advanced option, and can be somewhat brittle. Usage requires
2106    /// keeping the preconfigured TLS argument version in sync with reqwest,
2107    /// since version mismatches will result in an "unknown" TLS backend.
2108    ///
2109    /// If possible, it's preferable to use the methods on `ClientBuilder`
2110    /// to configure reqwest's TLS.
2111    ///
2112    /// # Optional
2113    ///
2114    /// This requires one of the optional features `native-tls` or
2115    /// `rustls-tls(-...)` to be enabled.
2116    #[cfg(any(feature = "native-tls", feature = "__rustls",))]
2117    #[cfg_attr(docsrs, doc(cfg(any(feature = "native-tls", feature = "rustls-tls"))))]
2118    pub fn use_preconfigured_tls(mut self, tls: impl Any) -> ClientBuilder {
2119        let mut tls = Some(tls);
2120        #[cfg(feature = "native-tls")]
2121        {
2122            if let Some(conn) = (&mut tls as &mut dyn Any).downcast_mut::<Option<TlsConnector>>() {
2123                let tls = conn.take().expect("is definitely Some");
2124                let tls = crate::tls::TlsBackend::BuiltNativeTls(tls);
2125                self.config.tls = tls;
2126                return self;
2127            }
2128        }
2129        #[cfg(feature = "__rustls")]
2130        {
2131            if let Some(conn) =
2132                (&mut tls as &mut dyn Any).downcast_mut::<Option<rustls::ClientConfig>>()
2133            {
2134                let tls = conn.take().expect("is definitely Some");
2135                let tls = crate::tls::TlsBackend::BuiltRustls(tls);
2136                self.config.tls = tls;
2137                return self;
2138            }
2139        }
2140
2141        // Otherwise, we don't recognize the TLS backend!
2142        self.config.tls = crate::tls::TlsBackend::UnknownPreconfigured;
2143        self
2144    }
2145
2146    /// Add TLS information as `TlsInfo` extension to responses.
2147    ///
2148    /// # Optional
2149    ///
2150    /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
2151    /// feature to be enabled.
2152    #[cfg(feature = "__tls")]
2153    #[cfg_attr(
2154        docsrs,
2155        doc(cfg(any(
2156            feature = "default-tls",
2157            feature = "native-tls",
2158            feature = "rustls-tls"
2159        )))
2160    )]
2161    pub fn tls_info(mut self, tls_info: bool) -> ClientBuilder {
2162        self.config.tls_info = tls_info;
2163        self
2164    }
2165
2166    /// Restrict the Client to be used with HTTPS only requests.
2167    ///
2168    /// Defaults to false.
2169    pub fn https_only(mut self, enabled: bool) -> ClientBuilder {
2170        self.config.https_only = enabled;
2171        self
2172    }
2173
2174    #[doc(hidden)]
2175    #[cfg(feature = "hickory-dns")]
2176    #[cfg_attr(docsrs, doc(cfg(feature = "hickory-dns")))]
2177    #[deprecated(note = "use `hickory_dns` instead")]
2178    pub fn trust_dns(mut self, enable: bool) -> ClientBuilder {
2179        self.config.hickory_dns = enable;
2180        self
2181    }
2182
2183    /// Enables the [hickory-dns](hickory_resolver) async resolver instead of a default threadpool
2184    /// using `getaddrinfo`.
2185    ///
2186    /// If the `hickory-dns` feature is turned on, the default option is enabled.
2187    ///
2188    /// # Optional
2189    ///
2190    /// This requires the optional `hickory-dns` feature to be enabled
2191    ///
2192    /// # Warning
2193    ///
2194    /// The hickory resolver does not work exactly the same, or on all the platforms
2195    /// that the default resolver does
2196    #[cfg(feature = "hickory-dns")]
2197    #[cfg_attr(docsrs, doc(cfg(feature = "hickory-dns")))]
2198    pub fn hickory_dns(mut self, enable: bool) -> ClientBuilder {
2199        self.config.hickory_dns = enable;
2200        self
2201    }
2202
2203    #[doc(hidden)]
2204    #[deprecated(note = "use `no_hickory_dns` instead")]
2205    pub fn no_trust_dns(self) -> ClientBuilder {
2206        self.no_hickory_dns()
2207    }
2208
2209    /// Disables the hickory-dns async resolver.
2210    ///
2211    /// This method exists even if the optional `hickory-dns` feature is not enabled.
2212    /// This can be used to ensure a `Client` doesn't use the hickory-dns async resolver
2213    /// even if another dependency were to enable the optional `hickory-dns` feature.
2214    pub fn no_hickory_dns(self) -> ClientBuilder {
2215        #[cfg(feature = "hickory-dns")]
2216        {
2217            self.hickory_dns(false)
2218        }
2219
2220        #[cfg(not(feature = "hickory-dns"))]
2221        {
2222            self
2223        }
2224    }
2225
2226    /// Override DNS resolution for specific domains to a particular IP address.
2227    ///
2228    /// Set the port to `0` to use the conventional port for the given scheme (e.g. 80 for http).
2229    /// Ports in the URL itself will always be used instead of the port in the overridden addr.
2230    pub fn resolve(self, domain: &str, addr: SocketAddr) -> ClientBuilder {
2231        self.resolve_to_addrs(domain, &[addr])
2232    }
2233
2234    /// Override DNS resolution for specific domains to particular IP addresses.
2235    ///
2236    /// Set the port to `0` to use the conventional port for the given scheme (e.g. 80 for http).
2237    /// Ports in the URL itself will always be used instead of the port in the overridden addr.
2238    pub fn resolve_to_addrs(mut self, domain: &str, addrs: &[SocketAddr]) -> ClientBuilder {
2239        self.config
2240            .dns_overrides
2241            .insert(domain.to_ascii_lowercase(), addrs.to_vec());
2242        self
2243    }
2244
2245    /// Override the DNS resolver implementation.
2246    ///
2247    /// Pass an `Arc` wrapping a type implementing `Resolve`.
2248    /// Overrides for specific names passed to `resolve` and `resolve_to_addrs` will
2249    /// still be applied on top of this resolver.
2250    pub fn dns_resolver<R: Resolve + 'static>(mut self, resolver: Arc<R>) -> ClientBuilder {
2251        self.config.dns_resolver = Some(resolver as _);
2252        self
2253    }
2254
2255    /// Override the DNS resolver implementation.
2256    ///
2257    /// Overrides for specific names passed to `resolve` and `resolve_to_addrs` will
2258    /// still be applied on top of this resolver.
2259    ///
2260    /// This method will replace `dns_resolver` in the next breaking change.
2261    pub fn dns_resolver2<R>(mut self, resolver: R) -> ClientBuilder
2262    where
2263        R: crate::dns::resolve::IntoResolve,
2264    {
2265        self.config.dns_resolver = Some(resolver.into_resolve());
2266        self
2267    }
2268
2269    /// Whether to send data on the first flight ("early data") in TLS 1.3 handshakes
2270    /// for HTTP/3 connections.
2271    ///
2272    /// The default is false.
2273    #[cfg(feature = "http3")]
2274    #[cfg_attr(docsrs, doc(cfg(all(reqwest_unstable, feature = "http3",))))]
2275    pub fn tls_early_data(mut self, enabled: bool) -> ClientBuilder {
2276        self.config.tls_enable_early_data = enabled;
2277        self
2278    }
2279
2280    /// Maximum duration of inactivity to accept before timing out the QUIC connection.
2281    ///
2282    /// Please see docs in [`TransportConfig`] in [`quinn`].
2283    ///
2284    /// [`TransportConfig`]: https://docs.rs/quinn/latest/quinn/struct.TransportConfig.html
2285    #[cfg(feature = "http3")]
2286    #[cfg_attr(docsrs, doc(cfg(all(reqwest_unstable, feature = "http3",))))]
2287    pub fn http3_max_idle_timeout(mut self, value: Duration) -> ClientBuilder {
2288        self.config.quic_max_idle_timeout = Some(value);
2289        self
2290    }
2291
2292    /// Maximum number of bytes the peer may transmit without acknowledgement on any one stream
2293    /// before becoming blocked.
2294    ///
2295    /// Please see docs in [`TransportConfig`] in [`quinn`].
2296    ///
2297    /// [`TransportConfig`]: https://docs.rs/quinn/latest/quinn/struct.TransportConfig.html
2298    ///
2299    /// # Panics
2300    ///
2301    /// Panics if the value is over 2^62.
2302    #[cfg(feature = "http3")]
2303    #[cfg_attr(docsrs, doc(cfg(all(reqwest_unstable, feature = "http3",))))]
2304    pub fn http3_stream_receive_window(mut self, value: u64) -> ClientBuilder {
2305        self.config.quic_stream_receive_window = Some(value.try_into().unwrap());
2306        self
2307    }
2308
2309    /// Maximum number of bytes the peer may transmit across all streams of a connection before
2310    /// becoming blocked.
2311    ///
2312    /// Please see docs in [`TransportConfig`] in [`quinn`].
2313    ///
2314    /// [`TransportConfig`]: https://docs.rs/quinn/latest/quinn/struct.TransportConfig.html
2315    ///
2316    /// # Panics
2317    ///
2318    /// Panics if the value is over 2^62.
2319    #[cfg(feature = "http3")]
2320    #[cfg_attr(docsrs, doc(cfg(all(reqwest_unstable, feature = "http3",))))]
2321    pub fn http3_conn_receive_window(mut self, value: u64) -> ClientBuilder {
2322        self.config.quic_receive_window = Some(value.try_into().unwrap());
2323        self
2324    }
2325
2326    /// Maximum number of bytes to transmit to a peer without acknowledgment
2327    ///
2328    /// Please see docs in [`TransportConfig`] in [`quinn`].
2329    ///
2330    /// [`TransportConfig`]: https://docs.rs/quinn/latest/quinn/struct.TransportConfig.html
2331    #[cfg(feature = "http3")]
2332    #[cfg_attr(docsrs, doc(cfg(all(reqwest_unstable, feature = "http3",))))]
2333    pub fn http3_send_window(mut self, value: u64) -> ClientBuilder {
2334        self.config.quic_send_window = Some(value);
2335        self
2336    }
2337
2338    /// Override the default congestion control algorithm to use [BBR]
2339    ///
2340    /// The current default congestion control algorithm is [CUBIC]. This method overrides the
2341    /// default.
2342    ///
2343    /// [BBR]: https://datatracker.ietf.org/doc/html/draft-ietf-ccwg-bbr
2344    /// [CUBIC]: https://datatracker.ietf.org/doc/html/rfc8312
2345    #[cfg(feature = "http3")]
2346    #[cfg_attr(docsrs, doc(cfg(all(reqwest_unstable, feature = "http3",))))]
2347    pub fn http3_congestion_bbr(mut self) -> ClientBuilder {
2348        self.config.quic_congestion_bbr = true;
2349        self
2350    }
2351
2352    /// Set the maximum HTTP/3 header size this client is willing to accept.
2353    ///
2354    /// See [header size constraints] section of the specification for details.
2355    ///
2356    /// [header size constraints]: https://www.rfc-editor.org/rfc/rfc9114.html#name-header-size-constraints
2357    ///
2358    /// Please see docs in [`Builder`] in [`h3`].
2359    ///
2360    /// [`Builder`]: https://docs.rs/h3/latest/h3/client/struct.Builder.html#method.max_field_section_size
2361    #[cfg(feature = "http3")]
2362    #[cfg_attr(docsrs, doc(cfg(all(reqwest_unstable, feature = "http3",))))]
2363    pub fn http3_max_field_section_size(mut self, value: u64) -> ClientBuilder {
2364        self.config.h3_max_field_section_size = Some(value.try_into().unwrap());
2365        self
2366    }
2367
2368    /// Enable whether to send HTTP/3 protocol grease on the connections.
2369    ///
2370    /// HTTP/3 uses the concept of "grease"
2371    ///
2372    /// to prevent potential interoperability issues in the future.
2373    /// In HTTP/3, the concept of grease is used to ensure that the protocol can evolve
2374    /// and accommodate future changes without breaking existing implementations.
2375    ///
2376    /// Please see docs in [`Builder`] in [`h3`].
2377    ///
2378    /// [`Builder`]: https://docs.rs/h3/latest/h3/client/struct.Builder.html#method.send_grease
2379    #[cfg(feature = "http3")]
2380    #[cfg_attr(docsrs, doc(cfg(all(reqwest_unstable, feature = "http3",))))]
2381    pub fn http3_send_grease(mut self, enabled: bool) -> ClientBuilder {
2382        self.config.h3_send_grease = Some(enabled);
2383        self
2384    }
2385
2386    /// Adds a new Tower [`Layer`](https://docs.rs/tower/latest/tower/trait.Layer.html) to the
2387    /// base connector [`Service`](https://docs.rs/tower/latest/tower/trait.Service.html) which
2388    /// is responsible for connection establishment.
2389    ///
2390    /// Each subsequent invocation of this function will wrap previous layers.
2391    ///
2392    /// If configured, the `connect_timeout` will be the outermost layer.
2393    ///
2394    /// Example usage:
2395    /// ```
2396    /// use std::time::Duration;
2397    ///
2398    /// # #[cfg(not(feature = "rustls-tls-no-provider"))]
2399    /// let client = reqwest::Client::builder()
2400    ///                      // resolved to outermost layer, meaning while we are waiting on concurrency limit
2401    ///                      .connect_timeout(Duration::from_millis(200))
2402    ///                      // underneath the concurrency check, so only after concurrency limit lets us through
2403    ///                      .connector_layer(tower::timeout::TimeoutLayer::new(Duration::from_millis(50)))
2404    ///                      .connector_layer(tower::limit::concurrency::ConcurrencyLimitLayer::new(2))
2405    ///                      .build()
2406    ///                      .unwrap();
2407    /// ```
2408    ///
2409    pub fn connector_layer<L>(mut self, layer: L) -> ClientBuilder
2410    where
2411        L: Layer<BoxedConnectorService> + Clone + Send + Sync + 'static,
2412        L::Service:
2413            Service<Unnameable, Response = Conn, Error = BoxError> + Clone + Send + Sync + 'static,
2414        <L::Service as Service<Unnameable>>::Future: Send + 'static,
2415    {
2416        let layer = BoxCloneSyncServiceLayer::new(layer);
2417
2418        self.config.connector_layers.push(layer);
2419
2420        self
2421    }
2422}
2423
2424type HyperClient = hyper_util::client::legacy::Client<Connector, super::Body>;
2425
2426impl Default for Client {
2427    fn default() -> Self {
2428        Self::new()
2429    }
2430}
2431
2432impl Client {
2433    /// Constructs a new `Client`.
2434    ///
2435    /// # Panics
2436    ///
2437    /// This method panics if a TLS backend cannot be initialized, or the resolver
2438    /// cannot load the system configuration.
2439    ///
2440    /// Use `Client::builder()` if you wish to handle the failure as an `Error`
2441    /// instead of panicking.
2442    pub fn new() -> Client {
2443        ClientBuilder::new().build().expect("Client::new()")
2444    }
2445
2446    /// Creates a `ClientBuilder` to configure a `Client`.
2447    ///
2448    /// This is the same as `ClientBuilder::new()`.
2449    pub fn builder() -> ClientBuilder {
2450        ClientBuilder::new()
2451    }
2452
2453    /// Convenience method to make a `GET` request to a URL.
2454    ///
2455    /// # Errors
2456    ///
2457    /// This method fails whenever the supplied `Url` cannot be parsed.
2458    pub fn get<U: IntoUrl>(&self, url: U) -> RequestBuilder {
2459        self.request(Method::GET, url)
2460    }
2461
2462    /// Convenience method to make a `POST` request to a URL.
2463    ///
2464    /// # Errors
2465    ///
2466    /// This method fails whenever the supplied `Url` cannot be parsed.
2467    pub fn post<U: IntoUrl>(&self, url: U) -> RequestBuilder {
2468        self.request(Method::POST, url)
2469    }
2470
2471    /// Convenience method to make a `PUT` request to a URL.
2472    ///
2473    /// # Errors
2474    ///
2475    /// This method fails whenever the supplied `Url` cannot be parsed.
2476    pub fn put<U: IntoUrl>(&self, url: U) -> RequestBuilder {
2477        self.request(Method::PUT, url)
2478    }
2479
2480    /// Convenience method to make a `PATCH` request to a URL.
2481    ///
2482    /// # Errors
2483    ///
2484    /// This method fails whenever the supplied `Url` cannot be parsed.
2485    pub fn patch<U: IntoUrl>(&self, url: U) -> RequestBuilder {
2486        self.request(Method::PATCH, url)
2487    }
2488
2489    /// Convenience method to make a `DELETE` request to a URL.
2490    ///
2491    /// # Errors
2492    ///
2493    /// This method fails whenever the supplied `Url` cannot be parsed.
2494    pub fn delete<U: IntoUrl>(&self, url: U) -> RequestBuilder {
2495        self.request(Method::DELETE, url)
2496    }
2497
2498    /// Convenience method to make a `HEAD` request to a URL.
2499    ///
2500    /// # Errors
2501    ///
2502    /// This method fails whenever the supplied `Url` cannot be parsed.
2503    pub fn head<U: IntoUrl>(&self, url: U) -> RequestBuilder {
2504        self.request(Method::HEAD, url)
2505    }
2506
2507    /// Start building a `Request` with the `Method` and `Url`.
2508    ///
2509    /// Returns a `RequestBuilder`, which will allow setting headers and
2510    /// the request body before sending.
2511    ///
2512    /// # Errors
2513    ///
2514    /// This method fails whenever the supplied `Url` cannot be parsed.
2515    pub fn request<U: IntoUrl>(&self, method: Method, url: U) -> RequestBuilder {
2516        let req = url.into_url().map(move |url| Request::new(method, url));
2517        RequestBuilder::new(self.clone(), req)
2518    }
2519
2520    /// Executes a `Request`.
2521    ///
2522    /// A `Request` can be built manually with `Request::new()` or obtained
2523    /// from a RequestBuilder with `RequestBuilder::build()`.
2524    ///
2525    /// You should prefer to use the `RequestBuilder` and
2526    /// `RequestBuilder::send()`.
2527    ///
2528    /// # Errors
2529    ///
2530    /// This method fails if there was an error while sending request,
2531    /// redirect loop was detected or redirect limit was exhausted.
2532    pub fn execute(
2533        &self,
2534        request: Request,
2535    ) -> impl Future<Output = Result<Response, crate::Error>> {
2536        self.execute_request(request)
2537    }
2538
2539    pub(super) fn execute_request(&self, req: Request) -> Pending {
2540        let (method, url, mut headers, body, version, extensions) = req.pieces();
2541        if url.scheme() != "http" && url.scheme() != "https" {
2542            return Pending::new_err(error::url_bad_scheme(url));
2543        }
2544
2545        // check if we're in https_only mode and check the scheme of the current URL
2546        if self.inner.https_only && url.scheme() != "https" {
2547            return Pending::new_err(error::url_bad_scheme(url));
2548        }
2549
2550        // insert default headers in the request headers
2551        // without overwriting already appended headers.
2552        for (key, value) in &self.inner.headers {
2553            if let Entry::Vacant(entry) = headers.entry(key) {
2554                entry.insert(value.clone());
2555            }
2556        }
2557
2558        let uri = match try_uri(&url) {
2559            Ok(uri) => uri,
2560            _ => return Pending::new_err(error::url_invalid_uri(url)),
2561        };
2562
2563        let body = body.unwrap_or_else(Body::empty);
2564
2565        self.proxy_auth(&uri, &mut headers);
2566        self.proxy_custom_headers(&uri, &mut headers);
2567
2568        let builder = hyper::Request::builder()
2569            .method(method.clone())
2570            .uri(uri)
2571            .version(version);
2572
2573        let in_flight = match version {
2574            #[cfg(feature = "http3")]
2575            http::Version::HTTP_3 if self.inner.h3_client.is_some() => {
2576                let mut req = builder.body(body).expect("valid request parts");
2577                *req.headers_mut() = headers.clone();
2578                let mut h3 = self.inner.h3_client.as_ref().unwrap().clone();
2579                ResponseFuture::H3(h3.call(req))
2580            }
2581            _ => {
2582                let mut req = builder.body(body).expect("valid request parts");
2583                *req.headers_mut() = headers.clone();
2584                let mut hyper = self.inner.hyper.clone();
2585                ResponseFuture::Default(hyper.call(req))
2586            }
2587        };
2588
2589        let total_timeout = self
2590            .inner
2591            .total_timeout
2592            .fetch(&extensions)
2593            .copied()
2594            .map(tokio::time::sleep)
2595            .map(Box::pin);
2596
2597        let read_timeout_fut = self
2598            .inner
2599            .read_timeout
2600            .map(tokio::time::sleep)
2601            .map(Box::pin);
2602
2603        Pending {
2604            inner: PendingInner::Request(Box::pin(PendingRequest {
2605                method,
2606                url,
2607                headers,
2608
2609                client: self.inner.clone(),
2610
2611                in_flight,
2612                total_timeout,
2613                read_timeout_fut,
2614                read_timeout: self.inner.read_timeout,
2615            })),
2616        }
2617    }
2618
2619    fn proxy_auth(&self, dst: &Uri, headers: &mut HeaderMap) {
2620        if !self.inner.proxies_maybe_http_auth {
2621            return;
2622        }
2623
2624        // Only set the header here if the destination scheme is 'http',
2625        // since otherwise, the header will be included in the CONNECT tunnel
2626        // request instead.
2627        if dst.scheme() != Some(&Scheme::HTTP) {
2628            return;
2629        }
2630
2631        if headers.contains_key(PROXY_AUTHORIZATION) {
2632            return;
2633        }
2634
2635        for proxy in self.inner.proxies.iter() {
2636            if let Some(header) = proxy.http_non_tunnel_basic_auth(dst) {
2637                headers.insert(PROXY_AUTHORIZATION, header);
2638                break;
2639            }
2640        }
2641    }
2642
2643    fn proxy_custom_headers(&self, dst: &Uri, headers: &mut HeaderMap) {
2644        if !self.inner.proxies_maybe_http_custom_headers {
2645            return;
2646        }
2647
2648        if dst.scheme() != Some(&Scheme::HTTP) {
2649            return;
2650        }
2651
2652        for proxy in self.inner.proxies.iter() {
2653            if let Some(iter) = proxy.http_non_tunnel_custom_headers(dst) {
2654                iter.iter().for_each(|(key, value)| {
2655                    headers.insert(key, value.clone());
2656                });
2657                break;
2658            }
2659        }
2660    }
2661}
2662
2663impl fmt::Debug for Client {
2664    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2665        let mut builder = f.debug_struct("Client");
2666        self.inner.fmt_fields(&mut builder);
2667        builder.finish()
2668    }
2669}
2670
2671impl tower_service::Service<Request> for Client {
2672    type Response = Response;
2673    type Error = crate::Error;
2674    type Future = Pending;
2675
2676    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
2677        Poll::Ready(Ok(()))
2678    }
2679
2680    fn call(&mut self, req: Request) -> Self::Future {
2681        self.execute_request(req)
2682    }
2683}
2684
2685impl tower_service::Service<Request> for &'_ Client {
2686    type Response = Response;
2687    type Error = crate::Error;
2688    type Future = Pending;
2689
2690    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
2691        Poll::Ready(Ok(()))
2692    }
2693
2694    fn call(&mut self, req: Request) -> Self::Future {
2695        self.execute_request(req)
2696    }
2697}
2698
2699impl fmt::Debug for ClientBuilder {
2700    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2701        let mut builder = f.debug_struct("ClientBuilder");
2702        self.config.fmt_fields(&mut builder);
2703        builder.finish()
2704    }
2705}
2706
2707impl Config {
2708    fn fmt_fields(&self, f: &mut fmt::DebugStruct<'_, '_>) {
2709        // Instead of deriving Debug, only print fields when their output
2710        // would provide relevant or interesting data.
2711
2712        #[cfg(feature = "cookies")]
2713        {
2714            if let Some(_) = self.cookie_store {
2715                f.field("cookie_store", &true);
2716            }
2717        }
2718
2719        f.field("accepts", &self.accepts);
2720
2721        if !self.proxies.is_empty() {
2722            f.field("proxies", &self.proxies);
2723        }
2724
2725        if !self.redirect_policy.is_default() {
2726            f.field("redirect_policy", &self.redirect_policy);
2727        }
2728
2729        if self.referer {
2730            f.field("referer", &true);
2731        }
2732
2733        f.field("default_headers", &self.headers);
2734
2735        if self.http1_title_case_headers {
2736            f.field("http1_title_case_headers", &true);
2737        }
2738
2739        if self.http1_allow_obsolete_multiline_headers_in_responses {
2740            f.field("http1_allow_obsolete_multiline_headers_in_responses", &true);
2741        }
2742
2743        if self.http1_ignore_invalid_headers_in_responses {
2744            f.field("http1_ignore_invalid_headers_in_responses", &true);
2745        }
2746
2747        if self.http1_allow_spaces_after_header_name_in_responses {
2748            f.field("http1_allow_spaces_after_header_name_in_responses", &true);
2749        }
2750
2751        if matches!(self.http_version_pref, HttpVersionPref::Http1) {
2752            f.field("http1_only", &true);
2753        }
2754
2755        #[cfg(feature = "http2")]
2756        if matches!(self.http_version_pref, HttpVersionPref::Http2) {
2757            f.field("http2_prior_knowledge", &true);
2758        }
2759
2760        if let Some(ref d) = self.connect_timeout {
2761            f.field("connect_timeout", d);
2762        }
2763
2764        if let Some(ref d) = self.timeout {
2765            f.field("timeout", d);
2766        }
2767
2768        if let Some(ref v) = self.local_address {
2769            f.field("local_address", v);
2770        }
2771
2772        #[cfg(any(
2773            target_os = "android",
2774            target_os = "fuchsia",
2775            target_os = "illumos",
2776            target_os = "ios",
2777            target_os = "linux",
2778            target_os = "macos",
2779            target_os = "solaris",
2780            target_os = "tvos",
2781            target_os = "visionos",
2782            target_os = "watchos",
2783        ))]
2784        if let Some(ref v) = self.interface {
2785            f.field("interface", v);
2786        }
2787
2788        if self.nodelay {
2789            f.field("tcp_nodelay", &true);
2790        }
2791
2792        #[cfg(feature = "__tls")]
2793        {
2794            if !self.hostname_verification {
2795                f.field("danger_accept_invalid_hostnames", &true);
2796            }
2797        }
2798
2799        #[cfg(feature = "__tls")]
2800        {
2801            if !self.certs_verification {
2802                f.field("danger_accept_invalid_certs", &true);
2803            }
2804
2805            if let Some(ref min_tls_version) = self.min_tls_version {
2806                f.field("min_tls_version", min_tls_version);
2807            }
2808
2809            if let Some(ref max_tls_version) = self.max_tls_version {
2810                f.field("max_tls_version", max_tls_version);
2811            }
2812
2813            f.field("tls_sni", &self.tls_sni);
2814
2815            f.field("tls_info", &self.tls_info);
2816        }
2817
2818        #[cfg(all(feature = "default-tls", feature = "__rustls"))]
2819        {
2820            f.field("tls_backend", &self.tls);
2821        }
2822
2823        if !self.dns_overrides.is_empty() {
2824            f.field("dns_overrides", &self.dns_overrides);
2825        }
2826
2827        #[cfg(feature = "http3")]
2828        {
2829            if self.tls_enable_early_data {
2830                f.field("tls_enable_early_data", &true);
2831            }
2832        }
2833
2834        #[cfg(unix)]
2835        if let Some(ref p) = self.unix_socket {
2836            f.field("unix_socket", p);
2837        }
2838    }
2839}
2840
2841#[cfg(not(feature = "cookies"))]
2842type MaybeCookieService<T> = T;
2843
2844#[cfg(feature = "cookies")]
2845type MaybeCookieService<T> = CookieService<T>;
2846
2847#[cfg(not(any(
2848    feature = "gzip",
2849    feature = "brotli",
2850    feature = "zstd",
2851    feature = "deflate"
2852)))]
2853type MaybeDecompression<T> = T;
2854
2855#[cfg(any(
2856    feature = "gzip",
2857    feature = "brotli",
2858    feature = "zstd",
2859    feature = "deflate"
2860))]
2861type MaybeDecompression<T> = Decompression<T>;
2862
2863type LayeredService<T> = MaybeDecompression<
2864    FollowRedirect<
2865        MaybeCookieService<tower::retry::Retry<crate::retry::Policy, T>>,
2866        TowerRedirectPolicy,
2867    >,
2868>;
2869type LayeredFuture<T> = <LayeredService<T> as Service<http::Request<Body>>>::Future;
2870
2871struct ClientRef {
2872    accepts: Accepts,
2873    #[cfg(feature = "cookies")]
2874    cookie_store: Option<Arc<dyn cookie::CookieStore>>,
2875    headers: HeaderMap,
2876    hyper: LayeredService<HyperService>,
2877    #[cfg(feature = "http3")]
2878    h3_client: Option<LayeredService<H3Client>>,
2879    referer: bool,
2880    total_timeout: RequestConfig<TotalTimeout>,
2881    read_timeout: Option<Duration>,
2882    proxies: Arc<Vec<ProxyMatcher>>,
2883    proxies_maybe_http_auth: bool,
2884    proxies_maybe_http_custom_headers: bool,
2885    https_only: bool,
2886    redirect_policy_desc: Option<String>,
2887}
2888
2889impl ClientRef {
2890    fn fmt_fields(&self, f: &mut fmt::DebugStruct<'_, '_>) {
2891        // Instead of deriving Debug, only print fields when their output
2892        // would provide relevant or interesting data.
2893
2894        #[cfg(feature = "cookies")]
2895        {
2896            if let Some(_) = self.cookie_store {
2897                f.field("cookie_store", &true);
2898            }
2899        }
2900
2901        f.field("accepts", &self.accepts);
2902
2903        if !self.proxies.is_empty() {
2904            f.field("proxies", &self.proxies);
2905        }
2906
2907        if let Some(s) = &self.redirect_policy_desc {
2908            f.field("redirect_policy", s);
2909        }
2910
2911        if self.referer {
2912            f.field("referer", &true);
2913        }
2914
2915        f.field("default_headers", &self.headers);
2916
2917        self.total_timeout.fmt_as_field(f);
2918
2919        if let Some(ref d) = self.read_timeout {
2920            f.field("read_timeout", d);
2921        }
2922    }
2923}
2924
2925pin_project! {
2926    pub struct Pending {
2927        #[pin]
2928        inner: PendingInner,
2929    }
2930}
2931
2932enum PendingInner {
2933    Request(Pin<Box<PendingRequest>>),
2934    Error(Option<crate::Error>),
2935}
2936
2937pin_project! {
2938    struct PendingRequest {
2939        method: Method,
2940        url: Url,
2941        headers: HeaderMap,
2942
2943        client: Arc<ClientRef>,
2944
2945        #[pin]
2946        in_flight: ResponseFuture,
2947        #[pin]
2948        total_timeout: Option<Pin<Box<Sleep>>>,
2949        #[pin]
2950        read_timeout_fut: Option<Pin<Box<Sleep>>>,
2951        read_timeout: Option<Duration>,
2952    }
2953}
2954
2955enum ResponseFuture {
2956    Default(LayeredFuture<HyperService>),
2957    #[cfg(feature = "http3")]
2958    H3(LayeredFuture<H3Client>),
2959}
2960
2961impl PendingRequest {
2962    fn in_flight(self: Pin<&mut Self>) -> Pin<&mut ResponseFuture> {
2963        self.project().in_flight
2964    }
2965
2966    fn total_timeout(self: Pin<&mut Self>) -> Pin<&mut Option<Pin<Box<Sleep>>>> {
2967        self.project().total_timeout
2968    }
2969
2970    fn read_timeout(self: Pin<&mut Self>) -> Pin<&mut Option<Pin<Box<Sleep>>>> {
2971        self.project().read_timeout_fut
2972    }
2973}
2974
2975impl Pending {
2976    pub(super) fn new_err(err: crate::Error) -> Pending {
2977        Pending {
2978            inner: PendingInner::Error(Some(err)),
2979        }
2980    }
2981
2982    fn inner(self: Pin<&mut Self>) -> Pin<&mut PendingInner> {
2983        self.project().inner
2984    }
2985}
2986
2987impl Future for Pending {
2988    type Output = Result<Response, crate::Error>;
2989
2990    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
2991        let inner = self.inner();
2992        match inner.get_mut() {
2993            PendingInner::Request(ref mut req) => Pin::new(req).poll(cx),
2994            PendingInner::Error(ref mut err) => Poll::Ready(Err(err
2995                .take()
2996                .expect("Pending error polled more than once"))),
2997        }
2998    }
2999}
3000
3001impl Future for PendingRequest {
3002    type Output = Result<Response, crate::Error>;
3003
3004    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
3005        if let Some(delay) = self.as_mut().total_timeout().as_mut().as_pin_mut() {
3006            if let Poll::Ready(()) = delay.poll(cx) {
3007                return Poll::Ready(Err(
3008                    crate::error::request(crate::error::TimedOut).with_url(self.url.clone())
3009                ));
3010            }
3011        }
3012
3013        if let Some(delay) = self.as_mut().read_timeout().as_mut().as_pin_mut() {
3014            if let Poll::Ready(()) = delay.poll(cx) {
3015                return Poll::Ready(Err(
3016                    crate::error::request(crate::error::TimedOut).with_url(self.url.clone())
3017                ));
3018            }
3019        }
3020
3021        let res = match self.as_mut().in_flight().get_mut() {
3022            ResponseFuture::Default(r) => match ready!(Pin::new(r).poll(cx)) {
3023                Err(e) => {
3024                    return Poll::Ready(Err(e.if_no_url(|| self.url.clone())));
3025                }
3026                Ok(res) => res.map(super::body::boxed),
3027            },
3028            #[cfg(feature = "http3")]
3029            ResponseFuture::H3(r) => match ready!(Pin::new(r).poll(cx)) {
3030                Err(e) => {
3031                    return Poll::Ready(Err(crate::error::request(e).with_url(self.url.clone())));
3032                }
3033                Ok(res) => res.map(super::body::boxed),
3034            },
3035        };
3036
3037        if let Some(url) = &res
3038            .extensions()
3039            .get::<tower_http::follow_redirect::RequestUri>()
3040        {
3041            self.url = match Url::parse(&url.0.to_string()) {
3042                Ok(url) => url,
3043                Err(e) => return Poll::Ready(Err(crate::error::decode(e))),
3044            }
3045        };
3046
3047        let res = Response::new(
3048            res,
3049            self.url.clone(),
3050            self.total_timeout.take(),
3051            self.read_timeout,
3052        );
3053        Poll::Ready(Ok(res))
3054    }
3055}
3056
3057impl fmt::Debug for Pending {
3058    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3059        match self.inner {
3060            PendingInner::Request(ref req) => f
3061                .debug_struct("Pending")
3062                .field("method", &req.method)
3063                .field("url", &req.url)
3064                .finish(),
3065            PendingInner::Error(ref err) => f.debug_struct("Pending").field("error", err).finish(),
3066        }
3067    }
3068}
3069
3070#[cfg(test)]
3071mod tests {
3072    #![cfg(not(feature = "rustls-tls-manual-roots-no-provider"))]
3073
3074    #[tokio::test]
3075    async fn execute_request_rejects_invalid_urls() {
3076        let url_str = "hxxps://www.rust-lang.org/";
3077        let url = url::Url::parse(url_str).unwrap();
3078        let result = crate::get(url.clone()).await;
3079
3080        assert!(result.is_err());
3081        let err = result.err().unwrap();
3082        assert!(err.is_builder());
3083        assert_eq!(url_str, err.url().unwrap().as_str());
3084    }
3085
3086    /// https://github.com/seanmonstar/reqwest/issues/668
3087    #[tokio::test]
3088    async fn execute_request_rejects_invalid_hostname() {
3089        let url_str = "https://{{hostname}}/";
3090        let url = url::Url::parse(url_str).unwrap();
3091        let result = crate::get(url.clone()).await;
3092
3093        assert!(result.is_err());
3094        let err = result.err().unwrap();
3095        assert!(err.is_builder());
3096        assert_eq!(url_str, err.url().unwrap().as_str());
3097    }
3098
3099    #[test]
3100    fn test_future_size() {
3101        let s = std::mem::size_of::<super::Pending>();
3102        assert!(s < 128, "size_of::<Pending>() == {s}, too big");
3103    }
3104}