mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
* fix(ws/client): handle short reads on payload frame length In the WebSocket specification, control frames may not be fragmented. However, the frame parser should handle fragmented control frames nonetheless. Whether or not the frame parser is given a set of fragmented bytes to parse is subject to the strategy in which the client buffers received bytes. All stages of the frame parser currently supports parsing frames fragmented across multiple TCP segments except for the payload frame length parsing stage. This commit implements buffering the bytes of a frame's payload length into a client instance so that the websocket client is able to properly parse payload frame lengths despite there being a short read over incoming TCP data. A test is added to test/js/web/websocket/websocket-client-short-read.test.ts which creates a make-shift WebSocket server that performs short writes over a single WebSocket frame. The test passes with this commit. * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
95 lines
2.3 KiB
JavaScript
95 lines
2.3 KiB
JavaScript
import { createServer } from "node:http";
|
|
import { WebSocketServer } from "ws";
|
|
|
|
const server = createServer();
|
|
const wss = new WebSocketServer({
|
|
perMessageDeflate: false,
|
|
noServer: true,
|
|
});
|
|
|
|
server.on("listening", () => {
|
|
const { address, port, family } = server.address();
|
|
const { href } = new URL(family === "IPv6" ? `ws://[${address}]:${port}` : `ws://${address}:${port}`);
|
|
console.log(href);
|
|
console.error("Listening:", href);
|
|
});
|
|
|
|
server.on("request", (request, response) => {
|
|
console.error("Received request:", { ...request.headers });
|
|
response.end();
|
|
});
|
|
|
|
server.on("clientError", (error, socket) => {
|
|
console.error("Received client error:", error);
|
|
socket.end();
|
|
});
|
|
|
|
server.on("error", error => {
|
|
console.error("Received error:", error);
|
|
});
|
|
|
|
server.on("upgrade", (request, socket, head) => {
|
|
console.error("Received upgrade:", { ...request.headers });
|
|
|
|
socket.on("data", data => {
|
|
console.error("Received bytes:", data);
|
|
});
|
|
|
|
wss.handleUpgrade(request, socket, head, ws => {
|
|
wss.emit("connection", ws, request);
|
|
});
|
|
});
|
|
|
|
wss.on("connection", (ws, request) => {
|
|
console.error("Received connection:", request.socket.remoteAddress);
|
|
|
|
ws.on("message", message => {
|
|
console.error("Received message:", message);
|
|
ws.send(message);
|
|
|
|
if (message === "ping") {
|
|
console.error("Sending ping");
|
|
ws.ping();
|
|
} else if (message === "pong") {
|
|
console.error("Sending pong");
|
|
ws.pong();
|
|
} else if (message === "close") {
|
|
console.error("Sending close");
|
|
ws.close();
|
|
} else if (message === "terminate") {
|
|
console.error("Sending terminate");
|
|
ws.terminate();
|
|
}
|
|
});
|
|
|
|
ws.on("ping", data => {
|
|
console.error("Received ping:", data);
|
|
ws.ping(data);
|
|
});
|
|
|
|
ws.on("pong", data => {
|
|
console.error("Received pong:", data);
|
|
ws.pong(data);
|
|
});
|
|
|
|
ws.on("close", (code, reason) => {
|
|
console.error("Received close:", code, reason);
|
|
});
|
|
|
|
ws.on("error", error => {
|
|
console.error("Received error:", error);
|
|
});
|
|
});
|
|
|
|
server.on("close", () => {
|
|
console.error("Server closed");
|
|
});
|
|
|
|
process.on("exit", exitCode => {
|
|
console.error("Server exited:", exitCode);
|
|
});
|
|
|
|
const hostname = process.env.HOST || "127.0.0.1";
|
|
const port = parseInt(process.env.PORT || "0");
|
|
server.listen(port, hostname);
|