@push.rocks/smartproxy 21.1.7 → 22.6.0

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 (155) hide show
  1. package/changelog.md +109 -0
  2. package/dist_rust/rustproxy +0 -0
  3. package/dist_ts/00_commitinfo_data.js +1 -1
  4. package/dist_ts/core/utils/shared-security-manager.d.ts +17 -0
  5. package/dist_ts/core/utils/shared-security-manager.js +66 -1
  6. package/dist_ts/index.d.ts +1 -5
  7. package/dist_ts/index.js +3 -9
  8. package/dist_ts/protocols/common/fragment-handler.js +5 -1
  9. package/dist_ts/proxies/http-proxy/default-certificates.d.ts +54 -0
  10. package/dist_ts/proxies/http-proxy/default-certificates.js +127 -0
  11. package/dist_ts/proxies/http-proxy/http-proxy.d.ts +1 -1
  12. package/dist_ts/proxies/http-proxy/http-proxy.js +9 -14
  13. package/dist_ts/proxies/http-proxy/index.d.ts +5 -1
  14. package/dist_ts/proxies/http-proxy/index.js +6 -2
  15. package/dist_ts/proxies/http-proxy/security-manager.d.ts +4 -12
  16. package/dist_ts/proxies/http-proxy/security-manager.js +66 -99
  17. package/dist_ts/proxies/index.d.ts +1 -5
  18. package/dist_ts/proxies/index.js +2 -6
  19. package/dist_ts/proxies/nftables-proxy/index.d.ts +1 -0
  20. package/dist_ts/proxies/nftables-proxy/index.js +2 -1
  21. package/dist_ts/proxies/nftables-proxy/nftables-proxy.d.ts +4 -26
  22. package/dist_ts/proxies/nftables-proxy/nftables-proxy.js +84 -236
  23. package/dist_ts/proxies/nftables-proxy/utils/index.d.ts +9 -0
  24. package/dist_ts/proxies/nftables-proxy/utils/index.js +12 -0
  25. package/dist_ts/proxies/nftables-proxy/utils/nft-command-executor.d.ts +66 -0
  26. package/dist_ts/proxies/nftables-proxy/utils/nft-command-executor.js +131 -0
  27. package/dist_ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.d.ts +39 -0
  28. package/dist_ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.js +112 -0
  29. package/dist_ts/proxies/nftables-proxy/utils/nft-rule-validator.d.ts +59 -0
  30. package/dist_ts/proxies/nftables-proxy/utils/nft-rule-validator.js +130 -0
  31. package/dist_ts/proxies/smart-proxy/certificate-manager.js +4 -3
  32. package/dist_ts/proxies/smart-proxy/connection-manager.d.ts +13 -2
  33. package/dist_ts/proxies/smart-proxy/connection-manager.js +16 -6
  34. package/dist_ts/proxies/smart-proxy/http-proxy-bridge.js +35 -10
  35. package/dist_ts/proxies/smart-proxy/index.d.ts +5 -10
  36. package/dist_ts/proxies/smart-proxy/index.js +7 -13
  37. package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +5 -3
  38. package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +17 -0
  39. package/dist_ts/proxies/smart-proxy/route-connection-handler.js +72 -9
  40. package/dist_ts/proxies/smart-proxy/route-preprocessor.d.ts +37 -0
  41. package/dist_ts/proxies/smart-proxy/route-preprocessor.js +103 -0
  42. package/dist_ts/proxies/smart-proxy/rust-binary-locator.d.ts +23 -0
  43. package/dist_ts/proxies/smart-proxy/rust-binary-locator.js +104 -0
  44. package/dist_ts/proxies/smart-proxy/rust-metrics-adapter.d.ts +74 -0
  45. package/dist_ts/proxies/smart-proxy/rust-metrics-adapter.js +146 -0
  46. package/dist_ts/proxies/smart-proxy/rust-proxy-bridge.d.ts +49 -0
  47. package/dist_ts/proxies/smart-proxy/rust-proxy-bridge.js +259 -0
  48. package/dist_ts/proxies/smart-proxy/security-manager.d.ts +14 -12
  49. package/dist_ts/proxies/smart-proxy/security-manager.js +80 -74
  50. package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +39 -157
  51. package/dist_ts/proxies/smart-proxy/smart-proxy.js +224 -622
  52. package/dist_ts/proxies/smart-proxy/socket-handler-server.d.ts +45 -0
  53. package/dist_ts/proxies/smart-proxy/socket-handler-server.js +253 -0
  54. package/dist_ts/proxies/smart-proxy/tls-manager.d.ts +2 -9
  55. package/dist_ts/proxies/smart-proxy/tls-manager.js +3 -26
  56. package/dist_ts/proxies/smart-proxy/utils/index.d.ts +1 -1
  57. package/dist_ts/proxies/smart-proxy/utils/index.js +3 -4
  58. package/dist_ts/proxies/smart-proxy/utils/route-helpers/api-helpers.d.ts +49 -0
  59. package/dist_ts/proxies/smart-proxy/utils/route-helpers/api-helpers.js +108 -0
  60. package/dist_ts/proxies/smart-proxy/utils/route-helpers/dynamic-helpers.d.ts +57 -0
  61. package/dist_ts/proxies/smart-proxy/utils/route-helpers/dynamic-helpers.js +89 -0
  62. package/dist_ts/proxies/smart-proxy/utils/route-helpers/http-helpers.d.ts +17 -0
  63. package/dist_ts/proxies/smart-proxy/utils/route-helpers/http-helpers.js +32 -0
  64. package/dist_ts/proxies/smart-proxy/utils/route-helpers/https-helpers.d.ts +68 -0
  65. package/dist_ts/proxies/smart-proxy/utils/route-helpers/https-helpers.js +117 -0
  66. package/dist_ts/proxies/smart-proxy/utils/route-helpers/index.d.ts +17 -0
  67. package/dist_ts/proxies/smart-proxy/utils/route-helpers/index.js +27 -0
  68. package/dist_ts/proxies/smart-proxy/utils/route-helpers/load-balancer-helpers.d.ts +63 -0
  69. package/dist_ts/proxies/smart-proxy/utils/route-helpers/load-balancer-helpers.js +105 -0
  70. package/dist_ts/proxies/smart-proxy/utils/route-helpers/nftables-helpers.d.ts +83 -0
  71. package/dist_ts/proxies/smart-proxy/utils/route-helpers/nftables-helpers.js +126 -0
  72. package/dist_ts/proxies/smart-proxy/utils/route-helpers/security-helpers.d.ts +47 -0
  73. package/dist_ts/proxies/smart-proxy/utils/route-helpers/security-helpers.js +66 -0
  74. package/dist_ts/proxies/smart-proxy/utils/route-helpers/socket-handlers.d.ts +70 -0
  75. package/dist_ts/proxies/smart-proxy/utils/route-helpers/socket-handlers.js +287 -0
  76. package/dist_ts/proxies/smart-proxy/utils/route-helpers/websocket-helpers.d.ts +46 -0
  77. package/dist_ts/proxies/smart-proxy/utils/route-helpers/websocket-helpers.js +67 -0
  78. package/dist_ts/proxies/smart-proxy/utils/route-helpers.d.ts +4 -457
  79. package/dist_ts/proxies/smart-proxy/utils/route-helpers.js +6 -950
  80. package/dist_ts/proxies/smart-proxy/utils/route-utils.js +2 -2
  81. package/dist_ts/proxies/smart-proxy/utils/route-validator.d.ts +67 -1
  82. package/dist_ts/proxies/smart-proxy/utils/route-validator.js +251 -3
  83. package/dist_ts/routing/index.d.ts +1 -1
  84. package/dist_ts/routing/index.js +3 -3
  85. package/dist_ts/routing/models/http-types.d.ts +119 -4
  86. package/dist_ts/routing/models/http-types.js +93 -5
  87. package/npmextra.json +12 -6
  88. package/package.json +34 -24
  89. package/readme.hints.md +184 -1
  90. package/readme.md +580 -266
  91. package/ts/00_commitinfo_data.ts +1 -1
  92. package/ts/core/utils/shared-security-manager.ts +98 -13
  93. package/ts/index.ts +4 -12
  94. package/ts/protocols/common/fragment-handler.ts +4 -0
  95. package/ts/proxies/index.ts +1 -9
  96. package/ts/proxies/nftables-proxy/index.ts +1 -0
  97. package/ts/proxies/nftables-proxy/nftables-proxy.ts +116 -290
  98. package/ts/proxies/nftables-proxy/utils/index.ts +38 -0
  99. package/ts/proxies/nftables-proxy/utils/nft-command-executor.ts +162 -0
  100. package/ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.ts +125 -0
  101. package/ts/proxies/nftables-proxy/utils/nft-rule-validator.ts +156 -0
  102. package/ts/proxies/smart-proxy/index.ts +6 -13
  103. package/ts/proxies/smart-proxy/models/interfaces.ts +6 -5
  104. package/ts/proxies/smart-proxy/route-preprocessor.ts +122 -0
  105. package/ts/proxies/smart-proxy/rust-binary-locator.ts +112 -0
  106. package/ts/proxies/smart-proxy/rust-metrics-adapter.ts +161 -0
  107. package/ts/proxies/smart-proxy/rust-proxy-bridge.ts +310 -0
  108. package/ts/proxies/smart-proxy/smart-proxy.ts +282 -800
  109. package/ts/proxies/smart-proxy/socket-handler-server.ts +279 -0
  110. package/ts/proxies/smart-proxy/utils/index.ts +3 -5
  111. package/ts/proxies/smart-proxy/utils/route-helpers/api-helpers.ts +144 -0
  112. package/ts/proxies/smart-proxy/utils/route-helpers/dynamic-helpers.ts +124 -0
  113. package/ts/proxies/smart-proxy/utils/route-helpers/http-helpers.ts +40 -0
  114. package/ts/proxies/smart-proxy/utils/route-helpers/https-helpers.ts +163 -0
  115. package/ts/proxies/smart-proxy/utils/route-helpers/index.ts +62 -0
  116. package/ts/proxies/smart-proxy/utils/route-helpers/load-balancer-helpers.ts +154 -0
  117. package/ts/proxies/smart-proxy/utils/route-helpers/nftables-helpers.ts +202 -0
  118. package/ts/proxies/smart-proxy/utils/route-helpers/security-helpers.ts +96 -0
  119. package/ts/proxies/smart-proxy/utils/route-helpers/socket-handlers.ts +337 -0
  120. package/ts/proxies/smart-proxy/utils/route-helpers/websocket-helpers.ts +98 -0
  121. package/ts/proxies/smart-proxy/utils/route-helpers.ts +5 -1302
  122. package/ts/proxies/smart-proxy/utils/route-utils.ts +1 -1
  123. package/ts/proxies/smart-proxy/utils/route-validator.ts +274 -4
  124. package/ts/routing/index.ts +2 -2
  125. package/ts/routing/models/http-types.ts +147 -4
  126. package/ts/proxies/http-proxy/certificate-manager.ts +0 -244
  127. package/ts/proxies/http-proxy/connection-pool.ts +0 -228
  128. package/ts/proxies/http-proxy/context-creator.ts +0 -145
  129. package/ts/proxies/http-proxy/function-cache.ts +0 -279
  130. package/ts/proxies/http-proxy/handlers/index.ts +0 -5
  131. package/ts/proxies/http-proxy/http-proxy.ts +0 -675
  132. package/ts/proxies/http-proxy/http-request-handler.ts +0 -331
  133. package/ts/proxies/http-proxy/http2-request-handler.ts +0 -255
  134. package/ts/proxies/http-proxy/index.ts +0 -13
  135. package/ts/proxies/http-proxy/models/http-types.ts +0 -148
  136. package/ts/proxies/http-proxy/models/index.ts +0 -5
  137. package/ts/proxies/http-proxy/models/types.ts +0 -125
  138. package/ts/proxies/http-proxy/request-handler.ts +0 -878
  139. package/ts/proxies/http-proxy/security-manager.ts +0 -433
  140. package/ts/proxies/http-proxy/websocket-handler.ts +0 -581
  141. package/ts/proxies/smart-proxy/acme-state-manager.ts +0 -112
  142. package/ts/proxies/smart-proxy/cert-store.ts +0 -92
  143. package/ts/proxies/smart-proxy/certificate-manager.ts +0 -894
  144. package/ts/proxies/smart-proxy/connection-manager.ts +0 -796
  145. package/ts/proxies/smart-proxy/http-proxy-bridge.ts +0 -187
  146. package/ts/proxies/smart-proxy/metrics-collector.ts +0 -453
  147. package/ts/proxies/smart-proxy/nftables-manager.ts +0 -271
  148. package/ts/proxies/smart-proxy/port-manager.ts +0 -358
  149. package/ts/proxies/smart-proxy/route-connection-handler.ts +0 -1640
  150. package/ts/proxies/smart-proxy/route-orchestrator.ts +0 -297
  151. package/ts/proxies/smart-proxy/security-manager.ts +0 -257
  152. package/ts/proxies/smart-proxy/throughput-tracker.ts +0 -138
  153. package/ts/proxies/smart-proxy/timeout-manager.ts +0 -196
  154. package/ts/proxies/smart-proxy/tls-manager.ts +0 -207
  155. package/ts/proxies/smart-proxy/utils/route-validators.ts +0 -283
@@ -1,244 +0,0 @@
1
- import * as plugins from '../../plugins.js';
2
- import * as fs from 'fs';
3
- import * as path from 'path';
4
- import { fileURLToPath } from 'url';
5
- import { AsyncFileSystem } from '../../core/utils/fs-utils.js';
6
- import { type IHttpProxyOptions, type ICertificateEntry, type ILogger, createLogger } from './models/types.js';
7
- import type { IRouteConfig } from '../smart-proxy/models/route-types.js';
8
-
9
- /**
10
- * @deprecated This class is deprecated. Use SmartCertManager instead.
11
- *
12
- * This is a stub implementation that maintains backward compatibility
13
- * while the functionality has been moved to SmartCertManager.
14
- */
15
- export class CertificateManager {
16
- private defaultCertificates: { key: string; cert: string };
17
- private certificateCache: Map<string, ICertificateEntry> = new Map();
18
- private certificateStoreDir: string;
19
- private logger: ILogger;
20
- private httpsServer: plugins.https.Server | null = null;
21
- private initialized = false;
22
-
23
- constructor(private options: IHttpProxyOptions) {
24
- this.certificateStoreDir = path.resolve(options.acme?.certificateStore || './certs');
25
- this.logger = createLogger(options.logLevel || 'info');
26
-
27
- this.logger.warn('CertificateManager is deprecated - use SmartCertManager instead');
28
-
29
- // Initialize synchronously for backward compatibility but log warning
30
- this.initializeSync();
31
- }
32
-
33
- /**
34
- * Synchronous initialization for backward compatibility
35
- * @deprecated This uses sync filesystem operations which block the event loop
36
- */
37
- private initializeSync(): void {
38
- // Ensure certificate store directory exists
39
- try {
40
- if (!fs.existsSync(this.certificateStoreDir)) {
41
- fs.mkdirSync(this.certificateStoreDir, { recursive: true });
42
- this.logger.info(`Created certificate store directory: ${this.certificateStoreDir}`);
43
- }
44
- } catch (error) {
45
- this.logger.warn(`Failed to create certificate store directory: ${error}`);
46
- }
47
-
48
- this.loadDefaultCertificates();
49
- }
50
-
51
- /**
52
- * Async initialization - preferred method
53
- */
54
- public async initialize(): Promise<void> {
55
- if (this.initialized) return;
56
-
57
- // Ensure certificate store directory exists
58
- try {
59
- await AsyncFileSystem.ensureDir(this.certificateStoreDir);
60
- this.logger.info(`Ensured certificate store directory: ${this.certificateStoreDir}`);
61
- } catch (error) {
62
- this.logger.warn(`Failed to create certificate store directory: ${error}`);
63
- }
64
-
65
- await this.loadDefaultCertificatesAsync();
66
- this.initialized = true;
67
- }
68
-
69
- /**
70
- * Loads default certificates from the filesystem
71
- * @deprecated This uses sync filesystem operations which block the event loop
72
- */
73
- public loadDefaultCertificates(): void {
74
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
75
- const certPath = path.join(__dirname, '..', '..', '..', 'assets', 'certs');
76
-
77
- try {
78
- this.defaultCertificates = {
79
- key: fs.readFileSync(path.join(certPath, 'key.pem'), 'utf8'),
80
- cert: fs.readFileSync(path.join(certPath, 'cert.pem'), 'utf8')
81
- };
82
- this.logger.info('Loaded default certificates from filesystem (sync - deprecated)');
83
- } catch (error) {
84
- this.logger.error(`Failed to load default certificates: ${error}`);
85
- this.generateSelfSignedCertificate();
86
- }
87
- }
88
-
89
- /**
90
- * Loads default certificates from the filesystem asynchronously
91
- */
92
- public async loadDefaultCertificatesAsync(): Promise<void> {
93
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
94
- const certPath = path.join(__dirname, '..', '..', '..', 'assets', 'certs');
95
-
96
- try {
97
- const [key, cert] = await Promise.all([
98
- AsyncFileSystem.readFile(path.join(certPath, 'key.pem')),
99
- AsyncFileSystem.readFile(path.join(certPath, 'cert.pem'))
100
- ]);
101
-
102
- this.defaultCertificates = { key, cert };
103
- this.logger.info('Loaded default certificates from filesystem (async)');
104
- } catch (error) {
105
- this.logger.error(`Failed to load default certificates: ${error}`);
106
- this.generateSelfSignedCertificate();
107
- }
108
- }
109
-
110
- /**
111
- * Generates self-signed certificates as fallback
112
- */
113
- private generateSelfSignedCertificate(): void {
114
- // Generate a self-signed certificate using forge or similar
115
- // For now, just use a placeholder
116
- const selfSignedCert = `-----BEGIN CERTIFICATE-----
117
- MIIBkTCB+wIJAKHHIgIIA0/cMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNVBAYTAlVT
118
- MB4XDTE0MDEwMTAwMDAwMFoXDTI0MDEwMTAwMDAwMFowDTELMAkGA1UEBhMCVVMw
119
- gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMRiH0VwnOH3jCV7c6JFZWYrvuqy
120
- -----END CERTIFICATE-----`;
121
-
122
- const selfSignedKey = `-----BEGIN PRIVATE KEY-----
123
- MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMRiH0VwnOH3jCV7
124
- c6JFZWYrvuqyALCLXj0pcr1iqNdHjegNXnkl5zjdaUjq4edNOKl7M1AlFiYjG2xk
125
- -----END PRIVATE KEY-----`;
126
-
127
- this.defaultCertificates = {
128
- key: selfSignedKey,
129
- cert: selfSignedCert
130
- };
131
-
132
- this.logger.warn('Using self-signed certificate as fallback');
133
- }
134
-
135
- /**
136
- * Gets the default certificates
137
- */
138
- public getDefaultCertificates(): { key: string; cert: string } {
139
- return this.defaultCertificates;
140
- }
141
-
142
- /**
143
- * @deprecated Use SmartCertManager instead
144
- */
145
- public setExternalPort80Handler(handler: any): void {
146
- this.logger.warn('setExternalPort80Handler is deprecated - use SmartCertManager instead');
147
- }
148
-
149
- /**
150
- * @deprecated Use SmartCertManager instead
151
- */
152
- public async updateRoutes(routes: IRouteConfig[]): Promise<void> {
153
- this.logger.warn('updateRoutes is deprecated - use SmartCertManager instead');
154
- }
155
-
156
- /**
157
- * Handles SNI callback to provide appropriate certificate
158
- */
159
- public handleSNI(domain: string, cb: (err: Error | null, ctx: plugins.tls.SecureContext) => void): void {
160
- const certificate = this.getCachedCertificate(domain);
161
-
162
- if (certificate) {
163
- const context = plugins.tls.createSecureContext({
164
- key: certificate.key,
165
- cert: certificate.cert
166
- });
167
- cb(null, context);
168
- return;
169
- }
170
-
171
- // Use default certificate if no domain-specific certificate found
172
- const defaultContext = plugins.tls.createSecureContext({
173
- key: this.defaultCertificates.key,
174
- cert: this.defaultCertificates.cert
175
- });
176
- cb(null, defaultContext);
177
- }
178
-
179
- /**
180
- * Updates a certificate in the cache
181
- */
182
- public updateCertificate(domain: string, cert: string, key: string): void {
183
- this.certificateCache.set(domain, {
184
- cert,
185
- key,
186
- expires: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000) // 90 days
187
- });
188
-
189
- this.logger.info(`Certificate updated for ${domain}`);
190
- }
191
-
192
- /**
193
- * Gets a cached certificate
194
- */
195
- private getCachedCertificate(domain: string): ICertificateEntry | null {
196
- return this.certificateCache.get(domain) || null;
197
- }
198
-
199
- /**
200
- * @deprecated Use SmartCertManager instead
201
- */
202
- public async initializePort80Handler(): Promise<any> {
203
- this.logger.warn('initializePort80Handler is deprecated - use SmartCertManager instead');
204
- return null;
205
- }
206
-
207
- /**
208
- * @deprecated Use SmartCertManager instead
209
- */
210
- public async stopPort80Handler(): Promise<void> {
211
- this.logger.warn('stopPort80Handler is deprecated - use SmartCertManager instead');
212
- }
213
-
214
- /**
215
- * @deprecated Use SmartCertManager instead
216
- */
217
- public registerDomainsWithPort80Handler(domains: string[]): void {
218
- this.logger.warn('registerDomainsWithPort80Handler is deprecated - use SmartCertManager instead');
219
- }
220
-
221
- /**
222
- * @deprecated Use SmartCertManager instead
223
- */
224
- public registerRoutesWithPort80Handler(routes: IRouteConfig[]): void {
225
- this.logger.warn('registerRoutesWithPort80Handler is deprecated - use SmartCertManager instead');
226
- }
227
-
228
- /**
229
- * Sets the HTTPS server for certificate updates
230
- */
231
- public setHttpsServer(server: plugins.https.Server): void {
232
- this.httpsServer = server;
233
- }
234
-
235
- /**
236
- * Gets statistics for metrics
237
- */
238
- public getStats() {
239
- return {
240
- cachedCertificates: this.certificateCache.size,
241
- defaultCertEnabled: true
242
- };
243
- }
244
- }
@@ -1,228 +0,0 @@
1
- import * as plugins from '../../plugins.js';
2
- import { type IHttpProxyOptions, type IConnectionEntry, type ILogger, createLogger } from './models/types.js';
3
- import { cleanupSocket } from '../../core/utils/socket-utils.js';
4
-
5
- /**
6
- * Manages a pool of backend connections for efficient reuse
7
- */
8
- export class ConnectionPool {
9
- private connectionPool: Map<string, Array<IConnectionEntry>> = new Map();
10
- private roundRobinPositions: Map<string, number> = new Map();
11
- private logger: ILogger;
12
-
13
- constructor(private options: IHttpProxyOptions) {
14
- this.logger = createLogger(options.logLevel || 'info');
15
- }
16
-
17
- /**
18
- * Get a connection from the pool or create a new one
19
- */
20
- public getConnection(host: string, port: number): Promise<plugins.net.Socket> {
21
- return new Promise((resolve, reject) => {
22
- const poolKey = `${host}:${port}`;
23
- const connectionList = this.connectionPool.get(poolKey) || [];
24
-
25
- // Look for an idle connection
26
- const idleConnectionIndex = connectionList.findIndex(c => c.isIdle);
27
-
28
- if (idleConnectionIndex >= 0) {
29
- // Get existing connection from pool
30
- const connection = connectionList[idleConnectionIndex];
31
- connection.isIdle = false;
32
- connection.lastUsed = Date.now();
33
- this.logger.debug(`Reusing connection from pool for ${poolKey}`);
34
-
35
- // Update the pool
36
- this.connectionPool.set(poolKey, connectionList);
37
-
38
- resolve(connection.socket);
39
- return;
40
- }
41
-
42
- // No idle connection available, create a new one if pool isn't full
43
- const poolSize = this.options.connectionPoolSize || 50;
44
- if (connectionList.length < poolSize) {
45
- this.logger.debug(`Creating new connection to ${host}:${port}`);
46
-
47
- try {
48
- const socket = plugins.net.connect({
49
- host,
50
- port,
51
- keepAlive: true,
52
- keepAliveInitialDelay: 30000 // 30 seconds
53
- });
54
-
55
- socket.once('connect', () => {
56
- // Add to connection pool
57
- const connection = {
58
- socket,
59
- lastUsed: Date.now(),
60
- isIdle: false
61
- };
62
-
63
- connectionList.push(connection);
64
- this.connectionPool.set(poolKey, connectionList);
65
-
66
- // Setup cleanup when the connection is closed
67
- socket.once('close', () => {
68
- const idx = connectionList.findIndex(c => c.socket === socket);
69
- if (idx >= 0) {
70
- connectionList.splice(idx, 1);
71
- this.connectionPool.set(poolKey, connectionList);
72
- this.logger.debug(`Removed closed connection from pool for ${poolKey}`);
73
- }
74
- });
75
-
76
- resolve(socket);
77
- });
78
-
79
- socket.once('error', (err) => {
80
- this.logger.error(`Error creating connection to ${host}:${port}`, err);
81
- reject(err);
82
- });
83
- } catch (err) {
84
- this.logger.error(`Failed to create connection to ${host}:${port}`, err);
85
- reject(err);
86
- }
87
- } else {
88
- // Pool is full, wait for an idle connection or reject
89
- this.logger.warn(`Connection pool for ${poolKey} is full (${connectionList.length})`);
90
- reject(new Error(`Connection pool for ${poolKey} is full`));
91
- }
92
- });
93
- }
94
-
95
- /**
96
- * Return a connection to the pool for reuse
97
- */
98
- public returnConnection(socket: plugins.net.Socket, host: string, port: number): void {
99
- const poolKey = `${host}:${port}`;
100
- const connectionList = this.connectionPool.get(poolKey) || [];
101
-
102
- // Find this connection in the pool
103
- const connectionIndex = connectionList.findIndex(c => c.socket === socket);
104
-
105
- if (connectionIndex >= 0) {
106
- // Mark as idle and update last used time
107
- connectionList[connectionIndex].isIdle = true;
108
- connectionList[connectionIndex].lastUsed = Date.now();
109
-
110
- this.logger.debug(`Returned connection to pool for ${poolKey}`);
111
- } else {
112
- this.logger.warn(`Attempted to return unknown connection to pool for ${poolKey}`);
113
- }
114
- }
115
-
116
- /**
117
- * Cleanup the connection pool by removing idle connections
118
- * or reducing pool size if it exceeds the configured maximum
119
- */
120
- public cleanupConnectionPool(): void {
121
- const now = Date.now();
122
- const idleTimeout = this.options.keepAliveTimeout || 120000; // 2 minutes default
123
-
124
- for (const [host, connections] of this.connectionPool.entries()) {
125
- // Sort by last used time (oldest first)
126
- connections.sort((a, b) => a.lastUsed - b.lastUsed);
127
-
128
- // Remove idle connections older than the idle timeout
129
- let removed = 0;
130
- while (connections.length > 0) {
131
- const connection = connections[0];
132
-
133
- // Remove if idle and exceeds timeout, or if pool is too large
134
- if ((connection.isIdle && now - connection.lastUsed > idleTimeout) ||
135
- connections.length > (this.options.connectionPoolSize || 50)) {
136
-
137
- cleanupSocket(connection.socket, `pool-${host}-idle`, { immediate: true }).catch(() => {});
138
-
139
- connections.shift(); // Remove from pool
140
- removed++;
141
- } else {
142
- break; // Stop removing if we've reached active or recent connections
143
- }
144
- }
145
-
146
- if (removed > 0) {
147
- this.logger.debug(`Removed ${removed} idle connections from pool for ${host}, ${connections.length} remaining`);
148
- }
149
-
150
- // Update the pool with the remaining connections
151
- if (connections.length === 0) {
152
- this.connectionPool.delete(host);
153
- } else {
154
- this.connectionPool.set(host, connections);
155
- }
156
- }
157
- }
158
-
159
- /**
160
- * Close all connections in the pool
161
- */
162
- public closeAllConnections(): void {
163
- for (const [host, connections] of this.connectionPool.entries()) {
164
- this.logger.debug(`Closing ${connections.length} connections to ${host}`);
165
-
166
- for (const connection of connections) {
167
- cleanupSocket(connection.socket, `pool-${host}-close`, { immediate: true }).catch(() => {});
168
- }
169
- }
170
-
171
- this.connectionPool.clear();
172
- this.roundRobinPositions.clear();
173
- }
174
-
175
- /**
176
- * Get load balancing target using round-robin
177
- */
178
- public getNextTarget(targets: string[], port: number): { host: string, port: number } {
179
- const targetKey = targets.join(',');
180
-
181
- // Initialize position if not exists
182
- if (!this.roundRobinPositions.has(targetKey)) {
183
- this.roundRobinPositions.set(targetKey, 0);
184
- }
185
-
186
- // Get current position and increment for next time
187
- const currentPosition = this.roundRobinPositions.get(targetKey)!;
188
- const nextPosition = (currentPosition + 1) % targets.length;
189
- this.roundRobinPositions.set(targetKey, nextPosition);
190
-
191
- // Return the selected target
192
- return {
193
- host: targets[currentPosition],
194
- port
195
- };
196
- }
197
-
198
- /**
199
- * Gets the connection pool status
200
- */
201
- public getPoolStatus(): Record<string, { total: number, idle: number }> {
202
- return Object.fromEntries(
203
- Array.from(this.connectionPool.entries()).map(([host, connections]) => [
204
- host,
205
- {
206
- total: connections.length,
207
- idle: connections.filter(c => c.isIdle).length
208
- }
209
- ])
210
- );
211
- }
212
-
213
- /**
214
- * Setup a periodic cleanup task
215
- */
216
- public setupPeriodicCleanup(interval: number = 60000): NodeJS.Timeout {
217
- const timer = setInterval(() => {
218
- this.cleanupConnectionPool();
219
- }, interval);
220
-
221
- // Don't prevent process exit
222
- if (timer.unref) {
223
- timer.unref();
224
- }
225
-
226
- return timer;
227
- }
228
- }
@@ -1,145 +0,0 @@
1
- import * as plugins from '../../plugins.js';
2
- import '../../core/models/socket-augmentation.js';
3
- import type { IRouteContext, IHttpRouteContext, IHttp2RouteContext } from '../../core/models/route-context.js';
4
-
5
- /**
6
- * Context creator for NetworkProxy
7
- * Creates route contexts for matching and function evaluation
8
- */
9
- export class ContextCreator {
10
- /**
11
- * Create a route context from HTTP request information
12
- */
13
- public createHttpRouteContext(req: any, options: {
14
- tlsVersion?: string;
15
- connectionId: string;
16
- clientIp: string;
17
- serverIp: string;
18
- }): IHttpRouteContext {
19
- // Parse headers
20
- const headers: Record<string, string> = {};
21
- for (const [key, value] of Object.entries(req.headers)) {
22
- if (typeof value === 'string') {
23
- headers[key.toLowerCase()] = value;
24
- } else if (Array.isArray(value) && value.length > 0) {
25
- headers[key.toLowerCase()] = value[0];
26
- }
27
- }
28
-
29
- // Parse domain from Host header
30
- const domain = headers['host']?.split(':')[0] || '';
31
-
32
- // Parse URL
33
- const url = new URL(`http://${domain}${req.url || '/'}`);
34
-
35
- return {
36
- // Connection basics
37
- port: req.socket.localPort || 0,
38
- domain,
39
- clientIp: options.clientIp,
40
- serverIp: options.serverIp,
41
-
42
- // HTTP specifics
43
- path: url.pathname,
44
- query: url.search ? url.search.substring(1) : '',
45
- headers,
46
-
47
- // TLS information
48
- isTls: !!req.socket.encrypted,
49
- tlsVersion: options.tlsVersion,
50
-
51
- // Request objects
52
- req,
53
-
54
- // Metadata
55
- timestamp: Date.now(),
56
- connectionId: options.connectionId
57
- };
58
- }
59
-
60
- /**
61
- * Create a route context from HTTP/2 stream and headers
62
- */
63
- public createHttp2RouteContext(
64
- stream: plugins.http2.ServerHttp2Stream,
65
- headers: plugins.http2.IncomingHttpHeaders,
66
- options: {
67
- connectionId: string;
68
- clientIp: string;
69
- serverIp: string;
70
- }
71
- ): IHttp2RouteContext {
72
- // Parse headers, excluding HTTP/2 pseudo-headers
73
- const processedHeaders: Record<string, string> = {};
74
- for (const [key, value] of Object.entries(headers)) {
75
- if (!key.startsWith(':') && typeof value === 'string') {
76
- processedHeaders[key.toLowerCase()] = value;
77
- }
78
- }
79
-
80
- // Get domain from :authority pseudo-header
81
- const authority = headers[':authority'] as string || '';
82
- const domain = authority.split(':')[0];
83
-
84
- // Get path from :path pseudo-header
85
- const path = headers[':path'] as string || '/';
86
-
87
- // Parse the path to extract query string
88
- const pathParts = path.split('?');
89
- const pathname = pathParts[0];
90
- const query = pathParts.length > 1 ? pathParts[1] : '';
91
-
92
- // Get the socket from the session
93
- const socket = (stream.session as any)?.socket;
94
-
95
- return {
96
- // Connection basics
97
- port: socket?.localPort || 0,
98
- domain,
99
- clientIp: options.clientIp,
100
- serverIp: options.serverIp,
101
-
102
- // HTTP specifics
103
- path: pathname,
104
- query,
105
- headers: processedHeaders,
106
-
107
- // HTTP/2 specific properties
108
- method: headers[':method'] as string,
109
- stream,
110
-
111
- // TLS information - HTTP/2 is always on TLS in browsers
112
- isTls: true,
113
- tlsVersion: socket?.getTLSVersion?.() || 'TLSv1.3',
114
-
115
- // Metadata
116
- timestamp: Date.now(),
117
- connectionId: options.connectionId
118
- };
119
- }
120
-
121
- /**
122
- * Create a basic route context from socket information
123
- */
124
- public createSocketRouteContext(socket: plugins.net.Socket, options: {
125
- domain?: string;
126
- tlsVersion?: string;
127
- connectionId: string;
128
- }): IRouteContext {
129
- return {
130
- // Connection basics
131
- port: socket.localPort || 0,
132
- domain: options.domain,
133
- clientIp: socket.remoteAddress?.replace('::ffff:', '') || '0.0.0.0',
134
- serverIp: socket.localAddress?.replace('::ffff:', '') || '0.0.0.0',
135
-
136
- // TLS information
137
- isTls: options.tlsVersion !== undefined,
138
- tlsVersion: options.tlsVersion,
139
-
140
- // Metadata
141
- timestamp: Date.now(),
142
- connectionId: options.connectionId
143
- };
144
- }
145
- }