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,818 @@
1
+ use std::{
2
+ convert::TryFrom,
3
+ fmt,
4
+ future::Future,
5
+ net::{IpAddr, Ipv4Addr, Ipv6Addr},
6
+ time::Duration,
7
+ };
8
+
9
+ use http::{Extensions, Request as HttpRequest, Uri, Version};
10
+ #[cfg(any(feature = "query", feature = "form", feature = "json"))]
11
+ use serde::Serialize;
12
+ #[cfg(feature = "multipart")]
13
+ use {super::multipart, bytes::Bytes, http::header::CONTENT_LENGTH};
14
+ #[cfg(feature = "cookies")]
15
+ use {
16
+ crate::cookie::{CookieStore, IntoCookieStore},
17
+ std::sync::Arc,
18
+ };
19
+
20
+ #[cfg(any(
21
+ feature = "gzip",
22
+ feature = "zstd",
23
+ feature = "brotli",
24
+ feature = "deflate",
25
+ ))]
26
+ use super::layer::decoder::AcceptEncoding;
27
+ use super::{
28
+ Body, EmulationFactory, Response,
29
+ http::{Client, future::Pending},
30
+ layer::{
31
+ config::{DefaultHeaders, RequestOptions},
32
+ timeout::TimeoutOptions,
33
+ },
34
+ };
35
+ #[cfg(any(feature = "multipart", feature = "form", feature = "json"))]
36
+ use crate::header::CONTENT_TYPE;
37
+ use crate::{
38
+ Error, Method, Proxy,
39
+ config::{RequestConfig, RequestConfigValue},
40
+ ext::UriExt,
41
+ header::{AUTHORIZATION, HeaderMap, HeaderName, HeaderValue, OrigHeaderMap},
42
+ redirect,
43
+ };
44
+
45
+ /// A request which can be executed with [`Client::execute()`].
46
+ #[derive(Debug)]
47
+ pub struct Request(http::Request<Option<Body>>);
48
+
49
+ /// A builder to construct the properties of a [`Request`].
50
+ ///
51
+ /// To construct a [`RequestBuilder`], refer to the [`Client`] documentation.
52
+ #[must_use = "RequestBuilder does nothing until you 'send' it"]
53
+ pub struct RequestBuilder {
54
+ client: Client,
55
+ request: crate::Result<Request>,
56
+ }
57
+
58
+ impl Request {
59
+ /// Constructs a new [`Request`].
60
+ pub fn new(method: Method, uri: Uri) -> Self {
61
+ let mut request = http::Request::new(None);
62
+ *request.method_mut() = method;
63
+ *request.uri_mut() = uri;
64
+ Request(request)
65
+ }
66
+
67
+ /// Get the method.
68
+ #[inline]
69
+ pub fn method(&self) -> &Method {
70
+ self.0.method()
71
+ }
72
+
73
+ /// Get a mutable reference to the method.
74
+ #[inline]
75
+ pub fn method_mut(&mut self) -> &mut Method {
76
+ self.0.method_mut()
77
+ }
78
+
79
+ /// Get the uri.
80
+ #[inline]
81
+ pub fn uri(&self) -> &Uri {
82
+ self.0.uri()
83
+ }
84
+
85
+ /// Get a mutable reference to the uri.
86
+ #[inline]
87
+ pub fn uri_mut(&mut self) -> &mut Uri {
88
+ self.0.uri_mut()
89
+ }
90
+
91
+ /// Get the headers.
92
+ #[inline]
93
+ pub fn headers(&self) -> &HeaderMap {
94
+ self.0.headers()
95
+ }
96
+
97
+ /// Get a mutable reference to the headers.
98
+ #[inline]
99
+ pub fn headers_mut(&mut self) -> &mut HeaderMap {
100
+ self.0.headers_mut()
101
+ }
102
+
103
+ /// Get the body.
104
+ #[inline]
105
+ pub fn body(&self) -> Option<&Body> {
106
+ self.0.body().as_ref()
107
+ }
108
+
109
+ /// Get a mutable reference to the body.
110
+ #[inline]
111
+ pub fn body_mut(&mut self) -> &mut Option<Body> {
112
+ self.0.body_mut()
113
+ }
114
+
115
+ /// Get the http version.
116
+ #[inline]
117
+ pub fn version(&self) -> Option<Version> {
118
+ self.config::<RequestOptions>()
119
+ .and_then(RequestOptions::enforced_version)
120
+ }
121
+
122
+ /// Get a mutable reference to the http version.
123
+ #[inline]
124
+ pub fn version_mut(&mut self) -> &mut Option<Version> {
125
+ self.config_mut::<RequestOptions>()
126
+ .get_or_insert_default()
127
+ .enforced_version_mut()
128
+ }
129
+
130
+ /// Attempt to clone the request.
131
+ ///
132
+ /// `None` is returned if the request can not be cloned, i.e. if the body is a stream.
133
+ pub fn try_clone(&self) -> Option<Request> {
134
+ let body = match self.body() {
135
+ Some(body) => Some(body.try_clone()?),
136
+ None => None,
137
+ };
138
+ let mut req = Request::new(self.method().clone(), self.uri().clone());
139
+ *req.headers_mut() = self.headers().clone();
140
+ *req.version_mut() = self.version();
141
+ *req.extensions_mut() = self.extensions().clone();
142
+ *req.body_mut() = body;
143
+ Some(req)
144
+ }
145
+
146
+ #[inline]
147
+ pub(crate) fn extensions(&self) -> &Extensions {
148
+ self.0.extensions()
149
+ }
150
+
151
+ #[inline]
152
+ pub(crate) fn extensions_mut(&mut self) -> &mut Extensions {
153
+ self.0.extensions_mut()
154
+ }
155
+
156
+ #[inline]
157
+ pub(crate) fn config<T>(&self) -> Option<&T::Value>
158
+ where
159
+ T: RequestConfigValue,
160
+ {
161
+ RequestConfig::<T>::get(self.extensions())
162
+ }
163
+
164
+ #[inline]
165
+ pub(crate) fn config_mut<T>(&mut self) -> &mut Option<T::Value>
166
+ where
167
+ T: RequestConfigValue,
168
+ {
169
+ RequestConfig::<T>::get_mut(self.extensions_mut())
170
+ }
171
+ }
172
+
173
+ impl RequestBuilder {
174
+ pub(super) fn new(client: Client, request: crate::Result<Request>) -> RequestBuilder {
175
+ let mut builder = RequestBuilder { client, request };
176
+
177
+ let auth = builder
178
+ .request
179
+ .as_mut()
180
+ .ok()
181
+ .and_then(|req| extract_authority(req.uri_mut()));
182
+
183
+ if let Some((username, password)) = auth {
184
+ builder.basic_auth(username, password)
185
+ } else {
186
+ builder
187
+ }
188
+ }
189
+
190
+ /// Assemble a builder starting from an existing `Client` and a `Request`.
191
+ pub fn from_parts(client: Client, request: Request) -> RequestBuilder {
192
+ RequestBuilder {
193
+ client,
194
+ request: crate::Result::Ok(request),
195
+ }
196
+ }
197
+
198
+ /// Add a `Header` to this Request with ability to define if `header_value` is sensitive.
199
+ fn header_sensitive<K, V>(mut self, key: K, value: V, sensitive: bool) -> RequestBuilder
200
+ where
201
+ HeaderName: TryFrom<K>,
202
+ <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
203
+ HeaderValue: TryFrom<V>,
204
+ <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
205
+ {
206
+ let mut error = None;
207
+ if let Ok(ref mut req) = self.request {
208
+ match <HeaderName as TryFrom<K>>::try_from(key) {
209
+ Ok(key) => match <HeaderValue as TryFrom<V>>::try_from(value) {
210
+ Ok(mut value) => {
211
+ // We want to potentially make an non-sensitive header
212
+ // to be sensitive, not the reverse. So, don't turn off
213
+ // a previously sensitive header.
214
+ if sensitive {
215
+ value.set_sensitive(true);
216
+ }
217
+ req.headers_mut().append(key, value);
218
+ }
219
+ Err(e) => error = Some(Error::builder(e.into())),
220
+ },
221
+ Err(e) => error = Some(Error::builder(e.into())),
222
+ };
223
+ }
224
+ if let Some(err) = error {
225
+ self.request = Err(err);
226
+ }
227
+ self
228
+ }
229
+
230
+ /// Add a `Header` to this Request.
231
+ ///
232
+ /// If the header is already present, the value will be replaced.
233
+ #[inline]
234
+ pub fn header<K, V>(self, key: K, value: V) -> RequestBuilder
235
+ where
236
+ HeaderName: TryFrom<K>,
237
+ <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
238
+ HeaderValue: TryFrom<V>,
239
+ <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
240
+ {
241
+ self.header_sensitive(key, value, false)
242
+ }
243
+
244
+ /// Add a set of Headers to the existing ones on this Request.
245
+ ///
246
+ /// The headers will be merged in to any already set.
247
+ pub fn headers(mut self, headers: HeaderMap) -> RequestBuilder {
248
+ if let Ok(ref mut req) = self.request {
249
+ crate::util::replace_headers(req.headers_mut(), headers);
250
+ }
251
+ self
252
+ }
253
+
254
+ /// Set the original headers for this request.
255
+ pub fn orig_headers(mut self, orig_headers: OrigHeaderMap) -> RequestBuilder {
256
+ if let Ok(ref mut req) = self.request {
257
+ req.config_mut::<OrigHeaderMap>().replace(orig_headers);
258
+ }
259
+ self
260
+ }
261
+
262
+ /// Enable or disable client default headers for this request.
263
+ ///
264
+ /// By default, client default headers are included. Set to `false` to skip them.
265
+ pub fn default_headers(mut self, enable: bool) -> RequestBuilder {
266
+ if let Ok(ref mut req) = self.request {
267
+ req.config_mut::<DefaultHeaders>().replace(enable);
268
+ }
269
+ self
270
+ }
271
+
272
+ /// Enable HTTP authentication.
273
+ ///
274
+ /// ```rust
275
+ /// # use wreq::Error;
276
+ /// #
277
+ /// # async fn run() -> Result<(), Error> {
278
+ /// let client = wreq::Client::new();
279
+ /// let resp = client
280
+ /// .get("http://httpbin.org/get")
281
+ /// .auth("your_token_here")
282
+ /// .send()
283
+ /// .await?;
284
+ /// # Ok(())
285
+ /// # }
286
+ /// ```
287
+ pub fn auth<V>(self, token: V) -> RequestBuilder
288
+ where
289
+ HeaderValue: TryFrom<V>,
290
+ <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
291
+ {
292
+ self.header_sensitive(AUTHORIZATION, token, true)
293
+ }
294
+
295
+ /// Enable HTTP basic authentication.
296
+ ///
297
+ /// ```rust
298
+ /// # use wreq::Error;
299
+ ///
300
+ /// # async fn run() -> Result<(), Error> {
301
+ /// let client = wreq::Client::new();
302
+ /// let resp = client
303
+ /// .delete("http://httpbin.org/delete")
304
+ /// .basic_auth("admin", Some("good password"))
305
+ /// .send()
306
+ /// .await?;
307
+ /// # Ok(())
308
+ /// # }
309
+ /// ```
310
+ pub fn basic_auth<U, P>(self, username: U, password: Option<P>) -> RequestBuilder
311
+ where
312
+ U: fmt::Display,
313
+ P: fmt::Display,
314
+ {
315
+ let header_value = crate::util::basic_auth(username, password);
316
+ self.header_sensitive(AUTHORIZATION, header_value, true)
317
+ }
318
+
319
+ /// Enable HTTP bearer authentication.
320
+ ///
321
+ /// ```rust
322
+ /// # use wreq::Error;
323
+ /// #
324
+ /// # async fn run() -> Result<(), Error> {
325
+ /// let client = wreq::Client::new();
326
+ /// let resp = client
327
+ /// .get("http://httpbin.org/get")
328
+ /// .bearer_auth("your_token_here")
329
+ /// .send()
330
+ /// .await?;
331
+ /// # Ok(())
332
+ /// # }
333
+ /// ```
334
+ pub fn bearer_auth<T>(self, token: T) -> RequestBuilder
335
+ where
336
+ T: fmt::Display,
337
+ {
338
+ let header_value = format!("Bearer {token}");
339
+ self.header_sensitive(AUTHORIZATION, header_value, true)
340
+ }
341
+
342
+ /// Enables a request timeout.
343
+ ///
344
+ /// The timeout is applied from when the request starts connecting until the
345
+ /// response body has finished. It affects only this request and overrides
346
+ /// the timeout configured using `ClientBuilder::timeout()`.
347
+ pub fn timeout(mut self, timeout: Duration) -> RequestBuilder {
348
+ if let Ok(ref mut req) = self.request {
349
+ req.config_mut::<TimeoutOptions>()
350
+ .get_or_insert_default()
351
+ .total_timeout(timeout);
352
+ }
353
+ self
354
+ }
355
+
356
+ /// Enables a read timeout.
357
+ ///
358
+ /// The read timeout is applied from when the response body starts being read
359
+ /// until the response body has finished. It affects only this request and
360
+ /// overrides the read timeout configured using `ClientBuilder::read_timeout()`.
361
+ pub fn read_timeout(mut self, timeout: Duration) -> RequestBuilder {
362
+ if let Ok(ref mut req) = self.request {
363
+ req.config_mut::<TimeoutOptions>()
364
+ .get_or_insert_default()
365
+ .read_timeout(timeout);
366
+ }
367
+ self
368
+ }
369
+
370
+ /// Set the request body.
371
+ pub fn body<T: Into<Body>>(mut self, body: T) -> RequestBuilder {
372
+ if let Ok(ref mut req) = self.request {
373
+ *req.body_mut() = Some(body.into());
374
+ }
375
+ self
376
+ }
377
+
378
+ /// Sends a multipart/form-data body.
379
+ ///
380
+ /// ```
381
+ /// # use wreq::Error;
382
+ ///
383
+ /// # async fn run() -> Result<(), Error> {
384
+ /// let client = wreq::Client::new();
385
+ /// let form = wreq::multipart::Form::new()
386
+ /// .text("key3", "value3")
387
+ /// .text("key4", "value4");
388
+ ///
389
+ /// let response = client.post("your uri").multipart(form).send().await?;
390
+ /// # Ok(())
391
+ /// # }
392
+ /// ```
393
+ #[cfg(feature = "multipart")]
394
+ #[cfg_attr(docsrs, doc(cfg(feature = "multipart")))]
395
+ pub fn multipart(mut self, mut multipart: multipart::Form) -> RequestBuilder {
396
+ if let Ok(ref mut req) = self.request {
397
+ match HeaderValue::from_maybe_shared(Bytes::from(format!(
398
+ "multipart/form-data; boundary={}",
399
+ multipart.boundary()
400
+ ))) {
401
+ Ok(content_type) => {
402
+ req.headers_mut()
403
+ .entry(CONTENT_TYPE)
404
+ .or_insert(content_type);
405
+
406
+ if let Some(length) = multipart.compute_length() {
407
+ req.headers_mut()
408
+ .entry(CONTENT_LENGTH)
409
+ .or_insert_with(|| HeaderValue::from(length));
410
+ }
411
+
412
+ *req.body_mut() = Some(multipart.stream())
413
+ }
414
+ Err(err) => {
415
+ self.request = Err(Error::builder(err));
416
+ }
417
+ };
418
+ }
419
+
420
+ self
421
+ }
422
+
423
+ /// Modify the query string of the URI.
424
+ ///
425
+ /// Modifies the URI of this request, adding the parameters provided.
426
+ /// This method appends and does not overwrite. This means that it can
427
+ /// be called multiple times and that existing query parameters are not
428
+ /// overwritten if the same key is used. The key will simply show up
429
+ /// twice in the query string.
430
+ /// Calling `.query(&[("foo", "a"), ("foo", "b")])` gives `"foo=a&foo=b"`.
431
+ ///
432
+ /// # Note
433
+ /// This method does not support serializing a single key-value
434
+ /// pair. Instead of using `.query(("key", "val"))`, use a sequence, such
435
+ /// as `.query(&[("key", "val")])`. It's also possible to serialize structs
436
+ /// and maps into a key-value pair.
437
+ ///
438
+ /// # Errors
439
+ /// This method will fail if the object you provide cannot be serialized
440
+ /// into a query string.
441
+ #[cfg(feature = "query")]
442
+ #[cfg_attr(docsrs, doc(cfg(feature = "query")))]
443
+ pub fn query<T: Serialize + ?Sized>(mut self, query: &T) -> RequestBuilder {
444
+ let mut error = None;
445
+ if let Ok(ref mut req) = self.request {
446
+ match serde_urlencoded::to_string(query) {
447
+ Ok(serializer) => {
448
+ let uri = req.uri_mut();
449
+ uri.set_query(serializer);
450
+ }
451
+ Err(err) => error = Some(Error::builder(err)),
452
+ }
453
+ }
454
+ if let Some(err) = error {
455
+ self.request = Err(err);
456
+ }
457
+ self
458
+ }
459
+
460
+ /// Send a form body.
461
+ ///
462
+ /// Sets the body to the uri encoded serialization of the passed value,
463
+ /// and also sets the `Content-Type: application/x-www-form-urlencoded`
464
+ /// header.
465
+ ///
466
+ /// ```rust
467
+ /// # use wreq::Error;
468
+ /// # use std::collections::HashMap;
469
+ /// #
470
+ /// # async fn run() -> Result<(), Error> {
471
+ /// let mut params = HashMap::new();
472
+ /// params.insert("lang", "rust");
473
+ ///
474
+ /// let client = wreq::Client::new();
475
+ /// let res = client
476
+ /// .post("http://httpbin.org")
477
+ /// .form(&params)
478
+ /// .send()
479
+ /// .await?;
480
+ /// # Ok(())
481
+ /// # }
482
+ /// ```
483
+ ///
484
+ /// # Errors
485
+ ///
486
+ /// This method fails if the passed value cannot be serialized into
487
+ /// uri encoded format
488
+ #[cfg(feature = "form")]
489
+ #[cfg_attr(docsrs, doc(cfg(feature = "form")))]
490
+ pub fn form<T: Serialize + ?Sized>(mut self, form: &T) -> RequestBuilder {
491
+ if let Ok(ref mut req) = self.request {
492
+ match serde_urlencoded::to_string(form) {
493
+ Ok(body) => {
494
+ req.headers_mut().entry(CONTENT_TYPE).or_insert_with(|| {
495
+ HeaderValue::from_static("application/x-www-form-urlencoded")
496
+ });
497
+ *req.body_mut() = Some(body.into());
498
+ }
499
+ Err(err) => self.request = Err(Error::builder(err)),
500
+ }
501
+ }
502
+ self
503
+ }
504
+
505
+ /// Send a JSON body.
506
+ ///
507
+ /// # Optional
508
+ ///
509
+ /// This requires the optional `json` feature enabled.
510
+ ///
511
+ /// # Errors
512
+ ///
513
+ /// Serialization can fail if `T`'s implementation of `Serialize` decides to
514
+ /// fail, or if `T` contains a map with non-string keys.
515
+ #[cfg(feature = "json")]
516
+ #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
517
+ pub fn json<T: Serialize + ?Sized>(mut self, json: &T) -> RequestBuilder {
518
+ if let Ok(ref mut req) = self.request {
519
+ match serde_json::to_vec(json) {
520
+ Ok(body) => {
521
+ req.headers_mut()
522
+ .entry(CONTENT_TYPE)
523
+ .or_insert_with(|| HeaderValue::from_static("application/json"));
524
+ *req.body_mut() = Some(body.into());
525
+ }
526
+ Err(err) => self.request = Err(Error::builder(err)),
527
+ }
528
+ }
529
+
530
+ self
531
+ }
532
+
533
+ /// Set HTTP version
534
+ pub fn version(mut self, version: Version) -> RequestBuilder {
535
+ if let Ok(ref mut req) = self.request {
536
+ req.version_mut().replace(version);
537
+ }
538
+ self
539
+ }
540
+
541
+ /// Set the redirect policy for this request.
542
+ pub fn redirect(mut self, policy: redirect::Policy) -> RequestBuilder {
543
+ if let Ok(ref mut req) = self.request {
544
+ req.config_mut::<redirect::Policy>().replace(policy);
545
+ }
546
+ self
547
+ }
548
+
549
+ /// Set the persistent cookie store for the request.
550
+ #[cfg(feature = "cookies")]
551
+ #[cfg_attr(docsrs, doc(cfg(feature = "cookies")))]
552
+ pub fn cookie_provider<C>(mut self, cookie_store: C) -> RequestBuilder
553
+ where
554
+ C: IntoCookieStore,
555
+ {
556
+ if let Ok(ref mut req) = self.request {
557
+ req.config_mut::<Arc<dyn CookieStore>>()
558
+ .replace(cookie_store.into_cookie_store());
559
+ }
560
+ self
561
+ }
562
+
563
+ /// Sets if this request will announce that it accepts gzip encoding.
564
+ #[cfg(feature = "gzip")]
565
+ #[cfg_attr(docsrs, doc(cfg(feature = "gzip")))]
566
+ pub fn gzip(mut self, gzip: bool) -> RequestBuilder {
567
+ if let Ok(ref mut req) = self.request {
568
+ req.config_mut::<AcceptEncoding>()
569
+ .get_or_insert_default()
570
+ .gzip = gzip;
571
+ }
572
+ self
573
+ }
574
+
575
+ /// Sets if this request will announce that it accepts brotli encoding.
576
+ #[cfg(feature = "brotli")]
577
+ #[cfg_attr(docsrs, doc(cfg(feature = "brotli")))]
578
+ pub fn brotli(mut self, brotli: bool) -> RequestBuilder {
579
+ if let Ok(ref mut req) = self.request {
580
+ req.config_mut::<AcceptEncoding>()
581
+ .get_or_insert_default()
582
+ .brotli = brotli;
583
+ }
584
+ self
585
+ }
586
+
587
+ /// Sets if this request will announce that it accepts deflate encoding.
588
+ #[cfg(feature = "deflate")]
589
+ #[cfg_attr(docsrs, doc(cfg(feature = "deflate")))]
590
+ pub fn deflate(mut self, deflate: bool) -> RequestBuilder {
591
+ if let Ok(ref mut req) = self.request {
592
+ req.config_mut::<AcceptEncoding>()
593
+ .get_or_insert_default()
594
+ .deflate = deflate;
595
+ }
596
+ self
597
+ }
598
+
599
+ /// Sets if this request will announce that it accepts zstd encoding.
600
+ #[cfg(feature = "zstd")]
601
+ #[cfg_attr(docsrs, doc(cfg(feature = "zstd")))]
602
+ pub fn zstd(mut self, zstd: bool) -> RequestBuilder {
603
+ if let Ok(ref mut req) = self.request {
604
+ req.config_mut::<AcceptEncoding>()
605
+ .get_or_insert_default()
606
+ .zstd = zstd;
607
+ }
608
+ self
609
+ }
610
+
611
+ /// Set the proxy for this request.
612
+ pub fn proxy(mut self, proxy: Proxy) -> RequestBuilder {
613
+ if let Ok(ref mut req) = self.request {
614
+ req.config_mut::<RequestOptions>()
615
+ .get_or_insert_default()
616
+ .proxy_matcher_mut()
617
+ .replace(proxy.into_matcher());
618
+ }
619
+ self
620
+ }
621
+
622
+ /// Set the local address for this request.
623
+ pub fn local_address<V>(mut self, local_address: V) -> RequestBuilder
624
+ where
625
+ V: Into<Option<IpAddr>>,
626
+ {
627
+ if let Ok(ref mut req) = self.request {
628
+ req.config_mut::<RequestOptions>()
629
+ .get_or_insert_default()
630
+ .tcp_connect_opts_mut()
631
+ .set_local_address(local_address.into());
632
+ }
633
+ self
634
+ }
635
+
636
+ /// Set the local addresses for this request.
637
+ pub fn local_addresses<V4, V6>(mut self, ipv4: V4, ipv6: V6) -> RequestBuilder
638
+ where
639
+ V4: Into<Option<Ipv4Addr>>,
640
+ V6: Into<Option<Ipv6Addr>>,
641
+ {
642
+ if let Ok(ref mut req) = self.request {
643
+ req.config_mut::<RequestOptions>()
644
+ .get_or_insert_default()
645
+ .tcp_connect_opts_mut()
646
+ .set_local_addresses(ipv4, ipv6);
647
+ }
648
+ self
649
+ }
650
+
651
+ /// Set the interface for this request.
652
+ #[cfg(any(
653
+ target_os = "android",
654
+ target_os = "fuchsia",
655
+ target_os = "illumos",
656
+ target_os = "ios",
657
+ target_os = "linux",
658
+ target_os = "macos",
659
+ target_os = "solaris",
660
+ target_os = "tvos",
661
+ target_os = "visionos",
662
+ target_os = "watchos",
663
+ ))]
664
+ #[cfg_attr(
665
+ docsrs,
666
+ doc(cfg(any(
667
+ target_os = "android",
668
+ target_os = "fuchsia",
669
+ target_os = "illumos",
670
+ target_os = "ios",
671
+ target_os = "linux",
672
+ target_os = "macos",
673
+ target_os = "solaris",
674
+ target_os = "tvos",
675
+ target_os = "visionos",
676
+ target_os = "watchos",
677
+ )))
678
+ )]
679
+ pub fn interface<I>(mut self, interface: I) -> RequestBuilder
680
+ where
681
+ I: Into<std::borrow::Cow<'static, str>>,
682
+ {
683
+ if let Ok(ref mut req) = self.request {
684
+ req.config_mut::<RequestOptions>()
685
+ .get_or_insert_default()
686
+ .tcp_connect_opts_mut()
687
+ .set_interface(interface);
688
+ }
689
+ self
690
+ }
691
+
692
+ /// Set the emulation for this request.
693
+ pub fn emulation<P>(mut self, factory: P) -> RequestBuilder
694
+ where
695
+ P: EmulationFactory,
696
+ {
697
+ if let Ok(ref mut req) = self.request {
698
+ let emulation = factory.emulation();
699
+ let (transport_opts, default_headers, orig_headers) = emulation.into_parts();
700
+ req.config_mut::<RequestOptions>()
701
+ .get_or_insert_default()
702
+ .transport_opts_mut()
703
+ .apply_transport_options(transport_opts);
704
+ self = self.headers(default_headers).orig_headers(orig_headers);
705
+ }
706
+
707
+ self
708
+ }
709
+
710
+ /// Build a `Request`, which can be inspected, modified and executed with
711
+ /// [`Client::execute()`].
712
+ pub fn build(self) -> crate::Result<Request> {
713
+ self.request
714
+ }
715
+
716
+ /// Build a `Request`, which can be inspected, modified and executed with
717
+ /// [`Client::execute()`].
718
+ ///
719
+ /// This is similar to [`RequestBuilder::build()`], but also returns the
720
+ /// embedded [`Client`].
721
+ pub fn build_split(self) -> (Client, crate::Result<Request>) {
722
+ (self.client, self.request)
723
+ }
724
+
725
+ /// Constructs the Request and sends it to the target URI, returning a
726
+ /// future Response.
727
+ ///
728
+ /// # Errors
729
+ ///
730
+ /// This method fails if there was an error while sending request,
731
+ /// redirect loop was detected or redirect limit was exhausted.
732
+ ///
733
+ /// # Example
734
+ ///
735
+ /// ```no_run
736
+ /// # use wreq::Error;
737
+ /// #
738
+ /// # async fn run() -> Result<(), Error> {
739
+ /// let response = wreq::Client::new().get("https://hyper.rs").send().await?;
740
+ /// # Ok(())
741
+ /// # }
742
+ /// ```
743
+ pub fn send(self) -> impl Future<Output = crate::Result<Response>> {
744
+ match self.request {
745
+ Ok(req) => self.client.execute(req),
746
+ Err(err) => Pending::error(err),
747
+ }
748
+ }
749
+
750
+ /// Attempt to clone the RequestBuilder.
751
+ ///
752
+ /// `None` is returned if the RequestBuilder can not be cloned,
753
+ /// i.e. if the request body is a stream.
754
+ ///
755
+ /// # Examples
756
+ ///
757
+ /// ```
758
+ /// # use wreq::Error;
759
+ /// #
760
+ /// # fn run() -> Result<(), Error> {
761
+ /// let client = wreq::Client::new();
762
+ /// let builder = client.post("http://httpbin.org/post").body("from a &str!");
763
+ /// let clone = builder.try_clone();
764
+ /// assert!(clone.is_some());
765
+ /// # Ok(())
766
+ /// # }
767
+ /// ```
768
+ pub fn try_clone(&self) -> Option<RequestBuilder> {
769
+ self.request
770
+ .as_ref()
771
+ .ok()
772
+ .and_then(|req| req.try_clone())
773
+ .map(|req| RequestBuilder {
774
+ client: self.client.clone(),
775
+ request: Ok(req),
776
+ })
777
+ }
778
+ }
779
+
780
+ /// Check the request URI for a "username:password" type authority, and if
781
+ /// found, remove it from the URI and return it.
782
+ fn extract_authority(uri: &mut Uri) -> Option<(String, Option<String>)> {
783
+ use percent_encoding::percent_decode;
784
+
785
+ let (username, password) = uri.userinfo();
786
+
787
+ let username: String = percent_decode(username?.as_bytes())
788
+ .decode_utf8()
789
+ .ok()?
790
+ .into();
791
+ let password = password.and_then(|pass| {
792
+ percent_decode(pass.as_bytes())
793
+ .decode_utf8()
794
+ .ok()
795
+ .map(String::from)
796
+ });
797
+
798
+ if !username.is_empty() || password.is_some() {
799
+ uri.set_userinfo("", None);
800
+ return Some((username, password));
801
+ }
802
+
803
+ None
804
+ }
805
+
806
+ impl<T: Into<Body>> From<HttpRequest<T>> for Request {
807
+ #[inline]
808
+ fn from(req: HttpRequest<T>) -> Request {
809
+ Request(req.map(Into::into).map(Some))
810
+ }
811
+ }
812
+
813
+ impl From<Request> for HttpRequest<Body> {
814
+ #[inline]
815
+ fn from(req: Request) -> HttpRequest<Body> {
816
+ req.0.map(|body| body.unwrap_or_else(Body::empty))
817
+ }
818
+ }