wreq-rb 0.6.0 → 0.6.2
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.
- checksums.yaml +4 -4
- data/Cargo.lock +257 -102
- data/ext/wreq_rb/Cargo.toml +7 -4
- data/ext/wreq_rb/src/client.rs +105 -15
- data/ext/wreq_rb/src/response.rs +28 -3
- data/lib/wreq-rb/version.rb +1 -1
- data/patches/0001-add-transfer-size-tracking.patch +11 -15
- data/vendor/wreq/Cargo.toml +9 -8
- data/vendor/wreq/README.md +5 -5
- data/vendor/wreq/bench/support/bench.rs +6 -2
- data/vendor/wreq/bench/support/client.rs +88 -1
- data/vendor/wreq/bench/support/exec.rs +0 -0
- data/vendor/wreq/bench/support/rt.rs +34 -0
- data/vendor/wreq/bench/support/server.rs +1 -1
- data/vendor/wreq/bench/support.rs +1 -15
- data/vendor/wreq/examples/cert_store.rs +13 -13
- data/vendor/wreq/examples/request_with_emulate.rs +1 -1
- data/vendor/wreq/examples/tcp_linger.rs +22 -0
- data/vendor/wreq/src/client/layer/client/pool.rs +17 -17
- data/vendor/wreq/src/client/layer/client.rs +2 -0
- data/vendor/wreq/src/client/layer/decoder.rs +71 -17
- data/vendor/wreq/src/client/layer/redirect/future.rs +49 -63
- data/vendor/wreq/src/client/layer/redirect/policy.rs +2 -26
- data/vendor/wreq/src/client/layer/redirect.rs +48 -60
- data/vendor/wreq/src/client/layer/retry.rs +12 -15
- data/vendor/wreq/src/client/layer/timeout/body.rs +27 -21
- data/vendor/wreq/src/client/layer/timeout/future.rs +33 -58
- data/vendor/wreq/src/client/layer/timeout.rs +8 -14
- data/vendor/wreq/src/client/request.rs +4 -0
- data/vendor/wreq/src/client.rs +53 -31
- data/vendor/wreq/src/conn/connector.rs +99 -129
- data/vendor/wreq/src/conn/http.rs +25 -18
- data/vendor/wreq/src/conn/net/tcp.rs +601 -107
- data/vendor/wreq/src/conn/proxy/socks.rs +6 -6
- data/vendor/wreq/src/conn/timeout.rs +166 -0
- data/vendor/wreq/src/conn.rs +5 -4
- data/vendor/wreq/src/cookie/jar.rs +1225 -0
- data/vendor/wreq/src/cookie/store.rs +321 -0
- data/vendor/wreq/src/cookie.rs +108 -612
- data/vendor/wreq/src/dns/resolve.rs +8 -2
- data/vendor/wreq/src/dns.rs +4 -4
- data/vendor/wreq/src/error.rs +53 -20
- data/vendor/wreq/src/lib.rs +1 -0
- data/vendor/wreq/src/proxy/matcher.rs +26 -12
- data/vendor/wreq/src/proxy/win.rs +39 -9
- data/vendor/wreq/src/redirect.rs +515 -100
- data/vendor/wreq/src/tls/conn.rs +3 -11
- data/vendor/wreq/src/tls/session.rs +7 -8
- data/vendor/wreq/src/tls/trust/store.rs +4 -4
- data/vendor/wreq/src/util.rs +23 -0
- data/vendor/wreq/tests/badssl.rs +72 -7
- data/vendor/wreq/tests/brotli.rs +1 -1
- data/vendor/wreq/tests/client.rs +24 -0
- data/vendor/wreq/tests/connector_layers.rs +8 -4
- data/vendor/wreq/tests/cookie.rs +59 -0
- data/vendor/wreq/tests/deflate.rs +1 -1
- data/vendor/wreq/tests/gzip.rs +53 -1
- data/vendor/wreq/tests/layers.rs +8 -4
- data/vendor/wreq/tests/redirect.rs +180 -97
- data/vendor/wreq/tests/timeouts.rs +47 -12
- data/vendor/wreq/tests/zstd.rs +1 -1
- metadata +8 -2
|
@@ -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
|
|
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
|
|
26
|
-
|
|
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(
|
|
32
|
+
Some(Body::default())
|
|
35
33
|
}
|
|
36
34
|
BodyRepr::None => None,
|
|
37
35
|
}
|
|
38
36
|
}
|
|
39
37
|
|
|
40
|
-
fn try_clone_from
|
|
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(
|
|
49
|
-
} else if let Some(cloned) =
|
|
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
|
|
59
|
-
pub struct FollowRedirectLayer
|
|
60
|
-
policy:
|
|
53
|
+
#[derive(Clone)]
|
|
54
|
+
pub struct FollowRedirectLayer {
|
|
55
|
+
policy: FollowRedirectPolicy,
|
|
61
56
|
}
|
|
62
57
|
|
|
63
|
-
impl
|
|
64
|
-
/// Create a new [`FollowRedirectLayer`] with the given redirection
|
|
58
|
+
impl FollowRedirectLayer {
|
|
59
|
+
/// Create a new [`FollowRedirectLayer`] with the given redirection policy.
|
|
65
60
|
#[inline(always)]
|
|
66
|
-
pub fn with_policy(policy:
|
|
61
|
+
pub(crate) fn with_policy(policy: FollowRedirectPolicy) -> Self {
|
|
67
62
|
FollowRedirectLayer { policy }
|
|
68
63
|
}
|
|
69
64
|
}
|
|
70
65
|
|
|
71
|
-
impl<S
|
|
66
|
+
impl<S> Layer<S> for FollowRedirectLayer
|
|
72
67
|
where
|
|
73
68
|
S: Clone,
|
|
74
|
-
P: Clone,
|
|
75
69
|
{
|
|
76
|
-
type Service = FollowRedirect<S
|
|
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
|
|
86
|
-
pub struct FollowRedirect<S
|
|
79
|
+
#[derive(Clone)]
|
|
80
|
+
pub struct FollowRedirect<S> {
|
|
87
81
|
inner: S,
|
|
88
|
-
policy:
|
|
82
|
+
policy: FollowRedirectPolicy,
|
|
89
83
|
}
|
|
90
84
|
|
|
91
|
-
impl<S
|
|
92
|
-
|
|
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
|
-
|
|
88
|
+
fn with_policy(inner: S, policy: FollowRedirectPolicy) -> Self {
|
|
98
89
|
FollowRedirect { inner, policy }
|
|
99
90
|
}
|
|
100
91
|
}
|
|
101
92
|
|
|
102
|
-
impl<
|
|
93
|
+
impl<ResBody, S> Service<Request<Body>> for FollowRedirect<S>
|
|
103
94
|
where
|
|
104
|
-
S: Service<Request<
|
|
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
|
|
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<
|
|
119
|
-
|
|
120
|
-
|
|
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
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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
|
|
@@ -57,33 +57,33 @@ pin_project! {
|
|
|
57
57
|
/// The timeout resets after every successful read. If a single read
|
|
58
58
|
/// takes longer than the specified duration, an error is returned.
|
|
59
59
|
pub struct ReadTimeoutBody<B> {
|
|
60
|
-
timeout: Duration,
|
|
61
|
-
#[pin]
|
|
62
|
-
sleep: Option<Pin<Box<dyn Sleep>>>,
|
|
63
60
|
#[pin]
|
|
64
61
|
body: B,
|
|
62
|
+
#[pin]
|
|
63
|
+
sleep: Option<Pin<Box<dyn Sleep>>>,
|
|
64
|
+
timeout: Duration,
|
|
65
65
|
timer: Timer,
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
// ===== impl TimeoutBody =====
|
|
70
|
+
|
|
70
71
|
impl<B> TimeoutBody<B> {
|
|
71
|
-
///
|
|
72
|
+
/// Wraps a body with the active total timeout and an optional read timeout.
|
|
72
73
|
pub fn new(
|
|
74
|
+
body: B,
|
|
73
75
|
timer: Timer,
|
|
74
|
-
deadline: Option<Duration>,
|
|
75
76
|
read_timeout: Option<Duration>,
|
|
76
|
-
|
|
77
|
+
total_timeout: Option<Pin<Box<dyn Sleep>>>,
|
|
77
78
|
) -> Self {
|
|
78
|
-
|
|
79
|
-
match (deadline, read_timeout) {
|
|
79
|
+
match (total_timeout, read_timeout) {
|
|
80
80
|
(Some(total_timeout), Some(read_timeout)) => TimeoutBody::CombinedTimeout {
|
|
81
81
|
body: TotalTimeoutBody {
|
|
82
82
|
timeout: total_timeout,
|
|
83
83
|
body: ReadTimeoutBody {
|
|
84
|
-
timeout: read_timeout,
|
|
85
|
-
sleep: None,
|
|
86
84
|
body,
|
|
85
|
+
sleep: None,
|
|
86
|
+
timeout: read_timeout,
|
|
87
87
|
timer,
|
|
88
88
|
},
|
|
89
89
|
},
|
|
@@ -160,7 +160,8 @@ where
|
|
|
160
160
|
)
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
//
|
|
163
|
+
// ===== impl TotalTimeoutBody =====
|
|
164
|
+
|
|
164
165
|
impl<B> Body for TotalTimeoutBody<B>
|
|
165
166
|
where
|
|
166
167
|
B: Body,
|
|
@@ -191,7 +192,8 @@ where
|
|
|
191
192
|
}
|
|
192
193
|
}
|
|
193
194
|
|
|
194
|
-
|
|
195
|
+
// ===== impl ReadTimeoutBody =====
|
|
196
|
+
|
|
195
197
|
impl<B> Body for ReadTimeoutBody<B>
|
|
196
198
|
where
|
|
197
199
|
B: Body,
|
|
@@ -206,23 +208,27 @@ where
|
|
|
206
208
|
) -> Poll<Option<Result<http_body::Frame<Self::Data>, Self::Error>>> {
|
|
207
209
|
let mut this = self.project();
|
|
208
210
|
|
|
209
|
-
//
|
|
211
|
+
// Start the timeout on the first poll.
|
|
210
212
|
if this.sleep.is_none() {
|
|
211
|
-
this.
|
|
213
|
+
let deadline = this.timer.now() + *this.timeout;
|
|
214
|
+
this.sleep.set(Some(this.timer.sleep_until(deadline)));
|
|
212
215
|
}
|
|
213
216
|
|
|
214
217
|
// Error if the timeout has expired.
|
|
215
|
-
if let Some(sleep) = this.sleep.as_mut().as_pin_mut()
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
218
|
+
if let Some(sleep) = this.sleep.as_mut().as_pin_mut()
|
|
219
|
+
&& sleep.poll(cx).is_ready()
|
|
220
|
+
{
|
|
221
|
+
return Poll::Ready(Some(Err(Error::body(TimedOut).into())));
|
|
219
222
|
}
|
|
220
223
|
|
|
221
224
|
// Poll the actual body
|
|
222
225
|
match ready!(this.body.poll_frame(cx)) {
|
|
223
226
|
Some(Ok(frame)) => {
|
|
224
|
-
//
|
|
225
|
-
this.sleep.
|
|
227
|
+
// Reuse the sleep to avoid allocating and registering a new timer for every frame.
|
|
228
|
+
if let Some(sleep) = this.sleep.as_mut().as_pin_mut() {
|
|
229
|
+
let deadline = this.timer.now() + *this.timeout;
|
|
230
|
+
this.timer.reset(sleep.get_mut(), deadline);
|
|
231
|
+
}
|
|
226
232
|
Poll::Ready(Some(Ok(frame)))
|
|
227
233
|
}
|
|
228
234
|
Some(Err(err)) => Poll::Ready(Some(Err(err.into()))),
|
|
@@ -16,80 +16,55 @@ use crate::{
|
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
pin_project! {
|
|
19
|
-
///
|
|
19
|
+
/// Waits for response headers, then moves the total timeout into the response body.
|
|
20
20
|
pub struct ResponseFuture<Fut> {
|
|
21
21
|
#[pin]
|
|
22
|
-
pub(
|
|
23
|
-
pub(
|
|
24
|
-
pub(
|
|
22
|
+
pub(super) fut: Fut,
|
|
23
|
+
pub(super) timer: Timer,
|
|
24
|
+
pub(super) read_timeout: Option<Duration>,
|
|
25
|
+
pub(super) read_timeout_fut: Option<Pin<Box<dyn Sleep>>>,
|
|
26
|
+
pub(super) total_timeout_fut: Option<Pin<Box<dyn Sleep>>>,
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
29
|
|
|
28
|
-
impl<
|
|
30
|
+
impl<Fut, ResBody, E> Future for ResponseFuture<Fut>
|
|
29
31
|
where
|
|
30
|
-
|
|
32
|
+
Fut: Future<Output = Result<Response<ResBody>, E>>,
|
|
31
33
|
E: Into<BoxError>,
|
|
32
34
|
{
|
|
33
|
-
type Output = Result<
|
|
35
|
+
type Output = Result<Response<TimeoutBody<ResBody>>, BoxError>;
|
|
34
36
|
|
|
35
37
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
36
38
|
let this = self.project();
|
|
37
39
|
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
// Helper closure for polling a timeout and returning a TimedOut error
|
|
45
|
-
let mut check_timeout = |sleep: Option<&mut Pin<Box<dyn Sleep>>>| {
|
|
46
|
-
if let Some(sleep) = sleep {
|
|
47
|
-
if sleep.as_mut().poll(cx).is_ready() {
|
|
48
|
-
return Some(Poll::Ready(Err(Error::request(TimedOut).into())));
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
None
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
// Check total timeout first
|
|
55
|
-
if let Some(poll) = check_timeout(this.total_timeout.as_mut()) {
|
|
56
|
-
return poll;
|
|
40
|
+
// The total timer covers response headers and body. Poll it first so an
|
|
41
|
+
// expired timeout wins, then move it into `TimeoutBody` below.
|
|
42
|
+
if let Some(timeout) = this.total_timeout_fut.as_mut()
|
|
43
|
+
&& timeout.as_mut().poll(cx).is_ready()
|
|
44
|
+
{
|
|
45
|
+
return Poll::Ready(Err(Error::request(TimedOut).into()));
|
|
57
46
|
}
|
|
58
47
|
|
|
59
|
-
//
|
|
60
|
-
|
|
61
|
-
|
|
48
|
+
// Before headers arrive, the read timer limits that wait. The body starts
|
|
49
|
+
// and resets its own read timer after each successful frame.
|
|
50
|
+
if let Some(timeout) = this.read_timeout_fut.as_mut()
|
|
51
|
+
&& timeout.as_mut().poll(cx).is_ready()
|
|
52
|
+
{
|
|
53
|
+
return Poll::Ready(Err(Error::request(TimedOut).into()));
|
|
62
54
|
}
|
|
63
55
|
|
|
64
|
-
Poll
|
|
65
|
-
|
|
66
|
-
|
|
56
|
+
// Poll the request after both timers so every pending future registers the
|
|
57
|
+
// current waker before `ready!` returns.
|
|
58
|
+
let response = ready!(this.fut.poll(cx)).map_err(Into::into)?;
|
|
67
59
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
impl<Fut, ResBody, E> Future for ResponseBodyTimeoutFuture<Fut>
|
|
81
|
-
where
|
|
82
|
-
Fut: Future<Output = Result<Response<ResBody>, E>>,
|
|
83
|
-
{
|
|
84
|
-
type Output = Result<Response<TimeoutBody<ResBody>>, E>;
|
|
85
|
-
|
|
86
|
-
#[inline(always)]
|
|
87
|
-
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
88
|
-
let timer = self.timer.clone();
|
|
89
|
-
let total_timeout = self.total_timeout;
|
|
90
|
-
let read_timeout = self.read_timeout;
|
|
91
|
-
let res = ready!(self.project().fut.poll(cx))?
|
|
92
|
-
.map(|body| TimeoutBody::new(timer, total_timeout, read_timeout, body));
|
|
93
|
-
Poll::Ready(Ok(res))
|
|
60
|
+
// Moving the running total timer preserves the original deadline.
|
|
61
|
+
Poll::Ready(Ok(response.map(|body| {
|
|
62
|
+
TimeoutBody::new(
|
|
63
|
+
body,
|
|
64
|
+
this.timer.clone(),
|
|
65
|
+
*this.read_timeout,
|
|
66
|
+
this.total_timeout_fut.take(),
|
|
67
|
+
)
|
|
68
|
+
})))
|
|
94
69
|
}
|
|
95
70
|
}
|
|
@@ -12,17 +12,14 @@ use http::{Request, Response};
|
|
|
12
12
|
use tower::{BoxError, Layer, Service};
|
|
13
13
|
use wreq_proto::rt::Timer as _;
|
|
14
14
|
|
|
15
|
-
use self::{
|
|
16
|
-
body::TimeoutBody,
|
|
17
|
-
future::{ResponseBodyTimeoutFuture, ResponseFuture},
|
|
18
|
-
};
|
|
15
|
+
use self::{body::TimeoutBody, future::ResponseFuture};
|
|
19
16
|
use crate::{config::RequestConfig, rt::Timer};
|
|
20
17
|
|
|
21
18
|
/// Options for configuring timeouts.
|
|
22
19
|
#[derive(Clone, Copy, Default)]
|
|
23
20
|
pub struct TimeoutOptions {
|
|
24
|
-
total_timeout: Option<Duration>,
|
|
25
21
|
read_timeout: Option<Duration>,
|
|
22
|
+
total_timeout: Option<Duration>,
|
|
26
23
|
}
|
|
27
24
|
|
|
28
25
|
impl TimeoutOptions {
|
|
@@ -88,7 +85,7 @@ where
|
|
|
88
85
|
{
|
|
89
86
|
type Response = Response<TimeoutBody<ResBody>>;
|
|
90
87
|
type Error = BoxError;
|
|
91
|
-
type Future = ResponseFuture<
|
|
88
|
+
type Future = ResponseFuture<S::Future>;
|
|
92
89
|
|
|
93
90
|
#[inline(always)]
|
|
94
91
|
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
@@ -99,14 +96,11 @@ where
|
|
|
99
96
|
fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
|
|
100
97
|
let (total_timeout, read_timeout) = fetch_timeout_options(&self.timeout, req.extensions());
|
|
101
98
|
ResponseFuture {
|
|
102
|
-
fut:
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
},
|
|
108
|
-
total_timeout: total_timeout.map(|timeout| self.timer.sleep(timeout)),
|
|
109
|
-
read_timeout: read_timeout.map(|timeout| self.timer.sleep(timeout)),
|
|
99
|
+
fut: self.inner.call(req),
|
|
100
|
+
timer: self.timer.clone(),
|
|
101
|
+
read_timeout,
|
|
102
|
+
read_timeout_fut: read_timeout.map(|timeout| self.timer.sleep(timeout)),
|
|
103
|
+
total_timeout_fut: total_timeout.map(|timeout| self.timer.sleep(timeout)),
|
|
110
104
|
}
|
|
111
105
|
}
|
|
112
106
|
}
|
|
@@ -473,6 +473,10 @@ impl RequestBuilder {
|
|
|
473
473
|
|
|
474
474
|
/// Send a JSON body.
|
|
475
475
|
///
|
|
476
|
+
/// Serializes the value as JSON and sets the resulting bytes as the request body.
|
|
477
|
+
///
|
|
478
|
+
/// Sets `Content-Type` to `application/json` unless it is already set.
|
|
479
|
+
///
|
|
476
480
|
/// # Optional
|
|
477
481
|
///
|
|
478
482
|
/// This requires the optional `json` feature enabled.
|