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