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