dusks_reqwest/blocking/client.rs
1#[cfg(any(feature = "native-tls", feature = "__rustls",))]
2use std::any::Any;
3use std::convert::TryInto;
4use std::fmt;
5use std::future::Future;
6use std::net::IpAddr;
7use std::net::SocketAddr;
8use std::sync::Arc;
9use std::thread;
10use std::time::Duration;
11
12use http::header::HeaderValue;
13use log::{error, trace};
14use tokio::sync::{mpsc, oneshot};
15
16use super::request::{Request, RequestBuilder};
17use super::response::Response;
18use super::wait;
19use crate::dns::Resolve;
20#[cfg(feature = "__tls")]
21use crate::tls;
22#[cfg(feature = "__tls")]
23use crate::Certificate;
24#[cfg(any(feature = "native-tls", feature = "__rustls"))]
25use crate::Identity;
26use crate::{async_impl, header, redirect, IntoUrl, Method, Proxy};
27
28/// A `Client` to make Requests with.
29///
30/// The Client has various configuration values to tweak, but the defaults
31/// are set to what is usually the most commonly desired value. To configure a
32/// `Client`, use `Client::builder()`.
33///
34/// The `Client` holds a connection pool internally, so it is advised that
35/// you create one and **reuse** it.
36///
37/// # Examples
38///
39/// ```rust
40/// use reqwest::blocking::Client;
41/// #
42/// # fn run() -> Result<(), reqwest::Error> {
43/// let client = Client::new();
44/// let resp = client.get("http://httpbin.org/").send()?;
45/// # drop(resp);
46/// # Ok(())
47/// # }
48///
49/// ```
50#[derive(Clone)]
51pub struct Client {
52 inner: ClientHandle,
53}
54
55/// A `ClientBuilder` can be used to create a `Client` with custom configuration.
56///
57/// # Example
58///
59/// ```
60/// # fn run() -> Result<(), reqwest::Error> {
61/// use std::time::Duration;
62///
63/// let client = reqwest::blocking::Client::builder()
64/// .timeout(Duration::from_secs(10))
65/// .build()?;
66/// # Ok(())
67/// # }
68/// ```
69#[must_use]
70pub struct ClientBuilder {
71 inner: async_impl::ClientBuilder,
72 timeout: Timeout,
73}
74
75impl Default for ClientBuilder {
76 fn default() -> Self {
77 Self::new()
78 }
79}
80
81impl ClientBuilder {
82 /// Constructs a new `ClientBuilder`.
83 ///
84 /// This is the same as `Client::builder()`.
85 pub fn new() -> ClientBuilder {
86 ClientBuilder {
87 inner: async_impl::ClientBuilder::new(),
88 timeout: Timeout::default(),
89 }
90 }
91
92 /// Returns a `Client` that uses this `ClientBuilder` configuration.
93 ///
94 /// # Errors
95 ///
96 /// This method fails if TLS backend cannot be initialized, or the resolver
97 /// cannot load the system configuration.
98 ///
99 /// # Panics
100 ///
101 /// This method panics if called from within an async runtime. See docs on
102 /// [`reqwest::blocking`][crate::blocking] for details.
103 pub fn build(self) -> crate::Result<Client> {
104 ClientHandle::new(self).map(|handle| Client { inner: handle })
105 }
106
107 // Higher-level options
108
109 /// Sets the `User-Agent` header to be used by this client.
110 ///
111 /// # Example
112 ///
113 /// ```rust
114 /// # fn doc() -> Result<(), reqwest::Error> {
115 /// // Name your user agent after your app?
116 /// static APP_USER_AGENT: &str = concat!(
117 /// env!("CARGO_PKG_NAME"),
118 /// "/",
119 /// env!("CARGO_PKG_VERSION"),
120 /// );
121 ///
122 /// let client = reqwest::blocking::Client::builder()
123 /// .user_agent(APP_USER_AGENT)
124 /// .build()?;
125 /// let res = client.get("https://www.rust-lang.org").send()?;
126 /// # Ok(())
127 /// # }
128 /// ```
129 pub fn user_agent<V>(self, value: V) -> ClientBuilder
130 where
131 V: TryInto<HeaderValue>,
132 V::Error: Into<http::Error>,
133 {
134 self.with_inner(move |inner| inner.user_agent(value))
135 }
136
137 /// Sets the default headers for every request.
138 ///
139 /// # Example
140 ///
141 /// ```rust
142 /// use reqwest::header;
143 /// # fn build_client() -> Result<(), reqwest::Error> {
144 /// let mut headers = header::HeaderMap::new();
145 /// headers.insert("X-MY-HEADER", header::HeaderValue::from_static("value"));
146 /// headers.insert(header::AUTHORIZATION, header::HeaderValue::from_static("secret"));
147 ///
148 /// // Consider marking security-sensitive headers with `set_sensitive`.
149 /// let mut auth_value = header::HeaderValue::from_static("secret");
150 /// auth_value.set_sensitive(true);
151 /// headers.insert(header::AUTHORIZATION, auth_value);
152 ///
153 /// // get a client builder
154 /// let client = reqwest::blocking::Client::builder()
155 /// .default_headers(headers)
156 /// .build()?;
157 /// let res = client.get("https://www.rust-lang.org").send()?;
158 /// # Ok(())
159 /// # }
160 /// ```
161 pub fn default_headers(self, headers: header::HeaderMap) -> ClientBuilder {
162 self.with_inner(move |inner| inner.default_headers(headers))
163 }
164
165 /// Enable a persistent cookie store for the client.
166 ///
167 /// Cookies received in responses will be preserved and included in
168 /// additional requests.
169 ///
170 /// By default, no cookie store is used.
171 ///
172 /// # Optional
173 ///
174 /// This requires the optional `cookies` feature to be enabled.
175 #[cfg(feature = "cookies")]
176 #[cfg_attr(docsrs, doc(cfg(feature = "cookies")))]
177 pub fn cookie_store(self, enable: bool) -> ClientBuilder {
178 self.with_inner(|inner| inner.cookie_store(enable))
179 }
180
181 /// Set the persistent cookie store for the client.
182 ///
183 /// Cookies received in responses will be passed to this store, and
184 /// additional requests will query this store for cookies.
185 ///
186 /// By default, no cookie store is used.
187 ///
188 /// # Optional
189 ///
190 /// This requires the optional `cookies` feature to be enabled.
191 #[cfg(feature = "cookies")]
192 #[cfg_attr(docsrs, doc(cfg(feature = "cookies")))]
193 pub fn cookie_provider<C: crate::cookie::CookieStore + 'static>(
194 self,
195 cookie_store: Arc<C>,
196 ) -> ClientBuilder {
197 self.with_inner(|inner| inner.cookie_provider(cookie_store))
198 }
199
200 /// Enable auto gzip decompression by checking the `Content-Encoding` response header.
201 ///
202 /// If auto gzip decompresson is turned on:
203 ///
204 /// - When sending a request and if the request's headers do not already contain
205 /// an `Accept-Encoding` **and** `Range` values, the `Accept-Encoding` header is set to `gzip`.
206 /// The request body is **not** automatically compressed.
207 /// - When receiving a response, if it's headers contain a `Content-Encoding` value that
208 /// equals to `gzip`, both values `Content-Encoding` and `Content-Length` are removed from the
209 /// headers' set. The response body is automatically decompressed.
210 ///
211 /// If the `gzip` feature is turned on, the default option is enabled.
212 ///
213 /// # Optional
214 ///
215 /// This requires the optional `gzip` feature to be enabled
216 #[cfg(feature = "gzip")]
217 #[cfg_attr(docsrs, doc(cfg(feature = "gzip")))]
218 pub fn gzip(self, enable: bool) -> ClientBuilder {
219 self.with_inner(|inner| inner.gzip(enable))
220 }
221
222 /// Enable auto brotli decompression by checking the `Content-Encoding` response header.
223 ///
224 /// If auto brotli decompression is turned on:
225 ///
226 /// - When sending a request and if the request's headers do not already contain
227 /// an `Accept-Encoding` **and** `Range` values, the `Accept-Encoding` header is set to `br`.
228 /// The request body is **not** automatically compressed.
229 /// - When receiving a response, if it's headers contain a `Content-Encoding` value that
230 /// equals to `br`, both values `Content-Encoding` and `Content-Length` are removed from the
231 /// headers' set. The response body is automatically decompressed.
232 ///
233 /// If the `brotli` feature is turned on, the default option is enabled.
234 ///
235 /// # Optional
236 ///
237 /// This requires the optional `brotli` feature to be enabled
238 #[cfg(feature = "brotli")]
239 #[cfg_attr(docsrs, doc(cfg(feature = "brotli")))]
240 pub fn brotli(self, enable: bool) -> ClientBuilder {
241 self.with_inner(|inner| inner.brotli(enable))
242 }
243
244 /// Enable auto zstd decompression by checking the `Content-Encoding` response header.
245 ///
246 /// If auto zstd decompression is turned on:
247 ///
248 /// - When sending a request and if the request's headers do not already contain
249 /// an `Accept-Encoding` **and** `Range` values, the `Accept-Encoding` header is set to `zstd`.
250 /// The request body is **not** automatically compressed.
251 /// - When receiving a response, if its headers contain a `Content-Encoding` value of
252 /// `zstd`, both `Content-Encoding` and `Content-Length` are removed from the
253 /// headers' set. The response body is automatically decompressed.
254 ///
255 /// If the `zstd` feature is turned on, the default option is enabled.
256 ///
257 /// # Optional
258 ///
259 /// This requires the optional `zstd` feature to be enabled
260 #[cfg(feature = "zstd")]
261 #[cfg_attr(docsrs, doc(cfg(feature = "zstd")))]
262 pub fn zstd(self, enable: bool) -> ClientBuilder {
263 self.with_inner(|inner| inner.zstd(enable))
264 }
265
266 /// Enable auto deflate decompression by checking the `Content-Encoding` response header.
267 ///
268 /// If auto deflate decompresson is turned on:
269 ///
270 /// - When sending a request and if the request's headers do not already contain
271 /// an `Accept-Encoding` **and** `Range` values, the `Accept-Encoding` header is set to `deflate`.
272 /// The request body is **not** automatically compressed.
273 /// - When receiving a response, if it's headers contain a `Content-Encoding` value that
274 /// equals to `deflate`, both values `Content-Encoding` and `Content-Length` are removed from the
275 /// headers' set. The response body is automatically decompressed.
276 ///
277 /// If the `deflate` feature is turned on, the default option is enabled.
278 ///
279 /// # Optional
280 ///
281 /// This requires the optional `deflate` feature to be enabled
282 #[cfg(feature = "deflate")]
283 #[cfg_attr(docsrs, doc(cfg(feature = "deflate")))]
284 pub fn deflate(self, enable: bool) -> ClientBuilder {
285 self.with_inner(|inner| inner.deflate(enable))
286 }
287
288 /// Disable auto response body gzip decompression.
289 ///
290 /// This method exists even if the optional `gzip` feature is not enabled.
291 /// This can be used to ensure a `Client` doesn't use gzip decompression
292 /// even if another dependency were to enable the optional `gzip` feature.
293 pub fn no_gzip(self) -> ClientBuilder {
294 self.with_inner(|inner| inner.no_gzip())
295 }
296
297 /// Disable auto response body brotli decompression.
298 ///
299 /// This method exists even if the optional `brotli` feature is not enabled.
300 /// This can be used to ensure a `Client` doesn't use brotli decompression
301 /// even if another dependency were to enable the optional `brotli` feature.
302 pub fn no_brotli(self) -> ClientBuilder {
303 self.with_inner(|inner| inner.no_brotli())
304 }
305
306 /// Disable auto response body zstd decompression.
307 ///
308 /// This method exists even if the optional `zstd` feature is not enabled.
309 /// This can be used to ensure a `Client` doesn't use zstd decompression
310 /// even if another dependency were to enable the optional `zstd` feature.
311 pub fn no_zstd(self) -> ClientBuilder {
312 self.with_inner(|inner| inner.no_zstd())
313 }
314
315 /// Disable auto response body deflate decompression.
316 ///
317 /// This method exists even if the optional `deflate` feature is not enabled.
318 /// This can be used to ensure a `Client` doesn't use deflate decompression
319 /// even if another dependency were to enable the optional `deflate` feature.
320 pub fn no_deflate(self) -> ClientBuilder {
321 self.with_inner(|inner| inner.no_deflate())
322 }
323
324 // Redirect options
325
326 /// Set a `redirect::Policy` for this client.
327 ///
328 /// Default will follow redirects up to a maximum of 10.
329 pub fn redirect(self, policy: redirect::Policy) -> ClientBuilder {
330 self.with_inner(move |inner| inner.redirect(policy))
331 }
332
333 /// Enable or disable automatic setting of the `Referer` header.
334 ///
335 /// Default is `true`.
336 pub fn referer(self, enable: bool) -> ClientBuilder {
337 self.with_inner(|inner| inner.referer(enable))
338 }
339
340 // Proxy options
341
342 /// Add a `Proxy` to the list of proxies the `Client` will use.
343 ///
344 /// # Note
345 ///
346 /// Adding a proxy will disable the automatic usage of the "system" proxy.
347 pub fn proxy(self, proxy: Proxy) -> ClientBuilder {
348 self.with_inner(move |inner| inner.proxy(proxy))
349 }
350
351 /// Clear all `Proxies`, so `Client` will use no proxy anymore.
352 ///
353 /// # Note
354 /// To add a proxy exclusion list, use [crate::proxy::Proxy::no_proxy()]
355 /// on all desired proxies instead.
356 ///
357 /// This also disables the automatic usage of the "system" proxy.
358 pub fn no_proxy(self) -> ClientBuilder {
359 self.with_inner(move |inner| inner.no_proxy())
360 }
361
362 // Timeout options
363
364 /// Set a timeout for connect, read and write operations of a `Client`.
365 ///
366 /// Default is 30 seconds.
367 ///
368 /// Pass `None` to disable timeout.
369 pub fn timeout<T>(mut self, timeout: T) -> ClientBuilder
370 where
371 T: Into<Option<Duration>>,
372 {
373 self.timeout = Timeout(timeout.into());
374 self
375 }
376
377 /// Set a timeout for only the connect phase of a `Client`.
378 ///
379 /// Default is `None`.
380 pub fn connect_timeout<T>(self, timeout: T) -> ClientBuilder
381 where
382 T: Into<Option<Duration>>,
383 {
384 let timeout = timeout.into();
385 if let Some(dur) = timeout {
386 self.with_inner(|inner| inner.connect_timeout(dur))
387 } else {
388 self
389 }
390 }
391
392 /// Set whether connections should emit verbose logs.
393 ///
394 /// Enabling this option will emit [log][] messages at the `TRACE` level
395 /// for read and write operations on connections.
396 ///
397 /// [log]: https://crates.io/crates/log
398 pub fn connection_verbose(self, verbose: bool) -> ClientBuilder {
399 self.with_inner(move |inner| inner.connection_verbose(verbose))
400 }
401
402 // HTTP options
403
404 /// Set an optional timeout for idle sockets being kept-alive.
405 ///
406 /// Pass `None` to disable timeout.
407 ///
408 /// Default is 90 seconds.
409 pub fn pool_idle_timeout<D>(self, val: D) -> ClientBuilder
410 where
411 D: Into<Option<Duration>>,
412 {
413 self.with_inner(|inner| inner.pool_idle_timeout(val))
414 }
415
416 /// Sets the maximum idle connection per host allowed in the pool.
417 pub fn pool_max_idle_per_host(self, max: usize) -> ClientBuilder {
418 self.with_inner(move |inner| inner.pool_max_idle_per_host(max))
419 }
420
421 /// Send headers as title case instead of lowercase.
422 pub fn http1_title_case_headers(self) -> ClientBuilder {
423 self.with_inner(|inner| inner.http1_title_case_headers())
424 }
425
426 /// Set whether HTTP/1 connections will accept obsolete line folding for
427 /// header values.
428 ///
429 /// Newline codepoints (`\r` and `\n`) will be transformed to spaces when
430 /// parsing.
431 pub fn http1_allow_obsolete_multiline_headers_in_responses(self, value: bool) -> ClientBuilder {
432 self.with_inner(|inner| inner.http1_allow_obsolete_multiline_headers_in_responses(value))
433 }
434
435 /// Sets whether invalid header lines should be silently ignored in HTTP/1 responses.
436 pub fn http1_ignore_invalid_headers_in_responses(self, value: bool) -> ClientBuilder {
437 self.with_inner(|inner| inner.http1_ignore_invalid_headers_in_responses(value))
438 }
439
440 /// Set whether HTTP/1 connections will accept spaces between header
441 /// names and the colon that follow them in responses.
442 ///
443 /// Newline codepoints (\r and \n) will be transformed to spaces when
444 /// parsing.
445 pub fn http1_allow_spaces_after_header_name_in_responses(self, value: bool) -> ClientBuilder {
446 self.with_inner(|inner| inner.http1_allow_spaces_after_header_name_in_responses(value))
447 }
448
449 /// Only use HTTP/1.
450 pub fn http1_only(self) -> ClientBuilder {
451 self.with_inner(|inner| inner.http1_only())
452 }
453
454 /// Allow HTTP/0.9 responses
455 pub fn http09_responses(self) -> ClientBuilder {
456 self.with_inner(|inner| inner.http09_responses())
457 }
458
459 /// Only use HTTP/2.
460 #[cfg(feature = "http2")]
461 #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
462 pub fn http2_prior_knowledge(self) -> ClientBuilder {
463 self.with_inner(|inner| inner.http2_prior_knowledge())
464 }
465
466 /// Sets the `SETTINGS_INITIAL_WINDOW_SIZE` option for HTTP2 stream-level flow control.
467 ///
468 /// Default is currently 65,535 but may change internally to optimize for common uses.
469 #[cfg(feature = "http2")]
470 #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
471 pub fn http2_initial_stream_window_size(self, sz: impl Into<Option<u32>>) -> ClientBuilder {
472 self.with_inner(|inner| inner.http2_initial_stream_window_size(sz))
473 }
474
475 /// Sets the max connection-level flow control for HTTP2
476 ///
477 /// Default is currently 65,535 but may change internally to optimize for common uses.
478 #[cfg(feature = "http2")]
479 #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
480 pub fn http2_initial_connection_window_size(self, sz: impl Into<Option<u32>>) -> ClientBuilder {
481 self.with_inner(|inner| inner.http2_initial_connection_window_size(sz))
482 }
483
484 /// Sets whether to use an adaptive flow control.
485 ///
486 /// Enabling this will override the limits set in `http2_initial_stream_window_size` and
487 /// `http2_initial_connection_window_size`.
488 #[cfg(feature = "http2")]
489 #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
490 pub fn http2_adaptive_window(self, enabled: bool) -> ClientBuilder {
491 self.with_inner(|inner| inner.http2_adaptive_window(enabled))
492 }
493
494 /// Sets the maximum frame size to use for HTTP2.
495 ///
496 /// Default is currently 16,384 but may change internally to optimize for common uses.
497 #[cfg(feature = "http2")]
498 #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
499 pub fn http2_max_frame_size(self, sz: impl Into<Option<u32>>) -> ClientBuilder {
500 self.with_inner(|inner| inner.http2_max_frame_size(sz))
501 }
502
503 /// This requires the optional `http3` feature to be
504 /// enabled.
505 #[cfg(feature = "http3")]
506 #[cfg_attr(docsrs, doc(cfg(feature = "http3")))]
507 pub fn http3_prior_knowledge(self) -> ClientBuilder {
508 self.with_inner(|inner| inner.http3_prior_knowledge())
509 }
510
511 // TCP options
512
513 /// Set whether sockets have `TCP_NODELAY` enabled.
514 ///
515 /// Default is `true`.
516 pub fn tcp_nodelay(self, enabled: bool) -> ClientBuilder {
517 self.with_inner(move |inner| inner.tcp_nodelay(enabled))
518 }
519
520 /// Bind to a local IP Address.
521 ///
522 /// # Example
523 ///
524 /// ```
525 /// use std::net::IpAddr;
526 /// let local_addr = IpAddr::from([12, 4, 1, 8]);
527 /// let client = reqwest::blocking::Client::builder()
528 /// .local_address(local_addr)
529 /// .build().unwrap();
530 /// ```
531 pub fn local_address<T>(self, addr: T) -> ClientBuilder
532 where
533 T: Into<Option<IpAddr>>,
534 {
535 self.with_inner(move |inner| inner.local_address(addr))
536 }
537
538 /// Bind to an interface by `SO_BINDTODEVICE`.
539 ///
540 /// # Example
541 ///
542 /// ```
543 /// let interface = "lo";
544 /// let client = reqwest::blocking::Client::builder()
545 /// .interface(interface)
546 /// .build().unwrap();
547 /// ```
548 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
549 pub fn interface(self, interface: &str) -> ClientBuilder {
550 self.with_inner(move |inner| inner.interface(interface))
551 }
552
553 /// Set that all sockets have `SO_KEEPALIVE` set with the supplied duration.
554 ///
555 /// If `None`, the option will not be set.
556 pub fn tcp_keepalive<D>(self, val: D) -> ClientBuilder
557 where
558 D: Into<Option<Duration>>,
559 {
560 self.with_inner(move |inner| inner.tcp_keepalive(val))
561 }
562
563 // TLS options
564
565 /// Add a custom root certificate.
566 ///
567 /// This allows connecting to a server that has a self-signed
568 /// certificate for example. This **does not** replace the existing
569 /// trusted store.
570 ///
571 /// # Example
572 ///
573 /// ```
574 /// # use std::fs::File;
575 /// # use std::io::Read;
576 /// # fn build_client() -> Result<(), Box<dyn std::error::Error>> {
577 /// // read a local binary DER encoded certificate
578 /// let der = std::fs::read("my-cert.der")?;
579 ///
580 /// // create a certificate
581 /// let cert = reqwest::Certificate::from_der(&der)?;
582 ///
583 /// // get a client builder
584 /// let client = reqwest::blocking::Client::builder()
585 /// .add_root_certificate(cert)
586 /// .build()?;
587 /// # drop(client);
588 /// # Ok(())
589 /// # }
590 /// ```
591 ///
592 /// # Optional
593 ///
594 /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
595 /// feature to be enabled.
596 #[cfg(feature = "__tls")]
597 #[cfg_attr(
598 docsrs,
599 doc(cfg(any(
600 feature = "default-tls",
601 feature = "native-tls",
602 feature = "rustls-tls"
603 )))
604 )]
605 pub fn add_root_certificate(self, cert: Certificate) -> ClientBuilder {
606 self.with_inner(move |inner| inner.add_root_certificate(cert))
607 }
608
609 /// Controls the use of built-in system certificates during certificate validation.
610 ///
611 /// Defaults to `true` -- built-in system certs will be used.
612 ///
613 /// # Optional
614 ///
615 /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
616 /// feature to be enabled.
617 #[cfg(feature = "__tls")]
618 #[cfg_attr(
619 docsrs,
620 doc(cfg(any(
621 feature = "default-tls",
622 feature = "native-tls",
623 feature = "rustls-tls"
624 )))
625 )]
626 pub fn tls_built_in_root_certs(self, tls_built_in_root_certs: bool) -> ClientBuilder {
627 self.with_inner(move |inner| inner.tls_built_in_root_certs(tls_built_in_root_certs))
628 }
629
630 /// Sets whether to load webpki root certs with rustls.
631 ///
632 /// If the feature is enabled, this value is `true` by default.
633 #[cfg(feature = "rustls-tls-webpki-roots")]
634 #[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls-webpki-roots")))]
635 pub fn tls_built_in_webpki_certs(self, enabled: bool) -> ClientBuilder {
636 self.with_inner(move |inner| inner.tls_built_in_webpki_certs(enabled))
637 }
638
639 /// Sets whether to load native root certs with rustls.
640 ///
641 /// If the feature is enabled, this value is `true` by default.
642 #[cfg(feature = "rustls-tls-native-roots")]
643 #[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls-native-roots")))]
644 pub fn tls_built_in_native_certs(self, enabled: bool) -> ClientBuilder {
645 self.with_inner(move |inner| inner.tls_built_in_native_certs(enabled))
646 }
647
648 /// Sets the identity to be used for client certificate authentication.
649 ///
650 /// # Optional
651 ///
652 /// This requires the optional `native-tls` or `rustls-tls(-...)` feature to be
653 /// enabled.
654 #[cfg(any(feature = "native-tls", feature = "__rustls"))]
655 #[cfg_attr(docsrs, doc(cfg(any(feature = "native-tls", feature = "rustls-tls"))))]
656 pub fn identity(self, identity: Identity) -> ClientBuilder {
657 self.with_inner(move |inner| inner.identity(identity))
658 }
659
660 /// Controls the use of hostname verification.
661 ///
662 /// Defaults to `false`.
663 ///
664 /// # Warning
665 ///
666 /// You should think very carefully before you use this method. If
667 /// hostname verification is not used, any valid certificate for any
668 /// site will be trusted for use from any other. This introduces a
669 /// significant vulnerability to man-in-the-middle attacks.
670 ///
671 /// # Optional
672 ///
673 /// This requires the optional `native-tls` feature to be enabled.
674 #[cfg(feature = "native-tls")]
675 #[cfg_attr(docsrs, doc(cfg(feature = "native-tls")))]
676 pub fn danger_accept_invalid_hostnames(self, accept_invalid_hostname: bool) -> ClientBuilder {
677 self.with_inner(|inner| inner.danger_accept_invalid_hostnames(accept_invalid_hostname))
678 }
679
680 /// Controls the use of certificate validation.
681 ///
682 /// Defaults to `false`.
683 ///
684 /// # Warning
685 ///
686 /// You should think very carefully before using this method. If
687 /// invalid certificates are trusted, *any* certificate for *any* site
688 /// will be trusted for use. This includes expired certificates. This
689 /// introduces significant vulnerabilities, and should only be used
690 /// as a last resort.
691 #[cfg(feature = "__tls")]
692 #[cfg_attr(
693 docsrs,
694 doc(cfg(any(
695 feature = "default-tls",
696 feature = "native-tls",
697 feature = "rustls-tls"
698 )))
699 )]
700 pub fn danger_accept_invalid_certs(self, accept_invalid_certs: bool) -> ClientBuilder {
701 self.with_inner(|inner| inner.danger_accept_invalid_certs(accept_invalid_certs))
702 }
703
704 /// Controls the use of TLS server name indication.
705 ///
706 /// Defaults to `true`.
707 #[cfg(feature = "__tls")]
708 #[cfg_attr(
709 docsrs,
710 doc(cfg(any(
711 feature = "default-tls",
712 feature = "native-tls",
713 feature = "rustls-tls"
714 )))
715 )]
716 pub fn tls_sni(self, tls_sni: bool) -> ClientBuilder {
717 self.with_inner(|inner| inner.tls_sni(tls_sni))
718 }
719
720 /// Set the minimum required TLS version for connections.
721 ///
722 /// By default the TLS backend's own default is used.
723 ///
724 /// # Errors
725 ///
726 /// A value of `tls::Version::TLS_1_3` will cause an error with the
727 /// `native-tls`/`default-tls` backend. This does not mean the version
728 /// isn't supported, just that it can't be set as a minimum due to
729 /// technical limitations.
730 ///
731 /// # Optional
732 ///
733 /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
734 /// feature to be enabled.
735 #[cfg(feature = "__tls")]
736 #[cfg_attr(
737 docsrs,
738 doc(cfg(any(
739 feature = "default-tls",
740 feature = "native-tls",
741 feature = "rustls-tls"
742 )))
743 )]
744 pub fn min_tls_version(self, version: tls::Version) -> ClientBuilder {
745 self.with_inner(|inner| inner.min_tls_version(version))
746 }
747
748 /// Set the maximum allowed TLS version for connections.
749 ///
750 /// By default there's no maximum.
751 ///
752 /// # Errors
753 ///
754 /// A value of `tls::Version::TLS_1_3` will cause an error with the
755 /// `native-tls`/`default-tls` backend. This does not mean the version
756 /// isn't supported, just that it can't be set as a maximum due to
757 /// technical limitations.
758 ///
759 /// # Optional
760 ///
761 /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
762 /// feature to be enabled.
763 #[cfg(feature = "__tls")]
764 #[cfg_attr(
765 docsrs,
766 doc(cfg(any(
767 feature = "default-tls",
768 feature = "native-tls",
769 feature = "rustls-tls"
770 )))
771 )]
772 pub fn max_tls_version(self, version: tls::Version) -> ClientBuilder {
773 self.with_inner(|inner| inner.max_tls_version(version))
774 }
775
776 /// Force using the native TLS backend.
777 ///
778 /// Since multiple TLS backends can be optionally enabled, this option will
779 /// force the `native-tls` backend to be used for this `Client`.
780 ///
781 /// # Optional
782 ///
783 /// This requires the optional `native-tls` feature to be enabled.
784 #[cfg(feature = "native-tls")]
785 #[cfg_attr(docsrs, doc(cfg(feature = "native-tls")))]
786 pub fn use_native_tls(self) -> ClientBuilder {
787 self.with_inner(move |inner| inner.use_native_tls())
788 }
789
790 /// Force using the Rustls TLS backend.
791 ///
792 /// Since multiple TLS backends can be optionally enabled, this option will
793 /// force the `rustls` backend to be used for this `Client`.
794 ///
795 /// # Optional
796 ///
797 /// This requires the optional `rustls-tls(-...)` feature to be enabled.
798 #[cfg(feature = "__rustls")]
799 #[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls")))]
800 pub fn use_rustls_tls(self) -> ClientBuilder {
801 self.with_inner(move |inner| inner.use_rustls_tls())
802 }
803
804 /// Add TLS information as `TlsInfo` extension to responses.
805 ///
806 /// # Optional
807 ///
808 /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
809 /// feature to be enabled.
810 #[cfg(feature = "__tls")]
811 #[cfg_attr(
812 docsrs,
813 doc(cfg(any(
814 feature = "default-tls",
815 feature = "native-tls",
816 feature = "rustls-tls"
817 )))
818 )]
819 pub fn tls_info(self, tls_info: bool) -> ClientBuilder {
820 self.with_inner(|inner| inner.tls_info(tls_info))
821 }
822
823 /// Use a preconfigured TLS backend.
824 ///
825 /// If the passed `Any` argument is not a TLS backend that reqwest
826 /// understands, the `ClientBuilder` will error when calling `build`.
827 ///
828 /// # Advanced
829 ///
830 /// This is an advanced option, and can be somewhat brittle. Usage requires
831 /// keeping the preconfigured TLS argument version in sync with reqwest,
832 /// since version mismatches will result in an "unknown" TLS backend.
833 ///
834 /// If possible, it's preferable to use the methods on `ClientBuilder`
835 /// to configure reqwest's TLS.
836 ///
837 /// # Optional
838 ///
839 /// This requires one of the optional features `native-tls` or
840 /// `rustls-tls(-...)` to be enabled.
841 #[cfg(any(feature = "native-tls", feature = "__rustls",))]
842 #[cfg_attr(docsrs, doc(cfg(any(feature = "native-tls", feature = "rustls-tls"))))]
843 pub fn use_preconfigured_tls(self, tls: impl Any) -> ClientBuilder {
844 self.with_inner(move |inner| inner.use_preconfigured_tls(tls))
845 }
846
847 /// Enables the [hickory-dns](hickory_resolver) async resolver instead of a default threadpool using `getaddrinfo`.
848 ///
849 /// If the `hickory-dns` feature is turned on, the default option is enabled.
850 ///
851 /// # Optional
852 ///
853 /// This requires the optional `hickory-dns` feature to be enabled
854 #[cfg(feature = "hickory-dns")]
855 #[cfg_attr(docsrs, doc(cfg(feature = "hickory-dns")))]
856 #[deprecated(note = "use `hickory_dns` instead", since = "0.12.0")]
857 pub fn trust_dns(self, enable: bool) -> ClientBuilder {
858 self.with_inner(|inner| inner.hickory_dns(enable))
859 }
860
861 /// Enables the [hickory-dns](hickory_resolver) async resolver instead of a default threadpool using `getaddrinfo`.
862 ///
863 /// If the `hickory-dns` feature is turned on, the default option is enabled.
864 ///
865 /// # Optional
866 ///
867 /// This requires the optional `hickory-dns` feature to be enabled
868 #[cfg(feature = "hickory-dns")]
869 #[cfg_attr(docsrs, doc(cfg(feature = "hickory-dns")))]
870 pub fn hickory_dns(self, enable: bool) -> ClientBuilder {
871 self.with_inner(|inner| inner.hickory_dns(enable))
872 }
873
874 /// Disables the hickory-dns async resolver.
875 ///
876 /// This method exists even if the optional `hickory-dns` feature is not enabled.
877 /// This can be used to ensure a `Client` doesn't use the hickory-dns async resolver
878 /// even if another dependency were to enable the optional `hickory-dns` feature.
879 #[deprecated(note = "use `no_hickory_dns` instead", since = "0.12.0")]
880 pub fn no_trust_dns(self) -> ClientBuilder {
881 self.with_inner(|inner| inner.no_hickory_dns())
882 }
883
884 /// Disables the hickory-dns async resolver.
885 ///
886 /// This method exists even if the optional `hickory-dns` feature is not enabled.
887 /// This can be used to ensure a `Client` doesn't use the hickory-dns async resolver
888 /// even if another dependency were to enable the optional `hickory-dns` feature.
889 pub fn no_hickory_dns(self) -> ClientBuilder {
890 self.with_inner(|inner| inner.no_hickory_dns())
891 }
892
893 /// Restrict the Client to be used with HTTPS only requests.
894 ///
895 /// Defaults to false.
896 pub fn https_only(self, enabled: bool) -> ClientBuilder {
897 self.with_inner(|inner| inner.https_only(enabled))
898 }
899
900 /// Override DNS resolution for specific domains to a particular IP address.
901 ///
902 /// Warning
903 ///
904 /// Since the DNS protocol has no notion of ports, if you wish to send
905 /// traffic to a particular port you must include this port in the URL
906 /// itself, any port in the overridden addr will be ignored and traffic sent
907 /// to the conventional port for the given scheme (e.g. 80 for http).
908 pub fn resolve(self, domain: &str, addr: SocketAddr) -> ClientBuilder {
909 self.resolve_to_addrs(domain, &[addr])
910 }
911
912 /// Override DNS resolution for specific domains to particular IP addresses.
913 ///
914 /// Warning
915 ///
916 /// Since the DNS protocol has no notion of ports, if you wish to send
917 /// traffic to a particular port you must include this port in the URL
918 /// itself, any port in the overridden addresses will be ignored and traffic sent
919 /// to the conventional port for the given scheme (e.g. 80 for http).
920 pub fn resolve_to_addrs(self, domain: &str, addrs: &[SocketAddr]) -> ClientBuilder {
921 self.with_inner(|inner| inner.resolve_to_addrs(domain, addrs))
922 }
923
924 /// Override the DNS resolver implementation.
925 ///
926 /// Pass an `Arc` wrapping a trait object implementing `Resolve`.
927 /// Overrides for specific names passed to `resolve` and `resolve_to_addrs` will
928 /// still be applied on top of this resolver.
929 pub fn dns_resolver<R: Resolve + 'static>(self, resolver: Arc<R>) -> ClientBuilder {
930 self.with_inner(|inner| inner.dns_resolver(resolver))
931 }
932
933 // private
934
935 fn with_inner<F>(mut self, func: F) -> ClientBuilder
936 where
937 F: FnOnce(async_impl::ClientBuilder) -> async_impl::ClientBuilder,
938 {
939 self.inner = func(self.inner);
940 self
941 }
942}
943
944impl From<async_impl::ClientBuilder> for ClientBuilder {
945 fn from(builder: async_impl::ClientBuilder) -> Self {
946 Self {
947 inner: builder,
948 timeout: Timeout::default(),
949 }
950 }
951}
952
953impl Default for Client {
954 fn default() -> Self {
955 Self::new()
956 }
957}
958
959impl Client {
960 /// Constructs a new `Client`.
961 ///
962 /// # Panic
963 ///
964 /// This method panics if TLS backend cannot be initialized, or the resolver
965 /// cannot load the system configuration.
966 ///
967 /// Use `Client::builder()` if you wish to handle the failure as an `Error`
968 /// instead of panicking.
969 ///
970 /// This method also panics if called from within an async runtime. See docs
971 /// on [`reqwest::blocking`][crate::blocking] for details.
972 pub fn new() -> Client {
973 ClientBuilder::new().build().expect("Client::new()")
974 }
975
976 /// Creates a `ClientBuilder` to configure a `Client`.
977 ///
978 /// This is the same as `ClientBuilder::new()`.
979 pub fn builder() -> ClientBuilder {
980 ClientBuilder::new()
981 }
982
983 /// Convenience method to make a `GET` request to a URL.
984 ///
985 /// # Errors
986 ///
987 /// This method fails whenever supplied `Url` cannot be parsed.
988 pub fn get<U: IntoUrl>(&self, url: U) -> RequestBuilder {
989 self.request(Method::GET, url)
990 }
991
992 /// Convenience method to make a `POST` request to a URL.
993 ///
994 /// # Errors
995 ///
996 /// This method fails whenever supplied `Url` cannot be parsed.
997 pub fn post<U: IntoUrl>(&self, url: U) -> RequestBuilder {
998 self.request(Method::POST, url)
999 }
1000
1001 /// Convenience method to make a `PUT` request to a URL.
1002 ///
1003 /// # Errors
1004 ///
1005 /// This method fails whenever supplied `Url` cannot be parsed.
1006 pub fn put<U: IntoUrl>(&self, url: U) -> RequestBuilder {
1007 self.request(Method::PUT, url)
1008 }
1009
1010 /// Convenience method to make a `PATCH` request to a URL.
1011 ///
1012 /// # Errors
1013 ///
1014 /// This method fails whenever supplied `Url` cannot be parsed.
1015 pub fn patch<U: IntoUrl>(&self, url: U) -> RequestBuilder {
1016 self.request(Method::PATCH, url)
1017 }
1018
1019 /// Convenience method to make a `DELETE` request to a URL.
1020 ///
1021 /// # Errors
1022 ///
1023 /// This method fails whenever supplied `Url` cannot be parsed.
1024 pub fn delete<U: IntoUrl>(&self, url: U) -> RequestBuilder {
1025 self.request(Method::DELETE, url)
1026 }
1027
1028 /// Convenience method to make a `HEAD` request to a URL.
1029 ///
1030 /// # Errors
1031 ///
1032 /// This method fails whenever supplied `Url` cannot be parsed.
1033 pub fn head<U: IntoUrl>(&self, url: U) -> RequestBuilder {
1034 self.request(Method::HEAD, url)
1035 }
1036
1037 /// Start building a `Request` with the `Method` and `Url`.
1038 ///
1039 /// Returns a `RequestBuilder`, which will allow setting headers and
1040 /// request body before sending.
1041 ///
1042 /// # Errors
1043 ///
1044 /// This method fails whenever supplied `Url` cannot be parsed.
1045 pub fn request<U: IntoUrl>(&self, method: Method, url: U) -> RequestBuilder {
1046 let req = url.into_url().map(move |url| Request::new(method, url));
1047 RequestBuilder::new(self.clone(), req)
1048 }
1049
1050 /// Executes a `Request`.
1051 ///
1052 /// A `Request` can be built manually with `Request::new()` or obtained
1053 /// from a RequestBuilder with `RequestBuilder::build()`.
1054 ///
1055 /// You should prefer to use the `RequestBuilder` and
1056 /// `RequestBuilder::send()`.
1057 ///
1058 /// # Errors
1059 ///
1060 /// This method fails if there was an error while sending request,
1061 /// or redirect limit was exhausted.
1062 pub fn execute(&self, request: Request) -> crate::Result<Response> {
1063 self.inner.execute_request(request)
1064 }
1065}
1066
1067impl fmt::Debug for Client {
1068 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1069 f.debug_struct("Client")
1070 //.field("gzip", &self.inner.gzip)
1071 //.field("redirect_policy", &self.inner.redirect_policy)
1072 //.field("referer", &self.inner.referer)
1073 .finish()
1074 }
1075}
1076
1077impl fmt::Debug for ClientBuilder {
1078 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1079 self.inner.fmt(f)
1080 }
1081}
1082
1083#[derive(Clone)]
1084struct ClientHandle {
1085 timeout: Timeout,
1086 inner: Arc<InnerClientHandle>,
1087}
1088
1089type OneshotResponse = oneshot::Sender<crate::Result<async_impl::Response>>;
1090type ThreadSender = mpsc::UnboundedSender<(async_impl::Request, OneshotResponse)>;
1091
1092struct InnerClientHandle {
1093 tx: Option<ThreadSender>,
1094 thread: Option<thread::JoinHandle<()>>,
1095}
1096
1097impl Drop for InnerClientHandle {
1098 fn drop(&mut self) {
1099 let id = self
1100 .thread
1101 .as_ref()
1102 .map(|h| h.thread().id())
1103 .expect("thread not dropped yet");
1104
1105 trace!("closing runtime thread ({id:?})");
1106 self.tx.take();
1107 trace!("signaled close for runtime thread ({id:?})");
1108 self.thread.take().map(|h| h.join());
1109 trace!("closed runtime thread ({id:?})");
1110 }
1111}
1112
1113impl ClientHandle {
1114 fn new(builder: ClientBuilder) -> crate::Result<ClientHandle> {
1115 let timeout = builder.timeout;
1116 let builder = builder.inner;
1117 let (tx, rx) = mpsc::unbounded_channel::<(async_impl::Request, OneshotResponse)>();
1118 let (spawn_tx, spawn_rx) = oneshot::channel::<crate::Result<()>>();
1119 let handle = thread::Builder::new()
1120 .name("reqwest-internal-sync-runtime".into())
1121 .spawn(move || {
1122 use tokio::runtime;
1123 let rt = match runtime::Builder::new_current_thread()
1124 .enable_all()
1125 .build()
1126 .map_err(crate::error::builder)
1127 {
1128 Err(e) => {
1129 if let Err(e) = spawn_tx.send(Err(e)) {
1130 error!("Failed to communicate runtime creation failure: {e:?}");
1131 }
1132 return;
1133 }
1134 Ok(v) => v,
1135 };
1136
1137 let f = async move {
1138 let client = match builder.build() {
1139 Err(e) => {
1140 if let Err(e) = spawn_tx.send(Err(e)) {
1141 error!("Failed to communicate client creation failure: {e:?}");
1142 }
1143 return;
1144 }
1145 Ok(v) => v,
1146 };
1147 if let Err(e) = spawn_tx.send(Ok(())) {
1148 error!("Failed to communicate successful startup: {e:?}");
1149 return;
1150 }
1151
1152 let mut rx = rx;
1153
1154 while let Some((req, req_tx)) = rx.recv().await {
1155 let req_fut = client.execute(req);
1156 tokio::spawn(forward(req_fut, req_tx));
1157 }
1158
1159 trace!("({:?}) Receiver is shutdown", thread::current().id());
1160 };
1161
1162 trace!("({:?}) start runtime::block_on", thread::current().id());
1163 rt.block_on(f);
1164 trace!("({:?}) end runtime::block_on", thread::current().id());
1165 drop(rt);
1166 trace!("({:?}) finished", thread::current().id());
1167 })
1168 .map_err(crate::error::builder)?;
1169
1170 // Wait for the runtime thread to start up...
1171 match wait::timeout(spawn_rx, None) {
1172 Ok(Ok(())) => (),
1173 Ok(Err(err)) => return Err(err),
1174 Err(_canceled) => event_loop_panicked(),
1175 }
1176
1177 let inner_handle = Arc::new(InnerClientHandle {
1178 tx: Some(tx),
1179 thread: Some(handle),
1180 });
1181
1182 Ok(ClientHandle {
1183 timeout,
1184 inner: inner_handle,
1185 })
1186 }
1187
1188 fn execute_request(&self, req: Request) -> crate::Result<Response> {
1189 let (tx, rx) = oneshot::channel();
1190 let (req, body) = req.into_async();
1191 let url = req.url().clone();
1192 let timeout = req.timeout().copied().or(self.timeout.0);
1193
1194 self.inner
1195 .tx
1196 .as_ref()
1197 .expect("core thread exited early")
1198 .send((req, tx))
1199 .expect("core thread panicked");
1200
1201 let result: Result<crate::Result<async_impl::Response>, wait::Waited<crate::Error>> =
1202 if let Some(body) = body {
1203 let f = async move {
1204 body.send().await?;
1205 rx.await.map_err(|_canceled| event_loop_panicked())
1206 };
1207 wait::timeout(f, timeout)
1208 } else {
1209 let f = async move { rx.await.map_err(|_canceled| event_loop_panicked()) };
1210 wait::timeout(f, timeout)
1211 };
1212
1213 match result {
1214 Ok(Err(err)) => Err(err.with_url(url)),
1215 Ok(Ok(res)) => Ok(Response::new(
1216 res,
1217 timeout,
1218 KeepCoreThreadAlive(Some(self.inner.clone())),
1219 )),
1220 Err(wait::Waited::TimedOut(e)) => Err(crate::error::request(e).with_url(url)),
1221 Err(wait::Waited::Inner(err)) => Err(err.with_url(url)),
1222 }
1223 }
1224}
1225
1226async fn forward<F>(fut: F, mut tx: OneshotResponse)
1227where
1228 F: Future<Output = crate::Result<async_impl::Response>>,
1229{
1230 use std::task::Poll;
1231
1232 futures_util::pin_mut!(fut);
1233
1234 // "select" on the sender being canceled, and the future completing
1235 let res = futures_util::future::poll_fn(|cx| {
1236 match fut.as_mut().poll(cx) {
1237 Poll::Ready(val) => Poll::Ready(Some(val)),
1238 Poll::Pending => {
1239 // check if the callback is canceled
1240 futures_core::ready!(tx.poll_closed(cx));
1241 Poll::Ready(None)
1242 }
1243 }
1244 })
1245 .await;
1246
1247 if let Some(res) = res {
1248 let _ = tx.send(res);
1249 }
1250 // else request is canceled
1251}
1252
1253#[derive(Clone, Copy)]
1254struct Timeout(Option<Duration>);
1255
1256impl Default for Timeout {
1257 fn default() -> Timeout {
1258 // default mentioned in ClientBuilder::timeout() doc comment
1259 Timeout(Some(Duration::from_secs(30)))
1260 }
1261}
1262
1263pub(crate) struct KeepCoreThreadAlive(#[allow(dead_code)] Option<Arc<InnerClientHandle>>);
1264
1265impl KeepCoreThreadAlive {
1266 pub(crate) fn empty() -> KeepCoreThreadAlive {
1267 KeepCoreThreadAlive(None)
1268 }
1269}
1270
1271#[cold]
1272#[inline(never)]
1273fn event_loop_panicked() -> ! {
1274 // The only possible reason there would be a Canceled error
1275 // is if the thread running the event loop panicked. We could return
1276 // an Err here, like a BrokenPipe, but the Client is not
1277 // recoverable. Additionally, the panic in the other thread
1278 // is not normal, and should likely be propagated.
1279 panic!("event loop thread panicked");
1280}