Upgrade async-tungstenite to tokio (#26193)

We're seeing panics caused by a buggy implementation of AsyncWrite
that is being passed to rustls: 

https://github.com/rustls/rustls/issues/2316#issuecomment-2662838186

One hypothesis was that we're using (comparatively) non-standard async
tools for connecting over websockets; so this attempts to make us be
(comparitvely) more standard.

Release Notes:

- N/A
This commit is contained in:
Conrad Irwin 2025-04-08 09:17:08 -06:00 committed by GitHub
parent ea33d78ae4
commit ca4cc4764b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 84 additions and 140 deletions

80
Cargo.lock generated
View File

@ -913,18 +913,6 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "async-native-tls"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9343dc5acf07e79ff82d0c37899f079db3534d99f189a1837c8e549c99405bec"
dependencies = [
"futures-util",
"native-tls",
"thiserror 1.0.69",
"url",
]
[[package]]
name = "async-net"
version = "2.0.0"
@ -1094,18 +1082,6 @@ version = "4.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
[[package]]
name = "async-tls"
version = "0.13.0"
source = "git+https://github.com/zed-industries/async-tls?rev=1e759a4b5e370f87dc15e40756ac4f8815b61d9d#1e759a4b5e370f87dc15e40756ac4f8815b61d9d"
dependencies = [
"futures-core",
"futures-io",
"rustls 0.23.25",
"rustls-pemfile 2.2.0",
"webpki-roots",
]
[[package]]
name = "async-trait"
version = "0.1.88"
@ -1119,12 +1095,10 @@ dependencies = [
[[package]]
name = "async-tungstenite"
version = "0.28.2"
version = "0.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c348fb0b6d132c596eca3dcd941df48fb597aafcb07a738ec41c004b087dc99"
checksum = "ef0f7efedeac57d9b26170f72965ecfd31473ca52ca7a64e925b0b6f5f079886"
dependencies = [
"async-std",
"async-tls",
"atomic-waker",
"futures-core",
"futures-io",
@ -1132,7 +1106,10 @@ dependencies = [
"futures-util",
"log",
"pin-project-lite",
"tungstenite 0.24.0",
"rustls-pki-types",
"tokio",
"tokio-rustls 0.26.2",
"tungstenite 0.26.2",
]
[[package]]
@ -2838,7 +2815,6 @@ name = "client"
version = "0.1.0"
dependencies = [
"anyhow",
"async-native-tls",
"async-recursion 0.3.2",
"async-tungstenite",
"chrono",
@ -2849,6 +2825,7 @@ dependencies = [
"feature_flags",
"futures 0.3.31",
"gpui",
"gpui_tokio",
"http_client",
"http_client_tls",
"log",
@ -2870,6 +2847,7 @@ dependencies = [
"thiserror 2.0.12",
"time",
"tiny_http",
"tokio",
"tokio-socks",
"url",
"util",
@ -7452,8 +7430,7 @@ dependencies = [
[[package]]
name = "jupyter-protocol"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9ae6296f9476658b3550293c113996daf75fa542cd8d078abb4c60207bded14"
source = "git+https://github.com/ConradIrwin/runtimed?rev=7130c804216b6914355d15d0b91ea91f6babd734#7130c804216b6914355d15d0b91ea91f6babd734"
dependencies = [
"anyhow",
"async-trait",
@ -7468,8 +7445,7 @@ dependencies = [
[[package]]
name = "jupyter-websocket-client"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49c1ba895c5271ff8dcae51c347fd3588905ba0025a57e20955fd231fe1228cc"
source = "git+https://github.com/ConradIrwin/runtimed?rev=7130c804216b6914355d15d0b91ea91f6babd734#7130c804216b6914355d15d0b91ea91f6babd734"
dependencies = [
"anyhow",
"async-trait",
@ -8776,8 +8752,7 @@ dependencies = [
[[package]]
name = "nbformat"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "244c1673f02b4d5f3c51b6f8ed28d57182cb166a50a6dbf651a3d53e23dc81c0"
source = "git+https://github.com/ConradIrwin/runtimed?rev=7130c804216b6914355d15d0b91ea91f6babd734#7130c804216b6914355d15d0b91ea91f6babd734"
dependencies = [
"anyhow",
"chrono",
@ -9556,15 +9531,6 @@ version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
[[package]]
name = "openssl-src"
version = "300.4.2+3.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "168ce4e058f975fe43e89d9ccf78ca668601887ae736090aacc23ae353c298e2"
dependencies = [
"cc",
]
[[package]]
name = "openssl-sys"
version = "0.9.107"
@ -9573,7 +9539,6 @@ checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07"
dependencies = [
"cc",
"libc",
"openssl-src",
"pkg-config",
"vcpkg",
]
@ -12102,8 +12067,7 @@ dependencies = [
[[package]]
name = "runtimelib"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9af6ed9fd10d7ee940676945510c197c2a472806bb652096a713985c44ffd643"
source = "git+https://github.com/ConradIrwin/runtimed?rev=7130c804216b6914355d15d0b91ea91f6babd734#7130c804216b6914355d15d0b91ea91f6babd734"
dependencies = [
"anyhow",
"async-dispatcher",
@ -15330,24 +15294,6 @@ dependencies = [
"utf-8",
]
[[package]]
name = "tungstenite"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a"
dependencies = [
"byteorder",
"bytes 1.10.1",
"data-encoding",
"http 1.3.1",
"httparse",
"log",
"rand 0.8.5",
"sha1",
"thiserror 1.0.69",
"utf-8",
]
[[package]]
name = "tungstenite"
version = "0.26.2"
@ -17711,7 +17657,6 @@ dependencies = [
"scopeguard",
"sea-orm",
"sea-query-binder",
"security-framework 2.11.1",
"security-framework 3.2.0",
"security-framework-sys",
"semver",
@ -17742,6 +17687,7 @@ dependencies = [
"toml_edit",
"tracing",
"tracing-core",
"tungstenite 0.26.2",
"unicode-properties",
"url",
"uuid",

View File

@ -396,7 +396,7 @@ async-pipe = { git = "https://github.com/zed-industries/async-pipe-rs", rev = "8
async-recursion = "1.0.0"
async-tar = "0.5.0"
async-trait = "0.1"
async-tungstenite = "0.28"
async-tungstenite = "0.29.1"
async-watch = "0.3.1"
async_zip = { version = "0.0.17", features = ["deflate", "deflate64"] }
aws-config = { version = "1.6.1", features = ["behavior-version-latest"] }
@ -453,8 +453,8 @@ indoc = "2"
inventory = "0.3.19"
itertools = "0.14.0"
jsonwebtoken = "9.3"
jupyter-protocol = { version = "0.6.0" }
jupyter-websocket-client = { version = "0.9.0" }
jupyter-protocol = { git = "https://github.com/ConradIrwin/runtimed", rev = "7130c804216b6914355d15d0b91ea91f6babd734" }
jupyter-websocket-client = { git = "https://github.com/ConradIrwin/runtimed" ,rev = "7130c804216b6914355d15d0b91ea91f6babd734" }
libc = "0.2"
libsqlite3-sys = { version = "0.30.1", features = ["bundled"] }
linkify = "0.10.0"
@ -463,7 +463,7 @@ log = { version = "0.4.16", features = ["kv_unstable_serde", "serde"] }
markup5ever_rcdom = "0.3.0"
mlua = { version = "0.10", features = ["lua54", "vendored", "async", "send"] }
nanoid = "0.4"
nbformat = { version = "0.10.0" }
nbformat = { git = "https://github.com/ConradIrwin/runtimed", rev = "7130c804216b6914355d15d0b91ea91f6babd734" }
nix = "0.29"
objc = "0.2"
open = "5.0.0"
@ -501,7 +501,7 @@ reqwest = { git = "https://github.com/zed-industries/reqwest.git", rev = "fd110f
"stream",
] }
rsa = "0.9.6"
runtimelib = { version = "0.25.0", default-features = false, features = [
runtimelib = { git = "https://github.com/ConradIrwin/runtimed", rev = "7130c804216b6914355d15d0b91ea91f6babd734", default-features = false, features = [
"async-dispatcher-runtime",
] }
rustc-demangle = "0.1.23"
@ -661,7 +661,6 @@ features = [
# TODO livekit https://github.com/RustAudio/cpal/pull/891
[patch.crates-io]
cpal = { git = "https://github.com/zed-industries/cpal", rev = "fd8bc2fd39f1f5fdee5a0690656caff9a26d9d50" }
real-async-tls = { git = "https://github.com/zed-industries/async-tls", rev = "1e759a4b5e370f87dc15e40756ac4f8815b61d9d", package = "async-tls" }
notify = { git = "https://github.com/zed-industries/notify.git", rev = "bbb9ea5ae52b253e095737847e367c30653a2e96" }
notify-types = { git = "https://github.com/zed-industries/notify.git", rev = "bbb9ea5ae52b253e095737847e367c30653a2e96" }

View File

@ -18,7 +18,7 @@ test-support = ["clock/test-support", "collections/test-support", "gpui/test-sup
[dependencies]
anyhow.workspace = true
async-recursion = "0.3"
async-tungstenite = { workspace = true, features = ["async-std", "async-tls"] }
async-tungstenite = { workspace = true, features = ["tokio", "tokio-rustls-manual-roots"] }
chrono = { workspace = true, features = ["serde"] }
clock.workspace = true
collections.workspace = true
@ -26,6 +26,7 @@ credentials_provider.workspace = true
feature_flags.workspace = true
futures.workspace = true
gpui.workspace = true
gpui_tokio.workspace = true
http_client.workspace = true
http_client_tls.workspace = true
log.workspace = true
@ -51,6 +52,7 @@ url.workspace = true
util.workspace = true
worktree.workspace = true
telemetry.workspace = true
tokio.workspace = true
workspace-hack.workspace = true
[dev-dependencies]
@ -67,4 +69,3 @@ windows.workspace = true
[target.'cfg(target_os = "macos")'.dependencies]
cocoa.workspace = true
async-native-tls = { version = "0.5.0", features = ["vendored"] }

View File

@ -20,7 +20,7 @@ use futures::{
AsyncReadExt, FutureExt, SinkExt, Stream, StreamExt, TryFutureExt as _, TryStreamExt,
channel::oneshot, future::BoxFuture,
};
use gpui::{App, AppContext as _, AsyncApp, Entity, Global, Task, WeakEntity, actions};
use gpui::{App, AsyncApp, Entity, Global, Task, WeakEntity, actions};
use http_client::{AsyncBody, HttpClient, HttpClientWithUrl};
use parking_lot::RwLock;
use postage::watch;
@ -1086,7 +1086,7 @@ impl Client {
let rpc_url = self.rpc_url(http, release_channel);
let system_id = self.telemetry.system_id();
let metrics_id = self.telemetry.metrics_id();
cx.background_spawn(async move {
cx.spawn(async move |cx| {
use HttpOrHttps::*;
#[derive(Debug)]
@ -1105,7 +1105,12 @@ impl Client {
.host_str()
.zip(rpc_url.port_or_known_default())
.ok_or_else(|| anyhow!("missing host in rpc url"))?;
let stream = connect_socks_proxy_stream(proxy.as_ref(), rpc_host).await?;
let stream = {
let handle = cx.update(|cx| gpui_tokio::Tokio::handle(cx)).ok().unwrap();
let _guard = handle.enter();
connect_socks_proxy_stream(proxy.as_ref(), rpc_host).await?
};
log::info!("connected to rpc endpoint {}", rpc_url);
@ -1144,30 +1149,19 @@ impl Client {
request_headers.insert("x-zed-metrics-id", HeaderValue::from_str(&metrics_id)?);
}
match url_scheme {
Https => {
let (stream, _) =
async_tungstenite::async_tls::client_async_tls_with_connector(
request,
stream,
Some(http_client_tls::tls_config().into()),
)
.await?;
Ok(Connection::new(
stream
.map_err(|error| anyhow!(error))
.sink_map_err(|error| anyhow!(error)),
))
}
Http => {
let (stream, _) = async_tungstenite::client_async(request, stream).await?;
Ok(Connection::new(
stream
.map_err(|error| anyhow!(error))
.sink_map_err(|error| anyhow!(error)),
))
}
}
let (stream, _) = async_tungstenite::tokio::client_async_tls_with_connector_and_config(
request,
stream,
Some(Arc::new(http_client_tls::tls_config()).into()),
None,
)
.await?;
Ok(Connection::new(
stream
.map_err(|error| anyhow!(error))
.sink_map_err(|error| anyhow!(error)),
))
})
}
@ -1639,7 +1633,7 @@ mod tests {
use crate::test::FakeServer;
use clock::FakeSystemClock;
use gpui::{BackgroundExecutor, TestAppContext};
use gpui::{AppContext as _, BackgroundExecutor, TestAppContext};
use http_client::FakeHttpClient;
use parking_lot::Mutex;
use proto::TypedEnvelope;

View File

@ -1,11 +1,7 @@
//! socks proxy
use anyhow::{Result, anyhow};
use futures::io::{AsyncRead, AsyncWrite};
use http_client::Uri;
use tokio_socks::{
io::Compat,
tcp::{Socks4Stream, Socks5Stream},
};
use tokio_socks::tcp::{Socks4Stream, Socks5Stream};
pub(crate) async fn connect_socks_proxy_stream(
proxy: Option<&Uri>,
@ -14,7 +10,7 @@ pub(crate) async fn connect_socks_proxy_stream(
let stream = match parse_socks_proxy(proxy) {
Some((socks_proxy, SocksVersion::V4)) => {
let stream = Socks4Stream::connect_with_socket(
Compat::new(smol::net::TcpStream::connect(socks_proxy).await?),
tokio::net::TcpStream::connect(socks_proxy).await?,
rpc_host,
)
.await
@ -23,13 +19,15 @@ pub(crate) async fn connect_socks_proxy_stream(
}
Some((socks_proxy, SocksVersion::V5)) => Box::new(
Socks5Stream::connect_with_socket(
Compat::new(smol::net::TcpStream::connect(socks_proxy).await?),
tokio::net::TcpStream::connect(socks_proxy).await?,
rpc_host,
)
.await
.map_err(|err| anyhow!("error connecting to socks {}", err))?,
) as Box<dyn AsyncReadWrite>,
None => Box::new(smol::net::TcpStream::connect(rpc_host).await?) as Box<dyn AsyncReadWrite>,
None => {
Box::new(tokio::net::TcpStream::connect(rpc_host).await?) as Box<dyn AsyncReadWrite>
}
};
Ok(stream)
}
@ -60,5 +58,11 @@ enum SocksVersion {
V5,
}
pub(crate) trait AsyncReadWrite: AsyncRead + AsyncWrite + Unpin + Send + 'static {}
impl<T: AsyncRead + AsyncWrite + Unpin + Send + 'static> AsyncReadWrite for T {}
pub(crate) trait AsyncReadWrite:
tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send + 'static
{
}
impl<T: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send + 'static> AsyncReadWrite
for T
{
}

View File

@ -4153,13 +4153,13 @@ async fn get_llm_api_token(
fn to_axum_message(message: TungsteniteMessage) -> anyhow::Result<AxumMessage> {
let message = match message {
TungsteniteMessage::Text(payload) => AxumMessage::Text(payload),
TungsteniteMessage::Binary(payload) => AxumMessage::Binary(payload),
TungsteniteMessage::Ping(payload) => AxumMessage::Ping(payload),
TungsteniteMessage::Pong(payload) => AxumMessage::Pong(payload),
TungsteniteMessage::Text(payload) => AxumMessage::Text(payload.as_str().to_string()),
TungsteniteMessage::Binary(payload) => AxumMessage::Binary(payload.into()),
TungsteniteMessage::Ping(payload) => AxumMessage::Ping(payload.into()),
TungsteniteMessage::Pong(payload) => AxumMessage::Pong(payload.into()),
TungsteniteMessage::Close(frame) => AxumMessage::Close(frame.map(|frame| AxumCloseFrame {
code: frame.code.into(),
reason: frame.reason,
reason: frame.reason.as_str().to_owned().into(),
})),
// We should never receive a frame while reading the message, according
// to the `tungstenite` maintainers:
@ -4179,14 +4179,14 @@ fn to_axum_message(message: TungsteniteMessage) -> anyhow::Result<AxumMessage> {
fn to_tungstenite_message(message: AxumMessage) -> TungsteniteMessage {
match message {
AxumMessage::Text(payload) => TungsteniteMessage::Text(payload),
AxumMessage::Binary(payload) => TungsteniteMessage::Binary(payload),
AxumMessage::Ping(payload) => TungsteniteMessage::Ping(payload),
AxumMessage::Pong(payload) => TungsteniteMessage::Pong(payload),
AxumMessage::Text(payload) => TungsteniteMessage::Text(payload.into()),
AxumMessage::Binary(payload) => TungsteniteMessage::Binary(payload.into()),
AxumMessage::Ping(payload) => TungsteniteMessage::Ping(payload.into()),
AxumMessage::Pong(payload) => TungsteniteMessage::Pong(payload.into()),
AxumMessage::Close(frame) => {
TungsteniteMessage::Close(frame.map(|frame| TungsteniteCloseFrame {
code: frame.code.into(),
reason: frame.reason,
reason: frame.reason.as_ref().into(),
}))
}
}

View File

@ -16,7 +16,7 @@ doctest = false
alacritty_terminal.workspace = true
anyhow.workspace = true
async-dispatcher.workspace = true
async-tungstenite = { workspace = true, features = ["async-std", "async-tls"] }
async-tungstenite = { workspace = true, features = ["tokio", "tokio-rustls-manual-roots"] }
base64.workspace = true
client.workspace = true
collections.workspace = true

View File

@ -3,10 +3,8 @@ use gpui::{App, AppContext as _, Entity, Task, Window};
use http_client::{AsyncBody, HttpClient, Request};
use jupyter_protocol::{ExecutionState, JupyterKernelspec, JupyterMessage, KernelInfoReply};
use async_tungstenite::{
async_std::connect_async,
tungstenite::{client::IntoClientRequest, http::HeaderValue},
};
use async_tungstenite::tokio::connect_async;
use async_tungstenite::tungstenite::{client::IntoClientRequest, http::HeaderValue};
use futures::StreamExt;
use smol::io::AsyncReadExt as _;

View File

@ -8,6 +8,7 @@ use futures::{SinkExt as _, StreamExt as _};
use proto::Message as _;
use std::time::Instant;
use std::{fmt::Debug, io};
use zstd::zstd_safe::WriteBuf;
const KIB: usize = 1024;
const MIB: usize = KIB * 1024;
@ -59,7 +60,9 @@ where
self.encoding_buffer.clear();
self.encoding_buffer.shrink_to(MAX_BUFFER_LEN);
self.stream.send(WebSocketMessage::Binary(buffer)).await?;
self.stream
.send(WebSocketMessage::Binary(buffer.into()))
.await?;
}
Message::Ping => {
self.stream

View File

@ -1030,7 +1030,7 @@ mod tests {
let _ = messages_ended_rx.await;
assert!(
server_conn
.send(WebSocketMessage::Binary(vec![]))
.send(WebSocketMessage::Binary(vec![].into()))
.await
.is_err()
);

View File

@ -1,5 +1,6 @@
# This file is generated by `cargo hakari`.
# To regenerate, run:
# cargo install cargo-hakari
# cargo hakari generate
[package]
@ -19,7 +20,7 @@ anstream = { version = "0.6" }
arrayvec = { version = "0.7", features = ["serde"] }
async-compression = { version = "0.4", default-features = false, features = ["deflate", "deflate64", "futures-io", "gzip"] }
async-std = { version = "1", features = ["attributes", "unstable"] }
async-tungstenite = { version = "0.28", features = ["async-std-runtime", "async-tls"] }
async-tungstenite = { version = "0.29", features = ["tokio-rustls-manual-roots"] }
aws-config = { version = "1", features = ["behavior-version-latest"] }
aws-credential-types = { version = "1", default-features = false, features = ["hardcoded-credentials", "test-util"] }
aws-runtime = { version = "1", default-features = false, features = ["event-stream", "http-02x", "sigv4a"] }
@ -112,6 +113,7 @@ tokio-rustls = { version = "0.26", default-features = false, features = ["tls12"
tokio-util = { version = "0.7", features = ["codec", "compat", "io"] }
tracing = { version = "0.1", features = ["log"] }
tracing-core = { version = "0.1" }
tungstenite = { version = "0.26", default-features = false, features = ["__rustls-tls", "handshake"] }
unicode-properties = { version = "0.1" }
url = { version = "2", features = ["serde"] }
uuid = { version = "1", features = ["serde", "v4", "v5", "v7"] }
@ -127,7 +129,7 @@ anstream = { version = "0.6" }
arrayvec = { version = "0.7", features = ["serde"] }
async-compression = { version = "0.4", default-features = false, features = ["deflate", "deflate64", "futures-io", "gzip"] }
async-std = { version = "1", features = ["attributes", "unstable"] }
async-tungstenite = { version = "0.28", features = ["async-std-runtime", "async-tls"] }
async-tungstenite = { version = "0.29", features = ["tokio-rustls-manual-roots"] }
aws-config = { version = "1", features = ["behavior-version-latest"] }
aws-credential-types = { version = "1", default-features = false, features = ["hardcoded-credentials", "test-util"] }
aws-runtime = { version = "1", default-features = false, features = ["event-stream", "http-02x", "sigv4a"] }
@ -231,6 +233,7 @@ tokio-rustls = { version = "0.26", default-features = false, features = ["tls12"
tokio-util = { version = "0.7", features = ["codec", "compat", "io"] }
tracing = { version = "0.1", features = ["log"] }
tracing-core = { version = "0.1" }
tungstenite = { version = "0.26", default-features = false, features = ["__rustls-tls", "handshake"] }
unicode-properties = { version = "0.1" }
url = { version = "2", features = ["serde"] }
uuid = { version = "1", features = ["serde", "v4", "v5", "v7"] }
@ -257,8 +260,7 @@ ring = { version = "0.17", features = ["std"] }
rustix-d585fab2519d2d1 = { package = "rustix", version = "0.38", default-features = false, features = ["event", "mm", "param", "pipe", "process", "procfs", "termios", "time"] }
rustix-dff4ba8e3ae991db = { package = "rustix", version = "1", features = ["fs", "termios", "time"] }
scopeguard = { version = "1" }
security-framework-7b89eefb6aaa9bf3 = { package = "security-framework", version = "3", features = ["OSX_10_14"] }
security-framework-f595c2ba2a3f28df = { package = "security-framework", version = "2", features = ["alpn"] }
security-framework = { version = "3", features = ["OSX_10_14"] }
security-framework-sys = { version = "2", features = ["OSX_10_14"] }
tokio-rustls = { version = "0.26", default-features = false, features = ["ring"] }
tokio-socks = { version = "0.5", features = ["futures-io"] }
@ -283,8 +285,7 @@ ring = { version = "0.17", features = ["std"] }
rustix-d585fab2519d2d1 = { package = "rustix", version = "0.38", default-features = false, features = ["event", "mm", "param", "pipe", "process", "procfs", "termios", "time"] }
rustix-dff4ba8e3ae991db = { package = "rustix", version = "1", features = ["fs", "termios", "time"] }
scopeguard = { version = "1" }
security-framework-7b89eefb6aaa9bf3 = { package = "security-framework", version = "3", features = ["OSX_10_14"] }
security-framework-f595c2ba2a3f28df = { package = "security-framework", version = "2", features = ["alpn"] }
security-framework = { version = "3", features = ["OSX_10_14"] }
security-framework-sys = { version = "2", features = ["OSX_10_14"] }
tokio-rustls = { version = "0.26", default-features = false, features = ["ring"] }
tokio-socks = { version = "0.5", features = ["futures-io"] }
@ -307,8 +308,7 @@ ring = { version = "0.17", features = ["std"] }
rustix-d585fab2519d2d1 = { package = "rustix", version = "0.38", default-features = false, features = ["event", "mm", "param", "pipe", "process", "procfs", "termios", "time"] }
rustix-dff4ba8e3ae991db = { package = "rustix", version = "1", features = ["fs", "termios", "time"] }
scopeguard = { version = "1" }
security-framework-7b89eefb6aaa9bf3 = { package = "security-framework", version = "3", features = ["OSX_10_14"] }
security-framework-f595c2ba2a3f28df = { package = "security-framework", version = "2", features = ["alpn"] }
security-framework = { version = "3", features = ["OSX_10_14"] }
security-framework-sys = { version = "2", features = ["OSX_10_14"] }
tokio-rustls = { version = "0.26", default-features = false, features = ["ring"] }
tokio-socks = { version = "0.5", features = ["futures-io"] }
@ -333,8 +333,7 @@ ring = { version = "0.17", features = ["std"] }
rustix-d585fab2519d2d1 = { package = "rustix", version = "0.38", default-features = false, features = ["event", "mm", "param", "pipe", "process", "procfs", "termios", "time"] }
rustix-dff4ba8e3ae991db = { package = "rustix", version = "1", features = ["fs", "termios", "time"] }
scopeguard = { version = "1" }
security-framework-7b89eefb6aaa9bf3 = { package = "security-framework", version = "3", features = ["OSX_10_14"] }
security-framework-f595c2ba2a3f28df = { package = "security-framework", version = "2", features = ["alpn"] }
security-framework = { version = "3", features = ["OSX_10_14"] }
security-framework-sys = { version = "2", features = ["OSX_10_14"] }
tokio-rustls = { version = "0.26", default-features = false, features = ["ring"] }
tokio-socks = { version = "0.5", features = ["futures-io"] }