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,149 @@
|
|
|
1
|
+
use super::AsyncConnWithInfo;
|
|
2
|
+
|
|
3
|
+
/// Controls whether to enable verbose tracing for connections.
|
|
4
|
+
///
|
|
5
|
+
/// When enabled (with the `tracing` feature), connections are wrapped to log I/O operations for
|
|
6
|
+
/// debugging.
|
|
7
|
+
#[derive(Clone, Copy)]
|
|
8
|
+
pub struct Verbose(pub(super) bool);
|
|
9
|
+
|
|
10
|
+
impl Verbose {
|
|
11
|
+
pub const OFF: Verbose = Verbose(false);
|
|
12
|
+
|
|
13
|
+
#[cfg_attr(not(feature = "tracing"), inline(always))]
|
|
14
|
+
pub(super) fn wrap<T>(&self, conn: T) -> Box<dyn AsyncConnWithInfo>
|
|
15
|
+
where
|
|
16
|
+
T: AsyncConnWithInfo + 'static,
|
|
17
|
+
{
|
|
18
|
+
#[cfg(feature = "tracing")]
|
|
19
|
+
if self.0 {
|
|
20
|
+
return Box::new(sealed::Wrapper {
|
|
21
|
+
id: crate::util::fast_random(),
|
|
22
|
+
inner: conn,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
Box::new(conn)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#[cfg(feature = "tracing")]
|
|
31
|
+
mod sealed {
|
|
32
|
+
use std::{
|
|
33
|
+
fmt,
|
|
34
|
+
io::{self, IoSlice},
|
|
35
|
+
pin::Pin,
|
|
36
|
+
task::{Context, Poll},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
|
|
40
|
+
|
|
41
|
+
use super::super::{Connected, Connection, TlsInfoFactory};
|
|
42
|
+
use crate::{tls::TlsInfo, util::Escape};
|
|
43
|
+
|
|
44
|
+
pub(super) struct Wrapper<T> {
|
|
45
|
+
pub(super) id: u64,
|
|
46
|
+
pub(super) inner: T,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
impl<T: Connection + AsyncRead + AsyncWrite + Unpin> Connection for Wrapper<T> {
|
|
50
|
+
#[inline]
|
|
51
|
+
fn connected(&self) -> Connected {
|
|
52
|
+
self.inner.connected()
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
impl<T: AsyncRead + AsyncWrite + Unpin> AsyncRead for Wrapper<T> {
|
|
57
|
+
fn poll_read(
|
|
58
|
+
mut self: Pin<&mut Self>,
|
|
59
|
+
cx: &mut Context,
|
|
60
|
+
buf: &mut ReadBuf<'_>,
|
|
61
|
+
) -> Poll<std::io::Result<()>> {
|
|
62
|
+
match Pin::new(&mut self.inner).poll_read(cx, buf) {
|
|
63
|
+
Poll::Ready(Ok(())) => {
|
|
64
|
+
trace!("{:08x} read: {:?}", self.id, Escape::new(buf.filled()));
|
|
65
|
+
Poll::Ready(Ok(()))
|
|
66
|
+
}
|
|
67
|
+
Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
|
|
68
|
+
Poll::Pending => Poll::Pending,
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
impl<T: AsyncRead + AsyncWrite + Unpin> AsyncWrite for Wrapper<T> {
|
|
74
|
+
fn poll_write(
|
|
75
|
+
mut self: Pin<&mut Self>,
|
|
76
|
+
cx: &mut Context,
|
|
77
|
+
buf: &[u8],
|
|
78
|
+
) -> Poll<io::Result<usize>> {
|
|
79
|
+
match Pin::new(&mut self.inner).poll_write(cx, buf) {
|
|
80
|
+
Poll::Ready(Ok(n)) => {
|
|
81
|
+
trace!("{:08x} write: {:?}", self.id, Escape::new(&buf[..n]));
|
|
82
|
+
Poll::Ready(Ok(n))
|
|
83
|
+
}
|
|
84
|
+
Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
|
|
85
|
+
Poll::Pending => Poll::Pending,
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
fn poll_write_vectored(
|
|
90
|
+
mut self: Pin<&mut Self>,
|
|
91
|
+
cx: &mut Context<'_>,
|
|
92
|
+
bufs: &[IoSlice<'_>],
|
|
93
|
+
) -> Poll<io::Result<usize>> {
|
|
94
|
+
match Pin::new(&mut self.inner).poll_write_vectored(cx, bufs) {
|
|
95
|
+
Poll::Ready(Ok(nwritten)) => {
|
|
96
|
+
trace!(
|
|
97
|
+
"{:08x} write (vectored): {:?}",
|
|
98
|
+
self.id,
|
|
99
|
+
Vectored { bufs, nwritten }
|
|
100
|
+
);
|
|
101
|
+
Poll::Ready(Ok(nwritten))
|
|
102
|
+
}
|
|
103
|
+
Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
|
|
104
|
+
Poll::Pending => Poll::Pending,
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
#[inline]
|
|
109
|
+
fn is_write_vectored(&self) -> bool {
|
|
110
|
+
self.inner.is_write_vectored()
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
#[inline]
|
|
114
|
+
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
|
|
115
|
+
Pin::new(&mut self.inner).poll_flush(cx)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
#[inline]
|
|
119
|
+
fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
|
|
120
|
+
Pin::new(&mut self.inner).poll_shutdown(cx)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
impl<T: TlsInfoFactory> TlsInfoFactory for Wrapper<T> {
|
|
125
|
+
fn tls_info(&self) -> Option<TlsInfo> {
|
|
126
|
+
self.inner.tls_info()
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
struct Vectored<'a, 'b> {
|
|
131
|
+
bufs: &'a [IoSlice<'b>],
|
|
132
|
+
nwritten: usize,
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
impl fmt::Debug for Vectored<'_, '_> {
|
|
136
|
+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
137
|
+
let mut left = self.nwritten;
|
|
138
|
+
for buf in self.bufs.iter() {
|
|
139
|
+
if left == 0 {
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
let n = std::cmp::min(left, buf.len());
|
|
143
|
+
Escape::new(&buf[..n]).fmt(f)?;
|
|
144
|
+
left -= n;
|
|
145
|
+
}
|
|
146
|
+
Ok(())
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
#[allow(clippy::module_inception)]
|
|
2
|
+
mod conn;
|
|
3
|
+
mod connector;
|
|
4
|
+
mod http;
|
|
5
|
+
mod proxy;
|
|
6
|
+
mod tls_info;
|
|
7
|
+
#[cfg(unix)]
|
|
8
|
+
mod uds;
|
|
9
|
+
mod verbose;
|
|
10
|
+
|
|
11
|
+
use std::{
|
|
12
|
+
fmt::{self, Debug, Formatter},
|
|
13
|
+
sync::{
|
|
14
|
+
Arc,
|
|
15
|
+
atomic::{AtomicBool, Ordering},
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
use ::http::{Extensions, HeaderMap, HeaderValue};
|
|
20
|
+
use tokio::io::{AsyncRead, AsyncWrite};
|
|
21
|
+
use tower::{
|
|
22
|
+
BoxError,
|
|
23
|
+
util::{BoxCloneSyncService, BoxCloneSyncServiceLayer},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
#[cfg(feature = "socks")]
|
|
27
|
+
pub(super) use self::proxy::socks;
|
|
28
|
+
pub(super) use self::{
|
|
29
|
+
conn::Conn,
|
|
30
|
+
connector::Connector,
|
|
31
|
+
http::{HttpInfo, TcpConnectOptions},
|
|
32
|
+
proxy::tunnel,
|
|
33
|
+
tls_info::TlsInfoFactory,
|
|
34
|
+
};
|
|
35
|
+
use crate::{client::ConnectRequest, dns::DynResolver, proxy::matcher::Intercept};
|
|
36
|
+
|
|
37
|
+
/// HTTP connector with dynamic DNS resolver.
|
|
38
|
+
pub type HttpConnector = self::http::HttpConnector<DynResolver>;
|
|
39
|
+
|
|
40
|
+
/// Boxed connector service for establishing connections.
|
|
41
|
+
pub type BoxedConnectorService = BoxCloneSyncService<Unnameable, Conn, BoxError>;
|
|
42
|
+
|
|
43
|
+
/// Boxed layer for building a boxed connector service.
|
|
44
|
+
pub type BoxedConnectorLayer =
|
|
45
|
+
BoxCloneSyncServiceLayer<BoxedConnectorService, Unnameable, Conn, BoxError>;
|
|
46
|
+
|
|
47
|
+
/// A wrapper type for [`ConnectRequest`] used to erase its concrete type.
|
|
48
|
+
///
|
|
49
|
+
/// [`Unnameable`] allows passing connection requests through trait objects or
|
|
50
|
+
/// type-erased interfaces where the concrete type of the request is not important.
|
|
51
|
+
/// This is mainly used internally to simplify service composition and dynamic dispatch.
|
|
52
|
+
pub struct Unnameable(pub(super) ConnectRequest);
|
|
53
|
+
|
|
54
|
+
/// A trait alias for types that can be used as async connections.
|
|
55
|
+
///
|
|
56
|
+
/// This trait is automatically implemented for any type that satisfies the required bounds:
|
|
57
|
+
/// - [`AsyncRead`] + [`AsyncWrite`]: For I/O operations
|
|
58
|
+
/// - [`Connection`]: For connection metadata
|
|
59
|
+
/// - [`Send`] + [`Sync`] + [`Unpin`] + `'static`: For async/await compatibility
|
|
60
|
+
trait AsyncConn: AsyncRead + AsyncWrite + Connection + Send + Sync + Unpin + 'static {}
|
|
61
|
+
|
|
62
|
+
/// An async connection that can also provide TLS information.
|
|
63
|
+
///
|
|
64
|
+
/// This extends [`AsyncConn`] with the ability to extract TLS certificate information
|
|
65
|
+
/// when available. Useful for connections that may be either plain TCP or TLS-encrypted.
|
|
66
|
+
trait AsyncConnWithInfo: AsyncConn + TlsInfoFactory {}
|
|
67
|
+
|
|
68
|
+
impl<T> AsyncConn for T where T: AsyncRead + AsyncWrite + Connection + Send + Sync + Unpin + 'static {}
|
|
69
|
+
|
|
70
|
+
impl<T> AsyncConnWithInfo for T where T: AsyncConn + TlsInfoFactory {}
|
|
71
|
+
|
|
72
|
+
/// Describes a type returned by a connector.
|
|
73
|
+
pub trait Connection {
|
|
74
|
+
/// Return metadata describing the connection.
|
|
75
|
+
fn connected(&self) -> Connected;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/// Indicates the negotiated ALPN protocol.
|
|
79
|
+
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
80
|
+
enum Alpn {
|
|
81
|
+
H2,
|
|
82
|
+
None,
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/// A pill that can be poisoned to indicate that a connection should not be reused.
|
|
86
|
+
#[derive(Clone)]
|
|
87
|
+
struct PoisonPill {
|
|
88
|
+
poisoned: Arc<AtomicBool>,
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/// A boxed asynchronous connection with associated information.
|
|
92
|
+
#[derive(Debug)]
|
|
93
|
+
struct Extra(Box<dyn ExtraInner>);
|
|
94
|
+
|
|
95
|
+
/// Inner trait for extra connection information.
|
|
96
|
+
trait ExtraInner: Send + Sync + Debug {
|
|
97
|
+
fn clone_box(&self) -> Box<dyn ExtraInner>;
|
|
98
|
+
fn set(&self, res: &mut Extensions);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// This indirection allows the `Connected` to have a type-erased "extra" value,
|
|
102
|
+
// while that type still knows its inner extra type. This allows the correct
|
|
103
|
+
// TypeId to be used when inserting into `res.extensions_mut()`.
|
|
104
|
+
#[derive(Debug, Clone)]
|
|
105
|
+
struct ExtraEnvelope<T>(T);
|
|
106
|
+
|
|
107
|
+
/// Chains two `ExtraInner` implementations together, inserting both into
|
|
108
|
+
/// the extensions.
|
|
109
|
+
#[derive(Debug)]
|
|
110
|
+
struct ExtraChain<T>(Box<dyn ExtraInner>, T);
|
|
111
|
+
|
|
112
|
+
/// Information about an HTTP proxy identity.
|
|
113
|
+
#[derive(Debug, Default, Clone)]
|
|
114
|
+
struct ProxyIdentity {
|
|
115
|
+
is_proxied: bool,
|
|
116
|
+
auth: Option<HeaderValue>,
|
|
117
|
+
headers: Option<HeaderMap>,
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/// Extra information about the connected transport.
|
|
121
|
+
///
|
|
122
|
+
/// This can be used to inform recipients about things like if ALPN
|
|
123
|
+
/// was used, or if connected to an HTTP proxy.
|
|
124
|
+
#[derive(Debug)]
|
|
125
|
+
pub struct Connected {
|
|
126
|
+
alpn: Alpn,
|
|
127
|
+
proxy: Box<ProxyIdentity>,
|
|
128
|
+
extra: Option<Extra>,
|
|
129
|
+
poisoned: PoisonPill,
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ===== impl PoisonPill =====
|
|
133
|
+
|
|
134
|
+
impl fmt::Debug for PoisonPill {
|
|
135
|
+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
136
|
+
// print the address of the pill—this makes debugging issues much easier
|
|
137
|
+
write!(
|
|
138
|
+
f,
|
|
139
|
+
"PoisonPill@{:p} {{ poisoned: {} }}",
|
|
140
|
+
self.poisoned,
|
|
141
|
+
self.poisoned.load(Ordering::Relaxed)
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
impl PoisonPill {
|
|
147
|
+
/// Create a healthy (not poisoned) pill.
|
|
148
|
+
#[inline]
|
|
149
|
+
fn healthy() -> Self {
|
|
150
|
+
Self {
|
|
151
|
+
poisoned: Arc::new(AtomicBool::new(false)),
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/// Poison this pill.
|
|
156
|
+
#[inline]
|
|
157
|
+
fn poison(&self) {
|
|
158
|
+
self.poisoned.store(true, Ordering::Relaxed)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/// Check if this pill is poisoned.
|
|
162
|
+
#[inline]
|
|
163
|
+
fn poisoned(&self) -> bool {
|
|
164
|
+
self.poisoned.load(Ordering::Relaxed)
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// ===== impl Connected =====
|
|
169
|
+
|
|
170
|
+
impl Connected {
|
|
171
|
+
/// Create new `Connected` type with empty metadata.
|
|
172
|
+
pub fn new() -> Connected {
|
|
173
|
+
Connected {
|
|
174
|
+
alpn: Alpn::None,
|
|
175
|
+
proxy: Box::new(ProxyIdentity::default()),
|
|
176
|
+
extra: None,
|
|
177
|
+
poisoned: PoisonPill::healthy(),
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/// Set extra connection information to be set in the extensions of every `Response`.
|
|
182
|
+
pub fn extra<T: Clone + Send + Sync + Debug + 'static>(mut self, extra: T) -> Connected {
|
|
183
|
+
if let Some(prev) = self.extra {
|
|
184
|
+
self.extra = Some(Extra(Box::new(ExtraChain(prev.0, extra))));
|
|
185
|
+
} else {
|
|
186
|
+
self.extra = Some(Extra(Box::new(ExtraEnvelope(extra))));
|
|
187
|
+
}
|
|
188
|
+
self
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/// Copies the extra connection information into an `Extensions` map.
|
|
192
|
+
pub fn set_extras(&self, extensions: &mut Extensions) {
|
|
193
|
+
if let Some(extra) = &self.extra {
|
|
194
|
+
extra.set(extensions);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/// Set that the proxy was used for this connected transport.
|
|
199
|
+
pub fn proxy(mut self, proxy: Intercept) -> Connected {
|
|
200
|
+
self.proxy.is_proxied = true;
|
|
201
|
+
|
|
202
|
+
if let Some(auth) = proxy.basic_auth() {
|
|
203
|
+
self.proxy.auth.replace(auth.clone());
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if let Some(headers) = proxy.custom_headers() {
|
|
207
|
+
self.proxy.headers.replace(headers.clone());
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
self
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/// Determines if the connected transport is to an HTTP proxy.
|
|
214
|
+
#[inline]
|
|
215
|
+
pub fn is_proxied(&self) -> bool {
|
|
216
|
+
self.proxy.is_proxied
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/// Get the proxy identity information for the connected transport.
|
|
220
|
+
#[inline]
|
|
221
|
+
pub fn proxy_auth(&self) -> Option<&HeaderValue> {
|
|
222
|
+
self.proxy.auth.as_ref()
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/// Get the custom proxy headers for the connected transport.
|
|
226
|
+
#[inline]
|
|
227
|
+
pub fn proxy_headers(&self) -> Option<&HeaderMap> {
|
|
228
|
+
self.proxy.headers.as_ref()
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/// Set that the connected transport negotiated HTTP/2 as its next protocol.
|
|
232
|
+
#[inline]
|
|
233
|
+
pub fn negotiated_h2(mut self) -> Connected {
|
|
234
|
+
self.alpn = Alpn::H2;
|
|
235
|
+
self
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/// Determines if the connected transport negotiated HTTP/2 as its next protocol.
|
|
239
|
+
#[inline]
|
|
240
|
+
pub fn is_negotiated_h2(&self) -> bool {
|
|
241
|
+
self.alpn == Alpn::H2
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/// Determine if this connection is poisoned
|
|
245
|
+
#[inline]
|
|
246
|
+
pub fn poisoned(&self) -> bool {
|
|
247
|
+
self.poisoned.poisoned()
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/// Poison this connection
|
|
251
|
+
///
|
|
252
|
+
/// A poisoned connection will not be reused for subsequent requests by the pool
|
|
253
|
+
#[inline]
|
|
254
|
+
pub fn poison(&self) {
|
|
255
|
+
self.poisoned.poison();
|
|
256
|
+
debug!(
|
|
257
|
+
"connection was poisoned. this connection will not be reused for subsequent requests"
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Don't public expose that `Connected` is `Clone`, unsure if we want to
|
|
262
|
+
// keep that contract...
|
|
263
|
+
pub(crate) fn clone(&self) -> Connected {
|
|
264
|
+
Connected {
|
|
265
|
+
alpn: self.alpn,
|
|
266
|
+
proxy: self.proxy.clone(),
|
|
267
|
+
extra: self.extra.clone(),
|
|
268
|
+
poisoned: self.poisoned.clone(),
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// ===== impl Extra =====
|
|
274
|
+
|
|
275
|
+
impl Extra {
|
|
276
|
+
#[inline]
|
|
277
|
+
fn set(&self, res: &mut Extensions) {
|
|
278
|
+
self.0.set(res);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
impl Clone for Extra {
|
|
283
|
+
fn clone(&self) -> Extra {
|
|
284
|
+
Extra(self.0.clone_box())
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// ===== impl ExtraEnvelope =====
|
|
289
|
+
|
|
290
|
+
impl<T> ExtraInner for ExtraEnvelope<T>
|
|
291
|
+
where
|
|
292
|
+
T: Clone + Send + Sync + Debug + 'static,
|
|
293
|
+
{
|
|
294
|
+
fn clone_box(&self) -> Box<dyn ExtraInner> {
|
|
295
|
+
Box::new(self.clone())
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
fn set(&self, res: &mut Extensions) {
|
|
299
|
+
res.insert(self.0.clone());
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// ===== impl ExtraChain =====
|
|
304
|
+
|
|
305
|
+
impl<T: Clone> Clone for ExtraChain<T> {
|
|
306
|
+
fn clone(&self) -> Self {
|
|
307
|
+
ExtraChain(self.0.clone_box(), self.1.clone())
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
impl<T> ExtraInner for ExtraChain<T>
|
|
312
|
+
where
|
|
313
|
+
T: Clone + Send + Sync + Debug + 'static,
|
|
314
|
+
{
|
|
315
|
+
fn clone_box(&self) -> Box<dyn ExtraInner> {
|
|
316
|
+
Box::new(self.clone())
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
fn set(&self, res: &mut Extensions) {
|
|
320
|
+
self.0.set(res);
|
|
321
|
+
res.insert(self.1.clone());
|
|
322
|
+
}
|
|
323
|
+
}
|