reqwest/async_impl/
client.rs

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