@push.rocks/smartproxy 16.0.2 → 16.0.4
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.
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/core/models/index.d.ts +2 -0
- package/dist_ts/core/models/index.js +3 -1
- package/dist_ts/core/models/route-context.d.ts +62 -0
- package/dist_ts/core/models/route-context.js +43 -0
- package/dist_ts/core/models/socket-augmentation.d.ts +12 -0
- package/dist_ts/core/models/socket-augmentation.js +18 -0
- package/dist_ts/core/utils/event-system.d.ts +200 -0
- package/dist_ts/core/utils/event-system.js +224 -0
- package/dist_ts/core/utils/index.d.ts +7 -0
- package/dist_ts/core/utils/index.js +8 -1
- package/dist_ts/core/utils/route-manager.d.ts +118 -0
- package/dist_ts/core/utils/route-manager.js +383 -0
- package/dist_ts/core/utils/route-utils.d.ts +94 -0
- package/dist_ts/core/utils/route-utils.js +264 -0
- package/dist_ts/core/utils/security-utils.d.ts +111 -0
- package/dist_ts/core/utils/security-utils.js +212 -0
- package/dist_ts/core/utils/shared-security-manager.d.ts +110 -0
- package/dist_ts/core/utils/shared-security-manager.js +252 -0
- package/dist_ts/core/utils/template-utils.d.ts +37 -0
- package/dist_ts/core/utils/template-utils.js +104 -0
- package/dist_ts/core/utils/websocket-utils.d.ts +23 -0
- package/dist_ts/core/utils/websocket-utils.js +86 -0
- package/dist_ts/http/router/index.d.ts +5 -1
- package/dist_ts/http/router/index.js +4 -2
- package/dist_ts/http/router/route-router.d.ts +108 -0
- package/dist_ts/http/router/route-router.js +393 -0
- package/dist_ts/index.d.ts +8 -2
- package/dist_ts/index.js +10 -3
- package/dist_ts/proxies/index.d.ts +7 -2
- package/dist_ts/proxies/index.js +10 -4
- package/dist_ts/proxies/network-proxy/certificate-manager.d.ts +21 -0
- package/dist_ts/proxies/network-proxy/certificate-manager.js +92 -1
- package/dist_ts/proxies/network-proxy/context-creator.d.ts +34 -0
- package/dist_ts/proxies/network-proxy/context-creator.js +108 -0
- package/dist_ts/proxies/network-proxy/function-cache.d.ts +90 -0
- package/dist_ts/proxies/network-proxy/function-cache.js +198 -0
- package/dist_ts/proxies/network-proxy/http-request-handler.d.ts +40 -0
- package/dist_ts/proxies/network-proxy/http-request-handler.js +256 -0
- package/dist_ts/proxies/network-proxy/http2-request-handler.d.ts +24 -0
- package/dist_ts/proxies/network-proxy/http2-request-handler.js +201 -0
- package/dist_ts/proxies/network-proxy/models/types.d.ts +73 -1
- package/dist_ts/proxies/network-proxy/models/types.js +242 -1
- package/dist_ts/proxies/network-proxy/network-proxy.d.ts +23 -20
- package/dist_ts/proxies/network-proxy/network-proxy.js +149 -60
- package/dist_ts/proxies/network-proxy/request-handler.d.ts +38 -5
- package/dist_ts/proxies/network-proxy/request-handler.js +584 -198
- package/dist_ts/proxies/network-proxy/security-manager.d.ts +65 -0
- package/dist_ts/proxies/network-proxy/security-manager.js +255 -0
- package/dist_ts/proxies/network-proxy/websocket-handler.d.ts +13 -2
- package/dist_ts/proxies/network-proxy/websocket-handler.js +238 -20
- package/dist_ts/proxies/smart-proxy/index.d.ts +1 -1
- package/dist_ts/proxies/smart-proxy/index.js +3 -3
- package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +3 -5
- package/dist_ts/proxies/smart-proxy/models/route-types.d.ts +56 -4
- package/dist_ts/proxies/smart-proxy/network-proxy-bridge.d.ts +4 -57
- package/dist_ts/proxies/smart-proxy/network-proxy-bridge.js +19 -228
- package/dist_ts/proxies/smart-proxy/port-manager.d.ts +81 -0
- package/dist_ts/proxies/smart-proxy/port-manager.js +166 -0
- package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +5 -0
- package/dist_ts/proxies/smart-proxy/route-connection-handler.js +131 -15
- package/dist_ts/proxies/smart-proxy/route-helpers/index.d.ts +3 -1
- package/dist_ts/proxies/smart-proxy/route-helpers/index.js +5 -3
- package/dist_ts/proxies/smart-proxy/route-helpers.d.ts +5 -178
- package/dist_ts/proxies/smart-proxy/route-helpers.js +8 -296
- package/dist_ts/proxies/smart-proxy/route-manager.d.ts +11 -2
- package/dist_ts/proxies/smart-proxy/route-manager.js +79 -10
- package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +29 -2
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +48 -43
- package/dist_ts/proxies/smart-proxy/utils/route-helpers.d.ts +67 -1
- package/dist_ts/proxies/smart-proxy/utils/route-helpers.js +120 -1
- package/dist_ts/proxies/smart-proxy/utils/route-validators.d.ts +3 -3
- package/dist_ts/proxies/smart-proxy/utils/route-validators.js +27 -5
- package/package.json +1 -1
- package/readme.md +102 -14
- package/readme.plan.md +103 -168
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/core/models/index.ts +2 -0
- package/ts/core/models/route-context.ts +113 -0
- package/ts/core/models/socket-augmentation.ts +33 -0
- package/ts/core/utils/event-system.ts +376 -0
- package/ts/core/utils/index.ts +7 -0
- package/ts/core/utils/route-manager.ts +489 -0
- package/ts/core/utils/route-utils.ts +312 -0
- package/ts/core/utils/security-utils.ts +309 -0
- package/ts/core/utils/shared-security-manager.ts +333 -0
- package/ts/core/utils/template-utils.ts +124 -0
- package/ts/core/utils/websocket-utils.ts +81 -0
- package/ts/http/router/index.ts +8 -1
- package/ts/http/router/route-router.ts +482 -0
- package/ts/index.ts +14 -2
- package/ts/proxies/index.ts +12 -3
- package/ts/proxies/network-proxy/certificate-manager.ts +114 -10
- package/ts/proxies/network-proxy/context-creator.ts +145 -0
- package/ts/proxies/network-proxy/function-cache.ts +259 -0
- package/ts/proxies/network-proxy/http-request-handler.ts +330 -0
- package/ts/proxies/network-proxy/http2-request-handler.ts +255 -0
- package/ts/proxies/network-proxy/models/types.ts +312 -1
- package/ts/proxies/network-proxy/network-proxy.ts +197 -85
- package/ts/proxies/network-proxy/request-handler.ts +698 -246
- package/ts/proxies/network-proxy/security-manager.ts +298 -0
- package/ts/proxies/network-proxy/websocket-handler.ts +276 -33
- package/ts/proxies/smart-proxy/index.ts +2 -12
- package/ts/proxies/smart-proxy/models/interfaces.ts +7 -4
- package/ts/proxies/smart-proxy/models/route-types.ts +77 -10
- package/ts/proxies/smart-proxy/network-proxy-bridge.ts +20 -257
- package/ts/proxies/smart-proxy/port-manager.ts +195 -0
- package/ts/proxies/smart-proxy/route-connection-handler.ts +156 -21
- package/ts/proxies/smart-proxy/route-manager.ts +98 -14
- package/ts/proxies/smart-proxy/smart-proxy.ts +56 -55
- package/ts/proxies/smart-proxy/utils/route-helpers.ts +167 -1
- package/ts/proxies/smart-proxy/utils/route-validators.ts +24 -5
- package/ts/proxies/smart-proxy/domain-config-manager.ts.bak +0 -441
- package/ts/proxies/smart-proxy/route-helpers/index.ts +0 -9
- package/ts/proxies/smart-proxy/route-helpers.ts +0 -498
|
@@ -1,20 +1,46 @@
|
|
|
1
1
|
import * as plugins from '../../plugins.js';
|
|
2
|
-
import
|
|
2
|
+
import '../../core/models/socket-augmentation.js';
|
|
3
|
+
import { createLogger, RouteManager } from './models/types.js';
|
|
3
4
|
import { ConnectionPool } from './connection-pool.js';
|
|
4
5
|
import { ProxyRouter } from '../../http/router/index.js';
|
|
6
|
+
import { ContextCreator } from './context-creator.js';
|
|
7
|
+
import { HttpRequestHandler } from './http-request-handler.js';
|
|
8
|
+
import { Http2RequestHandler } from './http2-request-handler.js';
|
|
9
|
+
import { toBaseContext } from '../../core/models/route-context.js';
|
|
10
|
+
import { TemplateUtils } from '../../core/utils/template-utils.js';
|
|
11
|
+
import { SecurityManager } from './security-manager.js';
|
|
5
12
|
/**
|
|
6
13
|
* Handles HTTP request processing and proxying
|
|
7
14
|
*/
|
|
8
15
|
export class RequestHandler {
|
|
9
|
-
constructor(options, connectionPool, router
|
|
16
|
+
constructor(options, connectionPool, legacyRouter, // Legacy router for backward compatibility
|
|
17
|
+
routeManager, functionCache, // FunctionCache - using any to avoid circular dependency
|
|
18
|
+
router // RouteRouter - using any to avoid circular dependency
|
|
19
|
+
) {
|
|
10
20
|
this.options = options;
|
|
11
21
|
this.connectionPool = connectionPool;
|
|
22
|
+
this.legacyRouter = legacyRouter;
|
|
23
|
+
this.routeManager = routeManager;
|
|
24
|
+
this.functionCache = functionCache;
|
|
12
25
|
this.router = router;
|
|
13
26
|
this.defaultHeaders = {};
|
|
14
27
|
this.metricsTracker = null;
|
|
15
28
|
// HTTP/2 client sessions for backend proxying
|
|
16
29
|
this.h2Sessions = new Map();
|
|
30
|
+
// Context creator for route contexts
|
|
31
|
+
this.contextCreator = new ContextCreator();
|
|
17
32
|
this.logger = createLogger(options.logLevel || 'info');
|
|
33
|
+
this.securityManager = new SecurityManager(this.logger);
|
|
34
|
+
// Schedule rate limit cleanup every minute
|
|
35
|
+
setInterval(() => {
|
|
36
|
+
this.securityManager.cleanupExpiredRateLimits();
|
|
37
|
+
}, 60000);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Set the route manager instance
|
|
41
|
+
*/
|
|
42
|
+
setRouteManager(routeManager) {
|
|
43
|
+
this.routeManager = routeManager;
|
|
18
44
|
}
|
|
19
45
|
/**
|
|
20
46
|
* Set the metrics tracker instance
|
|
@@ -40,31 +66,87 @@ export class RequestHandler {
|
|
|
40
66
|
}
|
|
41
67
|
/**
|
|
42
68
|
* Apply CORS headers to response if configured
|
|
69
|
+
* Implements Phase 5.5: Context-aware CORS handling
|
|
70
|
+
*
|
|
71
|
+
* @param res The server response to apply headers to
|
|
72
|
+
* @param req The incoming request
|
|
73
|
+
* @param route Optional route config with CORS settings
|
|
43
74
|
*/
|
|
44
|
-
applyCorsHeaders(res, req) {
|
|
45
|
-
if
|
|
75
|
+
applyCorsHeaders(res, req, route) {
|
|
76
|
+
// Use route-specific CORS config if available, otherwise use global config
|
|
77
|
+
let corsConfig = null;
|
|
78
|
+
// Route CORS config takes precedence if enabled
|
|
79
|
+
if (route?.headers?.cors?.enabled) {
|
|
80
|
+
corsConfig = route.headers.cors;
|
|
81
|
+
this.logger.debug(`Using route-specific CORS config for ${route.name || 'unnamed route'}`);
|
|
82
|
+
}
|
|
83
|
+
// Fall back to global CORS config if available
|
|
84
|
+
else if (this.options.cors) {
|
|
85
|
+
corsConfig = this.options.cors;
|
|
86
|
+
this.logger.debug('Using global CORS config');
|
|
87
|
+
}
|
|
88
|
+
// If no CORS config available, skip
|
|
89
|
+
if (!corsConfig) {
|
|
46
90
|
return;
|
|
47
91
|
}
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
|
|
92
|
+
// Get origin from request
|
|
93
|
+
const origin = req.headers.origin;
|
|
94
|
+
// Apply Allow-Origin (with dynamic validation if needed)
|
|
95
|
+
if (corsConfig.allowOrigin) {
|
|
96
|
+
// Handle multiple origins in array format
|
|
97
|
+
if (Array.isArray(corsConfig.allowOrigin)) {
|
|
98
|
+
if (origin && corsConfig.allowOrigin.includes(origin)) {
|
|
99
|
+
// Match found, set specific origin
|
|
100
|
+
res.setHeader('Access-Control-Allow-Origin', origin);
|
|
101
|
+
res.setHeader('Vary', 'Origin'); // Important for caching
|
|
102
|
+
}
|
|
103
|
+
else if (corsConfig.allowOrigin.includes('*')) {
|
|
104
|
+
// Wildcard match
|
|
105
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Handle single origin or wildcard
|
|
109
|
+
else if (corsConfig.allowOrigin === '*') {
|
|
110
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
111
|
+
}
|
|
112
|
+
// Match single origin against request
|
|
113
|
+
else if (origin && corsConfig.allowOrigin === origin) {
|
|
114
|
+
res.setHeader('Access-Control-Allow-Origin', origin);
|
|
115
|
+
res.setHeader('Vary', 'Origin');
|
|
116
|
+
}
|
|
117
|
+
// Use template variables if present
|
|
118
|
+
else if (origin && corsConfig.allowOrigin.includes('{')) {
|
|
119
|
+
const resolvedOrigin = TemplateUtils.resolveTemplateVariables(corsConfig.allowOrigin, { domain: req.headers.host });
|
|
120
|
+
if (resolvedOrigin === origin || resolvedOrigin === '*') {
|
|
121
|
+
res.setHeader('Access-Control-Allow-Origin', origin);
|
|
122
|
+
res.setHeader('Vary', 'Origin');
|
|
123
|
+
}
|
|
124
|
+
}
|
|
51
125
|
}
|
|
52
|
-
|
|
53
|
-
|
|
126
|
+
// Apply other CORS headers
|
|
127
|
+
if (corsConfig.allowMethods) {
|
|
128
|
+
res.setHeader('Access-Control-Allow-Methods', corsConfig.allowMethods);
|
|
54
129
|
}
|
|
55
|
-
if (
|
|
56
|
-
res.setHeader('Access-Control-Allow-Headers',
|
|
130
|
+
if (corsConfig.allowHeaders) {
|
|
131
|
+
res.setHeader('Access-Control-Allow-Headers', corsConfig.allowHeaders);
|
|
57
132
|
}
|
|
58
|
-
if (
|
|
59
|
-
res.setHeader('Access-Control-
|
|
133
|
+
if (corsConfig.allowCredentials) {
|
|
134
|
+
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
|
60
135
|
}
|
|
61
|
-
|
|
62
|
-
|
|
136
|
+
if (corsConfig.exposeHeaders) {
|
|
137
|
+
res.setHeader('Access-Control-Expose-Headers', corsConfig.exposeHeaders);
|
|
138
|
+
}
|
|
139
|
+
if (corsConfig.maxAge) {
|
|
140
|
+
res.setHeader('Access-Control-Max-Age', corsConfig.maxAge.toString());
|
|
141
|
+
}
|
|
142
|
+
// Handle CORS preflight requests if enabled (default: true)
|
|
143
|
+
if (req.method === 'OPTIONS' && corsConfig.preflight !== false) {
|
|
63
144
|
res.statusCode = 204; // No content
|
|
64
145
|
res.end();
|
|
65
146
|
return;
|
|
66
147
|
}
|
|
67
148
|
}
|
|
149
|
+
// First implementation of applyRouteHeaderModifications moved to the second implementation below
|
|
68
150
|
/**
|
|
69
151
|
* Apply default headers to response
|
|
70
152
|
*/
|
|
@@ -80,14 +162,147 @@ export class RequestHandler {
|
|
|
80
162
|
res.setHeader('Server', 'NetworkProxy');
|
|
81
163
|
}
|
|
82
164
|
}
|
|
165
|
+
/**
|
|
166
|
+
* Apply URL rewriting based on route configuration
|
|
167
|
+
* Implements Phase 5.2: URL rewriting using route context
|
|
168
|
+
*
|
|
169
|
+
* @param req The request with the URL to rewrite
|
|
170
|
+
* @param route The route configuration containing rewrite rules
|
|
171
|
+
* @param routeContext Context for template variable resolution
|
|
172
|
+
* @returns True if URL was rewritten, false otherwise
|
|
173
|
+
*/
|
|
174
|
+
applyUrlRewriting(req, route, routeContext) {
|
|
175
|
+
// Check if route has URL rewriting configuration
|
|
176
|
+
if (!route.action.advanced?.urlRewrite) {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
const rewriteConfig = route.action.advanced.urlRewrite;
|
|
180
|
+
// Store original URL for logging
|
|
181
|
+
const originalUrl = req.url;
|
|
182
|
+
if (rewriteConfig.pattern && rewriteConfig.target) {
|
|
183
|
+
try {
|
|
184
|
+
// Create a RegExp from the pattern
|
|
185
|
+
const regex = new RegExp(rewriteConfig.pattern, rewriteConfig.flags || '');
|
|
186
|
+
// Apply rewriting with template variable resolution
|
|
187
|
+
let target = rewriteConfig.target;
|
|
188
|
+
// Replace template variables in target with values from context
|
|
189
|
+
target = TemplateUtils.resolveTemplateVariables(target, routeContext);
|
|
190
|
+
// If onlyRewritePath is set, split URL into path and query parts
|
|
191
|
+
if (rewriteConfig.onlyRewritePath && req.url) {
|
|
192
|
+
const [path, query] = req.url.split('?');
|
|
193
|
+
const rewrittenPath = path.replace(regex, target);
|
|
194
|
+
req.url = query ? `${rewrittenPath}?${query}` : rewrittenPath;
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
// Perform the replacement on the entire URL
|
|
198
|
+
req.url = req.url?.replace(regex, target);
|
|
199
|
+
}
|
|
200
|
+
this.logger.debug(`URL rewritten: ${originalUrl} -> ${req.url}`);
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
catch (err) {
|
|
204
|
+
this.logger.error(`Error in URL rewriting: ${err}`);
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Apply header modifications from route configuration
|
|
212
|
+
* Implements Phase 5.1: Route-based header manipulation
|
|
213
|
+
*/
|
|
214
|
+
applyRouteHeaderModifications(route, req, res) {
|
|
215
|
+
// Check if route has header modifications
|
|
216
|
+
if (!route.headers) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
// Apply request header modifications (these will be sent to the backend)
|
|
220
|
+
if (route.headers.request && req.headers) {
|
|
221
|
+
for (const [key, value] of Object.entries(route.headers.request)) {
|
|
222
|
+
// Skip if header already exists and we're not overriding
|
|
223
|
+
if (req.headers[key.toLowerCase()] && !value.startsWith('!')) {
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
// Handle special delete directive (!delete)
|
|
227
|
+
if (value === '!delete') {
|
|
228
|
+
delete req.headers[key.toLowerCase()];
|
|
229
|
+
this.logger.debug(`Deleted request header: ${key}`);
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
// Handle forced override (!value)
|
|
233
|
+
let finalValue;
|
|
234
|
+
if (value.startsWith('!') && value !== '!delete') {
|
|
235
|
+
// Keep the ! but resolve any templates in the rest
|
|
236
|
+
const templateValue = value.substring(1);
|
|
237
|
+
finalValue = '!' + TemplateUtils.resolveTemplateVariables(templateValue, {});
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
// Resolve templates in the entire value
|
|
241
|
+
finalValue = TemplateUtils.resolveTemplateVariables(value, {});
|
|
242
|
+
}
|
|
243
|
+
// Set the header
|
|
244
|
+
req.headers[key.toLowerCase()] = finalValue;
|
|
245
|
+
this.logger.debug(`Modified request header: ${key}=${finalValue}`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// Apply response header modifications (these will be stored for later use)
|
|
249
|
+
if (route.headers.response) {
|
|
250
|
+
for (const [key, value] of Object.entries(route.headers.response)) {
|
|
251
|
+
// Skip if header already exists and we're not overriding
|
|
252
|
+
if (res.hasHeader(key) && !value.startsWith('!')) {
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
// Handle special delete directive (!delete)
|
|
256
|
+
if (value === '!delete') {
|
|
257
|
+
res.removeHeader(key);
|
|
258
|
+
this.logger.debug(`Deleted response header: ${key}`);
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
// Handle forced override (!value)
|
|
262
|
+
let finalValue;
|
|
263
|
+
if (value.startsWith('!') && value !== '!delete') {
|
|
264
|
+
// Keep the ! but resolve any templates in the rest
|
|
265
|
+
const templateValue = value.substring(1);
|
|
266
|
+
finalValue = '!' + TemplateUtils.resolveTemplateVariables(templateValue, {});
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
// Resolve templates in the entire value
|
|
270
|
+
finalValue = TemplateUtils.resolveTemplateVariables(value, {});
|
|
271
|
+
}
|
|
272
|
+
// Set the header
|
|
273
|
+
res.setHeader(key, finalValue);
|
|
274
|
+
this.logger.debug(`Modified response header: ${key}=${finalValue}`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
83
278
|
/**
|
|
84
279
|
* Handle an HTTP request
|
|
85
280
|
*/
|
|
86
281
|
async handleRequest(req, res) {
|
|
87
282
|
// Record start time for logging
|
|
88
283
|
const startTime = Date.now();
|
|
89
|
-
//
|
|
90
|
-
|
|
284
|
+
// Get route before applying CORS (we might need its settings)
|
|
285
|
+
// Try to find a matching route using RouteManager
|
|
286
|
+
let matchingRoute = null;
|
|
287
|
+
if (this.routeManager) {
|
|
288
|
+
try {
|
|
289
|
+
// Create a connection ID for this request
|
|
290
|
+
const connectionId = `http-${Date.now()}-${Math.floor(Math.random() * 10000)}`;
|
|
291
|
+
// Create route context for function-based targets
|
|
292
|
+
const routeContext = this.contextCreator.createHttpRouteContext(req, {
|
|
293
|
+
connectionId,
|
|
294
|
+
clientIp: req.socket.remoteAddress?.replace('::ffff:', '') || '0.0.0.0',
|
|
295
|
+
serverIp: req.socket.localAddress?.replace('::ffff:', '') || '0.0.0.0',
|
|
296
|
+
tlsVersion: req.socket.getTLSVersion?.() || undefined
|
|
297
|
+
});
|
|
298
|
+
matchingRoute = this.routeManager.findMatchingRoute(toBaseContext(routeContext));
|
|
299
|
+
}
|
|
300
|
+
catch (err) {
|
|
301
|
+
this.logger.error('Error finding matching route', err);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
// Apply CORS headers with route-specific settings if available
|
|
305
|
+
this.applyCorsHeaders(res, req, matchingRoute);
|
|
91
306
|
// If this is an OPTIONS request, the response has already been ended in applyCorsHeaders
|
|
92
307
|
// so we should return early to avoid trying to set more headers
|
|
93
308
|
if (req.method === 'OPTIONS') {
|
|
@@ -99,13 +314,202 @@ export class RequestHandler {
|
|
|
99
314
|
}
|
|
100
315
|
// Apply default headers
|
|
101
316
|
this.applyDefaultHeaders(res);
|
|
102
|
-
//
|
|
317
|
+
// We already have the connection ID and routeContext from CORS handling
|
|
318
|
+
const connectionId = `http-${Date.now()}-${Math.floor(Math.random() * 10000)}`;
|
|
319
|
+
// Create route context for function-based targets (if we don't already have one)
|
|
320
|
+
const routeContext = this.contextCreator.createHttpRouteContext(req, {
|
|
321
|
+
connectionId,
|
|
322
|
+
clientIp: req.socket.remoteAddress?.replace('::ffff:', '') || '0.0.0.0',
|
|
323
|
+
serverIp: req.socket.localAddress?.replace('::ffff:', '') || '0.0.0.0',
|
|
324
|
+
tlsVersion: req.socket.getTLSVersion?.() || undefined
|
|
325
|
+
});
|
|
326
|
+
// Check security restrictions if we have a matching route
|
|
327
|
+
if (matchingRoute) {
|
|
328
|
+
// Check IP filtering and rate limiting
|
|
329
|
+
if (!this.securityManager.isAllowed(matchingRoute, routeContext)) {
|
|
330
|
+
this.logger.warn(`Access denied for ${routeContext.clientIp} to ${matchingRoute.name || 'unnamed'}`);
|
|
331
|
+
res.statusCode = 403;
|
|
332
|
+
res.end('Forbidden: Access denied by security policy');
|
|
333
|
+
if (this.metricsTracker)
|
|
334
|
+
this.metricsTracker.incrementFailedRequests();
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
// Check basic auth
|
|
338
|
+
if (matchingRoute.security?.basicAuth?.enabled) {
|
|
339
|
+
const authHeader = req.headers.authorization;
|
|
340
|
+
if (!authHeader || !authHeader.startsWith('Basic ')) {
|
|
341
|
+
// No auth header provided - send 401 with WWW-Authenticate header
|
|
342
|
+
res.statusCode = 401;
|
|
343
|
+
const realm = matchingRoute.security.basicAuth.realm || 'Protected Area';
|
|
344
|
+
res.setHeader('WWW-Authenticate', `Basic realm="${realm}", charset="UTF-8"`);
|
|
345
|
+
res.end('Authentication Required');
|
|
346
|
+
if (this.metricsTracker)
|
|
347
|
+
this.metricsTracker.incrementFailedRequests();
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
// Verify credentials
|
|
351
|
+
try {
|
|
352
|
+
const credentials = Buffer.from(authHeader.substring(6), 'base64').toString('utf-8');
|
|
353
|
+
const [username, password] = credentials.split(':');
|
|
354
|
+
if (!this.securityManager.checkBasicAuth(matchingRoute, username, password)) {
|
|
355
|
+
res.statusCode = 401;
|
|
356
|
+
const realm = matchingRoute.security.basicAuth.realm || 'Protected Area';
|
|
357
|
+
res.setHeader('WWW-Authenticate', `Basic realm="${realm}", charset="UTF-8"`);
|
|
358
|
+
res.end('Invalid Credentials');
|
|
359
|
+
if (this.metricsTracker)
|
|
360
|
+
this.metricsTracker.incrementFailedRequests();
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
catch (err) {
|
|
365
|
+
this.logger.error(`Error verifying basic auth: ${err}`);
|
|
366
|
+
res.statusCode = 401;
|
|
367
|
+
res.end('Authentication Error');
|
|
368
|
+
if (this.metricsTracker)
|
|
369
|
+
this.metricsTracker.incrementFailedRequests();
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
// Check JWT auth
|
|
374
|
+
if (matchingRoute.security?.jwtAuth?.enabled) {
|
|
375
|
+
const authHeader = req.headers.authorization;
|
|
376
|
+
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
377
|
+
// No auth header provided - send 401
|
|
378
|
+
res.statusCode = 401;
|
|
379
|
+
res.end('Authentication Required: JWT token missing');
|
|
380
|
+
if (this.metricsTracker)
|
|
381
|
+
this.metricsTracker.incrementFailedRequests();
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
// Verify token
|
|
385
|
+
const token = authHeader.substring(7);
|
|
386
|
+
if (!this.securityManager.verifyJwtToken(matchingRoute, token)) {
|
|
387
|
+
res.statusCode = 401;
|
|
388
|
+
res.end('Invalid or Expired JWT');
|
|
389
|
+
if (this.metricsTracker)
|
|
390
|
+
this.metricsTracker.incrementFailedRequests();
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
// If we found a matching route with function-based targets, use it
|
|
396
|
+
if (matchingRoute && matchingRoute.action.type === 'forward' && matchingRoute.action.target) {
|
|
397
|
+
this.logger.debug(`Found matching route: ${matchingRoute.name || 'unnamed'}`);
|
|
398
|
+
// Extract target information, resolving functions if needed
|
|
399
|
+
let targetHost;
|
|
400
|
+
let targetPort;
|
|
401
|
+
try {
|
|
402
|
+
// Check function cache for host and resolve or use cached value
|
|
403
|
+
if (typeof matchingRoute.action.target.host === 'function') {
|
|
404
|
+
// Generate a function ID for caching (use route name or ID if available)
|
|
405
|
+
const functionId = `host-${matchingRoute.id || matchingRoute.name || 'unnamed'}`;
|
|
406
|
+
// Check if we have a cached result
|
|
407
|
+
if (this.functionCache) {
|
|
408
|
+
const cachedHost = this.functionCache.getCachedHost(routeContext, functionId);
|
|
409
|
+
if (cachedHost !== undefined) {
|
|
410
|
+
targetHost = cachedHost;
|
|
411
|
+
this.logger.debug(`Using cached host value for ${functionId}`);
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
// Resolve the function and cache the result
|
|
415
|
+
const resolvedHost = matchingRoute.action.target.host(toBaseContext(routeContext));
|
|
416
|
+
targetHost = resolvedHost;
|
|
417
|
+
// Cache the result
|
|
418
|
+
this.functionCache.cacheHost(routeContext, functionId, resolvedHost);
|
|
419
|
+
this.logger.debug(`Resolved and cached function-based host to: ${Array.isArray(resolvedHost) ? resolvedHost.join(', ') : resolvedHost}`);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
else {
|
|
423
|
+
// No cache available, just resolve
|
|
424
|
+
const resolvedHost = matchingRoute.action.target.host(routeContext);
|
|
425
|
+
targetHost = resolvedHost;
|
|
426
|
+
this.logger.debug(`Resolved function-based host to: ${Array.isArray(resolvedHost) ? resolvedHost.join(', ') : resolvedHost}`);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
else {
|
|
430
|
+
targetHost = matchingRoute.action.target.host;
|
|
431
|
+
}
|
|
432
|
+
// Check function cache for port and resolve or use cached value
|
|
433
|
+
if (typeof matchingRoute.action.target.port === 'function') {
|
|
434
|
+
// Generate a function ID for caching
|
|
435
|
+
const functionId = `port-${matchingRoute.id || matchingRoute.name || 'unnamed'}`;
|
|
436
|
+
// Check if we have a cached result
|
|
437
|
+
if (this.functionCache) {
|
|
438
|
+
const cachedPort = this.functionCache.getCachedPort(routeContext, functionId);
|
|
439
|
+
if (cachedPort !== undefined) {
|
|
440
|
+
targetPort = cachedPort;
|
|
441
|
+
this.logger.debug(`Using cached port value for ${functionId}`);
|
|
442
|
+
}
|
|
443
|
+
else {
|
|
444
|
+
// Resolve the function and cache the result
|
|
445
|
+
const resolvedPort = matchingRoute.action.target.port(toBaseContext(routeContext));
|
|
446
|
+
targetPort = resolvedPort;
|
|
447
|
+
// Cache the result
|
|
448
|
+
this.functionCache.cachePort(routeContext, functionId, resolvedPort);
|
|
449
|
+
this.logger.debug(`Resolved and cached function-based port to: ${resolvedPort}`);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
453
|
+
// No cache available, just resolve
|
|
454
|
+
const resolvedPort = matchingRoute.action.target.port(routeContext);
|
|
455
|
+
targetPort = resolvedPort;
|
|
456
|
+
this.logger.debug(`Resolved function-based port to: ${resolvedPort}`);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
else {
|
|
460
|
+
targetPort = matchingRoute.action.target.port === 'preserve' ? routeContext.port : matchingRoute.action.target.port;
|
|
461
|
+
}
|
|
462
|
+
// Select a single host if an array was provided
|
|
463
|
+
const selectedHost = Array.isArray(targetHost)
|
|
464
|
+
? targetHost[Math.floor(Math.random() * targetHost.length)]
|
|
465
|
+
: targetHost;
|
|
466
|
+
// Create a destination for the connection pool
|
|
467
|
+
const destination = {
|
|
468
|
+
host: selectedHost,
|
|
469
|
+
port: targetPort
|
|
470
|
+
};
|
|
471
|
+
// Apply URL rewriting if configured
|
|
472
|
+
this.applyUrlRewriting(req, matchingRoute, routeContext);
|
|
473
|
+
// Apply header modifications if configured
|
|
474
|
+
this.applyRouteHeaderModifications(matchingRoute, req, res);
|
|
475
|
+
// Continue with handling using the resolved destination
|
|
476
|
+
HttpRequestHandler.handleHttpRequestWithDestination(req, res, destination, routeContext, startTime, this.logger, this.metricsTracker, matchingRoute // Pass the route config for additional processing
|
|
477
|
+
);
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
catch (err) {
|
|
481
|
+
this.logger.error(`Error evaluating function-based target: ${err}`);
|
|
482
|
+
res.statusCode = 500;
|
|
483
|
+
res.end('Internal Server Error: Failed to evaluate target functions');
|
|
484
|
+
if (this.metricsTracker)
|
|
485
|
+
this.metricsTracker.incrementFailedRequests();
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
// Try modern router first, then fall back to legacy routing if needed
|
|
490
|
+
if (this.router) {
|
|
491
|
+
try {
|
|
492
|
+
// Try to find a matching route using the modern router
|
|
493
|
+
const route = this.router.routeReq(req);
|
|
494
|
+
if (route && route.action.type === 'forward' && route.action.target) {
|
|
495
|
+
// Handle this route similarly to RouteManager logic
|
|
496
|
+
this.logger.debug(`Found matching route via modern router: ${route.name || 'unnamed'}`);
|
|
497
|
+
// No need to do anything here, we'll continue with legacy routing
|
|
498
|
+
// The routeManager would have already found this route if applicable
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
catch (err) {
|
|
502
|
+
this.logger.error('Error using modern router', err);
|
|
503
|
+
// Continue with legacy routing
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
// Fall back to legacy routing if no matching route found via RouteManager
|
|
103
507
|
let proxyConfig;
|
|
104
508
|
try {
|
|
105
|
-
proxyConfig = this.
|
|
509
|
+
proxyConfig = this.legacyRouter.routeReq(req);
|
|
106
510
|
}
|
|
107
511
|
catch (err) {
|
|
108
|
-
this.logger.error('Error routing request', err);
|
|
512
|
+
this.logger.error('Error routing request with legacy router', err);
|
|
109
513
|
res.statusCode = 500;
|
|
110
514
|
res.end('Internal Server Error');
|
|
111
515
|
if (this.metricsTracker)
|
|
@@ -163,128 +567,159 @@ export class RequestHandler {
|
|
|
163
567
|
});
|
|
164
568
|
return;
|
|
165
569
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Handle HTTP/2 stream requests with function-based target support
|
|
573
|
+
*/
|
|
574
|
+
async handleHttp2(stream, headers) {
|
|
575
|
+
const startTime = Date.now();
|
|
576
|
+
// Create a connection ID for this HTTP/2 stream
|
|
577
|
+
const connectionId = `http2-${Date.now()}-${Math.floor(Math.random() * 10000)}`;
|
|
578
|
+
// Get client IP and server IP from the socket
|
|
579
|
+
const socket = stream.session?.socket;
|
|
580
|
+
const clientIp = socket?.remoteAddress?.replace('::ffff:', '') || '0.0.0.0';
|
|
581
|
+
const serverIp = socket?.localAddress?.replace('::ffff:', '') || '0.0.0.0';
|
|
582
|
+
// Create route context for function-based targets
|
|
583
|
+
const routeContext = this.contextCreator.createHttp2RouteContext(stream, headers, {
|
|
584
|
+
connectionId,
|
|
585
|
+
clientIp,
|
|
586
|
+
serverIp
|
|
587
|
+
});
|
|
588
|
+
// Try to find a matching route using RouteManager
|
|
589
|
+
let matchingRoute = null;
|
|
590
|
+
if (this.routeManager) {
|
|
591
|
+
try {
|
|
592
|
+
matchingRoute = this.routeManager.findMatchingRoute(toBaseContext(routeContext));
|
|
179
593
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
// Create options for the proxy request
|
|
183
|
-
const options = {
|
|
184
|
-
hostname: destination.host,
|
|
185
|
-
port: destination.port,
|
|
186
|
-
path: req.url,
|
|
187
|
-
method: req.method,
|
|
188
|
-
headers: { ...req.headers }
|
|
189
|
-
};
|
|
190
|
-
// Remove host header to avoid issues with virtual hosts on target server
|
|
191
|
-
// The host header should match the target server's expected hostname
|
|
192
|
-
if (options.headers && options.headers.host) {
|
|
193
|
-
if (proxyConfig.rewriteHostHeader) {
|
|
194
|
-
options.headers.host = `${destination.host}:${destination.port}`;
|
|
195
|
-
}
|
|
594
|
+
catch (err) {
|
|
595
|
+
this.logger.error('Error finding matching route for HTTP/2 request', err);
|
|
196
596
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
597
|
+
}
|
|
598
|
+
// If we found a matching route with function-based targets, use it
|
|
599
|
+
if (matchingRoute && matchingRoute.action.type === 'forward' && matchingRoute.action.target) {
|
|
600
|
+
this.logger.debug(`Found matching route for HTTP/2 request: ${matchingRoute.name || 'unnamed'}`);
|
|
601
|
+
// Extract target information, resolving functions if needed
|
|
602
|
+
let targetHost;
|
|
603
|
+
let targetPort;
|
|
604
|
+
try {
|
|
605
|
+
// Check function cache for host and resolve or use cached value
|
|
606
|
+
if (typeof matchingRoute.action.target.host === 'function') {
|
|
607
|
+
// Generate a function ID for caching (use route name or ID if available)
|
|
608
|
+
const functionId = `host-http2-${matchingRoute.id || matchingRoute.name || 'unnamed'}`;
|
|
609
|
+
// Check if we have a cached result
|
|
610
|
+
if (this.functionCache) {
|
|
611
|
+
const cachedHost = this.functionCache.getCachedHost(routeContext, functionId);
|
|
612
|
+
if (cachedHost !== undefined) {
|
|
613
|
+
targetHost = cachedHost;
|
|
614
|
+
this.logger.debug(`Using cached host value for HTTP/2: ${functionId}`);
|
|
615
|
+
}
|
|
616
|
+
else {
|
|
617
|
+
// Resolve the function and cache the result
|
|
618
|
+
const resolvedHost = matchingRoute.action.target.host(toBaseContext(routeContext));
|
|
619
|
+
targetHost = resolvedHost;
|
|
620
|
+
// Cache the result
|
|
621
|
+
this.functionCache.cacheHost(routeContext, functionId, resolvedHost);
|
|
622
|
+
this.logger.debug(`Resolved and cached HTTP/2 function-based host to: ${Array.isArray(resolvedHost) ? resolvedHost.join(', ') : resolvedHost}`);
|
|
623
|
+
}
|
|
206
624
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if (this.metricsTracker) {
|
|
213
|
-
this.metricsTracker.incrementRequestsServed();
|
|
625
|
+
else {
|
|
626
|
+
// No cache available, just resolve
|
|
627
|
+
const resolvedHost = matchingRoute.action.target.host(routeContext);
|
|
628
|
+
targetHost = resolvedHost;
|
|
629
|
+
this.logger.debug(`Resolved HTTP/2 function-based host to: ${Array.isArray(resolvedHost) ? resolvedHost.join(', ') : resolvedHost}`);
|
|
214
630
|
}
|
|
215
|
-
// Log the completed request
|
|
216
|
-
const duration = Date.now() - startTime;
|
|
217
|
-
this.logger.debug(`Request completed in ${duration}ms: ${req.method} ${req.url} ${res.statusCode}`, { duration, statusCode: res.statusCode });
|
|
218
|
-
});
|
|
219
|
-
});
|
|
220
|
-
// Handle proxy request errors
|
|
221
|
-
proxyReq.on('error', (error) => {
|
|
222
|
-
const duration = Date.now() - startTime;
|
|
223
|
-
this.logger.error(`Proxy error for ${req.method} ${req.url}: ${error.message}`, { duration, error: error.message });
|
|
224
|
-
// Increment failed requests counter
|
|
225
|
-
if (this.metricsTracker) {
|
|
226
|
-
this.metricsTracker.incrementFailedRequests();
|
|
227
631
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
632
|
+
else {
|
|
633
|
+
targetHost = matchingRoute.action.target.host;
|
|
634
|
+
}
|
|
635
|
+
// Check function cache for port and resolve or use cached value
|
|
636
|
+
if (typeof matchingRoute.action.target.port === 'function') {
|
|
637
|
+
// Generate a function ID for caching
|
|
638
|
+
const functionId = `port-http2-${matchingRoute.id || matchingRoute.name || 'unnamed'}`;
|
|
639
|
+
// Check if we have a cached result
|
|
640
|
+
if (this.functionCache) {
|
|
641
|
+
const cachedPort = this.functionCache.getCachedPort(routeContext, functionId);
|
|
642
|
+
if (cachedPort !== undefined) {
|
|
643
|
+
targetPort = cachedPort;
|
|
644
|
+
this.logger.debug(`Using cached port value for HTTP/2: ${functionId}`);
|
|
645
|
+
}
|
|
646
|
+
else {
|
|
647
|
+
// Resolve the function and cache the result
|
|
648
|
+
const resolvedPort = matchingRoute.action.target.port(toBaseContext(routeContext));
|
|
649
|
+
targetPort = resolvedPort;
|
|
650
|
+
// Cache the result
|
|
651
|
+
this.functionCache.cachePort(routeContext, functionId, resolvedPort);
|
|
652
|
+
this.logger.debug(`Resolved and cached HTTP/2 function-based port to: ${resolvedPort}`);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
else {
|
|
656
|
+
// No cache available, just resolve
|
|
657
|
+
const resolvedPort = matchingRoute.action.target.port(routeContext);
|
|
658
|
+
targetPort = resolvedPort;
|
|
659
|
+
this.logger.debug(`Resolved HTTP/2 function-based port to: ${resolvedPort}`);
|
|
660
|
+
}
|
|
232
661
|
}
|
|
233
662
|
else {
|
|
234
|
-
|
|
235
|
-
res.end();
|
|
663
|
+
targetPort = matchingRoute.action.target.port === 'preserve' ? routeContext.port : matchingRoute.action.target.port;
|
|
236
664
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
665
|
+
// Select a single host if an array was provided
|
|
666
|
+
const selectedHost = Array.isArray(targetHost)
|
|
667
|
+
? targetHost[Math.floor(Math.random() * targetHost.length)]
|
|
668
|
+
: targetHost;
|
|
669
|
+
// Create a destination for forwarding
|
|
670
|
+
const destination = {
|
|
671
|
+
host: selectedHost,
|
|
672
|
+
port: targetPort
|
|
673
|
+
};
|
|
674
|
+
// Handle HTTP/2 stream based on backend protocol
|
|
675
|
+
const backendProtocol = matchingRoute.action.options?.backendProtocol || this.options.backendProtocol;
|
|
676
|
+
if (backendProtocol === 'http2') {
|
|
677
|
+
// Forward to HTTP/2 backend
|
|
678
|
+
return Http2RequestHandler.handleHttp2WithHttp2Destination(stream, headers, destination, routeContext, this.h2Sessions, this.logger, this.metricsTracker);
|
|
247
679
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
this.logger.debug(`Response error: ${error.message}`);
|
|
252
|
-
proxyReq.destroy();
|
|
253
|
-
// Increment failed requests counter on response errors
|
|
254
|
-
if (this.metricsTracker) {
|
|
255
|
-
this.metricsTracker.incrementFailedRequests();
|
|
680
|
+
else {
|
|
681
|
+
// Forward to HTTP/1.1 backend
|
|
682
|
+
return Http2RequestHandler.handleHttp2WithHttp1Destination(stream, headers, destination, routeContext, this.logger, this.metricsTracker);
|
|
256
683
|
}
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
catch (error) {
|
|
260
|
-
// Handle any unexpected errors
|
|
261
|
-
this.logger.error(`Unexpected error handling request: ${error.message}`, { error: error.stack });
|
|
262
|
-
// Increment failed requests counter
|
|
263
|
-
if (this.metricsTracker) {
|
|
264
|
-
this.metricsTracker.incrementFailedRequests();
|
|
265
|
-
}
|
|
266
|
-
if (!res.headersSent) {
|
|
267
|
-
res.statusCode = 500;
|
|
268
|
-
res.end('Internal Server Error');
|
|
269
684
|
}
|
|
270
|
-
|
|
271
|
-
|
|
685
|
+
catch (err) {
|
|
686
|
+
this.logger.error(`Error evaluating function-based target for HTTP/2: ${err}`);
|
|
687
|
+
stream.respond({ ':status': 500 });
|
|
688
|
+
stream.end('Internal Server Error: Failed to evaluate target functions');
|
|
689
|
+
if (this.metricsTracker)
|
|
690
|
+
this.metricsTracker.incrementFailedRequests();
|
|
691
|
+
return;
|
|
272
692
|
}
|
|
273
693
|
}
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* Handle HTTP/2 stream requests by proxying to HTTP/1 backends
|
|
277
|
-
*/
|
|
278
|
-
async handleHttp2(stream, headers) {
|
|
279
|
-
const startTime = Date.now();
|
|
694
|
+
// Fall back to legacy routing if no matching route found
|
|
280
695
|
const method = headers[':method'] || 'GET';
|
|
281
696
|
const path = headers[':path'] || '/';
|
|
282
697
|
// If configured to proxy to backends over HTTP/2, use HTTP/2 client sessions
|
|
283
698
|
if (this.options.backendProtocol === 'http2') {
|
|
284
699
|
const authority = headers[':authority'] || '';
|
|
285
700
|
const host = authority.split(':')[0];
|
|
286
|
-
const fakeReq = {
|
|
287
|
-
|
|
701
|
+
const fakeReq = {
|
|
702
|
+
headers: { host },
|
|
703
|
+
method: headers[':method'],
|
|
704
|
+
url: headers[':path'],
|
|
705
|
+
socket: stream.session.socket
|
|
706
|
+
};
|
|
707
|
+
// Try modern router first if available
|
|
708
|
+
let route;
|
|
709
|
+
if (this.router) {
|
|
710
|
+
try {
|
|
711
|
+
route = this.router.routeReq(fakeReq);
|
|
712
|
+
if (route && route.action.type === 'forward' && route.action.target) {
|
|
713
|
+
this.logger.debug(`Found matching HTTP/2 route via modern router: ${route.name || 'unnamed'}`);
|
|
714
|
+
// The routeManager would have already found this route if applicable
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
catch (err) {
|
|
718
|
+
this.logger.error('Error using modern router for HTTP/2', err);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
// Fall back to legacy routing
|
|
722
|
+
const proxyConfig = this.legacyRouter.routeReq(fakeReq);
|
|
288
723
|
if (!proxyConfig) {
|
|
289
724
|
stream.respond({ ':status': 404 });
|
|
290
725
|
stream.end('Not Found');
|
|
@@ -293,52 +728,35 @@ export class RequestHandler {
|
|
|
293
728
|
return;
|
|
294
729
|
}
|
|
295
730
|
const destination = this.connectionPool.getNextTarget(proxyConfig.destinationIps, proxyConfig.destinationPorts[0]);
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
if (!session || session.closed || session.destroyed) {
|
|
299
|
-
session = plugins.http2.connect(`http://${destination.host}:${destination.port}`);
|
|
300
|
-
this.h2Sessions.set(key, session);
|
|
301
|
-
session.on('error', () => this.h2Sessions.delete(key));
|
|
302
|
-
session.on('close', () => this.h2Sessions.delete(key));
|
|
303
|
-
}
|
|
304
|
-
// Build headers for backend HTTP/2 request
|
|
305
|
-
const h2Headers = {
|
|
306
|
-
':method': headers[':method'],
|
|
307
|
-
':path': headers[':path'],
|
|
308
|
-
':authority': `${destination.host}:${destination.port}`
|
|
309
|
-
};
|
|
310
|
-
for (const [k, v] of Object.entries(headers)) {
|
|
311
|
-
if (!k.startsWith(':') && typeof v === 'string') {
|
|
312
|
-
h2Headers[k] = v;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
const h2Stream2 = session.request(h2Headers);
|
|
316
|
-
stream.pipe(h2Stream2);
|
|
317
|
-
h2Stream2.on('response', (hdrs) => {
|
|
318
|
-
// Map status and headers to client
|
|
319
|
-
const resp = { ':status': hdrs[':status'] };
|
|
320
|
-
for (const [hk, hv] of Object.entries(hdrs)) {
|
|
321
|
-
if (!hk.startsWith(':') && hv)
|
|
322
|
-
resp[hk] = hv;
|
|
323
|
-
}
|
|
324
|
-
stream.respond(resp);
|
|
325
|
-
h2Stream2.pipe(stream);
|
|
326
|
-
});
|
|
327
|
-
h2Stream2.on('error', (err) => {
|
|
328
|
-
stream.respond({ ':status': 502 });
|
|
329
|
-
stream.end(`Bad Gateway: ${err.message}`);
|
|
330
|
-
if (this.metricsTracker)
|
|
331
|
-
this.metricsTracker.incrementFailedRequests();
|
|
332
|
-
});
|
|
333
|
-
return;
|
|
731
|
+
// Use the helper for HTTP/2 to HTTP/2 routing
|
|
732
|
+
return Http2RequestHandler.handleHttp2WithHttp2Destination(stream, headers, destination, routeContext, this.h2Sessions, this.logger, this.metricsTracker);
|
|
334
733
|
}
|
|
335
734
|
try {
|
|
336
735
|
// Determine host for routing
|
|
337
736
|
const authority = headers[':authority'] || '';
|
|
338
737
|
const host = authority.split(':')[0];
|
|
339
738
|
// Fake request object for routing
|
|
340
|
-
const fakeReq = {
|
|
341
|
-
|
|
739
|
+
const fakeReq = {
|
|
740
|
+
headers: { host },
|
|
741
|
+
method,
|
|
742
|
+
url: path,
|
|
743
|
+
socket: stream.session.socket
|
|
744
|
+
};
|
|
745
|
+
// Try modern router first if available
|
|
746
|
+
if (this.router) {
|
|
747
|
+
try {
|
|
748
|
+
const route = this.router.routeReq(fakeReq);
|
|
749
|
+
if (route && route.action.type === 'forward' && route.action.target) {
|
|
750
|
+
this.logger.debug(`Found matching HTTP/2 route via modern router: ${route.name || 'unnamed'}`);
|
|
751
|
+
// The routeManager would have already found this route if applicable
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
catch (err) {
|
|
755
|
+
this.logger.error('Error using modern router for HTTP/2', err);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
// Fall back to legacy routing
|
|
759
|
+
const proxyConfig = this.legacyRouter.routeReq(fakeReq);
|
|
342
760
|
if (!proxyConfig) {
|
|
343
761
|
stream.respond({ ':status': 404 });
|
|
344
762
|
stream.end('Not Found');
|
|
@@ -348,40 +766,8 @@ export class RequestHandler {
|
|
|
348
766
|
}
|
|
349
767
|
// Select backend target
|
|
350
768
|
const destination = this.connectionPool.getNextTarget(proxyConfig.destinationIps, proxyConfig.destinationPorts[0]);
|
|
351
|
-
//
|
|
352
|
-
|
|
353
|
-
for (const [key, value] of Object.entries(headers)) {
|
|
354
|
-
if (typeof key === 'string' && typeof value === 'string' && !key.startsWith(':')) {
|
|
355
|
-
outboundHeaders[key] = value;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
if (outboundHeaders.host && proxyConfig.rewriteHostHeader) {
|
|
359
|
-
outboundHeaders.host = `${destination.host}:${destination.port}`;
|
|
360
|
-
}
|
|
361
|
-
// Create HTTP/1 proxy request
|
|
362
|
-
const proxyReq = plugins.http.request({ hostname: destination.host, port: destination.port, path, method, headers: outboundHeaders }, (proxyRes) => {
|
|
363
|
-
// Map status and headers back to HTTP/2
|
|
364
|
-
const responseHeaders = {};
|
|
365
|
-
for (const [k, v] of Object.entries(proxyRes.headers)) {
|
|
366
|
-
if (v !== undefined) {
|
|
367
|
-
responseHeaders[k] = v;
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
stream.respond({ ':status': proxyRes.statusCode || 500, ...responseHeaders });
|
|
371
|
-
proxyRes.pipe(stream);
|
|
372
|
-
stream.on('close', () => proxyReq.destroy());
|
|
373
|
-
stream.on('error', () => proxyReq.destroy());
|
|
374
|
-
if (this.metricsTracker)
|
|
375
|
-
stream.on('end', () => this.metricsTracker.incrementRequestsServed());
|
|
376
|
-
});
|
|
377
|
-
proxyReq.on('error', (err) => {
|
|
378
|
-
stream.respond({ ':status': 502 });
|
|
379
|
-
stream.end(`Bad Gateway: ${err.message}`);
|
|
380
|
-
if (this.metricsTracker)
|
|
381
|
-
this.metricsTracker.incrementFailedRequests();
|
|
382
|
-
});
|
|
383
|
-
// Pipe client stream to backend
|
|
384
|
-
stream.pipe(proxyReq);
|
|
769
|
+
// Use the helper for HTTP/2 to HTTP/1 routing
|
|
770
|
+
return Http2RequestHandler.handleHttp2WithHttp1Destination(stream, headers, destination, routeContext, this.logger, this.metricsTracker);
|
|
385
771
|
}
|
|
386
772
|
catch (err) {
|
|
387
773
|
stream.respond({ ':status': 500 });
|
|
@@ -391,4 +777,4 @@ export class RequestHandler {
|
|
|
391
777
|
}
|
|
392
778
|
}
|
|
393
779
|
}
|
|
394
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVxdWVzdC1oYW5kbGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHMvcHJveGllcy9uZXR3b3JrLXByb3h5L3JlcXVlc3QtaGFuZGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBQzVDLE9BQU8sRUFBMkMsWUFBWSxFQUE0QixNQUFNLG1CQUFtQixDQUFDO0FBQ3BILE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUN0RCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFhekQ7O0dBRUc7QUFDSCxNQUFNLE9BQU8sY0FBYztJQU96QixZQUNVLE9BQTZCLEVBQzdCLGNBQThCLEVBQzlCLE1BQW1CO1FBRm5CLFlBQU8sR0FBUCxPQUFPLENBQXNCO1FBQzdCLG1CQUFjLEdBQWQsY0FBYyxDQUFnQjtRQUM5QixXQUFNLEdBQU4sTUFBTSxDQUFhO1FBVHJCLG1CQUFjLEdBQThCLEVBQUUsQ0FBQztRQUUvQyxtQkFBYyxHQUEyQixJQUFJLENBQUM7UUFDdEQsOENBQThDO1FBQ3RDLGVBQVUsR0FBa0QsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQU81RSxJQUFJLENBQUMsTUFBTSxHQUFHLFlBQVksQ0FBQyxPQUFPLENBQUMsUUFBUSxJQUFJLE1BQU0sQ0FBQyxDQUFDO0lBQ3pELENBQUM7SUFFRDs7T0FFRztJQUNJLGlCQUFpQixDQUFDLE9BQXdCO1FBQy9DLElBQUksQ0FBQyxjQUFjLEdBQUcsT0FBTyxDQUFDO0lBQ2hDLENBQUM7SUFFRDs7T0FFRztJQUNJLGlCQUFpQixDQUFDLE9BQWtDO1FBQ3pELElBQUksQ0FBQyxjQUFjLEdBQUc7WUFDcEIsR0FBRyxJQUFJLENBQUMsY0FBYztZQUN0QixHQUFHLE9BQU87U0FDWCxDQUFDO1FBQ0YsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsa0NBQWtDLENBQUMsQ0FB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
|
|
780
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVxdWVzdC1oYW5kbGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHMvcHJveGllcy9uZXR3b3JrLXByb3h5L3JlcXVlc3QtaGFuZGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBQzVDLE9BQU8sMENBQTBDLENBQUM7QUFDbEQsT0FBTyxFQUdMLFlBQVksRUFFWixZQUFZLEVBQ2IsTUFBTSxtQkFBbUIsQ0FBQztBQUMzQixPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDdEQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ3pELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUN0RCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUMvRCxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUdqRSxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sb0NBQW9DLENBQUM7QUFDbkUsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBQ25FLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQWF4RDs7R0FFRztBQUNILE1BQU0sT0FBTyxjQUFjO0lBYXpCLFlBQ1UsT0FBNkIsRUFDN0IsY0FBOEIsRUFDOUIsWUFBeUIsRUFBRSwyQ0FBMkM7SUFDdEUsWUFBMkIsRUFDM0IsYUFBbUIsRUFBRSx5REFBeUQ7SUFDOUUsTUFBWSxDQUFDLHVEQUF1RDs7UUFMcEUsWUFBTyxHQUFQLE9BQU8sQ0FBc0I7UUFDN0IsbUJBQWMsR0FBZCxjQUFjLENBQWdCO1FBQzlCLGlCQUFZLEdBQVosWUFBWSxDQUFhO1FBQ3pCLGlCQUFZLEdBQVosWUFBWSxDQUFlO1FBQzNCLGtCQUFhLEdBQWIsYUFBYSxDQUFNO1FBQ25CLFdBQU0s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
|