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