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