From 192ab40bc476d3a5ce0198ffe9e747aa66a6115c Mon Sep 17 00:00:00 2001 From: Matt Mastracci Date: Fri, 15 Sep 2023 12:42:56 -0600 Subject: [PATCH 1/5] feat(ext/websocket): use rustls-tokio-stream --- Cargo.lock | 14 +++++++- Cargo.toml | 1 + cli/tests/testdata/run/websocket_test.ts | 2 +- cli/tests/unit/websocket_test.ts | 46 +++++++++++++++++++++++- ext/websocket/Cargo.toml | 3 +- ext/websocket/lib.rs | 18 ++++++---- 6 files changed, 74 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d5c1f5558b0733..70dee366fbc4ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1761,9 +1761,10 @@ dependencies = [ "http", "hyper 0.14.27", "once_cell", + "rustls", + "rustls-tokio-stream", "serde", "tokio", - "tokio-rustls", ] [[package]] @@ -4481,6 +4482,17 @@ dependencies = [ "base64 0.21.4", ] +[[package]] +name = "rustls-tokio-stream" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52577dfff2fb2daea75dbb6da12dea45f13954fb093b450bfafb2856725eb464" +dependencies = [ + "futures", + "rustls", + "tokio", +] + [[package]] name = "rustls-webpki" version = "0.101.7" diff --git a/Cargo.toml b/Cargo.toml index e859641dd9624e..da5299cb0b16a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -124,6 +124,7 @@ ring = "^0.17.0" rusqlite = { version = "=0.29.0", features = ["unlock_notify", "bundled"] } rustls = "0.21.8" rustls-pemfile = "1.0.0" +rustls-tokio-stream = "0.2.3" rustls-webpki = "0.101.4" rustls-native-certs = "0.6.2" webpki-roots = "0.25.2" diff --git a/cli/tests/testdata/run/websocket_test.ts b/cli/tests/testdata/run/websocket_test.ts index d80f03c92aa126..43db15cceeb1d5 100644 --- a/cli/tests/testdata/run/websocket_test.ts +++ b/cli/tests/testdata/run/websocket_test.ts @@ -163,7 +163,7 @@ Deno.test("websocket error", async () => { // Error message got changed because we don't use warp in test_util assertEquals( err.message, - "InvalidData: received corrupt message of type InvalidContentType", + "InvalidData: invalid data", ); promise1.resolve(); }; diff --git a/cli/tests/unit/websocket_test.ts b/cli/tests/unit/websocket_test.ts index b761cd118338c1..dae82fe3eff92e 100644 --- a/cli/tests/unit/websocket_test.ts +++ b/cli/tests/unit/websocket_test.ts @@ -35,7 +35,7 @@ Deno.test(async function websocketSendLargePacket() { assertEquals(ws.url, "wss://localhost:4243/"); ws.onerror = (e) => promise.reject(e); ws.onopen = () => { - ws.send("a".repeat(65000)); + ws.send("a".repeat(65000)); }; ws.onmessage = () => { ws.close(); @@ -277,3 +277,47 @@ Deno.test( } }, ); + +Deno.test(async function websocketTlsSocketWorks() { + const cert = await Deno.readTextFile("cli/tests/testdata/tls/localhost.crt"); + const key = await Deno.readTextFile("cli/tests/testdata/tls/localhost.key"); + + let messages: any[] = [], errors: any[] = []; + const promise = new Promise((okay, nope) => { + const ac = new AbortController(); + const server = Deno.serve({ + handler: (req) => { + const { response, socket } = Deno.upgradeWebSocket(req); + socket.onopen = () => socket.send('ping'); + socket.onmessage = (e) => { + messages.push(e.data); + socket.close(); + }; + socket.onerror = (e) => errors.push({ server: e }); + socket.onclose = () => ac.abort(); + return response; + }, + signal: ac.signal, + hostname: 'localhost', + port: servePort, + cert, + key, + }); + setTimeout(() => { + const ws = new WebSocket(`wss://localhost:${servePort}`); + ws.onmessage = (e) => { + messages.push(e.data) + ws.send('pong'); + }; + ws.onerror = (e) => errors.push(nope({ client: e })); + ws.onclose = () => okay(server.finished); + }, 1000); + }); + + const finished = await promise; + + assertEquals(errors, []); + assertEquals(messages, ['ping', 'pong']); + + await finished; +}); \ No newline at end of file diff --git a/ext/websocket/Cargo.toml b/ext/websocket/Cargo.toml index 7dd7a9afee1e8b..07d4aa3030b5df 100644 --- a/ext/websocket/Cargo.toml +++ b/ext/websocket/Cargo.toml @@ -22,6 +22,7 @@ fastwebsockets = { workspace = true, features = ["upgrade", "unstable-split"] } http.workspace = true hyper = { workspace = true, features = ["backports"] } once_cell.workspace = true +rustls.workspace = true +rustls-tokio-stream.workspace = true serde.workspace = true tokio.workspace = true -tokio-rustls.workspace = true diff --git a/ext/websocket/lib.rs b/ext/websocket/lib.rs index 0f3456eef22e03..c2b314bc4c6eec 100644 --- a/ext/websocket/lib.rs +++ b/ext/websocket/lib.rs @@ -29,6 +29,9 @@ use http::Request; use http::Uri; use hyper::Body; use once_cell::sync::Lazy; +use rustls::RootCertStore; +use rustls::ServerName; +use rustls_tokio_stream::TlsStream; use serde::Serialize; use std::borrow::Cow; use std::cell::Cell; @@ -36,6 +39,7 @@ use std::cell::RefCell; use std::convert::TryFrom; use std::fmt; use std::future::Future; +use std::num::NonZeroUsize; use std::path::PathBuf; use std::rc::Rc; use std::sync::Arc; @@ -44,9 +48,6 @@ use tokio::io::AsyncWrite; use tokio::io::ReadHalf; use tokio::io::WriteHalf; use tokio::net::TcpStream; -use tokio_rustls::rustls::RootCertStore; -use tokio_rustls::rustls::ServerName; -use tokio_rustls::TlsConnector; use fastwebsockets::CloseCode; use fastwebsockets::FragmentCollectorRead; @@ -284,11 +285,16 @@ where unsafely_ignore_certificate_errors, None, )?; - let tls_connector = TlsConnector::from(Arc::new(tls_config)); let dnsname = ServerName::try_from(domain.as_str()) .map_err(|_| invalid_hostname(domain))?; - let tls_socket = tls_connector.connect(dnsname, tcp_socket).await?; - handshake(cancel_resource, request, tls_socket).await? + let mut tls_connector = TlsStream::new_client_side( + tcp_socket, + tls_config.into(), + dnsname, + NonZeroUsize::new(65536), + ); + let _hs = tls_connector.handshake().await?; + handshake(cancel_resource, request, tls_connector).await? } _ => unreachable!(), }; From 5f4446eaebdb432658266c69e3f65a0b7d25daf0 Mon Sep 17 00:00:00 2001 From: Matt Mastracci Date: Mon, 30 Oct 2023 17:08:32 -0600 Subject: [PATCH 2/5] fmt --- cli/tests/unit/websocket_test.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cli/tests/unit/websocket_test.ts b/cli/tests/unit/websocket_test.ts index dae82fe3eff92e..8760581f921e8c 100644 --- a/cli/tests/unit/websocket_test.ts +++ b/cli/tests/unit/websocket_test.ts @@ -35,7 +35,7 @@ Deno.test(async function websocketSendLargePacket() { assertEquals(ws.url, "wss://localhost:4243/"); ws.onerror = (e) => promise.reject(e); ws.onopen = () => { - ws.send("a".repeat(65000)); + ws.send("a".repeat(65000)); }; ws.onmessage = () => { ws.close(); @@ -288,7 +288,7 @@ Deno.test(async function websocketTlsSocketWorks() { const server = Deno.serve({ handler: (req) => { const { response, socket } = Deno.upgradeWebSocket(req); - socket.onopen = () => socket.send('ping'); + socket.onopen = () => socket.send("ping"); socket.onmessage = (e) => { messages.push(e.data); socket.close(); @@ -298,7 +298,7 @@ Deno.test(async function websocketTlsSocketWorks() { return response; }, signal: ac.signal, - hostname: 'localhost', + hostname: "localhost", port: servePort, cert, key, @@ -306,8 +306,8 @@ Deno.test(async function websocketTlsSocketWorks() { setTimeout(() => { const ws = new WebSocket(`wss://localhost:${servePort}`); ws.onmessage = (e) => { - messages.push(e.data) - ws.send('pong'); + messages.push(e.data); + ws.send("pong"); }; ws.onerror = (e) => errors.push(nope({ client: e })); ws.onclose = () => okay(server.finished); @@ -317,7 +317,7 @@ Deno.test(async function websocketTlsSocketWorks() { const finished = await promise; assertEquals(errors, []); - assertEquals(messages, ['ping', 'pong']); + assertEquals(messages, ["ping", "pong"]); await finished; -}); \ No newline at end of file +}); From ec02e6908ccf4ac402c8e180379bd4b3fbdc1162 Mon Sep 17 00:00:00 2001 From: Matt Mastracci Date: Mon, 30 Oct 2023 17:10:12 -0600 Subject: [PATCH 3/5] fmt --- Cargo.lock | 5 ++--- Cargo.toml | 2 +- ext/websocket/Cargo.toml | 1 - ext/websocket/lib.rs | 4 ++-- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 70dee366fbc4ac..01e453aea48b3c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1761,7 +1761,6 @@ dependencies = [ "http", "hyper 0.14.27", "once_cell", - "rustls", "rustls-tokio-stream", "serde", "tokio", @@ -4484,9 +4483,9 @@ dependencies = [ [[package]] name = "rustls-tokio-stream" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52577dfff2fb2daea75dbb6da12dea45f13954fb093b450bfafb2856725eb464" +checksum = "8101c6e909600a3648a7774cb06837a5f976eb3265736d7135b4c177fa3020b9" dependencies = [ "futures", "rustls", diff --git a/Cargo.toml b/Cargo.toml index da5299cb0b16a0..7982135ed6bba8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -124,7 +124,7 @@ ring = "^0.17.0" rusqlite = { version = "=0.29.0", features = ["unlock_notify", "bundled"] } rustls = "0.21.8" rustls-pemfile = "1.0.0" -rustls-tokio-stream = "0.2.3" +rustls-tokio-stream = "0.2.4" rustls-webpki = "0.101.4" rustls-native-certs = "0.6.2" webpki-roots = "0.25.2" diff --git a/ext/websocket/Cargo.toml b/ext/websocket/Cargo.toml index 07d4aa3030b5df..da29203c496e18 100644 --- a/ext/websocket/Cargo.toml +++ b/ext/websocket/Cargo.toml @@ -22,7 +22,6 @@ fastwebsockets = { workspace = true, features = ["upgrade", "unstable-split"] } http.workspace = true hyper = { workspace = true, features = ["backports"] } once_cell.workspace = true -rustls.workspace = true rustls-tokio-stream.workspace = true serde.workspace = true tokio.workspace = true diff --git a/ext/websocket/lib.rs b/ext/websocket/lib.rs index c2b314bc4c6eec..ac40b8304c0878 100644 --- a/ext/websocket/lib.rs +++ b/ext/websocket/lib.rs @@ -29,8 +29,8 @@ use http::Request; use http::Uri; use hyper::Body; use once_cell::sync::Lazy; -use rustls::RootCertStore; -use rustls::ServerName; +use rustls_tokio_stream::rustls::RootCertStore; +use rustls_tokio_stream::rustls::ServerName; use rustls_tokio_stream::TlsStream; use serde::Serialize; use std::borrow::Cow; From f690bd3bf19adb7cf895877975a8cececc138474 Mon Sep 17 00:00:00 2001 From: Matt Mastracci Date: Mon, 30 Oct 2023 19:46:16 -0600 Subject: [PATCH 4/5] lint --- cli/tests/unit/websocket_test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/tests/unit/websocket_test.ts b/cli/tests/unit/websocket_test.ts index 8760581f921e8c..bba3c0e06eebdb 100644 --- a/cli/tests/unit/websocket_test.ts +++ b/cli/tests/unit/websocket_test.ts @@ -282,7 +282,7 @@ Deno.test(async function websocketTlsSocketWorks() { const cert = await Deno.readTextFile("cli/tests/testdata/tls/localhost.crt"); const key = await Deno.readTextFile("cli/tests/testdata/tls/localhost.key"); - let messages: any[] = [], errors: any[] = []; + const messages = [], errors = []; const promise = new Promise((okay, nope) => { const ac = new AbortController(); const server = Deno.serve({ From 478fef1caf1b2be17dd5b9c4b6111f0f6985f3f3 Mon Sep 17 00:00:00 2001 From: Matt Mastracci Date: Mon, 30 Oct 2023 20:23:31 -0600 Subject: [PATCH 5/5] fix check --- cli/tests/unit/websocket_test.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cli/tests/unit/websocket_test.ts b/cli/tests/unit/websocket_test.ts index bba3c0e06eebdb..8ae729d42b7f90 100644 --- a/cli/tests/unit/websocket_test.ts +++ b/cli/tests/unit/websocket_test.ts @@ -282,7 +282,8 @@ Deno.test(async function websocketTlsSocketWorks() { const cert = await Deno.readTextFile("cli/tests/testdata/tls/localhost.crt"); const key = await Deno.readTextFile("cli/tests/testdata/tls/localhost.key"); - const messages = [], errors = []; + const messages: string[] = [], + errors: { server?: Event; client?: Event }[] = []; const promise = new Promise((okay, nope) => { const ac = new AbortController(); const server = Deno.serve({ @@ -309,7 +310,10 @@ Deno.test(async function websocketTlsSocketWorks() { messages.push(e.data); ws.send("pong"); }; - ws.onerror = (e) => errors.push(nope({ client: e })); + ws.onerror = (e) => { + errors.push({ client: e }); + nope(); + }; ws.onclose = () => okay(server.finished); }, 1000); });