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