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