wreq-rb 0.3.0

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