wreq-rb 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +1922 -397
  3. data/LICENSE +203 -0
  4. data/README.md +19 -15
  5. data/ext/wreq_rb/Cargo.toml +4 -6
  6. data/ext/wreq_rb/src/client.rs +41 -48
  7. data/lib/wreq-rb/version.rb +1 -1
  8. data/patches/0001-add-transfer-size-tracking.patch +76 -67
  9. data/vendor/wreq/Cargo.toml +119 -71
  10. data/vendor/wreq/README.md +25 -20
  11. data/vendor/wreq/bench/http1.rs +25 -0
  12. data/vendor/wreq/bench/http1_over_tls.rs +25 -0
  13. data/vendor/wreq/bench/http2.rs +25 -0
  14. data/vendor/wreq/bench/http2_over_tls.rs +25 -0
  15. data/vendor/wreq/bench/support/bench.rs +91 -0
  16. data/vendor/wreq/bench/support/client.rs +217 -0
  17. data/vendor/wreq/bench/support/server.rs +188 -0
  18. data/vendor/wreq/bench/support.rs +56 -0
  19. data/vendor/wreq/examples/cert_store.rs +4 -4
  20. data/vendor/wreq/examples/{emulation.rs → emulate.rs} +2 -2
  21. data/vendor/wreq/examples/http2_websocket.rs +2 -2
  22. data/vendor/wreq/examples/keylog.rs +3 -3
  23. data/vendor/wreq/examples/{request_with_emulation.rs → request_with_emulate.rs} +2 -2
  24. data/vendor/wreq/examples/rt.rs +23 -0
  25. data/vendor/wreq/src/client/body.rs +23 -61
  26. data/vendor/wreq/src/client/emulate.rs +119 -0
  27. data/vendor/wreq/src/client/{http/future.rs → future.rs} +11 -32
  28. data/vendor/wreq/src/client/{http → layer}/client/pool.rs +66 -61
  29. data/vendor/wreq/src/client/{http → layer}/client.rs +416 -270
  30. data/vendor/wreq/src/client/layer/config.rs +27 -6
  31. data/vendor/wreq/src/client/layer/decoder.rs +9 -4
  32. data/vendor/wreq/src/client/layer/redirect/future.rs +6 -3
  33. data/vendor/wreq/src/client/layer/redirect.rs +4 -5
  34. data/vendor/wreq/src/client/layer/retry.rs +8 -5
  35. data/vendor/wreq/src/client/layer/timeout/body.rs +15 -6
  36. data/vendor/wreq/src/client/layer/timeout/future.rs +23 -18
  37. data/vendor/wreq/src/client/layer/timeout.rs +24 -74
  38. data/vendor/wreq/src/client/layer.rs +1 -2
  39. data/vendor/wreq/src/client/multipart.rs +137 -154
  40. data/vendor/wreq/src/client/request.rs +202 -118
  41. data/vendor/wreq/src/client/response.rs +46 -45
  42. data/vendor/wreq/src/client/upgrade.rs +15 -0
  43. data/vendor/wreq/src/client/ws.rs +73 -25
  44. data/vendor/wreq/src/client.rs +1655 -17
  45. data/vendor/wreq/src/config.rs +11 -11
  46. data/vendor/wreq/src/{client/conn → conn}/connector.rs +139 -137
  47. data/vendor/wreq/src/conn/descriptor.rs +143 -0
  48. data/vendor/wreq/src/conn/http.rs +484 -0
  49. data/vendor/wreq/src/conn/net/io.rs +75 -0
  50. data/vendor/wreq/src/conn/net/tcp/compio.rs +71 -0
  51. data/vendor/wreq/src/conn/net/tcp/tokio.rs +57 -0
  52. data/vendor/wreq/src/conn/net/tcp.rs +561 -0
  53. data/vendor/wreq/src/conn/net/uds/compio.rs +60 -0
  54. data/vendor/wreq/src/{client/conn/uds.rs → conn/net/uds/tokio.rs} +18 -12
  55. data/vendor/wreq/src/conn/net/uds.rs +11 -0
  56. data/vendor/wreq/src/conn/net.rs +130 -0
  57. data/vendor/wreq/src/{client/conn → conn}/proxy/socks.rs +2 -9
  58. data/vendor/wreq/src/{client/conn → conn}/proxy/tunnel.rs +21 -56
  59. data/vendor/wreq/src/conn/tls_info.rs +47 -0
  60. data/vendor/wreq/src/{client/conn.rs → conn.rs} +202 -54
  61. data/vendor/wreq/src/cookie.rs +302 -142
  62. data/vendor/wreq/src/dns/gai/compio.rs +77 -0
  63. data/vendor/wreq/src/dns/gai/tokio.rs +90 -0
  64. data/vendor/wreq/src/dns/gai.rs +14 -164
  65. data/vendor/wreq/src/dns/hickory.rs +16 -23
  66. data/vendor/wreq/src/dns/resolve.rs +7 -41
  67. data/vendor/wreq/src/dns.rs +90 -7
  68. data/vendor/wreq/src/error.rs +57 -31
  69. data/vendor/wreq/src/ext.rs +25 -0
  70. data/vendor/wreq/src/group.rs +211 -0
  71. data/vendor/wreq/src/header.rs +100 -112
  72. data/vendor/wreq/src/lib.rs +124 -73
  73. data/vendor/wreq/src/proxy.rs +6 -20
  74. data/vendor/wreq/src/redirect.rs +1 -1
  75. data/vendor/wreq/src/rt.rs +208 -0
  76. data/vendor/wreq/src/sync.rs +97 -98
  77. data/vendor/wreq/src/tls/compress.rs +124 -0
  78. data/vendor/wreq/src/tls/conn/ext.rs +54 -45
  79. data/vendor/wreq/src/tls/conn/service.rs +14 -18
  80. data/vendor/wreq/src/tls/conn.rs +169 -241
  81. data/vendor/wreq/src/tls/keylog.rs +68 -5
  82. data/vendor/wreq/src/tls/session.rs +205 -0
  83. data/vendor/wreq/src/tls/{x509 → trust}/identity.rs +4 -21
  84. data/vendor/wreq/src/tls/{x509/parser.rs → trust/parse.rs} +1 -1
  85. data/vendor/wreq/src/tls/{x509 → trust}/store.rs +42 -81
  86. data/vendor/wreq/src/tls/{x509.rs → trust.rs} +8 -2
  87. data/vendor/wreq/src/tls.rs +489 -25
  88. data/vendor/wreq/src/trace.rs +0 -12
  89. data/vendor/wreq/src/util.rs +1 -1
  90. data/vendor/wreq/tests/badssl.rs +10 -10
  91. data/vendor/wreq/tests/client.rs +3 -9
  92. data/vendor/wreq/tests/cookie.rs +6 -8
  93. data/vendor/wreq/tests/{emulation.rs → emulate.rs} +130 -22
  94. data/vendor/wreq/tests/multipart.rs +43 -1
  95. data/vendor/wreq/tests/proxy.rs +1 -1
  96. data/vendor/wreq/tests/support/layer.rs +1 -0
  97. metadata +49 -71
  98. data/patches/0002-add-cancel-connections.patch +0 -181
  99. data/vendor/wreq/src/client/conn/conn.rs +0 -231
  100. data/vendor/wreq/src/client/conn/http.rs +0 -1023
  101. data/vendor/wreq/src/client/conn/tls_info.rs +0 -98
  102. data/vendor/wreq/src/client/core/body/incoming.rs +0 -485
  103. data/vendor/wreq/src/client/core/body/length.rs +0 -118
  104. data/vendor/wreq/src/client/core/body.rs +0 -34
  105. data/vendor/wreq/src/client/core/common/buf.rs +0 -149
  106. data/vendor/wreq/src/client/core/common/rewind.rs +0 -141
  107. data/vendor/wreq/src/client/core/common/watch.rs +0 -76
  108. data/vendor/wreq/src/client/core/common.rs +0 -3
  109. data/vendor/wreq/src/client/core/conn/http1.rs +0 -342
  110. data/vendor/wreq/src/client/core/conn/http2.rs +0 -307
  111. data/vendor/wreq/src/client/core/conn.rs +0 -11
  112. data/vendor/wreq/src/client/core/dispatch.rs +0 -299
  113. data/vendor/wreq/src/client/core/error.rs +0 -435
  114. data/vendor/wreq/src/client/core/ext.rs +0 -201
  115. data/vendor/wreq/src/client/core/http1.rs +0 -178
  116. data/vendor/wreq/src/client/core/http2.rs +0 -483
  117. data/vendor/wreq/src/client/core/proto/h1/conn.rs +0 -988
  118. data/vendor/wreq/src/client/core/proto/h1/decode.rs +0 -1170
  119. data/vendor/wreq/src/client/core/proto/h1/dispatch.rs +0 -684
  120. data/vendor/wreq/src/client/core/proto/h1/encode.rs +0 -580
  121. data/vendor/wreq/src/client/core/proto/h1/io.rs +0 -879
  122. data/vendor/wreq/src/client/core/proto/h1/role.rs +0 -694
  123. data/vendor/wreq/src/client/core/proto/h1.rs +0 -104
  124. data/vendor/wreq/src/client/core/proto/h2/client.rs +0 -650
  125. data/vendor/wreq/src/client/core/proto/h2/ping.rs +0 -539
  126. data/vendor/wreq/src/client/core/proto/h2.rs +0 -379
  127. data/vendor/wreq/src/client/core/proto/headers.rs +0 -138
  128. data/vendor/wreq/src/client/core/proto.rs +0 -58
  129. data/vendor/wreq/src/client/core/rt/bounds.rs +0 -57
  130. data/vendor/wreq/src/client/core/rt/timer.rs +0 -150
  131. data/vendor/wreq/src/client/core/rt/tokio.rs +0 -99
  132. data/vendor/wreq/src/client/core/rt.rs +0 -25
  133. data/vendor/wreq/src/client/core/upgrade.rs +0 -267
  134. data/vendor/wreq/src/client/core.rs +0 -16
  135. data/vendor/wreq/src/client/emulation.rs +0 -161
  136. data/vendor/wreq/src/client/http/client/error.rs +0 -142
  137. data/vendor/wreq/src/client/http/client/exec.rs +0 -29
  138. data/vendor/wreq/src/client/http/client/extra.rs +0 -77
  139. data/vendor/wreq/src/client/http/client/util.rs +0 -104
  140. data/vendor/wreq/src/client/http.rs +0 -1629
  141. data/vendor/wreq/src/client/layer/config/options.rs +0 -156
  142. data/vendor/wreq/src/client/layer/cookie.rs +0 -161
  143. data/vendor/wreq/src/hash.rs +0 -143
  144. data/vendor/wreq/src/tls/conn/cache.rs +0 -123
  145. data/vendor/wreq/src/tls/conn/cert_compression.rs +0 -125
  146. data/vendor/wreq/src/tls/keylog/handle.rs +0 -64
  147. data/vendor/wreq/src/tls/options.rs +0 -464
  148. /data/vendor/wreq/src/client/{http → layer}/client/lazy.rs +0 -0
  149. /data/vendor/wreq/src/{client/conn → conn}/proxy.rs +0 -0
  150. /data/vendor/wreq/src/{client/conn → conn}/verbose.rs +0 -0
@@ -1,27 +1,1665 @@
1
- mod body;
2
- mod conn;
3
- mod core;
4
- mod emulation;
5
- mod http;
6
- mod request;
7
- mod response;
8
-
9
- pub mod layer;
1
+ pub(super) mod body;
2
+ pub(super) mod emulate;
3
+ pub(super) mod future;
4
+ pub(super) mod layer;
5
+ pub(super) mod request;
6
+ pub(super) mod response;
7
+ pub(super) mod upgrade;
8
+
10
9
  #[cfg(feature = "multipart")]
11
10
  pub mod multipart;
12
11
  #[cfg(feature = "ws")]
13
12
  pub mod ws;
14
13
 
15
- pub use self::{
14
+ use std::{
15
+ borrow::Cow,
16
+ collections::HashMap,
17
+ convert::TryInto,
18
+ net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
19
+ num::NonZeroUsize,
20
+ sync::Arc,
21
+ task::{Context, Poll},
22
+ time::Duration,
23
+ };
24
+
25
+ use http::header::{HeaderMap, HeaderValue, USER_AGENT};
26
+ use tower::{
27
+ BoxError, Layer, Service, ServiceBuilder, ServiceExt,
28
+ retry::{Retry, RetryLayer},
29
+ util::{BoxCloneSyncService, BoxCloneSyncServiceLayer, Either, Oneshot},
30
+ };
31
+ use wreq_proto::body::Incoming;
32
+
33
+ #[cfg(any(
34
+ feature = "gzip",
35
+ feature = "zstd",
36
+ feature = "brotli",
37
+ feature = "deflate",
38
+ ))]
39
+ use self::layer::decoder::{AcceptEncoding, DecompressionLayer};
40
+ #[cfg(feature = "ws")]
41
+ use self::ws::WebSocketRequestBuilder;
42
+ use self::{
16
43
  body::Body,
17
- core::{http1, http2, upgrade::Upgraded},
18
- emulation::{Emulation, EmulationBuilder, EmulationFactory},
19
- http::{Client, ClientBuilder},
44
+ emulate::IntoEmulation,
45
+ future::Pending,
46
+ layer::{
47
+ client::HttpClient,
48
+ config::{ConfigService, ConfigServiceLayer},
49
+ redirect::{FollowRedirect, FollowRedirectLayer},
50
+ retry::RetryPolicy,
51
+ timeout::{Timeout, TimeoutLayer, TimeoutOptions, body::TimeoutBody},
52
+ },
20
53
  request::{Request, RequestBuilder},
21
54
  response::Response,
22
55
  };
23
- pub(crate) use self::{
24
- conn::{Connected, Connection},
25
- core::{Error as CoreError, ext},
26
- http::{ConnectIdentity, ConnectRequest, client::error::Error},
56
+ #[cfg(feature = "cookies")]
57
+ use crate::cookie;
58
+ #[cfg(feature = "hickory-dns")]
59
+ use crate::dns::hickory::HickoryDnsResolver;
60
+ use crate::{
61
+ IntoUri, Method, Proxy,
62
+ conn::{
63
+ BoxedConnectorLayer, BoxedConnectorService, Conn, Unnameable, connector::Connector,
64
+ http::HttpConnect, net::SocketBindOptions,
65
+ },
66
+ dns::{DnsResolverWithOverrides, DynResolver, GaiResolver, IntoResolve, Resolve},
67
+ error::{self, Error},
68
+ header::OrigHeaderMap,
69
+ http1::Http1Options,
70
+ http2::Http2Options,
71
+ proxy::Matcher as ProxyMatcher,
72
+ redirect::{self, FollowRedirectPolicy},
73
+ retry,
74
+ rt::{BoxSendFuture, Executor, Timer},
75
+ tls::{
76
+ AlpnProtocol, TlsOptions, TlsVersion,
77
+ keylog::KeyLog,
78
+ session::{IntoTlsSessionCache, TlsSessionCache},
79
+ trust::{CertStore, Identity},
80
+ },
27
81
  };
82
+
83
+ #[cfg(not(any(
84
+ feature = "gzip",
85
+ feature = "zstd",
86
+ feature = "brotli",
87
+ feature = "deflate"
88
+ )))]
89
+ type MaybeDecompression<T> = T;
90
+
91
+ #[cfg(any(
92
+ feature = "gzip",
93
+ feature = "zstd",
94
+ feature = "brotli",
95
+ feature = "deflate"
96
+ ))]
97
+ type MaybeDecompression<T> = self::layer::decoder::Decompression<T>;
98
+
99
+ #[cfg(not(any(
100
+ feature = "gzip",
101
+ feature = "zstd",
102
+ feature = "brotli",
103
+ feature = "deflate"
104
+ )))]
105
+ type MaybeDecompressionBody<T> = T;
106
+
107
+ #[cfg(any(
108
+ feature = "gzip",
109
+ feature = "zstd",
110
+ feature = "brotli",
111
+ feature = "deflate"
112
+ ))]
113
+ type MaybeDecompressionBody<T> = tower_http::decompression::DecompressionBody<T>;
114
+
115
+ type ClientService = Timeout<
116
+ ConfigService<
117
+ MaybeDecompression<
118
+ Retry<RetryPolicy, FollowRedirect<HttpClient<Connector, Body>, FollowRedirectPolicy>>,
119
+ >,
120
+ >,
121
+ >;
122
+
123
+ type BoxedClientService = BoxCloneSyncService<
124
+ http::Request<Body>,
125
+ http::Response<TimeoutBody<MaybeDecompressionBody<Incoming>>>,
126
+ BoxError,
127
+ >;
128
+
129
+ type BoxedClientServiceLayer = BoxCloneSyncServiceLayer<
130
+ BoxCloneSyncService<
131
+ http::Request<Body>,
132
+ http::Response<MaybeDecompressionBody<Incoming>>,
133
+ BoxError,
134
+ >,
135
+ http::Request<Body>,
136
+ http::Response<MaybeDecompressionBody<Incoming>>,
137
+ BoxError,
138
+ >;
139
+
140
+ /// An [`Client`] to make Requests with.
141
+ ///
142
+ /// The Client has various configuration values to tweak, but the defaults
143
+ /// are set to what is usually the most commonly desired value. To configure a
144
+ /// [`Client`], use [`Client::builder()`].
145
+ ///
146
+ /// The [`Client`] holds a connection pool internally, so it is advised that
147
+ /// you create one and **reuse** it.
148
+ ///
149
+ /// You do **not** have to wrap the [`Client`] in an [`Rc`] or [`Arc`] to **reuse** it,
150
+ /// because it already uses an [`Arc`] internally.
151
+ ///
152
+ /// [`Rc`]: std::rc::Rc
153
+ #[derive(Clone)]
154
+ pub struct Client(Arc<Either<ClientService, BoxedClientService>>);
155
+
156
+ /// A [`ClientBuilder`] can be used to create a [`Client`] with custom configuration.
157
+ #[must_use]
158
+ pub struct ClientBuilder {
159
+ config: Config,
160
+ }
161
+
162
+ /// The HTTP version preference for the client.
163
+ #[repr(u8)]
164
+ enum HttpVersionPref {
165
+ Http1,
166
+ Http2,
167
+ All,
168
+ }
169
+
170
+ struct Config {
171
+ error: Option<Error>,
172
+ headers: HeaderMap,
173
+ orig_headers: OrigHeaderMap,
174
+ #[cfg(any(
175
+ feature = "gzip",
176
+ feature = "zstd",
177
+ feature = "brotli",
178
+ feature = "deflate",
179
+ ))]
180
+ accept_encoding: AcceptEncoding,
181
+ connect_timeout: Option<Duration>,
182
+ connection_verbose: bool,
183
+ pool_idle_timeout: Option<Duration>,
184
+ pool_max_idle_per_host: usize,
185
+ pool_max_size: Option<NonZeroUsize>,
186
+ tcp_nodelay: bool,
187
+ tcp_reuse_address: bool,
188
+ tcp_keepalive: Option<Duration>,
189
+ tcp_keepalive_interval: Option<Duration>,
190
+ tcp_keepalive_retries: Option<u32>,
191
+ #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
192
+ tcp_user_timeout: Option<Duration>,
193
+ tcp_send_buffer_size: Option<usize>,
194
+ tcp_recv_buffer_size: Option<usize>,
195
+ tcp_happy_eyeballs_timeout: Option<Duration>,
196
+ socket_bind_options: SocketBindOptions,
197
+ proxies: Vec<ProxyMatcher>,
198
+ auto_sys_proxy: bool,
199
+ retry_policy: retry::Policy,
200
+ redirect_policy: redirect::Policy,
201
+ referer: bool,
202
+ timeout_options: TimeoutOptions,
203
+ #[cfg(feature = "cookies")]
204
+ cookie_store: Option<Arc<dyn cookie::CookieStore>>,
205
+ #[cfg(feature = "hickory-dns")]
206
+ hickory_dns: bool,
207
+ dns_overrides: HashMap<Cow<'static, str>, Vec<SocketAddr>>,
208
+ dns_resolver: Option<Arc<dyn Resolve>>,
209
+ http_version_pref: HttpVersionPref,
210
+ https_only: bool,
211
+ layers: Vec<BoxedClientServiceLayer>,
212
+ connector_layers: Vec<BoxedConnectorLayer>,
213
+ tls_sni: bool,
214
+ tls_info: bool,
215
+ tls_keylog: Option<KeyLog>,
216
+ tls_identity: Option<Identity>,
217
+ tls_cert_store: Option<CertStore>,
218
+ tls_cert_verification: bool,
219
+ tls_verify_hostname: bool,
220
+ tls_min_version: Option<TlsVersion>,
221
+ tls_max_version: Option<TlsVersion>,
222
+ tls_session_cache: Option<Arc<dyn TlsSessionCache>>,
223
+ tls_options: Option<TlsOptions>,
224
+ http1_options: Option<Http1Options>,
225
+ http2_options: Option<Http2Options>,
226
+ timer: Timer,
227
+ executor: Executor,
228
+ }
229
+
230
+ // ===== impl Client =====
231
+
232
+ impl Default for Client {
233
+ fn default() -> Self {
234
+ Self::new()
235
+ }
236
+ }
237
+
238
+ impl Client {
239
+ /// Constructs a new [`Client`].
240
+ ///
241
+ /// # Panics
242
+ ///
243
+ /// This method panics if a TLS backend cannot be initialized, or the resolver
244
+ /// cannot load the system configuration.
245
+ ///
246
+ /// Use [`Client::builder()`] if you wish to handle the failure as an [`Error`]
247
+ /// instead of panicking.
248
+ #[inline]
249
+ pub fn new() -> Client {
250
+ Client::builder().build().expect("Client::new()")
251
+ }
252
+
253
+ /// Creates a [`ClientBuilder`] to configure a [`Client`].
254
+ pub fn builder() -> ClientBuilder {
255
+ ClientBuilder {
256
+ config: Config {
257
+ error: None,
258
+ headers: HeaderMap::new(),
259
+ orig_headers: OrigHeaderMap::new(),
260
+ #[cfg(any(
261
+ feature = "gzip",
262
+ feature = "zstd",
263
+ feature = "brotli",
264
+ feature = "deflate",
265
+ ))]
266
+ accept_encoding: AcceptEncoding::default(),
267
+ connect_timeout: None,
268
+ connection_verbose: false,
269
+ pool_idle_timeout: Some(Duration::from_secs(90)),
270
+ pool_max_idle_per_host: usize::MAX,
271
+ pool_max_size: None,
272
+ tcp_keepalive: Some(Duration::from_secs(15)),
273
+ tcp_keepalive_interval: Some(Duration::from_secs(15)),
274
+ tcp_keepalive_retries: Some(3),
275
+ #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
276
+ tcp_user_timeout: Some(Duration::from_secs(30)),
277
+ tcp_nodelay: true,
278
+ tcp_reuse_address: false,
279
+ tcp_send_buffer_size: None,
280
+ tcp_recv_buffer_size: None,
281
+ tcp_happy_eyeballs_timeout: Some(Duration::from_millis(300)),
282
+ socket_bind_options: SocketBindOptions::default(),
283
+ proxies: Vec::new(),
284
+ auto_sys_proxy: true,
285
+ retry_policy: retry::Policy::default(),
286
+ redirect_policy: redirect::Policy::none(),
287
+ referer: true,
288
+ timeout_options: TimeoutOptions::default(),
289
+ #[cfg(feature = "hickory-dns")]
290
+ hickory_dns: cfg!(feature = "hickory-dns"),
291
+ #[cfg(feature = "cookies")]
292
+ cookie_store: None,
293
+ dns_overrides: HashMap::new(),
294
+ dns_resolver: None,
295
+ http_version_pref: HttpVersionPref::All,
296
+ https_only: false,
297
+ http1_options: None,
298
+ http2_options: None,
299
+ layers: Vec::new(),
300
+ connector_layers: Vec::new(),
301
+ tls_sni: true,
302
+ tls_info: false,
303
+ tls_keylog: None,
304
+ tls_identity: None,
305
+ tls_cert_store: None,
306
+ tls_cert_verification: true,
307
+ tls_verify_hostname: true,
308
+ tls_min_version: None,
309
+ tls_max_version: None,
310
+ tls_session_cache: None,
311
+ tls_options: None,
312
+ timer: Timer::default(),
313
+ executor: Executor::default(),
314
+ },
315
+ }
316
+ }
317
+
318
+ /// Convenience method to make a `GET` request to a URI.
319
+ ///
320
+ /// # Errors
321
+ ///
322
+ /// This method fails whenever the supplied `Uri` cannot be parsed.
323
+ #[inline]
324
+ pub fn get<U: IntoUri>(&self, uri: U) -> RequestBuilder {
325
+ self.request(Method::GET, uri)
326
+ }
327
+
328
+ /// Convenience method to make a `POST` request to a URI.
329
+ ///
330
+ /// # Errors
331
+ ///
332
+ /// This method fails whenever the supplied `Uri` cannot be parsed.
333
+ #[inline]
334
+ pub fn post<U: IntoUri>(&self, uri: U) -> RequestBuilder {
335
+ self.request(Method::POST, uri)
336
+ }
337
+
338
+ /// Convenience method to make a `PUT` request to a URI.
339
+ ///
340
+ /// # Errors
341
+ ///
342
+ /// This method fails whenever the supplied `Uri` cannot be parsed.
343
+ #[inline]
344
+ pub fn put<U: IntoUri>(&self, uri: U) -> RequestBuilder {
345
+ self.request(Method::PUT, uri)
346
+ }
347
+
348
+ /// Convenience method to make a `PATCH` request to a URI.
349
+ ///
350
+ /// # Errors
351
+ ///
352
+ /// This method fails whenever the supplied `Uri` cannot be parsed.
353
+ #[inline]
354
+ pub fn patch<U: IntoUri>(&self, uri: U) -> RequestBuilder {
355
+ self.request(Method::PATCH, uri)
356
+ }
357
+
358
+ /// Convenience method to make a `DELETE` request to a URI.
359
+ ///
360
+ /// # Errors
361
+ ///
362
+ /// This method fails whenever the supplied `Uri` cannot be parsed.
363
+ #[inline]
364
+ pub fn delete<U: IntoUri>(&self, uri: U) -> RequestBuilder {
365
+ self.request(Method::DELETE, uri)
366
+ }
367
+
368
+ /// Convenience method to make a `HEAD` request to a URI.
369
+ ///
370
+ /// # Errors
371
+ ///
372
+ /// This method fails whenever the supplied `Uri` cannot be parsed.
373
+ #[inline]
374
+ pub fn head<U: IntoUri>(&self, uri: U) -> RequestBuilder {
375
+ self.request(Method::HEAD, uri)
376
+ }
377
+
378
+ /// Convenience method to make a `OPTIONS` request to a URI.
379
+ ///
380
+ /// # Errors
381
+ ///
382
+ /// This method fails whenever the supplied `Uri` cannot be parsed.
383
+ #[inline]
384
+ pub fn options<U: IntoUri>(&self, uri: U) -> RequestBuilder {
385
+ self.request(Method::OPTIONS, uri)
386
+ }
387
+
388
+ /// Start building a `Request` with the `Method` and `Uri`.
389
+ ///
390
+ /// Returns a `RequestBuilder`, which will allow setting headers and
391
+ /// the request body before sending.
392
+ ///
393
+ /// # Errors
394
+ ///
395
+ /// This method fails whenever the supplied `Uri` cannot be parsed.
396
+ pub fn request<U: IntoUri>(&self, method: Method, uri: U) -> RequestBuilder {
397
+ let req = uri.into_uri().map(move |uri| Request::new(method, uri));
398
+ RequestBuilder::new(self.clone(), req)
399
+ }
400
+
401
+ /// Upgrades the [`RequestBuilder`] to perform a
402
+ /// websocket handshake. This returns a wrapped type, so you must do
403
+ /// this after you set up your request, and just before you send the
404
+ /// request.
405
+ #[inline]
406
+ #[cfg(feature = "ws")]
407
+ #[cfg_attr(docsrs, doc(cfg(feature = "ws")))]
408
+ pub fn websocket<U: IntoUri>(&self, uri: U) -> WebSocketRequestBuilder {
409
+ WebSocketRequestBuilder::new(self.request(Method::GET, uri))
410
+ }
411
+
412
+ /// Executes a `Request`.
413
+ ///
414
+ /// A `Request` can be built manually with `Request::new()` or obtained
415
+ /// from a RequestBuilder with `RequestBuilder::build()`.
416
+ ///
417
+ /// You should prefer to use the `RequestBuilder` and
418
+ /// `RequestBuilder::send()`.
419
+ ///
420
+ /// # Errors
421
+ ///
422
+ /// This method fails if there was an error while sending request,
423
+ /// redirect loop was detected or redirect limit was exhausted.
424
+ pub fn execute(&self, request: Request) -> Pending {
425
+ let req = http::Request::<Body>::from(request);
426
+ Pending::Request {
427
+ uri: Some(req.uri().clone()),
428
+ fut: Box::pin(Oneshot::new((*self.0).clone(), req)),
429
+ }
430
+ }
431
+ }
432
+
433
+ impl tower::Service<Request> for Client {
434
+ type Response = Response;
435
+ type Error = Error;
436
+ type Future = Pending;
437
+
438
+ #[inline(always)]
439
+ fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
440
+ Poll::Ready(Ok(()))
441
+ }
442
+
443
+ #[inline(always)]
444
+ fn call(&mut self, req: Request) -> Self::Future {
445
+ self.execute(req)
446
+ }
447
+ }
448
+
449
+ impl tower::Service<Request> for &'_ Client {
450
+ type Response = Response;
451
+ type Error = Error;
452
+ type Future = Pending;
453
+
454
+ #[inline(always)]
455
+ fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
456
+ Poll::Ready(Ok(()))
457
+ }
458
+
459
+ #[inline(always)]
460
+ fn call(&mut self, req: Request) -> Self::Future {
461
+ self.execute(req)
462
+ }
463
+ }
464
+
465
+ // ===== impl ClientBuilder =====
466
+
467
+ impl ClientBuilder {
468
+ /// Returns a [`Client`] that uses this [`ClientBuilder`] configuration.
469
+ ///
470
+ /// # Errors
471
+ ///
472
+ /// This method fails if a TLS backend cannot be initialized, or the resolver
473
+ /// cannot load the system configuration.
474
+ pub fn build(self) -> crate::Result<Client> {
475
+ let mut config = self.config;
476
+
477
+ if let Some(err) = config.error {
478
+ return Err(err);
479
+ }
480
+
481
+ // Prepare proxies
482
+ if config.auto_sys_proxy {
483
+ config.proxies.push(ProxyMatcher::system());
484
+ }
485
+
486
+ // Create base client service
487
+ let service = {
488
+ let resolver = {
489
+ let mut resolver: Arc<dyn Resolve> = match config.dns_resolver {
490
+ Some(dns_resolver) => dns_resolver,
491
+ #[cfg(feature = "hickory-dns")]
492
+ None if config.hickory_dns => Arc::new(HickoryDnsResolver::new()),
493
+ None => Arc::new(GaiResolver::new()),
494
+ };
495
+
496
+ if !config.dns_overrides.is_empty() {
497
+ resolver = Arc::new(DnsResolverWithOverrides::new(
498
+ resolver,
499
+ config.dns_overrides,
500
+ ));
501
+ }
502
+ DynResolver::new(resolver)
503
+ };
504
+
505
+ let connector = Connector::builder(config.proxies, resolver)
506
+ .timeout(config.connect_timeout)
507
+ .tls_info(config.tls_info)
508
+ .tcp_nodelay(config.tcp_nodelay)
509
+ .verbose(config.connection_verbose)
510
+ .with_tls(|tls| {
511
+ tls.alpn_protocol(match config.http_version_pref {
512
+ HttpVersionPref::Http1 => Some(AlpnProtocol::HTTP1),
513
+ HttpVersionPref::Http2 => Some(AlpnProtocol::HTTP2),
514
+ _ => None,
515
+ })
516
+ .keylog(config.tls_keylog)
517
+ .cert_store(config.tls_cert_store)
518
+ .identity(config.tls_identity)
519
+ .max_version(config.tls_max_version)
520
+ .min_version(config.tls_min_version)
521
+ .tls_sni(config.tls_sni)
522
+ .verify_hostname(config.tls_verify_hostname)
523
+ .cert_verification(config.tls_cert_verification)
524
+ .session_store(config.tls_session_cache)
525
+ })
526
+ .with_http(|http| {
527
+ http.enforce_http(false);
528
+ http.set_keepalive(config.tcp_keepalive);
529
+ http.set_keepalive_interval(config.tcp_keepalive_interval);
530
+ http.set_keepalive_retries(config.tcp_keepalive_retries);
531
+ http.set_reuse_address(config.tcp_reuse_address);
532
+ http.set_connect_timeout(config.connect_timeout);
533
+ http.set_nodelay(config.tcp_nodelay);
534
+ http.set_send_buffer_size(config.tcp_send_buffer_size);
535
+ http.set_recv_buffer_size(config.tcp_recv_buffer_size);
536
+ http.set_happy_eyeballs_timeout(config.tcp_happy_eyeballs_timeout);
537
+
538
+ #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
539
+ http.set_tcp_user_timeout(config.tcp_user_timeout);
540
+
541
+ #[cfg(any(
542
+ target_os = "android",
543
+ target_os = "fuchsia",
544
+ target_os = "illumos",
545
+ target_os = "ios",
546
+ target_os = "linux",
547
+ target_os = "macos",
548
+ target_os = "solaris",
549
+ target_os = "tvos",
550
+ target_os = "visionos",
551
+ target_os = "watchos",
552
+ ))]
553
+ if let Some(interface) = config.socket_bind_options.interface {
554
+ http.set_interface(interface);
555
+ }
556
+
557
+ http.set_local_addresses(
558
+ config.socket_bind_options.ipv4_address,
559
+ config.socket_bind_options.ipv6_address,
560
+ );
561
+ })
562
+ .build(config.tls_options, config.connector_layers)?;
563
+
564
+ #[allow(unused_mut)]
565
+ let mut builder = HttpClient::builder(config.executor);
566
+
567
+ #[cfg(feature = "cookies")]
568
+ {
569
+ builder = builder.cookie_store(config.cookie_store);
570
+ }
571
+
572
+ builder
573
+ .http1_options(config.http1_options)
574
+ .http2_options(config.http2_options)
575
+ .http2_only(matches!(config.http_version_pref, HttpVersionPref::Http2))
576
+ .http2_timer(config.timer.clone())
577
+ .pool_timer(config.timer.clone())
578
+ .pool_idle_timeout(config.pool_idle_timeout)
579
+ .pool_max_idle_per_host(config.pool_max_idle_per_host)
580
+ .pool_max_size(config.pool_max_size)
581
+ .build(connector)
582
+ };
583
+
584
+ // Configured client service with layers
585
+ let client = {
586
+ let service = ServiceBuilder::new()
587
+ .layer(RetryLayer::new(RetryPolicy::new(config.retry_policy)))
588
+ .layer({
589
+ let policy = FollowRedirectPolicy::new(config.redirect_policy)
590
+ .with_referer(config.referer)
591
+ .with_https_only(config.https_only);
592
+ FollowRedirectLayer::with_policy(policy)
593
+ })
594
+ .service(service);
595
+
596
+ #[cfg(any(
597
+ feature = "gzip",
598
+ feature = "zstd",
599
+ feature = "brotli",
600
+ feature = "deflate",
601
+ ))]
602
+ let service = ServiceBuilder::new()
603
+ .layer(DecompressionLayer::new(config.accept_encoding))
604
+ .service(service);
605
+
606
+ let service = ServiceBuilder::new()
607
+ .layer(ConfigServiceLayer::new(
608
+ config.https_only,
609
+ config.headers,
610
+ config.orig_headers,
611
+ ))
612
+ .service(service);
613
+
614
+ if config.layers.is_empty() {
615
+ let service = ServiceBuilder::new()
616
+ .layer(TimeoutLayer::new(config.timer, config.timeout_options))
617
+ .service(service);
618
+
619
+ Either::Left(service)
620
+ } else {
621
+ let service = config
622
+ .layers
623
+ .into_iter()
624
+ .fold(BoxCloneSyncService::new(service), |service, layer| {
625
+ ServiceBuilder::new().layer(layer).service(service)
626
+ });
627
+
628
+ let service = ServiceBuilder::new()
629
+ .layer(TimeoutLayer::new(config.timer, config.timeout_options))
630
+ .service(service)
631
+ .map_err(error::map_timeout_to_request_error);
632
+
633
+ Either::Right(BoxCloneSyncService::new(service))
634
+ }
635
+ };
636
+
637
+ Ok(Client(Arc::new(client)))
638
+ }
639
+
640
+ // Runtime options
641
+
642
+ /// Provide a timer to be used for timeouts and intervals in client.
643
+ #[inline]
644
+ pub fn timer<M>(mut self, timer: M) -> Self
645
+ where
646
+ M: wreq_proto::rt::Timer + Send + Sync + 'static,
647
+ {
648
+ self.config.timer = Timer::new(timer);
649
+ self
650
+ }
651
+
652
+ /// Provide an executor to run background tasks in the client.
653
+ #[inline]
654
+ pub fn executor<E>(mut self, executor: E) -> Self
655
+ where
656
+ E: wreq_proto::rt::Executor<BoxSendFuture> + Send + Sync + 'static,
657
+ {
658
+ self.config.executor = Executor::new(executor);
659
+ self
660
+ }
661
+
662
+ // Higher-level options
663
+
664
+ /// Sets the `User-Agent` header to be used by this client.
665
+ ///
666
+ /// # Example
667
+ ///
668
+ /// ```rust
669
+ /// # async fn doc() -> wreq::Result<()> {
670
+ /// // Name your user agent after your app?
671
+ /// static APP_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),);
672
+ ///
673
+ /// let client = wreq::Client::builder().user_agent(APP_USER_AGENT).build()?;
674
+ /// let res = client.get("https://www.rust-lang.org").send().await?;
675
+ /// # Ok(())
676
+ /// # }
677
+ /// ```
678
+ pub fn user_agent<V>(mut self, value: V) -> ClientBuilder
679
+ where
680
+ V: TryInto<HeaderValue>,
681
+ V::Error: Into<http::Error>,
682
+ {
683
+ match value.try_into() {
684
+ Ok(value) => {
685
+ self.config.headers.insert(USER_AGENT, value);
686
+ }
687
+ Err(err) => {
688
+ self.config.error = Some(Error::builder(err.into()));
689
+ }
690
+ };
691
+ self
692
+ }
693
+
694
+ /// Sets the default headers for every request.
695
+ ///
696
+ /// # Example
697
+ ///
698
+ /// ```rust
699
+ /// use wreq::header;
700
+ /// # async fn doc() -> wreq::Result<()> {
701
+ /// let mut headers = header::HeaderMap::new();
702
+ /// headers.insert("X-MY-HEADER", header::HeaderValue::from_static("value"));
703
+ ///
704
+ /// // Consider marking security-sensitive headers with `set_sensitive`.
705
+ /// let mut auth_value = header::HeaderValue::from_static("secret");
706
+ /// auth_value.set_sensitive(true);
707
+ /// headers.insert(header::AUTHORIZATION, auth_value);
708
+ ///
709
+ /// // get a client builder
710
+ /// let client = wreq::Client::builder().default_headers(headers).build()?;
711
+ /// let res = client.get("https://www.rust-lang.org").send().await?;
712
+ /// # Ok(())
713
+ /// # }
714
+ /// ```
715
+ ///
716
+ /// Override the default headers:
717
+ ///
718
+ /// ```rust
719
+ /// use wreq::header;
720
+ /// # async fn doc() -> wreq::Result<()> {
721
+ /// let mut headers = header::HeaderMap::new();
722
+ /// headers.insert("X-MY-HEADER", header::HeaderValue::from_static("value"));
723
+ ///
724
+ /// // get a client builder
725
+ /// let client = wreq::Client::builder().default_headers(headers).build()?;
726
+ /// let res = client
727
+ /// .get("https://www.rust-lang.org")
728
+ /// .header("X-MY-HEADER", "new_value")
729
+ /// .send()
730
+ /// .await?;
731
+ /// # Ok(())
732
+ /// # }
733
+ /// ```
734
+ #[inline]
735
+ pub fn default_headers(mut self, headers: HeaderMap) -> ClientBuilder {
736
+ crate::util::replace_headers(&mut self.config.headers, headers);
737
+ self
738
+ }
739
+
740
+ /// Sets the original headers for every request.
741
+ #[inline]
742
+ pub fn orig_headers(mut self, orig_headers: OrigHeaderMap) -> ClientBuilder {
743
+ self.config.orig_headers.extend(orig_headers);
744
+ self
745
+ }
746
+
747
+ /// Enable a persistent cookie store for the client.
748
+ ///
749
+ /// Cookies received in responses will be preserved and included in
750
+ /// additional requests.
751
+ ///
752
+ /// By default, no cookie store is used.
753
+ ///
754
+ /// # Optional
755
+ ///
756
+ /// This requires the optional `cookies` feature to be enabled.
757
+ #[inline]
758
+ #[cfg(feature = "cookies")]
759
+ #[cfg_attr(docsrs, doc(cfg(feature = "cookies")))]
760
+ pub fn cookie_store(mut self, enable: bool) -> ClientBuilder {
761
+ if enable {
762
+ self.cookie_provider(Arc::new(cookie::Jar::default()))
763
+ } else {
764
+ self.config.cookie_store = None;
765
+ self
766
+ }
767
+ }
768
+
769
+ /// Set the persistent cookie store for the client.
770
+ ///
771
+ /// Cookies received in responses will be passed to this store, and
772
+ /// additional requests will query this store for cookies.
773
+ ///
774
+ /// By default, no cookie store is used.
775
+ ///
776
+ /// # Optional
777
+ ///
778
+ /// This requires the optional `cookies` feature to be enabled.
779
+ #[inline]
780
+ #[cfg(feature = "cookies")]
781
+ #[cfg_attr(docsrs, doc(cfg(feature = "cookies")))]
782
+ pub fn cookie_provider<C: cookie::IntoCookieStore>(mut self, cookie_store: C) -> ClientBuilder {
783
+ self.config.cookie_store = Some(cookie_store.into_shared());
784
+ self
785
+ }
786
+
787
+ /// Enable auto gzip decompression by checking the `Content-Encoding` response header.
788
+ ///
789
+ /// If auto gzip decompression is turned on:
790
+ ///
791
+ /// - When sending a request and if the request's headers do not already contain an
792
+ /// `Accept-Encoding` **and** `Range` values, the `Accept-Encoding` header is set to `gzip`.
793
+ /// The request body is **not** automatically compressed.
794
+ /// - When receiving a response, if its headers contain a `Content-Encoding` value of `gzip`,
795
+ /// both `Content-Encoding` and `Content-Length` are removed from the headers' set. The
796
+ /// response body is automatically decompressed.
797
+ ///
798
+ /// If the `gzip` feature is turned on, the default option is enabled.
799
+ ///
800
+ /// # Optional
801
+ ///
802
+ /// This requires the optional `gzip` feature to be enabled
803
+ #[inline]
804
+ #[cfg(feature = "gzip")]
805
+ #[cfg_attr(docsrs, doc(cfg(feature = "gzip")))]
806
+ pub fn gzip(mut self, enable: bool) -> ClientBuilder {
807
+ self.config.accept_encoding.gzip = enable;
808
+ self
809
+ }
810
+
811
+ /// Enable auto brotli decompression by checking the `Content-Encoding` response header.
812
+ ///
813
+ /// If auto brotli decompression is turned on:
814
+ ///
815
+ /// - When sending a request and if the request's headers do not already contain an
816
+ /// `Accept-Encoding` **and** `Range` values, the `Accept-Encoding` header is set to `br`. The
817
+ /// request body is **not** automatically compressed.
818
+ /// - When receiving a response, if its headers contain a `Content-Encoding` value of `br`, both
819
+ /// `Content-Encoding` and `Content-Length` are removed from the headers' set. The response
820
+ /// body is automatically decompressed.
821
+ ///
822
+ /// If the `brotli` feature is turned on, the default option is enabled.
823
+ ///
824
+ /// # Optional
825
+ ///
826
+ /// This requires the optional `brotli` feature to be enabled
827
+ #[inline]
828
+ #[cfg(feature = "brotli")]
829
+ #[cfg_attr(docsrs, doc(cfg(feature = "brotli")))]
830
+ pub fn brotli(mut self, enable: bool) -> ClientBuilder {
831
+ self.config.accept_encoding.brotli = enable;
832
+ self
833
+ }
834
+
835
+ /// Enable auto zstd decompression by checking the `Content-Encoding` response header.
836
+ ///
837
+ /// If auto zstd decompression is turned on:
838
+ ///
839
+ /// - When sending a request and if the request's headers do not already contain an
840
+ /// `Accept-Encoding` **and** `Range` values, the `Accept-Encoding` header is set to `zstd`.
841
+ /// The request body is **not** automatically compressed.
842
+ /// - When receiving a response, if its headers contain a `Content-Encoding` value of `zstd`,
843
+ /// both `Content-Encoding` and `Content-Length` are removed from the headers' set. The
844
+ /// response body is automatically decompressed.
845
+ ///
846
+ /// If the `zstd` feature is turned on, the default option is enabled.
847
+ ///
848
+ /// # Optional
849
+ ///
850
+ /// This requires the optional `zstd` feature to be enabled
851
+ #[inline]
852
+ #[cfg(feature = "zstd")]
853
+ #[cfg_attr(docsrs, doc(cfg(feature = "zstd")))]
854
+ pub fn zstd(mut self, enable: bool) -> ClientBuilder {
855
+ self.config.accept_encoding.zstd = enable;
856
+ self
857
+ }
858
+
859
+ /// Enable auto deflate decompression by checking the `Content-Encoding` response header.
860
+ ///
861
+ /// If auto deflate decompression is turned on:
862
+ ///
863
+ /// - When sending a request and if the request's headers do not already contain an
864
+ /// `Accept-Encoding` **and** `Range` values, the `Accept-Encoding` header is set to
865
+ /// `deflate`. The request body is **not** automatically compressed.
866
+ /// - When receiving a response, if it's headers contain a `Content-Encoding` value that equals
867
+ /// to `deflate`, both values `Content-Encoding` and `Content-Length` are removed from the
868
+ /// headers' set. The response body is automatically decompressed.
869
+ ///
870
+ /// If the `deflate` feature is turned on, the default option is enabled.
871
+ ///
872
+ /// # Optional
873
+ ///
874
+ /// This requires the optional `deflate` feature to be enabled
875
+ #[inline]
876
+ #[cfg(feature = "deflate")]
877
+ #[cfg_attr(docsrs, doc(cfg(feature = "deflate")))]
878
+ pub fn deflate(mut self, enable: bool) -> ClientBuilder {
879
+ self.config.accept_encoding.deflate = enable;
880
+ self
881
+ }
882
+
883
+ /// Disable auto response body zstd decompression.
884
+ ///
885
+ /// This method exists even if the optional `zstd` feature is not enabled.
886
+ /// This can be used to ensure a `Client` doesn't use zstd decompression
887
+ /// even if another dependency were to enable the optional `zstd` feature.
888
+ #[inline]
889
+ pub fn no_zstd(self) -> ClientBuilder {
890
+ #[cfg(feature = "zstd")]
891
+ {
892
+ self.zstd(false)
893
+ }
894
+
895
+ #[cfg(not(feature = "zstd"))]
896
+ {
897
+ self
898
+ }
899
+ }
900
+
901
+ /// Disable auto response body gzip decompression.
902
+ ///
903
+ /// This method exists even if the optional `gzip` feature is not enabled.
904
+ /// This can be used to ensure a `Client` doesn't use gzip decompression
905
+ /// even if another dependency were to enable the optional `gzip` feature.
906
+ #[inline]
907
+ pub fn no_gzip(self) -> ClientBuilder {
908
+ #[cfg(feature = "gzip")]
909
+ {
910
+ self.gzip(false)
911
+ }
912
+
913
+ #[cfg(not(feature = "gzip"))]
914
+ {
915
+ self
916
+ }
917
+ }
918
+
919
+ /// Disable auto response body brotli decompression.
920
+ ///
921
+ /// This method exists even if the optional `brotli` feature is not enabled.
922
+ /// This can be used to ensure a `Client` doesn't use brotli decompression
923
+ /// even if another dependency were to enable the optional `brotli` feature.
924
+ #[inline]
925
+ pub fn no_brotli(self) -> ClientBuilder {
926
+ #[cfg(feature = "brotli")]
927
+ {
928
+ self.brotli(false)
929
+ }
930
+
931
+ #[cfg(not(feature = "brotli"))]
932
+ {
933
+ self
934
+ }
935
+ }
936
+
937
+ /// Disable auto response body deflate decompression.
938
+ ///
939
+ /// This method exists even if the optional `deflate` feature is not enabled.
940
+ /// This can be used to ensure a `Client` doesn't use deflate decompression
941
+ /// even if another dependency were to enable the optional `deflate` feature.
942
+ #[inline]
943
+ pub fn no_deflate(self) -> ClientBuilder {
944
+ #[cfg(feature = "deflate")]
945
+ {
946
+ self.deflate(false)
947
+ }
948
+
949
+ #[cfg(not(feature = "deflate"))]
950
+ {
951
+ self
952
+ }
953
+ }
954
+
955
+ // Redirect options
956
+
957
+ /// Set a `RedirectPolicy` for this client.
958
+ ///
959
+ /// Default will follow redirects up to a maximum of 10.
960
+ #[inline]
961
+ pub fn redirect(mut self, policy: redirect::Policy) -> ClientBuilder {
962
+ self.config.redirect_policy = policy;
963
+ self
964
+ }
965
+
966
+ /// Enable or disable automatic setting of the `Referer` header.
967
+ ///
968
+ /// Default is `true`.
969
+ #[inline]
970
+ pub fn referer(mut self, enable: bool) -> ClientBuilder {
971
+ self.config.referer = enable;
972
+ self
973
+ }
974
+
975
+ // Retry options
976
+
977
+ /// Set a request retry policy.
978
+ pub fn retry(mut self, policy: retry::Policy) -> ClientBuilder {
979
+ self.config.retry_policy = policy;
980
+ self
981
+ }
982
+
983
+ // Proxy options
984
+
985
+ /// Add a `Proxy` to the list of proxies the `Client` will use.
986
+ ///
987
+ /// # Note
988
+ ///
989
+ /// Adding a proxy will disable the automatic usage of the "system" proxy.
990
+ ///
991
+ /// # Example
992
+ /// ```
993
+ /// use wreq::{Client, Proxy};
994
+ ///
995
+ /// let proxy = Proxy::http("http://proxy:8080").unwrap();
996
+ /// let client = Client::builder().proxy(proxy).build().unwrap();
997
+ /// ```
998
+ #[inline]
999
+ pub fn proxy(mut self, proxy: Proxy) -> ClientBuilder {
1000
+ self.config.proxies.push(proxy.into_matcher());
1001
+ self.config.auto_sys_proxy = false;
1002
+ self
1003
+ }
1004
+
1005
+ /// Clear all `Proxies`, so `Client` will use no proxy anymore.
1006
+ ///
1007
+ /// # Note
1008
+ /// To add a proxy exclusion list, use [crate::proxy::Proxy::no_proxy()]
1009
+ /// on all desired proxies instead.
1010
+ ///
1011
+ /// This also disables the automatic usage of the "system" proxy.
1012
+ #[inline]
1013
+ pub fn no_proxy(mut self) -> ClientBuilder {
1014
+ self.config.proxies.clear();
1015
+ self.config.auto_sys_proxy = false;
1016
+ self
1017
+ }
1018
+
1019
+ // Timeout options
1020
+
1021
+ /// Enables a request timeout.
1022
+ ///
1023
+ /// The timeout is applied from when the request starts connecting until the
1024
+ /// response body has finished.
1025
+ ///
1026
+ /// Default is no timeout.
1027
+ #[inline]
1028
+ pub fn timeout(mut self, timeout: Duration) -> ClientBuilder {
1029
+ self.config.timeout_options.total_timeout(timeout);
1030
+ self
1031
+ }
1032
+
1033
+ /// Set a timeout for only the read phase of a `Client`.
1034
+ ///
1035
+ /// Default is `None`.
1036
+ #[inline]
1037
+ pub fn read_timeout(mut self, timeout: Duration) -> ClientBuilder {
1038
+ self.config.timeout_options.read_timeout(timeout);
1039
+ self
1040
+ }
1041
+
1042
+ /// Set a timeout for only the connect phase of a `Client`.
1043
+ ///
1044
+ /// Default is `None`.
1045
+ ///
1046
+ /// # Note
1047
+ ///
1048
+ /// This **requires** the futures be executed in a tokio runtime with
1049
+ /// a tokio timer enabled.
1050
+ #[inline]
1051
+ pub fn connect_timeout(mut self, timeout: Duration) -> ClientBuilder {
1052
+ self.config.connect_timeout = Some(timeout);
1053
+ self
1054
+ }
1055
+
1056
+ /// Set whether connections should emit verbose logs.
1057
+ ///
1058
+ /// Enabling this option will emit [log][] messages at the `TRACE` level
1059
+ /// for read and write operations on connections.
1060
+ ///
1061
+ /// [log]: https://crates.io/crates/log
1062
+ #[inline]
1063
+ pub fn connection_verbose(mut self, verbose: bool) -> ClientBuilder {
1064
+ self.config.connection_verbose = verbose;
1065
+ self
1066
+ }
1067
+
1068
+ // HTTP options
1069
+
1070
+ /// Set an optional timeout for idle sockets being kept-alive.
1071
+ ///
1072
+ /// Pass `None` to disable timeout.
1073
+ ///
1074
+ /// Default is 90 seconds.
1075
+ #[inline]
1076
+ pub fn pool_idle_timeout<D>(mut self, val: D) -> ClientBuilder
1077
+ where
1078
+ D: Into<Option<Duration>>,
1079
+ {
1080
+ self.config.pool_idle_timeout = val.into();
1081
+ self
1082
+ }
1083
+
1084
+ /// Sets the maximum idle connection per host allowed in the pool.
1085
+ #[inline]
1086
+ pub fn pool_max_idle_per_host(mut self, max: usize) -> ClientBuilder {
1087
+ self.config.pool_max_idle_per_host = max;
1088
+ self
1089
+ }
1090
+
1091
+ /// Sets the maximum number of connections in the pool.
1092
+ #[inline]
1093
+ pub fn pool_max_size(mut self, max: usize) -> ClientBuilder {
1094
+ self.config.pool_max_size = NonZeroUsize::new(max);
1095
+ self
1096
+ }
1097
+
1098
+ /// Restrict the Client to be used with HTTPS only requests.
1099
+ ///
1100
+ /// Defaults to false.
1101
+ #[inline]
1102
+ pub fn https_only(mut self, enabled: bool) -> ClientBuilder {
1103
+ self.config.https_only = enabled;
1104
+ self
1105
+ }
1106
+
1107
+ /// Only use HTTP/1.
1108
+ #[inline]
1109
+ pub fn http1_only(mut self) -> ClientBuilder {
1110
+ self.config.http_version_pref = HttpVersionPref::Http1;
1111
+ self
1112
+ }
1113
+
1114
+ /// Only use HTTP/2.
1115
+ #[inline]
1116
+ pub fn http2_only(mut self) -> ClientBuilder {
1117
+ self.config.http_version_pref = HttpVersionPref::Http2;
1118
+ self
1119
+ }
1120
+
1121
+ /// Sets the HTTP/1 options for the client.
1122
+ #[inline]
1123
+ pub fn http1_options<T>(mut self, options: T) -> ClientBuilder
1124
+ where
1125
+ T: Into<Option<Http1Options>>,
1126
+ {
1127
+ self.config.http1_options = options.into();
1128
+ self
1129
+ }
1130
+
1131
+ /// Sets the HTTP/2 options for the client.
1132
+ #[inline]
1133
+ pub fn http2_options<T>(mut self, options: T) -> ClientBuilder
1134
+ where
1135
+ T: Into<Option<Http2Options>>,
1136
+ {
1137
+ self.config.http2_options = options.into();
1138
+ self
1139
+ }
1140
+
1141
+ // TCP options
1142
+
1143
+ /// Set whether sockets have `TCP_NODELAY` enabled.
1144
+ ///
1145
+ /// Default is `true`.
1146
+ #[inline]
1147
+ pub fn tcp_nodelay(mut self, enabled: bool) -> ClientBuilder {
1148
+ self.config.tcp_nodelay = enabled;
1149
+ self
1150
+ }
1151
+
1152
+ /// Set that all sockets have `SO_KEEPALIVE` set with the supplied duration.
1153
+ ///
1154
+ /// If `None`, the option will not be set.
1155
+ ///
1156
+ /// Default is 15 seconds.
1157
+ #[inline]
1158
+ pub fn tcp_keepalive<D>(mut self, val: D) -> ClientBuilder
1159
+ where
1160
+ D: Into<Option<Duration>>,
1161
+ {
1162
+ self.config.tcp_keepalive = val.into();
1163
+ self
1164
+ }
1165
+
1166
+ /// Set that all sockets have `SO_KEEPALIVE` set with the supplied interval.
1167
+ ///
1168
+ /// If `None`, the option will not be set.
1169
+ ///
1170
+ /// Default is 15 seconds.
1171
+ #[inline]
1172
+ pub fn tcp_keepalive_interval<D>(mut self, val: D) -> ClientBuilder
1173
+ where
1174
+ D: Into<Option<Duration>>,
1175
+ {
1176
+ self.config.tcp_keepalive_interval = val.into();
1177
+ self
1178
+ }
1179
+
1180
+ /// Set that all sockets have `SO_KEEPALIVE` set with the supplied retry count.
1181
+ ///
1182
+ /// If `None`, the option will not be set.
1183
+ ///
1184
+ /// Default is 3 retries.
1185
+ #[inline]
1186
+ pub fn tcp_keepalive_retries<C>(mut self, retries: C) -> ClientBuilder
1187
+ where
1188
+ C: Into<Option<u32>>,
1189
+ {
1190
+ self.config.tcp_keepalive_retries = retries.into();
1191
+ self
1192
+ }
1193
+
1194
+ /// Set that all sockets have `TCP_USER_TIMEOUT` set with the supplied duration.
1195
+ ///
1196
+ /// This option controls how long transmitted data may remain unacknowledged before
1197
+ /// the connection is force-closed.
1198
+ ///
1199
+ /// If `None`, the option will not be set.
1200
+ ///
1201
+ /// Default is 30 seconds.
1202
+ #[inline]
1203
+ #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
1204
+ #[cfg_attr(
1205
+ docsrs,
1206
+ doc(cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))
1207
+ )]
1208
+ pub fn tcp_user_timeout<D>(mut self, val: D) -> ClientBuilder
1209
+ where
1210
+ D: Into<Option<Duration>>,
1211
+ {
1212
+ self.config.tcp_user_timeout = val.into();
1213
+ self
1214
+ }
1215
+
1216
+ /// Set whether sockets have `SO_REUSEADDR` enabled.
1217
+ #[inline]
1218
+ pub fn tcp_reuse_address(mut self, enabled: bool) -> ClientBuilder {
1219
+ self.config.tcp_reuse_address = enabled;
1220
+ self
1221
+ }
1222
+
1223
+ /// Sets the size of the TCP send buffer on this client socket.
1224
+ ///
1225
+ /// On most operating systems, this sets the `SO_SNDBUF` socket option.
1226
+ #[inline]
1227
+ pub fn tcp_send_buffer_size<S>(mut self, size: S) -> ClientBuilder
1228
+ where
1229
+ S: Into<Option<usize>>,
1230
+ {
1231
+ self.config.tcp_send_buffer_size = size.into();
1232
+ self
1233
+ }
1234
+
1235
+ /// Sets the size of the TCP receive buffer on this client socket.
1236
+ ///
1237
+ /// On most operating systems, this sets the `SO_RCVBUF` socket option.
1238
+ #[inline]
1239
+ pub fn tcp_recv_buffer_size<S>(mut self, size: S) -> ClientBuilder
1240
+ where
1241
+ S: Into<Option<usize>>,
1242
+ {
1243
+ self.config.tcp_recv_buffer_size = size.into();
1244
+ self
1245
+ }
1246
+
1247
+ /// Set timeout for [RFC 6555 (Happy Eyeballs)][RFC 6555] algorithm.
1248
+ ///
1249
+ /// If hostname resolves to both IPv4 and IPv6 addresses and connection
1250
+ /// cannot be established using preferred address family before timeout
1251
+ /// elapses, then connector will in parallel attempt connection using other
1252
+ /// address family.
1253
+ ///
1254
+ /// If `None`, parallel connection attempts are disabled.
1255
+ ///
1256
+ /// Default is 300 milliseconds.
1257
+ ///
1258
+ /// [RFC 6555]: https://tools.ietf.org/html/rfc6555
1259
+ #[inline]
1260
+ pub fn tcp_happy_eyeballs_timeout<D>(mut self, val: D) -> ClientBuilder
1261
+ where
1262
+ D: Into<Option<Duration>>,
1263
+ {
1264
+ self.config.tcp_happy_eyeballs_timeout = val.into();
1265
+ self
1266
+ }
1267
+
1268
+ /// Bind to a local IP Address.
1269
+ ///
1270
+ /// # Example
1271
+ ///
1272
+ /// ```
1273
+ /// use std::net::IpAddr;
1274
+ /// let local_addr = IpAddr::from([12, 4, 1, 8]);
1275
+ /// let client = wreq::Client::builder()
1276
+ /// .local_address(local_addr)
1277
+ /// .build()
1278
+ /// .unwrap();
1279
+ /// ```
1280
+ #[inline]
1281
+ pub fn local_address<T>(mut self, addr: T) -> ClientBuilder
1282
+ where
1283
+ T: Into<Option<IpAddr>>,
1284
+ {
1285
+ self.config
1286
+ .socket_bind_options
1287
+ .set_local_address(addr.into());
1288
+ self
1289
+ }
1290
+
1291
+ /// Set that all sockets are bound to the configured IPv4 or IPv6 address (depending on host's
1292
+ /// preferences) before connection.
1293
+ ///
1294
+ /// # Example
1295
+ /// ///
1296
+ /// ```
1297
+ /// use std::net::{Ipv4Addr, Ipv6Addr};
1298
+ /// let ipv4 = Ipv4Addr::new(127, 0, 0, 1);
1299
+ /// let ipv6 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
1300
+ /// let client = wreq::Client::builder()
1301
+ /// .local_addresses(ipv4, ipv6)
1302
+ /// .build()
1303
+ /// .unwrap();
1304
+ /// ```
1305
+ #[inline]
1306
+ pub fn local_addresses<V4, V6>(mut self, ipv4: V4, ipv6: V6) -> ClientBuilder
1307
+ where
1308
+ V4: Into<Option<Ipv4Addr>>,
1309
+ V6: Into<Option<Ipv6Addr>>,
1310
+ {
1311
+ self.config
1312
+ .socket_bind_options
1313
+ .set_local_addresses(ipv4, ipv6);
1314
+ self
1315
+ }
1316
+
1317
+ /// Bind connections only on the specified network interface.
1318
+ ///
1319
+ /// This option is only available on the following operating systems:
1320
+ ///
1321
+ /// - Android
1322
+ /// - Fuchsia
1323
+ /// - Linux,
1324
+ /// - macOS and macOS-like systems (iOS, tvOS, watchOS and visionOS)
1325
+ /// - Solaris and illumos
1326
+ ///
1327
+ /// On Android, Linux, and Fuchsia, this uses the
1328
+ /// [`SO_BINDTODEVICE`][man-7-socket] socket option. On macOS and macOS-like
1329
+ /// systems, Solaris, and illumos, this instead uses the [`IP_BOUND_IF` and
1330
+ /// `IPV6_BOUND_IF`][man-7p-ip] socket options (as appropriate).
1331
+ ///
1332
+ /// Note that connections will fail if the provided interface name is not a
1333
+ /// network interface that currently exists when a connection is established.
1334
+ ///
1335
+ /// # Example
1336
+ ///
1337
+ /// ```
1338
+ /// # fn doc() -> Result<(), wreq::Error> {
1339
+ /// let interface = "lo";
1340
+ /// let client = wreq::Client::builder()
1341
+ /// .interface(interface)
1342
+ /// .build()?;
1343
+ /// # Ok(())
1344
+ /// # }
1345
+ /// ```
1346
+ ///
1347
+ /// [man-7-socket]: https://man7.org/linux/man-pages/man7/socket.7.html
1348
+ /// [man-7p-ip]: https://docs.oracle.com/cd/E86824_01/html/E54777/ip-7p.html
1349
+ #[inline]
1350
+ #[cfg(any(
1351
+ target_os = "android",
1352
+ target_os = "fuchsia",
1353
+ target_os = "illumos",
1354
+ target_os = "ios",
1355
+ target_os = "linux",
1356
+ target_os = "macos",
1357
+ target_os = "solaris",
1358
+ target_os = "tvos",
1359
+ target_os = "visionos",
1360
+ target_os = "watchos",
1361
+ ))]
1362
+ #[cfg_attr(
1363
+ docsrs,
1364
+ doc(cfg(any(
1365
+ target_os = "android",
1366
+ target_os = "fuchsia",
1367
+ target_os = "illumos",
1368
+ target_os = "ios",
1369
+ target_os = "linux",
1370
+ target_os = "macos",
1371
+ target_os = "solaris",
1372
+ target_os = "tvos",
1373
+ target_os = "visionos",
1374
+ target_os = "watchos",
1375
+ )))
1376
+ )]
1377
+ pub fn interface<T>(mut self, interface: T) -> ClientBuilder
1378
+ where
1379
+ T: Into<std::borrow::Cow<'static, str>>,
1380
+ {
1381
+ self.config.socket_bind_options.set_interface(interface);
1382
+ self
1383
+ }
1384
+
1385
+ // TLS options
1386
+
1387
+ /// Sets the identity to be used for client certificate authentication.
1388
+ #[inline]
1389
+ pub fn tls_identity(mut self, identity: Identity) -> ClientBuilder {
1390
+ self.config.tls_identity = Some(identity);
1391
+ self
1392
+ }
1393
+
1394
+ /// Sets the verify certificate store for the client.
1395
+ ///
1396
+ /// This method allows you to specify a custom verify certificate store to be used
1397
+ /// for TLS connections. By default, the system's verify certificate store is used.
1398
+ #[inline]
1399
+ pub fn tls_cert_store(mut self, store: CertStore) -> ClientBuilder {
1400
+ self.config.tls_cert_store = Some(store);
1401
+ self
1402
+ }
1403
+
1404
+ /// Controls the use of certificate validation.
1405
+ ///
1406
+ /// Defaults to `true`.
1407
+ ///
1408
+ /// # Warning
1409
+ ///
1410
+ /// You should think very carefully before using this method. If
1411
+ /// invalid certificates are trusted, *any* certificate for *any* site
1412
+ /// will be trusted for use. This includes expired certificates. This
1413
+ /// introduces significant vulnerabilities, and should only be used
1414
+ /// as a last resort.
1415
+ #[inline]
1416
+ pub fn tls_cert_verification(mut self, cert_verification: bool) -> ClientBuilder {
1417
+ self.config.tls_cert_verification = cert_verification;
1418
+ self
1419
+ }
1420
+
1421
+ /// Configures the use of hostname verification when connecting.
1422
+ ///
1423
+ /// Defaults to `true`.
1424
+ /// # Warning
1425
+ ///
1426
+ /// You should think very carefully before you use this method. If hostname verification is not
1427
+ /// used, *any* valid certificate for *any* site will be trusted for use from any other. This
1428
+ /// introduces a significant vulnerability to man-in-the-middle attacks.
1429
+ #[inline]
1430
+ pub fn tls_verify_hostname(mut self, verify_hostname: bool) -> ClientBuilder {
1431
+ self.config.tls_verify_hostname = verify_hostname;
1432
+ self
1433
+ }
1434
+
1435
+ /// Configures the use of Server Name Indication (SNI) when connecting.
1436
+ ///
1437
+ /// Defaults to `true`.
1438
+ #[inline]
1439
+ pub fn tls_sni(mut self, tls_sni: bool) -> ClientBuilder {
1440
+ self.config.tls_sni = tls_sni;
1441
+ self
1442
+ }
1443
+
1444
+ /// Configures TLS key logging for the client.
1445
+ #[inline]
1446
+ pub fn tls_keylog(mut self, keylog: KeyLog) -> ClientBuilder {
1447
+ self.config.tls_keylog = Some(keylog);
1448
+ self
1449
+ }
1450
+
1451
+ /// Set the minimum required TLS version for connections.
1452
+ ///
1453
+ /// By default the TLS backend's own default is used.
1454
+ #[inline]
1455
+ pub fn tls_min_version(mut self, version: TlsVersion) -> ClientBuilder {
1456
+ self.config.tls_min_version = Some(version);
1457
+ self
1458
+ }
1459
+
1460
+ /// Set the maximum allowed TLS version for connections.
1461
+ ///
1462
+ /// By default there's no maximum.
1463
+ #[inline]
1464
+ pub fn tls_max_version(mut self, version: TlsVersion) -> ClientBuilder {
1465
+ self.config.tls_max_version = Some(version);
1466
+ self
1467
+ }
1468
+
1469
+ /// Add TLS information as `TlsInfo` extension to responses.
1470
+ ///
1471
+ /// # Optional
1472
+ ///
1473
+ /// feature to be enabled.
1474
+ #[inline]
1475
+ pub fn tls_info(mut self, tls_info: bool) -> ClientBuilder {
1476
+ self.config.tls_info = tls_info;
1477
+ self
1478
+ }
1479
+
1480
+ /// Sets the TLS session cache.
1481
+ ///
1482
+ /// By default, an in-memory LRU cache is used. Use this method to provide
1483
+ /// a custom [`TlsSessionCache`] implementation (e.g., file-based or distributed).
1484
+ #[inline]
1485
+ pub fn tls_session_cache<S: IntoTlsSessionCache>(mut self, store: S) -> ClientBuilder {
1486
+ self.config.tls_session_cache = Some(store.into_shared());
1487
+ self
1488
+ }
1489
+
1490
+ /// Sets the TLS options for the client.
1491
+ #[inline]
1492
+ pub fn tls_options<T>(mut self, options: T) -> ClientBuilder
1493
+ where
1494
+ T: Into<Option<TlsOptions>>,
1495
+ {
1496
+ self.config.tls_options = options.into();
1497
+ self
1498
+ }
1499
+
1500
+ // DNS options
1501
+
1502
+ /// Disables the hickory-dns async resolver.
1503
+ ///
1504
+ /// This method exists even if the optional `hickory-dns` feature is not enabled.
1505
+ /// This can be used to ensure a `Client` doesn't use the hickory-dns async resolver
1506
+ /// even if another dependency were to enable the optional `hickory-dns` feature.
1507
+ #[inline]
1508
+ #[cfg(feature = "hickory-dns")]
1509
+ #[cfg_attr(docsrs, doc(cfg(feature = "hickory-dns")))]
1510
+ pub fn no_hickory_dns(mut self) -> ClientBuilder {
1511
+ self.config.hickory_dns = false;
1512
+ self
1513
+ }
1514
+
1515
+ /// Override DNS resolution for specific domains to a particular IP address.
1516
+ ///
1517
+ /// Warning
1518
+ ///
1519
+ /// Since the DNS protocol has no notion of ports, if you wish to send
1520
+ /// traffic to a particular port you must include this port in the URI
1521
+ /// itself, any port in the overridden addr will be ignored and traffic sent
1522
+ /// to the conventional port for the given scheme (e.g. 80 for http).
1523
+ #[inline]
1524
+ pub fn resolve<D>(self, domain: D, addr: SocketAddr) -> ClientBuilder
1525
+ where
1526
+ D: Into<Cow<'static, str>>,
1527
+ {
1528
+ self.resolve_to_addrs(domain, std::iter::once(addr))
1529
+ }
1530
+
1531
+ /// Override DNS resolution for specific domains to particular IP addresses.
1532
+ ///
1533
+ /// Warning
1534
+ ///
1535
+ /// Since the DNS protocol has no notion of ports, if you wish to send
1536
+ /// traffic to a particular port you must include this port in the URI
1537
+ /// itself, any port in the overridden addresses will be ignored and traffic sent
1538
+ /// to the conventional port for the given scheme (e.g. 80 for http).
1539
+ #[inline]
1540
+ pub fn resolve_to_addrs<D, A>(mut self, domain: D, addrs: A) -> ClientBuilder
1541
+ where
1542
+ D: Into<Cow<'static, str>>,
1543
+ A: IntoIterator<Item = SocketAddr>,
1544
+ {
1545
+ self.config
1546
+ .dns_overrides
1547
+ .insert(domain.into(), addrs.into_iter().collect());
1548
+ self
1549
+ }
1550
+
1551
+ /// Override the DNS resolver implementation.
1552
+ ///
1553
+ /// Pass any type implementing `IntoResolve`.
1554
+ /// Overrides for specific names passed to `resolve` and `resolve_to_addrs` will
1555
+ /// still be applied on top of this resolver.
1556
+ #[inline]
1557
+ pub fn dns_resolver<R: IntoResolve>(mut self, resolver: R) -> ClientBuilder {
1558
+ self.config.dns_resolver = Some(resolver.into_shared());
1559
+ self
1560
+ }
1561
+
1562
+ // Tower middleware options
1563
+
1564
+ /// Adds a new Tower [`Layer`](https://docs.rs/tower/latest/tower/trait.Layer.html) to the
1565
+ /// request [`Service`](https://docs.rs/tower/latest/tower/trait.Service.html) which is responsible
1566
+ /// for request processing.
1567
+ ///
1568
+ /// Each subsequent invocation of this function will wrap previous layers.
1569
+ ///
1570
+ /// If configured, the `timeout` will be the outermost layer.
1571
+ ///
1572
+ /// Example usage:
1573
+ /// ```
1574
+ /// use std::time::Duration;
1575
+ ///
1576
+ /// let client = wreq::Client::builder()
1577
+ /// .timeout(Duration::from_millis(200))
1578
+ /// .layer(tower::timeout::TimeoutLayer::new(Duration::from_millis(50)))
1579
+ /// .build()
1580
+ /// .unwrap();
1581
+ /// ```
1582
+ #[inline]
1583
+ pub fn layer<L>(mut self, layer: L) -> ClientBuilder
1584
+ where
1585
+ L: Layer<
1586
+ BoxCloneSyncService<
1587
+ http::Request<Body>,
1588
+ http::Response<MaybeDecompressionBody<Incoming>>,
1589
+ BoxError,
1590
+ >,
1591
+ > + Clone
1592
+ + Send
1593
+ + Sync
1594
+ + 'static,
1595
+ L::Service: Service<
1596
+ http::Request<Body>,
1597
+ Response = http::Response<MaybeDecompressionBody<Incoming>>,
1598
+ Error = BoxError,
1599
+ > + Clone
1600
+ + Send
1601
+ + Sync
1602
+ + 'static,
1603
+ <L::Service as Service<http::Request<Body>>>::Future: Send + 'static,
1604
+ {
1605
+ let layer = BoxCloneSyncServiceLayer::new(layer);
1606
+ self.config.layers.push(layer);
1607
+ self
1608
+ }
1609
+
1610
+ /// Adds a new Tower [`Layer`](https://docs.rs/tower/latest/tower/trait.Layer.html) to the
1611
+ /// base connector [`Service`](https://docs.rs/tower/latest/tower/trait.Service.html) which
1612
+ /// is responsible for connection establishment.a
1613
+ ///
1614
+ /// Each subsequent invocation of this function will wrap previous layers.
1615
+ ///
1616
+ /// If configured, the `connect_timeout` will be the outermost layer.
1617
+ ///
1618
+ /// Example usage:
1619
+ /// ```
1620
+ /// use std::time::Duration;
1621
+ ///
1622
+ /// let client = wreq::Client::builder()
1623
+ /// // resolved to outermost layer, meaning while we are waiting on concurrency limit
1624
+ /// .connect_timeout(Duration::from_millis(200))
1625
+ /// // underneath the concurrency check, so only after concurrency limit lets us through
1626
+ /// .connector_layer(tower::timeout::TimeoutLayer::new(Duration::from_millis(50)))
1627
+ /// .connector_layer(tower::limit::concurrency::ConcurrencyLimitLayer::new(2))
1628
+ /// .build()
1629
+ /// .unwrap();
1630
+ /// ```
1631
+ #[inline]
1632
+ pub fn connector_layer<L>(mut self, layer: L) -> ClientBuilder
1633
+ where
1634
+ L: Layer<BoxedConnectorService> + Clone + Send + Sync + 'static,
1635
+ L::Service:
1636
+ Service<Unnameable, Response = Conn, Error = BoxError> + Clone + Send + Sync + 'static,
1637
+ <L::Service as Service<Unnameable>>::Future: Send + 'static,
1638
+ {
1639
+ let layer = BoxCloneSyncServiceLayer::new(layer);
1640
+ self.config.connector_layers.push(layer);
1641
+ self
1642
+ }
1643
+
1644
+ // TLS/HTTP2 emulation options
1645
+
1646
+ /// Configures the client builder to emulation the specified HTTP context.
1647
+ ///
1648
+ /// This method sets the necessary headers, HTTP/1 and HTTP/2 options configurations, and TLS
1649
+ /// options config to use the specified HTTP context. It allows the client to mimic the
1650
+ /// behavior of different versions or setups, which can be useful for testing or ensuring
1651
+ /// compatibility with various environments.
1652
+ ///
1653
+ /// # Note
1654
+ /// This will overwrite the existing configuration.
1655
+ /// You must set emulation before you can perform subsequent HTTP1/HTTP2/TLS fine-tuning.
1656
+ #[inline]
1657
+ pub fn emulation<T: IntoEmulation>(self, emulation: T) -> ClientBuilder {
1658
+ let emulation = emulation.into_emulation();
1659
+ self.tls_options(emulation.tls_options)
1660
+ .http1_options(emulation.http1_options)
1661
+ .http2_options(emulation.http2_options)
1662
+ .default_headers(emulation.headers)
1663
+ .orig_headers(emulation.orig_headers)
1664
+ }
1665
+ }