Skip to main content

reqwest/async_impl/
client.rs

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