wreq-rb 0.6.0 → 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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +257 -102
  3. data/ext/wreq_rb/Cargo.toml +4 -4
  4. data/ext/wreq_rb/src/client.rs +1 -1
  5. data/lib/wreq-rb/version.rb +1 -1
  6. data/patches/0001-add-transfer-size-tracking.patch +11 -15
  7. data/vendor/wreq/Cargo.toml +9 -8
  8. data/vendor/wreq/README.md +5 -5
  9. data/vendor/wreq/bench/support/bench.rs +6 -2
  10. data/vendor/wreq/bench/support/client.rs +88 -1
  11. data/vendor/wreq/bench/support/exec.rs +0 -0
  12. data/vendor/wreq/bench/support/rt.rs +34 -0
  13. data/vendor/wreq/bench/support/server.rs +1 -1
  14. data/vendor/wreq/bench/support.rs +1 -15
  15. data/vendor/wreq/examples/cert_store.rs +13 -13
  16. data/vendor/wreq/examples/request_with_emulate.rs +1 -1
  17. data/vendor/wreq/examples/tcp_linger.rs +22 -0
  18. data/vendor/wreq/src/client/layer/client/pool.rs +17 -17
  19. data/vendor/wreq/src/client/layer/client.rs +2 -0
  20. data/vendor/wreq/src/client/layer/decoder.rs +71 -17
  21. data/vendor/wreq/src/client/layer/redirect/future.rs +49 -63
  22. data/vendor/wreq/src/client/layer/redirect/policy.rs +2 -26
  23. data/vendor/wreq/src/client/layer/redirect.rs +48 -60
  24. data/vendor/wreq/src/client/layer/retry.rs +12 -15
  25. data/vendor/wreq/src/client/layer/timeout/body.rs +27 -21
  26. data/vendor/wreq/src/client/layer/timeout/future.rs +33 -58
  27. data/vendor/wreq/src/client/layer/timeout.rs +8 -14
  28. data/vendor/wreq/src/client/request.rs +4 -0
  29. data/vendor/wreq/src/client.rs +53 -31
  30. data/vendor/wreq/src/conn/connector.rs +99 -129
  31. data/vendor/wreq/src/conn/http.rs +25 -18
  32. data/vendor/wreq/src/conn/net/tcp.rs +601 -107
  33. data/vendor/wreq/src/conn/proxy/socks.rs +6 -6
  34. data/vendor/wreq/src/conn/timeout.rs +166 -0
  35. data/vendor/wreq/src/conn.rs +5 -4
  36. data/vendor/wreq/src/cookie/jar.rs +1225 -0
  37. data/vendor/wreq/src/cookie/store.rs +321 -0
  38. data/vendor/wreq/src/cookie.rs +108 -612
  39. data/vendor/wreq/src/dns/resolve.rs +8 -2
  40. data/vendor/wreq/src/dns.rs +4 -4
  41. data/vendor/wreq/src/error.rs +53 -20
  42. data/vendor/wreq/src/lib.rs +1 -0
  43. data/vendor/wreq/src/proxy/matcher.rs +26 -12
  44. data/vendor/wreq/src/proxy/win.rs +39 -9
  45. data/vendor/wreq/src/redirect.rs +515 -100
  46. data/vendor/wreq/src/tls/conn.rs +3 -11
  47. data/vendor/wreq/src/tls/session.rs +7 -8
  48. data/vendor/wreq/src/tls/trust/store.rs +4 -4
  49. data/vendor/wreq/src/util.rs +23 -0
  50. data/vendor/wreq/tests/badssl.rs +72 -7
  51. data/vendor/wreq/tests/brotli.rs +1 -1
  52. data/vendor/wreq/tests/client.rs +24 -0
  53. data/vendor/wreq/tests/connector_layers.rs +8 -4
  54. data/vendor/wreq/tests/cookie.rs +59 -0
  55. data/vendor/wreq/tests/deflate.rs +1 -1
  56. data/vendor/wreq/tests/gzip.rs +53 -1
  57. data/vendor/wreq/tests/layers.rs +8 -4
  58. data/vendor/wreq/tests/redirect.rs +180 -97
  59. data/vendor/wreq/tests/timeouts.rs +47 -12
  60. data/vendor/wreq/tests/zstd.rs +1 -1
  61. metadata +7 -1
@@ -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.
@@ -10,11 +10,12 @@ use std::{
10
10
 
11
11
  use futures_util::future::Either;
12
12
  use http::{Request, Response};
13
- use http_body::Body;
13
+ use http_body::Body as HttpBody;
14
14
  use tower::{BoxError, Layer, Service};
15
15
 
16
16
  use self::future::ResponseFuture;
17
- pub use self::policy::{Action, Attempt, Policy};
17
+ pub use self::policy::{Action, Attempt};
18
+ use crate::{client::body::Body, redirect::FollowRedirectPolicy};
18
19
 
19
20
  enum BodyRepr<B> {
20
21
  Some(B),
@@ -22,31 +23,25 @@ enum BodyRepr<B> {
22
23
  None,
23
24
  }
24
25
 
25
- impl<B> BodyRepr<B>
26
- where
27
- B: Body + Default,
28
- {
29
- fn take(&mut self) -> Option<B> {
26
+ impl BodyRepr<Body> {
27
+ fn take(&mut self) -> Option<Body> {
30
28
  match mem::replace(self, BodyRepr::None) {
31
29
  BodyRepr::Some(body) => Some(body),
32
30
  BodyRepr::Empty => {
33
31
  *self = BodyRepr::Empty;
34
- Some(B::default())
32
+ Some(Body::default())
35
33
  }
36
34
  BodyRepr::None => None,
37
35
  }
38
36
  }
39
37
 
40
- fn try_clone_from<P, E>(&mut self, body: &B, policy: &P)
41
- where
42
- P: Policy<B, E>,
43
- {
38
+ fn try_clone_from(&mut self, body: &Body) {
44
39
  match self {
45
40
  BodyRepr::Some(_) | BodyRepr::Empty => {}
46
41
  BodyRepr::None => {
47
42
  if body.size_hint().exact() == Some(0) {
48
- *self = BodyRepr::Some(B::default());
49
- } else if let Some(cloned) = policy.clone_body(body) {
43
+ *self = BodyRepr::Some(Body::default());
44
+ } else if let Some(cloned) = body.try_clone() {
50
45
  *self = BodyRepr::Some(cloned);
51
46
  }
52
47
  }
@@ -55,25 +50,24 @@ where
55
50
  }
56
51
 
57
52
  /// [`Layer`] for retrying requests with a [`Service`] to follow redirection responses.
58
- #[derive(Clone, Copy, Default)]
59
- pub struct FollowRedirectLayer<P> {
60
- policy: P,
53
+ #[derive(Clone)]
54
+ pub struct FollowRedirectLayer {
55
+ policy: FollowRedirectPolicy,
61
56
  }
62
57
 
63
- impl<P> FollowRedirectLayer<P> {
64
- /// Create a new [`FollowRedirectLayer`] with the given redirection [`Policy`].
58
+ impl FollowRedirectLayer {
59
+ /// Create a new [`FollowRedirectLayer`] with the given redirection policy.
65
60
  #[inline(always)]
66
- pub fn with_policy(policy: P) -> Self {
61
+ pub(crate) fn with_policy(policy: FollowRedirectPolicy) -> Self {
67
62
  FollowRedirectLayer { policy }
68
63
  }
69
64
  }
70
65
 
71
- impl<S, P> Layer<S> for FollowRedirectLayer<P>
66
+ impl<S> Layer<S> for FollowRedirectLayer
72
67
  where
73
68
  S: Clone,
74
- P: Clone,
75
69
  {
76
- type Service = FollowRedirect<S, P>;
70
+ type Service = FollowRedirect<S>;
77
71
 
78
72
  #[inline(always)]
79
73
  fn layer(&self, inner: S) -> Self::Service {
@@ -82,63 +76,57 @@ where
82
76
  }
83
77
 
84
78
  /// Middleware that retries requests with a [`Service`] to follow redirection responses.
85
- #[derive(Clone, Copy)]
86
- pub struct FollowRedirect<S, P> {
79
+ #[derive(Clone)]
80
+ pub struct FollowRedirect<S> {
87
81
  inner: S,
88
- policy: P,
82
+ policy: FollowRedirectPolicy,
89
83
  }
90
84
 
91
- impl<S, P> FollowRedirect<S, P>
92
- where
93
- P: Clone,
94
- {
95
- /// Create a new [`FollowRedirect`] with the given redirection [`Policy`].
85
+ impl<S> FollowRedirect<S> {
86
+ /// Create a new [`FollowRedirect`] with the given redirection policy.
96
87
  #[inline(always)]
97
- pub fn with_policy(inner: S, policy: P) -> Self {
88
+ fn with_policy(inner: S, policy: FollowRedirectPolicy) -> Self {
98
89
  FollowRedirect { inner, policy }
99
90
  }
100
91
  }
101
92
 
102
- impl<ReqBody, ResBody, S, P> Service<Request<ReqBody>> for FollowRedirect<S, P>
93
+ impl<ResBody, S> Service<Request<Body>> for FollowRedirect<S>
103
94
  where
104
- S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone,
95
+ S: Service<Request<Body>, Response = Response<ResBody>> + Clone,
105
96
  S::Error: From<BoxError>,
106
- P: Policy<ReqBody, S::Error> + Clone,
107
- ReqBody: Body + Default,
108
97
  {
109
98
  type Response = Response<ResBody>;
110
99
  type Error = S::Error;
111
- type Future = ResponseFuture<S, ReqBody, P>;
100
+ type Future = ResponseFuture<S>;
112
101
 
113
102
  #[inline(always)]
114
103
  fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
115
104
  self.inner.poll_ready(cx)
116
105
  }
117
106
 
118
- fn call(&mut self, mut req: Request<ReqBody>) -> Self::Future {
119
- if self.policy.follow_redirects(&mut req) {
120
- let service = self.inner.clone();
121
- let mut service = mem::replace(&mut self.inner, service);
122
- let mut policy = self.policy.clone();
123
-
124
- let mut body_repr = BodyRepr::None;
125
- body_repr.try_clone_from(req.body(), &policy);
126
- policy.on_request(&mut req);
127
-
128
- let (parts, body) = req.into_parts();
129
- let req = Request::from_parts(parts.clone(), body);
130
- ResponseFuture::Redirect {
131
- future: Either::Left(service.call(req)),
132
- pending_future: None,
133
- service,
134
- policy,
135
- parts,
136
- body_repr,
137
- }
138
- } else {
139
- ResponseFuture::Direct {
107
+ fn call(&mut self, mut req: Request<Body>) -> Self::Future {
108
+ let Some(mut policy) = self.policy.for_request(&mut req) else {
109
+ return ResponseFuture::Direct {
140
110
  future: self.inner.call(req),
141
- }
111
+ };
112
+ };
113
+
114
+ let service = self.inner.clone();
115
+ let mut service = mem::replace(&mut self.inner, service);
116
+
117
+ let mut body_repr = BodyRepr::None;
118
+ body_repr.try_clone_from(req.body());
119
+
120
+ policy.on_request(&mut req);
121
+ let (parts, body) = req.into_parts();
122
+ let request = Request::from_parts(parts, ());
123
+ ResponseFuture::Redirect {
124
+ future: Either::Left(service.call(request.clone().map(|_| body))),
125
+ pending_future: None,
126
+ service,
127
+ policy,
128
+ request,
129
+ body_repr,
142
130
  }
143
131
  }
144
132
  }
@@ -132,22 +132,19 @@ fn is_retryable_error(err: &(dyn StdError + 'static)) -> bool {
132
132
  return false;
133
133
  };
134
134
 
135
- if let Some(cause) = err.source() {
136
- if let Some(err) = cause.downcast_ref::<http2::Error>() {
137
- // They sent us a graceful shutdown, try with a new connection!
138
- if err.is_go_away() && err.is_remote() && err.reason() == Some(http2::Reason::NO_ERROR)
139
- {
140
- return true;
141
- }
135
+ if let Some(cause) = err.source()
136
+ && let Some(err) = cause.downcast_ref::<http2::Error>()
137
+ {
138
+ // They sent us a graceful shutdown, try with a new connection!
139
+ if err.is_go_away() && err.is_remote() && err.reason() == Some(http2::Reason::NO_ERROR) {
140
+ return true;
141
+ }
142
142
 
143
- // REFUSED_STREAM was sent from the server, which is safe to retry.
144
- // https://www.rfc-editor.org/rfc/rfc9113.html#section-8.7-3.2
145
- if err.is_reset()
146
- && err.is_remote()
147
- && err.reason() == Some(http2::Reason::REFUSED_STREAM)
148
- {
149
- return true;
150
- }
143
+ // REFUSED_STREAM was sent from the server, which is safe to retry.
144
+ // https://www.rfc-editor.org/rfc/rfc9113.html#section-8.7-3.2
145
+ if err.is_reset() && err.is_remote() && err.reason() == Some(http2::Reason::REFUSED_STREAM)
146
+ {
147
+ return true;
151
148
  }
152
149
  }
153
150
  false