@push.rocks/smartproxy 19.5.5 → 19.5.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/dist_ts/core/utils/enhanced-connection-pool.js +7 -2
  2. package/dist_ts/core/utils/index.d.ts +1 -0
  3. package/dist_ts/core/utils/index.js +2 -1
  4. package/dist_ts/core/utils/lifecycle-component.js +23 -7
  5. package/dist_ts/core/utils/socket-utils.d.ts +28 -0
  6. package/dist_ts/core/utils/socket-utils.js +77 -0
  7. package/dist_ts/forwarding/handlers/http-handler.js +7 -4
  8. package/dist_ts/forwarding/handlers/https-passthrough-handler.js +14 -55
  9. package/dist_ts/forwarding/handlers/https-terminate-to-http-handler.js +52 -40
  10. package/dist_ts/forwarding/handlers/https-terminate-to-https-handler.js +31 -43
  11. package/dist_ts/proxies/http-proxy/connection-pool.js +4 -19
  12. package/dist_ts/proxies/http-proxy/http-proxy.js +3 -7
  13. package/dist_ts/proxies/smart-proxy/connection-manager.d.ts +0 -4
  14. package/dist_ts/proxies/smart-proxy/connection-manager.js +7 -30
  15. package/dist_ts/proxies/smart-proxy/http-proxy-bridge.js +13 -2
  16. package/dist_ts/proxies/smart-proxy/port-manager.js +3 -3
  17. package/dist_ts/proxies/smart-proxy/route-connection-handler.js +35 -4
  18. package/package.json +1 -1
  19. package/ts/core/utils/enhanced-connection-pool.ts +6 -1
  20. package/ts/core/utils/index.ts +1 -0
  21. package/ts/core/utils/lifecycle-component.ts +26 -6
  22. package/ts/core/utils/socket-utils.ts +96 -0
  23. package/ts/forwarding/handlers/http-handler.ts +7 -3
  24. package/ts/forwarding/handlers/https-passthrough-handler.ts +13 -62
  25. package/ts/forwarding/handlers/https-terminate-to-http-handler.ts +58 -46
  26. package/ts/forwarding/handlers/https-terminate-to-https-handler.ts +38 -53
  27. package/ts/proxies/http-proxy/connection-pool.ts +3 -16
  28. package/ts/proxies/http-proxy/http-proxy.ts +2 -5
  29. package/ts/proxies/smart-proxy/connection-manager.ts +6 -28
  30. package/ts/proxies/smart-proxy/http-proxy-bridge.ts +15 -1
  31. package/ts/proxies/smart-proxy/port-manager.ts +2 -2
  32. package/ts/proxies/smart-proxy/route-connection-handler.ts +39 -4
@@ -9,6 +9,7 @@ export abstract class LifecycleComponent {
9
9
  target: any;
10
10
  event: string;
11
11
  handler: Function;
12
+ actualHandler?: Function; // The actual handler registered (may be wrapped)
12
13
  once?: boolean;
13
14
  }> = [];
14
15
  private childComponents: Set<LifecycleComponent> = new Set();
@@ -21,7 +22,11 @@ export abstract class LifecycleComponent {
21
22
  protected setTimeout(handler: Function, timeout: number): NodeJS.Timeout {
22
23
  if (this.isShuttingDown) {
23
24
  // Return a dummy timer if shutting down
24
- return setTimeout(() => {}, 0);
25
+ const dummyTimer = setTimeout(() => {}, 0);
26
+ if (typeof dummyTimer.unref === 'function') {
27
+ dummyTimer.unref();
28
+ }
29
+ return dummyTimer;
25
30
  }
26
31
 
27
32
  const wrappedHandler = () => {
@@ -33,6 +38,12 @@ export abstract class LifecycleComponent {
33
38
 
34
39
  const timer = setTimeout(wrappedHandler, timeout);
35
40
  this.timers.add(timer);
41
+
42
+ // Allow process to exit even with timer
43
+ if (typeof timer.unref === 'function') {
44
+ timer.unref();
45
+ }
46
+
36
47
  return timer;
37
48
  }
38
49
 
@@ -42,7 +53,12 @@ export abstract class LifecycleComponent {
42
53
  protected setInterval(handler: Function, interval: number): NodeJS.Timeout {
43
54
  if (this.isShuttingDown) {
44
55
  // Return a dummy timer if shutting down
45
- return setInterval(() => {}, interval);
56
+ const dummyTimer = setInterval(() => {}, interval);
57
+ if (typeof dummyTimer.unref === 'function') {
58
+ dummyTimer.unref();
59
+ }
60
+ clearInterval(dummyTimer); // Clear immediately since we don't need it
61
+ return dummyTimer;
46
62
  }
47
63
 
48
64
  const wrappedHandler = () => {
@@ -121,11 +137,12 @@ export abstract class LifecycleComponent {
121
137
  throw new Error('Target must support on() or addEventListener()');
122
138
  }
123
139
 
124
- // Store the original handler in our tracking (not the wrapped one)
140
+ // Store both the original handler and the actual handler registered
125
141
  this.listeners.push({
126
142
  target,
127
143
  event,
128
144
  handler,
145
+ actualHandler, // The handler that was actually registered (may be wrapped)
129
146
  once: options?.once
130
147
  });
131
148
  }
@@ -208,12 +225,15 @@ export abstract class LifecycleComponent {
208
225
  this.intervals.clear();
209
226
 
210
227
  // Remove all event listeners
211
- for (const { target, event, handler } of this.listeners) {
228
+ for (const { target, event, handler, actualHandler } of this.listeners) {
229
+ // Use actualHandler if available (for wrapped handlers), otherwise use the original handler
230
+ const handlerToRemove = actualHandler || handler;
231
+
212
232
  // All listeners need to be removed, including 'once' listeners that might not have fired
213
233
  if (typeof target.removeListener === 'function') {
214
- target.removeListener(event, handler);
234
+ target.removeListener(event, handlerToRemove);
215
235
  } else if (typeof target.removeEventListener === 'function') {
216
- target.removeEventListener(event, handler);
236
+ target.removeEventListener(event, handlerToRemove);
217
237
  }
218
238
  }
219
239
  this.listeners = [];
@@ -0,0 +1,96 @@
1
+ import * as plugins from '../../plugins.js';
2
+
3
+ /**
4
+ * Safely cleanup a socket by removing all listeners and destroying it
5
+ * @param socket The socket to cleanup
6
+ * @param socketName Optional name for logging
7
+ */
8
+ export function cleanupSocket(socket: plugins.net.Socket | plugins.tls.TLSSocket | null, socketName?: string): void {
9
+ if (!socket) return;
10
+
11
+ try {
12
+ // Remove all event listeners
13
+ socket.removeAllListeners();
14
+
15
+ // Unpipe any streams
16
+ socket.unpipe();
17
+
18
+ // Destroy if not already destroyed
19
+ if (!socket.destroyed) {
20
+ socket.destroy();
21
+ }
22
+ } catch (err) {
23
+ console.error(`Error cleaning up socket${socketName ? ` (${socketName})` : ''}: ${err}`);
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Create a cleanup handler for paired sockets (client and server)
29
+ * @param clientSocket The client socket
30
+ * @param serverSocket The server socket (optional)
31
+ * @param onCleanup Optional callback when cleanup is done
32
+ * @returns A cleanup function that can be called multiple times safely
33
+ */
34
+ export function createSocketCleanupHandler(
35
+ clientSocket: plugins.net.Socket | plugins.tls.TLSSocket,
36
+ serverSocket?: plugins.net.Socket | plugins.tls.TLSSocket | null,
37
+ onCleanup?: (reason: string) => void
38
+ ): (reason: string) => void {
39
+ let cleanedUp = false;
40
+
41
+ return (reason: string) => {
42
+ if (cleanedUp) return;
43
+ cleanedUp = true;
44
+
45
+ // Cleanup both sockets
46
+ cleanupSocket(clientSocket, 'client');
47
+ if (serverSocket) {
48
+ cleanupSocket(serverSocket, 'server');
49
+ }
50
+
51
+ // Call cleanup callback if provided
52
+ if (onCleanup) {
53
+ onCleanup(reason);
54
+ }
55
+ };
56
+ }
57
+
58
+ /**
59
+ * Setup socket error and close handlers with proper cleanup
60
+ * @param socket The socket to setup handlers for
61
+ * @param handleClose The cleanup function to call
62
+ * @param errorPrefix Optional prefix for error messages
63
+ */
64
+ export function setupSocketHandlers(
65
+ socket: plugins.net.Socket | plugins.tls.TLSSocket,
66
+ handleClose: (reason: string) => void,
67
+ errorPrefix?: string
68
+ ): void {
69
+ socket.on('error', (error) => {
70
+ const prefix = errorPrefix || 'Socket';
71
+ handleClose(`${prefix}_error: ${error.message}`);
72
+ });
73
+
74
+ socket.on('close', () => {
75
+ const prefix = errorPrefix || 'socket';
76
+ handleClose(`${prefix}_closed`);
77
+ });
78
+
79
+ socket.on('timeout', () => {
80
+ const prefix = errorPrefix || 'socket';
81
+ handleClose(`${prefix}_timeout`);
82
+ });
83
+ }
84
+
85
+ /**
86
+ * Pipe two sockets together with proper cleanup on either end
87
+ * @param socket1 First socket
88
+ * @param socket2 Second socket
89
+ */
90
+ export function pipeSockets(
91
+ socket1: plugins.net.Socket | plugins.tls.TLSSocket,
92
+ socket2: plugins.net.Socket | plugins.tls.TLSSocket
93
+ ): void {
94
+ socket1.pipe(socket2);
95
+ socket2.pipe(socket1);
96
+ }
@@ -2,6 +2,7 @@ import * as plugins from '../../plugins.js';
2
2
  import { ForwardingHandler } from './base-handler.js';
3
3
  import type { IForwardConfig } from '../config/forwarding-types.js';
4
4
  import { ForwardingHandlerEvents } from '../config/forwarding-types.js';
5
+ import { setupSocketHandlers } from '../../core/utils/socket-utils.js';
5
6
 
6
7
  /**
7
8
  * Handler for HTTP-only forwarding
@@ -40,12 +41,15 @@ export class HttpForwardingHandler extends ForwardingHandler {
40
41
  const remoteAddress = socket.remoteAddress || 'unknown';
41
42
  const localPort = socket.localPort || 80;
42
43
 
43
- socket.on('close', (hadError) => {
44
+ // Set up socket handlers with proper cleanup
45
+ const handleClose = (reason: string) => {
44
46
  this.emit(ForwardingHandlerEvents.DISCONNECTED, {
45
47
  remoteAddress,
46
- hadError
48
+ reason
47
49
  });
48
- });
50
+ };
51
+
52
+ setupSocketHandlers(socket, handleClose, 'http');
49
53
 
50
54
  socket.on('error', (error) => {
51
55
  this.emit(ForwardingHandlerEvents.ERROR, {
@@ -2,6 +2,7 @@ import * as plugins from '../../plugins.js';
2
2
  import { ForwardingHandler } from './base-handler.js';
3
3
  import type { IForwardConfig } from '../config/forwarding-types.js';
4
4
  import { ForwardingHandlerEvents } from '../config/forwarding-types.js';
5
+ import { createSocketCleanupHandler, setupSocketHandlers, pipeSockets } from '../../core/utils/socket-utils.js';
5
6
 
6
7
  /**
7
8
  * Handler for HTTPS passthrough (SNI forwarding without termination)
@@ -50,35 +51,23 @@ export class HttpsPassthroughHandler extends ForwardingHandler {
50
51
  // Create a connection to the target server
51
52
  const serverSocket = plugins.net.connect(target.port, target.host);
52
53
 
53
- // Handle errors on the server socket
54
- serverSocket.on('error', (error) => {
55
- this.emit(ForwardingHandlerEvents.ERROR, {
56
- remoteAddress,
57
- error: `Target connection error: ${error.message}`
58
- });
59
-
60
- // Close the client socket if it's still open
61
- if (!clientSocket.destroyed) {
62
- clientSocket.destroy();
63
- }
64
- });
54
+ // Track data transfer for logging
55
+ let bytesSent = 0;
56
+ let bytesReceived = 0;
65
57
 
66
- // Handle errors on the client socket
67
- clientSocket.on('error', (error) => {
68
- this.emit(ForwardingHandlerEvents.ERROR, {
58
+ // Create cleanup handler with our utility
59
+ const handleClose = createSocketCleanupHandler(clientSocket, serverSocket, (reason) => {
60
+ this.emit(ForwardingHandlerEvents.DISCONNECTED, {
69
61
  remoteAddress,
70
- error: `Client connection error: ${error.message}`
62
+ bytesSent,
63
+ bytesReceived,
64
+ reason
71
65
  });
72
-
73
- // Close the server socket if it's still open
74
- if (!serverSocket.destroyed) {
75
- serverSocket.destroy();
76
- }
77
66
  });
78
67
 
79
- // Track data transfer for logging
80
- let bytesSent = 0;
81
- let bytesReceived = 0;
68
+ // Setup error and close handlers for both sockets
69
+ setupSocketHandlers(serverSocket, handleClose, 'server');
70
+ setupSocketHandlers(clientSocket, handleClose, 'client');
82
71
 
83
72
  // Forward data from client to server
84
73
  clientSocket.on('data', (data) => {
@@ -128,48 +117,10 @@ export class HttpsPassthroughHandler extends ForwardingHandler {
128
117
  });
129
118
  });
130
119
 
131
- // Handle connection close
132
- const handleClose = () => {
133
- if (!clientSocket.destroyed) {
134
- clientSocket.destroy();
135
- }
136
-
137
- if (!serverSocket.destroyed) {
138
- serverSocket.destroy();
139
- }
140
-
141
- this.emit(ForwardingHandlerEvents.DISCONNECTED, {
142
- remoteAddress,
143
- bytesSent,
144
- bytesReceived
145
- });
146
- };
147
-
148
- // Set up close handlers
149
- clientSocket.on('close', handleClose);
150
- serverSocket.on('close', handleClose);
151
-
152
120
  // Set timeouts
153
121
  const timeout = this.getTimeout();
154
122
  clientSocket.setTimeout(timeout);
155
123
  serverSocket.setTimeout(timeout);
156
-
157
- // Handle timeouts
158
- clientSocket.on('timeout', () => {
159
- this.emit(ForwardingHandlerEvents.ERROR, {
160
- remoteAddress,
161
- error: 'Client connection timeout'
162
- });
163
- handleClose();
164
- });
165
-
166
- serverSocket.on('timeout', () => {
167
- this.emit(ForwardingHandlerEvents.ERROR, {
168
- remoteAddress,
169
- error: 'Server connection timeout'
170
- });
171
- handleClose();
172
- });
173
124
  }
174
125
 
175
126
  /**
@@ -2,6 +2,7 @@ import * as plugins from '../../plugins.js';
2
2
  import { ForwardingHandler } from './base-handler.js';
3
3
  import type { IForwardConfig } from '../config/forwarding-types.js';
4
4
  import { ForwardingHandlerEvents } from '../config/forwarding-types.js';
5
+ import { createSocketCleanupHandler, setupSocketHandlers } from '../../core/utils/socket-utils.js';
5
6
 
6
7
  /**
7
8
  * Handler for HTTPS termination with HTTP backend
@@ -95,76 +96,87 @@ export class HttpsTerminateToHttpHandler extends ForwardingHandler {
95
96
  tls: true
96
97
  });
97
98
 
98
- // Handle TLS errors
99
- tlsSocket.on('error', (error) => {
100
- this.emit(ForwardingHandlerEvents.ERROR, {
99
+ // Variables to track connections
100
+ let backendSocket: plugins.net.Socket | null = null;
101
+ let dataBuffer = Buffer.alloc(0);
102
+ let connectionEstablished = false;
103
+
104
+ // Create cleanup handler for all sockets
105
+ const handleClose = createSocketCleanupHandler(tlsSocket, backendSocket, (reason) => {
106
+ this.emit(ForwardingHandlerEvents.DISCONNECTED, {
101
107
  remoteAddress,
102
- error: `TLS error: ${error.message}`
108
+ reason
103
109
  });
104
-
105
- if (!tlsSocket.destroyed) {
106
- tlsSocket.destroy();
107
- }
110
+ dataBuffer = Buffer.alloc(0);
111
+ connectionEstablished = false;
108
112
  });
109
113
 
110
- // The TLS socket will now emit HTTP traffic that can be processed
111
- // In a real implementation, we would create an HTTP parser and handle
112
- // the requests here, but for simplicity, we'll just log the data
114
+ // Set up error handling with our cleanup utility
115
+ setupSocketHandlers(tlsSocket, handleClose, 'tls');
113
116
 
114
- let dataBuffer = Buffer.alloc(0);
117
+ // Set timeout
118
+ const timeout = this.getTimeout();
119
+ tlsSocket.setTimeout(timeout);
120
+
121
+ tlsSocket.on('timeout', () => {
122
+ this.emit(ForwardingHandlerEvents.ERROR, {
123
+ remoteAddress,
124
+ error: 'TLS connection timeout'
125
+ });
126
+ handleClose('timeout');
127
+ });
115
128
 
129
+ // Handle TLS data
116
130
  tlsSocket.on('data', (data) => {
131
+ // If backend connection already established, just forward the data
132
+ if (connectionEstablished && backendSocket && !backendSocket.destroyed) {
133
+ backendSocket.write(data);
134
+ return;
135
+ }
136
+
117
137
  // Append to buffer
118
138
  dataBuffer = Buffer.concat([dataBuffer, data]);
119
139
 
120
140
  // Very basic HTTP parsing - in a real implementation, use http-parser
121
- if (dataBuffer.includes(Buffer.from('\r\n\r\n'))) {
141
+ if (dataBuffer.includes(Buffer.from('\r\n\r\n')) && !connectionEstablished) {
122
142
  const target = this.getTargetFromConfig();
123
143
 
124
- // Simple example: forward the data to an HTTP server
125
- const socket = plugins.net.connect(target.port, target.host, () => {
126
- socket.write(dataBuffer);
127
- dataBuffer = Buffer.alloc(0);
144
+ // Create backend connection
145
+ backendSocket = plugins.net.connect(target.port, target.host, () => {
146
+ connectionEstablished = true;
147
+
148
+ // Send buffered data
149
+ if (dataBuffer.length > 0) {
150
+ backendSocket!.write(dataBuffer);
151
+ dataBuffer = Buffer.alloc(0);
152
+ }
128
153
 
129
154
  // Set up bidirectional data flow
130
- tlsSocket.pipe(socket);
131
- socket.pipe(tlsSocket);
155
+ tlsSocket.pipe(backendSocket!);
156
+ backendSocket!.pipe(tlsSocket);
132
157
  });
133
158
 
134
- socket.on('error', (error) => {
159
+ // Update the cleanup handler with the backend socket
160
+ const newHandleClose = createSocketCleanupHandler(tlsSocket, backendSocket, (reason) => {
161
+ this.emit(ForwardingHandlerEvents.DISCONNECTED, {
162
+ remoteAddress,
163
+ reason
164
+ });
165
+ dataBuffer = Buffer.alloc(0);
166
+ connectionEstablished = false;
167
+ });
168
+
169
+ // Set up handlers for backend socket
170
+ setupSocketHandlers(backendSocket, newHandleClose, 'backend');
171
+
172
+ backendSocket.on('error', (error) => {
135
173
  this.emit(ForwardingHandlerEvents.ERROR, {
136
174
  remoteAddress,
137
175
  error: `Target connection error: ${error.message}`
138
176
  });
139
-
140
- if (!tlsSocket.destroyed) {
141
- tlsSocket.destroy();
142
- }
143
177
  });
144
178
  }
145
179
  });
146
-
147
- // Handle close
148
- tlsSocket.on('close', () => {
149
- this.emit(ForwardingHandlerEvents.DISCONNECTED, {
150
- remoteAddress
151
- });
152
- });
153
-
154
- // Set timeout
155
- const timeout = this.getTimeout();
156
- tlsSocket.setTimeout(timeout);
157
-
158
- tlsSocket.on('timeout', () => {
159
- this.emit(ForwardingHandlerEvents.ERROR, {
160
- remoteAddress,
161
- error: 'TLS connection timeout'
162
- });
163
-
164
- if (!tlsSocket.destroyed) {
165
- tlsSocket.destroy();
166
- }
167
- });
168
180
  }
169
181
 
170
182
  /**
@@ -2,6 +2,7 @@ import * as plugins from '../../plugins.js';
2
2
  import { ForwardingHandler } from './base-handler.js';
3
3
  import type { IForwardConfig } from '../config/forwarding-types.js';
4
4
  import { ForwardingHandlerEvents } from '../config/forwarding-types.js';
5
+ import { createSocketCleanupHandler, setupSocketHandlers } from '../../core/utils/socket-utils.js';
5
6
 
6
7
  /**
7
8
  * Handler for HTTPS termination with HTTPS backend
@@ -93,28 +94,38 @@ export class HttpsTerminateToHttpsHandler extends ForwardingHandler {
93
94
  tls: true
94
95
  });
95
96
 
96
- // Handle TLS errors
97
- tlsSocket.on('error', (error) => {
98
- this.emit(ForwardingHandlerEvents.ERROR, {
97
+ // Variable to track backend socket
98
+ let backendSocket: plugins.tls.TLSSocket | null = null;
99
+
100
+ // Create cleanup handler for both sockets
101
+ const handleClose = createSocketCleanupHandler(tlsSocket, backendSocket, (reason) => {
102
+ this.emit(ForwardingHandlerEvents.DISCONNECTED, {
99
103
  remoteAddress,
100
- error: `TLS error: ${error.message}`
104
+ reason
101
105
  });
102
-
103
- if (!tlsSocket.destroyed) {
104
- tlsSocket.destroy();
105
- }
106
106
  });
107
107
 
108
- // The TLS socket will now emit HTTP traffic that can be processed
109
- // In a real implementation, we would create an HTTP parser and handle
110
- // the requests here, but for simplicity, we'll just forward the data
108
+ // Set up error handling with our cleanup utility
109
+ setupSocketHandlers(tlsSocket, handleClose, 'tls');
110
+
111
+ // Set timeout
112
+ const timeout = this.getTimeout();
113
+ tlsSocket.setTimeout(timeout);
114
+
115
+ tlsSocket.on('timeout', () => {
116
+ this.emit(ForwardingHandlerEvents.ERROR, {
117
+ remoteAddress,
118
+ error: 'TLS connection timeout'
119
+ });
120
+ handleClose('timeout');
121
+ });
111
122
 
112
123
  // Get the target from configuration
113
124
  const target = this.getTargetFromConfig();
114
125
 
115
126
  // Set up the connection to the HTTPS backend
116
127
  const connectToBackend = () => {
117
- const backendSocket = plugins.tls.connect({
128
+ backendSocket = plugins.tls.connect({
118
129
  host: target.host,
119
130
  port: target.port,
120
131
  // In a real implementation, we would configure TLS options
@@ -127,30 +138,29 @@ export class HttpsTerminateToHttpsHandler extends ForwardingHandler {
127
138
  });
128
139
 
129
140
  // Set up bidirectional data flow
130
- tlsSocket.pipe(backendSocket);
131
- backendSocket.pipe(tlsSocket);
141
+ tlsSocket.pipe(backendSocket!);
142
+ backendSocket!.pipe(tlsSocket);
132
143
  });
133
144
 
145
+ // Update the cleanup handler with the backend socket
146
+ const newHandleClose = createSocketCleanupHandler(tlsSocket, backendSocket, (reason) => {
147
+ this.emit(ForwardingHandlerEvents.DISCONNECTED, {
148
+ remoteAddress,
149
+ reason
150
+ });
151
+ });
152
+
153
+ // Set up handlers for backend socket
154
+ setupSocketHandlers(backendSocket, newHandleClose, 'backend');
155
+
134
156
  backendSocket.on('error', (error) => {
135
157
  this.emit(ForwardingHandlerEvents.ERROR, {
136
158
  remoteAddress,
137
159
  error: `Backend connection error: ${error.message}`
138
160
  });
139
-
140
- if (!tlsSocket.destroyed) {
141
- tlsSocket.destroy();
142
- }
143
- });
144
-
145
- // Handle close
146
- backendSocket.on('close', () => {
147
- if (!tlsSocket.destroyed) {
148
- tlsSocket.destroy();
149
- }
150
161
  });
151
162
 
152
- // Set timeout
153
- const timeout = this.getTimeout();
163
+ // Set timeout for backend socket
154
164
  backendSocket.setTimeout(timeout);
155
165
 
156
166
  backendSocket.on('timeout', () => {
@@ -158,10 +168,7 @@ export class HttpsTerminateToHttpsHandler extends ForwardingHandler {
158
168
  remoteAddress,
159
169
  error: 'Backend connection timeout'
160
170
  });
161
-
162
- if (!backendSocket.destroyed) {
163
- backendSocket.destroy();
164
- }
171
+ newHandleClose('backend_timeout');
165
172
  });
166
173
  };
167
174
 
@@ -169,28 +176,6 @@ export class HttpsTerminateToHttpsHandler extends ForwardingHandler {
169
176
  tlsSocket.on('secure', () => {
170
177
  connectToBackend();
171
178
  });
172
-
173
- // Handle close
174
- tlsSocket.on('close', () => {
175
- this.emit(ForwardingHandlerEvents.DISCONNECTED, {
176
- remoteAddress
177
- });
178
- });
179
-
180
- // Set timeout
181
- const timeout = this.getTimeout();
182
- tlsSocket.setTimeout(timeout);
183
-
184
- tlsSocket.on('timeout', () => {
185
- this.emit(ForwardingHandlerEvents.ERROR, {
186
- remoteAddress,
187
- error: 'TLS connection timeout'
188
- });
189
-
190
- if (!tlsSocket.destroyed) {
191
- tlsSocket.destroy();
192
- }
193
- });
194
179
  }
195
180
 
196
181
  /**
@@ -1,5 +1,6 @@
1
1
  import * as plugins from '../../plugins.js';
2
2
  import { type IHttpProxyOptions, type IConnectionEntry, type ILogger, createLogger } from './models/types.js';
3
+ import { cleanupSocket } from '../../core/utils/socket-utils.js';
3
4
 
4
5
  /**
5
6
  * Manages a pool of backend connections for efficient reuse
@@ -133,14 +134,7 @@ export class ConnectionPool {
133
134
  if ((connection.isIdle && now - connection.lastUsed > idleTimeout) ||
134
135
  connections.length > (this.options.connectionPoolSize || 50)) {
135
136
 
136
- try {
137
- if (!connection.socket.destroyed) {
138
- connection.socket.end();
139
- connection.socket.destroy();
140
- }
141
- } catch (err) {
142
- this.logger.error(`Error destroying pooled connection to ${host}`, err);
143
- }
137
+ cleanupSocket(connection.socket, `pool-${host}-idle`);
144
138
 
145
139
  connections.shift(); // Remove from pool
146
140
  removed++;
@@ -170,14 +164,7 @@ export class ConnectionPool {
170
164
  this.logger.debug(`Closing ${connections.length} connections to ${host}`);
171
165
 
172
166
  for (const connection of connections) {
173
- try {
174
- if (!connection.socket.destroyed) {
175
- connection.socket.end();
176
- connection.socket.destroy();
177
- }
178
- } catch (error) {
179
- this.logger.error(`Error closing connection to ${host}:`, error);
180
- }
167
+ cleanupSocket(connection.socket, `pool-${host}-close`);
181
168
  }
182
169
  }
183
170
 
@@ -18,6 +18,7 @@ import { RequestHandler, type IMetricsTracker } from './request-handler.js';
18
18
  import { WebSocketHandler } from './websocket-handler.js';
19
19
  import { ProxyRouter } from '../../routing/router/index.js';
20
20
  import { RouteRouter } from '../../routing/router/route-router.js';
21
+ import { cleanupSocket } from '../../core/utils/socket-utils.js';
21
22
  import { FunctionCache } from './function-cache.js';
22
23
 
23
24
  /**
@@ -520,11 +521,7 @@ export class HttpProxy implements IMetricsTracker {
520
521
 
521
522
  // Close all tracked sockets
522
523
  for (const socket of this.socketMap.getArray()) {
523
- try {
524
- socket.destroy();
525
- } catch (error) {
526
- this.logger.error('Error destroying socket', error);
527
- }
524
+ cleanupSocket(socket, 'http-proxy-stop');
528
525
  }
529
526
 
530
527
  // Close all connection pool connections