Skip to main content

reqwest/async_impl/
client.rs

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