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