wreq-rb 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +1922 -397
  3. data/LICENSE +203 -0
  4. data/README.md +19 -15
  5. data/ext/wreq_rb/Cargo.toml +4 -6
  6. data/ext/wreq_rb/src/client.rs +41 -48
  7. data/lib/wreq-rb/version.rb +1 -1
  8. data/patches/0001-add-transfer-size-tracking.patch +76 -67
  9. data/vendor/wreq/Cargo.toml +119 -71
  10. data/vendor/wreq/README.md +25 -20
  11. data/vendor/wreq/bench/http1.rs +25 -0
  12. data/vendor/wreq/bench/http1_over_tls.rs +25 -0
  13. data/vendor/wreq/bench/http2.rs +25 -0
  14. data/vendor/wreq/bench/http2_over_tls.rs +25 -0
  15. data/vendor/wreq/bench/support/bench.rs +91 -0
  16. data/vendor/wreq/bench/support/client.rs +217 -0
  17. data/vendor/wreq/bench/support/server.rs +188 -0
  18. data/vendor/wreq/bench/support.rs +56 -0
  19. data/vendor/wreq/examples/cert_store.rs +4 -4
  20. data/vendor/wreq/examples/{emulation.rs → emulate.rs} +2 -2
  21. data/vendor/wreq/examples/http2_websocket.rs +2 -2
  22. data/vendor/wreq/examples/keylog.rs +3 -3
  23. data/vendor/wreq/examples/{request_with_emulation.rs → request_with_emulate.rs} +2 -2
  24. data/vendor/wreq/examples/rt.rs +23 -0
  25. data/vendor/wreq/src/client/body.rs +23 -61
  26. data/vendor/wreq/src/client/emulate.rs +119 -0
  27. data/vendor/wreq/src/client/{http/future.rs → future.rs} +11 -32
  28. data/vendor/wreq/src/client/{http → layer}/client/pool.rs +66 -61
  29. data/vendor/wreq/src/client/{http → layer}/client.rs +416 -270
  30. data/vendor/wreq/src/client/layer/config.rs +27 -6
  31. data/vendor/wreq/src/client/layer/decoder.rs +9 -4
  32. data/vendor/wreq/src/client/layer/redirect/future.rs +6 -3
  33. data/vendor/wreq/src/client/layer/redirect.rs +4 -5
  34. data/vendor/wreq/src/client/layer/retry.rs +8 -5
  35. data/vendor/wreq/src/client/layer/timeout/body.rs +15 -6
  36. data/vendor/wreq/src/client/layer/timeout/future.rs +23 -18
  37. data/vendor/wreq/src/client/layer/timeout.rs +24 -74
  38. data/vendor/wreq/src/client/layer.rs +1 -2
  39. data/vendor/wreq/src/client/multipart.rs +137 -154
  40. data/vendor/wreq/src/client/request.rs +202 -118
  41. data/vendor/wreq/src/client/response.rs +46 -45
  42. data/vendor/wreq/src/client/upgrade.rs +15 -0
  43. data/vendor/wreq/src/client/ws.rs +73 -25
  44. data/vendor/wreq/src/client.rs +1655 -17
  45. data/vendor/wreq/src/config.rs +11 -11
  46. data/vendor/wreq/src/{client/conn → conn}/connector.rs +139 -137
  47. data/vendor/wreq/src/conn/descriptor.rs +143 -0
  48. data/vendor/wreq/src/conn/http.rs +484 -0
  49. data/vendor/wreq/src/conn/net/io.rs +75 -0
  50. data/vendor/wreq/src/conn/net/tcp/compio.rs +71 -0
  51. data/vendor/wreq/src/conn/net/tcp/tokio.rs +57 -0
  52. data/vendor/wreq/src/conn/net/tcp.rs +561 -0
  53. data/vendor/wreq/src/conn/net/uds/compio.rs +60 -0
  54. data/vendor/wreq/src/{client/conn/uds.rs → conn/net/uds/tokio.rs} +18 -12
  55. data/vendor/wreq/src/conn/net/uds.rs +11 -0
  56. data/vendor/wreq/src/conn/net.rs +130 -0
  57. data/vendor/wreq/src/{client/conn → conn}/proxy/socks.rs +2 -9
  58. data/vendor/wreq/src/{client/conn → conn}/proxy/tunnel.rs +21 -56
  59. data/vendor/wreq/src/conn/tls_info.rs +47 -0
  60. data/vendor/wreq/src/{client/conn.rs → conn.rs} +202 -54
  61. data/vendor/wreq/src/cookie.rs +302 -142
  62. data/vendor/wreq/src/dns/gai/compio.rs +77 -0
  63. data/vendor/wreq/src/dns/gai/tokio.rs +90 -0
  64. data/vendor/wreq/src/dns/gai.rs +14 -164
  65. data/vendor/wreq/src/dns/hickory.rs +16 -23
  66. data/vendor/wreq/src/dns/resolve.rs +7 -41
  67. data/vendor/wreq/src/dns.rs +90 -7
  68. data/vendor/wreq/src/error.rs +57 -31
  69. data/vendor/wreq/src/ext.rs +25 -0
  70. data/vendor/wreq/src/group.rs +211 -0
  71. data/vendor/wreq/src/header.rs +100 -112
  72. data/vendor/wreq/src/lib.rs +124 -73
  73. data/vendor/wreq/src/proxy.rs +6 -20
  74. data/vendor/wreq/src/redirect.rs +1 -1
  75. data/vendor/wreq/src/rt.rs +208 -0
  76. data/vendor/wreq/src/sync.rs +97 -98
  77. data/vendor/wreq/src/tls/compress.rs +124 -0
  78. data/vendor/wreq/src/tls/conn/ext.rs +54 -45
  79. data/vendor/wreq/src/tls/conn/service.rs +14 -18
  80. data/vendor/wreq/src/tls/conn.rs +169 -241
  81. data/vendor/wreq/src/tls/keylog.rs +68 -5
  82. data/vendor/wreq/src/tls/session.rs +205 -0
  83. data/vendor/wreq/src/tls/{x509 → trust}/identity.rs +4 -21
  84. data/vendor/wreq/src/tls/{x509/parser.rs → trust/parse.rs} +1 -1
  85. data/vendor/wreq/src/tls/{x509 → trust}/store.rs +42 -81
  86. data/vendor/wreq/src/tls/{x509.rs → trust.rs} +8 -2
  87. data/vendor/wreq/src/tls.rs +489 -25
  88. data/vendor/wreq/src/trace.rs +0 -12
  89. data/vendor/wreq/src/util.rs +1 -1
  90. data/vendor/wreq/tests/badssl.rs +10 -10
  91. data/vendor/wreq/tests/client.rs +3 -9
  92. data/vendor/wreq/tests/cookie.rs +6 -8
  93. data/vendor/wreq/tests/{emulation.rs → emulate.rs} +130 -22
  94. data/vendor/wreq/tests/multipart.rs +43 -1
  95. data/vendor/wreq/tests/proxy.rs +1 -1
  96. data/vendor/wreq/tests/support/layer.rs +1 -0
  97. metadata +49 -71
  98. data/patches/0002-add-cancel-connections.patch +0 -181
  99. data/vendor/wreq/src/client/conn/conn.rs +0 -231
  100. data/vendor/wreq/src/client/conn/http.rs +0 -1023
  101. data/vendor/wreq/src/client/conn/tls_info.rs +0 -98
  102. data/vendor/wreq/src/client/core/body/incoming.rs +0 -485
  103. data/vendor/wreq/src/client/core/body/length.rs +0 -118
  104. data/vendor/wreq/src/client/core/body.rs +0 -34
  105. data/vendor/wreq/src/client/core/common/buf.rs +0 -149
  106. data/vendor/wreq/src/client/core/common/rewind.rs +0 -141
  107. data/vendor/wreq/src/client/core/common/watch.rs +0 -76
  108. data/vendor/wreq/src/client/core/common.rs +0 -3
  109. data/vendor/wreq/src/client/core/conn/http1.rs +0 -342
  110. data/vendor/wreq/src/client/core/conn/http2.rs +0 -307
  111. data/vendor/wreq/src/client/core/conn.rs +0 -11
  112. data/vendor/wreq/src/client/core/dispatch.rs +0 -299
  113. data/vendor/wreq/src/client/core/error.rs +0 -435
  114. data/vendor/wreq/src/client/core/ext.rs +0 -201
  115. data/vendor/wreq/src/client/core/http1.rs +0 -178
  116. data/vendor/wreq/src/client/core/http2.rs +0 -483
  117. data/vendor/wreq/src/client/core/proto/h1/conn.rs +0 -988
  118. data/vendor/wreq/src/client/core/proto/h1/decode.rs +0 -1170
  119. data/vendor/wreq/src/client/core/proto/h1/dispatch.rs +0 -684
  120. data/vendor/wreq/src/client/core/proto/h1/encode.rs +0 -580
  121. data/vendor/wreq/src/client/core/proto/h1/io.rs +0 -879
  122. data/vendor/wreq/src/client/core/proto/h1/role.rs +0 -694
  123. data/vendor/wreq/src/client/core/proto/h1.rs +0 -104
  124. data/vendor/wreq/src/client/core/proto/h2/client.rs +0 -650
  125. data/vendor/wreq/src/client/core/proto/h2/ping.rs +0 -539
  126. data/vendor/wreq/src/client/core/proto/h2.rs +0 -379
  127. data/vendor/wreq/src/client/core/proto/headers.rs +0 -138
  128. data/vendor/wreq/src/client/core/proto.rs +0 -58
  129. data/vendor/wreq/src/client/core/rt/bounds.rs +0 -57
  130. data/vendor/wreq/src/client/core/rt/timer.rs +0 -150
  131. data/vendor/wreq/src/client/core/rt/tokio.rs +0 -99
  132. data/vendor/wreq/src/client/core/rt.rs +0 -25
  133. data/vendor/wreq/src/client/core/upgrade.rs +0 -267
  134. data/vendor/wreq/src/client/core.rs +0 -16
  135. data/vendor/wreq/src/client/emulation.rs +0 -161
  136. data/vendor/wreq/src/client/http/client/error.rs +0 -142
  137. data/vendor/wreq/src/client/http/client/exec.rs +0 -29
  138. data/vendor/wreq/src/client/http/client/extra.rs +0 -77
  139. data/vendor/wreq/src/client/http/client/util.rs +0 -104
  140. data/vendor/wreq/src/client/http.rs +0 -1629
  141. data/vendor/wreq/src/client/layer/config/options.rs +0 -156
  142. data/vendor/wreq/src/client/layer/cookie.rs +0 -161
  143. data/vendor/wreq/src/hash.rs +0 -143
  144. data/vendor/wreq/src/tls/conn/cache.rs +0 -123
  145. data/vendor/wreq/src/tls/conn/cert_compression.rs +0 -125
  146. data/vendor/wreq/src/tls/keylog/handle.rs +0 -64
  147. data/vendor/wreq/src/tls/options.rs +0 -464
  148. /data/vendor/wreq/src/client/{http → layer}/client/lazy.rs +0 -0
  149. /data/vendor/wreq/src/{client/conn → conn}/proxy.rs +0 -0
  150. /data/vendor/wreq/src/{client/conn → conn}/verbose.rs +0 -0
@@ -6,16 +6,13 @@ use std::{
6
6
  time::Duration,
7
7
  };
8
8
 
9
- use http::{Extensions, Request as HttpRequest, Uri, Version};
9
+ #[cfg(any(feature = "form", feature = "json", feature = "multipart"))]
10
+ use http::header::CONTENT_TYPE;
11
+ use http::{Extensions, Uri, Version};
10
12
  #[cfg(any(feature = "query", feature = "form", feature = "json"))]
11
13
  use serde::Serialize;
12
14
  #[cfg(feature = "multipart")]
13
15
  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
16
 
20
17
  #[cfg(any(
21
18
  feature = "gzip",
@@ -25,19 +22,20 @@ use {
25
22
  ))]
26
23
  use super::layer::decoder::AcceptEncoding;
27
24
  use super::{
28
- Body, EmulationFactory, Response,
29
- http::{Client, future::Pending},
25
+ Body, Client, IntoEmulation, Response,
26
+ future::Pending,
30
27
  layer::{
31
28
  config::{DefaultHeaders, RequestOptions},
32
29
  timeout::TimeoutOptions,
33
30
  },
34
31
  };
35
- #[cfg(any(feature = "multipart", feature = "form", feature = "json"))]
36
- use crate::header::CONTENT_TYPE;
32
+ #[cfg(feature = "cookies")]
33
+ use crate::cookie::{CookieStore, IntoCookieStore};
37
34
  use crate::{
38
35
  Error, Method, Proxy,
39
36
  config::{RequestConfig, RequestConfigValue},
40
37
  ext::UriExt,
38
+ group::Group,
41
39
  header::{AUTHORIZATION, HeaderMap, HeaderName, HeaderValue, OrigHeaderMap},
42
40
  redirect,
43
41
  };
@@ -116,15 +114,49 @@ impl Request {
116
114
  #[inline]
117
115
  pub fn version(&self) -> Option<Version> {
118
116
  self.config::<RequestOptions>()
119
- .and_then(RequestOptions::enforced_version)
117
+ .and_then(|opts| opts.version)
120
118
  }
121
119
 
122
120
  /// Get a mutable reference to the http version.
123
121
  #[inline]
124
122
  pub fn version_mut(&mut self) -> &mut Option<Version> {
125
- self.config_mut::<RequestOptions>()
123
+ &mut self
124
+ .config_mut::<RequestOptions>()
126
125
  .get_or_insert_default()
127
- .enforced_version_mut()
126
+ .version
127
+ }
128
+
129
+ /// Returns a reference to the associated extensions.
130
+ ///
131
+ /// # Examples
132
+ ///
133
+ /// ```
134
+ /// # use wreq;
135
+ /// let request = wreq::get("http://httpbin.org/get")
136
+ /// .build()
137
+ /// .expect("failed to build request");
138
+ /// assert!(request.extensions().get::<i32>().is_none());
139
+ /// ```
140
+ #[inline]
141
+ pub fn extensions(&self) -> &Extensions {
142
+ self.0.extensions()
143
+ }
144
+
145
+ /// Returns a mutable reference to the associated extensions.
146
+ ///
147
+ /// # Examples
148
+ ///
149
+ /// ```
150
+ /// # use wreq;
151
+ /// let mut request = wreq::get("http://httpbin.org/get")
152
+ /// .build()
153
+ /// .expect("failed to build request");
154
+ /// request.extensions_mut().insert("hello");
155
+ /// assert_eq!(request.extensions().get(), Some(&"hello"));
156
+ /// ```
157
+ #[inline]
158
+ pub fn extensions_mut(&mut self) -> &mut Extensions {
159
+ self.0.extensions_mut()
128
160
  }
129
161
 
130
162
  /// Attempt to clone the request.
@@ -143,16 +175,6 @@ impl Request {
143
175
  Some(req)
144
176
  }
145
177
 
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
178
  #[inline]
157
179
  pub(crate) fn config<T>(&self) -> Option<&T::Value>
158
180
  where
@@ -331,10 +353,7 @@ impl RequestBuilder {
331
353
  /// # Ok(())
332
354
  /// # }
333
355
  /// ```
334
- pub fn bearer_auth<T>(self, token: T) -> RequestBuilder
335
- where
336
- T: fmt::Display,
337
- {
356
+ pub fn bearer_auth<T: fmt::Display>(self, token: T) -> RequestBuilder {
338
357
  let header_value = format!("Bearer {token}");
339
358
  self.header_sensitive(AUTHORIZATION, header_value, true)
340
359
  }
@@ -367,59 +386,6 @@ impl RequestBuilder {
367
386
  self
368
387
  }
369
388
 
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
389
  /// Modify the query string of the URI.
424
390
  ///
425
391
  /// Modifies the URI of this request, adding the parameters provided.
@@ -443,7 +409,7 @@ impl RequestBuilder {
443
409
  pub fn query<T: Serialize + ?Sized>(mut self, query: &T) -> RequestBuilder {
444
410
  let mut error = None;
445
411
  if let Ok(ref mut req) = self.request {
446
- match serde_urlencoded::to_string(query) {
412
+ match serde_html_form::to_string(query) {
447
413
  Ok(serializer) => {
448
414
  let uri = req.uri_mut();
449
415
  uri.set_query(serializer);
@@ -489,12 +455,15 @@ impl RequestBuilder {
489
455
  #[cfg_attr(docsrs, doc(cfg(feature = "form")))]
490
456
  pub fn form<T: Serialize + ?Sized>(mut self, form: &T) -> RequestBuilder {
491
457
  if let Ok(ref mut req) = self.request {
492
- match serde_urlencoded::to_string(form) {
458
+ match serde_html_form::to_string(form) {
493
459
  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());
460
+ const HEADER_VALUE: HeaderValue =
461
+ HeaderValue::from_static("application/x-www-form-urlencoded");
462
+
463
+ req.headers_mut()
464
+ .entry(CONTENT_TYPE)
465
+ .or_insert(HEADER_VALUE);
466
+ req.body_mut().replace(body.into());
498
467
  }
499
468
  Err(err) => self.request = Err(Error::builder(err)),
500
469
  }
@@ -518,10 +487,12 @@ impl RequestBuilder {
518
487
  if let Ok(ref mut req) = self.request {
519
488
  match serde_json::to_vec(json) {
520
489
  Ok(body) => {
490
+ const HEADER_VALUE: HeaderValue = HeaderValue::from_static("application/json");
491
+
521
492
  req.headers_mut()
522
493
  .entry(CONTENT_TYPE)
523
- .or_insert_with(|| HeaderValue::from_static("application/json"));
524
- *req.body_mut() = Some(body.into());
494
+ .or_insert(HEADER_VALUE);
495
+ req.body_mut().replace(body.into());
525
496
  }
526
497
  Err(err) => self.request = Err(Error::builder(err)),
527
498
  }
@@ -530,10 +501,66 @@ impl RequestBuilder {
530
501
  self
531
502
  }
532
503
 
504
+ /// Set the request body.
505
+ pub fn body<T: Into<Body>>(mut self, body: T) -> RequestBuilder {
506
+ if let Ok(ref mut req) = self.request {
507
+ *req.body_mut() = Some(body.into());
508
+ }
509
+ self
510
+ }
511
+
512
+ /// Sends a multipart/form-data body.
513
+ ///
514
+ /// ```
515
+ /// # use wreq::Error;
516
+ ///
517
+ /// # async fn run() -> Result<(), Error> {
518
+ /// let client = wreq::Client::new();
519
+ /// let form = wreq::multipart::Form::new()
520
+ /// .text("key3", "value3")
521
+ /// .text("key4", "value4");
522
+ ///
523
+ /// let response = client.post("your uri").multipart(form).send().await?;
524
+ /// # Ok(())
525
+ /// # }
526
+ /// ```
527
+ #[cfg(feature = "multipart")]
528
+ #[cfg_attr(docsrs, doc(cfg(feature = "multipart")))]
529
+ pub fn multipart(mut self, mut multipart: multipart::Form) -> RequestBuilder {
530
+ if let Ok(ref mut req) = self.request {
531
+ match HeaderValue::from_maybe_shared(Bytes::from(format!(
532
+ "multipart/form-data; boundary={}",
533
+ multipart.boundary()
534
+ ))) {
535
+ Ok(content_type) => {
536
+ req.headers_mut()
537
+ .entry(CONTENT_TYPE)
538
+ .or_insert(content_type);
539
+
540
+ if let Some(length) = multipart.compute_length() {
541
+ req.headers_mut()
542
+ .entry(CONTENT_LENGTH)
543
+ .or_insert_with(|| HeaderValue::from(length));
544
+ }
545
+
546
+ *req.body_mut() = Some(multipart.stream())
547
+ }
548
+ Err(err) => {
549
+ self.request = Err(Error::builder(err));
550
+ }
551
+ };
552
+ }
553
+
554
+ self
555
+ }
556
+
533
557
  /// Set HTTP version
534
558
  pub fn version(mut self, version: Version) -> RequestBuilder {
535
559
  if let Ok(ref mut req) = self.request {
536
560
  req.version_mut().replace(version);
561
+ req.config_mut::<RequestOptions>()
562
+ .get_or_insert_default()
563
+ .version = Some(version);
537
564
  }
538
565
  self
539
566
  }
@@ -549,13 +576,12 @@ impl RequestBuilder {
549
576
  /// Set the persistent cookie store for the request.
550
577
  #[cfg(feature = "cookies")]
551
578
  #[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
- {
579
+ pub fn cookie_provider<C: IntoCookieStore>(mut self, cookie_store: C) -> RequestBuilder {
556
580
  if let Ok(ref mut req) = self.request {
581
+ use std::sync::Arc;
582
+
557
583
  req.config_mut::<Arc<dyn CookieStore>>()
558
- .replace(cookie_store.into_cookie_store());
584
+ .replace(cookie_store.into_shared());
559
585
  }
560
586
  self
561
587
  }
@@ -613,8 +639,7 @@ impl RequestBuilder {
613
639
  if let Ok(ref mut req) = self.request {
614
640
  req.config_mut::<RequestOptions>()
615
641
  .get_or_insert_default()
616
- .proxy_matcher_mut()
617
- .replace(proxy.into_matcher());
642
+ .proxy = Some(proxy.into_matcher());
618
643
  }
619
644
  self
620
645
  }
@@ -627,14 +652,15 @@ impl RequestBuilder {
627
652
  if let Ok(ref mut req) = self.request {
628
653
  req.config_mut::<RequestOptions>()
629
654
  .get_or_insert_default()
630
- .tcp_connect_opts_mut()
631
- .set_local_address(local_address.into());
655
+ .socket_bind_options
656
+ .get_or_insert_default()
657
+ .set_local_address(local_address);
632
658
  }
633
659
  self
634
660
  }
635
661
 
636
662
  /// Set the local addresses for this request.
637
- pub fn local_addresses<V4, V6>(mut self, ipv4: V4, ipv6: V6) -> RequestBuilder
663
+ pub fn local_addresses<V4, V6>(mut self, ipv4_address: V4, ipv6_address: V6) -> RequestBuilder
638
664
  where
639
665
  V4: Into<Option<Ipv4Addr>>,
640
666
  V6: Into<Option<Ipv6Addr>>,
@@ -642,13 +668,45 @@ impl RequestBuilder {
642
668
  if let Ok(ref mut req) = self.request {
643
669
  req.config_mut::<RequestOptions>()
644
670
  .get_or_insert_default()
645
- .tcp_connect_opts_mut()
646
- .set_local_addresses(ipv4, ipv6);
671
+ .socket_bind_options
672
+ .get_or_insert_default()
673
+ .set_local_addresses(ipv4_address, ipv6_address);
647
674
  }
648
675
  self
649
676
  }
650
677
 
651
- /// Set the interface for this request.
678
+ /// Bind connections only on the specified network interface.
679
+ ///
680
+ /// This option is only available on the following operating systems:
681
+ ///
682
+ /// - Android
683
+ /// - Fuchsia
684
+ /// - Linux,
685
+ /// - macOS and macOS-like systems (iOS, tvOS, watchOS and visionOS)
686
+ /// - Solaris and illumos
687
+ ///
688
+ /// On Android, Linux, and Fuchsia, this uses the
689
+ /// [`SO_BINDTODEVICE`][man-7-socket] socket option. On macOS and macOS-like
690
+ /// systems, Solaris, and illumos, this instead uses the [`IP_BOUND_IF` and
691
+ /// `IPV6_BOUND_IF`][man-7p-ip] socket options (as appropriate).
692
+ ///
693
+ /// Note that connections will fail if the provided interface name is not a
694
+ /// network interface that currently exists when a connection is established.
695
+ ///
696
+ /// # Example
697
+ ///
698
+ /// ```
699
+ /// # fn doc() -> Result<(), wreq::Error> {
700
+ /// let interface = "lo";
701
+ /// let client = wreq::Client::builder()
702
+ /// .interface(interface)
703
+ /// .build()?;
704
+ /// # Ok(())
705
+ /// # }
706
+ /// ```
707
+ ///
708
+ /// [man-7-socket]: https://man7.org/linux/man-pages/man7/socket.7.html
709
+ /// [man-7p-ip]: https://docs.oracle.com/cd/E86824_01/html/E54777/ip-7p.html
652
710
  #[cfg(any(
653
711
  target_os = "android",
654
712
  target_os = "fuchsia",
@@ -683,32 +741,57 @@ impl RequestBuilder {
683
741
  if let Ok(ref mut req) = self.request {
684
742
  req.config_mut::<RequestOptions>()
685
743
  .get_or_insert_default()
686
- .tcp_connect_opts_mut()
744
+ .socket_bind_options
745
+ .get_or_insert_default()
687
746
  .set_interface(interface);
688
747
  }
689
748
  self
690
749
  }
691
750
 
692
- /// Set the emulation for this request.
693
- pub fn emulation<P>(mut self, factory: P) -> RequestBuilder
694
- where
695
- P: EmulationFactory,
696
- {
751
+ /// Sets the request builder to emulation the specified HTTP context.
752
+ ///
753
+ /// This method sets the necessary headers, HTTP/1 and HTTP/2 options configurations, and TLS
754
+ /// options config to use the specified HTTP context. It allows the client to mimic the
755
+ /// behavior of different versions or setups, which can be useful for testing or ensuring
756
+ /// compatibility with various environments.
757
+ ///
758
+ /// # Note
759
+ /// This will overwrite the existing configuration.
760
+ /// You must set emulation before you can perform subsequent HTTP1/HTTP2/TLS fine-tuning.
761
+ pub fn emulation<T: IntoEmulation>(mut self, emulation: T) -> RequestBuilder {
762
+ if let Ok(ref mut req) = self.request {
763
+ let emulation = emulation.into_emulation();
764
+ let opts = req.config_mut::<RequestOptions>().get_or_insert_default();
765
+ opts.group.emulate(emulation.group);
766
+ opts.tls_options = emulation.tls_options;
767
+ opts.http1_options = emulation.http1_options;
768
+ opts.http2_options = emulation.http2_options;
769
+ return self
770
+ .headers(emulation.headers)
771
+ .orig_headers(emulation.orig_headers);
772
+ }
773
+
774
+ self
775
+ }
776
+
777
+ /// Assigns a logical group to this request.
778
+ ///
779
+ /// Groups define the request's identity and execution context.
780
+ /// Requests in different groups are logically partitioned to ensure
781
+ /// resource isolation and prevent metadata leakage.
782
+ pub fn group(mut self, group: Group) -> RequestBuilder {
697
783
  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
784
  req.config_mut::<RequestOptions>()
701
785
  .get_or_insert_default()
702
- .transport_opts_mut()
703
- .apply_transport_options(transport_opts);
704
- self = self.headers(default_headers).orig_headers(orig_headers);
786
+ .group
787
+ .request(group);
705
788
  }
706
-
707
789
  self
708
790
  }
709
791
 
710
792
  /// Build a `Request`, which can be inspected, modified and executed with
711
793
  /// [`Client::execute()`].
794
+ #[inline]
712
795
  pub fn build(self) -> crate::Result<Request> {
713
796
  self.request
714
797
  }
@@ -718,6 +801,7 @@ impl RequestBuilder {
718
801
  ///
719
802
  /// This is similar to [`RequestBuilder::build()`], but also returns the
720
803
  /// embedded [`Client`].
804
+ #[inline]
721
805
  pub fn build_split(self) -> (Client, crate::Result<Request>) {
722
806
  (self.client, self.request)
723
807
  }
@@ -743,7 +827,7 @@ impl RequestBuilder {
743
827
  pub fn send(self) -> impl Future<Output = crate::Result<Response>> {
744
828
  match self.request {
745
829
  Ok(req) => self.client.execute(req),
746
- Err(err) => Pending::error(err),
830
+ Err(err) => Pending::Error { error: Some(err) },
747
831
  }
748
832
  }
749
833
 
@@ -803,16 +887,16 @@ fn extract_authority(uri: &mut Uri) -> Option<(String, Option<String>)> {
803
887
  None
804
888
  }
805
889
 
806
- impl<T: Into<Body>> From<HttpRequest<T>> for Request {
890
+ impl<T: Into<Body>> From<http::Request<T>> for Request {
807
891
  #[inline]
808
- fn from(req: HttpRequest<T>) -> Request {
892
+ fn from(req: http::Request<T>) -> Request {
809
893
  Request(req.map(Into::into).map(Some))
810
894
  }
811
895
  }
812
896
 
813
- impl From<Request> for HttpRequest<Body> {
897
+ impl From<Request> for http::Request<Body> {
814
898
  #[inline]
815
- fn from(req: Request) -> HttpRequest<Body> {
899
+ fn from(req: Request) -> http::Request<Body> {
816
900
  req.0.map(|body| body.unwrap_or_else(Body::empty))
817
901
  }
818
902
  }
@@ -16,14 +16,16 @@ use http_body_util::{BodyExt, Collected};
16
16
  use mime::Mime;
17
17
  #[cfg(feature = "json")]
18
18
  use serde::de::DeserializeOwned;
19
+ use wreq_proto::ext::ReasonPhrase;
19
20
 
20
- use super::{
21
- conn::HttpInfo,
22
- core::{ext::ReasonPhrase, upgrade},
23
- };
24
21
  #[cfg(feature = "cookies")]
25
22
  use crate::cookie;
26
- use crate::{Body, Error, Upgraded, error::BoxError, ext::RequestUri};
23
+ use crate::{
24
+ Body, Error,
25
+ conn::{Connected, http::HttpInfo},
26
+ error::BoxError,
27
+ ext::RequestUri,
28
+ };
27
29
 
28
30
  /// A Response to a submitted [`crate::Request`].
29
31
  #[derive(Debug)]
@@ -33,14 +35,18 @@ pub struct Response {
33
35
  }
34
36
 
35
37
  impl Response {
36
- pub(super) fn new<B>(res: http::Response<B>, uri: Uri) -> Response
38
+ #[inline]
39
+ pub(super) fn new<B>(mut res: http::Response<B>, uri: Uri) -> Response
37
40
  where
38
41
  B: HttpBody + Send + Sync + 'static,
39
42
  B::Data: Into<Bytes>,
40
43
  B::Error: Into<BoxError>,
41
44
  {
42
45
  Response {
43
- uri,
46
+ uri: res
47
+ .extensions_mut()
48
+ .remove::<RequestUri>()
49
+ .map_or(uri, |request_uri| request_uri.0),
44
50
  res: res.map(Body::wrap),
45
51
  }
46
52
  }
@@ -269,8 +275,15 @@ impl Response {
269
275
  #[cfg(feature = "json")]
270
276
  #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
271
277
  pub async fn json<T: DeserializeOwned>(self) -> crate::Result<T> {
272
- let full = self.bytes().await?;
273
- serde_json::from_slice(&full).map_err(Error::decode)
278
+ match http_body_util::BodyExt::collect(self.res.into_body())
279
+ .await
280
+ .map(Collected::<Bytes>::to_bytes)
281
+ {
282
+ Ok(full) => serde_json::from_slice(&full)
283
+ .map_err(Error::decode)
284
+ .map_err(|err| err.with_uri(self.uri)),
285
+ Err(err) => Err(err.with_uri(self.uri)),
286
+ }
274
287
  }
275
288
 
276
289
  /// Get the full response body as [`Bytes`].
@@ -290,38 +303,12 @@ impl Response {
290
303
  /// # Ok(())
291
304
  /// # }
292
305
  /// ```
306
+ #[inline]
293
307
  pub async fn bytes(self) -> crate::Result<Bytes> {
294
308
  BodyExt::collect(self.res.into_body())
295
309
  .await
296
310
  .map(Collected::<Bytes>::to_bytes)
297
- }
298
-
299
- /// Stream a chunk of the response body.
300
- ///
301
- /// When the response body has been exhausted, this will return `None`.
302
- ///
303
- /// # Example
304
- ///
305
- /// ```
306
- /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
307
- /// let mut res = wreq::get("https://hyper.rs").send().await?;
308
- ///
309
- /// while let Some(chunk) = res.chunk().await? {
310
- /// println!("Chunk: {chunk:?}");
311
- /// }
312
- /// # Ok(())
313
- /// # }
314
- /// ```
315
- pub async fn chunk(&mut self) -> crate::Result<Option<Bytes>> {
316
- loop {
317
- if let Some(res) = self.res.body_mut().frame().await {
318
- if let Ok(buf) = res?.into_data() {
319
- return Ok(Some(buf));
320
- }
321
- } else {
322
- return Ok(None);
323
- }
324
- }
311
+ .map_err(|err| err.with_uri(self.uri))
325
312
  }
326
313
 
327
314
  /// Convert the response into a [`Stream`] of [`Bytes`] from the body.
@@ -348,6 +335,7 @@ impl Response {
348
335
  /// # Optional
349
336
  ///
350
337
  /// This requires the optional `stream` feature to be enabled.
338
+ #[inline]
351
339
  #[cfg(feature = "stream")]
352
340
  #[cfg_attr(docsrs, doc(cfg(feature = "stream")))]
353
341
  pub fn bytes_stream(self) -> impl Stream<Item = crate::Result<Bytes>> {
@@ -414,6 +402,23 @@ impl Response {
414
402
  self.res.extensions_mut()
415
403
  }
416
404
 
405
+ /// Forbids the [`Response`] connection from being recycled back into the pool.
406
+ ///
407
+ /// This marks the underlying connection as "poisoned." Once marked, the connection
408
+ /// will be discarded instead of reused after the current request-response cycle completes.
409
+ ///
410
+ /// # Note on Lifecycle
411
+ /// Marking the connection does not trigger an immediate shutdown. For pooled
412
+ /// connections, the physical closure is deferred until the `Response` body
413
+ /// is dropped or the pool's background cleaner reclaims the resource.
414
+ #[inline]
415
+ pub fn forbid_recycle(&self) {
416
+ self.res
417
+ .extensions()
418
+ .get::<Connected>()
419
+ .map(Connected::poison);
420
+ }
421
+
417
422
  // util methods
418
423
 
419
424
  /// Turn a response into an error if the server returned an error.
@@ -471,11 +476,6 @@ impl Response {
471
476
  Ok(self)
472
477
  }
473
478
  }
474
-
475
- /// Consumes the [`Response`] and returns a future for a possible HTTP upgrade.
476
- pub async fn upgrade(self) -> crate::Result<Upgraded> {
477
- upgrade::on(self.res).await.map_err(Error::upgrade)
478
- }
479
479
  }
480
480
 
481
481
  /// I'm not sure this conversion is that useful... People should be encouraged
@@ -503,6 +503,7 @@ impl From<Response> for http::Response<Body> {
503
503
 
504
504
  /// A [`Response`] can be piped as the [`Body`] of another request.
505
505
  impl From<Response> for Body {
506
+ #[inline]
506
507
  fn from(r: Response) -> Body {
507
508
  Body::wrap(r.res.into_body())
508
509
  }
@@ -514,7 +515,7 @@ impl HttpBody for Response {
514
515
 
515
516
  type Error = Error;
516
517
 
517
- #[inline]
518
+ #[inline(always)]
518
519
  fn poll_frame(
519
520
  mut self: Pin<&mut Self>,
520
521
  cx: &mut Context<'_>,
@@ -522,12 +523,12 @@ impl HttpBody for Response {
522
523
  Pin::new(self.res.body_mut()).poll_frame(cx)
523
524
  }
524
525
 
525
- #[inline]
526
+ #[inline(always)]
526
527
  fn is_end_stream(&self) -> bool {
527
528
  self.res.body().is_end_stream()
528
529
  }
529
530
 
530
- #[inline]
531
+ #[inline(always)]
531
532
  fn size_hint(&self) -> http_body::SizeHint {
532
533
  self.res.body().size_hint()
533
534
  }
@@ -0,0 +1,15 @@
1
+ pub use upgrade::Upgraded;
2
+ use wreq_proto::upgrade;
3
+
4
+ use super::response::Response;
5
+ use crate::Error;
6
+
7
+ impl Response {
8
+ /// Consumes the [`Response`] and returns a future for a possible HTTP upgrade.
9
+ #[inline]
10
+ pub async fn upgrade(self) -> crate::Result<Upgraded> {
11
+ upgrade::on(http::Response::from(self))
12
+ .await
13
+ .map_err(Error::upgrade)
14
+ }
15
+ }