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