wreq 1.2.3-x64-mingw-ucrt

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 (69) hide show
  1. checksums.yaml +7 -0
  2. data/Cargo.lock +1687 -0
  3. data/Cargo.toml +54 -0
  4. data/Gemfile +18 -0
  5. data/LICENSE +201 -0
  6. data/README.md +153 -0
  7. data/Rakefile +90 -0
  8. data/build.rs +16 -0
  9. data/docs/windows-gnu-tokio-crash.md +70 -0
  10. data/examples/body.rb +42 -0
  11. data/examples/client.rb +33 -0
  12. data/examples/cookie.rb +24 -0
  13. data/examples/emulate_request.rb +37 -0
  14. data/examples/headers.rb +27 -0
  15. data/examples/proxy.rb +113 -0
  16. data/examples/send_stream.rb +85 -0
  17. data/examples/stream.rb +14 -0
  18. data/examples/thread_interrupt.rb +83 -0
  19. data/extconf.rb +7 -0
  20. data/lib/wreq.rb +303 -0
  21. data/lib/wreq_ruby/3.3/wreq_ruby.so +0 -0
  22. data/lib/wreq_ruby/3.4/wreq_ruby.so +0 -0
  23. data/lib/wreq_ruby/4.0/wreq_ruby.so +0 -0
  24. data/lib/wreq_ruby/body.rb +36 -0
  25. data/lib/wreq_ruby/client.rb +526 -0
  26. data/lib/wreq_ruby/cookie.rb +156 -0
  27. data/lib/wreq_ruby/emulate.rb +232 -0
  28. data/lib/wreq_ruby/error.rb +157 -0
  29. data/lib/wreq_ruby/header.rb +205 -0
  30. data/lib/wreq_ruby/http.rb +160 -0
  31. data/lib/wreq_ruby/response.rb +209 -0
  32. data/script/build_platform_gem.rb +34 -0
  33. data/script/build_windows_gnu.ps1 +257 -0
  34. data/src/arch.rs +33 -0
  35. data/src/client/body/form.rs +2 -0
  36. data/src/client/body/json.rs +16 -0
  37. data/src/client/body/stream.rs +146 -0
  38. data/src/client/body.rs +57 -0
  39. data/src/client/param.rs +19 -0
  40. data/src/client/query.rs +2 -0
  41. data/src/client/req.rs +274 -0
  42. data/src/client/resp.rs +248 -0
  43. data/src/client.rs +413 -0
  44. data/src/cookie.rs +312 -0
  45. data/src/emulate.rs +376 -0
  46. data/src/error.rs +163 -0
  47. data/src/extractor.rs +117 -0
  48. data/src/gvl.rs +154 -0
  49. data/src/header.rs +245 -0
  50. data/src/http.rs +142 -0
  51. data/src/lib.rs +98 -0
  52. data/src/macros.rs +123 -0
  53. data/src/rt.rs +46 -0
  54. data/test/client_cookie_test.rb +46 -0
  55. data/test/client_test.rb +136 -0
  56. data/test/cookie_test.rb +182 -0
  57. data/test/emulation_test.rb +21 -0
  58. data/test/error_handling_test.rb +92 -0
  59. data/test/header_test.rb +290 -0
  60. data/test/inspect_test.rb +125 -0
  61. data/test/module_methods_test.rb +75 -0
  62. data/test/orig_header_test.rb +115 -0
  63. data/test/request_parameters_test.rb +175 -0
  64. data/test/request_test.rb +244 -0
  65. data/test/response_test.rb +69 -0
  66. data/test/stream_test.rb +397 -0
  67. data/test/test_helper.rb +52 -0
  68. data/wreq.gemspec +68 -0
  69. metadata +123 -0
data/src/client.rs ADDED
@@ -0,0 +1,413 @@
1
+ mod body;
2
+ mod param;
3
+ mod query;
4
+ mod req;
5
+ pub mod resp;
6
+
7
+ use std::{net::IpAddr, time::Duration};
8
+
9
+ use magnus::{
10
+ Module, Object, RHash, RModule, Ruby, TryConvert, Value, function, method, typed_data::Obj,
11
+ };
12
+ use serde::Deserialize;
13
+ use wreq::Proxy;
14
+
15
+ use crate::{
16
+ client::{req::execute_request, resp::Response},
17
+ cookie::Jar,
18
+ emulate::Emulation,
19
+ error::wreq_error_to_magnus,
20
+ extractor::Extractor,
21
+ gvl,
22
+ header::{Headers, OrigHeaders, UserAgent},
23
+ http::Method,
24
+ };
25
+
26
+ /// A builder for `Client`.
27
+ #[derive(Default, Deserialize)]
28
+ struct Builder {
29
+ // The emulation option for the client.
30
+ #[serde(skip)]
31
+ emulation: Option<Emulation>,
32
+ /// The user agent to use for the client.
33
+ #[serde(skip)]
34
+ user_agent: Option<UserAgent>,
35
+ /// The headers to use for the client.
36
+ #[serde(skip)]
37
+ headers: Option<Headers>,
38
+ /// The original headers to use for the client.
39
+ #[serde(skip)]
40
+ orig_headers: Option<OrigHeaders>,
41
+ /// Whether to use referer.
42
+ referer: Option<bool>,
43
+ /// Whether to allow redirects.
44
+ allow_redirects: Option<bool>,
45
+ /// The maximum number of redirects to follow.
46
+ max_redirects: Option<usize>,
47
+
48
+ // ========= Cookie options =========
49
+ /// Whether to use cookie store.
50
+ cookie_store: Option<bool>,
51
+ /// Whether to use cookie store provider.
52
+ #[serde(skip)]
53
+ cookie_provider: Option<Jar>,
54
+
55
+ // ========= Timeout options =========
56
+ /// The timeout to use for the client. (in seconds)
57
+ timeout: Option<u64>,
58
+ /// The connect timeout to use for the client. (in seconds)
59
+ connect_timeout: Option<u64>,
60
+ /// The read timeout to use for the client. (in seconds)
61
+ read_timeout: Option<u64>,
62
+
63
+ // ========= TCP options =========
64
+ /// Set that all sockets have `SO_KEEPALIVE` set with the supplied duration. (in seconds)
65
+ tcp_keepalive: Option<u64>,
66
+ /// Set the interval between TCP keepalive probes. (in seconds)
67
+ tcp_keepalive_interval: Option<u64>,
68
+ /// Set the number of retries for TCP keepalive.
69
+ tcp_keepalive_retries: Option<u32>,
70
+ /// Set an optional user timeout for TCP sockets. (in seconds)
71
+ #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
72
+ tcp_user_timeout: Option<u64>,
73
+ /// Set that all sockets have `NO_DELAY` set.
74
+ tcp_nodelay: Option<bool>,
75
+ /// Set that all sockets have `SO_REUSEADDR` set.
76
+ tcp_reuse_address: Option<bool>,
77
+
78
+ // ========= Connection pool options =========
79
+ /// Set an optional timeout for idle sockets being kept-alive. (in seconds)
80
+ pool_idle_timeout: Option<u64>,
81
+ /// Sets the maximum idle connection per host allowed in the pool.
82
+ pool_max_idle_per_host: Option<usize>,
83
+ /// Sets the maximum number of connections in the pool.
84
+ pool_max_size: Option<usize>,
85
+
86
+ // ========= Protocol options =========
87
+ /// Whether to use the HTTP/1 protocol only.
88
+ http1_only: Option<bool>,
89
+ /// Whether to use the HTTP/2 protocol only.
90
+ http2_only: Option<bool>,
91
+ /// Whether to use HTTPS only.
92
+ https_only: Option<bool>,
93
+
94
+ // ========= TLS options =========
95
+ /// Whether to verify the SSL certificate or root certificate file path.
96
+ verify: Option<bool>,
97
+
98
+ // ========= Network options =========
99
+ /// Whether to disable the proxy for the client.
100
+ no_proxy: Option<bool>,
101
+ /// The proxy to use for the client.
102
+ #[serde(skip)]
103
+ proxy: Option<Proxy>,
104
+ /// Bind to a local IP Address.
105
+ local_address: Option<IpAddr>,
106
+ /// Bind to an interface by `SO_BINDTODEVICE`.
107
+ #[allow(dead_code)]
108
+ interface: Option<String>,
109
+
110
+ // ========= Compression options =========
111
+ /// Sets gzip as an accepted encoding.
112
+ gzip: Option<bool>,
113
+ /// Sets brotli as an accepted encoding.
114
+ brotli: Option<bool>,
115
+ /// Sets deflate as an accepted encoding.
116
+ deflate: Option<bool>,
117
+ /// Sets zstd as an accepted encoding.
118
+ zstd: Option<bool>,
119
+ }
120
+
121
+ #[derive(Clone, Default)]
122
+ #[magnus::wrap(class = "Wreq::Client", free_immediately, size)]
123
+ pub struct Client(wreq::Client);
124
+
125
+ // ===== impl Builder =====
126
+
127
+ impl Builder {
128
+ /// Create a new [`Builder`] from Ruby keyword arguments.
129
+ fn new(ruby: &magnus::Ruby, keyword: &Value) -> Result<Self, magnus::Error> {
130
+ let Ok(hash) = RHash::try_convert(*keyword) else {
131
+ return Ok(Default::default());
132
+ };
133
+
134
+ let mut builder: Self = serde_magnus::deserialize(ruby, hash)?;
135
+
136
+ if let Some(v) = hash.get(ruby.to_symbol(stringify!(emulation))) {
137
+ builder.emulation = Some((*Obj::<Emulation>::try_convert(v)?).clone());
138
+ }
139
+
140
+ if let Some(v) = hash.get(ruby.to_symbol(stringify!(user_agent))) {
141
+ builder.user_agent = Some(UserAgent::try_convert(v)?);
142
+ }
143
+
144
+ if let Some(v) = hash.get(ruby.to_symbol(stringify!(headers))) {
145
+ builder.headers = Some(Headers::try_convert(v)?);
146
+ }
147
+
148
+ if let Some(v) = hash.get(ruby.to_symbol(stringify!(orig_headers))) {
149
+ builder.orig_headers = Some(OrigHeaders::try_convert(v)?);
150
+ }
151
+
152
+ if let Some(v) = hash.get(ruby.to_symbol(stringify!(cookie_provider))) {
153
+ builder.cookie_provider = Some((*Obj::<Jar>::try_convert(v)?).clone());
154
+ }
155
+
156
+ builder.proxy = Extractor::<Proxy>::try_convert(*keyword)?.into_inner();
157
+
158
+ Ok(builder)
159
+ }
160
+ }
161
+
162
+ // ===== impl Client =====
163
+
164
+ impl Client {
165
+ /// Create a new [`Client`] with the given keyword arguments.
166
+ pub fn new(ruby: &Ruby, keyword: &[Value]) -> Result<Self, magnus::Error> {
167
+ if let Some(keyword) = keyword.first() {
168
+ let mut params = Builder::new(ruby, keyword)?;
169
+ gvl::nogvl(|| {
170
+ let mut builder = wreq::Client::builder();
171
+
172
+ // Emulation options.
173
+ apply_option!(set_if_some_inner, builder, params.emulation, emulation);
174
+
175
+ // User agent options.
176
+ apply_option!(set_if_some_inner, builder, params.user_agent, user_agent);
177
+
178
+ // Headers options.
179
+ apply_option!(
180
+ set_if_some_into_inner,
181
+ builder,
182
+ params.headers,
183
+ default_headers
184
+ );
185
+ apply_option!(
186
+ set_if_some_inner,
187
+ builder,
188
+ params.orig_headers,
189
+ orig_headers
190
+ );
191
+
192
+ // Allow redirects options.
193
+ apply_option!(set_if_some, builder, params.referer, referer);
194
+ apply_option!(
195
+ set_if_true_with,
196
+ builder,
197
+ params.allow_redirects,
198
+ redirect,
199
+ false,
200
+ params
201
+ .max_redirects
202
+ .take()
203
+ .map(wreq::redirect::Policy::limited)
204
+ .unwrap_or_default()
205
+ );
206
+
207
+ // Cookie options.
208
+ apply_option!(set_if_some, builder, params.cookie_store, cookie_store);
209
+ apply_option!(
210
+ set_if_some_inner,
211
+ builder,
212
+ params.cookie_provider,
213
+ cookie_provider
214
+ );
215
+
216
+ // TCP options.
217
+ apply_option!(
218
+ set_if_some_map,
219
+ builder,
220
+ params.tcp_keepalive,
221
+ tcp_keepalive,
222
+ Duration::from_secs
223
+ );
224
+ apply_option!(
225
+ set_if_some_map,
226
+ builder,
227
+ params.tcp_keepalive_interval,
228
+ tcp_keepalive_interval,
229
+ Duration::from_secs
230
+ );
231
+ apply_option!(
232
+ set_if_some,
233
+ builder,
234
+ params.tcp_keepalive_retries,
235
+ tcp_keepalive_retries
236
+ );
237
+ #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
238
+ apply_option!(
239
+ set_if_some_map,
240
+ builder,
241
+ params.tcp_user_timeout,
242
+ tcp_user_timeout,
243
+ Duration::from_secs
244
+ );
245
+ apply_option!(set_if_some, builder, params.tcp_nodelay, tcp_nodelay);
246
+ apply_option!(
247
+ set_if_some,
248
+ builder,
249
+ params.tcp_reuse_address,
250
+ tcp_reuse_address
251
+ );
252
+
253
+ // Timeout options.
254
+ apply_option!(
255
+ set_if_some_map,
256
+ builder,
257
+ params.timeout,
258
+ timeout,
259
+ Duration::from_secs
260
+ );
261
+ apply_option!(
262
+ set_if_some_map,
263
+ builder,
264
+ params.connect_timeout,
265
+ connect_timeout,
266
+ Duration::from_secs
267
+ );
268
+ apply_option!(
269
+ set_if_some_map,
270
+ builder,
271
+ params.read_timeout,
272
+ read_timeout,
273
+ Duration::from_secs
274
+ );
275
+
276
+ // Pool options.
277
+ apply_option!(
278
+ set_if_some_map,
279
+ builder,
280
+ params.pool_idle_timeout,
281
+ pool_idle_timeout,
282
+ Duration::from_secs
283
+ );
284
+ apply_option!(
285
+ set_if_some,
286
+ builder,
287
+ params.pool_max_idle_per_host,
288
+ pool_max_idle_per_host
289
+ );
290
+ apply_option!(set_if_some, builder, params.pool_max_size, pool_max_size);
291
+
292
+ // Protocol options.
293
+ apply_option!(set_if_true, builder, params.http1_only, http1_only, false);
294
+ apply_option!(set_if_true, builder, params.http2_only, http2_only, false);
295
+ apply_option!(set_if_some, builder, params.https_only, https_only);
296
+
297
+ // TLS options.
298
+ apply_option!(set_if_some, builder, params.verify, tls_cert_verification);
299
+
300
+ // Network options.
301
+ apply_option!(set_if_some, builder, params.proxy, proxy);
302
+ apply_option!(set_if_true, builder, params.no_proxy, no_proxy, false);
303
+ apply_option!(set_if_some, builder, params.local_address, local_address);
304
+ #[cfg(any(
305
+ target_os = "android",
306
+ target_os = "fuchsia",
307
+ target_os = "illumos",
308
+ target_os = "ios",
309
+ target_os = "linux",
310
+ target_os = "macos",
311
+ target_os = "solaris",
312
+ target_os = "tvos",
313
+ target_os = "visionos",
314
+ target_os = "watchos",
315
+ ))]
316
+ apply_option!(set_if_some, builder, params.interface, interface);
317
+
318
+ // Compression options.
319
+ apply_option!(set_if_some, builder, params.gzip, gzip);
320
+ apply_option!(set_if_some, builder, params.brotli, brotli);
321
+ apply_option!(set_if_some, builder, params.deflate, deflate);
322
+ apply_option!(set_if_some, builder, params.zstd, zstd);
323
+
324
+ builder.build().map(Client).map_err(wreq_error_to_magnus)
325
+ })
326
+ } else {
327
+ gvl::nogvl(|| Ok(Self(wreq::Client::new())))
328
+ }
329
+ }
330
+ }
331
+
332
+ impl Client {
333
+ /// Send a HTTP request.
334
+ #[inline]
335
+ pub fn request(rb_self: &Self, args: &[Value]) -> Result<Response, magnus::Error> {
336
+ let ((method, url), request) = extract_request!(args, (Obj<Method>, String));
337
+ execute_request(rb_self.0.clone(), *method, url, request)
338
+ }
339
+
340
+ /// Send a GET request.
341
+ #[inline]
342
+ pub fn get(rb_self: &Self, args: &[Value]) -> Result<Response, magnus::Error> {
343
+ let ((url,), request) = extract_request!(args, (String,));
344
+ execute_request(rb_self.0.clone(), Method::GET, url, request)
345
+ }
346
+
347
+ /// Send a POST request.
348
+ #[inline]
349
+ pub fn post(rb_self: &Self, args: &[Value]) -> Result<Response, magnus::Error> {
350
+ let ((url,), request) = extract_request!(args, (String,));
351
+ execute_request(rb_self.0.clone(), Method::POST, url, request)
352
+ }
353
+
354
+ /// Send a PUT request.
355
+ #[inline]
356
+ pub fn put(rb_self: &Self, args: &[Value]) -> Result<Response, magnus::Error> {
357
+ let ((url,), request) = extract_request!(args, (String,));
358
+ execute_request(rb_self.0.clone(), Method::PUT, url, request)
359
+ }
360
+
361
+ /// Send a DELETE request.
362
+ #[inline]
363
+ pub fn delete(rb_self: &Self, args: &[Value]) -> Result<Response, magnus::Error> {
364
+ let ((url,), request) = extract_request!(args, (String,));
365
+ execute_request(rb_self.0.clone(), Method::DELETE, url, request)
366
+ }
367
+
368
+ /// Send a HEAD request.
369
+ #[inline]
370
+ pub fn head(rb_self: &Self, args: &[Value]) -> Result<Response, magnus::Error> {
371
+ let ((url,), request) = extract_request!(args, (String,));
372
+ execute_request(rb_self.0.clone(), Method::HEAD, url, request)
373
+ }
374
+
375
+ /// Send an OPTIONS request.
376
+ #[inline]
377
+ pub fn options(rb_self: &Self, args: &[Value]) -> Result<Response, magnus::Error> {
378
+ let ((url,), request) = extract_request!(args, (String,));
379
+ execute_request(rb_self.0.clone(), Method::OPTIONS, url, request)
380
+ }
381
+
382
+ /// Send a TRACE request.
383
+ #[inline]
384
+ pub fn trace(rb_self: &Self, args: &[Value]) -> Result<Response, magnus::Error> {
385
+ let ((url,), request) = extract_request!(args, (String,));
386
+ execute_request(rb_self.0.clone(), Method::TRACE, url, request)
387
+ }
388
+
389
+ /// Send a PATCH request.
390
+ #[inline]
391
+ pub fn patch(rb_self: &Self, args: &[Value]) -> Result<Response, magnus::Error> {
392
+ let ((url,), request) = extract_request!(args, (String,));
393
+ execute_request(rb_self.0.clone(), Method::PATCH, url, request)
394
+ }
395
+ }
396
+
397
+ pub fn include(ruby: &Ruby, gem_module: &RModule) -> Result<(), magnus::Error> {
398
+ let client_class = gem_module.define_class("Client", ruby.class_object())?;
399
+ client_class.define_singleton_method("new", function!(Client::new, -1))?;
400
+ client_class.define_method("request", method!(Client::request, -1))?;
401
+ client_class.define_method("get", method!(Client::get, -1))?;
402
+ client_class.define_method("post", method!(Client::post, -1))?;
403
+ client_class.define_method("put", method!(Client::put, -1))?;
404
+ client_class.define_method("delete", method!(Client::delete, -1))?;
405
+ client_class.define_method("head", method!(Client::head, -1))?;
406
+ client_class.define_method("options", method!(Client::options, -1))?;
407
+ client_class.define_method("trace", method!(Client::trace, -1))?;
408
+ client_class.define_method("patch", method!(Client::patch, -1))?;
409
+
410
+ resp::include(ruby, gem_module)?;
411
+ body::include(ruby, gem_module)?;
412
+ Ok(())
413
+ }