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