wreq-rb 0.5.1 → 0.6.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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +257 -102
  3. data/README.md +28 -0
  4. data/ext/wreq_rb/Cargo.toml +4 -4
  5. data/ext/wreq_rb/src/client.rs +176 -2
  6. data/lib/wreq-rb/version.rb +1 -1
  7. data/patches/0001-add-transfer-size-tracking.patch +11 -15
  8. data/vendor/wreq/Cargo.toml +9 -8
  9. data/vendor/wreq/README.md +5 -5
  10. data/vendor/wreq/bench/support/bench.rs +6 -2
  11. data/vendor/wreq/bench/support/client.rs +88 -1
  12. data/vendor/wreq/bench/support/exec.rs +0 -0
  13. data/vendor/wreq/bench/support/rt.rs +34 -0
  14. data/vendor/wreq/bench/support/server.rs +1 -1
  15. data/vendor/wreq/bench/support.rs +1 -15
  16. data/vendor/wreq/examples/cert_store.rs +13 -13
  17. data/vendor/wreq/examples/request_with_emulate.rs +1 -1
  18. data/vendor/wreq/examples/tcp_linger.rs +22 -0
  19. data/vendor/wreq/src/client/layer/client/pool.rs +17 -17
  20. data/vendor/wreq/src/client/layer/client.rs +2 -0
  21. data/vendor/wreq/src/client/layer/decoder.rs +71 -17
  22. data/vendor/wreq/src/client/layer/redirect/future.rs +49 -63
  23. data/vendor/wreq/src/client/layer/redirect/policy.rs +2 -26
  24. data/vendor/wreq/src/client/layer/redirect.rs +48 -60
  25. data/vendor/wreq/src/client/layer/retry.rs +12 -15
  26. data/vendor/wreq/src/client/layer/timeout/body.rs +27 -21
  27. data/vendor/wreq/src/client/layer/timeout/future.rs +33 -58
  28. data/vendor/wreq/src/client/layer/timeout.rs +8 -14
  29. data/vendor/wreq/src/client/request.rs +4 -0
  30. data/vendor/wreq/src/client.rs +53 -31
  31. data/vendor/wreq/src/conn/connector.rs +99 -129
  32. data/vendor/wreq/src/conn/http.rs +25 -18
  33. data/vendor/wreq/src/conn/net/tcp.rs +601 -107
  34. data/vendor/wreq/src/conn/proxy/socks.rs +6 -6
  35. data/vendor/wreq/src/conn/timeout.rs +166 -0
  36. data/vendor/wreq/src/conn.rs +5 -4
  37. data/vendor/wreq/src/cookie/jar.rs +1225 -0
  38. data/vendor/wreq/src/cookie/store.rs +321 -0
  39. data/vendor/wreq/src/cookie.rs +108 -612
  40. data/vendor/wreq/src/dns/resolve.rs +8 -2
  41. data/vendor/wreq/src/dns.rs +4 -4
  42. data/vendor/wreq/src/error.rs +53 -20
  43. data/vendor/wreq/src/lib.rs +1 -0
  44. data/vendor/wreq/src/proxy/matcher.rs +26 -12
  45. data/vendor/wreq/src/proxy/win.rs +39 -9
  46. data/vendor/wreq/src/redirect.rs +515 -100
  47. data/vendor/wreq/src/tls/conn.rs +3 -11
  48. data/vendor/wreq/src/tls/session.rs +7 -8
  49. data/vendor/wreq/src/tls/trust/store.rs +4 -4
  50. data/vendor/wreq/src/util.rs +23 -0
  51. data/vendor/wreq/tests/badssl.rs +72 -7
  52. data/vendor/wreq/tests/brotli.rs +1 -1
  53. data/vendor/wreq/tests/client.rs +24 -0
  54. data/vendor/wreq/tests/connector_layers.rs +8 -4
  55. data/vendor/wreq/tests/cookie.rs +59 -0
  56. data/vendor/wreq/tests/deflate.rs +1 -1
  57. data/vendor/wreq/tests/gzip.rs +53 -1
  58. data/vendor/wreq/tests/layers.rs +8 -4
  59. data/vendor/wreq/tests/redirect.rs +180 -97
  60. data/vendor/wreq/tests/timeouts.rs +47 -12
  61. data/vendor/wreq/tests/zstd.rs +1 -1
  62. metadata +8 -2
@@ -1,5 +1,6 @@
1
1
  pub mod bench;
2
2
  pub mod client;
3
+ pub mod rt;
3
4
  pub mod server;
4
5
 
5
6
  use std::fmt;
@@ -39,18 +40,3 @@ impl fmt::Display for Tls {
39
40
  f.write_str(value)
40
41
  }
41
42
  }
42
-
43
- pub fn current_thread_runtime() -> tokio::runtime::Runtime {
44
- tokio::runtime::Builder::new_current_thread()
45
- .enable_all()
46
- .build()
47
- .expect("Failed to build current-thread runtime")
48
- }
49
-
50
- pub fn multi_thread_runtime() -> tokio::runtime::Runtime {
51
- tokio::runtime::Builder::new_multi_thread()
52
- .worker_threads(4)
53
- .enable_all()
54
- .build()
55
- .expect("Failed to build multi-thread runtime")
56
- }
@@ -56,21 +56,21 @@ async fn main() -> wreq::Result<()> {
56
56
 
57
57
  // Use the API you're already familiar with
58
58
  let resp = client.get("https://self-signed.badssl.com/").send().await?;
59
- if let Some(tls_info) = resp.extensions().get::<TlsInfo>() {
60
- if let Some(peer_cert_der) = tls_info.peer_certificate() {
61
- // Create self-signed certificate Store
62
- let self_signed_store = CertStore::from_der_certs(&[peer_cert_der])?;
59
+ if let Some(tls_info) = resp.extensions().get::<TlsInfo>()
60
+ && let Some(peer_cert_der) = tls_info.peer_certificate()
61
+ {
62
+ // Create self-signed certificate Store
63
+ let self_signed_store = CertStore::from_der_certs([peer_cert_der])?;
63
64
 
64
- // Create a client with self-signed certificate store
65
- let client = Client::builder()
66
- .tls_cert_store(self_signed_store)
67
- .connect_timeout(Duration::from_secs(10))
68
- .build()?;
65
+ // Create a client with self-signed certificate store
66
+ let client = Client::builder()
67
+ .tls_cert_store(self_signed_store)
68
+ .connect_timeout(Duration::from_secs(10))
69
+ .build()?;
69
70
 
70
- // Use the API you're already familiar with
71
- let resp = client.get("https://self-signed.badssl.com/").send().await?;
72
- println!("{}", resp.text().await?);
73
- }
71
+ // Use the API you're already familiar with
72
+ let resp = client.get("https://self-signed.badssl.com/").send().await?;
73
+ println!("{}", resp.text().await?);
74
74
  }
75
75
 
76
76
  Ok(())
@@ -105,7 +105,7 @@ async fn main() -> wreq::Result<()> {
105
105
  .build(Default::default());
106
106
 
107
107
  // Use the API you're already familiar with
108
- let resp = wreq::get("https://tls.peet.ws/api/all")
108
+ let resp = wreq::get("https://pingly.us.kg/api/all")
109
109
  .emulation(emulation)
110
110
  .send()
111
111
  .await?;
@@ -0,0 +1,22 @@
1
+ use std::time::Duration;
2
+
3
+ use wreq::Client;
4
+
5
+ #[tokio::main]
6
+ async fn main() -> wreq::Result<()> {
7
+ // Reset connections on close rather than closing them gracefully.
8
+ let client = Client::builder().tcp_linger(Duration::ZERO).build()?;
9
+
10
+ let resp = client.get("https://tls.peet.ws/api/all").send().await?;
11
+ println!("{}", resp.text().await?);
12
+
13
+ // Non-zero duration waits for unsent data to be flushed.
14
+ let client = Client::builder()
15
+ .tcp_linger(Duration::from_secs(5))
16
+ .build()?;
17
+
18
+ let resp = client.get("https://tls.peet.ws/api/all").send().await?;
19
+ println!("{}", resp.text().await?);
20
+
21
+ Ok(())
22
+ }
@@ -156,20 +156,20 @@ impl<T: Poolable, K: Key> Pool<T, K> {
156
156
  /// Ensure that there is only ever 1 connecting task for HTTP/2
157
157
  /// connections. This does nothing for HTTP/1.
158
158
  pub fn connecting(&self, key: K, ver: Ver) -> Option<Connecting<T, K>> {
159
- if ver == Ver::Http2 {
160
- if let Some(ref enabled) = self.inner {
161
- let mut inner = enabled.lock();
162
- return if inner.connecting.insert(key.clone()) {
163
- let connecting = Connecting {
164
- key,
165
- pool: WeakOpt::downgrade(enabled),
166
- };
167
- Some(connecting)
168
- } else {
169
- trace!("HTTP/2 connecting already in progress for {:?}", key);
170
- None
159
+ if ver == Ver::Http2
160
+ && let Some(ref enabled) = self.inner
161
+ {
162
+ let mut inner = enabled.lock();
163
+ return if inner.connecting.insert(key.clone()) {
164
+ let connecting = Connecting {
165
+ key,
166
+ pool: WeakOpt::downgrade(enabled),
171
167
  };
172
- }
168
+ Some(connecting)
169
+ } else {
170
+ trace!("HTTP/2 connecting already in progress for {:?}", key);
171
+ None
172
+ };
173
173
  }
174
174
 
175
175
  // else
@@ -233,10 +233,10 @@ impl<T: Poolable, K: Key> Pool<T, K> {
233
233
  // unique or shared. So, the hack is to just assume Ver::Http2 means
234
234
  // shared... :(
235
235
  let mut pool_ref = WeakOpt::none();
236
- if !value.can_share() {
237
- if let Some(ref enabled) = self.inner {
238
- pool_ref = WeakOpt::downgrade(enabled);
239
- }
236
+ if !value.can_share()
237
+ && let Some(ref enabled) = self.inner
238
+ {
239
+ pool_ref = WeakOpt::downgrade(enabled);
240
240
  }
241
241
 
242
242
  Pooled {
@@ -232,6 +232,7 @@ where
232
232
  }
233
233
  }
234
234
 
235
+ #[allow(clippy::result_large_err)]
235
236
  async fn try_send_request(
236
237
  &self,
237
238
  mut req: Request<B>,
@@ -751,6 +752,7 @@ impl<B> PoolClient<B> {
751
752
 
752
753
  impl<B: Body + 'static> PoolClient<B> {
753
754
  #[inline]
755
+ #[allow(clippy::result_large_err)]
754
756
  fn try_send_request(
755
757
  &mut self,
756
758
  req: Request<B>,
@@ -2,7 +2,10 @@
2
2
 
3
3
  use std::task::{Context, Poll};
4
4
 
5
- use http::{Request, Response};
5
+ use http::{
6
+ HeaderValue, Request, Response,
7
+ header::{ACCEPT_ENCODING, RANGE},
8
+ };
6
9
  use http_body::Body;
7
10
  use tower::{Layer, Service};
8
11
  use tower_http::decompression::{self, DecompressionBody, ResponseFuture};
@@ -26,15 +29,26 @@ pub(crate) struct AcceptEncoding {
26
29
  pub(crate) deflate: bool,
27
30
  }
28
31
 
29
- /// Layer that adds response body decompression to a service.
32
+ /// Builds response decompression middleware for a client service.
33
+ ///
34
+ /// `DecompressionLayer` stores the client's default [`AcceptEncoding`] configuration
35
+ /// and applies it when constructing a [`Decompression`] service.
30
36
  #[derive(Clone)]
31
37
  pub struct DecompressionLayer {
32
38
  accept: AcceptEncoding,
33
39
  }
34
40
 
35
- /// Service that decompresses response bodies based on the [`AcceptEncoding`] configuration.
41
+ /// Negotiates response encodings and transparently decodes response bodies.
42
+ ///
43
+ /// Before forwarding a request, `Decompression` applies request-specific
44
+ /// [`AcceptEncoding`] settings and keeps range requests on the identity representation.
45
+ /// The wrapped `tower-http` service then advertises enabled encodings and decodes matching
46
+ /// responses.
36
47
  #[derive(Clone)]
37
- pub struct Decompression<S>(Option<decompression::Decompression<S>>);
48
+ pub struct Decompression<S> {
49
+ decoder: Option<decompression::Decompression<S>>,
50
+ enabled: bool,
51
+ }
38
52
 
39
53
  // ===== AcceptEncoding =====
40
54
 
@@ -53,6 +67,32 @@ impl Default for AcceptEncoding {
53
67
  }
54
68
  }
55
69
 
70
+ impl AcceptEncoding {
71
+ fn is_enabled(&self) -> bool {
72
+ #[cfg(feature = "gzip")]
73
+ if self.gzip {
74
+ return true;
75
+ }
76
+
77
+ #[cfg(feature = "deflate")]
78
+ if self.deflate {
79
+ return true;
80
+ }
81
+
82
+ #[cfg(feature = "brotli")]
83
+ if self.brotli {
84
+ return true;
85
+ }
86
+
87
+ #[cfg(feature = "zstd")]
88
+ if self.zstd {
89
+ return true;
90
+ }
91
+
92
+ false
93
+ }
94
+ }
95
+
56
96
  impl_request_config_value!(AcceptEncoding);
57
97
 
58
98
  // ===== impl DecompressionLayer =====
@@ -75,10 +115,10 @@ impl<S> Layer<S> for DecompressionLayer {
75
115
  .no_deflate()
76
116
  .no_gzip()
77
117
  .no_zstd();
78
- Decompression(Some(Decompression::<S>::accept_in_place(
79
- decoder,
80
- &self.accept,
81
- )))
118
+ Decompression {
119
+ decoder: Some(Decompression::<S>::accept_in_place(decoder, &self.accept)),
120
+ enabled: self.accept.is_enabled(),
121
+ }
82
122
  }
83
123
  }
84
124
 
@@ -127,18 +167,32 @@ where
127
167
 
128
168
  #[inline(always)]
129
169
  fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
130
- self.0.as_mut().expect(Self::BUG_MSG).poll_ready(cx)
170
+ self.decoder.as_mut().expect(Self::BUG_MSG).poll_ready(cx)
131
171
  }
132
172
 
133
- fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
134
- if let Some(accept_encoding) = RequestConfig::<AcceptEncoding>::get(req.extensions()) {
135
- if let Some(decoder) = self.0.take() {
136
- self.0
137
- .replace(Decompression::accept_in_place(decoder, accept_encoding));
138
- }
139
- debug_assert!(self.0.is_some());
173
+ fn call(&mut self, mut req: Request<ReqBody>) -> Self::Future {
174
+ let enabled =
175
+ if let Some(accept_encoding) = RequestConfig::<AcceptEncoding>::get(req.extensions()) {
176
+ if let Some(decoder) = self.decoder.take() {
177
+ self.decoder
178
+ .replace(Decompression::accept_in_place(decoder, accept_encoding));
179
+ }
180
+ debug_assert!(self.decoder.is_some());
181
+ accept_encoding.is_enabled()
182
+ } else {
183
+ self.enabled
184
+ };
185
+
186
+ if enabled && req.headers().contains_key(RANGE) {
187
+ // tower-http does not account for Range when adding Accept-Encoding, so correct it
188
+ // before delegating. RFC 9110 section 14.1.2 applies byte ranges to the encoded
189
+ // representation, and Fetch avoids partial codings by requesting identity:
190
+ // https://www.rfc-editor.org/rfc/rfc9110.html#section-14.1.2
191
+ // https://fetch.spec.whatwg.org/#http-network-or-cache-fetch
192
+ req.headers_mut()
193
+ .insert(ACCEPT_ENCODING, HeaderValue::from_static("identity"));
140
194
  }
141
195
 
142
- self.0.as_mut().expect(Self::BUG_MSG).call(req)
196
+ self.decoder.as_mut().expect(Self::BUG_MSG).call(req)
143
197
  }
144
198
  }
@@ -9,42 +9,40 @@ use futures_util::future::Either;
9
9
  use http::{
10
10
  HeaderMap, Method, Request, Response, StatusCode, Uri,
11
11
  header::{CONTENT_ENCODING, CONTENT_LENGTH, CONTENT_TYPE, LOCATION, TRANSFER_ENCODING},
12
- request::Parts,
13
12
  };
14
- use http_body::Body;
15
13
  use pin_project_lite::pin_project;
16
14
  use tower::{BoxError, Service, util::Oneshot};
17
15
  use url::Url;
18
16
 
19
17
  use super::{
20
18
  BodyRepr,
21
- policy::{Action, Attempt, Policy},
19
+ policy::{Action, Attempt},
22
20
  };
23
- use crate::{Error, ext::RequestUri, into_uri::IntoUriSealed};
21
+ use crate::{Body, ext::RequestUri, into_uri::IntoUriSealed, redirect::FollowRedirectPolicy};
24
22
 
25
23
  /// Pending future state for handling redirects.
26
- pub struct Pending<ReqBody, Response> {
24
+ pub struct Pending<Response> {
27
25
  future: Pin<Box<dyn Future<Output = Action> + Send>>,
28
26
  location: Uri,
29
- body: ReqBody,
27
+ body: Body,
30
28
  res: Response,
31
29
  }
32
30
 
33
31
  pin_project! {
34
32
  /// Response future for [`FollowRedirect`].
35
33
  #[project = ResponseFutureProj]
36
- pub enum ResponseFuture<S, B, P>
34
+ pub enum ResponseFuture<S>
37
35
  where
38
- S: Service<Request<B>>,
36
+ S: Service<Request<Body>>,
39
37
  {
40
38
  Redirect {
41
39
  #[pin]
42
- future: Either<S::Future, Oneshot<S, Request<B>>>,
43
- pending_future: Option<Pending<B, S::Response>>,
40
+ future: Either<S::Future, Oneshot<S, Request<Body>>>,
41
+ pending_future: Option<Pending<S::Response>>,
44
42
  service: S,
45
- policy: P,
46
- parts: Parts,
47
- body_repr: BodyRepr<B>,
43
+ policy: FollowRedirectPolicy,
44
+ request: Request<()>,
45
+ body_repr: BodyRepr<Body>,
48
46
  },
49
47
 
50
48
  Direct {
@@ -54,14 +52,12 @@ pin_project! {
54
52
  }
55
53
  }
56
54
 
57
- impl<S, ReqBody, ResBody, P> Future for ResponseFuture<S, ReqBody, P>
55
+ impl<S, B> Future for ResponseFuture<S>
58
56
  where
59
- S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone,
57
+ S: Service<Request<Body>, Response = Response<B>> + Clone,
60
58
  S::Error: From<BoxError>,
61
- P: Policy<ReqBody, S::Error>,
62
- ReqBody: Body + Default,
63
59
  {
64
- type Output = Result<Response<ResBody>, S::Error>;
60
+ type Output = Result<Response<B>, S::Error>;
65
61
 
66
62
  fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
67
63
  match self.project() {
@@ -71,7 +67,7 @@ where
71
67
  pending_future,
72
68
  service,
73
69
  policy,
74
- parts,
70
+ request,
75
71
  body_repr,
76
72
  } => {
77
73
  // Check if we have a pending action to resolve
@@ -91,7 +87,7 @@ where
91
87
  future: &mut future,
92
88
  service,
93
89
  policy,
94
- parts,
90
+ request,
95
91
  body: state.body,
96
92
  body_repr,
97
93
  res: state.res,
@@ -103,7 +99,8 @@ where
103
99
  // Poll the current future to get the response
104
100
  let mut res = {
105
101
  let mut res = ready!(future.as_mut().poll(cx)?);
106
- res.extensions_mut().insert(RequestUri(parts.uri.clone()));
102
+ res.extensions_mut()
103
+ .insert(RequestUri(request.uri().clone()));
107
104
  res
108
105
  };
109
106
 
@@ -112,19 +109,19 @@ where
112
109
  StatusCode::MOVED_PERMANENTLY | StatusCode::FOUND => {
113
110
  // User agents MAY change the request method from POST to GET
114
111
  // (RFC 7231 section 6.4.2. and 6.4.3.).
115
- if parts.method == Method::POST {
116
- parts.method = Method::GET;
112
+ if request.method() == Method::POST {
113
+ *request.method_mut() = Method::GET;
117
114
  *body_repr = BodyRepr::Empty;
118
- drop_payload_headers(&mut parts.headers);
115
+ drop_payload_headers(request.headers_mut());
119
116
  }
120
117
  }
121
118
  StatusCode::SEE_OTHER => {
122
119
  // A user agent can perform a GET or HEAD request (RFC 7231 section 6.4.4.).
123
- if parts.method != Method::HEAD {
124
- parts.method = Method::GET;
120
+ if request.method() != Method::HEAD {
121
+ *request.method_mut() = Method::GET;
125
122
  }
126
123
  *body_repr = BodyRepr::Empty;
127
- drop_payload_headers(&mut parts.headers);
124
+ drop_payload_headers(request.headers_mut());
128
125
  }
129
126
  StatusCode::TEMPORARY_REDIRECT | StatusCode::PERMANENT_REDIRECT => {}
130
127
  _ => {
@@ -144,7 +141,7 @@ where
144
141
  .headers()
145
142
  .get(LOCATION)
146
143
  .and_then(|loc| loc.to_str().ok())
147
- .and_then(|loc| resolve_uri(loc, &parts.uri))
144
+ .and_then(|loc| resolve_uri(loc, request.uri()))
148
145
  else {
149
146
  return Poll::Ready(Ok(res));
150
147
  };
@@ -154,7 +151,7 @@ where
154
151
  status: res.status(),
155
152
  headers: res.headers(),
156
153
  location: &location,
157
- previous: &parts.uri,
154
+ previous: request.uri(),
158
155
  };
159
156
 
160
157
  // Resolve the action, awaiting if it's pending
@@ -180,7 +177,7 @@ where
180
177
  future: &mut future,
181
178
  service,
182
179
  policy,
183
- parts,
180
+ request,
184
181
  body,
185
182
  body_repr,
186
183
  res,
@@ -215,59 +212,48 @@ fn drop_payload_headers(headers: &mut HeaderMap) {
215
212
  }
216
213
  }
217
214
 
218
- type RedirectFuturePin<'a, S, ReqBody> =
219
- Pin<&'a mut Either<<S as Service<Request<ReqBody>>>::Future, Oneshot<S, Request<ReqBody>>>>;
215
+ type RedirectFuturePin<'a, S> =
216
+ Pin<&'a mut Either<<S as Service<Request<Body>>>::Future, Oneshot<S, Request<Body>>>>;
220
217
 
221
- struct RedirectAction<'a, S, ReqBody, ResBody, P>
218
+ struct RedirectAction<'a, S, B>
222
219
  where
223
- S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone,
224
- P: Policy<ReqBody, S::Error>,
220
+ S: Service<Request<Body>, Response = Response<B>> + Clone,
225
221
  {
226
222
  action: Action,
227
- future: &'a mut RedirectFuturePin<'a, S, ReqBody>,
223
+ future: &'a mut RedirectFuturePin<'a, S>,
228
224
  service: &'a S,
229
- policy: &'a mut P,
230
- parts: &'a mut Parts,
231
- body: ReqBody,
232
- body_repr: &'a mut BodyRepr<ReqBody>,
233
- res: Response<ResBody>,
225
+ policy: &'a mut FollowRedirectPolicy,
226
+ request: &'a mut Request<()>,
227
+ body: Body,
228
+ body_repr: &'a mut BodyRepr<Body>,
229
+ res: Response<B>,
234
230
  location: Uri,
235
231
  }
236
232
 
237
- fn handle_action<S, ReqBody, ResBody, P>(
233
+ fn handle_action<S, B>(
238
234
  cx: &mut Context<'_>,
239
- redirect: RedirectAction<'_, S, ReqBody, ResBody, P>,
240
- ) -> Poll<Result<Response<ResBody>, S::Error>>
235
+ redirect: RedirectAction<'_, S, B>,
236
+ ) -> Poll<Result<Response<B>, S::Error>>
241
237
  where
242
- S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone,
238
+ S: Service<Request<Body>, Response = Response<B>> + Clone,
243
239
  S::Error: From<BoxError>,
244
- P: Policy<ReqBody, S::Error>,
245
- ReqBody: Body + Default,
246
240
  {
247
241
  match redirect.action {
248
242
  Action::Follow => {
249
- redirect.parts.uri = redirect.location;
250
- redirect
251
- .body_repr
252
- .try_clone_from(&redirect.body, redirect.policy);
243
+ *redirect.request.uri_mut() = redirect.location;
244
+ redirect.body_repr.try_clone_from(&redirect.body);
245
+ redirect.policy.on_request(redirect.request);
253
246
 
254
- let mut req = Request::from_parts(redirect.parts.clone(), redirect.body);
255
- redirect.policy.on_request(&mut req);
256
- redirect
257
- .future
258
- .set(Either::Right(Oneshot::new(redirect.service.clone(), req)));
247
+ redirect.future.set(Either::Right(Oneshot::new(
248
+ redirect.service.clone(),
249
+ redirect.request.clone().map(|_| redirect.body),
250
+ )));
259
251
 
260
252
  cx.waker().wake_by_ref();
261
253
  Poll::Pending
262
254
  }
263
255
  Action::Stop => Poll::Ready(Ok(redirect.res)),
264
- Action::Pending(_) => Poll::Ready(Err(S::Error::from(
265
- Error::redirect(
266
- "Nested pending Action is not supported in redirect policy",
267
- redirect.parts.uri.clone(),
268
- )
269
- .into(),
270
- ))),
271
256
  Action::Error(err) => Poll::Ready(Err(err.into())),
257
+ Action::Pending(_) => unreachable!(),
272
258
  }
273
259
  }
@@ -2,34 +2,10 @@
2
2
 
3
3
  use std::{fmt, pin::Pin};
4
4
 
5
- use http::{HeaderMap, Request, Response, StatusCode, Uri};
5
+ use http::{HeaderMap, StatusCode, Uri};
6
6
 
7
7
  use crate::error::BoxError;
8
8
 
9
- /// Trait for the policy on handling redirection responses.
10
- pub trait Policy<B, E> {
11
- /// Invoked when the service received a response with a redirection status code (`3xx`).
12
- ///
13
- /// This method returns an [`Action`] which indicates whether the service should follow
14
- /// the redirection.
15
- fn redirect(&mut self, attempt: Attempt<'_>) -> Result<Action, E>;
16
-
17
- /// Returns whether redirection is currently permitted by this policy.
18
- ///
19
- /// This method is called to determine whether the client should follow redirects at all.
20
- /// It allows policies to enable or disable redirection behavior based on the [`Request`].
21
- fn follow_redirects(&mut self, _request: &mut Request<B>) -> bool;
22
-
23
- /// Invoked right before the service makes a [`Request`].
24
- fn on_request(&mut self, _request: &mut Request<B>);
25
-
26
- /// Invoked right after the service received a [`Response`].
27
- fn on_response<Body>(&mut self, _response: &mut Response<Body>);
28
-
29
- /// Try to clone a request body before the service makes a redirected request.
30
- fn clone_body(&self, _body: &B) -> Option<B>;
31
- }
32
-
33
9
  /// A type that holds information on a redirection attempt.
34
10
  pub struct Attempt<'a> {
35
11
  pub(crate) status: StatusCode,
@@ -38,7 +14,7 @@ pub struct Attempt<'a> {
38
14
  pub(crate) previous: &'a Uri,
39
15
  }
40
16
 
41
- /// A value returned by [`Policy::redirect`] which indicates the action
17
+ /// A value which indicates the action
42
18
  /// [`FollowRedirect`][super::FollowRedirect] should take for a redirection response.
43
19
  pub enum Action {
44
20
  /// Follow the redirection.