fix(websocket): keep upgraded WebSocket tunnels on dedicated lifecycle timeouts
This commit is contained in:
@@ -415,4 +415,68 @@ tap.test('should handle large WebSocket messages', async () => {
|
||||
await assertPortsFree([PROXY_PORT, BACKEND_PORT]);
|
||||
});
|
||||
|
||||
// ─── Test 7: Idle WebSocket outlives short HTTP socket timeout ───
|
||||
tap.test('should keep idle WebSocket open beyond HTTP socket timeout', async (tools) => {
|
||||
tools.timeout(15000);
|
||||
|
||||
const [PROXY_PORT, BACKEND_PORT] = await findFreePorts(2);
|
||||
let proxy: SmartProxy | undefined;
|
||||
let ws: WebSocket | undefined;
|
||||
|
||||
const backendServer = http.createServer();
|
||||
const wss = new WebSocketServer({ server: backendServer });
|
||||
|
||||
wss.on('connection', (backendWs) => {
|
||||
backendWs.on('message', (data) => {
|
||||
backendWs.send(`echo: ${data.toString()}`);
|
||||
});
|
||||
});
|
||||
|
||||
try {
|
||||
await new Promise<void>((resolve) => {
|
||||
backendServer.listen(BACKEND_PORT, '127.0.0.1', () => resolve());
|
||||
});
|
||||
|
||||
proxy = new SmartProxy({
|
||||
socketTimeout: 1000,
|
||||
maxConnectionLifetime: 1000,
|
||||
routes: [{
|
||||
name: 'ws-idle-timeout-route',
|
||||
match: { ports: PROXY_PORT },
|
||||
action: {
|
||||
type: 'forward',
|
||||
targets: [{ host: '127.0.0.1', port: BACKEND_PORT }],
|
||||
websocket: { enabled: true },
|
||||
},
|
||||
}],
|
||||
});
|
||||
await proxy.start();
|
||||
|
||||
const connection = connectWs(
|
||||
`ws://127.0.0.1:${PROXY_PORT}/`,
|
||||
{ Host: 'test.local' },
|
||||
);
|
||||
ws = connection.ws;
|
||||
await connection.opened;
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 6500));
|
||||
expect(ws.readyState).toEqual(WebSocket.OPEN);
|
||||
|
||||
ws.send('still open');
|
||||
await waitFor(() => connection.messages.length >= 1);
|
||||
expect(connection.messages[0]).toEqual('echo: still open');
|
||||
} finally {
|
||||
if (ws && ws.readyState !== WebSocket.CLOSED) {
|
||||
await closeWs(ws);
|
||||
}
|
||||
if (proxy) {
|
||||
await proxy.stop();
|
||||
}
|
||||
wss.close();
|
||||
await new Promise<void>((resolve) => backendServer.close(() => resolve()));
|
||||
await new Promise((r) => setTimeout(r, 500));
|
||||
await assertPortsFree([PROXY_PORT, BACKEND_PORT]);
|
||||
}
|
||||
});
|
||||
|
||||
export default tap.start();
|
||||
|
||||
Reference in New Issue
Block a user