Fix connection leak in route-connection-handler by using safe socket creation
The previous fix only addressed ForwardingHandler classes but missed the critical setupDirectConnection() method in route-connection-handler.ts where SmartProxy actually handles connections. This caused active connections to rise indefinitely on ECONNREFUSED errors. Changes: - Import createSocketWithErrorHandler in route-connection-handler.ts - Replace net.connect() with createSocketWithErrorHandler() in setupDirectConnection() - Properly clean up connection records when server connection fails - Add connectionFailed flag to prevent setup of failed connections This ensures connection records are cleaned up immediately when backend connections fail, preventing memory leaks.
This commit is contained in:
parent
900942a263
commit
300ab1a077
@ -457,4 +457,11 @@ const socket = createSocketWithErrorHandler({
|
||||
- `test/test.forwarding-error-fix.node.ts` - Tests forwarding handlers handle errors gracefully
|
||||
|
||||
### Configuration
|
||||
No configuration changes needed. The fix is transparent to users.
|
||||
No configuration changes needed. The fix is transparent to users.
|
||||
|
||||
### Important Note
|
||||
The fix was applied in two places:
|
||||
1. **ForwardingHandler classes** (`https-passthrough-handler.ts`, etc.) - These are standalone forwarding utilities
|
||||
2. **SmartProxy route-connection-handler** (`route-connection-handler.ts`) - This is where the actual SmartProxy connection handling happens
|
||||
|
||||
The critical fix for SmartProxy was in `setupDirectConnection()` method in route-connection-handler.ts, which now uses `createSocketWithErrorHandler()` to properly handle connection failures and clean up connection records.
|
@ -9,7 +9,7 @@ import { TlsManager } from './tls-manager.js';
|
||||
import { HttpProxyBridge } from './http-proxy-bridge.js';
|
||||
import { TimeoutManager } from './timeout-manager.js';
|
||||
import { RouteManager } from './route-manager.js';
|
||||
import { cleanupSocket, createIndependentSocketHandlers, setupSocketHandlers } from '../../core/utils/socket-utils.js';
|
||||
import { cleanupSocket, createIndependentSocketHandlers, setupSocketHandlers, createSocketWithErrorHandler } from '../../core/utils/socket-utils.js';
|
||||
|
||||
/**
|
||||
* Handles new connection processing and setup logic with support for route-based configuration
|
||||
@ -1073,13 +1073,52 @@ export class RouteConnectionHandler {
|
||||
record.pendingDataSize = initialChunk.length;
|
||||
}
|
||||
|
||||
// Create the target socket
|
||||
const targetSocket = plugins.net.connect(connectionOptions);
|
||||
record.outgoing = targetSocket;
|
||||
record.outgoingStartTime = Date.now();
|
||||
// Create the target socket with immediate error handling
|
||||
let targetSocket: plugins.net.Socket;
|
||||
|
||||
// Flag to track if initial connection failed
|
||||
let connectionFailed = false;
|
||||
|
||||
targetSocket = createSocketWithErrorHandler({
|
||||
port: finalTargetPort,
|
||||
host: finalTargetHost,
|
||||
onError: (error) => {
|
||||
// Mark connection as failed
|
||||
connectionFailed = true;
|
||||
|
||||
// Connection failed - clean up immediately
|
||||
logger.log('error',
|
||||
`Connection setup error for ${connectionId} to ${finalTargetHost}:${finalTargetPort}: ${error.message} (${(error as any).code})`,
|
||||
{
|
||||
connectionId,
|
||||
targetHost: finalTargetHost,
|
||||
targetPort: finalTargetPort,
|
||||
errorMessage: error.message,
|
||||
errorCode: (error as any).code,
|
||||
component: 'route-handler'
|
||||
}
|
||||
);
|
||||
|
||||
// Resume the incoming socket to prevent it from hanging
|
||||
socket.resume();
|
||||
|
||||
// Clean up the incoming socket
|
||||
if (!socket.destroyed) {
|
||||
socket.destroy();
|
||||
}
|
||||
|
||||
// Clean up the connection record
|
||||
this.connectionManager.initiateCleanupOnce(record, `connection_failed_${(error as any).code || 'unknown'}`);
|
||||
}
|
||||
});
|
||||
|
||||
// Only proceed with setup if connection didn't fail immediately
|
||||
if (!connectionFailed) {
|
||||
record.outgoing = targetSocket;
|
||||
record.outgoingStartTime = Date.now();
|
||||
|
||||
// Apply socket optimizations
|
||||
targetSocket.setNoDelay(this.settings.noDelay);
|
||||
// Apply socket optimizations
|
||||
targetSocket.setNoDelay(this.settings.noDelay);
|
||||
|
||||
// Apply keep-alive settings if enabled
|
||||
if (this.settings.keepAlive) {
|
||||
@ -1346,5 +1385,6 @@ export class RouteConnectionHandler {
|
||||
record.tlsHandshakeComplete = true;
|
||||
}
|
||||
});
|
||||
} // End of if (!connectionFailed)
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user