mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 18:38:55 +00:00
101 lines
4.1 KiB
TypeScript
101 lines
4.1 KiB
TypeScript
import { TCPSocketListener } from "bun";
|
|
import { describe, expect, test } from "bun:test";
|
|
import { WebSocket } from "ws";
|
|
|
|
const hostname = process.env.HOST || "127.0.0.1";
|
|
const port = parseInt(process.env.PORT || "0");
|
|
|
|
describe("WebSocket", () => {
|
|
test("short read on payload length", async () => {
|
|
let server: TCPSocketListener | undefined;
|
|
let client: WebSocket | undefined;
|
|
let init = false;
|
|
|
|
try {
|
|
server = Bun.listen({
|
|
socket: {
|
|
data(socket, data) {
|
|
if (init) {
|
|
return;
|
|
}
|
|
|
|
init = true;
|
|
|
|
const frame = data.toString("utf-8");
|
|
if (!frame.startsWith("GET")) {
|
|
throw new Error("Invalid handshake");
|
|
}
|
|
|
|
const magic = /Sec-WebSocket-Key: (.*)\r\n/.exec(frame);
|
|
if (!magic) {
|
|
throw new Error("Missing Sec-WebSocket-Key");
|
|
}
|
|
|
|
const hasher = new Bun.CryptoHasher("sha1");
|
|
hasher.update(magic[1]);
|
|
hasher.update("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
|
|
const accept = hasher.digest("base64");
|
|
|
|
// Respond with a websocket handshake.
|
|
socket.write(
|
|
"HTTP/1.1 101 Switching Protocols\r\n" +
|
|
"Upgrade: websocket\r\n" +
|
|
"Connection: Upgrade\r\n" +
|
|
`Sec-WebSocket-Accept: ${accept}\r\n` +
|
|
"\r\n",
|
|
);
|
|
socket.flush();
|
|
|
|
// Partially write a websocket text frame with an incomplete big-endian u16 length.
|
|
socket.write(Uint8Array.from([129, 126, 0]));
|
|
socket.flush();
|
|
|
|
// Write the remainder of the websocket text frame.
|
|
setTimeout(() => {
|
|
socket.write(
|
|
Uint8Array.from([
|
|
253, 123, 34, 106, 115, 111, 110, 114, 112, 99, 34, 58, 34, 50, 46, 48, 34, 44, 34, 109, 101, 116,
|
|
104, 111, 100, 34, 58, 34, 116, 114, 97, 110, 115, 97, 99, 116, 105, 111, 110, 78, 111, 116, 105, 102,
|
|
105, 99, 97, 116, 105, 111, 110, 34, 44, 34, 112, 97, 114, 97, 109, 115, 34, 58, 123, 34, 114, 101,
|
|
115, 117, 108, 116, 34, 58, 123, 34, 99, 111, 110, 116, 101, 120, 116, 34, 58, 123, 34, 115, 108, 111,
|
|
116, 34, 58, 50, 52, 57, 54, 48, 50, 49, 55, 57, 125, 44, 34, 118, 97, 108, 117, 101, 34, 58, 123, 34,
|
|
115, 105, 103, 110, 97, 116, 117, 114, 101, 34, 58, 34, 50, 80, 50, 120, 102, 51, 109, 85, 49, 118,
|
|
114, 110, 89, 99, 100, 49, 76, 105, 99, 104, 56, 69, 76, 104, 104, 88, 120, 55, 50, 111, 67, 105, 110,
|
|
77, 97, 81, 88, 101, 113, 106, 118, 68, 55, 111, 52, 101, 75, 77, 53, 70, 66, 51, 78, 76, 97, 104, 86,
|
|
55, 68, 87, 101, 81, 106, 105, 102, 98, 107, 53, 56, 75, 121, 104, 66, 119, 98, 119, 88, 49, 104, 103,
|
|
119, 103, 112, 112, 102, 118, 77, 71, 34, 44, 34, 115, 108, 111, 116, 34, 58, 50, 52, 57, 54, 48, 50,
|
|
49, 55, 57, 125, 125, 44, 34, 115, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 58, 52,
|
|
48, 50, 56, 125, 125,
|
|
]),
|
|
);
|
|
socket.flush();
|
|
}, 0);
|
|
},
|
|
},
|
|
hostname,
|
|
port,
|
|
});
|
|
|
|
const { promise, resolve } = Promise.withResolvers<string>();
|
|
|
|
client = new WebSocket(`ws://${server.hostname}:${server.port}`);
|
|
client.addEventListener("error", err => {
|
|
throw new Error(err.message);
|
|
});
|
|
client.addEventListener("close", err => {
|
|
if (!err.wasClean) {
|
|
throw new Error(err.reason);
|
|
}
|
|
});
|
|
client.addEventListener("message", event => resolve(event.data.toString("utf-8")));
|
|
|
|
expect(await promise).toEqual(
|
|
`{"jsonrpc":"2.0","method":"transactionNotification","params":{"result":{"context":{"slot":249602179},"value":{"signature":"2P2xf3mU1vrnYcd1Lich8ELhhXx72oCinMaQXeqjvD7o4eKM5FB3NLahV7DWeQjifbk58KyhBwbwX1hgwgppfvMG","slot":249602179}},"subscription":4028}}`,
|
|
);
|
|
} finally {
|
|
client?.close();
|
|
server?.stop(true);
|
|
}
|
|
});
|
|
});
|