import { expect, test } from "bun:test"; import { tls as options } from "harness"; import https from "https"; import type { AddressInfo } from "node:net"; import tls from "tls"; import { WebSocketServer } from "ws"; test("should not crash when closing sockets after upgrade", async () => { const { promise, resolve } = Promise.withResolvers(); let http_sockets: tls.TLSSocket[] = []; const server = https.createServer(options, (req, res) => { http_sockets.push(res.socket as tls.TLSSocket); res.writeHead(200, { "Content-Type": "text/plain", "Connection": "Keep-Alive" }); res.end("okay"); res.detachSocket(res.socket!); }); server.listen(0, "127.0.0.1", () => { const wsServer = new WebSocketServer({ server }); wsServer.on("connection", socket => {}); const port = (server.address() as AddressInfo).port; const socket = tls.connect({ port, ca: options.cert }, () => { // normal request keep the socket alive socket.write(`GET / HTTP/1.1\r\nHost: localhost:${port}\r\nConnection: Keep-Alive\r\nContent-Length: 0\r\n\r\n`); socket.write(`GET / HTTP/1.1\r\nHost: localhost:${port}\r\nConnection: Keep-Alive\r\nContent-Length: 0\r\n\r\n`); socket.write(`GET / HTTP/1.1\r\nHost: localhost:${port}\r\nConnection: Keep-Alive\r\nContent-Length: 0\r\n\r\n`); // upgrade to websocket socket.write( `GET / HTTP/1.1\r\nHost: localhost:${port}\r\nConnection: Upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n`, ); }); socket.on("data", data => { const isWebSocket = data?.toString().includes("Upgrade: websocket"); if (isWebSocket) { socket.destroy(); setTimeout(() => { http_sockets.forEach(http_socket => { http_socket?.destroy(); }); server.closeAllConnections(); resolve(); }, 10); } }); }); await promise; expect().pass(); });