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