Files
bun.sh/test/js/node/http/node-http-with-ws.test.ts
Ciro Spaciari 76545140af fix(node:http) fix closing socket after upgraded to websocket (#23150)
### What does this PR do?
handle socket upgrade in NodeHTTP.cpp
### How did you verify your code works?
Run the test added with asan it should catch the bug

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-02 14:55:28 -07:00

51 lines
1.9 KiB
TypeScript

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();
});