reqwest/async_impl/
client.rs

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