reqwest/async_impl/
client.rs

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