reqwest/async_impl/
client.rs

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