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 a custom root certificate.
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 /// .add_root_certificate(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-tls(-...)`
785 /// feature to be enabled.
786 #[cfg(feature = "__tls")]
787 #[cfg_attr(
788 docsrs,
789 doc(cfg(any(
790 feature = "default-tls",
791 feature = "native-tls",
792 feature = "rustls-tls"
793 )))
794 )]
795 pub fn add_root_certificate(self, cert: Certificate) -> ClientBuilder {
796 self.with_inner(move |inner| inner.add_root_certificate(cert))
797 }
798
799 /// Add a certificate revocation list.
800 ///
801 ///
802 /// # Optional
803 ///
804 /// This requires the `rustls-tls(-...)` Cargo feature enabled.
805 #[cfg(feature = "__rustls")]
806 #[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls")))]
807 pub fn add_crl(self, crl: CertificateRevocationList) -> ClientBuilder {
808 self.with_inner(move |inner| inner.add_crl(crl))
809 }
810
811 /// Add multiple certificate revocation lists.
812 ///
813 ///
814 /// # Optional
815 ///
816 /// This requires the `rustls-tls(-...)` Cargo feature enabled.
817 #[cfg(feature = "__rustls")]
818 #[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls")))]
819 pub fn add_crls(
820 self,
821 crls: impl IntoIterator<Item = CertificateRevocationList>,
822 ) -> ClientBuilder {
823 self.with_inner(move |inner| inner.add_crls(crls))
824 }
825
826 /// Controls the use of built-in system certificates during certificate validation.
827 ///
828 /// Defaults to `true` -- built-in system certs will be used.
829 ///
830 /// # Optional
831 ///
832 /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
833 /// feature to be enabled.
834 #[cfg(feature = "__tls")]
835 #[cfg_attr(
836 docsrs,
837 doc(cfg(any(
838 feature = "default-tls",
839 feature = "native-tls",
840 feature = "rustls-tls"
841 )))
842 )]
843 pub fn tls_built_in_root_certs(self, tls_built_in_root_certs: bool) -> ClientBuilder {
844 self.with_inner(move |inner| inner.tls_built_in_root_certs(tls_built_in_root_certs))
845 }
846
847 /// Sets whether to load webpki root certs with rustls.
848 ///
849 /// If the feature is enabled, this value is `true` by default.
850 #[cfg(feature = "rustls-tls-webpki-roots-no-provider")]
851 #[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls-webpki-roots-no-provider")))]
852 pub fn tls_built_in_webpki_certs(self, enabled: bool) -> ClientBuilder {
853 self.with_inner(move |inner| inner.tls_built_in_webpki_certs(enabled))
854 }
855
856 /// Sets whether to load native root certs with rustls.
857 ///
858 /// If the feature is enabled, this value is `true` by default.
859 #[cfg(feature = "rustls-tls-native-roots-no-provider")]
860 #[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls-native-roots-no-provider")))]
861 pub fn tls_built_in_native_certs(self, enabled: bool) -> ClientBuilder {
862 self.with_inner(move |inner| inner.tls_built_in_native_certs(enabled))
863 }
864
865 /// Sets the identity to be used for client certificate authentication.
866 ///
867 /// # Optional
868 ///
869 /// This requires the optional `native-tls` or `rustls-tls(-...)` feature to be
870 /// enabled.
871 #[cfg(any(feature = "native-tls", feature = "__rustls"))]
872 #[cfg_attr(docsrs, doc(cfg(any(feature = "native-tls", feature = "rustls-tls"))))]
873 pub fn identity(self, identity: Identity) -> ClientBuilder {
874 self.with_inner(move |inner| inner.identity(identity))
875 }
876
877 /// Controls the use of hostname verification.
878 ///
879 /// Defaults to `false`.
880 ///
881 /// # Warning
882 ///
883 /// You should think very carefully before you use this method. If
884 /// hostname verification is not used, any valid certificate for any
885 /// site will be trusted for use from any other. This introduces a
886 /// significant vulnerability to man-in-the-middle attacks.
887 ///
888 /// # Optional
889 ///
890 /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
891 /// feature to be enabled.
892 #[cfg(feature = "__tls")]
893 #[cfg_attr(
894 docsrs,
895 doc(cfg(any(
896 feature = "default-tls",
897 feature = "native-tls",
898 feature = "rustls-tls"
899 )))
900 )]
901 pub fn danger_accept_invalid_hostnames(self, accept_invalid_hostname: bool) -> ClientBuilder {
902 self.with_inner(|inner| inner.danger_accept_invalid_hostnames(accept_invalid_hostname))
903 }
904
905 /// Controls the use of certificate validation.
906 ///
907 /// Defaults to `false`.
908 ///
909 /// # Warning
910 ///
911 /// You should think very carefully before using this method. If
912 /// invalid certificates are trusted, *any* certificate for *any* site
913 /// will be trusted for use. This includes expired certificates. This
914 /// introduces significant vulnerabilities, and should only be used
915 /// as a last resort.
916 #[cfg(feature = "__tls")]
917 #[cfg_attr(
918 docsrs,
919 doc(cfg(any(
920 feature = "default-tls",
921 feature = "native-tls",
922 feature = "rustls-tls"
923 )))
924 )]
925 pub fn danger_accept_invalid_certs(self, accept_invalid_certs: bool) -> ClientBuilder {
926 self.with_inner(|inner| inner.danger_accept_invalid_certs(accept_invalid_certs))
927 }
928
929 /// Controls the use of TLS server name indication.
930 ///
931 /// Defaults to `true`.
932 #[cfg(feature = "__tls")]
933 #[cfg_attr(
934 docsrs,
935 doc(cfg(any(
936 feature = "default-tls",
937 feature = "native-tls",
938 feature = "rustls-tls"
939 )))
940 )]
941 pub fn tls_sni(self, tls_sni: bool) -> ClientBuilder {
942 self.with_inner(|inner| inner.tls_sni(tls_sni))
943 }
944
945 /// Set the minimum required TLS version for connections.
946 ///
947 /// By default, the TLS backend's own default is used.
948 ///
949 /// # Errors
950 ///
951 /// A value of `tls::Version::TLS_1_3` will cause an error with the
952 /// `native-tls`/`default-tls` backend. This does not mean the version
953 /// isn't supported, just that it can't be set as a minimum due to
954 /// technical limitations.
955 ///
956 /// # Optional
957 ///
958 /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
959 /// feature to be enabled.
960 #[cfg(feature = "__tls")]
961 #[cfg_attr(
962 docsrs,
963 doc(cfg(any(
964 feature = "default-tls",
965 feature = "native-tls",
966 feature = "rustls-tls"
967 )))
968 )]
969 pub fn min_tls_version(self, version: tls::Version) -> ClientBuilder {
970 self.with_inner(|inner| inner.min_tls_version(version))
971 }
972
973 /// Set the maximum allowed TLS version for connections.
974 ///
975 /// By default, there's no maximum.
976 ///
977 /// # Errors
978 ///
979 /// A value of `tls::Version::TLS_1_3` will cause an error with the
980 /// `native-tls`/`default-tls` backend. This does not mean the version
981 /// isn't supported, just that it can't be set as a maximum due to
982 /// technical limitations.
983 ///
984 /// # Optional
985 ///
986 /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
987 /// feature to be enabled.
988 #[cfg(feature = "__tls")]
989 #[cfg_attr(
990 docsrs,
991 doc(cfg(any(
992 feature = "default-tls",
993 feature = "native-tls",
994 feature = "rustls-tls"
995 )))
996 )]
997 pub fn max_tls_version(self, version: tls::Version) -> ClientBuilder {
998 self.with_inner(|inner| inner.max_tls_version(version))
999 }
1000
1001 /// Force using the native TLS backend.
1002 ///
1003 /// Since multiple TLS backends can be optionally enabled, this option will
1004 /// force the `native-tls` backend to be used for this `Client`.
1005 ///
1006 /// # Optional
1007 ///
1008 /// This requires the optional `native-tls` feature to be enabled.
1009 #[cfg(feature = "native-tls")]
1010 #[cfg_attr(docsrs, doc(cfg(feature = "native-tls")))]
1011 pub fn use_native_tls(self) -> ClientBuilder {
1012 self.with_inner(move |inner| inner.use_native_tls())
1013 }
1014
1015 /// Force using the Rustls TLS backend.
1016 ///
1017 /// Since multiple TLS backends can be optionally enabled, this option will
1018 /// force the `rustls` backend to be used for this `Client`.
1019 ///
1020 /// # Optional
1021 ///
1022 /// This requires the optional `rustls-tls(-...)` feature to be enabled.
1023 #[cfg(feature = "__rustls")]
1024 #[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls")))]
1025 pub fn use_rustls_tls(self) -> ClientBuilder {
1026 self.with_inner(move |inner| inner.use_rustls_tls())
1027 }
1028
1029 /// Add TLS information as `TlsInfo` extension to responses.
1030 ///
1031 /// # Optional
1032 ///
1033 /// This requires the optional `default-tls`, `native-tls`, or `rustls-tls(-...)`
1034 /// feature to be enabled.
1035 #[cfg(feature = "__tls")]
1036 #[cfg_attr(
1037 docsrs,
1038 doc(cfg(any(
1039 feature = "default-tls",
1040 feature = "native-tls",
1041 feature = "rustls-tls"
1042 )))
1043 )]
1044 pub fn tls_info(self, tls_info: bool) -> ClientBuilder {
1045 self.with_inner(|inner| inner.tls_info(tls_info))
1046 }
1047
1048 /// Use a preconfigured TLS backend.
1049 ///
1050 /// If the passed `Any` argument is not a TLS backend that reqwest
1051 /// understands, the `ClientBuilder` will error when calling `build`.
1052 ///
1053 /// # Advanced
1054 ///
1055 /// This is an advanced option, and can be somewhat brittle. Usage requires
1056 /// keeping the preconfigured TLS argument version in sync with reqwest,
1057 /// since version mismatches will result in an "unknown" TLS backend.
1058 ///
1059 /// If possible, it's preferable to use the methods on `ClientBuilder`
1060 /// to configure reqwest's TLS.
1061 ///
1062 /// # Optional
1063 ///
1064 /// This requires one of the optional features `native-tls` or
1065 /// `rustls-tls(-...)` to be enabled.
1066 #[cfg(any(feature = "native-tls", feature = "__rustls",))]
1067 #[cfg_attr(docsrs, doc(cfg(any(feature = "native-tls", feature = "rustls-tls"))))]
1068 pub fn use_preconfigured_tls(self, tls: impl Any) -> ClientBuilder {
1069 self.with_inner(move |inner| inner.use_preconfigured_tls(tls))
1070 }
1071
1072 /// Enables the [hickory-dns](hickory_resolver) async resolver instead of a default threadpool using `getaddrinfo`.
1073 ///
1074 /// If the `hickory-dns` feature is turned on, the default option is enabled.
1075 ///
1076 /// # Optional
1077 ///
1078 /// This requires the optional `hickory-dns` feature to be enabled
1079 #[cfg(feature = "hickory-dns")]
1080 #[cfg_attr(docsrs, doc(cfg(feature = "hickory-dns")))]
1081 #[deprecated(note = "use `hickory_dns` instead", since = "0.12.0")]
1082 pub fn trust_dns(self, enable: bool) -> ClientBuilder {
1083 self.with_inner(|inner| inner.hickory_dns(enable))
1084 }
1085
1086 /// Enables the [hickory-dns](hickory_resolver) async resolver instead of a default threadpool using `getaddrinfo`.
1087 ///
1088 /// If the `hickory-dns` feature is turned on, the default option is enabled.
1089 ///
1090 /// # Optional
1091 ///
1092 /// This requires the optional `hickory-dns` feature to be enabled
1093 #[cfg(feature = "hickory-dns")]
1094 #[cfg_attr(docsrs, doc(cfg(feature = "hickory-dns")))]
1095 pub fn hickory_dns(self, enable: bool) -> ClientBuilder {
1096 self.with_inner(|inner| inner.hickory_dns(enable))
1097 }
1098
1099 /// Disables the hickory-dns async resolver.
1100 ///
1101 /// This method exists even if the optional `hickory-dns` feature is not enabled.
1102 /// This can be used to ensure a `Client` doesn't use the hickory-dns async resolver
1103 /// even if another dependency were to enable the optional `hickory-dns` feature.
1104 #[deprecated(note = "use `no_hickory_dns` instead", since = "0.12.0")]
1105 pub fn no_trust_dns(self) -> ClientBuilder {
1106 self.with_inner(|inner| inner.no_hickory_dns())
1107 }
1108
1109 /// Disables the hickory-dns async resolver.
1110 ///
1111 /// This method exists even if the optional `hickory-dns` feature is not enabled.
1112 /// This can be used to ensure a `Client` doesn't use the hickory-dns async resolver
1113 /// even if another dependency were to enable the optional `hickory-dns` feature.
1114 pub fn no_hickory_dns(self) -> ClientBuilder {
1115 self.with_inner(|inner| inner.no_hickory_dns())
1116 }
1117
1118 /// Restrict the Client to be used with HTTPS only requests.
1119 ///
1120 /// Defaults to false.
1121 pub fn https_only(self, enabled: bool) -> ClientBuilder {
1122 self.with_inner(|inner| inner.https_only(enabled))
1123 }
1124
1125 /// Override DNS resolution for specific domains to a particular IP address.
1126 ///
1127 /// Set the port to `0` to use the conventional port for the given scheme (e.g. 80 for http).
1128 /// Ports in the URL itself will always be used instead of the port in the overridden addr.
1129 pub fn resolve(self, domain: &str, addr: SocketAddr) -> ClientBuilder {
1130 self.resolve_to_addrs(domain, &[addr])
1131 }
1132
1133 /// Override DNS resolution for specific domains to particular IP addresses.
1134 ///
1135 /// Set the port to `0` to use the conventional port for the given scheme (e.g. 80 for http).
1136 /// Ports in the URL itself will always be used instead of the port in the overridden addr.
1137 pub fn resolve_to_addrs(self, domain: &str, addrs: &[SocketAddr]) -> ClientBuilder {
1138 self.with_inner(|inner| inner.resolve_to_addrs(domain, addrs))
1139 }
1140
1141 /// Override the DNS resolver implementation.
1142 ///
1143 /// Pass an `Arc` wrapping a trait object implementing `Resolve`.
1144 /// Overrides for specific names passed to `resolve` and `resolve_to_addrs` will
1145 /// still be applied on top of this resolver.
1146 pub fn dns_resolver<R: Resolve + 'static>(self, resolver: Arc<R>) -> ClientBuilder {
1147 self.with_inner(|inner| inner.dns_resolver(resolver))
1148 }
1149
1150 /// Adds a new Tower [`Layer`](https://docs.rs/tower/latest/tower/trait.Layer.html) to the
1151 /// base connector [`Service`](https://docs.rs/tower/latest/tower/trait.Service.html) which
1152 /// is responsible for connection establishment.
1153 ///
1154 /// Each subsequent invocation of this function will wrap previous layers.
1155 ///
1156 /// Example usage:
1157 /// ```
1158 /// use std::time::Duration;
1159 ///
1160 /// let client = reqwest::blocking::Client::builder()
1161 /// // resolved to outermost layer, meaning while we are waiting on concurrency limit
1162 /// .connect_timeout(Duration::from_millis(200))
1163 /// // underneath the concurrency check, so only after concurrency limit lets us through
1164 /// .connector_layer(tower::timeout::TimeoutLayer::new(Duration::from_millis(50)))
1165 /// .connector_layer(tower::limit::concurrency::ConcurrencyLimitLayer::new(2))
1166 /// .build()
1167 /// .unwrap();
1168 /// ```
1169 pub fn connector_layer<L>(self, layer: L) -> ClientBuilder
1170 where
1171 L: Layer<BoxedConnectorService> + Clone + Send + Sync + 'static,
1172 L::Service:
1173 Service<Unnameable, Response = Conn, Error = BoxError> + Clone + Send + Sync + 'static,
1174 <L::Service as Service<Unnameable>>::Future: Send + 'static,
1175 {
1176 self.with_inner(|inner| inner.connector_layer(layer))
1177 }
1178
1179 // private
1180
1181 fn with_inner<F>(mut self, func: F) -> ClientBuilder
1182 where
1183 F: FnOnce(async_impl::ClientBuilder) -> async_impl::ClientBuilder,
1184 {
1185 self.inner = func(self.inner);
1186 self
1187 }
1188}
1189
1190impl From<async_impl::ClientBuilder> for ClientBuilder {
1191 fn from(builder: async_impl::ClientBuilder) -> Self {
1192 Self {
1193 inner: builder,
1194 timeout: Timeout::default(),
1195 }
1196 }
1197}
1198
1199impl Default for Client {
1200 fn default() -> Self {
1201 Self::new()
1202 }
1203}
1204
1205impl Client {
1206 /// Constructs a new `Client`.
1207 ///
1208 /// # Panic
1209 ///
1210 /// This method panics if TLS backend cannot be initialized, or the resolver
1211 /// cannot load the system configuration.
1212 ///
1213 /// Use `Client::builder()` if you wish to handle the failure as an `Error`
1214 /// instead of panicking.
1215 ///
1216 /// This method also panics if called from within an async runtime. See docs
1217 /// on [`reqwest::blocking`][crate::blocking] for details.
1218 pub fn new() -> Client {
1219 ClientBuilder::new().build().expect("Client::new()")
1220 }
1221
1222 /// Creates a `ClientBuilder` to configure a `Client`.
1223 ///
1224 /// This is the same as `ClientBuilder::new()`.
1225 pub fn builder() -> ClientBuilder {
1226 ClientBuilder::new()
1227 }
1228
1229 /// Convenience method to make a `GET` request to a URL.
1230 ///
1231 /// # Errors
1232 ///
1233 /// This method fails whenever supplied `Url` cannot be parsed.
1234 pub fn get<U: IntoUrl>(&self, url: U) -> RequestBuilder {
1235 self.request(Method::GET, url)
1236 }
1237
1238 /// Convenience method to make a `POST` request to a URL.
1239 ///
1240 /// # Errors
1241 ///
1242 /// This method fails whenever supplied `Url` cannot be parsed.
1243 pub fn post<U: IntoUrl>(&self, url: U) -> RequestBuilder {
1244 self.request(Method::POST, url)
1245 }
1246
1247 /// Convenience method to make a `PUT` request to a URL.
1248 ///
1249 /// # Errors
1250 ///
1251 /// This method fails whenever supplied `Url` cannot be parsed.
1252 pub fn put<U: IntoUrl>(&self, url: U) -> RequestBuilder {
1253 self.request(Method::PUT, url)
1254 }
1255
1256 /// Convenience method to make a `PATCH` request to a URL.
1257 ///
1258 /// # Errors
1259 ///
1260 /// This method fails whenever supplied `Url` cannot be parsed.
1261 pub fn patch<U: IntoUrl>(&self, url: U) -> RequestBuilder {
1262 self.request(Method::PATCH, url)
1263 }
1264
1265 /// Convenience method to make a `DELETE` request to a URL.
1266 ///
1267 /// # Errors
1268 ///
1269 /// This method fails whenever supplied `Url` cannot be parsed.
1270 pub fn delete<U: IntoUrl>(&self, url: U) -> RequestBuilder {
1271 self.request(Method::DELETE, url)
1272 }
1273
1274 /// Convenience method to make a `HEAD` request to a URL.
1275 ///
1276 /// # Errors
1277 ///
1278 /// This method fails whenever supplied `Url` cannot be parsed.
1279 pub fn head<U: IntoUrl>(&self, url: U) -> RequestBuilder {
1280 self.request(Method::HEAD, url)
1281 }
1282
1283 /// Start building a `Request` with the `Method` and `Url`.
1284 ///
1285 /// Returns a `RequestBuilder`, which will allow setting headers and
1286 /// request body before sending.
1287 ///
1288 /// # Errors
1289 ///
1290 /// This method fails whenever supplied `Url` cannot be parsed.
1291 pub fn request<U: IntoUrl>(&self, method: Method, url: U) -> RequestBuilder {
1292 let req = url.into_url().map(move |url| Request::new(method, url));
1293 RequestBuilder::new(self.clone(), req)
1294 }
1295
1296 /// Executes a `Request`.
1297 ///
1298 /// A `Request` can be built manually with `Request::new()` or obtained
1299 /// from a RequestBuilder with `RequestBuilder::build()`.
1300 ///
1301 /// You should prefer to use the `RequestBuilder` and
1302 /// `RequestBuilder::send()`.
1303 ///
1304 /// # Errors
1305 ///
1306 /// This method fails if there was an error while sending request,
1307 /// or redirect limit was exhausted.
1308 pub fn execute(&self, request: Request) -> crate::Result<Response> {
1309 self.inner.execute_request(request)
1310 }
1311}
1312
1313impl fmt::Debug for Client {
1314 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1315 f.debug_struct("Client")
1316 //.field("gzip", &self.inner.gzip)
1317 //.field("redirect_policy", &self.inner.redirect_policy)
1318 //.field("referer", &self.inner.referer)
1319 .finish()
1320 }
1321}
1322
1323impl fmt::Debug for ClientBuilder {
1324 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1325 self.inner.fmt(f)
1326 }
1327}
1328
1329#[derive(Clone)]
1330struct ClientHandle {
1331 timeout: Timeout,
1332 inner: Arc<InnerClientHandle>,
1333}
1334
1335type OneshotResponse = oneshot::Sender<crate::Result<async_impl::Response>>;
1336type ThreadSender = mpsc::UnboundedSender<(async_impl::Request, OneshotResponse)>;
1337
1338struct InnerClientHandle {
1339 tx: Option<ThreadSender>,
1340 thread: Option<thread::JoinHandle<()>>,
1341}
1342
1343impl Drop for InnerClientHandle {
1344 fn drop(&mut self) {
1345 let id = self
1346 .thread
1347 .as_ref()
1348 .map(|h| h.thread().id())
1349 .expect("thread not dropped yet");
1350
1351 trace!("closing runtime thread ({id:?})");
1352 self.tx.take();
1353 trace!("signaled close for runtime thread ({id:?})");
1354 self.thread.take().map(|h| h.join());
1355 trace!("closed runtime thread ({id:?})");
1356 }
1357}
1358
1359impl ClientHandle {
1360 fn new(builder: ClientBuilder) -> crate::Result<ClientHandle> {
1361 let timeout = builder.timeout;
1362 let builder = builder.inner;
1363 let (tx, rx) = mpsc::unbounded_channel::<(async_impl::Request, OneshotResponse)>();
1364 let (spawn_tx, spawn_rx) = oneshot::channel::<crate::Result<()>>();
1365 let handle = thread::Builder::new()
1366 .name("reqwest-internal-sync-runtime".into())
1367 .spawn(move || {
1368 use tokio::runtime;
1369 let rt = match runtime::Builder::new_current_thread()
1370 .enable_all()
1371 .build()
1372 .map_err(crate::error::builder)
1373 {
1374 Err(e) => {
1375 if let Err(e) = spawn_tx.send(Err(e)) {
1376 error!("Failed to communicate runtime creation failure: {e:?}");
1377 }
1378 return;
1379 }
1380 Ok(v) => v,
1381 };
1382
1383 let f = async move {
1384 let client = match builder.build() {
1385 Err(e) => {
1386 if let Err(e) = spawn_tx.send(Err(e)) {
1387 error!("Failed to communicate client creation failure: {e:?}");
1388 }
1389 return;
1390 }
1391 Ok(v) => v,
1392 };
1393 if let Err(e) = spawn_tx.send(Ok(())) {
1394 error!("Failed to communicate successful startup: {e:?}");
1395 return;
1396 }
1397
1398 let mut rx = rx;
1399
1400 while let Some((req, req_tx)) = rx.recv().await {
1401 let req_fut = client.execute(req);
1402 tokio::spawn(forward(req_fut, req_tx));
1403 }
1404
1405 trace!("({:?}) Receiver is shutdown", thread::current().id());
1406 };
1407
1408 trace!("({:?}) start runtime::block_on", thread::current().id());
1409 rt.block_on(f);
1410 trace!("({:?}) end runtime::block_on", thread::current().id());
1411 drop(rt);
1412 trace!("({:?}) finished", thread::current().id());
1413 })
1414 .map_err(crate::error::builder)?;
1415
1416 // Wait for the runtime thread to start up...
1417 match wait::timeout(spawn_rx, None) {
1418 Ok(Ok(())) => (),
1419 Ok(Err(err)) => return Err(err),
1420 Err(_canceled) => event_loop_panicked(),
1421 }
1422
1423 let inner_handle = Arc::new(InnerClientHandle {
1424 tx: Some(tx),
1425 thread: Some(handle),
1426 });
1427
1428 Ok(ClientHandle {
1429 timeout,
1430 inner: inner_handle,
1431 })
1432 }
1433
1434 fn execute_request(&self, req: Request) -> crate::Result<Response> {
1435 let (tx, rx) = oneshot::channel();
1436 let (req, body) = req.into_async();
1437 let url = req.url().clone();
1438 let timeout = req.timeout().copied().or(self.timeout.0);
1439
1440 self.inner
1441 .tx
1442 .as_ref()
1443 .expect("core thread exited early")
1444 .send((req, tx))
1445 .expect("core thread panicked");
1446
1447 let result: Result<crate::Result<async_impl::Response>, wait::Waited<crate::Error>> =
1448 if let Some(body) = body {
1449 let f = async move {
1450 body.send().await?;
1451 rx.await.map_err(|_canceled| event_loop_panicked())
1452 };
1453 wait::timeout(f, timeout)
1454 } else {
1455 let f = async move { rx.await.map_err(|_canceled| event_loop_panicked()) };
1456 wait::timeout(f, timeout)
1457 };
1458
1459 match result {
1460 Ok(Err(err)) => Err(err.with_url(url)),
1461 Ok(Ok(res)) => Ok(Response::new(
1462 res,
1463 timeout,
1464 KeepCoreThreadAlive(Some(self.inner.clone())),
1465 )),
1466 Err(wait::Waited::TimedOut(e)) => Err(crate::error::request(e).with_url(url)),
1467 Err(wait::Waited::Inner(err)) => Err(err.with_url(url)),
1468 }
1469 }
1470}
1471
1472async fn forward<F>(fut: F, mut tx: OneshotResponse)
1473where
1474 F: Future<Output = crate::Result<async_impl::Response>>,
1475{
1476 futures_util::pin_mut!(fut);
1477
1478 // "select" on the sender being canceled, and the future completing
1479 let res = std::future::poll_fn(|cx| {
1480 match fut.as_mut().poll(cx) {
1481 Poll::Ready(val) => Poll::Ready(Some(val)),
1482 Poll::Pending => {
1483 // check if the callback is canceled
1484 ready!(tx.poll_closed(cx));
1485 Poll::Ready(None)
1486 }
1487 }
1488 })
1489 .await;
1490
1491 if let Some(res) = res {
1492 let _ = tx.send(res);
1493 }
1494 // else request is canceled
1495}
1496
1497#[derive(Clone, Copy)]
1498struct Timeout(Option<Duration>);
1499
1500impl Default for Timeout {
1501 fn default() -> Timeout {
1502 // default mentioned in ClientBuilder::timeout() doc comment
1503 Timeout(Some(Duration::from_secs(30)))
1504 }
1505}
1506
1507pub(crate) struct KeepCoreThreadAlive(#[allow(dead_code)] Option<Arc<InnerClientHandle>>);
1508
1509impl KeepCoreThreadAlive {
1510 pub(crate) fn empty() -> KeepCoreThreadAlive {
1511 KeepCoreThreadAlive(None)
1512 }
1513}
1514
1515#[cold]
1516#[inline(never)]
1517fn event_loop_panicked() -> ! {
1518 // The only possible reason there would be a Canceled error
1519 // is if the thread running the event loop panicked. We could return
1520 // an Err here, like a BrokenPipe, but the Client is not
1521 // recoverable. Additionally, the panic in the other thread
1522 // is not normal, and should likely be propagated.
1523 panic!("event loop thread panicked");
1524}