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