fix(network-proxy/websocket): Improve WebSocket connection closure and update router integration

This commit is contained in:
Philipp Kunz 2025-05-15 20:08:18 +00:00
parent 0e2c8d498d
commit 1a038f001f
5 changed files with 33 additions and 7 deletions

View File

@ -1,5 +1,12 @@
# Changelog
## 2025-05-15 - 18.1.1 - fix(network-proxy/websocket)
Improve WebSocket connection closure and update router integration
- Wrap WS close logic in try-catch blocks to ensure valid close codes are used for both incoming and outgoing WebSocket connections
- Use explicit numeric close codes (defaulting to 1000 when unavailable) to prevent improper socket termination
- Update NetworkProxy updateRoutes to also refresh the WebSocket handler routes for consistent configuration
## 2025-05-15 - 18.1.0 - feat(nftables)
Add NFTables integration for kernel-level forwarding and update documentation, tests, and helper functions

View File

@ -238,6 +238,10 @@ tap.test('should start the proxy server', async () => {
},
tls: {
mode: 'terminate'
},
websocket: {
enabled: true,
subprotocols: ['echo-protocol']
}
}
}

View File

@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@push.rocks/smartproxy',
version: '18.1.0',
version: '18.1.1',
description: 'A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.'
}

View File

@ -500,6 +500,9 @@ export class NetworkProxy implements IMetricsTracker {
this.logger.warn('Router has no recognized configuration method');
}
// Update WebSocket handler with new routes
this.webSocketHandler.setRoutes(routes);
this.logger.info(`Route configuration updated with ${routes.length} routes and ${legacyConfigs.length} proxy configs`);
}

View File

@ -419,9 +419,15 @@ export class WebSocketHandler {
wsIncoming.on('close', (code, reason) => {
this.logger.debug(`WebSocket client connection closed: ${code} ${reason}`);
if (wsOutgoing.readyState === wsOutgoing.OPEN) {
const validCode = code || 1000;
const reasonString = toBuffer(reason).toString();
wsOutgoing.close(validCode, reasonString);
// Ensure code is a valid WebSocket close code number
const validCode = typeof code === 'number' && code >= 1000 && code <= 4999 ? code : 1000;
try {
const reasonString = reason ? toBuffer(reason).toString() : '';
wsOutgoing.close(validCode, reasonString);
} catch (err) {
this.logger.error('Error closing wsOutgoing:', err);
wsOutgoing.close(validCode);
}
}
// Clean up timers
@ -432,9 +438,15 @@ export class WebSocketHandler {
wsOutgoing.on('close', (code, reason) => {
this.logger.debug(`WebSocket target connection closed: ${code} ${reason}`);
if (wsIncoming.readyState === wsIncoming.OPEN) {
const validCode = code || 1000;
const reasonString = toBuffer(reason).toString();
wsIncoming.close(validCode, reasonString);
// Ensure code is a valid WebSocket close code number
const validCode = typeof code === 'number' && code >= 1000 && code <= 4999 ? code : 1000;
try {
const reasonString = reason ? toBuffer(reason).toString() : '';
wsIncoming.close(validCode, reasonString);
} catch (err) {
this.logger.error('Error closing wsIncoming:', err);
wsIncoming.close(validCode);
}
}
// Clean up timers