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