Add timeout selection + refine error logic + update tests

This commit is contained in:
PoleTransformer
2025-12-30 20:29:55 -08:00
parent a2c81ebf44
commit 20e2cf69e4
3 changed files with 109 additions and 20 deletions
+91 -6
View File
@@ -3,6 +3,24 @@ const { describe, test } = require("node:test");
const assert = require("node:assert");
const { WebSocketMonitorType } = require("../../server/monitor-types/websocket-upgrade");
const { UP, PENDING } = require("../../src/util");
const net = require("node:net");
/**
* Simulates non compliant WS Server, doesnt send Sec-WebSocket-Accept header
* @param {number} port Port the server listens on. Defaults to 8080
* @returns {Promise} Promise that resolves to the created server once listening
*/
function nonCompliantWS(port = 8080) {
const srv = net.createServer((socket) => {
socket.once("data", (buf) => {
socket.write("HTTP/1.1 101 Switching Protocols\r\n" +
"Upgrade: websocket\r\n" +
"Connection: Upgrade\r\n\r\n");
socket.destroy();
});
});
return new Promise((resolve) => srv.listen(port, () => resolve(srv)));
}
describe("Websocket Test", {
}, () => {
@@ -12,6 +30,7 @@ describe("Websocket Test", {
const monitor = {
url: "wss://example.org",
wsIgnoreSecWebsocketAcceptHeader: false,
timeout: 30,
};
const heartbeat = {
@@ -32,6 +51,7 @@ describe("Websocket Test", {
url: "wss://echo.websocket.org",
wsIgnoreSecWebsocketAcceptHeader: false,
accepted_statuscodes_json: JSON.stringify([ "1000" ]),
timeout: 30,
};
const heartbeat = {
@@ -57,6 +77,7 @@ describe("Websocket Test", {
url: "ws://localhost:8080",
wsIgnoreSecWebsocketAcceptHeader: false,
accepted_statuscodes_json: JSON.stringify([ "1000" ]),
timeout: 30,
};
const heartbeat = {
@@ -80,6 +101,7 @@ describe("Websocket Test", {
url: "wss://echo.websocket.org",
wsIgnoreSecWebsocketAcceptHeader: false,
accepted_statuscodes_json: JSON.stringify([ "1001" ]),
timeout: 30,
};
const heartbeat = {
@@ -93,13 +115,37 @@ describe("Websocket Test", {
);
});
test("Non compliant WS server without IgnoreSecWebsocket", async () => {
test("Secure WS Server no status code", async () => {
const websocketMonitor = new WebSocketMonitorType();
const monitor = {
url: "wss://c.img-cdn.net/yE4s7KehTFyj/",
url: "wss://echo.websocket.org",
wsIgnoreSecWebsocketAcceptHeader: false,
accepted_statuscodes_json: JSON.stringify([ "" ]),
timeout: 30,
};
const heartbeat = {
msg: "",
status: PENDING,
};
await assert.rejects(
websocketMonitor.check(monitor, heartbeat, {}),
new Error("Unexpected status code: 1000")
);
});
test("Non compliant WS server without IgnoreSecWebsocket", async (t) => {
t.after(() => wss.close());
const websocketMonitor = new WebSocketMonitorType();
const wss = await nonCompliantWS();
const monitor = {
url: "ws://localhost:8080",
wsIgnoreSecWebsocketAcceptHeader: false,
accepted_statuscodes_json: JSON.stringify([ "1000" ]),
timeout: 30,
};
const heartbeat = {
@@ -113,13 +159,16 @@ describe("Websocket Test", {
);
});
test("Non compliant WS server with IgnoreSecWebsocket", async () => {
test("Non compliant WS server with IgnoreSecWebsocket", async (t) => {
t.after(() => wss.close());
const websocketMonitor = new WebSocketMonitorType();
const wss = await nonCompliantWS();
const monitor = {
url: "wss://c.img-cdn.net/yE4s7KehTFyj/",
url: "ws://localhost:8080",
wsIgnoreSecWebsocketAcceptHeader: true,
accepted_statuscodes_json: JSON.stringify([ "1000" ]),
timeout: 30,
};
const heartbeat = {
@@ -143,6 +192,7 @@ describe("Websocket Test", {
url: "wss://echo.websocket.org",
wsIgnoreSecWebsocketAcceptHeader: true,
accepted_statuscodes_json: JSON.stringify([ "1000" ]),
timeout: 30,
};
const heartbeat = {
@@ -166,6 +216,7 @@ describe("Websocket Test", {
url: "wss://example.org",
wsIgnoreSecWebsocketAcceptHeader: true,
accepted_statuscodes_json: JSON.stringify([ "1000" ]),
timeout: 30,
};
const heartbeat = {
@@ -187,6 +238,7 @@ describe("Websocket Test", {
wsIgnoreSecWebsocketAcceptHeader: false,
wsSubprotocol: "ocpp1.6",
accepted_statuscodes_json: JSON.stringify([ "1000" ]),
timeout: 30,
};
const heartbeat = {
@@ -200,14 +252,15 @@ describe("Websocket Test", {
);
});
test("Multiple subprotocols bad input", async () => {
test("Multiple subprotocols invalid input", async () => {
const websocketMonitor = new WebSocketMonitorType();
const monitor = {
url: "wss://echo.websocket.org",
wsIgnoreSecWebsocketAcceptHeader: false,
wsSubprotocol: " ocpp2.0 , ocpp1.6 , ",
wsSubprotocol: " # & ,ocpp2.0 [] , ocpp1.6 , ,, ; ",
accepted_statuscodes_json: JSON.stringify([ "1000" ]),
timeout: 30,
};
const heartbeat = {
@@ -221,6 +274,37 @@ describe("Websocket Test", {
);
});
test("Insecure WS subprotocol multiple spaces", async (t) => {
t.after(() => wss.close());
const websocketMonitor = new WebSocketMonitorType();
const wss = new WebSocketServer({ port: 8080,
handleProtocols: (protocols) => {
return Array.from(protocols).includes("test") ? "test" : null;
}
});
const monitor = {
url: "ws://localhost:8080",
wsIgnoreSecWebsocketAcceptHeader: false,
wsSubprotocol: "invalid , test ",
accepted_statuscodes_json: JSON.stringify([ "1000" ]),
timeout: 30,
};
const heartbeat = {
msg: "",
status: PENDING,
};
const expected = {
msg: "1000 - OK",
status: UP,
};
await websocketMonitor.check(monitor, heartbeat, {});
assert.deepStrictEqual(heartbeat, expected);
});
test("Insecure WS support one subprotocol", async (t) => {
t.after(() => wss.close());
const websocketMonitor = new WebSocketMonitorType();
@@ -235,6 +319,7 @@ describe("Websocket Test", {
wsIgnoreSecWebsocketAcceptHeader: false,
wsSubprotocol: "invalid,test",
accepted_statuscodes_json: JSON.stringify([ "1000" ]),
timeout: 30,
};
const heartbeat = {