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,379 @@
1
+ pub(crate) mod client;
2
+ pub(crate) mod ping;
3
+
4
+ use std::{
5
+ future::Future,
6
+ io::{self, Cursor, IoSlice},
7
+ pin::Pin,
8
+ task::{Context, Poll, ready},
9
+ };
10
+
11
+ use bytes::{Buf, Bytes};
12
+ use http::{
13
+ HeaderMap,
14
+ header::{CONNECTION, HeaderName, TE, TRANSFER_ENCODING, UPGRADE},
15
+ };
16
+ use http_body::Body;
17
+ use http2::{Reason, RecvStream, SendStream};
18
+ use pin_project_lite::pin_project;
19
+ use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
20
+
21
+ pub(crate) use self::client::ClientTask;
22
+ use crate::client::core::{self, Error, error::BoxError, proto::h2::ping::Recorder};
23
+
24
+ /// Default initial stream window size defined in HTTP2 spec.
25
+ pub(crate) const SPEC_WINDOW_SIZE: u32 = 65_535;
26
+
27
+ // List of connection headers from RFC 9110 Section 7.6.1
28
+ //
29
+ // TE headers are allowed in HTTP/2 requests as long as the value is "trailers", so they're
30
+ // tested separately.
31
+ static CONNECTION_HEADERS: [HeaderName; 4] = [
32
+ HeaderName::from_static("keep-alive"),
33
+ HeaderName::from_static("proxy-connection"),
34
+ TRANSFER_ENCODING,
35
+ UPGRADE,
36
+ ];
37
+
38
+ fn strip_connection_headers(headers: &mut HeaderMap, is_request: bool) {
39
+ for header in &CONNECTION_HEADERS {
40
+ if headers.remove(header).is_some() {
41
+ warn!("Connection header illegal in HTTP/2: {}", header.as_str());
42
+ }
43
+ }
44
+
45
+ if is_request {
46
+ if headers
47
+ .get(TE)
48
+ .is_some_and(|te_header| te_header != "trailers")
49
+ {
50
+ warn!("TE headers not set to \"trailers\" are illegal in HTTP/2 requests");
51
+ headers.remove(TE);
52
+ }
53
+ } else if headers.remove(TE).is_some() {
54
+ warn!("TE headers illegal in HTTP/2 responses");
55
+ }
56
+
57
+ if let Some(header) = headers.remove(CONNECTION) {
58
+ warn!(
59
+ "Connection header illegal in HTTP/2: {}",
60
+ CONNECTION.as_str()
61
+ );
62
+ let header_contents = header.to_str().unwrap();
63
+
64
+ // A `Connection` header may have a comma-separated list of names of other headers that
65
+ // are meant for only this specific connection.
66
+ //
67
+ // Iterate these names and remove them as headers. Connection-specific headers are
68
+ // forbidden in HTTP2, as that information has been moved into frame types of the h2
69
+ // protocol.
70
+ for name in header_contents.split(',') {
71
+ let name = name.trim();
72
+ headers.remove(name);
73
+ }
74
+ }
75
+ }
76
+
77
+ // body adapters used by both Client and Server
78
+
79
+ pin_project! {
80
+ pub(crate) struct PipeToSendStream<S>
81
+ where
82
+ S: Body,
83
+ {
84
+ body_tx: SendStream<SendBuf<S::Data>>,
85
+ data_done: bool,
86
+ #[pin]
87
+ stream: S,
88
+ }
89
+ }
90
+
91
+ impl<S> PipeToSendStream<S>
92
+ where
93
+ S: Body,
94
+ {
95
+ fn new(stream: S, tx: SendStream<SendBuf<S::Data>>) -> PipeToSendStream<S> {
96
+ PipeToSendStream {
97
+ body_tx: tx,
98
+ data_done: false,
99
+ stream,
100
+ }
101
+ }
102
+ }
103
+
104
+ impl<S> Future for PipeToSendStream<S>
105
+ where
106
+ S: Body,
107
+ S::Error: Into<BoxError>,
108
+ {
109
+ type Output = core::Result<()>;
110
+
111
+ fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
112
+ let mut me = self.project();
113
+ loop {
114
+ // we don't have the next chunk of data yet, so just reserve 1 byte to make
115
+ // sure there's some capacity available. h2 will handle the capacity management
116
+ // for the actual body chunk.
117
+ me.body_tx.reserve_capacity(1);
118
+
119
+ if me.body_tx.capacity() == 0 {
120
+ loop {
121
+ match ready!(me.body_tx.poll_capacity(cx)) {
122
+ Some(Ok(0)) => {}
123
+ Some(Ok(_)) => break,
124
+ Some(Err(e)) => {
125
+ return Poll::Ready(Err(Error::new_body_write(e)));
126
+ }
127
+ None => {
128
+ // None means the stream is no longer in a
129
+ // streaming state, we either finished it
130
+ // somehow, or the remote reset us.
131
+ return Poll::Ready(Err(Error::new_body_write(
132
+ "send stream capacity unexpectedly closed",
133
+ )));
134
+ }
135
+ }
136
+ }
137
+ } else if let Poll::Ready(reason) =
138
+ me.body_tx.poll_reset(cx).map_err(Error::new_body_write)?
139
+ {
140
+ debug!("stream received RST_STREAM: {:?}", reason);
141
+ return Poll::Ready(Err(Error::new_body_write(::http2::Error::from(reason))));
142
+ }
143
+
144
+ match ready!(me.stream.as_mut().poll_frame(cx)) {
145
+ Some(Ok(frame)) => {
146
+ if frame.is_data() {
147
+ let chunk = frame.into_data().unwrap_or_else(|_| unreachable!());
148
+ let is_eos = me.stream.is_end_stream();
149
+ trace!(
150
+ "send body chunk: {} bytes, eos={}",
151
+ chunk.remaining(),
152
+ is_eos,
153
+ );
154
+
155
+ let buf = SendBuf::Buf(chunk);
156
+ me.body_tx
157
+ .send_data(buf, is_eos)
158
+ .map_err(Error::new_body_write)?;
159
+
160
+ if is_eos {
161
+ return Poll::Ready(Ok(()));
162
+ }
163
+ } else if frame.is_trailers() {
164
+ // no more DATA, so give any capacity back
165
+ me.body_tx.reserve_capacity(0);
166
+ me.body_tx
167
+ .send_trailers(frame.into_trailers().unwrap_or_else(|_| unreachable!()))
168
+ .map_err(Error::new_body_write)?;
169
+ return Poll::Ready(Ok(()));
170
+ } else {
171
+ trace!("discarding unknown frame");
172
+ // loop again
173
+ }
174
+ }
175
+ Some(Err(e)) => return Poll::Ready(Err(me.body_tx.on_user_err(e))),
176
+ None => {
177
+ // no more frames means we're done here
178
+ // but at this point, we haven't sent an EOS DATA, or
179
+ // any trailers, so send an empty EOS DATA.
180
+ return Poll::Ready(me.body_tx.send_eos_frame());
181
+ }
182
+ }
183
+ }
184
+ }
185
+ }
186
+
187
+ trait SendStreamExt {
188
+ fn on_user_err<E>(&mut self, err: E) -> Error
189
+ where
190
+ E: Into<BoxError>;
191
+ fn send_eos_frame(&mut self) -> core::Result<()>;
192
+ }
193
+
194
+ impl<B: Buf> SendStreamExt for SendStream<SendBuf<B>> {
195
+ fn on_user_err<E>(&mut self, err: E) -> Error
196
+ where
197
+ E: Into<BoxError>,
198
+ {
199
+ let err = Error::new_user_body(err);
200
+ debug!("send body user stream error: {}", err);
201
+ self.send_reset(err.h2_reason());
202
+ err
203
+ }
204
+
205
+ fn send_eos_frame(&mut self) -> core::Result<()> {
206
+ trace!("send body eos");
207
+ self.send_data(SendBuf::None, true)
208
+ .map_err(Error::new_body_write)
209
+ }
210
+ }
211
+
212
+ #[repr(usize)]
213
+ enum SendBuf<B> {
214
+ Buf(B),
215
+ Cursor(Cursor<Box<[u8]>>),
216
+ None,
217
+ }
218
+
219
+ impl<B: Buf> Buf for SendBuf<B> {
220
+ #[inline]
221
+ fn remaining(&self) -> usize {
222
+ match *self {
223
+ Self::Buf(ref b) => b.remaining(),
224
+ Self::Cursor(ref c) => Buf::remaining(c),
225
+ Self::None => 0,
226
+ }
227
+ }
228
+
229
+ #[inline]
230
+ fn chunk(&self) -> &[u8] {
231
+ match *self {
232
+ Self::Buf(ref b) => b.chunk(),
233
+ Self::Cursor(ref c) => c.chunk(),
234
+ Self::None => &[],
235
+ }
236
+ }
237
+
238
+ #[inline]
239
+ fn advance(&mut self, cnt: usize) {
240
+ match *self {
241
+ Self::Buf(ref mut b) => b.advance(cnt),
242
+ Self::Cursor(ref mut c) => c.advance(cnt),
243
+ Self::None => {}
244
+ }
245
+ }
246
+
247
+ fn chunks_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize {
248
+ match *self {
249
+ Self::Buf(ref b) => b.chunks_vectored(dst),
250
+ Self::Cursor(ref c) => c.chunks_vectored(dst),
251
+ Self::None => 0,
252
+ }
253
+ }
254
+ }
255
+
256
+ struct H2Upgraded<B>
257
+ where
258
+ B: Buf,
259
+ {
260
+ ping: Recorder,
261
+ send_stream: SendStream<SendBuf<B>>,
262
+ recv_stream: RecvStream,
263
+ buf: Bytes,
264
+ }
265
+
266
+ impl<B> AsyncRead for H2Upgraded<B>
267
+ where
268
+ B: Buf,
269
+ {
270
+ fn poll_read(
271
+ mut self: Pin<&mut Self>,
272
+ cx: &mut Context<'_>,
273
+ read_buf: &mut ReadBuf<'_>,
274
+ ) -> Poll<io::Result<()>> {
275
+ if self.buf.is_empty() {
276
+ self.buf = loop {
277
+ match ready!(self.recv_stream.poll_data(cx)) {
278
+ None => return Poll::Ready(Ok(())),
279
+ Some(Ok(buf)) if buf.is_empty() && !self.recv_stream.is_end_stream() => {
280
+ continue;
281
+ }
282
+ Some(Ok(buf)) => {
283
+ self.ping.record_data(buf.len());
284
+ break buf;
285
+ }
286
+ Some(Err(e)) => {
287
+ return Poll::Ready(match e.reason() {
288
+ Some(Reason::NO_ERROR) | Some(Reason::CANCEL) => Ok(()),
289
+ Some(Reason::STREAM_CLOSED) => {
290
+ Err(io::Error::new(io::ErrorKind::BrokenPipe, e))
291
+ }
292
+ _ => Err(h2_to_io_error(e)),
293
+ });
294
+ }
295
+ }
296
+ };
297
+ }
298
+ let cnt = std::cmp::min(self.buf.len(), read_buf.remaining());
299
+ read_buf.put_slice(&self.buf[..cnt]);
300
+ self.buf.advance(cnt);
301
+ let _ = self.recv_stream.flow_control().release_capacity(cnt);
302
+ Poll::Ready(Ok(()))
303
+ }
304
+ }
305
+
306
+ impl<B> AsyncWrite for H2Upgraded<B>
307
+ where
308
+ B: Buf,
309
+ {
310
+ fn poll_write(
311
+ mut self: Pin<&mut Self>,
312
+ cx: &mut Context<'_>,
313
+ buf: &[u8],
314
+ ) -> Poll<io::Result<usize>> {
315
+ if buf.is_empty() {
316
+ return Poll::Ready(Ok(0));
317
+ }
318
+ self.send_stream.reserve_capacity(buf.len());
319
+
320
+ // We ignore all errors returned by `poll_capacity` and `write`, as we
321
+ // will get the correct from `poll_reset` anyway.
322
+ let cnt = match ready!(self.send_stream.poll_capacity(cx)) {
323
+ None => Some(0),
324
+ Some(Ok(cnt)) => self
325
+ .send_stream
326
+ .send_data(SendBuf::Cursor(Cursor::new(buf[..cnt].into())), false)
327
+ .ok()
328
+ .map(|()| cnt),
329
+ Some(Err(_)) => None,
330
+ };
331
+
332
+ if let Some(cnt) = cnt {
333
+ return Poll::Ready(Ok(cnt));
334
+ }
335
+
336
+ Poll::Ready(Err(h2_to_io_error(
337
+ match ready!(self.send_stream.poll_reset(cx)) {
338
+ Ok(Reason::NO_ERROR) | Ok(Reason::CANCEL) | Ok(Reason::STREAM_CLOSED) => {
339
+ return Poll::Ready(Err(io::ErrorKind::BrokenPipe.into()));
340
+ }
341
+ Ok(reason) => reason.into(),
342
+ Err(e) => e,
343
+ },
344
+ )))
345
+ }
346
+
347
+ fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
348
+ Poll::Ready(Ok(()))
349
+ }
350
+
351
+ fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
352
+ if self
353
+ .send_stream
354
+ .send_data(SendBuf::Cursor(Cursor::new([].into())), true)
355
+ .is_ok()
356
+ {
357
+ return Poll::Ready(Ok(()));
358
+ }
359
+
360
+ Poll::Ready(Err(h2_to_io_error(
361
+ match ready!(self.send_stream.poll_reset(cx)) {
362
+ Ok(Reason::NO_ERROR) => return Poll::Ready(Ok(())),
363
+ Ok(Reason::CANCEL) | Ok(Reason::STREAM_CLOSED) => {
364
+ return Poll::Ready(Err(io::ErrorKind::BrokenPipe.into()));
365
+ }
366
+ Ok(reason) => reason.into(),
367
+ Err(e) => e,
368
+ },
369
+ )))
370
+ }
371
+ }
372
+
373
+ fn h2_to_io_error(e: http2::Error) -> std::io::Error {
374
+ if e.is_io() {
375
+ e.into_io().unwrap()
376
+ } else {
377
+ std::io::Error::other(e)
378
+ }
379
+ }
@@ -0,0 +1,138 @@
1
+ use bytes::BytesMut;
2
+ use http::{
3
+ HeaderMap, Method,
4
+ header::{CONTENT_LENGTH, HeaderValue, ValueIter},
5
+ };
6
+
7
+ pub(super) fn connection_keep_alive(value: &HeaderValue) -> bool {
8
+ connection_has(value, "keep-alive")
9
+ }
10
+
11
+ pub(super) fn connection_close(value: &HeaderValue) -> bool {
12
+ connection_has(value, "close")
13
+ }
14
+
15
+ fn connection_has(value: &HeaderValue, needle: &str) -> bool {
16
+ if let Ok(s) = value.to_str() {
17
+ for val in s.split(',') {
18
+ if val.trim().eq_ignore_ascii_case(needle) {
19
+ return true;
20
+ }
21
+ }
22
+ }
23
+ false
24
+ }
25
+
26
+ pub(super) fn content_length_parse_all(headers: &HeaderMap) -> Option<u64> {
27
+ content_length_parse_all_values(headers.get_all(CONTENT_LENGTH).into_iter())
28
+ }
29
+
30
+ pub(super) fn content_length_parse_all_values(values: ValueIter<'_, HeaderValue>) -> Option<u64> {
31
+ // If multiple Content-Length headers were sent, everything can still
32
+ // be alright if they all contain the same value, and all parse
33
+ // correctly. If not, then it's an error.
34
+
35
+ let mut content_length: Option<u64> = None;
36
+ for h in values {
37
+ if let Ok(line) = h.to_str() {
38
+ for v in line.split(',') {
39
+ if let Some(n) = from_digits(v.trim().as_bytes()) {
40
+ if content_length.is_none() {
41
+ content_length = Some(n)
42
+ } else if content_length != Some(n) {
43
+ return None;
44
+ }
45
+ } else {
46
+ return None;
47
+ }
48
+ }
49
+ } else {
50
+ return None;
51
+ }
52
+ }
53
+
54
+ content_length
55
+ }
56
+
57
+ fn from_digits(bytes: &[u8]) -> Option<u64> {
58
+ // cannot use FromStr for u64, since it allows a signed prefix
59
+ let mut result = 0u64;
60
+ const RADIX: u64 = 10;
61
+
62
+ if bytes.is_empty() {
63
+ return None;
64
+ }
65
+
66
+ for &b in bytes {
67
+ // can't use char::to_digit, since we haven't verified these bytes
68
+ // are utf-8.
69
+ match b {
70
+ b'0'..=b'9' => {
71
+ result = result.checked_mul(RADIX)?;
72
+ result = result.checked_add((b - b'0') as u64)?;
73
+ }
74
+ _ => {
75
+ // not a DIGIT, get outta here!
76
+ return None;
77
+ }
78
+ }
79
+ }
80
+
81
+ Some(result)
82
+ }
83
+
84
+ pub(super) fn method_has_defined_payload_semantics(method: &Method) -> bool {
85
+ !matches!(
86
+ *method,
87
+ Method::GET | Method::HEAD | Method::DELETE | Method::CONNECT | Method::OPTIONS
88
+ )
89
+ }
90
+
91
+ pub(super) fn set_content_length_if_missing(headers: &mut HeaderMap, len: u64) {
92
+ headers
93
+ .entry(CONTENT_LENGTH)
94
+ .or_insert_with(|| HeaderValue::from(len));
95
+ }
96
+
97
+ pub(super) fn transfer_encoding_is_chunked(headers: &HeaderMap) -> bool {
98
+ is_chunked(headers.get_all(http::header::TRANSFER_ENCODING).into_iter())
99
+ }
100
+
101
+ pub(super) fn is_chunked(mut encodings: ValueIter<'_, HeaderValue>) -> bool {
102
+ // chunked must always be the last encoding, according to spec
103
+ if let Some(line) = encodings.next_back() {
104
+ return is_chunked_(line);
105
+ }
106
+
107
+ false
108
+ }
109
+
110
+ pub(super) fn is_chunked_(value: &HeaderValue) -> bool {
111
+ // chunked must always be the last encoding, according to spec
112
+ if let Ok(s) = value.to_str() {
113
+ if let Some(encoding) = s.rsplit(',').next() {
114
+ return encoding.trim().eq_ignore_ascii_case("chunked");
115
+ }
116
+ }
117
+
118
+ false
119
+ }
120
+
121
+ pub(super) fn add_chunked(mut entry: http::header::OccupiedEntry<'_, HeaderValue>) {
122
+ const CHUNKED: &str = "chunked";
123
+
124
+ if let Some(line) = entry.iter_mut().next_back() {
125
+ // + 2 for ", "
126
+ let new_cap = line.as_bytes().len() + CHUNKED.len() + 2;
127
+ let mut buf = BytesMut::with_capacity(new_cap);
128
+ buf.extend_from_slice(line.as_bytes());
129
+ buf.extend_from_slice(b", ");
130
+ buf.extend_from_slice(CHUNKED.as_bytes());
131
+
132
+ *line = HeaderValue::from_maybe_shared(buf.freeze())
133
+ .expect("original header value plus ascii is valid");
134
+ return;
135
+ }
136
+
137
+ entry.insert(HeaderValue::from_static(CHUNKED));
138
+ }
@@ -0,0 +1,58 @@
1
+ //! Pieces pertaining to the HTTP message protocol.
2
+
3
+ mod headers;
4
+
5
+ pub(crate) mod h1;
6
+ pub(crate) mod h2;
7
+
8
+ pub(crate) use self::h1::{Conn, dispatch};
9
+ use crate::client::core::upgrade;
10
+
11
+ /// An Incoming Message head. Includes request/status line, and headers.
12
+ #[derive(Debug, Default)]
13
+ pub(crate) struct MessageHead<S> {
14
+ /// HTTP version of the message.
15
+ pub(crate) version: http::Version,
16
+ /// Subject (request line or status line) of Incoming message.
17
+ pub(crate) subject: S,
18
+ /// Headers of the Incoming message.
19
+ pub(crate) headers: http::HeaderMap,
20
+ /// Extensions.
21
+ extensions: http::Extensions,
22
+ }
23
+
24
+ /// An incoming request message.
25
+ pub(crate) type RequestHead = MessageHead<RequestLine>;
26
+
27
+ #[derive(Debug, Default, PartialEq)]
28
+ pub(crate) struct RequestLine(pub(crate) http::Method, pub(crate) http::Uri);
29
+
30
+ /// An incoming response message.
31
+ pub(crate) type ResponseHead = MessageHead<http::StatusCode>;
32
+
33
+ #[derive(Debug)]
34
+ pub(crate) enum BodyLength {
35
+ /// Content-Length
36
+ Known(u64),
37
+ /// Transfer-Encoding: chunked (if h1)
38
+ Unknown,
39
+ }
40
+
41
+ /// Status of when a Dispatcher future completes.
42
+ pub(crate) enum Dispatched {
43
+ /// Dispatcher completely shutdown connection.
44
+ Shutdown,
45
+ /// Dispatcher has pending upgrade, and so did not shutdown.
46
+ Upgrade(upgrade::Pending),
47
+ }
48
+
49
+ impl MessageHead<http::StatusCode> {
50
+ fn into_response<B>(self, body: B) -> http::Response<B> {
51
+ let mut res = http::Response::new(body);
52
+ *res.status_mut() = self.subject;
53
+ *res.headers_mut() = self.headers;
54
+ *res.version_mut() = self.version;
55
+ *res.extensions_mut() = self.extensions;
56
+ res
57
+ }
58
+ }
@@ -0,0 +1,57 @@
1
+ //! Trait aliases
2
+ //!
3
+ //! Traits in this module ease setting bounds and usually automatically
4
+ //! implemented by implementing another trait.
5
+
6
+ pub use self::h2_client::Http2ClientConnExec;
7
+
8
+ mod h2_client {
9
+ use std::future::Future;
10
+
11
+ use tokio::io::{AsyncRead, AsyncWrite};
12
+
13
+ use crate::client::core::{error::BoxError, proto::h2::client::H2ClientFuture, rt::Executor};
14
+
15
+ /// An executor to spawn http2 futures for the client.
16
+ ///
17
+ /// This trait is implemented for any type that implements [`Executor`]
18
+ /// trait for any future.
19
+ ///
20
+ /// This trait is sealed and cannot be implemented for types outside this crate.
21
+ pub trait Http2ClientConnExec<B, T>: sealed_client::Sealed<(B, T)>
22
+ where
23
+ B: http_body::Body,
24
+ B::Error: Into<BoxError>,
25
+ T: AsyncRead + AsyncWrite + Unpin,
26
+ {
27
+ #[doc(hidden)]
28
+ fn execute_h2_future(&mut self, future: H2ClientFuture<B, T>);
29
+ }
30
+
31
+ impl<E, B, T> Http2ClientConnExec<B, T> for E
32
+ where
33
+ E: Executor<H2ClientFuture<B, T>>,
34
+ B: http_body::Body + 'static,
35
+ B::Error: Into<BoxError>,
36
+ H2ClientFuture<B, T>: Future<Output = ()>,
37
+ T: AsyncRead + AsyncWrite + Unpin,
38
+ {
39
+ fn execute_h2_future(&mut self, future: H2ClientFuture<B, T>) {
40
+ self.execute(future)
41
+ }
42
+ }
43
+
44
+ impl<E, B, T> sealed_client::Sealed<(B, T)> for E
45
+ where
46
+ E: Executor<H2ClientFuture<B, T>>,
47
+ B: http_body::Body + 'static,
48
+ B::Error: Into<BoxError>,
49
+ H2ClientFuture<B, T>: Future<Output = ()>,
50
+ T: AsyncRead + AsyncWrite + Unpin,
51
+ {
52
+ }
53
+
54
+ mod sealed_client {
55
+ pub trait Sealed<X> {}
56
+ }
57
+ }