wreq-rb 0.5.0 → 0.5.1
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 +4 -4
- data/Cargo.lock +1922 -397
- data/LICENSE +203 -0
- data/README.md +19 -15
- data/ext/wreq_rb/Cargo.toml +4 -6
- data/ext/wreq_rb/src/client.rs +41 -48
- data/lib/wreq-rb/version.rb +1 -1
- data/patches/0001-add-transfer-size-tracking.patch +76 -67
- data/vendor/wreq/Cargo.toml +119 -71
- data/vendor/wreq/README.md +25 -20
- data/vendor/wreq/bench/http1.rs +25 -0
- data/vendor/wreq/bench/http1_over_tls.rs +25 -0
- data/vendor/wreq/bench/http2.rs +25 -0
- data/vendor/wreq/bench/http2_over_tls.rs +25 -0
- data/vendor/wreq/bench/support/bench.rs +91 -0
- data/vendor/wreq/bench/support/client.rs +217 -0
- data/vendor/wreq/bench/support/server.rs +188 -0
- data/vendor/wreq/bench/support.rs +56 -0
- data/vendor/wreq/examples/cert_store.rs +4 -4
- data/vendor/wreq/examples/{emulation.rs → emulate.rs} +2 -2
- data/vendor/wreq/examples/http2_websocket.rs +2 -2
- data/vendor/wreq/examples/keylog.rs +3 -3
- data/vendor/wreq/examples/{request_with_emulation.rs → request_with_emulate.rs} +2 -2
- data/vendor/wreq/examples/rt.rs +23 -0
- data/vendor/wreq/src/client/body.rs +23 -61
- data/vendor/wreq/src/client/emulate.rs +119 -0
- data/vendor/wreq/src/client/{http/future.rs → future.rs} +11 -32
- data/vendor/wreq/src/client/{http → layer}/client/pool.rs +66 -61
- data/vendor/wreq/src/client/{http → layer}/client.rs +416 -270
- data/vendor/wreq/src/client/layer/config.rs +27 -6
- data/vendor/wreq/src/client/layer/decoder.rs +9 -4
- data/vendor/wreq/src/client/layer/redirect/future.rs +6 -3
- data/vendor/wreq/src/client/layer/redirect.rs +4 -5
- data/vendor/wreq/src/client/layer/retry.rs +8 -5
- data/vendor/wreq/src/client/layer/timeout/body.rs +15 -6
- data/vendor/wreq/src/client/layer/timeout/future.rs +23 -18
- data/vendor/wreq/src/client/layer/timeout.rs +24 -74
- data/vendor/wreq/src/client/layer.rs +1 -2
- data/vendor/wreq/src/client/multipart.rs +137 -154
- data/vendor/wreq/src/client/request.rs +202 -118
- data/vendor/wreq/src/client/response.rs +46 -45
- data/vendor/wreq/src/client/upgrade.rs +15 -0
- data/vendor/wreq/src/client/ws.rs +73 -25
- data/vendor/wreq/src/client.rs +1655 -17
- data/vendor/wreq/src/config.rs +11 -11
- data/vendor/wreq/src/{client/conn → conn}/connector.rs +139 -137
- data/vendor/wreq/src/conn/descriptor.rs +143 -0
- data/vendor/wreq/src/conn/http.rs +484 -0
- data/vendor/wreq/src/conn/net/io.rs +75 -0
- data/vendor/wreq/src/conn/net/tcp/compio.rs +71 -0
- data/vendor/wreq/src/conn/net/tcp/tokio.rs +57 -0
- data/vendor/wreq/src/conn/net/tcp.rs +561 -0
- data/vendor/wreq/src/conn/net/uds/compio.rs +60 -0
- data/vendor/wreq/src/{client/conn/uds.rs → conn/net/uds/tokio.rs} +18 -12
- data/vendor/wreq/src/conn/net/uds.rs +11 -0
- data/vendor/wreq/src/conn/net.rs +130 -0
- data/vendor/wreq/src/{client/conn → conn}/proxy/socks.rs +2 -9
- data/vendor/wreq/src/{client/conn → conn}/proxy/tunnel.rs +21 -56
- data/vendor/wreq/src/conn/tls_info.rs +47 -0
- data/vendor/wreq/src/{client/conn.rs → conn.rs} +202 -54
- data/vendor/wreq/src/cookie.rs +302 -142
- data/vendor/wreq/src/dns/gai/compio.rs +77 -0
- data/vendor/wreq/src/dns/gai/tokio.rs +90 -0
- data/vendor/wreq/src/dns/gai.rs +14 -164
- data/vendor/wreq/src/dns/hickory.rs +16 -23
- data/vendor/wreq/src/dns/resolve.rs +7 -41
- data/vendor/wreq/src/dns.rs +90 -7
- data/vendor/wreq/src/error.rs +57 -31
- data/vendor/wreq/src/ext.rs +25 -0
- data/vendor/wreq/src/group.rs +211 -0
- data/vendor/wreq/src/header.rs +100 -112
- data/vendor/wreq/src/lib.rs +124 -73
- data/vendor/wreq/src/proxy.rs +6 -20
- data/vendor/wreq/src/redirect.rs +1 -1
- data/vendor/wreq/src/rt.rs +208 -0
- data/vendor/wreq/src/sync.rs +97 -98
- data/vendor/wreq/src/tls/compress.rs +124 -0
- data/vendor/wreq/src/tls/conn/ext.rs +54 -45
- data/vendor/wreq/src/tls/conn/service.rs +14 -18
- data/vendor/wreq/src/tls/conn.rs +169 -241
- data/vendor/wreq/src/tls/keylog.rs +68 -5
- data/vendor/wreq/src/tls/session.rs +205 -0
- data/vendor/wreq/src/tls/{x509 → trust}/identity.rs +4 -21
- data/vendor/wreq/src/tls/{x509/parser.rs → trust/parse.rs} +1 -1
- data/vendor/wreq/src/tls/{x509 → trust}/store.rs +42 -81
- data/vendor/wreq/src/tls/{x509.rs → trust.rs} +8 -2
- data/vendor/wreq/src/tls.rs +489 -25
- data/vendor/wreq/src/trace.rs +0 -12
- data/vendor/wreq/src/util.rs +1 -1
- data/vendor/wreq/tests/badssl.rs +10 -10
- data/vendor/wreq/tests/client.rs +3 -9
- data/vendor/wreq/tests/cookie.rs +6 -8
- data/vendor/wreq/tests/{emulation.rs → emulate.rs} +130 -22
- data/vendor/wreq/tests/multipart.rs +43 -1
- data/vendor/wreq/tests/proxy.rs +1 -1
- data/vendor/wreq/tests/support/layer.rs +1 -0
- metadata +49 -71
- data/patches/0002-add-cancel-connections.patch +0 -181
- data/vendor/wreq/src/client/conn/conn.rs +0 -231
- data/vendor/wreq/src/client/conn/http.rs +0 -1023
- data/vendor/wreq/src/client/conn/tls_info.rs +0 -98
- data/vendor/wreq/src/client/core/body/incoming.rs +0 -485
- data/vendor/wreq/src/client/core/body/length.rs +0 -118
- data/vendor/wreq/src/client/core/body.rs +0 -34
- data/vendor/wreq/src/client/core/common/buf.rs +0 -149
- data/vendor/wreq/src/client/core/common/rewind.rs +0 -141
- data/vendor/wreq/src/client/core/common/watch.rs +0 -76
- data/vendor/wreq/src/client/core/common.rs +0 -3
- data/vendor/wreq/src/client/core/conn/http1.rs +0 -342
- data/vendor/wreq/src/client/core/conn/http2.rs +0 -307
- data/vendor/wreq/src/client/core/conn.rs +0 -11
- data/vendor/wreq/src/client/core/dispatch.rs +0 -299
- data/vendor/wreq/src/client/core/error.rs +0 -435
- data/vendor/wreq/src/client/core/ext.rs +0 -201
- data/vendor/wreq/src/client/core/http1.rs +0 -178
- data/vendor/wreq/src/client/core/http2.rs +0 -483
- data/vendor/wreq/src/client/core/proto/h1/conn.rs +0 -988
- data/vendor/wreq/src/client/core/proto/h1/decode.rs +0 -1170
- data/vendor/wreq/src/client/core/proto/h1/dispatch.rs +0 -684
- data/vendor/wreq/src/client/core/proto/h1/encode.rs +0 -580
- data/vendor/wreq/src/client/core/proto/h1/io.rs +0 -879
- data/vendor/wreq/src/client/core/proto/h1/role.rs +0 -694
- data/vendor/wreq/src/client/core/proto/h1.rs +0 -104
- data/vendor/wreq/src/client/core/proto/h2/client.rs +0 -650
- data/vendor/wreq/src/client/core/proto/h2/ping.rs +0 -539
- data/vendor/wreq/src/client/core/proto/h2.rs +0 -379
- data/vendor/wreq/src/client/core/proto/headers.rs +0 -138
- data/vendor/wreq/src/client/core/proto.rs +0 -58
- data/vendor/wreq/src/client/core/rt/bounds.rs +0 -57
- data/vendor/wreq/src/client/core/rt/timer.rs +0 -150
- data/vendor/wreq/src/client/core/rt/tokio.rs +0 -99
- data/vendor/wreq/src/client/core/rt.rs +0 -25
- data/vendor/wreq/src/client/core/upgrade.rs +0 -267
- data/vendor/wreq/src/client/core.rs +0 -16
- data/vendor/wreq/src/client/emulation.rs +0 -161
- data/vendor/wreq/src/client/http/client/error.rs +0 -142
- data/vendor/wreq/src/client/http/client/exec.rs +0 -29
- data/vendor/wreq/src/client/http/client/extra.rs +0 -77
- data/vendor/wreq/src/client/http/client/util.rs +0 -104
- data/vendor/wreq/src/client/http.rs +0 -1629
- data/vendor/wreq/src/client/layer/config/options.rs +0 -156
- data/vendor/wreq/src/client/layer/cookie.rs +0 -161
- data/vendor/wreq/src/hash.rs +0 -143
- data/vendor/wreq/src/tls/conn/cache.rs +0 -123
- data/vendor/wreq/src/tls/conn/cert_compression.rs +0 -125
- data/vendor/wreq/src/tls/keylog/handle.rs +0 -64
- data/vendor/wreq/src/tls/options.rs +0 -464
- /data/vendor/wreq/src/client/{http → layer}/client/lazy.rs +0 -0
- /data/vendor/wreq/src/{client/conn → conn}/proxy.rs +0 -0
- /data/vendor/wreq/src/{client/conn → conn}/verbose.rs +0 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
//! Compio-based unix socket connector.
|
|
2
|
+
|
|
3
|
+
#![allow(dead_code)]
|
|
4
|
+
|
|
5
|
+
use std::{
|
|
6
|
+
io,
|
|
7
|
+
path::Path,
|
|
8
|
+
sync::Arc,
|
|
9
|
+
task::{Context, Poll},
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
use compio::net::UnixStream;
|
|
13
|
+
use http::Uri;
|
|
14
|
+
use wreq_rt::rt::compio::{future::SendFuture, io::CompioIO};
|
|
15
|
+
|
|
16
|
+
use super::BoxConnecting;
|
|
17
|
+
use crate::conn::{Connected, Connection, net::io::CompioConnection, tls_info::TlsInfoFactory};
|
|
18
|
+
|
|
19
|
+
#[derive(Clone)]
|
|
20
|
+
pub struct UnixConnector(Arc<Path>);
|
|
21
|
+
|
|
22
|
+
impl UnixConnector {
|
|
23
|
+
/// Creates a new [`UnixConnector`] for the specified socket path.
|
|
24
|
+
#[inline]
|
|
25
|
+
pub fn new(path: impl Into<Arc<Path>>) -> Self {
|
|
26
|
+
Self(path.into())
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
impl tower::Service<Uri> for UnixConnector {
|
|
31
|
+
type Response = CompioConnection<UnixStream>;
|
|
32
|
+
type Error = io::Error;
|
|
33
|
+
type Future = BoxConnecting<Self::Response>;
|
|
34
|
+
|
|
35
|
+
#[inline]
|
|
36
|
+
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
37
|
+
Poll::Ready(Ok(()))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
fn call(&mut self, _: Uri) -> Self::Future {
|
|
41
|
+
let fut = UnixStream::connect(self.0.clone());
|
|
42
|
+
Box::pin(SendFuture::new(async move {
|
|
43
|
+
let io = fut.await?;
|
|
44
|
+
Ok(CompioConnection {
|
|
45
|
+
peer_addr: None,
|
|
46
|
+
local_addr: None,
|
|
47
|
+
inner: CompioIO::new(io),
|
|
48
|
+
})
|
|
49
|
+
}))
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
impl Connection for CompioConnection<UnixStream> {
|
|
54
|
+
#[inline]
|
|
55
|
+
fn connected(&self) -> Connected {
|
|
56
|
+
Connected::new()
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
impl TlsInfoFactory for CompioConnection<UnixStream> {}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
//! Tokio-based unix socket connector.
|
|
2
|
+
|
|
1
3
|
use std::{
|
|
2
4
|
io,
|
|
3
5
|
path::Path,
|
|
4
|
-
pin::Pin,
|
|
5
6
|
sync::Arc,
|
|
6
7
|
task::{Context, Poll},
|
|
7
8
|
};
|
|
@@ -9,30 +10,33 @@ use std::{
|
|
|
9
10
|
use http::Uri;
|
|
10
11
|
use tokio::net::UnixStream;
|
|
11
12
|
|
|
12
|
-
use super::
|
|
13
|
-
|
|
14
|
-
type ConnectResult = io::Result<UnixStream>;
|
|
15
|
-
type BoxConnecting = Pin<Box<dyn Future<Output = ConnectResult> + Send>>;
|
|
13
|
+
use super::BoxConnecting;
|
|
14
|
+
use crate::conn::{Connected, Connection, tls_info::TlsInfoFactory};
|
|
16
15
|
|
|
17
16
|
#[derive(Clone)]
|
|
18
|
-
pub struct UnixConnector(
|
|
17
|
+
pub struct UnixConnector(Arc<Path>);
|
|
18
|
+
|
|
19
|
+
impl UnixConnector {
|
|
20
|
+
/// Creates a new [`UnixConnector`] for the specified socket path.
|
|
21
|
+
#[inline]
|
|
22
|
+
pub fn new(path: impl Into<Arc<Path>>) -> Self {
|
|
23
|
+
Self(path.into())
|
|
24
|
+
}
|
|
25
|
+
}
|
|
19
26
|
|
|
20
27
|
impl tower::Service<Uri> for UnixConnector {
|
|
21
28
|
type Response = UnixStream;
|
|
22
29
|
type Error = io::Error;
|
|
23
|
-
type Future = BoxConnecting
|
|
30
|
+
type Future = BoxConnecting<Self::Response>;
|
|
24
31
|
|
|
25
32
|
#[inline]
|
|
26
33
|
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
27
34
|
Poll::Ready(Ok(()))
|
|
28
35
|
}
|
|
29
36
|
|
|
37
|
+
#[inline]
|
|
30
38
|
fn call(&mut self, _: Uri) -> Self::Future {
|
|
31
|
-
|
|
32
|
-
Box::pin(async move {
|
|
33
|
-
let io = fut.await?;
|
|
34
|
-
Ok::<_, io::Error>(io)
|
|
35
|
-
})
|
|
39
|
+
Box::pin(UnixStream::connect(self.0.clone()))
|
|
36
40
|
}
|
|
37
41
|
}
|
|
38
42
|
|
|
@@ -42,3 +46,5 @@ impl Connection for UnixStream {
|
|
|
42
46
|
Connected::new()
|
|
43
47
|
}
|
|
44
48
|
}
|
|
49
|
+
|
|
50
|
+
impl TlsInfoFactory for UnixStream {}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//! Unix Domain Socket (UDS) connection types and utilities.
|
|
2
|
+
|
|
3
|
+
#[cfg(all(unix, feature = "tokio-rt"))]
|
|
4
|
+
pub mod tokio;
|
|
5
|
+
|
|
6
|
+
#[cfg(all(unix, feature = "compio-rt"))]
|
|
7
|
+
pub mod compio;
|
|
8
|
+
|
|
9
|
+
use std::{io::Result, pin::Pin};
|
|
10
|
+
|
|
11
|
+
type BoxConnecting<T> = Pin<Box<dyn Future<Output = Result<T>> + Send>>;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
//! Network connection types and utilities.
|
|
2
|
+
|
|
3
|
+
pub(super) mod tcp;
|
|
4
|
+
|
|
5
|
+
if_any_rt!(
|
|
6
|
+
mod io;
|
|
7
|
+
#[cfg(unix)]
|
|
8
|
+
mod uds;
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
if_all_rt! {
|
|
12
|
+
pub use tcp::tokio::TcpConnector;
|
|
13
|
+
#[cfg(unix)]
|
|
14
|
+
pub use uds::tokio::UnixConnector;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if_tokio_rt! {
|
|
18
|
+
pub use tcp::tokio::TcpConnector;
|
|
19
|
+
#[cfg(unix)]
|
|
20
|
+
pub use uds::tokio::UnixConnector;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if_compio_rt! {
|
|
24
|
+
pub use tcp::compio::TcpConnector;
|
|
25
|
+
#[cfg(unix)]
|
|
26
|
+
pub use uds::compio::UnixConnector;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
|
30
|
+
|
|
31
|
+
/// Options for configuring socket bind behavior for outbound connections.
|
|
32
|
+
#[derive(Debug, Clone, Hash, PartialEq, Eq, Default)]
|
|
33
|
+
pub(crate) struct SocketBindOptions {
|
|
34
|
+
#[cfg(any(
|
|
35
|
+
target_os = "illumos",
|
|
36
|
+
target_os = "ios",
|
|
37
|
+
target_os = "macos",
|
|
38
|
+
target_os = "solaris",
|
|
39
|
+
target_os = "tvos",
|
|
40
|
+
target_os = "visionos",
|
|
41
|
+
target_os = "watchos",
|
|
42
|
+
target_os = "android",
|
|
43
|
+
target_os = "fuchsia",
|
|
44
|
+
target_os = "linux",
|
|
45
|
+
))]
|
|
46
|
+
pub interface: Option<std::borrow::Cow<'static, str>>,
|
|
47
|
+
pub ipv4_address: Option<Ipv4Addr>,
|
|
48
|
+
pub ipv6_address: Option<Ipv6Addr>,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
impl SocketBindOptions {
|
|
52
|
+
/// Sets the name of the network interface to bind the socket to.
|
|
53
|
+
///
|
|
54
|
+
/// ## Platform behavior
|
|
55
|
+
/// - On Linux/Fuchsia/Android: sets `SO_BINDTODEVICE`
|
|
56
|
+
/// - On macOS/illumos/Solaris/iOS/etc.: sets `IP_BOUND_IF`
|
|
57
|
+
///
|
|
58
|
+
/// If `interface` is `None`, the socket will not be explicitly bound to any device.
|
|
59
|
+
///
|
|
60
|
+
/// # Errors
|
|
61
|
+
///
|
|
62
|
+
/// On platforms that require a `CString` (e.g. macOS), this will return an error if the
|
|
63
|
+
/// interface name contains an internal null byte (`\0`), which is invalid in C strings.
|
|
64
|
+
///
|
|
65
|
+
/// # See Also
|
|
66
|
+
/// - [VRF documentation](https://www.kernel.org/doc/Documentation/networking/vrf.txt)
|
|
67
|
+
/// - [`man 7 socket`](https://man7.org/linux/man-pages/man7/socket.7.html)
|
|
68
|
+
/// - [`man 7p ip`](https://docs.oracle.com/cd/E86824_01/html/E54777/ip-7p.html)
|
|
69
|
+
#[cfg(any(
|
|
70
|
+
target_os = "android",
|
|
71
|
+
target_os = "fuchsia",
|
|
72
|
+
target_os = "illumos",
|
|
73
|
+
target_os = "ios",
|
|
74
|
+
target_os = "linux",
|
|
75
|
+
target_os = "macos",
|
|
76
|
+
target_os = "solaris",
|
|
77
|
+
target_os = "tvos",
|
|
78
|
+
target_os = "visionos",
|
|
79
|
+
target_os = "watchos",
|
|
80
|
+
))]
|
|
81
|
+
#[inline]
|
|
82
|
+
pub fn set_interface<I>(&mut self, interface: I) -> &mut Self
|
|
83
|
+
where
|
|
84
|
+
I: Into<std::borrow::Cow<'static, str>>,
|
|
85
|
+
{
|
|
86
|
+
self.interface = Some(interface.into());
|
|
87
|
+
self
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/// Set that all sockets are bound to the configured address before connection.
|
|
91
|
+
///
|
|
92
|
+
/// If `None`, the sockets will not be bound.
|
|
93
|
+
///
|
|
94
|
+
/// Default is `None`.
|
|
95
|
+
#[inline]
|
|
96
|
+
pub fn set_local_address<V>(&mut self, local_address: V)
|
|
97
|
+
where
|
|
98
|
+
V: Into<Option<IpAddr>>,
|
|
99
|
+
{
|
|
100
|
+
match local_address.into() {
|
|
101
|
+
Some(IpAddr::V4(a)) => {
|
|
102
|
+
self.ipv4_address = Some(a);
|
|
103
|
+
}
|
|
104
|
+
Some(IpAddr::V6(a)) => {
|
|
105
|
+
self.ipv6_address = Some(a);
|
|
106
|
+
}
|
|
107
|
+
_ => {}
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/// Set that all sockets are bound to the configured IPv4 or IPv6 address (depending on host's
|
|
112
|
+
/// preferences) before connection.
|
|
113
|
+
///
|
|
114
|
+
/// If `None`, the sockets will not be bound.
|
|
115
|
+
///
|
|
116
|
+
/// Default is `None`.
|
|
117
|
+
#[inline]
|
|
118
|
+
pub fn set_local_addresses<V4, V6>(&mut self, ipv4_address: V4, ipv6_address: V6)
|
|
119
|
+
where
|
|
120
|
+
V4: Into<Option<Ipv4Addr>>,
|
|
121
|
+
V6: Into<Option<Ipv6Addr>>,
|
|
122
|
+
{
|
|
123
|
+
if let Some(addr) = ipv4_address.into() {
|
|
124
|
+
self.ipv4_address = Some(addr);
|
|
125
|
+
}
|
|
126
|
+
if let Some(addr) = ipv6_address.into() {
|
|
127
|
+
self.ipv6_address = Some(addr);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -102,15 +102,8 @@ impl<C, R> SocksConnector<C, R>
|
|
|
102
102
|
where
|
|
103
103
|
R: InternalResolve + Clone,
|
|
104
104
|
{
|
|
105
|
-
/// Create a new
|
|
106
|
-
|
|
107
|
-
/// This wraps an underlying connector, and stores the address of a
|
|
108
|
-
/// SOCKS proxy server.
|
|
109
|
-
///
|
|
110
|
-
/// A `SocksConnector` can then be called with any destination. The `proxy_dst` passed to
|
|
111
|
-
/// `call` will not be used to create the underlying connection, but will
|
|
112
|
-
/// be used in a SOCKS handshake sent to the proxy destination.
|
|
113
|
-
pub fn new_with_resolver(proxy_dst: Uri, inner: C, resolver: R) -> Self {
|
|
105
|
+
/// Create a new [`SocksConnector`].
|
|
106
|
+
pub fn new(proxy_dst: Uri, inner: C, resolver: R) -> Self {
|
|
114
107
|
SocksConnector {
|
|
115
108
|
inner,
|
|
116
109
|
resolver,
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
use std::{
|
|
2
|
-
io,
|
|
3
2
|
marker::{PhantomData, Unpin},
|
|
4
|
-
|
|
5
|
-
task::{self, Poll, ready},
|
|
3
|
+
task::{self, Poll},
|
|
6
4
|
};
|
|
7
5
|
|
|
6
|
+
use bytes::BytesMut;
|
|
8
7
|
use http::{HeaderMap, HeaderValue, Uri};
|
|
9
|
-
use tokio::io::{AsyncRead, AsyncWrite,
|
|
10
|
-
use tower::Service;
|
|
8
|
+
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
|
9
|
+
use tower::{BoxError, Service};
|
|
11
10
|
|
|
12
11
|
use super::Tunneling;
|
|
13
|
-
use crate::
|
|
12
|
+
use crate::ext::UriExt;
|
|
14
13
|
|
|
15
14
|
/// Tunnel Proxy via HTTP CONNECT
|
|
16
15
|
///
|
|
@@ -35,9 +34,9 @@ enum Headers {
|
|
|
35
34
|
pub enum TunnelError {
|
|
36
35
|
ConnectFailed(BoxError),
|
|
37
36
|
Io(std::io::Error),
|
|
37
|
+
Parse(httparse::Error),
|
|
38
38
|
MissingHost,
|
|
39
39
|
ProxyAuthRequired,
|
|
40
|
-
ProxyHeadersTooLong,
|
|
41
40
|
TunnelUnexpectedEof,
|
|
42
41
|
TunnelUnsuccessful,
|
|
43
42
|
}
|
|
@@ -175,64 +174,29 @@ where
|
|
|
175
174
|
// headers end
|
|
176
175
|
buf.extend_from_slice(b"\r\n");
|
|
177
176
|
|
|
178
|
-
write_all(&
|
|
177
|
+
conn.write_all(&buf).await.map_err(TunnelError::Io)?;
|
|
178
|
+
conn.flush().await.map_err(TunnelError::Io)?;
|
|
179
179
|
|
|
180
|
-
let mut buf =
|
|
181
|
-
let mut pos = 0;
|
|
180
|
+
let mut buf = BytesMut::with_capacity(8192);
|
|
182
181
|
|
|
183
182
|
loop {
|
|
184
|
-
|
|
185
|
-
.await
|
|
186
|
-
.map_err(TunnelError::Io)?;
|
|
187
|
-
|
|
188
|
-
if n == 0 {
|
|
183
|
+
if conn.read_buf(&mut buf).await.map_err(TunnelError::Io)? == 0 {
|
|
189
184
|
return Err(TunnelError::TunnelUnexpectedEof);
|
|
190
185
|
}
|
|
191
|
-
pos += n;
|
|
192
186
|
|
|
193
|
-
let
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
return Err(TunnelError::
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
} else if recvd.starts_with(b"HTTP/1.1 407") {
|
|
203
|
-
return Err(TunnelError::ProxyAuthRequired);
|
|
204
|
-
} else {
|
|
205
|
-
return Err(TunnelError::TunnelUnsuccessful);
|
|
187
|
+
let mut headers = [httparse::EMPTY_HEADER; 64];
|
|
188
|
+
let mut res = httparse::Response::new(&mut headers);
|
|
189
|
+
match res.parse(&buf).map_err(TunnelError::Parse)? {
|
|
190
|
+
httparse::Status::Partial => continue,
|
|
191
|
+
httparse::Status::Complete(_) => match res.code {
|
|
192
|
+
Some(200) => return Ok(conn),
|
|
193
|
+
Some(407) => return Err(TunnelError::ProxyAuthRequired),
|
|
194
|
+
Some(_) | None => return Err(TunnelError::TunnelUnsuccessful),
|
|
195
|
+
},
|
|
206
196
|
}
|
|
207
197
|
}
|
|
208
198
|
}
|
|
209
199
|
|
|
210
|
-
async fn read<T>(io: &mut T, buf: &mut [u8]) -> io::Result<usize>
|
|
211
|
-
where
|
|
212
|
-
T: AsyncRead + Unpin,
|
|
213
|
-
{
|
|
214
|
-
std::future::poll_fn(move |cx| {
|
|
215
|
-
let mut buf = ReadBuf::new(buf);
|
|
216
|
-
ready!(Pin::new(&mut *io).poll_read(cx, &mut buf))?;
|
|
217
|
-
Poll::Ready(Ok(buf.filled().len()))
|
|
218
|
-
})
|
|
219
|
-
.await
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
async fn write_all<T>(io: &mut T, buf: &[u8]) -> io::Result<()>
|
|
223
|
-
where
|
|
224
|
-
T: AsyncWrite + Unpin,
|
|
225
|
-
{
|
|
226
|
-
let mut n = 0;
|
|
227
|
-
std::future::poll_fn(move |cx| {
|
|
228
|
-
while n < buf.len() {
|
|
229
|
-
n += ready!(Pin::new(&mut *io).poll_write(cx, &buf[n..])?);
|
|
230
|
-
}
|
|
231
|
-
Poll::Ready(Ok(()))
|
|
232
|
-
})
|
|
233
|
-
.await
|
|
234
|
-
}
|
|
235
|
-
|
|
236
200
|
impl std::fmt::Display for TunnelError {
|
|
237
201
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
238
202
|
f.write_str("tunnel error: ")?;
|
|
@@ -240,7 +204,7 @@ impl std::fmt::Display for TunnelError {
|
|
|
240
204
|
f.write_str(match self {
|
|
241
205
|
TunnelError::MissingHost => "missing destination host",
|
|
242
206
|
TunnelError::ProxyAuthRequired => "proxy authorization required",
|
|
243
|
-
TunnelError::
|
|
207
|
+
TunnelError::Parse(_) => "invalid proxy response",
|
|
244
208
|
TunnelError::TunnelUnexpectedEof => "unexpected end of file",
|
|
245
209
|
TunnelError::TunnelUnsuccessful => "unsuccessful",
|
|
246
210
|
TunnelError::ConnectFailed(_) => "failed to create underlying connection",
|
|
@@ -253,6 +217,7 @@ impl std::error::Error for TunnelError {
|
|
|
253
217
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
|
254
218
|
match self {
|
|
255
219
|
TunnelError::Io(e) => Some(e),
|
|
220
|
+
TunnelError::Parse(e) => Some(e),
|
|
256
221
|
TunnelError::ConnectFailed(e) => Some(&**e),
|
|
257
222
|
_ => None,
|
|
258
223
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
use bytes::Bytes;
|
|
2
|
+
use tokio_btls::SslStream;
|
|
3
|
+
|
|
4
|
+
use crate::tls::{TlsInfo, conn::MaybeHttpsStream};
|
|
5
|
+
|
|
6
|
+
/// A trait for extracting TLS information from a connection.
|
|
7
|
+
pub trait TlsInfoFactory {
|
|
8
|
+
#[inline]
|
|
9
|
+
fn tls_info(&self) -> Option<TlsInfo> {
|
|
10
|
+
None
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
fn extract_tls_info<S>(ssl_stream: &SslStream<S>) -> TlsInfo {
|
|
15
|
+
let ssl = ssl_stream.ssl();
|
|
16
|
+
TlsInfo {
|
|
17
|
+
peer_certificate: ssl
|
|
18
|
+
.peer_certificate()
|
|
19
|
+
.and_then(|cert| cert.to_der().ok())
|
|
20
|
+
.map(Bytes::from),
|
|
21
|
+
peer_certificate_chain: ssl.peer_cert_chain().map(|chain| {
|
|
22
|
+
chain
|
|
23
|
+
.iter()
|
|
24
|
+
.filter_map(|cert| cert.to_der().ok())
|
|
25
|
+
.map(Bytes::from)
|
|
26
|
+
.collect()
|
|
27
|
+
}),
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Generic impl: any SslStream can provide TLS info.
|
|
32
|
+
impl<T> TlsInfoFactory for SslStream<T> {
|
|
33
|
+
#[inline]
|
|
34
|
+
fn tls_info(&self) -> Option<TlsInfo> {
|
|
35
|
+
Some(extract_tls_info(self))
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Generic impl: MaybeHttpsStream delegates to the inner stream.
|
|
40
|
+
impl<T: TlsInfoFactory> TlsInfoFactory for MaybeHttpsStream<T> {
|
|
41
|
+
fn tls_info(&self) -> Option<TlsInfo> {
|
|
42
|
+
match self {
|
|
43
|
+
MaybeHttpsStream::Https(tls) => tls.tls_info(),
|
|
44
|
+
MaybeHttpsStream::Http(_) => None,
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|