reqwest_tor/async_impl/
client.rs

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