@push.rocks/smartproxy 19.5.19 → 19.5.20

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 (101) hide show
  1. package/dist_ts/core/models/index.d.ts +2 -0
  2. package/dist_ts/core/models/index.js +3 -1
  3. package/dist_ts/core/models/socket-types.d.ts +14 -0
  4. package/dist_ts/core/models/socket-types.js +15 -0
  5. package/dist_ts/core/models/wrapped-socket.d.ts +34 -0
  6. package/dist_ts/core/models/wrapped-socket.js +82 -0
  7. package/dist_ts/core/routing/index.d.ts +11 -0
  8. package/dist_ts/core/routing/index.js +17 -0
  9. package/dist_ts/core/routing/matchers/domain.d.ts +34 -0
  10. package/dist_ts/core/routing/matchers/domain.js +91 -0
  11. package/dist_ts/core/routing/matchers/header.d.ts +32 -0
  12. package/dist_ts/core/routing/matchers/header.js +94 -0
  13. package/dist_ts/core/routing/matchers/index.d.ts +18 -0
  14. package/dist_ts/core/routing/matchers/index.js +20 -0
  15. package/dist_ts/core/routing/matchers/ip.d.ts +53 -0
  16. package/dist_ts/core/routing/matchers/ip.js +169 -0
  17. package/dist_ts/core/routing/matchers/path.d.ts +44 -0
  18. package/dist_ts/core/routing/matchers/path.js +148 -0
  19. package/dist_ts/core/routing/route-manager.d.ts +88 -0
  20. package/dist_ts/core/routing/route-manager.js +342 -0
  21. package/dist_ts/core/routing/route-utils.d.ts +28 -0
  22. package/dist_ts/core/routing/route-utils.js +67 -0
  23. package/dist_ts/core/routing/specificity.d.ts +30 -0
  24. package/dist_ts/core/routing/specificity.js +115 -0
  25. package/dist_ts/core/routing/types.d.ts +41 -0
  26. package/dist_ts/core/routing/types.js +5 -0
  27. package/dist_ts/core/utils/index.d.ts +0 -2
  28. package/dist_ts/core/utils/index.js +1 -3
  29. package/dist_ts/core/utils/route-manager.d.ts +0 -30
  30. package/dist_ts/core/utils/route-manager.js +6 -47
  31. package/dist_ts/core/utils/route-utils.d.ts +2 -68
  32. package/dist_ts/core/utils/route-utils.js +21 -218
  33. package/dist_ts/core/utils/security-utils.js +4 -4
  34. package/dist_ts/index.d.ts +2 -5
  35. package/dist_ts/index.js +5 -11
  36. package/dist_ts/proxies/http-proxy/http-proxy.d.ts +0 -1
  37. package/dist_ts/proxies/http-proxy/http-proxy.js +15 -60
  38. package/dist_ts/proxies/http-proxy/models/types.d.ts +0 -90
  39. package/dist_ts/proxies/http-proxy/models/types.js +1 -242
  40. package/dist_ts/proxies/http-proxy/request-handler.d.ts +3 -5
  41. package/dist_ts/proxies/http-proxy/request-handler.js +20 -171
  42. package/dist_ts/proxies/http-proxy/websocket-handler.d.ts +2 -5
  43. package/dist_ts/proxies/http-proxy/websocket-handler.js +15 -23
  44. package/dist_ts/proxies/index.d.ts +2 -2
  45. package/dist_ts/proxies/index.js +4 -3
  46. package/dist_ts/proxies/smart-proxy/connection-manager.d.ts +3 -1
  47. package/dist_ts/proxies/smart-proxy/connection-manager.js +15 -7
  48. package/dist_ts/proxies/smart-proxy/http-proxy-bridge.d.ts +2 -1
  49. package/dist_ts/proxies/smart-proxy/http-proxy-bridge.js +5 -2
  50. package/dist_ts/proxies/smart-proxy/index.d.ts +1 -1
  51. package/dist_ts/proxies/smart-proxy/index.js +2 -2
  52. package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +6 -2
  53. package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +1 -1
  54. package/dist_ts/proxies/smart-proxy/route-connection-handler.js +48 -25
  55. package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +1 -1
  56. package/dist_ts/proxies/smart-proxy/smart-proxy.js +15 -4
  57. package/dist_ts/proxies/smart-proxy/utils/route-utils.js +10 -43
  58. package/dist_ts/routing/router/http-router.d.ts +89 -0
  59. package/dist_ts/routing/router/http-router.js +205 -0
  60. package/dist_ts/routing/router/index.d.ts +2 -5
  61. package/dist_ts/routing/router/index.js +3 -4
  62. package/package.json +1 -1
  63. package/readme.delete.md +187 -0
  64. package/readme.hints.md +189 -1
  65. package/readme.plan.md +621 -0
  66. package/readme.routing.md +341 -0
  67. package/ts/core/models/index.ts +2 -0
  68. package/ts/core/models/socket-types.ts +21 -0
  69. package/ts/core/models/wrapped-socket.ts +99 -0
  70. package/ts/core/routing/index.ts +21 -0
  71. package/ts/core/routing/matchers/domain.ts +119 -0
  72. package/ts/core/routing/matchers/header.ts +120 -0
  73. package/ts/core/routing/matchers/index.ts +22 -0
  74. package/ts/core/routing/matchers/ip.ts +207 -0
  75. package/ts/core/routing/matchers/path.ts +184 -0
  76. package/ts/core/{utils → routing}/route-manager.ts +7 -57
  77. package/ts/core/routing/route-utils.ts +88 -0
  78. package/ts/core/routing/specificity.ts +141 -0
  79. package/ts/core/routing/types.ts +49 -0
  80. package/ts/core/utils/index.ts +0 -2
  81. package/ts/core/utils/security-utils.ts +3 -7
  82. package/ts/index.ts +4 -14
  83. package/ts/proxies/http-proxy/http-proxy.ts +13 -68
  84. package/ts/proxies/http-proxy/models/types.ts +0 -324
  85. package/ts/proxies/http-proxy/request-handler.ts +15 -186
  86. package/ts/proxies/http-proxy/websocket-handler.ts +15 -26
  87. package/ts/proxies/index.ts +3 -2
  88. package/ts/proxies/smart-proxy/connection-manager.ts +15 -7
  89. package/ts/proxies/smart-proxy/http-proxy-bridge.ts +6 -2
  90. package/ts/proxies/smart-proxy/index.ts +1 -1
  91. package/ts/proxies/smart-proxy/models/interfaces.ts +8 -2
  92. package/ts/proxies/smart-proxy/route-connection-handler.ts +58 -30
  93. package/ts/proxies/smart-proxy/smart-proxy.ts +15 -3
  94. package/ts/proxies/smart-proxy/utils/route-utils.ts +11 -49
  95. package/ts/routing/router/http-router.ts +266 -0
  96. package/ts/routing/router/index.ts +3 -8
  97. package/readme.problems.md +0 -170
  98. package/ts/core/utils/route-utils.ts +0 -312
  99. package/ts/proxies/smart-proxy/route-manager.ts +0 -554
  100. package/ts/routing/router/proxy-router.ts +0 -437
  101. package/ts/routing/router/route-router.ts +0 -482
@@ -13,7 +13,6 @@ export interface IAcmeOptions {
13
13
  skipConfiguredCerts?: boolean;
14
14
  }
15
15
  import type { IRouteConfig } from '../../smart-proxy/models/route-types.js';
16
- import type { IRouteContext } from '../../../core/models/route-context.js';
17
16
 
18
17
  /**
19
18
  * Configuration options for HttpProxy
@@ -34,7 +33,6 @@ export interface IHttpProxyOptions {
34
33
  // Settings for SmartProxy integration
35
34
  connectionPoolSize?: number; // Maximum connections to maintain in the pool to each backend
36
35
  portProxyIntegration?: boolean; // Flag to indicate this proxy is used by SmartProxy
37
- useExternalPort80Handler?: boolean; // @deprecated - use SmartCertManager instead
38
36
  // Protocol to use when proxying to backends: HTTP/1.x or HTTP/2
39
37
  backendProtocol?: 'http1' | 'http2';
40
38
 
@@ -58,329 +56,7 @@ export interface ICertificateEntry {
58
56
  expires?: Date;
59
57
  }
60
58
 
61
- /**
62
- * @deprecated Use IRouteConfig instead. This interface will be removed in a future release.
63
- *
64
- * IMPORTANT: This is a legacy interface maintained only for backward compatibility.
65
- * New code should use IRouteConfig for all configuration purposes.
66
- *
67
- * @see IRouteConfig for the modern, recommended configuration format
68
- */
69
- export interface IReverseProxyConfig {
70
- /** Target hostnames/IPs to proxy requests to */
71
- destinationIps: string[];
72
-
73
- /** Target ports to proxy requests to */
74
- destinationPorts: number[];
75
-
76
- /** Hostname to match for routing */
77
- hostName: string;
78
-
79
- /** SSL private key for this host (PEM format) */
80
- privateKey: string;
81
-
82
- /** SSL public key/certificate for this host (PEM format) */
83
- publicKey: string;
84
-
85
- /** Basic authentication configuration */
86
- authentication?: {
87
- type: 'Basic';
88
- user: string;
89
- pass: string;
90
- };
91
-
92
- /** Whether to rewrite the Host header to match the target */
93
- rewriteHostHeader?: boolean;
94
-
95
- /**
96
- * Protocol to use when proxying to this backend: 'http1' or 'http2'.
97
- * Overrides the global backendProtocol option if set.
98
- */
99
- backendProtocol?: 'http1' | 'http2';
100
- }
101
-
102
- /**
103
- * Convert a legacy IReverseProxyConfig to the modern IRouteConfig format
104
- *
105
- * @deprecated This function is maintained for backward compatibility.
106
- * New code should create IRouteConfig objects directly.
107
- *
108
- * @param legacyConfig The legacy configuration to convert
109
- * @param proxyPort The port the proxy listens on
110
- * @returns A modern route configuration equivalent to the legacy config
111
- */
112
- export function convertLegacyConfigToRouteConfig(
113
- legacyConfig: IReverseProxyConfig,
114
- proxyPort: number
115
- ): IRouteConfig {
116
- // Create basic route configuration
117
- const routeConfig: IRouteConfig = {
118
- // Match properties
119
- match: {
120
- ports: proxyPort,
121
- domains: legacyConfig.hostName
122
- },
123
-
124
- // Action properties
125
- action: {
126
- type: 'forward',
127
- target: {
128
- host: legacyConfig.destinationIps,
129
- port: legacyConfig.destinationPorts[0]
130
- },
131
-
132
- // TLS mode is always 'terminate' for legacy configs
133
- tls: {
134
- mode: 'terminate',
135
- certificate: {
136
- key: legacyConfig.privateKey,
137
- cert: legacyConfig.publicKey
138
- }
139
- },
140
-
141
- // Advanced options
142
- advanced: {
143
- // Rewrite host header if specified
144
- headers: legacyConfig.rewriteHostHeader ? { 'host': '{domain}' } : {}
145
- }
146
- },
147
-
148
- // Metadata
149
- name: `Legacy Config - ${legacyConfig.hostName}`,
150
- priority: 0, // Default priority
151
- enabled: true
152
- };
153
-
154
- // Add authentication if present
155
- if (legacyConfig.authentication) {
156
- routeConfig.security = {
157
- authentication: {
158
- type: 'basic',
159
- credentials: [{
160
- username: legacyConfig.authentication.user,
161
- password: legacyConfig.authentication.pass
162
- }]
163
- }
164
- };
165
- }
166
-
167
- // Add backend protocol if specified
168
- if (legacyConfig.backendProtocol) {
169
- if (!routeConfig.action.options) {
170
- routeConfig.action.options = {};
171
- }
172
- routeConfig.action.options.backendProtocol = legacyConfig.backendProtocol;
173
- }
174
-
175
- return routeConfig;
176
- }
177
-
178
- /**
179
- * Route manager for NetworkProxy
180
- * Handles route matching and configuration
181
- */
182
- export class RouteManager {
183
- private routes: IRouteConfig[] = [];
184
- private logger: ILogger;
185
-
186
- constructor(logger: ILogger) {
187
- this.logger = logger;
188
- }
189
-
190
- /**
191
- * Update the routes configuration
192
- */
193
- public updateRoutes(routes: IRouteConfig[]): void {
194
- // Sort routes by priority (higher first)
195
- this.routes = [...routes].sort((a, b) => {
196
- const priorityA = a.priority ?? 0;
197
- const priorityB = b.priority ?? 0;
198
- return priorityB - priorityA;
199
- });
200
-
201
- this.logger.info(`Updated RouteManager with ${this.routes.length} routes`);
202
- }
203
-
204
- /**
205
- * Get all routes
206
- */
207
- public getRoutes(): IRouteConfig[] {
208
- return [...this.routes];
209
- }
210
-
211
- /**
212
- * Find the first matching route for a context
213
- */
214
- public findMatchingRoute(context: IRouteContext): IRouteConfig | null {
215
- for (const route of this.routes) {
216
- if (this.matchesRoute(route, context)) {
217
- return route;
218
- }
219
- }
220
- return null;
221
- }
222
59
 
223
- /**
224
- * Check if a route matches the given context
225
- */
226
- private matchesRoute(route: IRouteConfig, context: IRouteContext): boolean {
227
- // Skip disabled routes
228
- if (route.enabled === false) {
229
- return false;
230
- }
231
-
232
- // Check domain match if specified
233
- if (route.match.domains && context.domain) {
234
- const domains = Array.isArray(route.match.domains)
235
- ? route.match.domains
236
- : [route.match.domains];
237
-
238
- if (!domains.some(domainPattern => this.matchDomain(domainPattern, context.domain!))) {
239
- return false;
240
- }
241
- }
242
-
243
- // Check path match if specified
244
- if (route.match.path && context.path) {
245
- if (!this.matchPath(route.match.path, context.path)) {
246
- return false;
247
- }
248
- }
249
-
250
- // Check client IP match if specified
251
- if (route.match.clientIp && context.clientIp) {
252
- if (!route.match.clientIp.some(ip => this.matchIp(ip, context.clientIp))) {
253
- return false;
254
- }
255
- }
256
-
257
- // Check TLS version match if specified
258
- if (route.match.tlsVersion && context.tlsVersion) {
259
- if (!route.match.tlsVersion.includes(context.tlsVersion)) {
260
- return false;
261
- }
262
- }
263
-
264
- // All criteria matched
265
- return true;
266
- }
267
-
268
- /**
269
- * Match a domain pattern against a domain
270
- */
271
- private matchDomain(pattern: string, domain: string): boolean {
272
- if (pattern === domain) {
273
- return true;
274
- }
275
-
276
- if (pattern.includes('*')) {
277
- const regexPattern = pattern
278
- .replace(/\./g, '\\.')
279
- .replace(/\*/g, '.*');
280
-
281
- const regex = new RegExp(`^${regexPattern}$`, 'i');
282
- return regex.test(domain);
283
- }
284
-
285
- return false;
286
- }
287
-
288
- /**
289
- * Match a path pattern against a path
290
- */
291
- private matchPath(pattern: string, path: string): boolean {
292
- if (pattern === path) {
293
- return true;
294
- }
295
-
296
- if (pattern.endsWith('*')) {
297
- const prefix = pattern.slice(0, -1);
298
- return path.startsWith(prefix);
299
- }
300
-
301
- return false;
302
- }
303
-
304
- /**
305
- * Match an IP pattern against an IP
306
- * Supports exact matches, wildcard patterns, and CIDR notation
307
- */
308
- private matchIp(pattern: string, ip: string): boolean {
309
- // Exact match
310
- if (pattern === ip) {
311
- return true;
312
- }
313
-
314
- // Wildcard matching (e.g., 192.168.0.*)
315
- if (pattern.includes('*')) {
316
- const regexPattern = pattern
317
- .replace(/\./g, '\\.')
318
- .replace(/\*/g, '.*');
319
-
320
- const regex = new RegExp(`^${regexPattern}$`);
321
- return regex.test(ip);
322
- }
323
-
324
- // CIDR matching (e.g., 192.168.0.0/24)
325
- if (pattern.includes('/')) {
326
- try {
327
- const [subnet, bits] = pattern.split('/');
328
-
329
- // Convert IP addresses to numeric format for comparison
330
- const ipBinary = this.ipToBinary(ip);
331
- const subnetBinary = this.ipToBinary(subnet);
332
-
333
- if (!ipBinary || !subnetBinary) {
334
- return false;
335
- }
336
-
337
- // Get the subnet mask from CIDR notation
338
- const mask = parseInt(bits, 10);
339
- if (isNaN(mask) || mask < 0 || mask > 32) {
340
- return false;
341
- }
342
-
343
- // Check if the first 'mask' bits match between IP and subnet
344
- return ipBinary.slice(0, mask) === subnetBinary.slice(0, mask);
345
- } catch (error) {
346
- // If we encounter any error during CIDR matching, return false
347
- return false;
348
- }
349
- }
350
-
351
- return false;
352
- }
353
-
354
- /**
355
- * Convert an IP address to its binary representation
356
- * @param ip The IP address to convert
357
- * @returns Binary string representation or null if invalid
358
- */
359
- private ipToBinary(ip: string): string | null {
360
- // Handle IPv4 addresses only for now
361
- const parts = ip.split('.');
362
-
363
- // Validate IP format
364
- if (parts.length !== 4) {
365
- return null;
366
- }
367
-
368
- // Convert each octet to 8-bit binary and concatenate
369
- try {
370
- return parts
371
- .map(part => {
372
- const num = parseInt(part, 10);
373
- if (isNaN(num) || num < 0 || num > 255) {
374
- throw new Error('Invalid IP octet');
375
- }
376
- return num.toString(2).padStart(8, '0');
377
- })
378
- .join('');
379
- } catch (error) {
380
- return null;
381
- }
382
- }
383
- }
384
60
 
385
61
  /**
386
62
  * Interface for connection tracking in the pool
@@ -4,11 +4,9 @@ import {
4
4
  type IHttpProxyOptions,
5
5
  type ILogger,
6
6
  createLogger,
7
- type IReverseProxyConfig,
8
- RouteManager
9
7
  } from './models/types.js';
8
+ import { SharedRouteManager as RouteManager } from '../../core/routing/route-manager.js';
10
9
  import { ConnectionPool } from './connection-pool.js';
11
- import { ProxyRouter } from '../../routing/router/index.js';
12
10
  import { ContextCreator } from './context-creator.js';
13
11
  import { HttpRequestHandler } from './http-request-handler.js';
14
12
  import { Http2RequestHandler } from './http2-request-handler.js';
@@ -48,10 +46,9 @@ export class RequestHandler {
48
46
  constructor(
49
47
  private options: IHttpProxyOptions,
50
48
  private connectionPool: ConnectionPool,
51
- private legacyRouter: ProxyRouter, // Legacy router for backward compatibility
52
49
  private routeManager?: RouteManager,
53
50
  private functionCache?: any, // FunctionCache - using any to avoid circular dependency
54
- private router?: any // RouteRouter - using any to avoid circular dependency
51
+ private router?: any // HttpRouter - using any to avoid circular dependency
55
52
  ) {
56
53
  this.logger = createLogger(options.logLevel || 'info');
57
54
  this.securityManager = new SecurityManager(this.logger);
@@ -373,7 +370,8 @@ export class RequestHandler {
373
370
  tlsVersion: req.socket.getTLSVersion?.() || undefined
374
371
  });
375
372
 
376
- matchingRoute = this.routeManager.findMatchingRoute(toBaseContext(routeContext));
373
+ const matchResult = this.routeManager.findMatchingRoute(toBaseContext(routeContext));
374
+ matchingRoute = matchResult?.route || null;
377
375
  } catch (err) {
378
376
  this.logger.error('Error finding matching route', err);
379
377
  }
@@ -581,86 +579,11 @@ export class RequestHandler {
581
579
  }
582
580
  }
583
581
 
584
- // Try modern router first, then fall back to legacy routing if needed
585
- if (this.router) {
586
- try {
587
- // Try to find a matching route using the modern router
588
- const route = this.router.routeReq(req);
589
- if (route && route.action.type === 'forward' && route.action.target) {
590
- // Handle this route similarly to RouteManager logic
591
- this.logger.debug(`Found matching route via modern router: ${route.name || 'unnamed'}`);
592
-
593
- // No need to do anything here, we'll continue with legacy routing
594
- // The routeManager would have already found this route if applicable
595
- }
596
- } catch (err) {
597
- this.logger.error('Error using modern router', err);
598
- // Continue with legacy routing
599
- }
600
- }
601
-
602
- // Fall back to legacy routing if no matching route found via RouteManager
603
- let proxyConfig: IReverseProxyConfig | undefined;
604
- try {
605
- proxyConfig = this.legacyRouter.routeReq(req);
606
- } catch (err) {
607
- this.logger.error('Error routing request with legacy router', err);
608
- res.statusCode = 500;
609
- res.end('Internal Server Error');
610
- if (this.metricsTracker) this.metricsTracker.incrementFailedRequests();
611
- return;
612
- }
613
- if (!proxyConfig) {
614
- this.logger.warn(`No proxy configuration for host: ${req.headers.host}`);
615
- res.statusCode = 404;
616
- res.end('Not Found: No proxy configuration for this host');
617
- if (this.metricsTracker) this.metricsTracker.incrementFailedRequests();
618
- return;
619
- }
620
- // Determine protocol to backend (per-domain override or global)
621
- const backendProto = proxyConfig.backendProtocol || this.options.backendProtocol;
622
- if (backendProto === 'http2') {
623
- const destination = this.connectionPool.getNextTarget(
624
- proxyConfig.destinationIps,
625
- proxyConfig.destinationPorts[0]
626
- );
627
- const key = `${destination.host}:${destination.port}`;
628
- let session = this.h2Sessions.get(key);
629
- if (!session || session.closed || (session as any).destroyed) {
630
- session = plugins.http2.connect(`http://${destination.host}:${destination.port}`);
631
- this.h2Sessions.set(key, session);
632
- session.on('error', () => this.h2Sessions.delete(key));
633
- session.on('close', () => this.h2Sessions.delete(key));
634
- }
635
- // Build headers for HTTP/2 request
636
- const hdrs: Record<string, any> = {
637
- ':method': req.method,
638
- ':path': req.url,
639
- ':authority': `${destination.host}:${destination.port}`
640
- };
641
- for (const [hk, hv] of Object.entries(req.headers)) {
642
- if (typeof hv === 'string') hdrs[hk] = hv;
643
- }
644
- const h2Stream = session.request(hdrs);
645
- req.pipe(h2Stream);
646
- h2Stream.on('response', (hdrs2: any) => {
647
- const status = (hdrs2[':status'] as number) || 502;
648
- res.statusCode = status;
649
- // Copy headers from HTTP/2 response to HTTP/1 response
650
- for (const [hk, hv] of Object.entries(hdrs2)) {
651
- if (!hk.startsWith(':') && hv != null) {
652
- res.setHeader(hk, hv as string | string[]);
653
- }
654
- }
655
- h2Stream.pipe(res);
656
- });
657
- h2Stream.on('error', (err) => {
658
- res.statusCode = 502;
659
- res.end(`Bad Gateway: ${err.message}`);
660
- if (this.metricsTracker) this.metricsTracker.incrementFailedRequests();
661
- });
662
- return;
663
- }
582
+ // If no route was found, return 404
583
+ this.logger.warn(`No route configuration for host: ${req.headers.host}`);
584
+ res.statusCode = 404;
585
+ res.end('Not Found: No route configuration for this host');
586
+ if (this.metricsTracker) this.metricsTracker.incrementFailedRequests();
664
587
  }
665
588
 
666
589
  /**
@@ -688,7 +611,8 @@ export class RequestHandler {
688
611
  let matchingRoute: IRouteConfig | null = null;
689
612
  if (this.routeManager) {
690
613
  try {
691
- matchingRoute = this.routeManager.findMatchingRoute(toBaseContext(routeContext));
614
+ const matchResult = this.routeManager.findMatchingRoute(toBaseContext(routeContext));
615
+ matchingRoute = matchResult?.route || null;
692
616
  } catch (err) {
693
617
  this.logger.error('Error finding matching route for HTTP/2 request', err);
694
618
  }
@@ -812,104 +736,9 @@ export class RequestHandler {
812
736
  const method = headers[':method'] || 'GET';
813
737
  const path = headers[':path'] || '/';
814
738
 
815
- // If configured to proxy to backends over HTTP/2, use HTTP/2 client sessions
816
- if (this.options.backendProtocol === 'http2') {
817
- const authority = headers[':authority'] as string || '';
818
- const host = authority.split(':')[0];
819
- const fakeReq: any = {
820
- headers: { host },
821
- method: headers[':method'],
822
- url: headers[':path'],
823
- socket: (stream.session as any).socket
824
- };
825
- // Try modern router first if available
826
- let route;
827
- if (this.router) {
828
- try {
829
- route = this.router.routeReq(fakeReq);
830
- if (route && route.action.type === 'forward' && route.action.target) {
831
- this.logger.debug(`Found matching HTTP/2 route via modern router: ${route.name || 'unnamed'}`);
832
- // The routeManager would have already found this route if applicable
833
- }
834
- } catch (err) {
835
- this.logger.error('Error using modern router for HTTP/2', err);
836
- }
837
- }
838
-
839
- // Fall back to legacy routing
840
- const proxyConfig = this.legacyRouter.routeReq(fakeReq);
841
- if (!proxyConfig) {
842
- stream.respond({ ':status': 404 });
843
- stream.end('Not Found');
844
- if (this.metricsTracker) this.metricsTracker.incrementFailedRequests();
845
- return;
846
- }
847
- const destination = this.connectionPool.getNextTarget(proxyConfig.destinationIps, proxyConfig.destinationPorts[0]);
848
-
849
- // Use the helper for HTTP/2 to HTTP/2 routing
850
- return Http2RequestHandler.handleHttp2WithHttp2Destination(
851
- stream,
852
- headers,
853
- destination,
854
- routeContext,
855
- this.h2Sessions,
856
- this.logger,
857
- this.metricsTracker
858
- );
859
- }
860
-
861
- try {
862
- // Determine host for routing
863
- const authority = headers[':authority'] as string || '';
864
- const host = authority.split(':')[0];
865
- // Fake request object for routing
866
- const fakeReq: any = {
867
- headers: { host },
868
- method,
869
- url: path,
870
- socket: (stream.session as any).socket
871
- };
872
- // Try modern router first if available
873
- if (this.router) {
874
- try {
875
- const route = this.router.routeReq(fakeReq);
876
- if (route && route.action.type === 'forward' && route.action.target) {
877
- this.logger.debug(`Found matching HTTP/2 route via modern router: ${route.name || 'unnamed'}`);
878
- // The routeManager would have already found this route if applicable
879
- }
880
- } catch (err) {
881
- this.logger.error('Error using modern router for HTTP/2', err);
882
- }
883
- }
884
-
885
- // Fall back to legacy routing
886
- const proxyConfig = this.legacyRouter.routeReq(fakeReq as any);
887
- if (!proxyConfig) {
888
- stream.respond({ ':status': 404 });
889
- stream.end('Not Found');
890
- if (this.metricsTracker) this.metricsTracker.incrementFailedRequests();
891
- return;
892
- }
893
-
894
- // Select backend target
895
- const destination = this.connectionPool.getNextTarget(
896
- proxyConfig.destinationIps,
897
- proxyConfig.destinationPorts[0]
898
- );
899
-
900
- // Use the helper for HTTP/2 to HTTP/1 routing
901
- return Http2RequestHandler.handleHttp2WithHttp1Destination(
902
- stream,
903
- headers,
904
- destination,
905
- routeContext,
906
- this.logger,
907
- this.metricsTracker
908
- );
909
- } catch (err: any) {
910
- stream.respond({ ':status': 500 });
911
- stream.end('Internal Server Error');
912
- if (this.metricsTracker) this.metricsTracker.incrementFailedRequests();
913
- }
739
+ // No route was found
740
+ stream.respond({ ':status': 404 });
741
+ stream.end('Not Found: No route configuration for this request');
742
+ if (this.metricsTracker) this.metricsTracker.incrementFailedRequests();
914
743
  }
915
744
  }
@@ -1,8 +1,8 @@
1
1
  import * as plugins from '../../plugins.js';
2
2
  import '../../core/models/socket-augmentation.js';
3
- import { type IHttpProxyOptions, type IWebSocketWithHeartbeat, type ILogger, createLogger, type IReverseProxyConfig } from './models/types.js';
3
+ import { type IHttpProxyOptions, type IWebSocketWithHeartbeat, type ILogger, createLogger } from './models/types.js';
4
4
  import { ConnectionPool } from './connection-pool.js';
5
- import { ProxyRouter, RouteRouter } from '../../routing/router/index.js';
5
+ import { HttpRouter } from '../../routing/router/index.js';
6
6
  import type { IRouteConfig } from '../smart-proxy/models/route-types.js';
7
7
  import type { IRouteContext } from '../../core/models/route-context.js';
8
8
  import { toBaseContext } from '../../core/models/route-context.js';
@@ -19,21 +19,20 @@ export class WebSocketHandler {
19
19
  private wsServer: plugins.ws.WebSocketServer | null = null;
20
20
  private logger: ILogger;
21
21
  private contextCreator: ContextCreator = new ContextCreator();
22
- private routeRouter: RouteRouter | null = null;
22
+ private router: HttpRouter | null = null;
23
23
  private securityManager: SecurityManager;
24
24
 
25
25
  constructor(
26
26
  private options: IHttpProxyOptions,
27
27
  private connectionPool: ConnectionPool,
28
- private legacyRouter: ProxyRouter, // Legacy router for backward compatibility
29
- private routes: IRouteConfig[] = [] // Routes for modern router
28
+ private routes: IRouteConfig[] = []
30
29
  ) {
31
30
  this.logger = createLogger(options.logLevel || 'info');
32
31
  this.securityManager = new SecurityManager(this.logger, routes);
33
32
 
34
- // Initialize modern router if we have routes
33
+ // Initialize router if we have routes
35
34
  if (routes.length > 0) {
36
- this.routeRouter = new RouteRouter(routes, this.logger);
35
+ this.router = new HttpRouter(routes, this.logger);
37
36
  }
38
37
  }
39
38
 
@@ -44,10 +43,10 @@ export class WebSocketHandler {
44
43
  this.routes = routes;
45
44
 
46
45
  // Initialize or update the route router
47
- if (!this.routeRouter) {
48
- this.routeRouter = new RouteRouter(routes, this.logger);
46
+ if (!this.router) {
47
+ this.router = new HttpRouter(routes, this.logger);
49
48
  } else {
50
- this.routeRouter.setRoutes(routes);
49
+ this.router.setRoutes(routes);
51
50
  }
52
51
 
53
52
  // Update the security manager
@@ -139,8 +138,8 @@ export class WebSocketHandler {
139
138
 
140
139
  // Try modern router first if available
141
140
  let route: IRouteConfig | undefined;
142
- if (this.routeRouter) {
143
- route = this.routeRouter.routeReq(req);
141
+ if (this.router) {
142
+ route = this.router.routeReq(req);
144
143
  }
145
144
 
146
145
  // Define destination variables
@@ -227,20 +226,10 @@ export class WebSocketHandler {
227
226
  return;
228
227
  }
229
228
  } else {
230
- // Fall back to legacy routing if no matching route found via modern router
231
- const proxyConfig = this.legacyRouter.routeReq(req);
232
-
233
- if (!proxyConfig) {
234
- this.logger.warn(`No proxy configuration for WebSocket host: ${req.headers.host}`);
235
- wsIncoming.close(1008, 'No proxy configuration for this host');
236
- return;
237
- }
238
-
239
- // Get destination target using round-robin if multiple targets
240
- destination = this.connectionPool.getNextTarget(
241
- proxyConfig.destinationIps,
242
- proxyConfig.destinationPorts[0]
243
- );
229
+ // No route found
230
+ this.logger.warn(`No route configuration for WebSocket host: ${req.headers.host}`);
231
+ wsIncoming.close(1008, 'No route configuration for this host');
232
+ return;
244
233
  }
245
234
 
246
235
  // Build target URL with potential path rewriting
@@ -7,11 +7,12 @@ export { HttpProxy, CertificateManager, ConnectionPool, RequestHandler, WebSocke
7
7
  export type { IMetricsTracker, MetricsTracker } from './http-proxy/index.js';
8
8
  // Export http-proxy models except IAcmeOptions
9
9
  export type { IHttpProxyOptions, ICertificateEntry, ILogger } from './http-proxy/models/types.js';
10
- export { RouteManager as HttpProxyRouteManager } from './http-proxy/models/types.js';
10
+ // RouteManager has been unified - use SharedRouteManager from core/routing
11
+ export { SharedRouteManager as HttpProxyRouteManager } from '../core/routing/route-manager.js';
11
12
 
12
13
  // Export SmartProxy with selective imports to avoid conflicts
13
14
  export { SmartProxy, ConnectionManager, SecurityManager, TimeoutManager, TlsManager, HttpProxyBridge, RouteConnectionHandler } from './smart-proxy/index.js';
14
- export { RouteManager as SmartProxyRouteManager } from './smart-proxy/route-manager.js';
15
+ export { SharedRouteManager as SmartProxyRouteManager } from '../core/routing/route-manager.js';
15
16
  export * from './smart-proxy/utils/index.js';
16
17
  // Export smart-proxy models except IAcmeOptions
17
18
  export type { ISmartProxyOptions, IConnectionRecord, IRouteConfig, IRouteMatch, IRouteAction, IRouteTls, IRouteContext } from './smart-proxy/models/index.js';