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.
Files changed (150) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +1922 -397
  3. data/LICENSE +203 -0
  4. data/README.md +19 -15
  5. data/ext/wreq_rb/Cargo.toml +4 -6
  6. data/ext/wreq_rb/src/client.rs +41 -48
  7. data/lib/wreq-rb/version.rb +1 -1
  8. data/patches/0001-add-transfer-size-tracking.patch +76 -67
  9. data/vendor/wreq/Cargo.toml +119 -71
  10. data/vendor/wreq/README.md +25 -20
  11. data/vendor/wreq/bench/http1.rs +25 -0
  12. data/vendor/wreq/bench/http1_over_tls.rs +25 -0
  13. data/vendor/wreq/bench/http2.rs +25 -0
  14. data/vendor/wreq/bench/http2_over_tls.rs +25 -0
  15. data/vendor/wreq/bench/support/bench.rs +91 -0
  16. data/vendor/wreq/bench/support/client.rs +217 -0
  17. data/vendor/wreq/bench/support/server.rs +188 -0
  18. data/vendor/wreq/bench/support.rs +56 -0
  19. data/vendor/wreq/examples/cert_store.rs +4 -4
  20. data/vendor/wreq/examples/{emulation.rs → emulate.rs} +2 -2
  21. data/vendor/wreq/examples/http2_websocket.rs +2 -2
  22. data/vendor/wreq/examples/keylog.rs +3 -3
  23. data/vendor/wreq/examples/{request_with_emulation.rs → request_with_emulate.rs} +2 -2
  24. data/vendor/wreq/examples/rt.rs +23 -0
  25. data/vendor/wreq/src/client/body.rs +23 -61
  26. data/vendor/wreq/src/client/emulate.rs +119 -0
  27. data/vendor/wreq/src/client/{http/future.rs → future.rs} +11 -32
  28. data/vendor/wreq/src/client/{http → layer}/client/pool.rs +66 -61
  29. data/vendor/wreq/src/client/{http → layer}/client.rs +416 -270
  30. data/vendor/wreq/src/client/layer/config.rs +27 -6
  31. data/vendor/wreq/src/client/layer/decoder.rs +9 -4
  32. data/vendor/wreq/src/client/layer/redirect/future.rs +6 -3
  33. data/vendor/wreq/src/client/layer/redirect.rs +4 -5
  34. data/vendor/wreq/src/client/layer/retry.rs +8 -5
  35. data/vendor/wreq/src/client/layer/timeout/body.rs +15 -6
  36. data/vendor/wreq/src/client/layer/timeout/future.rs +23 -18
  37. data/vendor/wreq/src/client/layer/timeout.rs +24 -74
  38. data/vendor/wreq/src/client/layer.rs +1 -2
  39. data/vendor/wreq/src/client/multipart.rs +137 -154
  40. data/vendor/wreq/src/client/request.rs +202 -118
  41. data/vendor/wreq/src/client/response.rs +46 -45
  42. data/vendor/wreq/src/client/upgrade.rs +15 -0
  43. data/vendor/wreq/src/client/ws.rs +73 -25
  44. data/vendor/wreq/src/client.rs +1655 -17
  45. data/vendor/wreq/src/config.rs +11 -11
  46. data/vendor/wreq/src/{client/conn → conn}/connector.rs +139 -137
  47. data/vendor/wreq/src/conn/descriptor.rs +143 -0
  48. data/vendor/wreq/src/conn/http.rs +484 -0
  49. data/vendor/wreq/src/conn/net/io.rs +75 -0
  50. data/vendor/wreq/src/conn/net/tcp/compio.rs +71 -0
  51. data/vendor/wreq/src/conn/net/tcp/tokio.rs +57 -0
  52. data/vendor/wreq/src/conn/net/tcp.rs +561 -0
  53. data/vendor/wreq/src/conn/net/uds/compio.rs +60 -0
  54. data/vendor/wreq/src/{client/conn/uds.rs → conn/net/uds/tokio.rs} +18 -12
  55. data/vendor/wreq/src/conn/net/uds.rs +11 -0
  56. data/vendor/wreq/src/conn/net.rs +130 -0
  57. data/vendor/wreq/src/{client/conn → conn}/proxy/socks.rs +2 -9
  58. data/vendor/wreq/src/{client/conn → conn}/proxy/tunnel.rs +21 -56
  59. data/vendor/wreq/src/conn/tls_info.rs +47 -0
  60. data/vendor/wreq/src/{client/conn.rs → conn.rs} +202 -54
  61. data/vendor/wreq/src/cookie.rs +302 -142
  62. data/vendor/wreq/src/dns/gai/compio.rs +77 -0
  63. data/vendor/wreq/src/dns/gai/tokio.rs +90 -0
  64. data/vendor/wreq/src/dns/gai.rs +14 -164
  65. data/vendor/wreq/src/dns/hickory.rs +16 -23
  66. data/vendor/wreq/src/dns/resolve.rs +7 -41
  67. data/vendor/wreq/src/dns.rs +90 -7
  68. data/vendor/wreq/src/error.rs +57 -31
  69. data/vendor/wreq/src/ext.rs +25 -0
  70. data/vendor/wreq/src/group.rs +211 -0
  71. data/vendor/wreq/src/header.rs +100 -112
  72. data/vendor/wreq/src/lib.rs +124 -73
  73. data/vendor/wreq/src/proxy.rs +6 -20
  74. data/vendor/wreq/src/redirect.rs +1 -1
  75. data/vendor/wreq/src/rt.rs +208 -0
  76. data/vendor/wreq/src/sync.rs +97 -98
  77. data/vendor/wreq/src/tls/compress.rs +124 -0
  78. data/vendor/wreq/src/tls/conn/ext.rs +54 -45
  79. data/vendor/wreq/src/tls/conn/service.rs +14 -18
  80. data/vendor/wreq/src/tls/conn.rs +169 -241
  81. data/vendor/wreq/src/tls/keylog.rs +68 -5
  82. data/vendor/wreq/src/tls/session.rs +205 -0
  83. data/vendor/wreq/src/tls/{x509 → trust}/identity.rs +4 -21
  84. data/vendor/wreq/src/tls/{x509/parser.rs → trust/parse.rs} +1 -1
  85. data/vendor/wreq/src/tls/{x509 → trust}/store.rs +42 -81
  86. data/vendor/wreq/src/tls/{x509.rs → trust.rs} +8 -2
  87. data/vendor/wreq/src/tls.rs +489 -25
  88. data/vendor/wreq/src/trace.rs +0 -12
  89. data/vendor/wreq/src/util.rs +1 -1
  90. data/vendor/wreq/tests/badssl.rs +10 -10
  91. data/vendor/wreq/tests/client.rs +3 -9
  92. data/vendor/wreq/tests/cookie.rs +6 -8
  93. data/vendor/wreq/tests/{emulation.rs → emulate.rs} +130 -22
  94. data/vendor/wreq/tests/multipart.rs +43 -1
  95. data/vendor/wreq/tests/proxy.rs +1 -1
  96. data/vendor/wreq/tests/support/layer.rs +1 -0
  97. metadata +49 -71
  98. data/patches/0002-add-cancel-connections.patch +0 -181
  99. data/vendor/wreq/src/client/conn/conn.rs +0 -231
  100. data/vendor/wreq/src/client/conn/http.rs +0 -1023
  101. data/vendor/wreq/src/client/conn/tls_info.rs +0 -98
  102. data/vendor/wreq/src/client/core/body/incoming.rs +0 -485
  103. data/vendor/wreq/src/client/core/body/length.rs +0 -118
  104. data/vendor/wreq/src/client/core/body.rs +0 -34
  105. data/vendor/wreq/src/client/core/common/buf.rs +0 -149
  106. data/vendor/wreq/src/client/core/common/rewind.rs +0 -141
  107. data/vendor/wreq/src/client/core/common/watch.rs +0 -76
  108. data/vendor/wreq/src/client/core/common.rs +0 -3
  109. data/vendor/wreq/src/client/core/conn/http1.rs +0 -342
  110. data/vendor/wreq/src/client/core/conn/http2.rs +0 -307
  111. data/vendor/wreq/src/client/core/conn.rs +0 -11
  112. data/vendor/wreq/src/client/core/dispatch.rs +0 -299
  113. data/vendor/wreq/src/client/core/error.rs +0 -435
  114. data/vendor/wreq/src/client/core/ext.rs +0 -201
  115. data/vendor/wreq/src/client/core/http1.rs +0 -178
  116. data/vendor/wreq/src/client/core/http2.rs +0 -483
  117. data/vendor/wreq/src/client/core/proto/h1/conn.rs +0 -988
  118. data/vendor/wreq/src/client/core/proto/h1/decode.rs +0 -1170
  119. data/vendor/wreq/src/client/core/proto/h1/dispatch.rs +0 -684
  120. data/vendor/wreq/src/client/core/proto/h1/encode.rs +0 -580
  121. data/vendor/wreq/src/client/core/proto/h1/io.rs +0 -879
  122. data/vendor/wreq/src/client/core/proto/h1/role.rs +0 -694
  123. data/vendor/wreq/src/client/core/proto/h1.rs +0 -104
  124. data/vendor/wreq/src/client/core/proto/h2/client.rs +0 -650
  125. data/vendor/wreq/src/client/core/proto/h2/ping.rs +0 -539
  126. data/vendor/wreq/src/client/core/proto/h2.rs +0 -379
  127. data/vendor/wreq/src/client/core/proto/headers.rs +0 -138
  128. data/vendor/wreq/src/client/core/proto.rs +0 -58
  129. data/vendor/wreq/src/client/core/rt/bounds.rs +0 -57
  130. data/vendor/wreq/src/client/core/rt/timer.rs +0 -150
  131. data/vendor/wreq/src/client/core/rt/tokio.rs +0 -99
  132. data/vendor/wreq/src/client/core/rt.rs +0 -25
  133. data/vendor/wreq/src/client/core/upgrade.rs +0 -267
  134. data/vendor/wreq/src/client/core.rs +0 -16
  135. data/vendor/wreq/src/client/emulation.rs +0 -161
  136. data/vendor/wreq/src/client/http/client/error.rs +0 -142
  137. data/vendor/wreq/src/client/http/client/exec.rs +0 -29
  138. data/vendor/wreq/src/client/http/client/extra.rs +0 -77
  139. data/vendor/wreq/src/client/http/client/util.rs +0 -104
  140. data/vendor/wreq/src/client/http.rs +0 -1629
  141. data/vendor/wreq/src/client/layer/config/options.rs +0 -156
  142. data/vendor/wreq/src/client/layer/cookie.rs +0 -161
  143. data/vendor/wreq/src/hash.rs +0 -143
  144. data/vendor/wreq/src/tls/conn/cache.rs +0 -123
  145. data/vendor/wreq/src/tls/conn/cert_compression.rs +0 -125
  146. data/vendor/wreq/src/tls/keylog/handle.rs +0 -64
  147. data/vendor/wreq/src/tls/options.rs +0 -464
  148. /data/vendor/wreq/src/client/{http → layer}/client/lazy.rs +0 -0
  149. /data/vendor/wreq/src/{client/conn → conn}/proxy.rs +0 -0
  150. /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::{Connected, Connection};
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(pub(crate) Arc<Path>);
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
- let fut = UnixStream::connect(self.0.clone());
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 SOCKS connector with the given inner service.
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
- pin::Pin,
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, ReadBuf};
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::{error::BoxError, ext::UriExt};
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(&mut conn, &buf).await.map_err(TunnelError::Io)?;
177
+ conn.write_all(&buf).await.map_err(TunnelError::Io)?;
178
+ conn.flush().await.map_err(TunnelError::Io)?;
179
179
 
180
- let mut buf = [0; 8192];
181
- let mut pos = 0;
180
+ let mut buf = BytesMut::with_capacity(8192);
182
181
 
183
182
  loop {
184
- let n = read(&mut conn, &mut buf[pos..])
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 recvd = &buf[..pos];
194
- if recvd.starts_with(b"HTTP/1.1 200") || recvd.starts_with(b"HTTP/1.0 200") {
195
- if recvd.ends_with(b"\r\n\r\n") {
196
- return Ok(conn);
197
- }
198
- if pos == buf.len() {
199
- return Err(TunnelError::ProxyHeadersTooLong);
200
- }
201
- // else read more
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::ProxyHeadersTooLong => "proxy response headers too long",
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
+ }