@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
@@ -4,6 +4,7 @@ import { SecurityManager } from './security-manager.js';
4
4
  import { TimeoutManager } from './timeout-manager.js';
5
5
  import { logger } from '../../core/utils/logger.js';
6
6
  import { LifecycleComponent } from '../../core/utils/lifecycle-component.js';
7
+ import { cleanupSocket } from '../../core/utils/socket-utils.js';
7
8
 
8
9
  /**
9
10
  * Manages connection lifecycle, tracking, and cleanup with performance optimizations
@@ -278,10 +279,10 @@ export class ConnectionManager extends LifecycleComponent {
278
279
  }
279
280
 
280
281
  // Handle socket cleanup without delay
281
- this.cleanupSocketImmediate(record, 'incoming', record.incoming);
282
+ cleanupSocket(record.incoming, `${record.id}-incoming`);
282
283
 
283
284
  if (record.outgoing) {
284
- this.cleanupSocketImmediate(record, 'outgoing', record.outgoing);
285
+ cleanupSocket(record.outgoing, `${record.id}-outgoing`);
285
286
  }
286
287
 
287
288
  // Clear pendingData to avoid memory leaks
@@ -313,23 +314,6 @@ export class ConnectionManager extends LifecycleComponent {
313
314
  }
314
315
  }
315
316
 
316
- /**
317
- * Helper method to clean up a socket immediately
318
- */
319
- private cleanupSocketImmediate(record: IConnectionRecord, side: 'incoming' | 'outgoing', socket: plugins.net.Socket): void {
320
- try {
321
- if (!socket.destroyed) {
322
- socket.destroy();
323
- }
324
- } catch (err) {
325
- logger.log('error', `Error destroying ${side} socket: ${err}`, {
326
- connectionId: record.id,
327
- side,
328
- error: err,
329
- component: 'connection-manager'
330
- });
331
- }
332
- }
333
317
 
334
318
  /**
335
319
  * Creates a generic error handler for incoming or outgoing sockets
@@ -552,19 +536,13 @@ export class ConnectionManager extends LifecycleComponent {
552
536
  record.cleanupTimer = undefined;
553
537
  }
554
538
 
555
- // Immediate destruction
539
+ // Immediate destruction using socket-utils
556
540
  if (record.incoming) {
557
- record.incoming.removeAllListeners();
558
- if (!record.incoming.destroyed) {
559
- record.incoming.destroy();
560
- }
541
+ cleanupSocket(record.incoming, `${record.id}-incoming-shutdown`);
561
542
  }
562
543
 
563
544
  if (record.outgoing) {
564
- record.outgoing.removeAllListeners();
565
- if (!record.outgoing.destroyed) {
566
- record.outgoing.destroy();
567
- }
545
+ cleanupSocket(record.outgoing, `${record.id}-outgoing-shutdown`);
568
546
  }
569
547
  } catch (err) {
570
548
  logger.log('error', `Error during connection cleanup: ${err}`, {
@@ -128,10 +128,24 @@ export class HttpProxyBridge {
128
128
  proxySocket.pipe(socket);
129
129
 
130
130
  // Handle cleanup
131
+ let cleanedUp = false;
131
132
  const cleanup = (reason: string) => {
133
+ if (cleanedUp) return;
134
+ cleanedUp = true;
135
+
136
+ // Remove all event listeners to prevent memory leaks
137
+ socket.removeAllListeners('end');
138
+ socket.removeAllListeners('error');
139
+ proxySocket.removeAllListeners('end');
140
+ proxySocket.removeAllListeners('error');
141
+
132
142
  socket.unpipe(proxySocket);
133
143
  proxySocket.unpipe(socket);
134
- proxySocket.destroy();
144
+
145
+ if (!proxySocket.destroyed) {
146
+ proxySocket.destroy();
147
+ }
148
+
135
149
  cleanupCallback(reason);
136
150
  };
137
151
 
@@ -2,6 +2,7 @@ import * as plugins from '../../plugins.js';
2
2
  import type { ISmartProxyOptions } from './models/interfaces.js';
3
3
  import { RouteConnectionHandler } from './route-connection-handler.js';
4
4
  import { logger } from '../../core/utils/logger.js';
5
+ import { cleanupSocket } from '../../core/utils/socket-utils.js';
5
6
 
6
7
  /**
7
8
  * PortManager handles the dynamic creation and removal of port listeners
@@ -64,8 +65,7 @@ export class PortManager {
64
65
  const server = plugins.net.createServer((socket) => {
65
66
  // Check if shutting down
66
67
  if (this.isShuttingDown) {
67
- socket.end();
68
- socket.destroy();
68
+ cleanupSocket(socket, 'port-manager-shutdown');
69
69
  return;
70
70
  }
71
71
 
@@ -9,7 +9,7 @@ import { TlsManager } from './tls-manager.js';
9
9
  import { HttpProxyBridge } from './http-proxy-bridge.js';
10
10
  import { TimeoutManager } from './timeout-manager.js';
11
11
  import { RouteManager } from './route-manager.js';
12
- import type { ForwardingHandler } from '../../forwarding/handlers/base-handler.js';
12
+ import { cleanupSocket } from '../../core/utils/socket-utils.js';
13
13
 
14
14
  /**
15
15
  * Handles new connection processing and setup logic with support for route-based configuration
@@ -84,8 +84,7 @@ export class RouteConnectionHandler {
84
84
  const ipValidation = this.securityManager.validateIP(remoteIP);
85
85
  if (!ipValidation.allowed) {
86
86
  logger.log('warn', `Connection rejected`, { remoteIP, reason: ipValidation.reason, component: 'route-handler' });
87
- socket.end();
88
- socket.destroy();
87
+ cleanupSocket(socket, `rejected-${ipValidation.reason}`);
89
88
  return;
90
89
  }
91
90
 
@@ -822,6 +821,38 @@ export class RouteConnectionHandler {
822
821
  return;
823
822
  }
824
823
 
824
+ // Track event listeners added by the handler so we can clean them up
825
+ const originalOn = socket.on.bind(socket);
826
+ const originalOnce = socket.once.bind(socket);
827
+ const trackedListeners: Array<{event: string; listener: (...args: any[]) => void}> = [];
828
+
829
+ // Override socket.on to track listeners
830
+ socket.on = function(event: string, listener: (...args: any[]) => void) {
831
+ trackedListeners.push({event, listener});
832
+ return originalOn(event, listener);
833
+ } as any;
834
+
835
+ // Override socket.once to track listeners
836
+ socket.once = function(event: string, listener: (...args: any[]) => void) {
837
+ trackedListeners.push({event, listener});
838
+ return originalOnce(event, listener);
839
+ } as any;
840
+
841
+ // Set up automatic cleanup when socket closes
842
+ const cleanupHandler = () => {
843
+ // Remove all tracked listeners
844
+ for (const {event, listener} of trackedListeners) {
845
+ socket.removeListener(event, listener);
846
+ }
847
+ // Restore original methods
848
+ socket.on = originalOn;
849
+ socket.once = originalOnce;
850
+ };
851
+
852
+ // Listen for socket close to trigger cleanup
853
+ originalOnce('close', cleanupHandler);
854
+ originalOnce('error', cleanupHandler);
855
+
825
856
  // Create route context for the handler
826
857
  const routeContext = this.createRouteContext({
827
858
  connectionId: record.id,
@@ -855,6 +886,8 @@ export class RouteConnectionHandler {
855
886
  error: error.message,
856
887
  component: 'route-handler'
857
888
  });
889
+ // Remove all event listeners before destroying to prevent memory leaks
890
+ socket.removeAllListeners();
858
891
  if (!socket.destroyed) {
859
892
  socket.destroy();
860
893
  }
@@ -875,6 +908,8 @@ export class RouteConnectionHandler {
875
908
  error: error.message,
876
909
  component: 'route-handler'
877
910
  });
911
+ // Remove all event listeners before destroying to prevent memory leaks
912
+ socket.removeAllListeners();
878
913
  if (!socket.destroyed) {
879
914
  socket.destroy();
880
915
  }
@@ -1229,7 +1264,7 @@ export class RouteConnectionHandler {
1229
1264
  connectionId,
1230
1265
  serverName,
1231
1266
  connInfo,
1232
- (connectionId, reason) => this.connectionManager.initiateCleanupOnce(record, reason)
1267
+ (_connectionId, reason) => this.connectionManager.initiateCleanupOnce(record, reason)
1233
1268
  );
1234
1269
 
1235
1270
  // Store the handler in the connection record so we can remove it during cleanup