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 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 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 /// Sets an interval for HTTP2 Ping frames should be sent to keep a connection alive.
532 ///
533 /// Pass `None` to disable HTTP2 keep-alive.
534 /// Default is currently disabled.
535 #[cfg(feature = "http2")]
536 #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
537 pub fn http2_keep_alive_interval(self, interval: impl Into<Option<Duration>>) -> ClientBuilder {
538 self.with_inner(|inner| inner.http2_keep_alive_interval(interval))
539 }
540
541 /// Sets a timeout for receiving an acknowledgement of the keep-alive ping.
542 ///
543 /// If the ping is not acknowledged within the timeout, the connection will be closed.
544 /// Does nothing if `http2_keep_alive_interval` is disabled.
545 /// Default is currently disabled.
546 #[cfg(feature = "http2")]
547 #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
548 pub fn http2_keep_alive_timeout(self, timeout: Duration) -> ClientBuilder {
549 self.with_inner(|inner| inner.http2_keep_alive_timeout(timeout))
550 }
551
552 /// Sets whether HTTP2 keep-alive should apply while the connection is idle.
553 ///
554 /// If disabled, keep-alive pings are only sent while there are open request/responses streams.
555 /// If enabled, pings are also sent when no streams are active.
556 /// Does nothing if `http2_keep_alive_interval` is disabled.
557 /// Default is `false`.
558 #[cfg(feature = "http2")]
559 #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
560 pub fn http2_keep_alive_while_idle(self, enabled: bool) -> ClientBuilder {
561 self.with_inner(|inner| inner.http2_keep_alive_while_idle(enabled))
562 }
563
564 /// This requires the optional `http3` feature to be
565 /// enabled.
566 #[cfg(feature = "http3")]
567 #[cfg_attr(docsrs, doc(cfg(feature = "http3")))]
568 pub fn http3_prior_knowledge(self) -> ClientBuilder {
569 self.with_inner(|inner| inner.http3_prior_knowledge())
570 }
571
572 /// Maximum duration of inactivity to accept before timing out the QUIC connection.
573 ///
574 /// Please see docs in [`TransportConfig`] in [`quinn`].
575 ///
576 /// [`TransportConfig`]: https://docs.rs/quinn/latest/quinn/struct.TransportConfig.html
577 #[cfg(feature = "http3")]
578 #[cfg_attr(docsrs, doc(cfg(all(reqwest_unstable, feature = "http3",))))]
579 pub fn http3_max_idle_timeout(self, value: Duration) -> ClientBuilder {
580 self.with_inner(|inner| inner.http3_max_idle_timeout(value))
581 }
582
583 /// Maximum number of bytes the peer may transmit without acknowledgement on any one stream
584 /// before becoming blocked.
585 ///
586 /// Please see docs in [`TransportConfig`] in [`quinn`].
587 ///
588 /// [`TransportConfig`]: https://docs.rs/quinn/latest/quinn/struct.TransportConfig.html
589 ///
590 /// # Panics
591 ///
592 /// Panics if the value is over 2^62.
593 #[cfg(feature = "http3")]
594 #[cfg_attr(docsrs, doc(cfg(all(reqwest_unstable, feature = "http3",))))]
595 pub fn http3_stream_receive_window(self, value: u64) -> ClientBuilder {
596 self.with_inner(|inner| inner.http3_stream_receive_window(value))
597 }
598
599 /// Maximum number of bytes the peer may transmit across all streams of a connection before
600 /// becoming blocked.
601 ///
602 /// Please see docs in [`TransportConfig`] in [`quinn`].
603 ///
604 /// [`TransportConfig`]: https://docs.rs/quinn/latest/quinn/struct.TransportConfig.html
605 ///
606 /// # Panics
607 ///
608 /// Panics if the value is over 2^62.
609 #[cfg(feature = "http3")]
610 #[cfg_attr(docsrs, doc(cfg(all(reqwest_unstable, feature = "http3",))))]
611 pub fn http3_conn_receive_window(self, value: u64) -> ClientBuilder {
612 self.with_inner(|inner| inner.http3_conn_receive_window(value))
613 }
614
615 /// Maximum number of bytes to transmit to a peer without acknowledgment
616 ///
617 /// Please see docs in [`TransportConfig`] in [`quinn`].
618 ///
619 /// [`TransportConfig`]: https://docs.rs/quinn/latest/quinn/struct.TransportConfig.html
620 #[cfg(feature = "http3")]
621 #[cfg_attr(docsrs, doc(cfg(all(reqwest_unstable, feature = "http3",))))]
622 pub fn http3_send_window(self, value: u64) -> ClientBuilder {
623 self.with_inner(|inner| inner.http3_send_window(value))
624 }
625
626 /// Override the default congestion control algorithm to use [BBR]
627 ///
628 /// The current default congestion control algorithm is [CUBIC]. This method overrides the
629 /// default.
630 ///
631 /// [BBR]: https://datatracker.ietf.org/doc/html/draft-ietf-ccwg-bbr
632 /// [CUBIC]: https://datatracker.ietf.org/doc/html/rfc8312
633 #[cfg(feature = "http3")]
634 #[cfg_attr(docsrs, doc(cfg(all(reqwest_unstable, feature = "http3",))))]
635 pub fn http3_congestion_bbr(self) -> ClientBuilder {
636 self.with_inner(|inner| inner.http3_congestion_bbr())
637 }
638
639 /// Set the maximum HTTP/3 header size this client is willing to accept.
640 ///
641 /// See [header size constraints] section of the specification for details.
642 ///
643 /// [header size constraints]: https://www.rfc-editor.org/rfc/rfc9114.html#name-header-size-constraints
644 ///
645 /// Please see docs in [`Builder`] in [`h3`].
646 ///
647 /// [`Builder`]: https://docs.rs/h3/latest/h3/client/struct.Builder.html#method.max_field_section_size
648 #[cfg(feature = "http3")]
649 #[cfg_attr(docsrs, doc(cfg(all(reqwest_unstable, feature = "http3",))))]
650 pub fn http3_max_field_section_size(self, value: u64) -> ClientBuilder {
651 self.with_inner(|inner| inner.http3_max_field_section_size(value))
652 }
653
654 /// Enable whether to send HTTP/3 protocol grease on the connections.
655 ///
656 /// HTTP/3 uses the concept of "grease"
657 ///
658 /// to prevent potential interoperability issues in the future.
659 /// In HTTP/3, the concept of grease is used to ensure that the protocol can evolve
660 /// and accommodate future changes without breaking existing implementations.
661 ///
662 /// Please see docs in [`Builder`] in [`h3`].
663 ///
664 /// [`Builder`]: https://docs.rs/h3/latest/h3/client/struct.Builder.html#method.send_grease
665 #[cfg(feature = "http3")]
666 #[cfg_attr(docsrs, doc(cfg(all(reqwest_unstable, feature = "http3",))))]
667 pub fn http3_send_grease(self, enabled: bool) -> ClientBuilder {
668 self.with_inner(|inner| inner.http3_send_grease(enabled))
669 }
670
671 // TCP options
672
673 /// Set whether sockets have `TCP_NODELAY` enabled.
674 ///
675 /// Default is `true`.
676 pub fn tcp_nodelay(self, enabled: bool) -> ClientBuilder {
677 self.with_inner(move |inner| inner.tcp_nodelay(enabled))
678 }
679
680 /// Bind to a local IP Address.
681 ///
682 /// # Example
683 ///
684 /// ```
685 /// use std::net::IpAddr;
686 /// let local_addr = IpAddr::from([12, 4, 1, 8]);
687 /// let client = reqwest::blocking::Client::builder()
688 /// .local_address(local_addr)
689 /// .build().unwrap();
690 /// ```
691 pub fn local_address<T>(self, addr: T) -> ClientBuilder
692 where
693 T: Into<Option<IpAddr>>,
694 {
695 self.with_inner(move |inner| inner.local_address(addr))
696 }
697
698 /// Bind to an interface by `SO_BINDTODEVICE`.
699 ///
700 /// # Example
701 ///
702 /// ```
703 /// let interface = "lo";
704 /// let client = reqwest::blocking::Client::builder()
705 /// .interface(interface)
706 /// .build().unwrap();
707 /// ```
708 #[cfg(any(
709 target_os = "android",
710 target_os = "fuchsia",
711 target_os = "illumos",
712 target_os = "ios",
713 target_os = "linux",
714 target_os = "macos",
715 target_os = "solaris",
716 target_os = "tvos",
717 target_os = "visionos",
718 target_os = "watchos",
719 ))]
720 pub fn interface(self, interface: &str) -> ClientBuilder {
721 self.with_inner(move |inner| inner.interface(interface))
722 }
723
724 /// Set that all sockets have `SO_KEEPALIVE` set with the supplied duration.
725 ///
726 /// If `None`, the option will not be set.
727 pub fn tcp_keepalive<D>(self, val: D) -> ClientBuilder
728 where
729 D: Into<Option<Duration>>,
730 {
731 self.with_inner(move |inner| inner.tcp_keepalive(val))
732 }
733
734 /// Set that all sockets have `SO_KEEPALIVE` set with the supplied interval.
735 ///
736 /// If `None`, the option will not be set.
737 pub fn tcp_keepalive_interval<D>(self, val: D) -> ClientBuilder
738 where
739 D: Into<Option<Duration>>,
740 {
741 self.with_inner(move |inner| inner.tcp_keepalive_interval(val))
742 }
743
744 /// Set that all sockets have `SO_KEEPALIVE` set with the supplied retry count.
745 ///
746 /// If `None`, the option will not be set.
747 pub fn tcp_keepalive_retries<C>(self, retries: C) -> ClientBuilder
748 where
749 C: Into<Option<u32>>,
750 {
751 self.with_inner(move |inner| inner.tcp_keepalive_retries(retries))
752 }
753
754 /// Set that all sockets have `TCP_USER_TIMEOUT` set with the supplied duration.
755 ///
756 /// This option controls how long transmitted data may remain unacknowledged before
757 /// the connection is force-closed.
758 ///
759 /// The current default is `None` (option disabled).
760 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
761 pub fn tcp_user_timeout<D>(self, val: D) -> ClientBuilder
762 where
763 D: Into<Option<Duration>>,
764 {
765 self.with_inner(move |inner| inner.tcp_user_timeout(val))
766 }
767
768 // Alt Transports
769
770 /// Set that all connections will use this Unix socket.
771 ///
772 /// If a request URI uses the `https` scheme, TLS will still be used over
773 /// the Unix socket.
774 ///
775 /// # Note
776 ///
777 /// This option is not compatible with any of the TCP or Proxy options.
778 /// Setting this will ignore all those options previously set.
779 ///
780 /// Likewise, DNS resolution will not be done on the domain name.
781 #[cfg(unix)]
782 pub fn unix_socket(self, path: impl UnixSocketProvider) -> ClientBuilder {
783 self.with_inner(move |inner| inner.unix_socket(path))
784 }
785
786 // TLS options
787
788 /// Add custom root certificates.
789 ///
790 /// This allows connecting to a server that has a self-signed
791 /// certificate for example. This **does not** replace the existing
792 /// trusted store.
793 ///
794 /// # Example
795 ///
796 /// ```
797 /// # use std::fs::File;
798 /// # use std::io::Read;
799 /// # fn build_client() -> Result<(), Box<dyn std::error::Error>> {
800 /// // read a local binary DER encoded certificate
801 /// let der = std::fs::read("my-cert.der")?;
802 ///
803 /// // create a certificate
804 /// let cert = reqwest::Certificate::from_der(&der)?;
805 ///
806 /// // get a client builder
807 /// let client = reqwest::blocking::Client::builder()
808 /// .tls_certs_merge([cert])
809 /// .build()?;
810 /// # drop(client);
811 /// # Ok(())
812 /// # }
813 /// ```
814 ///
815 /// # Optional
816 ///
817 /// This requires the optional `default-tls`, `native-tls`, or `rustls(-...)`
818 /// feature to be enabled.
819 #[cfg(feature = "__tls")]
820 #[cfg_attr(
821 docsrs,
822 doc(cfg(any(feature = "default-tls", feature = "native-tls", feature = "rustls")))
823 )]
824 pub fn tls_certs_merge(self, certs: impl IntoIterator<Item = Certificate>) -> ClientBuilder {
825 self.with_inner(move |inner| inner.tls_certs_merge(certs))
826 }
827
828 /// Use only the provided certificate roots.
829 ///
830 /// This can be used to connect to a server that has a self-signed
831 /// certificate for example.
832 ///
833 /// This option disables any native or built-in roots, and **only** uses
834 /// the roots provided to this method.
835 ///
836 /// # Optional
837 ///
838 /// This requires the optional `default-tls`, `native-tls`, or `rustls(-...)`
839 /// feature to be enabled.
840 #[cfg(feature = "__tls")]
841 #[cfg_attr(
842 docsrs,
843 doc(cfg(any(feature = "default-tls", feature = "native-tls", feature = "rustls")))
844 )]
845 pub fn tls_certs_only(self, certs: impl IntoIterator<Item = Certificate>) -> ClientBuilder {
846 self.with_inner(move |inner| inner.tls_certs_only(certs))
847 }
848
849 /// Deprecated: use [`ClientBuilder::tls_certs_merge()`] or [`ClientBuilder::tls_certs_only()`] instead.
850 #[cfg(feature = "__tls")]
851 pub fn add_root_certificate(self, cert: Certificate) -> ClientBuilder {
852 self.with_inner(move |inner| inner.add_root_certificate(cert))
853 }
854
855 /// Add multiple certificate revocation lists.
856 ///
857 /// # Errors
858 ///
859 /// This only works if also using only provided root certificates. This
860 /// cannot work with the native verifier.
861 ///
862 /// If CRLs are added but `tls_certs_only()` is not called, the builder
863 /// will return an error.
864 ///
865 /// # Optional
866 ///
867 /// This requires the `rustls(-...)` Cargo feature enabled.
868 #[cfg(feature = "__rustls")]
869 #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
870 pub fn tls_crls_only(
871 self,
872 crls: impl IntoIterator<Item = CertificateRevocationList>,
873 ) -> ClientBuilder {
874 self.with_inner(move |inner| inner.tls_crls_only(crls))
875 }
876
877 /// Deprecated: use [`ClientBuilder::tls_crls_only()`] instead.
878 #[cfg(feature = "__rustls")]
879 #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
880 pub fn add_crl(self, crl: CertificateRevocationList) -> ClientBuilder {
881 self.with_inner(move |inner| inner.add_crl(crl))
882 }
883
884 /// Deprecated: use [`ClientBuilder::tls_crls_only()`] instead.
885 #[cfg(feature = "__rustls")]
886 #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
887 pub fn add_crls(
888 self,
889 crls: impl IntoIterator<Item = CertificateRevocationList>,
890 ) -> ClientBuilder {
891 self.with_inner(move |inner| inner.add_crls(crls))
892 }
893
894 /// Sets the identity to be used for client certificate authentication.
895 ///
896 /// # Optional
897 ///
898 /// This requires the optional `native-tls` or `rustls(-...)` feature to be
899 /// enabled.
900 #[cfg(any(feature = "__native-tls", feature = "__rustls"))]
901 #[cfg_attr(docsrs, doc(cfg(any(feature = "native-tls", feature = "rustls"))))]
902 pub fn identity(self, identity: Identity) -> ClientBuilder {
903 self.with_inner(move |inner| inner.identity(identity))
904 }
905
906 /// Controls the use of hostname verification.
907 ///
908 /// Defaults to `false`.
909 ///
910 /// # Warning
911 ///
912 /// You should think very carefully before you use this method. If
913 /// hostname verification is not used, any valid certificate for any
914 /// site will be trusted for use from any other. This introduces a
915 /// significant vulnerability to man-in-the-middle attacks.
916 ///
917 /// # Errors
918 ///
919 /// Depending on the TLS backend and verifier, this might not work with
920 /// native certificates, only those added with [`ClientBuilder::tls_certs_only()`].
921 ///
922 /// # Optional
923 ///
924 /// This requires the optional `default-tls`, `native-tls`, or `rustls(-...)`
925 /// feature to be enabled.
926 #[cfg(feature = "__tls")]
927 #[cfg_attr(
928 docsrs,
929 doc(cfg(any(feature = "default-tls", feature = "native-tls", feature = "rustls")))
930 )]
931 pub fn tls_danger_accept_invalid_hostnames(
932 self,
933 accept_invalid_hostname: bool,
934 ) -> ClientBuilder {
935 self.with_inner(|inner| inner.tls_danger_accept_invalid_hostnames(accept_invalid_hostname))
936 }
937
938 /// Deprecated: use [`ClientBuilder::tls_danger_accept_invalid_hostnames()`] instead.
939 #[cfg(feature = "__tls")]
940 pub fn danger_accept_invalid_hostnames(self, accept_invalid_hostname: bool) -> ClientBuilder {
941 self.with_inner(|inner| inner.danger_accept_invalid_hostnames(accept_invalid_hostname))
942 }
943
944 /// Controls the use of certificate validation.
945 ///
946 /// Defaults to `false`.
947 ///
948 /// # Warning
949 ///
950 /// You should think very carefully before using this method. If
951 /// invalid certificates are trusted, *any* certificate for *any* site
952 /// will be trusted for use. This includes expired certificates. This
953 /// introduces significant vulnerabilities, and should only be used
954 /// as a last resort.
955 #[cfg(feature = "__tls")]
956 #[cfg_attr(
957 docsrs,
958 doc(cfg(any(feature = "default-tls", feature = "native-tls", feature = "rustls")))
959 )]
960 pub fn tls_danger_accept_invalid_certs(self, accept_invalid_certs: bool) -> ClientBuilder {
961 self.with_inner(|inner| inner.tls_danger_accept_invalid_certs(accept_invalid_certs))
962 }
963
964 /// Deprecated: use [`ClientBuilder::tls_danger_accept_invalid_certs()`] instead.
965 #[cfg(feature = "__tls")]
966 pub fn danger_accept_invalid_certs(self, accept_invalid_certs: bool) -> ClientBuilder {
967 self.with_inner(|inner| inner.danger_accept_invalid_certs(accept_invalid_certs))
968 }
969
970 /// Controls the use of TLS server name indication.
971 ///
972 /// Defaults to `true`.
973 #[cfg(feature = "__tls")]
974 #[cfg_attr(
975 docsrs,
976 doc(cfg(any(feature = "default-tls", feature = "native-tls", feature = "rustls")))
977 )]
978 pub fn tls_sni(self, tls_sni: bool) -> ClientBuilder {
979 self.with_inner(|inner| inner.tls_sni(tls_sni))
980 }
981
982 /// Controls if the SSLKEYLOGFILE environment variable is respected.
983 ///
984 /// When enabled, if the environment variable `SSLKEYLOGFILE` is present at runtime,
985 /// TLS keys will be logged to the file at the path described in the variable.
986 /// This can be used by end-users to allow debugging TLS connections.
987 ///
988 /// Defaults to `false`.
989 ///
990 /// # Optional
991 ///
992 /// This requires the `rustls(-...)` Cargo feature enabled.
993 #[cfg(feature = "__rustls")]
994 #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
995 pub fn tls_sslkeylogfile(self, on: bool) -> ClientBuilder {
996 self.with_inner(|inner| inner.tls_sslkeylogfile(on))
997 }
998
999 /// Set the minimum required TLS version for connections.
1000 ///
1001 /// By default, the TLS backend's own default is used.
1002 ///
1003 /// # Errors
1004 ///
1005 /// A value of `tls::Version::TLS_1_3` will cause an error with the
1006 /// `native-tls` backend. This does not mean the version
1007 /// isn't supported, just that it can't be set as a minimum due to
1008 /// technical limitations.
1009 ///
1010 /// # Optional
1011 ///
1012 /// This requires the optional `default-tls`, `native-tls`, or `rustls(-...)`
1013 /// feature to be enabled.
1014 #[cfg(feature = "__tls")]
1015 #[cfg_attr(
1016 docsrs,
1017 doc(cfg(any(feature = "default-tls", feature = "native-tls", feature = "rustls")))
1018 )]
1019 pub fn tls_version_min(self, version: tls::Version) -> ClientBuilder {
1020 self.with_inner(|inner| inner.tls_version_min(version))
1021 }
1022
1023 /// Deprecated: use [`ClientBuilder::tls_version_min()`] instead.
1024 #[cfg(feature = "__tls")]
1025 pub fn min_tls_version(self, version: tls::Version) -> ClientBuilder {
1026 self.with_inner(|inner| inner.min_tls_version(version))
1027 }
1028
1029 /// Set the maximum allowed TLS version for connections.
1030 ///
1031 /// By default, there's no maximum.
1032 ///
1033 /// # Errors
1034 ///
1035 /// A value of `tls::Version::TLS_1_3` will cause an error with the
1036 /// `native-tls` backend. This does not mean the version
1037 /// isn't supported, just that it can't be set as a maximum due to
1038 /// technical limitations.
1039 ///
1040 /// # Optional
1041 ///
1042 /// This requires the optional `default-tls`, `native-tls`, or `rustls(-...)`
1043 /// feature to be enabled.
1044 #[cfg(feature = "__tls")]
1045 #[cfg_attr(
1046 docsrs,
1047 doc(cfg(any(feature = "default-tls", feature = "native-tls", feature = "rustls")))
1048 )]
1049 pub fn tls_version_max(self, version: tls::Version) -> ClientBuilder {
1050 self.with_inner(|inner| inner.tls_version_max(version))
1051 }
1052
1053 /// Deprecated: use [`ClientBuilder::tls_version_max()`] instead.
1054 #[cfg(feature = "__tls")]
1055 pub fn max_tls_version(self, version: tls::Version) -> ClientBuilder {
1056 self.with_inner(|inner| inner.max_tls_version(version))
1057 }
1058
1059 /// Force using the native TLS backend.
1060 ///
1061 /// Since multiple TLS backends can be optionally enabled, this option will
1062 /// force the `native-tls` backend to be used for this `Client`.
1063 ///
1064 /// # Optional
1065 ///
1066 /// This requires the optional `native-tls` feature to be enabled.
1067 #[cfg(feature = "__native-tls")]
1068 #[cfg_attr(docsrs, doc(cfg(feature = "native-tls")))]
1069 pub fn tls_backend_native(self) -> ClientBuilder {
1070 self.with_inner(move |inner| inner.tls_backend_native())
1071 }
1072
1073 /// Deprecated: use [`ClientBuilder::tls_backend_native()`] instead.
1074 #[cfg(feature = "__native-tls")]
1075 pub fn use_native_tls(self) -> ClientBuilder {
1076 self.with_inner(move |inner| inner.use_native_tls())
1077 }
1078
1079 /// Force using the Rustls TLS backend.
1080 ///
1081 /// Since multiple TLS backends can be optionally enabled, this option will
1082 /// force the `rustls` backend to be used for this `Client`.
1083 ///
1084 /// # Optional
1085 ///
1086 /// This requires the optional `rustls(-...)` feature to be enabled.
1087 #[cfg(feature = "__rustls")]
1088 #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
1089 pub fn tls_backend_rustls(self) -> ClientBuilder {
1090 self.with_inner(move |inner| inner.tls_backend_rustls())
1091 }
1092
1093 /// Deprecated: use [`ClientBuilder::tls_backend_rustls()`] instead.
1094 #[cfg(feature = "__rustls")]
1095 #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
1096 pub fn use_rustls_tls(self) -> ClientBuilder {
1097 self.with_inner(move |inner| inner.use_rustls_tls())
1098 }
1099
1100 /// Add TLS information as `TlsInfo` extension to responses.
1101 ///
1102 /// # Optional
1103 ///
1104 /// This requires the optional `default-tls`, `native-tls`, or `rustls(-...)`
1105 /// feature to be enabled.
1106 #[cfg(feature = "__tls")]
1107 #[cfg_attr(
1108 docsrs,
1109 doc(cfg(any(feature = "default-tls", feature = "native-tls", feature = "rustls")))
1110 )]
1111 pub fn tls_info(self, tls_info: bool) -> ClientBuilder {
1112 self.with_inner(|inner| inner.tls_info(tls_info))
1113 }
1114
1115 /// Use a preconfigured TLS backend.
1116 ///
1117 /// If the passed `Any` argument is not a TLS backend that reqwest
1118 /// understands, the `ClientBuilder` will error when calling `build`.
1119 ///
1120 /// # Advanced
1121 ///
1122 /// This is an advanced option, and can be somewhat brittle. Usage requires
1123 /// keeping the preconfigured TLS argument version in sync with reqwest,
1124 /// since version mismatches will result in an "unknown" TLS backend.
1125 ///
1126 /// If possible, it's preferable to use the methods on `ClientBuilder`
1127 /// to configure reqwest's TLS.
1128 ///
1129 /// # Optional
1130 ///
1131 /// This requires one of the optional features `native-tls` or
1132 /// `rustls(-...)` to be enabled.
1133 #[cfg(any(feature = "__native-tls", feature = "__rustls",))]
1134 #[cfg_attr(docsrs, doc(cfg(any(feature = "native-tls", feature = "rustls"))))]
1135 pub fn tls_backend_preconfigured(self, tls: impl Any) -> ClientBuilder {
1136 self.with_inner(move |inner| inner.tls_backend_preconfigured(tls))
1137 }
1138
1139 /// Deprecated: use [`ClientBuilder::tls_backend_preconfigured()`] instead.
1140 #[cfg(any(feature = "__native-tls", feature = "__rustls",))]
1141 pub fn use_preconfigured_tls(self, tls: impl Any) -> ClientBuilder {
1142 self.with_inner(move |inner| inner.use_preconfigured_tls(tls))
1143 }
1144
1145 /// Enables the [hickory-dns](hickory_resolver) async resolver instead of a default threadpool using `getaddrinfo`.
1146 ///
1147 /// If the `hickory-dns` feature is turned on, the default option is enabled.
1148 ///
1149 /// # Optional
1150 ///
1151 /// This requires the optional `hickory-dns` feature to be enabled
1152 #[cfg(feature = "hickory-dns")]
1153 #[cfg_attr(docsrs, doc(cfg(feature = "hickory-dns")))]
1154 pub fn hickory_dns(self, enable: bool) -> ClientBuilder {
1155 self.with_inner(|inner| inner.hickory_dns(enable))
1156 }
1157
1158 /// Disables the hickory-dns async resolver.
1159 ///
1160 /// This method exists even if the optional `hickory-dns` feature is not enabled.
1161 /// This can be used to ensure a `Client` doesn't use the hickory-dns async resolver
1162 /// even if another dependency were to enable the optional `hickory-dns` feature.
1163 pub fn no_hickory_dns(self) -> ClientBuilder {
1164 self.with_inner(|inner| inner.no_hickory_dns())
1165 }
1166
1167 /// Restrict the Client to be used with HTTPS only requests.
1168 ///
1169 /// Defaults to false.
1170 pub fn https_only(self, enabled: bool) -> ClientBuilder {
1171 self.with_inner(|inner| inner.https_only(enabled))
1172 }
1173
1174 /// Override DNS resolution for specific domains to a particular IP address.
1175 ///
1176 /// Set the port to `0` to use the conventional port for the given scheme (e.g. 80 for http).
1177 /// Ports in the URL itself will always be used instead of the port in the overridden addr.
1178 pub fn resolve(self, domain: &str, addr: SocketAddr) -> ClientBuilder {
1179 self.resolve_to_addrs(domain, &[addr])
1180 }
1181
1182 /// Override DNS resolution for specific domains to particular IP addresses.
1183 ///
1184 /// Set the port to `0` to use the conventional port for the given scheme (e.g. 80 for http).
1185 /// Ports in the URL itself will always be used instead of the port in the overridden addr.
1186 pub fn resolve_to_addrs(self, domain: &str, addrs: &[SocketAddr]) -> ClientBuilder {
1187 self.with_inner(|inner| inner.resolve_to_addrs(domain, addrs))
1188 }
1189
1190 /// Override the DNS resolver implementation.
1191 ///
1192 /// Pass an `Arc` wrapping a trait object implementing `Resolve`.
1193 /// Overrides for specific names passed to `resolve` and `resolve_to_addrs` will
1194 /// still be applied on top of this resolver.
1195 pub fn dns_resolver<R: Resolve + 'static>(self, resolver: Arc<R>) -> ClientBuilder {
1196 self.with_inner(|inner| inner.dns_resolver(resolver))
1197 }
1198
1199 /// Adds a new Tower [`Layer`](https://docs.rs/tower/latest/tower/trait.Layer.html) to the
1200 /// base connector [`Service`](https://docs.rs/tower/latest/tower/trait.Service.html) which
1201 /// is responsible for connection establishment.
1202 ///
1203 /// Each subsequent invocation of this function will wrap previous layers.
1204 ///
1205 /// Example usage:
1206 /// ```
1207 /// use std::time::Duration;
1208 ///
1209 /// let client = reqwest::blocking::Client::builder()
1210 /// // resolved to outermost layer, meaning while we are waiting on concurrency limit
1211 /// .connect_timeout(Duration::from_millis(200))
1212 /// // underneath the concurrency check, so only after concurrency limit lets us through
1213 /// .connector_layer(tower::timeout::TimeoutLayer::new(Duration::from_millis(50)))
1214 /// .connector_layer(tower::limit::concurrency::ConcurrencyLimitLayer::new(2))
1215 /// .build()
1216 /// .unwrap();
1217 /// ```
1218 pub fn connector_layer<L>(self, layer: L) -> ClientBuilder
1219 where
1220 L: Layer<BoxedConnectorService> + Clone + Send + Sync + 'static,
1221 L::Service:
1222 Service<Unnameable, Response = Conn, Error = BoxError> + Clone + Send + Sync + 'static,
1223 <L::Service as Service<Unnameable>>::Future: Send + 'static,
1224 {
1225 self.with_inner(|inner| inner.connector_layer(layer))
1226 }
1227
1228 // private
1229
1230 fn with_inner<F>(mut self, func: F) -> ClientBuilder
1231 where
1232 F: FnOnce(async_impl::ClientBuilder) -> async_impl::ClientBuilder,
1233 {
1234 self.inner = func(self.inner);
1235 self
1236 }
1237}
1238
1239impl From<async_impl::ClientBuilder> for ClientBuilder {
1240 fn from(builder: async_impl::ClientBuilder) -> Self {
1241 Self {
1242 inner: builder,
1243 timeout: Timeout::default(),
1244 }
1245 }
1246}
1247
1248impl Default for Client {
1249 fn default() -> Self {
1250 Self::new()
1251 }
1252}
1253
1254impl Client {
1255 /// Constructs a new `Client`.
1256 ///
1257 /// # Panic
1258 ///
1259 /// This method panics if TLS backend cannot be initialized, or the resolver
1260 /// cannot load the system configuration.
1261 ///
1262 /// Use `Client::builder()` if you wish to handle the failure as an `Error`
1263 /// instead of panicking.
1264 ///
1265 /// This method also panics if called from within an async runtime. See docs
1266 /// on [`reqwest::blocking`][crate::blocking] for details.
1267 pub fn new() -> Client {
1268 ClientBuilder::new().build().expect("Client::new()")
1269 }
1270
1271 /// Creates a `ClientBuilder` to configure a `Client`.
1272 ///
1273 /// This is the same as `ClientBuilder::new()`.
1274 pub fn builder() -> ClientBuilder {
1275 ClientBuilder::new()
1276 }
1277
1278 /// Convenience method to make a `GET` request to a URL.
1279 ///
1280 /// # Errors
1281 ///
1282 /// This method fails whenever supplied `Url` cannot be parsed.
1283 pub fn get<U: IntoUrl>(&self, url: U) -> RequestBuilder {
1284 self.request(Method::GET, url)
1285 }
1286
1287 /// Convenience method to make a `POST` request to a URL.
1288 ///
1289 /// # Errors
1290 ///
1291 /// This method fails whenever supplied `Url` cannot be parsed.
1292 pub fn post<U: IntoUrl>(&self, url: U) -> RequestBuilder {
1293 self.request(Method::POST, url)
1294 }
1295
1296 /// Convenience method to make a `PUT` request to a URL.
1297 ///
1298 /// # Errors
1299 ///
1300 /// This method fails whenever supplied `Url` cannot be parsed.
1301 pub fn put<U: IntoUrl>(&self, url: U) -> RequestBuilder {
1302 self.request(Method::PUT, url)
1303 }
1304
1305 /// Convenience method to make a `PATCH` request to a URL.
1306 ///
1307 /// # Errors
1308 ///
1309 /// This method fails whenever supplied `Url` cannot be parsed.
1310 pub fn patch<U: IntoUrl>(&self, url: U) -> RequestBuilder {
1311 self.request(Method::PATCH, url)
1312 }
1313
1314 /// Convenience method to make a `DELETE` request to a URL.
1315 ///
1316 /// # Errors
1317 ///
1318 /// This method fails whenever supplied `Url` cannot be parsed.
1319 pub fn delete<U: IntoUrl>(&self, url: U) -> RequestBuilder {
1320 self.request(Method::DELETE, url)
1321 }
1322
1323 /// Convenience method to make a `HEAD` request to a URL.
1324 ///
1325 /// # Errors
1326 ///
1327 /// This method fails whenever supplied `Url` cannot be parsed.
1328 pub fn head<U: IntoUrl>(&self, url: U) -> RequestBuilder {
1329 self.request(Method::HEAD, url)
1330 }
1331
1332 /// Start building a `Request` with the `Method` and `Url`.
1333 ///
1334 /// Returns a `RequestBuilder`, which will allow setting headers and
1335 /// request body before sending.
1336 ///
1337 /// # Errors
1338 ///
1339 /// This method fails whenever supplied `Url` cannot be parsed.
1340 pub fn request<U: IntoUrl>(&self, method: Method, url: U) -> RequestBuilder {
1341 let req = url.into_url().map(move |url| Request::new(method, url));
1342 RequestBuilder::new(self.clone(), req)
1343 }
1344
1345 /// Executes a `Request`.
1346 ///
1347 /// A `Request` can be built manually with `Request::new()` or obtained
1348 /// from a RequestBuilder with `RequestBuilder::build()`.
1349 ///
1350 /// You should prefer to use the `RequestBuilder` and
1351 /// `RequestBuilder::send()`.
1352 ///
1353 /// # Errors
1354 ///
1355 /// This method fails if there was an error while sending request,
1356 /// or redirect limit was exhausted.
1357 pub fn execute(&self, request: Request) -> crate::Result<Response> {
1358 self.inner.execute_request(request)
1359 }
1360}
1361
1362impl fmt::Debug for Client {
1363 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1364 f.debug_struct("Client")
1365 //.field("gzip", &self.inner.gzip)
1366 //.field("redirect_policy", &self.inner.redirect_policy)
1367 //.field("referer", &self.inner.referer)
1368 .finish()
1369 }
1370}
1371
1372impl fmt::Debug for ClientBuilder {
1373 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1374 self.inner.fmt(f)
1375 }
1376}
1377
1378#[derive(Clone)]
1379struct ClientHandle {
1380 timeout: Timeout,
1381 inner: Arc<InnerClientHandle>,
1382}
1383
1384type OneshotResponse = oneshot::Sender<crate::Result<async_impl::Response>>;
1385type ThreadSender = mpsc::UnboundedSender<(async_impl::Request, OneshotResponse)>;
1386
1387struct InnerClientHandle {
1388 tx: Option<ThreadSender>,
1389 thread: Option<thread::JoinHandle<()>>,
1390}
1391
1392impl Drop for InnerClientHandle {
1393 fn drop(&mut self) {
1394 let id = self
1395 .thread
1396 .as_ref()
1397 .map(|h| h.thread().id())
1398 .expect("thread not dropped yet");
1399
1400 trace!("closing runtime thread ({id:?})");
1401 self.tx.take();
1402 trace!("signaled close for runtime thread ({id:?})");
1403 self.thread.take().map(|h| h.join());
1404 trace!("closed runtime thread ({id:?})");
1405 }
1406}
1407
1408impl ClientHandle {
1409 fn new(builder: ClientBuilder) -> crate::Result<ClientHandle> {
1410 let timeout = builder.timeout;
1411 let builder = builder.inner;
1412 let (tx, rx) = mpsc::unbounded_channel::<(async_impl::Request, OneshotResponse)>();
1413 let (spawn_tx, spawn_rx) = oneshot::channel::<crate::Result<()>>();
1414 let handle = thread::Builder::new()
1415 .name("reqwest-internal-sync-runtime".into())
1416 .spawn(move || {
1417 use tokio::runtime;
1418 let rt = match runtime::Builder::new_current_thread()
1419 .enable_all()
1420 .build()
1421 .map_err(crate::error::builder)
1422 {
1423 Err(e) => {
1424 if let Err(e) = spawn_tx.send(Err(e)) {
1425 error!("Failed to communicate runtime creation failure: {e:?}");
1426 }
1427 return;
1428 }
1429 Ok(v) => v,
1430 };
1431
1432 let f = async move {
1433 let client = match builder.build() {
1434 Err(e) => {
1435 if let Err(e) = spawn_tx.send(Err(e)) {
1436 error!("Failed to communicate client creation failure: {e:?}");
1437 }
1438 return;
1439 }
1440 Ok(v) => v,
1441 };
1442 if let Err(e) = spawn_tx.send(Ok(())) {
1443 error!("Failed to communicate successful startup: {e:?}");
1444 return;
1445 }
1446
1447 let mut rx = rx;
1448
1449 while let Some((req, req_tx)) = rx.recv().await {
1450 let req_fut = client.execute(req);
1451 tokio::spawn(forward(req_fut, req_tx));
1452 }
1453
1454 trace!("({:?}) Receiver is shutdown", thread::current().id());
1455 };
1456
1457 trace!("({:?}) start runtime::block_on", thread::current().id());
1458 rt.block_on(f);
1459 trace!("({:?}) end runtime::block_on", thread::current().id());
1460 drop(rt);
1461 trace!("({:?}) finished", thread::current().id());
1462 })
1463 .map_err(crate::error::builder)?;
1464
1465 // Wait for the runtime thread to start up...
1466 match wait::timeout(spawn_rx, None) {
1467 Ok(Ok(())) => (),
1468 Ok(Err(err)) => return Err(err),
1469 Err(_canceled) => event_loop_panicked(),
1470 }
1471
1472 let inner_handle = Arc::new(InnerClientHandle {
1473 tx: Some(tx),
1474 thread: Some(handle),
1475 });
1476
1477 Ok(ClientHandle {
1478 timeout,
1479 inner: inner_handle,
1480 })
1481 }
1482
1483 fn execute_request(&self, req: Request) -> crate::Result<Response> {
1484 let (tx, rx) = oneshot::channel();
1485 let (req, body) = req.into_async();
1486 let url = req.url().clone();
1487 let timeout = req.timeout().copied().or(self.timeout.0);
1488
1489 self.inner
1490 .tx
1491 .as_ref()
1492 .expect("core thread exited early")
1493 .send((req, tx))
1494 .expect("core thread panicked");
1495
1496 let result: Result<crate::Result<async_impl::Response>, wait::Waited<crate::Error>> =
1497 if let Some(body) = body {
1498 let f = async move {
1499 body.send().await?;
1500 rx.await.map_err(|_canceled| event_loop_panicked())
1501 };
1502 wait::timeout(f, timeout)
1503 } else {
1504 let f = async move { rx.await.map_err(|_canceled| event_loop_panicked()) };
1505 wait::timeout(f, timeout)
1506 };
1507
1508 match result {
1509 Ok(Err(err)) => Err(err.with_url(url)),
1510 Ok(Ok(res)) => Ok(Response::new(
1511 res,
1512 timeout,
1513 KeepCoreThreadAlive(Some(self.inner.clone())),
1514 )),
1515 Err(wait::Waited::TimedOut(e)) => Err(crate::error::request(e).with_url(url)),
1516 Err(wait::Waited::Inner(err)) => Err(err.with_url(url)),
1517 }
1518 }
1519}
1520
1521async fn forward<F>(fut: F, mut tx: OneshotResponse)
1522where
1523 F: Future<Output = crate::Result<async_impl::Response>>,
1524{
1525 futures_util::pin_mut!(fut);
1526
1527 // "select" on the sender being canceled, and the future completing
1528 let res = std::future::poll_fn(|cx| {
1529 match fut.as_mut().poll(cx) {
1530 Poll::Ready(val) => Poll::Ready(Some(val)),
1531 Poll::Pending => {
1532 // check if the callback is canceled
1533 ready!(tx.poll_closed(cx));
1534 Poll::Ready(None)
1535 }
1536 }
1537 })
1538 .await;
1539
1540 if let Some(res) = res {
1541 let _ = tx.send(res);
1542 }
1543 // else request is canceled
1544}
1545
1546#[derive(Clone, Copy)]
1547struct Timeout(Option<Duration>);
1548
1549impl Default for Timeout {
1550 fn default() -> Timeout {
1551 // default mentioned in ClientBuilder::timeout() doc comment
1552 Timeout(Some(Duration::from_secs(30)))
1553 }
1554}
1555
1556pub(crate) struct KeepCoreThreadAlive(#[allow(dead_code)] Option<Arc<InnerClientHandle>>);
1557
1558impl KeepCoreThreadAlive {
1559 pub(crate) fn empty() -> KeepCoreThreadAlive {
1560 KeepCoreThreadAlive(None)
1561 }
1562}
1563
1564#[cold]
1565#[inline(never)]
1566fn event_loop_panicked() -> ! {
1567 // The only possible reason there would be a Canceled error
1568 // is if the thread running the event loop panicked. We could return
1569 // an Err here, like a BrokenPipe, but the Client is not
1570 // recoverable. Additionally, the panic in the other thread
1571 // is not normal, and should likely be propagated.
1572 panic!("event loop thread panicked");
1573}