fix(proxy): close connection buildup vectors in HTTP idle, WebSocket, socket relay, and TLS forwarding paths

- Add HTTP keep-alive idle timeout (60s default) with periodic watchdog that
  skips active requests (panic-safe via RAII ActiveRequestGuard)
- Make WebSocket inactivity/max-lifetime timeouts configurable from ConnectionConfig
  instead of hardcoded 1h/24h
- Replace bare copy_bidirectional in socket handler relay with timeout+cancel-aware
  split forwarding (inactivity, max lifetime, graceful shutdown)
- Add CancellationToken to forward_bidirectional_split_with_timeouts so TLS-terminated
  TCP connections respond to graceful shutdown
- Fix graceful_stop to actually abort listener tasks that exceed the shutdown deadline
  (previously they detached and ran forever)
- Add 10s metadata parsing timeout on TS socket-handler-server to prevent stuck sockets
This commit is contained in:
2026-02-26 21:29:19 +00:00
parent ef060d5e79
commit 8db621657f
3 changed files with 215 additions and 47 deletions

View File

@@ -92,6 +92,16 @@ export class SocketHandlerServer {
let metadataBuffer = '';
let metadataParsed = false;
// 10s timeout for metadata parsing phase — if Rust connects but never
// sends the JSON metadata line, don't hold the socket open indefinitely.
socket.setTimeout(10_000);
socket.on('timeout', () => {
if (!metadataParsed) {
logger.log('warn', 'Socket handler metadata timeout, closing', { component: 'socket-handler-server' });
socket.destroy();
}
});
const onData = (chunk: Buffer) => {
if (metadataParsed) return;
@@ -108,6 +118,7 @@ export class SocketHandlerServer {
}
metadataParsed = true;
socket.setTimeout(0); // Clear metadata timeout
socket.removeListener('data', onData);
socket.pause(); // Prevent data loss between handler removal and pipe setup