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