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.
- checksums.yaml +7 -0
- data/Cargo.lock +2688 -0
- data/Cargo.toml +6 -0
- data/README.md +179 -0
- data/ext/wreq_rb/Cargo.toml +39 -0
- data/ext/wreq_rb/extconf.rb +22 -0
- data/ext/wreq_rb/src/client.rs +565 -0
- data/ext/wreq_rb/src/error.rs +25 -0
- data/ext/wreq_rb/src/lib.rs +20 -0
- data/ext/wreq_rb/src/response.rs +132 -0
- data/lib/wreq-rb/version.rb +5 -0
- data/lib/wreq-rb.rb +17 -0
- data/patches/0001-add-transfer-size-tracking.patch +292 -0
- data/vendor/wreq/Cargo.toml +306 -0
- data/vendor/wreq/LICENSE +202 -0
- data/vendor/wreq/README.md +122 -0
- data/vendor/wreq/examples/cert_store.rs +77 -0
- data/vendor/wreq/examples/connect_via_lower_priority_tokio_runtime.rs +258 -0
- data/vendor/wreq/examples/emulation.rs +118 -0
- data/vendor/wreq/examples/form.rs +14 -0
- data/vendor/wreq/examples/http1_websocket.rs +37 -0
- data/vendor/wreq/examples/http2_websocket.rs +45 -0
- data/vendor/wreq/examples/json_dynamic.rs +41 -0
- data/vendor/wreq/examples/json_typed.rs +47 -0
- data/vendor/wreq/examples/keylog.rs +16 -0
- data/vendor/wreq/examples/request_with_emulation.rs +115 -0
- data/vendor/wreq/examples/request_with_interface.rs +37 -0
- data/vendor/wreq/examples/request_with_local_address.rs +16 -0
- data/vendor/wreq/examples/request_with_proxy.rs +13 -0
- data/vendor/wreq/examples/request_with_redirect.rs +22 -0
- data/vendor/wreq/examples/request_with_version.rs +15 -0
- data/vendor/wreq/examples/tor_socks.rs +24 -0
- data/vendor/wreq/examples/unix_socket.rs +33 -0
- data/vendor/wreq/src/client/body.rs +304 -0
- data/vendor/wreq/src/client/conn/conn.rs +231 -0
- data/vendor/wreq/src/client/conn/connector.rs +549 -0
- data/vendor/wreq/src/client/conn/http.rs +1023 -0
- data/vendor/wreq/src/client/conn/proxy/socks.rs +233 -0
- data/vendor/wreq/src/client/conn/proxy/tunnel.rs +260 -0
- data/vendor/wreq/src/client/conn/proxy.rs +39 -0
- data/vendor/wreq/src/client/conn/tls_info.rs +98 -0
- data/vendor/wreq/src/client/conn/uds.rs +44 -0
- data/vendor/wreq/src/client/conn/verbose.rs +149 -0
- data/vendor/wreq/src/client/conn.rs +323 -0
- data/vendor/wreq/src/client/core/body/incoming.rs +485 -0
- data/vendor/wreq/src/client/core/body/length.rs +118 -0
- data/vendor/wreq/src/client/core/body.rs +34 -0
- data/vendor/wreq/src/client/core/common/buf.rs +149 -0
- data/vendor/wreq/src/client/core/common/rewind.rs +141 -0
- data/vendor/wreq/src/client/core/common/watch.rs +76 -0
- data/vendor/wreq/src/client/core/common.rs +3 -0
- data/vendor/wreq/src/client/core/conn/http1.rs +342 -0
- data/vendor/wreq/src/client/core/conn/http2.rs +307 -0
- data/vendor/wreq/src/client/core/conn.rs +11 -0
- data/vendor/wreq/src/client/core/dispatch.rs +299 -0
- data/vendor/wreq/src/client/core/error.rs +435 -0
- data/vendor/wreq/src/client/core/ext.rs +201 -0
- data/vendor/wreq/src/client/core/http1.rs +178 -0
- data/vendor/wreq/src/client/core/http2.rs +483 -0
- data/vendor/wreq/src/client/core/proto/h1/conn.rs +988 -0
- data/vendor/wreq/src/client/core/proto/h1/decode.rs +1170 -0
- data/vendor/wreq/src/client/core/proto/h1/dispatch.rs +684 -0
- data/vendor/wreq/src/client/core/proto/h1/encode.rs +580 -0
- data/vendor/wreq/src/client/core/proto/h1/io.rs +879 -0
- data/vendor/wreq/src/client/core/proto/h1/role.rs +694 -0
- data/vendor/wreq/src/client/core/proto/h1.rs +104 -0
- data/vendor/wreq/src/client/core/proto/h2/client.rs +650 -0
- data/vendor/wreq/src/client/core/proto/h2/ping.rs +539 -0
- data/vendor/wreq/src/client/core/proto/h2.rs +379 -0
- data/vendor/wreq/src/client/core/proto/headers.rs +138 -0
- data/vendor/wreq/src/client/core/proto.rs +58 -0
- data/vendor/wreq/src/client/core/rt/bounds.rs +57 -0
- data/vendor/wreq/src/client/core/rt/timer.rs +150 -0
- data/vendor/wreq/src/client/core/rt/tokio.rs +99 -0
- data/vendor/wreq/src/client/core/rt.rs +25 -0
- data/vendor/wreq/src/client/core/upgrade.rs +267 -0
- data/vendor/wreq/src/client/core.rs +16 -0
- data/vendor/wreq/src/client/emulation.rs +161 -0
- data/vendor/wreq/src/client/http/client/error.rs +142 -0
- data/vendor/wreq/src/client/http/client/exec.rs +29 -0
- data/vendor/wreq/src/client/http/client/extra.rs +77 -0
- data/vendor/wreq/src/client/http/client/lazy.rs +79 -0
- data/vendor/wreq/src/client/http/client/pool.rs +1105 -0
- data/vendor/wreq/src/client/http/client/util.rs +104 -0
- data/vendor/wreq/src/client/http/client.rs +1003 -0
- data/vendor/wreq/src/client/http/future.rs +99 -0
- data/vendor/wreq/src/client/http.rs +1629 -0
- data/vendor/wreq/src/client/layer/config/options.rs +156 -0
- data/vendor/wreq/src/client/layer/config.rs +116 -0
- data/vendor/wreq/src/client/layer/cookie.rs +161 -0
- data/vendor/wreq/src/client/layer/decoder.rs +139 -0
- data/vendor/wreq/src/client/layer/redirect/future.rs +270 -0
- data/vendor/wreq/src/client/layer/redirect/policy.rs +63 -0
- data/vendor/wreq/src/client/layer/redirect.rs +145 -0
- data/vendor/wreq/src/client/layer/retry/classify.rs +105 -0
- data/vendor/wreq/src/client/layer/retry/scope.rs +51 -0
- data/vendor/wreq/src/client/layer/retry.rs +151 -0
- data/vendor/wreq/src/client/layer/timeout/body.rs +233 -0
- data/vendor/wreq/src/client/layer/timeout/future.rs +90 -0
- data/vendor/wreq/src/client/layer/timeout.rs +177 -0
- data/vendor/wreq/src/client/layer.rs +15 -0
- data/vendor/wreq/src/client/multipart.rs +717 -0
- data/vendor/wreq/src/client/request.rs +818 -0
- data/vendor/wreq/src/client/response.rs +534 -0
- data/vendor/wreq/src/client/ws/json.rs +99 -0
- data/vendor/wreq/src/client/ws/message.rs +453 -0
- data/vendor/wreq/src/client/ws.rs +714 -0
- data/vendor/wreq/src/client.rs +27 -0
- data/vendor/wreq/src/config.rs +140 -0
- data/vendor/wreq/src/cookie.rs +579 -0
- data/vendor/wreq/src/dns/gai.rs +249 -0
- data/vendor/wreq/src/dns/hickory.rs +78 -0
- data/vendor/wreq/src/dns/resolve.rs +180 -0
- data/vendor/wreq/src/dns.rs +69 -0
- data/vendor/wreq/src/error.rs +502 -0
- data/vendor/wreq/src/ext.rs +398 -0
- data/vendor/wreq/src/hash.rs +143 -0
- data/vendor/wreq/src/header.rs +506 -0
- data/vendor/wreq/src/into_uri.rs +187 -0
- data/vendor/wreq/src/lib.rs +586 -0
- data/vendor/wreq/src/proxy/mac.rs +82 -0
- data/vendor/wreq/src/proxy/matcher.rs +806 -0
- data/vendor/wreq/src/proxy/uds.rs +66 -0
- data/vendor/wreq/src/proxy/win.rs +31 -0
- data/vendor/wreq/src/proxy.rs +569 -0
- data/vendor/wreq/src/redirect.rs +575 -0
- data/vendor/wreq/src/retry.rs +198 -0
- data/vendor/wreq/src/sync.rs +129 -0
- data/vendor/wreq/src/tls/conn/cache.rs +123 -0
- data/vendor/wreq/src/tls/conn/cert_compression.rs +125 -0
- data/vendor/wreq/src/tls/conn/ext.rs +82 -0
- data/vendor/wreq/src/tls/conn/macros.rs +34 -0
- data/vendor/wreq/src/tls/conn/service.rs +138 -0
- data/vendor/wreq/src/tls/conn.rs +681 -0
- data/vendor/wreq/src/tls/keylog/handle.rs +64 -0
- data/vendor/wreq/src/tls/keylog.rs +99 -0
- data/vendor/wreq/src/tls/options.rs +464 -0
- data/vendor/wreq/src/tls/x509/identity.rs +122 -0
- data/vendor/wreq/src/tls/x509/parser.rs +71 -0
- data/vendor/wreq/src/tls/x509/store.rs +228 -0
- data/vendor/wreq/src/tls/x509.rs +68 -0
- data/vendor/wreq/src/tls.rs +154 -0
- data/vendor/wreq/src/trace.rs +55 -0
- data/vendor/wreq/src/util.rs +122 -0
- data/vendor/wreq/tests/badssl.rs +228 -0
- data/vendor/wreq/tests/brotli.rs +350 -0
- data/vendor/wreq/tests/client.rs +1098 -0
- data/vendor/wreq/tests/connector_layers.rs +227 -0
- data/vendor/wreq/tests/cookie.rs +306 -0
- data/vendor/wreq/tests/deflate.rs +347 -0
- data/vendor/wreq/tests/emulation.rs +260 -0
- data/vendor/wreq/tests/gzip.rs +347 -0
- data/vendor/wreq/tests/layers.rs +261 -0
- data/vendor/wreq/tests/multipart.rs +165 -0
- data/vendor/wreq/tests/proxy.rs +438 -0
- data/vendor/wreq/tests/redirect.rs +629 -0
- data/vendor/wreq/tests/retry.rs +135 -0
- data/vendor/wreq/tests/support/delay_server.rs +117 -0
- data/vendor/wreq/tests/support/error.rs +16 -0
- data/vendor/wreq/tests/support/layer.rs +183 -0
- data/vendor/wreq/tests/support/mod.rs +9 -0
- data/vendor/wreq/tests/support/server.rs +232 -0
- data/vendor/wreq/tests/timeouts.rs +281 -0
- data/vendor/wreq/tests/unix_socket.rs +135 -0
- data/vendor/wreq/tests/upgrade.rs +98 -0
- data/vendor/wreq/tests/zstd.rs +559 -0
- metadata +225 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
//! HTTP/2 client connections
|
|
2
|
+
|
|
3
|
+
use std::{
|
|
4
|
+
fmt,
|
|
5
|
+
future::Future,
|
|
6
|
+
marker::PhantomData,
|
|
7
|
+
pin::Pin,
|
|
8
|
+
task::{Context, Poll, ready},
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
use http::{Request, Response};
|
|
12
|
+
use http_body::Body;
|
|
13
|
+
use tokio::io::{AsyncRead, AsyncWrite};
|
|
14
|
+
|
|
15
|
+
use crate::{
|
|
16
|
+
client::core::{
|
|
17
|
+
Result,
|
|
18
|
+
body::Incoming as IncomingBody,
|
|
19
|
+
dispatch::{self, TrySendError},
|
|
20
|
+
error::{BoxError, Error},
|
|
21
|
+
proto::{self, h2::ping},
|
|
22
|
+
rt::{ArcTimer, Time, Timer, bounds::Http2ClientConnExec},
|
|
23
|
+
},
|
|
24
|
+
http2::Http2Options,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/// The sender side of an established connection.
|
|
28
|
+
pub struct SendRequest<B> {
|
|
29
|
+
dispatch: dispatch::UnboundedSender<Request<B>, Response<IncomingBody>>,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
impl<B> Clone for SendRequest<B> {
|
|
33
|
+
fn clone(&self) -> SendRequest<B> {
|
|
34
|
+
SendRequest {
|
|
35
|
+
dispatch: self.dispatch.clone(),
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/// A future that processes all HTTP state for the IO object.
|
|
41
|
+
///
|
|
42
|
+
/// In most cases, this should just be spawned into an executor, so that it
|
|
43
|
+
/// can process incoming and outgoing messages, notice hangups, and the like.
|
|
44
|
+
#[must_use = "futures do nothing unless polled"]
|
|
45
|
+
pub struct Connection<T, B, E>
|
|
46
|
+
where
|
|
47
|
+
T: AsyncRead + AsyncWrite + Unpin,
|
|
48
|
+
B: Body + 'static,
|
|
49
|
+
E: Http2ClientConnExec<B, T> + Unpin,
|
|
50
|
+
B::Error: Into<BoxError>,
|
|
51
|
+
{
|
|
52
|
+
inner: (PhantomData<T>, proto::h2::ClientTask<B, E, T>),
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/// A builder to configure an HTTP connection.
|
|
56
|
+
///
|
|
57
|
+
/// After setting options, the builder is used to create a handshake future.
|
|
58
|
+
///
|
|
59
|
+
/// **Note**: The default values of options are *not considered stable*. They
|
|
60
|
+
/// are subject to change at any time.
|
|
61
|
+
#[derive(Clone)]
|
|
62
|
+
pub struct Builder<Ex> {
|
|
63
|
+
exec: Ex,
|
|
64
|
+
timer: Time,
|
|
65
|
+
opts: Http2Options,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ===== impl SendRequest
|
|
69
|
+
|
|
70
|
+
impl<B> SendRequest<B> {
|
|
71
|
+
/// Polls to determine whether this sender can be used yet for a request.
|
|
72
|
+
///
|
|
73
|
+
/// If the associated connection is closed, this returns an Error.
|
|
74
|
+
pub fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<()>> {
|
|
75
|
+
if self.is_closed() {
|
|
76
|
+
Poll::Ready(Err(Error::new_closed()))
|
|
77
|
+
} else {
|
|
78
|
+
Poll::Ready(Ok(()))
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/// Waits until the dispatcher is ready
|
|
83
|
+
///
|
|
84
|
+
/// If the associated connection is closed, this returns an Error.
|
|
85
|
+
pub async fn ready(&mut self) -> Result<()> {
|
|
86
|
+
std::future::poll_fn(|cx| self.poll_ready(cx)).await
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/// Checks if the connection is currently ready to send a request.
|
|
90
|
+
///
|
|
91
|
+
/// # Note
|
|
92
|
+
///
|
|
93
|
+
/// This is mostly a hint. Due to inherent latency of networks, it is
|
|
94
|
+
/// possible that even after checking this is ready, sending a request
|
|
95
|
+
/// may still fail because the connection was closed in the meantime.
|
|
96
|
+
pub fn is_ready(&self) -> bool {
|
|
97
|
+
self.dispatch.is_ready()
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/// Checks if the connection side has been closed.
|
|
101
|
+
pub fn is_closed(&self) -> bool {
|
|
102
|
+
self.dispatch.is_closed()
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
impl<B> SendRequest<B>
|
|
107
|
+
where
|
|
108
|
+
B: Body + 'static,
|
|
109
|
+
{
|
|
110
|
+
/// Sends a `Request` on the associated connection.
|
|
111
|
+
///
|
|
112
|
+
/// Returns a future that if successful, yields the `Response`.
|
|
113
|
+
///
|
|
114
|
+
/// # Error
|
|
115
|
+
///
|
|
116
|
+
/// If there was an error before trying to serialize the request to the
|
|
117
|
+
/// connection, the message will be returned as part of this error.
|
|
118
|
+
pub fn try_send_request(
|
|
119
|
+
&mut self,
|
|
120
|
+
req: Request<B>,
|
|
121
|
+
) -> impl Future<Output = std::result::Result<Response<IncomingBody>, TrySendError<Request<B>>>>
|
|
122
|
+
{
|
|
123
|
+
let sent = self.dispatch.try_send(req);
|
|
124
|
+
async move {
|
|
125
|
+
match sent {
|
|
126
|
+
Ok(rx) => match rx.await {
|
|
127
|
+
Ok(Ok(res)) => Ok(res),
|
|
128
|
+
Ok(Err(err)) => Err(err),
|
|
129
|
+
// this is definite bug if it happens, but it shouldn't happen!
|
|
130
|
+
Err(_) => panic!("dispatch dropped without returning error"),
|
|
131
|
+
},
|
|
132
|
+
Err(req) => {
|
|
133
|
+
debug!("connection was not ready");
|
|
134
|
+
let error = Error::new_canceled().with("connection was not ready");
|
|
135
|
+
Err(TrySendError {
|
|
136
|
+
error,
|
|
137
|
+
message: Some(req),
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
impl<B> fmt::Debug for SendRequest<B> {
|
|
146
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
147
|
+
f.debug_struct("SendRequest").finish()
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ===== impl Connection
|
|
152
|
+
|
|
153
|
+
impl<T, B, E> fmt::Debug for Connection<T, B, E>
|
|
154
|
+
where
|
|
155
|
+
T: AsyncRead + AsyncWrite + fmt::Debug + 'static + Unpin,
|
|
156
|
+
B: Body + 'static,
|
|
157
|
+
E: Http2ClientConnExec<B, T> + Unpin,
|
|
158
|
+
B::Error: Into<BoxError>,
|
|
159
|
+
{
|
|
160
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
161
|
+
f.debug_struct("Connection").finish()
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
impl<T, B, E> Future for Connection<T, B, E>
|
|
166
|
+
where
|
|
167
|
+
T: AsyncRead + AsyncWrite + Unpin + 'static,
|
|
168
|
+
B: Body + 'static + Unpin,
|
|
169
|
+
B::Data: Send,
|
|
170
|
+
E: Unpin,
|
|
171
|
+
B::Error: Into<BoxError>,
|
|
172
|
+
E: Http2ClientConnExec<B, T> + Unpin,
|
|
173
|
+
{
|
|
174
|
+
type Output = Result<()>;
|
|
175
|
+
|
|
176
|
+
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
177
|
+
match ready!(Pin::new(&mut self.inner.1).poll(cx))? {
|
|
178
|
+
proto::Dispatched::Shutdown => Poll::Ready(Ok(())),
|
|
179
|
+
proto::Dispatched::Upgrade(_pending) => unreachable!("http2 cannot upgrade"),
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// ===== impl Builder
|
|
185
|
+
|
|
186
|
+
impl<Ex> Builder<Ex>
|
|
187
|
+
where
|
|
188
|
+
Ex: Clone,
|
|
189
|
+
{
|
|
190
|
+
/// Creates a new connection builder.
|
|
191
|
+
#[inline]
|
|
192
|
+
pub fn new(exec: Ex) -> Builder<Ex> {
|
|
193
|
+
Builder {
|
|
194
|
+
exec,
|
|
195
|
+
timer: Time::Empty,
|
|
196
|
+
opts: Default::default(),
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/// Provide a timer to execute background HTTP2 tasks.
|
|
201
|
+
#[inline]
|
|
202
|
+
pub fn timer<M>(&mut self, timer: M)
|
|
203
|
+
where
|
|
204
|
+
M: Timer + Send + Sync + 'static,
|
|
205
|
+
{
|
|
206
|
+
self.timer = Time::Timer(ArcTimer::new(timer));
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/// Provide a options configuration for the HTTP/2 connection.
|
|
210
|
+
#[inline]
|
|
211
|
+
pub fn options(&mut self, opts: Http2Options) {
|
|
212
|
+
self.opts = opts;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/// Constructs a connection with the configured options and IO.
|
|
216
|
+
///
|
|
217
|
+
/// Note, if [`Connection`] is not `await`-ed, [`SendRequest`] will
|
|
218
|
+
/// do nothing.
|
|
219
|
+
pub async fn handshake<T, B>(self, io: T) -> Result<(SendRequest<B>, Connection<T, B, Ex>)>
|
|
220
|
+
where
|
|
221
|
+
T: AsyncRead + AsyncWrite + Unpin,
|
|
222
|
+
B: Body + 'static,
|
|
223
|
+
B::Data: Send,
|
|
224
|
+
B::Error: Into<BoxError>,
|
|
225
|
+
Ex: Http2ClientConnExec<B, T> + Unpin,
|
|
226
|
+
{
|
|
227
|
+
trace!("client handshake HTTP/2");
|
|
228
|
+
|
|
229
|
+
// Crate the HTTP/2 client with the provided options.
|
|
230
|
+
let builder = {
|
|
231
|
+
let mut builder = http2::client::Builder::default();
|
|
232
|
+
builder
|
|
233
|
+
.initial_max_send_streams(self.opts.initial_max_send_streams)
|
|
234
|
+
.initial_window_size(self.opts.initial_window_size)
|
|
235
|
+
.initial_connection_window_size(self.opts.initial_conn_window_size)
|
|
236
|
+
.max_send_buffer_size(self.opts.max_send_buffer_size);
|
|
237
|
+
if let Some(id) = self.opts.initial_stream_id {
|
|
238
|
+
builder.initial_stream_id(id);
|
|
239
|
+
}
|
|
240
|
+
if let Some(max) = self.opts.max_pending_accept_reset_streams {
|
|
241
|
+
builder.max_pending_accept_reset_streams(max);
|
|
242
|
+
}
|
|
243
|
+
if let Some(max) = self.opts.max_concurrent_reset_streams {
|
|
244
|
+
builder.max_concurrent_reset_streams(max);
|
|
245
|
+
}
|
|
246
|
+
if let Some(max) = self.opts.max_concurrent_streams {
|
|
247
|
+
builder.max_concurrent_streams(max);
|
|
248
|
+
}
|
|
249
|
+
if let Some(max) = self.opts.max_header_list_size {
|
|
250
|
+
builder.max_header_list_size(max);
|
|
251
|
+
}
|
|
252
|
+
if let Some(opt) = self.opts.enable_push {
|
|
253
|
+
builder.enable_push(opt);
|
|
254
|
+
}
|
|
255
|
+
if let Some(max) = self.opts.max_frame_size {
|
|
256
|
+
builder.max_frame_size(max);
|
|
257
|
+
}
|
|
258
|
+
if let Some(max) = self.opts.header_table_size {
|
|
259
|
+
builder.header_table_size(max);
|
|
260
|
+
}
|
|
261
|
+
if let Some(v) = self.opts.enable_connect_protocol {
|
|
262
|
+
builder.enable_connect_protocol(v);
|
|
263
|
+
}
|
|
264
|
+
if let Some(v) = self.opts.no_rfc7540_priorities {
|
|
265
|
+
builder.no_rfc7540_priorities(v);
|
|
266
|
+
}
|
|
267
|
+
if let Some(order) = self.opts.settings_order {
|
|
268
|
+
builder.settings_order(order);
|
|
269
|
+
}
|
|
270
|
+
if let Some(experimental_settings) = self.opts.experimental_settings {
|
|
271
|
+
builder.experimental_settings(experimental_settings);
|
|
272
|
+
}
|
|
273
|
+
if let Some(stream_dependency) = self.opts.headers_stream_dependency {
|
|
274
|
+
builder.headers_stream_dependency(stream_dependency);
|
|
275
|
+
}
|
|
276
|
+
if let Some(order) = self.opts.headers_pseudo_order {
|
|
277
|
+
builder.headers_pseudo_order(order);
|
|
278
|
+
}
|
|
279
|
+
if let Some(priority) = self.opts.priorities {
|
|
280
|
+
builder.priorities(priority);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
builder
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
// Create the ping configuration for the connection.
|
|
287
|
+
let ping_config = ping::Config::new(
|
|
288
|
+
self.opts.adaptive_window,
|
|
289
|
+
self.opts.initial_window_size,
|
|
290
|
+
self.opts.keep_alive_interval,
|
|
291
|
+
self.opts.keep_alive_timeout,
|
|
292
|
+
self.opts.keep_alive_while_idle,
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
let (tx, rx) = dispatch::channel();
|
|
296
|
+
let h2 = proto::h2::client::handshake(io, rx, builder, ping_config, self.exec, self.timer)
|
|
297
|
+
.await?;
|
|
298
|
+
Ok((
|
|
299
|
+
SendRequest {
|
|
300
|
+
dispatch: tx.unbound(),
|
|
301
|
+
},
|
|
302
|
+
Connection {
|
|
303
|
+
inner: (PhantomData, h2),
|
|
304
|
+
},
|
|
305
|
+
))
|
|
306
|
+
}
|
|
307
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//! Lower-level client connection API.
|
|
2
|
+
//!
|
|
3
|
+
//! The types in this module are to provide a lower-level API based around a
|
|
4
|
+
//! single connection. Connecting to a host, pooling connections, and the like
|
|
5
|
+
//! are not handled at this level. This module provides the building blocks to
|
|
6
|
+
//! customize those things externally.
|
|
7
|
+
|
|
8
|
+
pub mod http1;
|
|
9
|
+
pub mod http2;
|
|
10
|
+
|
|
11
|
+
pub use super::dispatch::TrySendError;
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
use std::{
|
|
2
|
+
future::Future,
|
|
3
|
+
pin::Pin,
|
|
4
|
+
task::{Context, Poll},
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
use http::{Request, Response};
|
|
8
|
+
use http_body::Body;
|
|
9
|
+
use pin_project_lite::pin_project;
|
|
10
|
+
use tokio::sync::{mpsc, oneshot};
|
|
11
|
+
|
|
12
|
+
use super::{Error, body::Incoming, proto::h2::client::ResponseFutMap};
|
|
13
|
+
|
|
14
|
+
pub(crate) type RetryPromise<T, U> = oneshot::Receiver<Result<U, TrySendError<T>>>;
|
|
15
|
+
|
|
16
|
+
/// An error when calling `try_send_request`.
|
|
17
|
+
///
|
|
18
|
+
/// There is a possibility of an error occurring on a connection in-between the
|
|
19
|
+
/// time that a request is queued and when it is actually written to the IO
|
|
20
|
+
/// transport. If that happens, it is safe to return the request back to the
|
|
21
|
+
/// caller, as it was never fully sent.
|
|
22
|
+
#[derive(Debug)]
|
|
23
|
+
pub struct TrySendError<T> {
|
|
24
|
+
pub(crate) error: Error,
|
|
25
|
+
pub(crate) message: Option<T>,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
pub(crate) fn channel<T, U>() -> (Sender<T, U>, Receiver<T, U>) {
|
|
29
|
+
let (tx, rx) = mpsc::unbounded_channel();
|
|
30
|
+
let (giver, taker) = want::new();
|
|
31
|
+
let tx = Sender {
|
|
32
|
+
buffered_once: false,
|
|
33
|
+
giver,
|
|
34
|
+
inner: tx,
|
|
35
|
+
};
|
|
36
|
+
let rx = Receiver { inner: rx, taker };
|
|
37
|
+
(tx, rx)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/// A bounded sender of requests and callbacks for when responses are ready.
|
|
41
|
+
///
|
|
42
|
+
/// While the inner sender is unbounded, the Giver is used to determine
|
|
43
|
+
/// if the Receiver is ready for another request.
|
|
44
|
+
pub(crate) struct Sender<T, U> {
|
|
45
|
+
/// One message is always allowed, even if the Receiver hasn't asked
|
|
46
|
+
/// for it yet. This boolean keeps track of whether we've sent one
|
|
47
|
+
/// without notice.
|
|
48
|
+
buffered_once: bool,
|
|
49
|
+
/// The Giver helps watch that the Receiver side has been polled
|
|
50
|
+
/// when the queue is empty. This helps us know when a request and
|
|
51
|
+
/// response have been fully processed, and a connection is ready
|
|
52
|
+
/// for more.
|
|
53
|
+
giver: want::Giver,
|
|
54
|
+
/// Actually bounded by the Giver, plus `buffered_once`.
|
|
55
|
+
inner: mpsc::UnboundedSender<Envelope<T, U>>,
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/// An unbounded version.
|
|
59
|
+
///
|
|
60
|
+
/// Cannot poll the Giver, but can still use it to determine if the Receiver
|
|
61
|
+
/// has been dropped. However, this version can be cloned.
|
|
62
|
+
pub(crate) struct UnboundedSender<T, U> {
|
|
63
|
+
/// Only used for `is_closed`, since mpsc::UnboundedSender cannot be checked.
|
|
64
|
+
giver: want::SharedGiver,
|
|
65
|
+
inner: mpsc::UnboundedSender<Envelope<T, U>>,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
impl<T, U> Sender<T, U> {
|
|
69
|
+
pub(crate) fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<super::Result<()>> {
|
|
70
|
+
self.giver.poll_want(cx).map_err(|_| Error::new_closed())
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
pub(crate) fn is_ready(&self) -> bool {
|
|
74
|
+
self.giver.is_wanting()
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
fn can_send(&mut self) -> bool {
|
|
78
|
+
if self.giver.give() || !self.buffered_once {
|
|
79
|
+
// If the receiver is ready *now*, then of course we can send.
|
|
80
|
+
//
|
|
81
|
+
// If the receiver isn't ready yet, but we don't have anything
|
|
82
|
+
// in the channel yet, then allow one message.
|
|
83
|
+
self.buffered_once = true;
|
|
84
|
+
true
|
|
85
|
+
} else {
|
|
86
|
+
false
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
pub(crate) fn try_send(&mut self, val: T) -> Result<RetryPromise<T, U>, T> {
|
|
91
|
+
if !self.can_send() {
|
|
92
|
+
return Err(val);
|
|
93
|
+
}
|
|
94
|
+
let (tx, rx) = oneshot::channel();
|
|
95
|
+
self.inner
|
|
96
|
+
.send(Envelope(Some((val, Callback(Some(tx))))))
|
|
97
|
+
.map(move |_| rx)
|
|
98
|
+
.map_err(|mut e| (e.0).0.take().expect("envelope not dropped").0)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
pub(crate) fn unbound(self) -> UnboundedSender<T, U> {
|
|
102
|
+
UnboundedSender {
|
|
103
|
+
giver: self.giver.shared(),
|
|
104
|
+
inner: self.inner,
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
impl<T, U> UnboundedSender<T, U> {
|
|
110
|
+
pub(crate) fn is_ready(&self) -> bool {
|
|
111
|
+
!self.giver.is_canceled()
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
pub(crate) fn is_closed(&self) -> bool {
|
|
115
|
+
self.giver.is_canceled()
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
pub(crate) fn try_send(&mut self, val: T) -> Result<RetryPromise<T, U>, T> {
|
|
119
|
+
let (tx, rx) = oneshot::channel();
|
|
120
|
+
self.inner
|
|
121
|
+
.send(Envelope(Some((val, Callback(Some(tx))))))
|
|
122
|
+
.map(move |_| rx)
|
|
123
|
+
.map_err(|mut e| (e.0).0.take().expect("envelope not dropped").0)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
impl<T, U> Clone for UnboundedSender<T, U> {
|
|
128
|
+
fn clone(&self) -> Self {
|
|
129
|
+
UnboundedSender {
|
|
130
|
+
giver: self.giver.clone(),
|
|
131
|
+
inner: self.inner.clone(),
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
pub(crate) struct Receiver<T, U> {
|
|
137
|
+
inner: mpsc::UnboundedReceiver<Envelope<T, U>>,
|
|
138
|
+
taker: want::Taker,
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
impl<T, U> Receiver<T, U> {
|
|
142
|
+
pub(crate) fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<(T, Callback<T, U>)>> {
|
|
143
|
+
match self.inner.poll_recv(cx) {
|
|
144
|
+
Poll::Ready(item) => {
|
|
145
|
+
Poll::Ready(item.map(|mut env| env.0.take().expect("envelope not dropped")))
|
|
146
|
+
}
|
|
147
|
+
Poll::Pending => {
|
|
148
|
+
self.taker.want();
|
|
149
|
+
Poll::Pending
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
pub(crate) fn close(&mut self) {
|
|
155
|
+
self.taker.cancel();
|
|
156
|
+
self.inner.close();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
pub(crate) fn try_recv(&mut self) -> Option<(T, Callback<T, U>)> {
|
|
160
|
+
use futures_util::FutureExt;
|
|
161
|
+
match self.inner.recv().now_or_never() {
|
|
162
|
+
Some(Some(mut env)) => env.0.take(),
|
|
163
|
+
_ => None,
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
impl<T, U> Drop for Receiver<T, U> {
|
|
169
|
+
fn drop(&mut self) {
|
|
170
|
+
// Notify the giver about the closure first, before dropping
|
|
171
|
+
// the mpsc::Receiver.
|
|
172
|
+
self.taker.cancel();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
struct Envelope<T, U>(Option<(T, Callback<T, U>)>);
|
|
177
|
+
|
|
178
|
+
impl<T, U> Drop for Envelope<T, U> {
|
|
179
|
+
fn drop(&mut self) {
|
|
180
|
+
if let Some((val, cb)) = self.0.take() {
|
|
181
|
+
cb.send(Err(TrySendError {
|
|
182
|
+
error: Error::new_canceled().with("connection closed"),
|
|
183
|
+
message: Some(val),
|
|
184
|
+
}));
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
pub(crate) struct Callback<T, U>(Option<oneshot::Sender<Result<U, TrySendError<T>>>>);
|
|
190
|
+
|
|
191
|
+
impl<T, U> Drop for Callback<T, U> {
|
|
192
|
+
fn drop(&mut self) {
|
|
193
|
+
if let Some(tx) = self.0.take() {
|
|
194
|
+
let _ = tx.send(Err(TrySendError {
|
|
195
|
+
error: dispatch_gone(),
|
|
196
|
+
message: None,
|
|
197
|
+
}));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
#[cold]
|
|
203
|
+
fn dispatch_gone() -> Error {
|
|
204
|
+
// FIXME(nox): What errors do we want here?
|
|
205
|
+
Error::new_user_dispatch_gone().with(if std::thread::panicking() {
|
|
206
|
+
"user code panicked"
|
|
207
|
+
} else {
|
|
208
|
+
"runtime dropped the dispatch task"
|
|
209
|
+
})
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
impl<T, U> Callback<T, U> {
|
|
213
|
+
pub(crate) fn is_canceled(&self) -> bool {
|
|
214
|
+
if let Some(ref tx) = self.0 {
|
|
215
|
+
return tx.is_closed();
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
unreachable!()
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
pub(crate) fn poll_canceled(&mut self, cx: &mut Context<'_>) -> Poll<()> {
|
|
222
|
+
if let Some(ref mut tx) = self.0 {
|
|
223
|
+
return tx.poll_closed(cx);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
unreachable!()
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
pub(crate) fn send(mut self, val: Result<U, TrySendError<T>>) {
|
|
230
|
+
let _ = self.0.take().unwrap().send(val);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
impl<T> TrySendError<T> {
|
|
235
|
+
/// Take the message from this error.
|
|
236
|
+
///
|
|
237
|
+
/// The message will not always have been recovered. If an error occurs
|
|
238
|
+
/// after the message has been serialized onto the connection, it will not
|
|
239
|
+
/// be available here.
|
|
240
|
+
pub fn take_message(&mut self) -> Option<T> {
|
|
241
|
+
self.message.take()
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/// Consumes this to return the inner error.
|
|
245
|
+
pub fn into_error(self) -> Error {
|
|
246
|
+
self.error
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
pin_project! {
|
|
251
|
+
pub struct SendWhen<B>
|
|
252
|
+
where
|
|
253
|
+
B: Body,
|
|
254
|
+
B: 'static,
|
|
255
|
+
{
|
|
256
|
+
#[pin]
|
|
257
|
+
pub(crate) when: ResponseFutMap<B>,
|
|
258
|
+
#[pin]
|
|
259
|
+
pub(crate) call_back: Option<Callback<Request<B>, Response<Incoming>>>,
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
impl<B> Future for SendWhen<B>
|
|
264
|
+
where
|
|
265
|
+
B: Body + 'static,
|
|
266
|
+
B::Data: Send,
|
|
267
|
+
{
|
|
268
|
+
type Output = ();
|
|
269
|
+
|
|
270
|
+
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
271
|
+
let mut this = self.project();
|
|
272
|
+
|
|
273
|
+
let mut call_back = this.call_back.take().expect("polled after complete");
|
|
274
|
+
|
|
275
|
+
match Pin::new(&mut this.when).poll(cx) {
|
|
276
|
+
Poll::Ready(Ok(res)) => {
|
|
277
|
+
call_back.send(Ok(res));
|
|
278
|
+
Poll::Ready(())
|
|
279
|
+
}
|
|
280
|
+
Poll::Pending => {
|
|
281
|
+
// check if the callback is canceled
|
|
282
|
+
match call_back.poll_canceled(cx) {
|
|
283
|
+
Poll::Ready(v) => v,
|
|
284
|
+
Poll::Pending => {
|
|
285
|
+
// Move call_back back to struct before return
|
|
286
|
+
this.call_back.set(Some(call_back));
|
|
287
|
+
return Poll::Pending;
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
trace!("send_when canceled");
|
|
291
|
+
Poll::Ready(())
|
|
292
|
+
}
|
|
293
|
+
Poll::Ready(Err((error, message))) => {
|
|
294
|
+
call_back.send(Err(TrySendError { error, message }));
|
|
295
|
+
Poll::Ready(())
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|