wreq-rb 0.3.0

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 (167) hide show
  1. checksums.yaml +7 -0
  2. data/Cargo.lock +2688 -0
  3. data/Cargo.toml +6 -0
  4. data/README.md +179 -0
  5. data/ext/wreq_rb/Cargo.toml +39 -0
  6. data/ext/wreq_rb/extconf.rb +22 -0
  7. data/ext/wreq_rb/src/client.rs +565 -0
  8. data/ext/wreq_rb/src/error.rs +25 -0
  9. data/ext/wreq_rb/src/lib.rs +20 -0
  10. data/ext/wreq_rb/src/response.rs +132 -0
  11. data/lib/wreq-rb/version.rb +5 -0
  12. data/lib/wreq-rb.rb +17 -0
  13. data/patches/0001-add-transfer-size-tracking.patch +292 -0
  14. data/vendor/wreq/Cargo.toml +306 -0
  15. data/vendor/wreq/LICENSE +202 -0
  16. data/vendor/wreq/README.md +122 -0
  17. data/vendor/wreq/examples/cert_store.rs +77 -0
  18. data/vendor/wreq/examples/connect_via_lower_priority_tokio_runtime.rs +258 -0
  19. data/vendor/wreq/examples/emulation.rs +118 -0
  20. data/vendor/wreq/examples/form.rs +14 -0
  21. data/vendor/wreq/examples/http1_websocket.rs +37 -0
  22. data/vendor/wreq/examples/http2_websocket.rs +45 -0
  23. data/vendor/wreq/examples/json_dynamic.rs +41 -0
  24. data/vendor/wreq/examples/json_typed.rs +47 -0
  25. data/vendor/wreq/examples/keylog.rs +16 -0
  26. data/vendor/wreq/examples/request_with_emulation.rs +115 -0
  27. data/vendor/wreq/examples/request_with_interface.rs +37 -0
  28. data/vendor/wreq/examples/request_with_local_address.rs +16 -0
  29. data/vendor/wreq/examples/request_with_proxy.rs +13 -0
  30. data/vendor/wreq/examples/request_with_redirect.rs +22 -0
  31. data/vendor/wreq/examples/request_with_version.rs +15 -0
  32. data/vendor/wreq/examples/tor_socks.rs +24 -0
  33. data/vendor/wreq/examples/unix_socket.rs +33 -0
  34. data/vendor/wreq/src/client/body.rs +304 -0
  35. data/vendor/wreq/src/client/conn/conn.rs +231 -0
  36. data/vendor/wreq/src/client/conn/connector.rs +549 -0
  37. data/vendor/wreq/src/client/conn/http.rs +1023 -0
  38. data/vendor/wreq/src/client/conn/proxy/socks.rs +233 -0
  39. data/vendor/wreq/src/client/conn/proxy/tunnel.rs +260 -0
  40. data/vendor/wreq/src/client/conn/proxy.rs +39 -0
  41. data/vendor/wreq/src/client/conn/tls_info.rs +98 -0
  42. data/vendor/wreq/src/client/conn/uds.rs +44 -0
  43. data/vendor/wreq/src/client/conn/verbose.rs +149 -0
  44. data/vendor/wreq/src/client/conn.rs +323 -0
  45. data/vendor/wreq/src/client/core/body/incoming.rs +485 -0
  46. data/vendor/wreq/src/client/core/body/length.rs +118 -0
  47. data/vendor/wreq/src/client/core/body.rs +34 -0
  48. data/vendor/wreq/src/client/core/common/buf.rs +149 -0
  49. data/vendor/wreq/src/client/core/common/rewind.rs +141 -0
  50. data/vendor/wreq/src/client/core/common/watch.rs +76 -0
  51. data/vendor/wreq/src/client/core/common.rs +3 -0
  52. data/vendor/wreq/src/client/core/conn/http1.rs +342 -0
  53. data/vendor/wreq/src/client/core/conn/http2.rs +307 -0
  54. data/vendor/wreq/src/client/core/conn.rs +11 -0
  55. data/vendor/wreq/src/client/core/dispatch.rs +299 -0
  56. data/vendor/wreq/src/client/core/error.rs +435 -0
  57. data/vendor/wreq/src/client/core/ext.rs +201 -0
  58. data/vendor/wreq/src/client/core/http1.rs +178 -0
  59. data/vendor/wreq/src/client/core/http2.rs +483 -0
  60. data/vendor/wreq/src/client/core/proto/h1/conn.rs +988 -0
  61. data/vendor/wreq/src/client/core/proto/h1/decode.rs +1170 -0
  62. data/vendor/wreq/src/client/core/proto/h1/dispatch.rs +684 -0
  63. data/vendor/wreq/src/client/core/proto/h1/encode.rs +580 -0
  64. data/vendor/wreq/src/client/core/proto/h1/io.rs +879 -0
  65. data/vendor/wreq/src/client/core/proto/h1/role.rs +694 -0
  66. data/vendor/wreq/src/client/core/proto/h1.rs +104 -0
  67. data/vendor/wreq/src/client/core/proto/h2/client.rs +650 -0
  68. data/vendor/wreq/src/client/core/proto/h2/ping.rs +539 -0
  69. data/vendor/wreq/src/client/core/proto/h2.rs +379 -0
  70. data/vendor/wreq/src/client/core/proto/headers.rs +138 -0
  71. data/vendor/wreq/src/client/core/proto.rs +58 -0
  72. data/vendor/wreq/src/client/core/rt/bounds.rs +57 -0
  73. data/vendor/wreq/src/client/core/rt/timer.rs +150 -0
  74. data/vendor/wreq/src/client/core/rt/tokio.rs +99 -0
  75. data/vendor/wreq/src/client/core/rt.rs +25 -0
  76. data/vendor/wreq/src/client/core/upgrade.rs +267 -0
  77. data/vendor/wreq/src/client/core.rs +16 -0
  78. data/vendor/wreq/src/client/emulation.rs +161 -0
  79. data/vendor/wreq/src/client/http/client/error.rs +142 -0
  80. data/vendor/wreq/src/client/http/client/exec.rs +29 -0
  81. data/vendor/wreq/src/client/http/client/extra.rs +77 -0
  82. data/vendor/wreq/src/client/http/client/lazy.rs +79 -0
  83. data/vendor/wreq/src/client/http/client/pool.rs +1105 -0
  84. data/vendor/wreq/src/client/http/client/util.rs +104 -0
  85. data/vendor/wreq/src/client/http/client.rs +1003 -0
  86. data/vendor/wreq/src/client/http/future.rs +99 -0
  87. data/vendor/wreq/src/client/http.rs +1629 -0
  88. data/vendor/wreq/src/client/layer/config/options.rs +156 -0
  89. data/vendor/wreq/src/client/layer/config.rs +116 -0
  90. data/vendor/wreq/src/client/layer/cookie.rs +161 -0
  91. data/vendor/wreq/src/client/layer/decoder.rs +139 -0
  92. data/vendor/wreq/src/client/layer/redirect/future.rs +270 -0
  93. data/vendor/wreq/src/client/layer/redirect/policy.rs +63 -0
  94. data/vendor/wreq/src/client/layer/redirect.rs +145 -0
  95. data/vendor/wreq/src/client/layer/retry/classify.rs +105 -0
  96. data/vendor/wreq/src/client/layer/retry/scope.rs +51 -0
  97. data/vendor/wreq/src/client/layer/retry.rs +151 -0
  98. data/vendor/wreq/src/client/layer/timeout/body.rs +233 -0
  99. data/vendor/wreq/src/client/layer/timeout/future.rs +90 -0
  100. data/vendor/wreq/src/client/layer/timeout.rs +177 -0
  101. data/vendor/wreq/src/client/layer.rs +15 -0
  102. data/vendor/wreq/src/client/multipart.rs +717 -0
  103. data/vendor/wreq/src/client/request.rs +818 -0
  104. data/vendor/wreq/src/client/response.rs +534 -0
  105. data/vendor/wreq/src/client/ws/json.rs +99 -0
  106. data/vendor/wreq/src/client/ws/message.rs +453 -0
  107. data/vendor/wreq/src/client/ws.rs +714 -0
  108. data/vendor/wreq/src/client.rs +27 -0
  109. data/vendor/wreq/src/config.rs +140 -0
  110. data/vendor/wreq/src/cookie.rs +579 -0
  111. data/vendor/wreq/src/dns/gai.rs +249 -0
  112. data/vendor/wreq/src/dns/hickory.rs +78 -0
  113. data/vendor/wreq/src/dns/resolve.rs +180 -0
  114. data/vendor/wreq/src/dns.rs +69 -0
  115. data/vendor/wreq/src/error.rs +502 -0
  116. data/vendor/wreq/src/ext.rs +398 -0
  117. data/vendor/wreq/src/hash.rs +143 -0
  118. data/vendor/wreq/src/header.rs +506 -0
  119. data/vendor/wreq/src/into_uri.rs +187 -0
  120. data/vendor/wreq/src/lib.rs +586 -0
  121. data/vendor/wreq/src/proxy/mac.rs +82 -0
  122. data/vendor/wreq/src/proxy/matcher.rs +806 -0
  123. data/vendor/wreq/src/proxy/uds.rs +66 -0
  124. data/vendor/wreq/src/proxy/win.rs +31 -0
  125. data/vendor/wreq/src/proxy.rs +569 -0
  126. data/vendor/wreq/src/redirect.rs +575 -0
  127. data/vendor/wreq/src/retry.rs +198 -0
  128. data/vendor/wreq/src/sync.rs +129 -0
  129. data/vendor/wreq/src/tls/conn/cache.rs +123 -0
  130. data/vendor/wreq/src/tls/conn/cert_compression.rs +125 -0
  131. data/vendor/wreq/src/tls/conn/ext.rs +82 -0
  132. data/vendor/wreq/src/tls/conn/macros.rs +34 -0
  133. data/vendor/wreq/src/tls/conn/service.rs +138 -0
  134. data/vendor/wreq/src/tls/conn.rs +681 -0
  135. data/vendor/wreq/src/tls/keylog/handle.rs +64 -0
  136. data/vendor/wreq/src/tls/keylog.rs +99 -0
  137. data/vendor/wreq/src/tls/options.rs +464 -0
  138. data/vendor/wreq/src/tls/x509/identity.rs +122 -0
  139. data/vendor/wreq/src/tls/x509/parser.rs +71 -0
  140. data/vendor/wreq/src/tls/x509/store.rs +228 -0
  141. data/vendor/wreq/src/tls/x509.rs +68 -0
  142. data/vendor/wreq/src/tls.rs +154 -0
  143. data/vendor/wreq/src/trace.rs +55 -0
  144. data/vendor/wreq/src/util.rs +122 -0
  145. data/vendor/wreq/tests/badssl.rs +228 -0
  146. data/vendor/wreq/tests/brotli.rs +350 -0
  147. data/vendor/wreq/tests/client.rs +1098 -0
  148. data/vendor/wreq/tests/connector_layers.rs +227 -0
  149. data/vendor/wreq/tests/cookie.rs +306 -0
  150. data/vendor/wreq/tests/deflate.rs +347 -0
  151. data/vendor/wreq/tests/emulation.rs +260 -0
  152. data/vendor/wreq/tests/gzip.rs +347 -0
  153. data/vendor/wreq/tests/layers.rs +261 -0
  154. data/vendor/wreq/tests/multipart.rs +165 -0
  155. data/vendor/wreq/tests/proxy.rs +438 -0
  156. data/vendor/wreq/tests/redirect.rs +629 -0
  157. data/vendor/wreq/tests/retry.rs +135 -0
  158. data/vendor/wreq/tests/support/delay_server.rs +117 -0
  159. data/vendor/wreq/tests/support/error.rs +16 -0
  160. data/vendor/wreq/tests/support/layer.rs +183 -0
  161. data/vendor/wreq/tests/support/mod.rs +9 -0
  162. data/vendor/wreq/tests/support/server.rs +232 -0
  163. data/vendor/wreq/tests/timeouts.rs +281 -0
  164. data/vendor/wreq/tests/unix_socket.rs +135 -0
  165. data/vendor/wreq/tests/upgrade.rs +98 -0
  166. data/vendor/wreq/tests/zstd.rs +559 -0
  167. metadata +225 -0
@@ -0,0 +1,485 @@
1
+ use std::{
2
+ fmt,
3
+ future::Future,
4
+ pin::Pin,
5
+ task::{Context, Poll, ready},
6
+ };
7
+
8
+ use bytes::Bytes;
9
+ use futures_channel::{mpsc, oneshot};
10
+ use futures_util::{Stream, stream::FusedStream};
11
+ use http::HeaderMap;
12
+ use http_body::{Body, Frame, SizeHint};
13
+
14
+ use super::DecodedLength;
15
+ use crate::client::core::{self, Error, common::watch, proto::h2::ping};
16
+
17
+ type BodySender = mpsc::Sender<Result<Bytes, Error>>;
18
+ type TrailersSender = oneshot::Sender<HeaderMap>;
19
+
20
+ /// A stream of `Bytes`, used when receiving bodies from the network.
21
+ ///
22
+ /// Note that Users should not instantiate this struct directly. When working with the crate::core:
23
+ /// client, `Incoming` is returned to you in responses.
24
+ #[must_use = "streams do nothing unless polled"]
25
+ pub struct Incoming {
26
+ kind: Kind,
27
+ }
28
+
29
+ enum Kind {
30
+ Empty,
31
+ Chan {
32
+ content_length: DecodedLength,
33
+ want_tx: watch::Sender,
34
+ data_rx: mpsc::Receiver<Result<Bytes, Error>>,
35
+ trailers_rx: oneshot::Receiver<HeaderMap>,
36
+ },
37
+ H2 {
38
+ content_length: DecodedLength,
39
+ data_done: bool,
40
+ ping: ping::Recorder,
41
+ recv: http2::RecvStream,
42
+ },
43
+ }
44
+
45
+ /// A sender half created through [`Body::channel()`].
46
+ ///
47
+ /// Useful when wanting to stream chunks from another thread.
48
+ ///
49
+ /// ## Body Closing
50
+ ///
51
+ /// Note that the request body will always be closed normally when the sender is dropped (meaning
52
+ /// that the empty terminating chunk will be sent to the remote). If you desire to close the
53
+ /// connection with an incomplete response (e.g. in the case of an error during asynchronous
54
+ /// processing), call the [`Sender::abort()`] method to abort the body in an abnormal fashion.
55
+ ///
56
+ /// [`Body::channel()`]: struct.Body.html#method.channel
57
+ /// [`Sender::abort()`]: struct.Sender.html#method.abort
58
+ #[must_use = "Sender does nothing unless sent on"]
59
+ pub(crate) struct Sender {
60
+ want_rx: watch::Receiver,
61
+ data_tx: BodySender,
62
+ trailers_tx: Option<TrailersSender>,
63
+ }
64
+
65
+ const WANT_PENDING: usize = 1;
66
+ const WANT_READY: usize = 2;
67
+
68
+ impl Incoming {
69
+ /// Create a `Body` stream with an associated sender half.
70
+ ///
71
+ /// Useful when wanting to stream chunks from another thread.
72
+ #[inline]
73
+ #[cfg(test)]
74
+ pub(crate) fn channel() -> (Sender, Incoming) {
75
+ Self::new_channel(DecodedLength::CHUNKED, /* wanter = */ false)
76
+ }
77
+
78
+ pub(crate) fn new_channel(content_length: DecodedLength, wanter: bool) -> (Sender, Incoming) {
79
+ let (data_tx, data_rx) = mpsc::channel(0);
80
+ let (trailers_tx, trailers_rx) = oneshot::channel();
81
+
82
+ // If wanter is true, `Sender::poll_ready()` won't becoming ready
83
+ // until the `Body` has been polled for data once.
84
+ let want = if wanter { WANT_PENDING } else { WANT_READY };
85
+
86
+ let (want_tx, want_rx) = watch::channel(want);
87
+
88
+ let tx = Sender {
89
+ want_rx,
90
+ data_tx,
91
+ trailers_tx: Some(trailers_tx),
92
+ };
93
+ let rx = Incoming::new(Kind::Chan {
94
+ content_length,
95
+ want_tx,
96
+ data_rx,
97
+ trailers_rx,
98
+ });
99
+
100
+ (tx, rx)
101
+ }
102
+
103
+ fn new(kind: Kind) -> Incoming {
104
+ Incoming { kind }
105
+ }
106
+
107
+ pub(crate) fn empty() -> Incoming {
108
+ Incoming::new(Kind::Empty)
109
+ }
110
+
111
+ pub(crate) fn h2(
112
+ recv: http2::RecvStream,
113
+ mut content_length: DecodedLength,
114
+ ping: ping::Recorder,
115
+ ) -> Self {
116
+ // If the stream is already EOS, then the "unknown length" is clearly
117
+ // actually ZERO.
118
+ if !content_length.is_exact() && recv.is_end_stream() {
119
+ content_length = DecodedLength::ZERO;
120
+ }
121
+
122
+ Incoming::new(Kind::H2 {
123
+ data_done: false,
124
+ ping,
125
+ content_length,
126
+ recv,
127
+ })
128
+ }
129
+ }
130
+
131
+ impl Body for Incoming {
132
+ type Data = Bytes;
133
+ type Error = Error;
134
+
135
+ fn poll_frame(
136
+ mut self: Pin<&mut Self>,
137
+ cx: &mut Context<'_>,
138
+ ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
139
+ match self.kind {
140
+ Kind::Empty => Poll::Ready(None),
141
+ Kind::Chan {
142
+ content_length: ref mut len,
143
+ ref mut data_rx,
144
+ ref mut want_tx,
145
+ ref mut trailers_rx,
146
+ } => {
147
+ want_tx.send(WANT_READY);
148
+
149
+ if !data_rx.is_terminated() {
150
+ if let Some(chunk) = ready!(Pin::new(data_rx).poll_next(cx)?) {
151
+ len.sub_if(chunk.len() as u64);
152
+ return Poll::Ready(Some(Ok(Frame::data(chunk))));
153
+ }
154
+ }
155
+
156
+ // check trailers after data is terminated
157
+ match ready!(Pin::new(trailers_rx).poll(cx)) {
158
+ Ok(t) => Poll::Ready(Some(Ok(Frame::trailers(t)))),
159
+ Err(_) => Poll::Ready(None),
160
+ }
161
+ }
162
+ Kind::H2 {
163
+ ref mut data_done,
164
+ ref ping,
165
+ recv: ref mut h2,
166
+ content_length: ref mut len,
167
+ } => {
168
+ if !*data_done {
169
+ match ready!(h2.poll_data(cx)) {
170
+ Some(Ok(bytes)) => {
171
+ let _ = h2.flow_control().release_capacity(bytes.len());
172
+ len.sub_if(bytes.len() as u64);
173
+ ping.record_data(bytes.len());
174
+ return Poll::Ready(Some(Ok(Frame::data(bytes))));
175
+ }
176
+ Some(Err(e)) => {
177
+ return match e.reason() {
178
+ // These reasons should cause the body reading to stop, but not fail
179
+ // it. The same logic as for `Read
180
+ // for H2Upgraded` is applied here.
181
+ Some(http2::Reason::NO_ERROR) | Some(http2::Reason::CANCEL) => {
182
+ Poll::Ready(None)
183
+ }
184
+ _ => Poll::Ready(Some(Err(Error::new_body(e)))),
185
+ };
186
+ }
187
+ None => {
188
+ *data_done = true;
189
+ // fall through to trailers
190
+ }
191
+ }
192
+ }
193
+
194
+ // after data, check trailers
195
+ match ready!(h2.poll_trailers(cx)) {
196
+ Ok(t) => {
197
+ ping.record_non_data();
198
+ Poll::Ready(Ok(t.map(Frame::trailers)).transpose())
199
+ }
200
+ Err(e) => Poll::Ready(Some(Err(Error::new_h2(e)))),
201
+ }
202
+ }
203
+ }
204
+ }
205
+
206
+ fn is_end_stream(&self) -> bool {
207
+ match self.kind {
208
+ Kind::Empty => true,
209
+ Kind::Chan { content_length, .. } => content_length == DecodedLength::ZERO,
210
+ Kind::H2 { recv: ref h2, .. } => h2.is_end_stream(),
211
+ }
212
+ }
213
+
214
+ fn size_hint(&self) -> SizeHint {
215
+ fn opt_len(decoded_length: DecodedLength) -> SizeHint {
216
+ if let Some(content_length) = decoded_length.into_opt() {
217
+ SizeHint::with_exact(content_length)
218
+ } else {
219
+ SizeHint::default()
220
+ }
221
+ }
222
+
223
+ match self.kind {
224
+ Kind::Empty => SizeHint::with_exact(0),
225
+ Kind::Chan { content_length, .. } => opt_len(content_length),
226
+ Kind::H2 { content_length, .. } => opt_len(content_length),
227
+ }
228
+ }
229
+ }
230
+
231
+ impl fmt::Debug for Incoming {
232
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233
+ #[derive(Debug)]
234
+ struct Streaming;
235
+ #[derive(Debug)]
236
+ struct Empty;
237
+
238
+ let mut builder = f.debug_tuple("Body");
239
+ match self.kind {
240
+ Kind::Empty => builder.field(&Empty),
241
+ _ => builder.field(&Streaming),
242
+ };
243
+
244
+ builder.finish()
245
+ }
246
+ }
247
+
248
+ impl Sender {
249
+ /// Check to see if this `Sender` can send more data.
250
+ pub(crate) fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<core::Result<()>> {
251
+ // Check if the receiver end has tried polling for the body yet
252
+ ready!(self.poll_want(cx)?);
253
+ self.data_tx.poll_ready(cx).map_err(|_| Error::new_closed())
254
+ }
255
+
256
+ fn poll_want(&mut self, cx: &mut Context<'_>) -> Poll<core::Result<()>> {
257
+ match self.want_rx.load(cx) {
258
+ WANT_READY => Poll::Ready(Ok(())),
259
+ WANT_PENDING => Poll::Pending,
260
+ watch::CLOSED => Poll::Ready(Err(Error::new_closed())),
261
+ unexpected => unreachable!("want_rx value: {}", unexpected),
262
+ }
263
+ }
264
+
265
+ #[cfg(test)]
266
+ async fn ready(&mut self) -> core::Result<()> {
267
+ std::future::poll_fn(|cx| self.poll_ready(cx)).await
268
+ }
269
+
270
+ /// Try to send data on this channel.
271
+ ///
272
+ /// # Errors
273
+ ///
274
+ /// Returns `Err(Bytes)` if the channel could not (currently) accept
275
+ /// another `Bytes`.
276
+ ///
277
+ /// # Note
278
+ ///
279
+ /// This is mostly useful for when trying to send from some other thread
280
+ /// that doesn't have an async context. If in an async context, prefer
281
+ /// `send_data()` instead.
282
+ pub(crate) fn try_send_data(&mut self, chunk: Bytes) -> Result<(), Bytes> {
283
+ self.data_tx
284
+ .try_send(Ok(chunk))
285
+ .map_err(|err| err.into_inner().expect("just sent Ok"))
286
+ }
287
+
288
+ pub(crate) fn try_send_trailers(
289
+ &mut self,
290
+ trailers: HeaderMap,
291
+ ) -> Result<(), Option<HeaderMap>> {
292
+ let tx = match self.trailers_tx.take() {
293
+ Some(tx) => tx,
294
+ None => return Err(None),
295
+ };
296
+
297
+ tx.send(trailers).map_err(Some)
298
+ }
299
+
300
+ #[cfg(test)]
301
+ pub(crate) fn abort(mut self) {
302
+ self.send_error(Error::new_body_write_aborted());
303
+ }
304
+
305
+ pub(crate) fn send_error(&mut self, err: Error) {
306
+ let _ = self
307
+ .data_tx
308
+ // clone so the send works even if buffer is full
309
+ .clone()
310
+ .try_send(Err(err));
311
+ }
312
+ }
313
+
314
+ impl fmt::Debug for Sender {
315
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
316
+ #[derive(Debug)]
317
+ struct Open;
318
+ #[derive(Debug)]
319
+ struct Closed;
320
+
321
+ let mut builder = f.debug_tuple("Sender");
322
+ match self.want_rx.peek() {
323
+ watch::CLOSED => builder.field(&Closed),
324
+ _ => builder.field(&Open),
325
+ };
326
+
327
+ builder.finish()
328
+ }
329
+ }
330
+
331
+ #[cfg(test)]
332
+ mod tests {
333
+ use std::{mem, task::Poll};
334
+
335
+ use http_body_util::BodyExt;
336
+
337
+ use super::{Body, DecodedLength, Incoming, Sender, SizeHint};
338
+
339
+ #[test]
340
+ fn test_size_of() {
341
+ // These are mostly to help catch *accidentally* increasing
342
+ // the size by too much.
343
+
344
+ let body_size = mem::size_of::<Incoming>();
345
+ let body_expected_size = mem::size_of::<u64>() * 5;
346
+ assert!(
347
+ body_size <= body_expected_size,
348
+ "Body size = {body_size} <= {body_expected_size}",
349
+ );
350
+
351
+ //assert_eq!(body_size, mem::size_of::<Option<Incoming>>(), "Option<Incoming>");
352
+
353
+ assert_eq!(
354
+ mem::size_of::<Sender>(),
355
+ mem::size_of::<usize>() * 5,
356
+ "Sender"
357
+ );
358
+
359
+ assert_eq!(
360
+ mem::size_of::<Sender>(),
361
+ mem::size_of::<Option<Sender>>(),
362
+ "Option<Sender>"
363
+ );
364
+ }
365
+
366
+ #[test]
367
+ fn size_hint() {
368
+ fn eq(body: Incoming, b: SizeHint, note: &str) {
369
+ let a = body.size_hint();
370
+ assert_eq!(a.lower(), b.lower(), "lower for {note:?}");
371
+ assert_eq!(a.upper(), b.upper(), "upper for {note:?}");
372
+ }
373
+
374
+ eq(Incoming::empty(), SizeHint::with_exact(0), "empty");
375
+
376
+ eq(Incoming::channel().1, SizeHint::new(), "channel");
377
+
378
+ eq(
379
+ Incoming::new_channel(DecodedLength::new(4), /* wanter = */ false).1,
380
+ SizeHint::with_exact(4),
381
+ "channel with length",
382
+ );
383
+ }
384
+
385
+ #[tokio::test]
386
+ async fn channel_abort() {
387
+ let (tx, mut rx) = Incoming::channel();
388
+
389
+ tx.abort();
390
+
391
+ let err = rx.frame().await.unwrap().unwrap_err();
392
+ assert!(err.is_body_write_aborted(), "{err:?}");
393
+ }
394
+
395
+ #[tokio::test]
396
+ async fn channel_abort_when_buffer_is_full() {
397
+ let (mut tx, mut rx) = Incoming::channel();
398
+
399
+ tx.try_send_data("chunk 1".into()).expect("send 1");
400
+ // buffer is full, but can still send abort
401
+ tx.abort();
402
+
403
+ let chunk1 = rx
404
+ .frame()
405
+ .await
406
+ .expect("item 1")
407
+ .expect("chunk 1")
408
+ .into_data()
409
+ .unwrap();
410
+ assert_eq!(chunk1, "chunk 1");
411
+
412
+ let err = rx.frame().await.unwrap().unwrap_err();
413
+ assert!(err.is_body_write_aborted(), "{err:?}");
414
+ }
415
+
416
+ #[test]
417
+ fn channel_buffers_one() {
418
+ let (mut tx, _rx) = Incoming::channel();
419
+
420
+ tx.try_send_data("chunk 1".into()).expect("send 1");
421
+
422
+ // buffer is now full
423
+ let chunk2 = tx.try_send_data("chunk 2".into()).expect_err("send 2");
424
+ assert_eq!(chunk2, "chunk 2");
425
+ }
426
+
427
+ #[tokio::test]
428
+ async fn channel_empty() {
429
+ let (_, mut rx) = Incoming::channel();
430
+
431
+ assert!(rx.frame().await.is_none());
432
+ }
433
+
434
+ #[test]
435
+ fn channel_ready() {
436
+ let (mut tx, _rx) =
437
+ Incoming::new_channel(DecodedLength::CHUNKED, /* wanter = */ false);
438
+
439
+ let mut tx_ready = tokio_test::task::spawn(tx.ready());
440
+
441
+ assert!(tx_ready.poll().is_ready(), "tx is ready immediately");
442
+ }
443
+
444
+ #[test]
445
+ fn channel_wanter() {
446
+ let (mut tx, mut rx) =
447
+ Incoming::new_channel(DecodedLength::CHUNKED, /* wanter = */ true);
448
+
449
+ let mut tx_ready = tokio_test::task::spawn(tx.ready());
450
+ let mut rx_data = tokio_test::task::spawn(rx.frame());
451
+
452
+ assert!(
453
+ tx_ready.poll().is_pending(),
454
+ "tx isn't ready before rx has been polled"
455
+ );
456
+
457
+ assert!(rx_data.poll().is_pending(), "poll rx.data");
458
+ assert!(tx_ready.is_woken(), "rx poll wakes tx");
459
+
460
+ assert!(
461
+ tx_ready.poll().is_ready(),
462
+ "tx is ready after rx has been polled"
463
+ );
464
+ }
465
+
466
+ #[test]
467
+ fn channel_notices_closure() {
468
+ let (mut tx, rx) = Incoming::new_channel(DecodedLength::CHUNKED, /* wanter = */ true);
469
+
470
+ let mut tx_ready = tokio_test::task::spawn(tx.ready());
471
+
472
+ assert!(
473
+ tx_ready.poll().is_pending(),
474
+ "tx isn't ready before rx has been polled"
475
+ );
476
+
477
+ drop(rx);
478
+ assert!(tx_ready.is_woken(), "dropping rx wakes tx");
479
+
480
+ match tx_ready.poll() {
481
+ Poll::Ready(Err(ref e)) if e.is_closed() => (),
482
+ unexpected => panic!("tx poll ready unexpected: {unexpected:?}"),
483
+ }
484
+ }
485
+ }
@@ -0,0 +1,118 @@
1
+ use std::fmt;
2
+
3
+ use crate::client::core::error::Parse;
4
+
5
+ #[derive(Clone, Copy, PartialEq, Eq)]
6
+ pub(crate) struct DecodedLength(u64);
7
+
8
+ impl From<Option<u64>> for DecodedLength {
9
+ fn from(len: Option<u64>) -> Self {
10
+ len.and_then(|len| {
11
+ // If the length is u64::MAX, oh well, just reported chunked.
12
+ Self::checked_new(len).ok()
13
+ })
14
+ .unwrap_or(DecodedLength::CHUNKED)
15
+ }
16
+ }
17
+
18
+ const MAX_LEN: u64 = u64::MAX - 2;
19
+
20
+ impl DecodedLength {
21
+ pub(crate) const CLOSE_DELIMITED: DecodedLength = DecodedLength(u64::MAX);
22
+ pub(crate) const CHUNKED: DecodedLength = DecodedLength(u64::MAX - 1);
23
+ pub(crate) const ZERO: DecodedLength = DecodedLength(0);
24
+
25
+ #[cfg(test)]
26
+ pub(crate) fn new(len: u64) -> Self {
27
+ debug_assert!(len <= MAX_LEN);
28
+ DecodedLength(len)
29
+ }
30
+
31
+ /// Takes the length as a content-length without other checks.
32
+ ///
33
+ /// Should only be called if previously confirmed this isn't
34
+ /// CLOSE_DELIMITED or CHUNKED.
35
+ #[inline]
36
+ pub(crate) fn danger_len(self) -> u64 {
37
+ debug_assert!(self.0 < Self::CHUNKED.0);
38
+ self.0
39
+ }
40
+
41
+ /// Converts to an `Option<u64>` representing a Known or Unknown length.
42
+ pub(crate) fn into_opt(self) -> Option<u64> {
43
+ match self {
44
+ DecodedLength::CHUNKED | DecodedLength::CLOSE_DELIMITED => None,
45
+ DecodedLength(known) => Some(known),
46
+ }
47
+ }
48
+
49
+ /// Checks the `u64` is within the maximum allowed for content-length.
50
+ pub(crate) fn checked_new(len: u64) -> Result<Self, Parse> {
51
+ if len <= MAX_LEN {
52
+ Ok(DecodedLength(len))
53
+ } else {
54
+ warn!("content-length bigger than maximum: {} > {}", len, MAX_LEN);
55
+ Err(Parse::TooLarge)
56
+ }
57
+ }
58
+
59
+ pub(crate) fn sub_if(&mut self, amt: u64) {
60
+ match *self {
61
+ DecodedLength::CHUNKED | DecodedLength::CLOSE_DELIMITED => (),
62
+ DecodedLength(ref mut known) => {
63
+ *known -= amt;
64
+ }
65
+ }
66
+ }
67
+
68
+ /// Returns whether this represents an exact length.
69
+ ///
70
+ /// This includes 0, which of course is an exact known length.
71
+ ///
72
+ /// It would return false if "chunked" or otherwise size-unknown.
73
+ pub(crate) fn is_exact(&self) -> bool {
74
+ self.0 <= MAX_LEN
75
+ }
76
+ }
77
+
78
+ impl fmt::Debug for DecodedLength {
79
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80
+ match *self {
81
+ DecodedLength::CLOSE_DELIMITED => f.write_str("CLOSE_DELIMITED"),
82
+ DecodedLength::CHUNKED => f.write_str("CHUNKED"),
83
+ DecodedLength(n) => f.debug_tuple("DecodedLength").field(&n).finish(),
84
+ }
85
+ }
86
+ }
87
+
88
+ impl fmt::Display for DecodedLength {
89
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90
+ match *self {
91
+ DecodedLength::CLOSE_DELIMITED => f.write_str("close-delimited"),
92
+ DecodedLength::CHUNKED => f.write_str("chunked encoding"),
93
+ DecodedLength::ZERO => f.write_str("empty"),
94
+ DecodedLength(n) => write!(f, "content-length ({n} bytes)"),
95
+ }
96
+ }
97
+ }
98
+
99
+ #[cfg(test)]
100
+ mod tests {
101
+ use super::*;
102
+
103
+ #[test]
104
+ fn sub_if_known() {
105
+ let mut len = DecodedLength::new(30);
106
+ len.sub_if(20);
107
+
108
+ assert_eq!(len.0, 10);
109
+ }
110
+
111
+ #[test]
112
+ fn sub_if_chunked() {
113
+ let mut len = DecodedLength::CHUNKED;
114
+ len.sub_if(20);
115
+
116
+ assert_eq!(len, DecodedLength::CHUNKED);
117
+ }
118
+ }
@@ -0,0 +1,34 @@
1
+ //! Streaming bodies for Requests and Responses
2
+ //!
3
+ //! For both [Clients](crate::client), requests and
4
+ //! responses use streaming bodies, instead of complete buffering. This
5
+ //! allows applications to not use memory they don't need, and allows exerting
6
+ //! back-pressure on connections by only reading when asked.
7
+ //!
8
+ //! There are two pieces to this in crate::core::
9
+ //!
10
+ //! - **The [\`Body`\] trait** describes all possible bodies. crate::core: allows any body type that
11
+ //! implements `Body`, allowing applications to have fine-grained control over their streaming.
12
+ //! - **The [`Incoming`] concrete type**, which is an implementation of `Body`, and returned by
13
+ //! crate::core: as a "receive stream" (so, for server requests and client responses).
14
+ //!
15
+ //! There are additional implementations available in [`http-body-util`][],
16
+ //! such as a `Full` or `Empty` body.
17
+ //!
18
+ //! [`http-body-util`]: https://docs.rs/http-body-util
19
+
20
+ mod incoming;
21
+ mod length;
22
+
23
+ pub(crate) use self::{
24
+ incoming::{Incoming, Sender},
25
+ length::DecodedLength,
26
+ };
27
+
28
+ fn _assert_send_sync() {
29
+ fn _assert_send<T: Send>() {}
30
+ fn _assert_sync<T: Sync>() {}
31
+
32
+ _assert_send::<Incoming>();
33
+ _assert_sync::<Incoming>();
34
+ }