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