@push.rocks/smartproxy 22.6.0 → 23.1.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.
- package/changelog.md +18 -0
- package/dist_rust/{rustproxy → rustproxy_linux_amd64} +0 -0
- package/dist_rust/rustproxy_linux_arm64 +0 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/index.d.ts +0 -1
- package/dist_ts/index.js +1 -3
- package/dist_ts/plugins.d.ts +2 -1
- package/dist_ts/plugins.js +3 -2
- package/dist_ts/proxies/index.d.ts +0 -1
- package/dist_ts/proxies/index.js +1 -3
- package/dist_ts/proxies/smart-proxy/models/route-types.js +1 -1
- package/dist_ts/proxies/smart-proxy/rust-proxy-bridge.d.ts +9 -21
- package/dist_ts/proxies/smart-proxy/rust-proxy-bridge.js +83 -212
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +2 -3
- package/npmextra.json +3 -0
- package/package.json +13 -11
- package/readme.md +35 -31
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/index.ts +0 -3
- package/ts/plugins.ts +2 -0
- package/ts/proxies/index.ts +0 -3
- package/ts/proxies/smart-proxy/models/route-types.ts +0 -2
- package/ts/proxies/smart-proxy/rust-proxy-bridge.ts +102 -233
- package/ts/proxies/smart-proxy/smart-proxy.ts +1 -2
- package/dist_ts/common/eventUtils.d.ts +0 -14
- package/dist_ts/common/eventUtils.js +0 -20
- package/dist_ts/common/types.d.ts +0 -82
- package/dist_ts/common/types.js +0 -15
- package/dist_ts/core/utils/event-system.d.ts +0 -200
- package/dist_ts/core/utils/event-system.js +0 -224
- package/dist_ts/core/utils/event-utils.d.ts +0 -15
- package/dist_ts/core/utils/event-utils.js +0 -11
- package/dist_ts/core/utils/route-manager.d.ts +0 -88
- package/dist_ts/core/utils/route-manager.js +0 -342
- package/dist_ts/core/utils/route-utils.d.ts +0 -28
- package/dist_ts/core/utils/route-utils.js +0 -67
- package/dist_ts/detection/detectors/http-detector-v2.d.ts +0 -33
- package/dist_ts/detection/detectors/http-detector-v2.js +0 -87
- package/dist_ts/detection/detectors/tls-detector-v2.d.ts +0 -33
- package/dist_ts/detection/detectors/tls-detector-v2.js +0 -80
- package/dist_ts/detection/protocol-detector-v2.d.ts +0 -46
- package/dist_ts/detection/protocol-detector-v2.js +0 -116
- package/dist_ts/forwarding/config/forwarding-types.d.ts +0 -42
- package/dist_ts/forwarding/config/forwarding-types.js +0 -18
- package/dist_ts/forwarding/config/index.d.ts +0 -9
- package/dist_ts/forwarding/config/index.js +0 -10
- package/dist_ts/forwarding/factory/forwarding-factory.d.ts +0 -25
- package/dist_ts/forwarding/factory/forwarding-factory.js +0 -172
- package/dist_ts/forwarding/factory/index.d.ts +0 -4
- package/dist_ts/forwarding/factory/index.js +0 -5
- package/dist_ts/forwarding/handlers/base-handler.d.ts +0 -62
- package/dist_ts/forwarding/handlers/base-handler.js +0 -121
- package/dist_ts/forwarding/handlers/http-handler.d.ts +0 -30
- package/dist_ts/forwarding/handlers/http-handler.js +0 -143
- package/dist_ts/forwarding/handlers/https-passthrough-handler.d.ts +0 -29
- package/dist_ts/forwarding/handlers/https-passthrough-handler.js +0 -156
- package/dist_ts/forwarding/handlers/https-terminate-to-http-handler.d.ts +0 -36
- package/dist_ts/forwarding/handlers/https-terminate-to-http-handler.js +0 -276
- package/dist_ts/forwarding/handlers/https-terminate-to-https-handler.d.ts +0 -35
- package/dist_ts/forwarding/handlers/https-terminate-to-https-handler.js +0 -261
- package/dist_ts/forwarding/handlers/index.d.ts +0 -8
- package/dist_ts/forwarding/handlers/index.js +0 -9
- package/dist_ts/forwarding/index.d.ts +0 -13
- package/dist_ts/forwarding/index.js +0 -16
- package/dist_ts/http/index.d.ts +0 -5
- package/dist_ts/http/index.js +0 -8
- package/dist_ts/http/models/http-types.d.ts +0 -6
- package/dist_ts/http/models/http-types.js +0 -7
- package/dist_ts/http/router/index.d.ts +0 -8
- package/dist_ts/http/router/index.js +0 -7
- package/dist_ts/http/router/proxy-router.d.ts +0 -115
- package/dist_ts/http/router/proxy-router.js +0 -325
- package/dist_ts/http/router/route-router.d.ts +0 -108
- package/dist_ts/http/router/route-router.js +0 -393
- package/dist_ts/protocols/tls/constants.d.ts +0 -122
- package/dist_ts/protocols/tls/constants.js +0 -135
- package/dist_ts/protocols/tls/parser.d.ts +0 -53
- package/dist_ts/protocols/tls/parser.js +0 -294
- package/dist_ts/protocols/tls/types.d.ts +0 -65
- package/dist_ts/protocols/tls/types.js +0 -5
- package/dist_ts/proxies/http-proxy/certificate-manager.d.ts +0 -95
- package/dist_ts/proxies/http-proxy/certificate-manager.js +0 -214
- package/dist_ts/proxies/http-proxy/connection-pool.d.ts +0 -47
- package/dist_ts/proxies/http-proxy/connection-pool.js +0 -195
- package/dist_ts/proxies/http-proxy/context-creator.d.ts +0 -34
- package/dist_ts/proxies/http-proxy/context-creator.js +0 -108
- package/dist_ts/proxies/http-proxy/default-certificates.d.ts +0 -54
- package/dist_ts/proxies/http-proxy/default-certificates.js +0 -127
- package/dist_ts/proxies/http-proxy/function-cache.d.ts +0 -95
- package/dist_ts/proxies/http-proxy/function-cache.js +0 -215
- package/dist_ts/proxies/http-proxy/handlers/index.d.ts +0 -4
- package/dist_ts/proxies/http-proxy/handlers/index.js +0 -6
- package/dist_ts/proxies/http-proxy/handlers/redirect-handler.d.ts +0 -18
- package/dist_ts/proxies/http-proxy/handlers/redirect-handler.js +0 -78
- package/dist_ts/proxies/http-proxy/handlers/static-handler.d.ts +0 -19
- package/dist_ts/proxies/http-proxy/handlers/static-handler.js +0 -211
- package/dist_ts/proxies/http-proxy/http-proxy.d.ts +0 -117
- package/dist_ts/proxies/http-proxy/http-proxy.js +0 -521
- package/dist_ts/proxies/http-proxy/http-request-handler.d.ts +0 -40
- package/dist_ts/proxies/http-proxy/http-request-handler.js +0 -257
- package/dist_ts/proxies/http-proxy/http2-request-handler.d.ts +0 -24
- package/dist_ts/proxies/http-proxy/http2-request-handler.js +0 -201
- package/dist_ts/proxies/http-proxy/index.d.ts +0 -14
- package/dist_ts/proxies/http-proxy/index.js +0 -16
- package/dist_ts/proxies/http-proxy/models/http-types.d.ts +0 -117
- package/dist_ts/proxies/http-proxy/models/http-types.js +0 -92
- package/dist_ts/proxies/http-proxy/models/index.d.ts +0 -5
- package/dist_ts/proxies/http-proxy/models/index.js +0 -6
- package/dist_ts/proxies/http-proxy/models/types.d.ts +0 -75
- package/dist_ts/proxies/http-proxy/models/types.js +0 -35
- package/dist_ts/proxies/http-proxy/request-handler.d.ts +0 -97
- package/dist_ts/proxies/http-proxy/request-handler.js +0 -737
- package/dist_ts/proxies/http-proxy/security-manager.d.ts +0 -98
- package/dist_ts/proxies/http-proxy/security-manager.js +0 -341
- package/dist_ts/proxies/http-proxy/websocket-handler.d.ts +0 -50
- package/dist_ts/proxies/http-proxy/websocket-handler.js +0 -505
- package/dist_ts/proxies/nftables-proxy/index.d.ts +0 -6
- package/dist_ts/proxies/nftables-proxy/index.js +0 -7
- package/dist_ts/proxies/nftables-proxy/models/errors.d.ts +0 -15
- package/dist_ts/proxies/nftables-proxy/models/errors.js +0 -28
- package/dist_ts/proxies/nftables-proxy/models/index.d.ts +0 -5
- package/dist_ts/proxies/nftables-proxy/models/index.js +0 -6
- package/dist_ts/proxies/nftables-proxy/models/interfaces.d.ts +0 -75
- package/dist_ts/proxies/nftables-proxy/models/interfaces.js +0 -5
- package/dist_ts/proxies/nftables-proxy/nftables-proxy.d.ts +0 -124
- package/dist_ts/proxies/nftables-proxy/nftables-proxy.js +0 -1374
- package/dist_ts/proxies/nftables-proxy/utils/index.d.ts +0 -9
- package/dist_ts/proxies/nftables-proxy/utils/index.js +0 -12
- package/dist_ts/proxies/nftables-proxy/utils/nft-command-executor.d.ts +0 -66
- package/dist_ts/proxies/nftables-proxy/utils/nft-command-executor.js +0 -131
- package/dist_ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.d.ts +0 -39
- package/dist_ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.js +0 -112
- package/dist_ts/proxies/nftables-proxy/utils/nft-rule-validator.d.ts +0 -59
- package/dist_ts/proxies/nftables-proxy/utils/nft-rule-validator.js +0 -130
- package/dist_ts/proxies/smart-proxy/acme-state-manager.d.ts +0 -42
- package/dist_ts/proxies/smart-proxy/acme-state-manager.js +0 -101
- package/dist_ts/proxies/smart-proxy/cert-store.d.ts +0 -10
- package/dist_ts/proxies/smart-proxy/cert-store.js +0 -72
- package/dist_ts/proxies/smart-proxy/certificate-manager.d.ts +0 -164
- package/dist_ts/proxies/smart-proxy/certificate-manager.js +0 -745
- package/dist_ts/proxies/smart-proxy/connection-manager.d.ts +0 -128
- package/dist_ts/proxies/smart-proxy/connection-manager.js +0 -689
- package/dist_ts/proxies/smart-proxy/http-proxy-bridge.d.ts +0 -43
- package/dist_ts/proxies/smart-proxy/http-proxy-bridge.js +0 -180
- package/dist_ts/proxies/smart-proxy/metrics-collector.d.ts +0 -98
- package/dist_ts/proxies/smart-proxy/metrics-collector.js +0 -355
- package/dist_ts/proxies/smart-proxy/nftables-manager.d.ts +0 -82
- package/dist_ts/proxies/smart-proxy/nftables-manager.js +0 -237
- package/dist_ts/proxies/smart-proxy/port-manager.d.ts +0 -117
- package/dist_ts/proxies/smart-proxy/port-manager.js +0 -318
- package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +0 -60
- package/dist_ts/proxies/smart-proxy/route-connection-handler.js +0 -1407
- package/dist_ts/proxies/smart-proxy/route-manager.d.ts +0 -112
- package/dist_ts/proxies/smart-proxy/route-manager.js +0 -453
- package/dist_ts/proxies/smart-proxy/route-orchestrator.d.ts +0 -56
- package/dist_ts/proxies/smart-proxy/route-orchestrator.js +0 -204
- package/dist_ts/proxies/smart-proxy/rust-binary-locator.d.ts +0 -23
- package/dist_ts/proxies/smart-proxy/rust-binary-locator.js +0 -104
- package/dist_ts/proxies/smart-proxy/security-manager.d.ts +0 -74
- package/dist_ts/proxies/smart-proxy/security-manager.js +0 -227
- package/dist_ts/proxies/smart-proxy/throughput-tracker.d.ts +0 -36
- package/dist_ts/proxies/smart-proxy/throughput-tracker.js +0 -115
- package/dist_ts/proxies/smart-proxy/timeout-manager.d.ts +0 -48
- package/dist_ts/proxies/smart-proxy/timeout-manager.js +0 -158
- package/dist_ts/proxies/smart-proxy/tls-manager.d.ts +0 -50
- package/dist_ts/proxies/smart-proxy/tls-manager.js +0 -110
- package/dist_ts/proxies/smart-proxy/utils/route-patterns.d.ts +0 -161
- package/dist_ts/proxies/smart-proxy/utils/route-patterns.js +0 -282
- package/dist_ts/proxies/smart-proxy/utils/route-validators.d.ts +0 -73
- package/dist_ts/proxies/smart-proxy/utils/route-validators.js +0 -259
- package/dist_ts/routing/router/proxy-router.d.ts +0 -115
- package/dist_ts/routing/router/proxy-router.js +0 -325
- package/dist_ts/routing/router/route-router.d.ts +0 -108
- package/dist_ts/routing/router/route-router.js +0 -393
- package/dist_ts/tls/alerts/index.d.ts +0 -4
- package/dist_ts/tls/alerts/index.js +0 -5
- package/dist_ts/tls/alerts/tls-alert.d.ts +0 -150
- package/dist_ts/tls/alerts/tls-alert.js +0 -226
- package/dist_ts/tls/sni/client-hello-parser.d.ts +0 -100
- package/dist_ts/tls/sni/client-hello-parser.js +0 -464
- package/dist_ts/tls/sni/sni-extraction.d.ts +0 -58
- package/dist_ts/tls/sni/sni-extraction.js +0 -275
- package/dist_ts/tls/utils/index.d.ts +0 -4
- package/dist_ts/tls/utils/index.js +0 -5
- package/dist_ts/tls/utils/tls-utils.d.ts +0 -49
- package/dist_ts/tls/utils/tls-utils.js +0 -75
- package/ts/proxies/nftables-proxy/index.ts +0 -6
- package/ts/proxies/nftables-proxy/models/errors.ts +0 -30
- package/ts/proxies/nftables-proxy/models/index.ts +0 -5
- package/ts/proxies/nftables-proxy/models/interfaces.ts +0 -94
- package/ts/proxies/nftables-proxy/nftables-proxy.ts +0 -1754
- package/ts/proxies/nftables-proxy/utils/index.ts +0 -38
- package/ts/proxies/nftables-proxy/utils/nft-command-executor.ts +0 -162
- package/ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.ts +0 -125
- package/ts/proxies/nftables-proxy/utils/nft-rule-validator.ts +0 -156
- package/ts/proxies/smart-proxy/rust-binary-locator.ts +0 -112
|
@@ -1,521 +0,0 @@
|
|
|
1
|
-
import * as plugins from '../../plugins.js';
|
|
2
|
-
import { createLogger, } from './models/types.js';
|
|
3
|
-
import { SharedRouteManager as RouteManager } from '../../core/routing/route-manager.js';
|
|
4
|
-
import { createBaseRouteContext } from '../../core/models/route-context.js';
|
|
5
|
-
import { DefaultCertificateProvider } from './default-certificates.js';
|
|
6
|
-
import { ConnectionPool } from './connection-pool.js';
|
|
7
|
-
import { RequestHandler } from './request-handler.js';
|
|
8
|
-
import { WebSocketHandler } from './websocket-handler.js';
|
|
9
|
-
import { HttpRouter } from '../../routing/router/index.js';
|
|
10
|
-
import { cleanupSocket } from '../../core/utils/socket-utils.js';
|
|
11
|
-
import { FunctionCache } from './function-cache.js';
|
|
12
|
-
import { SecurityManager } from './security-manager.js';
|
|
13
|
-
import { connectionLogDeduplicator } from '../../core/utils/log-deduplicator.js';
|
|
14
|
-
/**
|
|
15
|
-
* HttpProxy provides a reverse proxy with TLS termination, WebSocket support,
|
|
16
|
-
* automatic certificate management, and high-performance connection pooling.
|
|
17
|
-
* Handles all HTTP/HTTPS traffic including redirects, ACME challenges, and static routes.
|
|
18
|
-
*/
|
|
19
|
-
export class HttpProxy {
|
|
20
|
-
// Provide a minimal JSON representation to avoid circular references during deep equality checks
|
|
21
|
-
toJSON() {
|
|
22
|
-
return {};
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Creates a new HttpProxy instance
|
|
26
|
-
*/
|
|
27
|
-
constructor(optionsArg) {
|
|
28
|
-
this.routes = [];
|
|
29
|
-
this.router = new HttpRouter(); // Unified HTTP router
|
|
30
|
-
// State tracking
|
|
31
|
-
this.socketMap = new plugins.lik.ObjectMap();
|
|
32
|
-
this.activeContexts = new Set();
|
|
33
|
-
this.connectedClients = 0;
|
|
34
|
-
this.startTime = 0;
|
|
35
|
-
this.requestsServed = 0;
|
|
36
|
-
this.failedRequests = 0;
|
|
37
|
-
// Tracking for SmartProxy integration
|
|
38
|
-
this.portProxyConnections = 0;
|
|
39
|
-
this.tlsTerminatedConnections = 0;
|
|
40
|
-
// Set default options
|
|
41
|
-
this.options = {
|
|
42
|
-
port: optionsArg.port,
|
|
43
|
-
maxConnections: optionsArg.maxConnections || 10000,
|
|
44
|
-
keepAliveTimeout: optionsArg.keepAliveTimeout || 120000, // 2 minutes
|
|
45
|
-
headersTimeout: optionsArg.headersTimeout || 60000, // 1 minute
|
|
46
|
-
logLevel: optionsArg.logLevel || 'info',
|
|
47
|
-
cors: optionsArg.cors || {
|
|
48
|
-
allowOrigin: '*',
|
|
49
|
-
allowMethods: 'GET, POST, PUT, DELETE, OPTIONS',
|
|
50
|
-
allowHeaders: 'Content-Type, Authorization',
|
|
51
|
-
maxAge: 86400
|
|
52
|
-
},
|
|
53
|
-
// Defaults for SmartProxy integration
|
|
54
|
-
connectionPoolSize: optionsArg.connectionPoolSize || 50,
|
|
55
|
-
portProxyIntegration: optionsArg.portProxyIntegration || false,
|
|
56
|
-
// Backend protocol (http1 or http2)
|
|
57
|
-
backendProtocol: optionsArg.backendProtocol || 'http1',
|
|
58
|
-
// Default ACME options
|
|
59
|
-
acme: {
|
|
60
|
-
enabled: optionsArg.acme?.enabled || false,
|
|
61
|
-
port: optionsArg.acme?.port || 80,
|
|
62
|
-
accountEmail: optionsArg.acme?.accountEmail || 'admin@example.com',
|
|
63
|
-
useProduction: optionsArg.acme?.useProduction || false, // Default to staging for safety
|
|
64
|
-
renewThresholdDays: optionsArg.acme?.renewThresholdDays || 30,
|
|
65
|
-
autoRenew: optionsArg.acme?.autoRenew !== false, // Default to true
|
|
66
|
-
certificateStore: optionsArg.acme?.certificateStore || './certs',
|
|
67
|
-
skipConfiguredCerts: optionsArg.acme?.skipConfiguredCerts || false
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
// Initialize logger
|
|
71
|
-
this.logger = createLogger(this.options.logLevel);
|
|
72
|
-
// Initialize route manager
|
|
73
|
-
this.routeManager = new RouteManager({
|
|
74
|
-
logger: this.logger,
|
|
75
|
-
enableDetailedLogging: this.options.logLevel === 'debug',
|
|
76
|
-
routes: []
|
|
77
|
-
});
|
|
78
|
-
// Initialize function cache
|
|
79
|
-
this.functionCache = new FunctionCache(this.logger, {
|
|
80
|
-
maxCacheSize: this.options.functionCacheSize || 1000,
|
|
81
|
-
defaultTtl: this.options.functionCacheTtl || 5000
|
|
82
|
-
});
|
|
83
|
-
// Initialize security manager
|
|
84
|
-
this.securityManager = new SecurityManager(this.logger, [], this.options.maxConnectionsPerIP || 100, this.options.connectionRateLimitPerMinute || 300);
|
|
85
|
-
// Initialize other components
|
|
86
|
-
this.defaultCertProvider = new DefaultCertificateProvider(this.logger);
|
|
87
|
-
this.connectionPool = new ConnectionPool(this.options);
|
|
88
|
-
this.requestHandler = new RequestHandler(this.options, this.connectionPool, this.routeManager, this.functionCache, this.router);
|
|
89
|
-
this.webSocketHandler = new WebSocketHandler(this.options, this.connectionPool, this.routes // Pass current routes to WebSocketHandler
|
|
90
|
-
);
|
|
91
|
-
// Connect request handler to this metrics tracker
|
|
92
|
-
this.requestHandler.setMetricsTracker(this);
|
|
93
|
-
// Initialize with any provided routes
|
|
94
|
-
if (this.options.routes && this.options.routes.length > 0) {
|
|
95
|
-
this.updateRouteConfigs(this.options.routes);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Implements IMetricsTracker interface to increment request counters
|
|
100
|
-
*/
|
|
101
|
-
incrementRequestsServed() {
|
|
102
|
-
this.requestsServed++;
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Implements IMetricsTracker interface to increment failed request counters
|
|
106
|
-
*/
|
|
107
|
-
incrementFailedRequests() {
|
|
108
|
-
this.failedRequests++;
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Returns the port number this HttpProxy is listening on
|
|
112
|
-
* Useful for SmartProxy to determine where to forward connections
|
|
113
|
-
*/
|
|
114
|
-
getListeningPort() {
|
|
115
|
-
// If the server is running, get the actual listening port
|
|
116
|
-
if (this.httpsServer && this.httpsServer.address()) {
|
|
117
|
-
const address = this.httpsServer.address();
|
|
118
|
-
if (address && typeof address === 'object' && 'port' in address) {
|
|
119
|
-
return address.port;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
// Fallback to configured port
|
|
123
|
-
return this.options.port;
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Updates the server capacity settings
|
|
127
|
-
* @param maxConnections Maximum number of simultaneous connections
|
|
128
|
-
* @param keepAliveTimeout Keep-alive timeout in milliseconds
|
|
129
|
-
* @param connectionPoolSize Size of the connection pool per backend
|
|
130
|
-
*/
|
|
131
|
-
updateCapacity(maxConnections, keepAliveTimeout, connectionPoolSize) {
|
|
132
|
-
if (maxConnections !== undefined) {
|
|
133
|
-
this.options.maxConnections = maxConnections;
|
|
134
|
-
this.logger.info(`Updated max connections to ${maxConnections}`);
|
|
135
|
-
}
|
|
136
|
-
if (keepAliveTimeout !== undefined) {
|
|
137
|
-
this.options.keepAliveTimeout = keepAliveTimeout;
|
|
138
|
-
if (this.httpsServer) {
|
|
139
|
-
// HTTP/2 servers have setTimeout method for timeout management
|
|
140
|
-
this.httpsServer.setTimeout(keepAliveTimeout);
|
|
141
|
-
this.logger.info(`Updated server timeout to ${keepAliveTimeout}ms`);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
if (connectionPoolSize !== undefined) {
|
|
145
|
-
this.options.connectionPoolSize = connectionPoolSize;
|
|
146
|
-
this.logger.info(`Updated connection pool size to ${connectionPoolSize}`);
|
|
147
|
-
// Clean up excess connections in the pool
|
|
148
|
-
this.connectionPool.cleanupConnectionPool();
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Returns current server metrics
|
|
153
|
-
* Useful for SmartProxy to determine which HttpProxy to use for load balancing
|
|
154
|
-
*/
|
|
155
|
-
getMetrics() {
|
|
156
|
-
return {
|
|
157
|
-
activeConnections: this.connectedClients,
|
|
158
|
-
totalRequests: this.requestsServed,
|
|
159
|
-
failedRequests: this.failedRequests,
|
|
160
|
-
portProxyConnections: this.portProxyConnections,
|
|
161
|
-
tlsTerminatedConnections: this.tlsTerminatedConnections,
|
|
162
|
-
connectionPoolSize: this.connectionPool.getPoolStatus(),
|
|
163
|
-
uptime: Math.floor((Date.now() - this.startTime) / 1000),
|
|
164
|
-
memoryUsage: process.memoryUsage(),
|
|
165
|
-
activeWebSockets: this.webSocketHandler.getConnectionInfo().activeConnections,
|
|
166
|
-
functionCache: this.functionCache.getStats()
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
/**
|
|
170
|
-
* Starts the proxy server
|
|
171
|
-
*/
|
|
172
|
-
async start() {
|
|
173
|
-
this.startTime = Date.now();
|
|
174
|
-
// Create HTTP/2 server with HTTP/1 fallback
|
|
175
|
-
const defaultCerts = this.defaultCertProvider.getDefaultCertificates();
|
|
176
|
-
this.httpsServer = plugins.http2.createSecureServer({
|
|
177
|
-
key: defaultCerts.key,
|
|
178
|
-
cert: defaultCerts.cert,
|
|
179
|
-
allowHTTP1: true,
|
|
180
|
-
ALPNProtocols: ['h2', 'http/1.1']
|
|
181
|
-
});
|
|
182
|
-
// Track raw TCP connections for metrics and limits
|
|
183
|
-
this.setupConnectionTracking();
|
|
184
|
-
// Handle incoming HTTP/2 streams
|
|
185
|
-
this.httpsServer.on('stream', (stream, headers) => {
|
|
186
|
-
this.requestHandler.handleHttp2(stream, headers);
|
|
187
|
-
});
|
|
188
|
-
// Handle HTTP/1.x fallback requests
|
|
189
|
-
this.httpsServer.on('request', (req, res) => {
|
|
190
|
-
this.requestHandler.handleRequest(req, res);
|
|
191
|
-
});
|
|
192
|
-
// Setup WebSocket support on HTTP/1 fallback
|
|
193
|
-
this.webSocketHandler.initialize(this.httpsServer);
|
|
194
|
-
// Start metrics logging
|
|
195
|
-
this.setupMetricsCollection();
|
|
196
|
-
// Start periodic connection pool cleanup
|
|
197
|
-
this.connectionPoolCleanupInterval = this.connectionPool.setupPeriodicCleanup();
|
|
198
|
-
// Start the server
|
|
199
|
-
return new Promise((resolve) => {
|
|
200
|
-
this.httpsServer.listen(this.options.port, () => {
|
|
201
|
-
this.logger.info(`HttpProxy started on port ${this.options.port}`);
|
|
202
|
-
resolve();
|
|
203
|
-
});
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
/**
|
|
207
|
-
* Check if an address is a loopback address (IPv4 or IPv6)
|
|
208
|
-
*/
|
|
209
|
-
isLoopback(addr) {
|
|
210
|
-
if (!addr)
|
|
211
|
-
return false;
|
|
212
|
-
// Check for IPv6 loopback
|
|
213
|
-
if (addr === '::1')
|
|
214
|
-
return true;
|
|
215
|
-
// Handle IPv6-mapped IPv4 addresses
|
|
216
|
-
if (addr.startsWith('::ffff:')) {
|
|
217
|
-
addr = addr.substring(7);
|
|
218
|
-
}
|
|
219
|
-
// Check for IPv4 loopback range (127.0.0.0/8)
|
|
220
|
-
return addr.startsWith('127.');
|
|
221
|
-
}
|
|
222
|
-
/**
|
|
223
|
-
* Sets up tracking of TCP connections
|
|
224
|
-
*/
|
|
225
|
-
setupConnectionTracking() {
|
|
226
|
-
this.httpsServer.on('connection', (connection) => {
|
|
227
|
-
let remoteIP = connection.remoteAddress || '';
|
|
228
|
-
const connectionId = Math.random().toString(36).substring(2, 15);
|
|
229
|
-
const isFromSmartProxy = this.options.portProxyIntegration && this.isLoopback(connection.remoteAddress);
|
|
230
|
-
// For SmartProxy connections, wait for CLIENT_IP header
|
|
231
|
-
if (isFromSmartProxy) {
|
|
232
|
-
const MAX_PREFACE = 256; // bytes - prevent DoS
|
|
233
|
-
const HEADER_TIMEOUT_MS = 2000; // timeout for header parsing (increased for slow networks)
|
|
234
|
-
let headerTimer;
|
|
235
|
-
let buffered = Buffer.alloc(0);
|
|
236
|
-
const onData = (chunk) => {
|
|
237
|
-
buffered = Buffer.concat([buffered, chunk]);
|
|
238
|
-
// Prevent unbounded growth
|
|
239
|
-
if (buffered.length > MAX_PREFACE) {
|
|
240
|
-
connection.removeListener('data', onData);
|
|
241
|
-
if (headerTimer)
|
|
242
|
-
clearTimeout(headerTimer);
|
|
243
|
-
this.logger.warn('Header preface too large, closing connection');
|
|
244
|
-
connection.destroy();
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
247
|
-
const idx = buffered.indexOf('\r\n');
|
|
248
|
-
if (idx !== -1) {
|
|
249
|
-
const headerLine = buffered.slice(0, idx).toString('utf8');
|
|
250
|
-
if (headerLine.startsWith('CLIENT_IP:')) {
|
|
251
|
-
remoteIP = headerLine.substring(10).trim();
|
|
252
|
-
this.logger.debug(`Extracted client IP from SmartProxy: ${remoteIP}`);
|
|
253
|
-
}
|
|
254
|
-
// Clean up listener and timer
|
|
255
|
-
connection.removeListener('data', onData);
|
|
256
|
-
if (headerTimer)
|
|
257
|
-
clearTimeout(headerTimer);
|
|
258
|
-
// Put remaining data back onto the stream
|
|
259
|
-
const remaining = buffered.slice(idx + 2);
|
|
260
|
-
if (remaining.length > 0) {
|
|
261
|
-
connection.unshift(remaining);
|
|
262
|
-
}
|
|
263
|
-
// Store the real IP on the connection
|
|
264
|
-
connection._realRemoteIP = remoteIP;
|
|
265
|
-
// Validate the real IP
|
|
266
|
-
const ipValidation = this.securityManager.validateIP(remoteIP);
|
|
267
|
-
if (!ipValidation.allowed) {
|
|
268
|
-
connectionLogDeduplicator.log('ip-rejected', 'warn', `HttpProxy connection rejected (via SmartProxy)`, { remoteIP, reason: ipValidation.reason, component: 'http-proxy' }, remoteIP);
|
|
269
|
-
connection.destroy();
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
// Track connection by real IP
|
|
273
|
-
this.securityManager.trackConnectionByIP(remoteIP, connectionId);
|
|
274
|
-
}
|
|
275
|
-
};
|
|
276
|
-
// Set timeout for header parsing
|
|
277
|
-
headerTimer = setTimeout(() => {
|
|
278
|
-
connection.removeListener('data', onData);
|
|
279
|
-
this.logger.warn('Header parsing timeout, closing connection');
|
|
280
|
-
connection.destroy();
|
|
281
|
-
}, HEADER_TIMEOUT_MS);
|
|
282
|
-
// Unref the timer so it doesn't keep the process alive
|
|
283
|
-
if (headerTimer.unref)
|
|
284
|
-
headerTimer.unref();
|
|
285
|
-
// Use prependListener to get data first
|
|
286
|
-
connection.prependListener('data', onData);
|
|
287
|
-
}
|
|
288
|
-
else {
|
|
289
|
-
// Direct connection - validate immediately
|
|
290
|
-
const ipValidation = this.securityManager.validateIP(remoteIP);
|
|
291
|
-
if (!ipValidation.allowed) {
|
|
292
|
-
connectionLogDeduplicator.log('ip-rejected', 'warn', `HttpProxy connection rejected`, { remoteIP, reason: ipValidation.reason, component: 'http-proxy' }, remoteIP);
|
|
293
|
-
connection.destroy();
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
// Track connection by IP
|
|
297
|
-
this.securityManager.trackConnectionByIP(remoteIP, connectionId);
|
|
298
|
-
}
|
|
299
|
-
// Then check global max connections
|
|
300
|
-
if (this.socketMap.getArray().length >= this.options.maxConnections) {
|
|
301
|
-
connectionLogDeduplicator.log('connection-rejected', 'warn', 'HttpProxy max connections reached', {
|
|
302
|
-
reason: 'global-limit',
|
|
303
|
-
currentConnections: this.socketMap.getArray().length,
|
|
304
|
-
maxConnections: this.options.maxConnections,
|
|
305
|
-
component: 'http-proxy'
|
|
306
|
-
}, 'http-proxy-global-limit');
|
|
307
|
-
connection.destroy();
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
// Add connection to tracking with metadata
|
|
311
|
-
connection._connectionId = connectionId;
|
|
312
|
-
connection._remoteIP = remoteIP;
|
|
313
|
-
this.socketMap.add(connection);
|
|
314
|
-
this.connectedClients = this.socketMap.getArray().length;
|
|
315
|
-
// Check for connection from SmartProxy by inspecting the source port
|
|
316
|
-
const localPort = connection.localPort || 0;
|
|
317
|
-
const remotePort = connection.remotePort || 0;
|
|
318
|
-
// If this connection is from a SmartProxy
|
|
319
|
-
if (isFromSmartProxy) {
|
|
320
|
-
this.portProxyConnections++;
|
|
321
|
-
this.logger.debug(`New connection from SmartProxy for client ${remoteIP} (local: ${localPort}, remote: ${remotePort})`);
|
|
322
|
-
}
|
|
323
|
-
else {
|
|
324
|
-
this.logger.debug(`New direct connection from ${remoteIP} (local: ${localPort}, remote: ${remotePort})`);
|
|
325
|
-
}
|
|
326
|
-
// Setup connection cleanup handlers
|
|
327
|
-
const cleanupConnection = () => {
|
|
328
|
-
if (this.socketMap.checkForObject(connection)) {
|
|
329
|
-
this.socketMap.remove(connection);
|
|
330
|
-
this.connectedClients = this.socketMap.getArray().length;
|
|
331
|
-
// Remove IP tracking
|
|
332
|
-
const connId = connection._connectionId;
|
|
333
|
-
const connIP = connection._realRemoteIP || connection._remoteIP;
|
|
334
|
-
if (connId && connIP) {
|
|
335
|
-
this.securityManager.removeConnectionByIP(connIP, connId);
|
|
336
|
-
}
|
|
337
|
-
// If this was a SmartProxy connection, decrement the counter
|
|
338
|
-
if (this.options.portProxyIntegration && connection.remoteAddress?.includes('127.0.0.1')) {
|
|
339
|
-
this.portProxyConnections--;
|
|
340
|
-
}
|
|
341
|
-
this.logger.debug(`Connection closed from ${connIP || 'unknown'}. ${this.connectedClients} connections remaining`);
|
|
342
|
-
}
|
|
343
|
-
};
|
|
344
|
-
connection.on('close', cleanupConnection);
|
|
345
|
-
connection.on('error', (err) => {
|
|
346
|
-
this.logger.debug('Connection error', err);
|
|
347
|
-
cleanupConnection();
|
|
348
|
-
});
|
|
349
|
-
connection.on('end', cleanupConnection);
|
|
350
|
-
});
|
|
351
|
-
// Track TLS handshake completions
|
|
352
|
-
this.httpsServer.on('secureConnection', (tlsSocket) => {
|
|
353
|
-
this.tlsTerminatedConnections++;
|
|
354
|
-
this.logger.debug('TLS handshake completed, connection secured');
|
|
355
|
-
});
|
|
356
|
-
}
|
|
357
|
-
/**
|
|
358
|
-
* Sets up metrics collection
|
|
359
|
-
*/
|
|
360
|
-
setupMetricsCollection() {
|
|
361
|
-
this.metricsInterval = setInterval(() => {
|
|
362
|
-
const uptime = Math.floor((Date.now() - this.startTime) / 1000);
|
|
363
|
-
const metrics = {
|
|
364
|
-
uptime,
|
|
365
|
-
activeConnections: this.connectedClients,
|
|
366
|
-
totalRequests: this.requestsServed,
|
|
367
|
-
failedRequests: this.failedRequests,
|
|
368
|
-
portProxyConnections: this.portProxyConnections,
|
|
369
|
-
tlsTerminatedConnections: this.tlsTerminatedConnections,
|
|
370
|
-
activeWebSockets: this.webSocketHandler.getConnectionInfo().activeConnections,
|
|
371
|
-
memoryUsage: process.memoryUsage(),
|
|
372
|
-
activeContexts: Array.from(this.activeContexts),
|
|
373
|
-
connectionPool: this.connectionPool.getPoolStatus()
|
|
374
|
-
};
|
|
375
|
-
this.logger.debug('Proxy metrics', metrics);
|
|
376
|
-
}, 60000); // Log metrics every minute
|
|
377
|
-
// Don't keep process alive just for metrics
|
|
378
|
-
if (this.metricsInterval.unref) {
|
|
379
|
-
this.metricsInterval.unref();
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
/**
|
|
383
|
-
* Updates the route configurations - this is the primary method for configuring HttpProxy
|
|
384
|
-
* @param routes The new route configurations to use
|
|
385
|
-
*/
|
|
386
|
-
async updateRouteConfigs(routes) {
|
|
387
|
-
this.logger.info(`Updating route configurations (${routes.length} routes)`);
|
|
388
|
-
// Update routes in RouteManager, modern router, WebSocketHandler, and SecurityManager
|
|
389
|
-
this.routeManager.updateRoutes(routes);
|
|
390
|
-
this.router.setRoutes(routes);
|
|
391
|
-
this.webSocketHandler.setRoutes(routes);
|
|
392
|
-
this.requestHandler.securityManager.setRoutes(routes);
|
|
393
|
-
this.routes = routes;
|
|
394
|
-
// Collect all domains and certificates for configuration
|
|
395
|
-
const currentHostnames = new Set();
|
|
396
|
-
const certificateUpdates = new Map();
|
|
397
|
-
// Process each route to extract domain and certificate information
|
|
398
|
-
for (const route of routes) {
|
|
399
|
-
// Skip non-forward routes or routes without domains
|
|
400
|
-
if (route.action.type !== 'forward' || !route.match.domains) {
|
|
401
|
-
continue;
|
|
402
|
-
}
|
|
403
|
-
// Get domains from route
|
|
404
|
-
const domains = Array.isArray(route.match.domains)
|
|
405
|
-
? route.match.domains
|
|
406
|
-
: [route.match.domains];
|
|
407
|
-
// Process each domain
|
|
408
|
-
for (const domain of domains) {
|
|
409
|
-
// Skip wildcard domains for direct host configuration
|
|
410
|
-
if (domain.includes('*')) {
|
|
411
|
-
continue;
|
|
412
|
-
}
|
|
413
|
-
currentHostnames.add(domain);
|
|
414
|
-
// Check if we have a static certificate for this domain
|
|
415
|
-
if (route.action.tls?.certificate && route.action.tls.certificate !== 'auto') {
|
|
416
|
-
certificateUpdates.set(domain, {
|
|
417
|
-
cert: route.action.tls.certificate.cert,
|
|
418
|
-
key: route.action.tls.certificate.key
|
|
419
|
-
});
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
// Update certificate cache with any static certificates
|
|
424
|
-
for (const [domain, certData] of certificateUpdates.entries()) {
|
|
425
|
-
try {
|
|
426
|
-
this.defaultCertProvider.updateCertificate(domain, certData.cert, certData.key);
|
|
427
|
-
this.activeContexts.add(domain);
|
|
428
|
-
}
|
|
429
|
-
catch (error) {
|
|
430
|
-
this.logger.error(`Failed to add SSL context for ${domain}`, error);
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
// Clean up removed contexts
|
|
434
|
-
for (const hostname of this.activeContexts) {
|
|
435
|
-
if (!currentHostnames.has(hostname)) {
|
|
436
|
-
this.logger.info(`Hostname ${hostname} removed from configuration`);
|
|
437
|
-
this.activeContexts.delete(hostname);
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
// Update the router with new routes
|
|
441
|
-
this.router.setRoutes(routes);
|
|
442
|
-
// Update WebSocket handler with new routes
|
|
443
|
-
this.webSocketHandler.setRoutes(routes);
|
|
444
|
-
this.logger.info(`Route configuration updated with ${routes.length} routes`);
|
|
445
|
-
}
|
|
446
|
-
// Legacy methods have been removed.
|
|
447
|
-
// Please use updateRouteConfigs() directly with modern route-based configuration.
|
|
448
|
-
/**
|
|
449
|
-
* Adds default headers to be included in all responses
|
|
450
|
-
*/
|
|
451
|
-
async addDefaultHeaders(headersArg) {
|
|
452
|
-
this.logger.info('Adding default headers', headersArg);
|
|
453
|
-
this.requestHandler.setDefaultHeaders(headersArg);
|
|
454
|
-
}
|
|
455
|
-
/**
|
|
456
|
-
* Stops the proxy server
|
|
457
|
-
*/
|
|
458
|
-
async stop() {
|
|
459
|
-
this.logger.info('Stopping HttpProxy server');
|
|
460
|
-
// Clear intervals
|
|
461
|
-
if (this.metricsInterval) {
|
|
462
|
-
clearInterval(this.metricsInterval);
|
|
463
|
-
}
|
|
464
|
-
if (this.connectionPoolCleanupInterval) {
|
|
465
|
-
clearInterval(this.connectionPoolCleanupInterval);
|
|
466
|
-
}
|
|
467
|
-
// Stop WebSocket handler
|
|
468
|
-
this.webSocketHandler.shutdown();
|
|
469
|
-
// Destroy request handler (cleans up intervals and caches)
|
|
470
|
-
if (this.requestHandler && typeof this.requestHandler.destroy === 'function') {
|
|
471
|
-
this.requestHandler.destroy();
|
|
472
|
-
}
|
|
473
|
-
// Close all tracked sockets
|
|
474
|
-
const socketCleanupPromises = this.socketMap.getArray().map(socket => cleanupSocket(socket, 'http-proxy-stop', { immediate: true }));
|
|
475
|
-
await Promise.all(socketCleanupPromises);
|
|
476
|
-
// Close all connection pool connections
|
|
477
|
-
this.connectionPool.closeAllConnections();
|
|
478
|
-
// Certificate management cleanup is handled by SmartCertManager
|
|
479
|
-
// Flush any pending deduplicated logs
|
|
480
|
-
connectionLogDeduplicator.flushAll();
|
|
481
|
-
// Close the HTTPS server
|
|
482
|
-
return new Promise((resolve) => {
|
|
483
|
-
this.httpsServer.close(() => {
|
|
484
|
-
this.logger.info('HttpProxy server stopped successfully');
|
|
485
|
-
resolve();
|
|
486
|
-
});
|
|
487
|
-
});
|
|
488
|
-
}
|
|
489
|
-
/**
|
|
490
|
-
* Requests a new certificate for a domain
|
|
491
|
-
* This can be used to manually trigger certificate issuance
|
|
492
|
-
* @param domain The domain to request a certificate for
|
|
493
|
-
* @returns A promise that resolves when the request is submitted (not when the certificate is issued)
|
|
494
|
-
*/
|
|
495
|
-
async requestCertificate(domain) {
|
|
496
|
-
this.logger.warn('requestCertificate is deprecated - use SmartCertManager instead');
|
|
497
|
-
return false;
|
|
498
|
-
}
|
|
499
|
-
/**
|
|
500
|
-
* Update certificate for a domain
|
|
501
|
-
*
|
|
502
|
-
* This method allows direct updates of certificates from external sources
|
|
503
|
-
* like Port80Handler or custom certificate providers.
|
|
504
|
-
*
|
|
505
|
-
* @param domain The domain to update certificate for
|
|
506
|
-
* @param certificate The new certificate (public key)
|
|
507
|
-
* @param privateKey The new private key
|
|
508
|
-
* @param expiryDate Optional expiry date
|
|
509
|
-
*/
|
|
510
|
-
updateCertificate(domain, certificate, privateKey, expiryDate) {
|
|
511
|
-
this.logger.info(`Updating certificate for ${domain}`);
|
|
512
|
-
this.defaultCertProvider.updateCertificate(domain, certificate, privateKey);
|
|
513
|
-
}
|
|
514
|
-
/**
|
|
515
|
-
* Gets all route configurations currently in use
|
|
516
|
-
*/
|
|
517
|
-
getRouteConfigs() {
|
|
518
|
-
return this.routeManager.getRoutes();
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cC1wcm94eS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL3Byb3hpZXMvaHR0cC1wcm94eS9odHRwLXByb3h5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFDNUMsT0FBTyxFQUNMLFlBQVksR0FDYixNQUFNLG1CQUFtQixDQUFDO0FBQzNCLE9BQU8sRUFBRSxrQkFBa0IsSUFBSSxZQUFZLEVBQUUsTUFBTSxxQ0FBcUMsQ0FBQztBQU96RixPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUM1RSxPQUFPLEVBQUUsMEJBQTBCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUN2RSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDdEQsT0FBTyxFQUFFLGNBQWMsRUFBd0IsTUFBTSxzQkFBc0IsQ0FBQztBQUM1RSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUMxRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDM0QsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBQ2pFLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDeEQsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sc0NBQXNDLENBQUM7QUFFakY7Ozs7R0FJRztBQUNILE1BQU0sT0FBTyxTQUFTO0lBQ3BCLGlHQUFpRztJQUMxRixNQUFNO1FBQ1gsT0FBTyxFQUFFLENBQUM7SUFDWixDQUFDO0lBcUNEOztPQUVHO0lBQ0gsWUFBWSxVQUE2QjtRQXJDbEMsV0FBTSxHQUFtQixFQUFFLENBQUM7UUFVM0IsV0FBTSxHQUFHLElBQUksVUFBVSxFQUFFLENBQUMsQ0FBQyxzQkFBc0I7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
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import * as plugins from '../../plugins.js';
|
|
2
|
-
import '../../core/models/socket-augmentation.js';
|
|
3
|
-
import type { IHttpRouteContext } from '../../core/models/route-context.js';
|
|
4
|
-
import type { ILogger } from './models/types.js';
|
|
5
|
-
import type { IMetricsTracker } from './request-handler.js';
|
|
6
|
-
import type { IRouteConfig } from '../smart-proxy/models/route-types.js';
|
|
7
|
-
/**
|
|
8
|
-
* HTTP Request Handler Helper - handles requests with specific destinations
|
|
9
|
-
* This is a helper class for the main RequestHandler
|
|
10
|
-
*/
|
|
11
|
-
export declare class HttpRequestHandler {
|
|
12
|
-
/**
|
|
13
|
-
* Handle HTTP request with a specific destination
|
|
14
|
-
*/
|
|
15
|
-
static handleHttpRequestWithDestination(req: plugins.http.IncomingMessage, res: plugins.http.ServerResponse, destination: {
|
|
16
|
-
host: string;
|
|
17
|
-
port: number;
|
|
18
|
-
}, routeContext: IHttpRouteContext, startTime: number, logger: ILogger, metricsTracker?: IMetricsTracker | null, route?: IRouteConfig): Promise<void>;
|
|
19
|
-
/**
|
|
20
|
-
* Apply URL rewriting based on route configuration
|
|
21
|
-
* Implements Phase 5.2: URL rewriting using route context
|
|
22
|
-
*
|
|
23
|
-
* @param req The request with the URL to rewrite
|
|
24
|
-
* @param route The route configuration containing rewrite rules
|
|
25
|
-
* @param routeContext Context for template variable resolution
|
|
26
|
-
* @param logger Logger for debugging information
|
|
27
|
-
* @returns True if URL was rewritten, false otherwise
|
|
28
|
-
*/
|
|
29
|
-
private static applyUrlRewriting;
|
|
30
|
-
/**
|
|
31
|
-
* Apply header modifications from route configuration to request headers
|
|
32
|
-
* Implements Phase 5.1: Route-based header manipulation for requests
|
|
33
|
-
*/
|
|
34
|
-
private static applyRouteHeaderModifications;
|
|
35
|
-
/**
|
|
36
|
-
* Apply header modifications from route configuration to response headers
|
|
37
|
-
* Implements Phase 5.1: Route-based header manipulation for responses
|
|
38
|
-
*/
|
|
39
|
-
private static applyResponseHeaderModifications;
|
|
40
|
-
}
|