1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
//! Carrying the request body upstream while the answer is already on its
//! way back.
//!
//! Split from [`crate::exchange`] because it answers a different question.
//! That module decides what a request *means* — how it is framed, whether
//! the credential admits it, whether the backend is contacted at all. This
//! one decides nothing: it moves a body one way, watches for a head coming
//! the other, and reports which of the two halves gave out first. They have
//! to overlap, and the reason is not throughput — a backend may answer
//! before it has finished reading, and an edge still inside `write_all` at
//! that moment loses the answer it already had.
//!
//! The two failures kept apart here are the whole of it. A body that stops
//! short is the *client's*: the head is already upstream, so the backend is
//! blocked reading against a length that will never arrive, and nothing but
//! a half-close will move it. A write that fails is the *backend's*: it has
//! stopped taking bytes, usually because it has already answered, and that
//! answer is still the thing worth having. Told apart they are a 400 and a
//! 502. Confused, the first of them is not a wrong status but a hang — the
//! edge waits for a response that cannot exist, on a stream no timeout
//! covers, holding the in-flight guard `ServeHandle::shutdown` drains
//! against.
//!
//! Measured, before the halves were told apart: a client that declared
//! `Content-Length: 1000`, sent ten bytes and hung up got nothing back,
//! ever, and the first Ctrl-C on `modelpipe serve` never returned. With
//! only ordinary traffic in flight the same shutdown took a second.
//!
//! The half-close is most of the answer but not all of it, because it
//! depends on the backend doing something with what it is told. One that
//! holds its socket open after the end of the stream — measured, against a
//! server blocked in `read` that neither answers nor closes — put the
//! exchange straight back where it was. [`ANSWER_GRACE`] is the floor under
//! that, and it is armed only by a pump that has already failed, which is
//! what keeps it from ever becoming the request timeout this crate is right
//! not to have.
//!
//! Generic over its streams like everything above the transport, so the
//! half-close is a FIN on a socket and `tokio::io::duplex()`'s peer seeing
//! `Ok(0)` in the tests — which is why every case below is exercised
//! without one.
use Duration;
use ;
use crate;
use crate;
use crate;
use cratehead_read;
use cratehttp_head;
/// How long the backend has to answer a request whose body never arrived.
///
/// **Not a request timeout, and it cannot become one.** It is armed only
/// once the pump has *failed*, which means the backend never received the
/// whole request — so no inference is running, and nobody is waiting on a
/// result. A legitimate call that takes forty minutes has a pump that
/// succeeded, leaves this disarmed, and is never cut by it. That
/// distinction is the whole reason the bound can exist here at all when
/// `exchange`'s own docs rightly refuse to put one on an admitted request.
///
/// The half-close tells a blocked backend the body stopped; this covers the
/// backend that is told and still says nothing. Measured against one that
/// holds its socket open after the end of the stream: without this the
/// exchange never returned, so it never released its in-flight guard, and
/// `ServeHandle::shutdown` — documented as draining rather than cutting —
/// waited on it forever. One misbehaving backend could hold a teardown
/// open indefinitely.
///
/// Generous, because the client may still be there: an unreadable chunk
/// size leaves the socket open and the client waiting, and a backend that
/// is going to answer the end of a body answers it promptly.
pub const ANSWER_GRACE: Duration = from_secs;
/// What came back, once the request body had been carried as far as it
/// could go.
pub
/// Forward the body, and half-close upstream if it could not be finished.
///
/// The half-close is the liveness fix and it is why this is one function
/// rather than two: [`carry`]'s pinned future holds the write half for its
/// whole scope, so nothing outside can touch it once the pump is running.
/// Folding the forward and the shutdown together is what hands the borrow
/// back.
///
/// A body that arrives whole leaves the write open. That is not symmetry
/// for its own sake: the backend then has exactly the bytes the head
/// declared and knows where the message ends, and a half-close there reads
/// to some servers as an abort of a request that was fine. It is also what
/// makes "could this truncate a slow upload?" answerable — slowness is
/// `Poll::Pending`, never `Err`, so the shutdown below is unreachable for
/// it.
async
/// Carry the request body to the backend while watching for its answer.
///
/// The pump is polled first, so a backend that answers only after reading —
/// every well-behaved one — sees the whole body and the response is read
/// afterwards. When a head arrives first the pump is abandoned, which is
/// correct: the backend has committed to an answer and the rest of the body
/// cannot change it.
///
/// **The backend's answer always wins, even over a failed pump.** That is
/// the case the discarded-error version of this function was written for,
/// and it is a real one rather than a hypothetical: a backend may answer
/// `413` on an oversized payload, `400` on bad JSON or `429`, and then stop
/// draining. Its close arrives as an RST because the receive queue is not
/// empty, the RST makes the kernel discard what it had already delivered,
/// and an edge still inside `write_all` at that moment loses a response it
/// had already been sent. The client got a cleanly closed stream with zero
/// bytes in it — no status, no 502 — for every request whose body outran
/// the backend's socket buffer, which presented as a size-dependent
/// phantom. Charging a pump failure to the client *before* reading is how
/// that bug comes back, so the fault only decides what happens when
/// nothing readable came back at all.
pub async
/// The backend's *final* response head, with any interim ones skipped.
///
/// A `1xx` is a complete head that is not a response: the client asked for
/// it (`Expect: 100-continue`) or the backend volunteered it, and the real
/// answer is the next head on the stream. Returning the first head made the
/// interim one the final one — and since a `1xx` carries neither
/// `Content-Length` nor `Transfer-Encoding`, the framing that followed was
/// `UntilClose`, so the client waited on a close a keep-alive backend never
/// sends. An interim head arrived as a hang, not as a wrong status.
///
/// The bytes that came in with the interim head are the start of the head
/// after it, which is why the reader takes a prefix.
async