@push.rocks/smartproxy 20.0.1 → 21.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.
Files changed (164) hide show
  1. package/changelog.md +26 -0
  2. package/dist_ts/core/utils/proxy-protocol.d.ts +5 -17
  3. package/dist_ts/core/utils/proxy-protocol.js +13 -97
  4. package/dist_ts/core/utils/websocket-utils.d.ts +6 -7
  5. package/dist_ts/core/utils/websocket-utils.js +10 -66
  6. package/dist_ts/detection/detectors/http-detector-v2.d.ts +33 -0
  7. package/dist_ts/detection/detectors/http-detector-v2.js +87 -0
  8. package/dist_ts/detection/detectors/http-detector.d.ts +33 -0
  9. package/dist_ts/detection/detectors/http-detector.js +89 -0
  10. package/dist_ts/detection/detectors/quick-detector.d.ts +28 -0
  11. package/dist_ts/detection/detectors/quick-detector.js +131 -0
  12. package/dist_ts/detection/detectors/routing-extractor.d.ts +28 -0
  13. package/dist_ts/detection/detectors/routing-extractor.js +122 -0
  14. package/dist_ts/detection/detectors/tls-detector-v2.d.ts +33 -0
  15. package/dist_ts/detection/detectors/tls-detector-v2.js +80 -0
  16. package/dist_ts/detection/detectors/tls-detector.d.ts +33 -0
  17. package/dist_ts/detection/detectors/tls-detector.js +106 -0
  18. package/dist_ts/detection/index.d.ts +17 -0
  19. package/dist_ts/detection/index.js +22 -0
  20. package/dist_ts/detection/models/detection-types.d.ts +87 -0
  21. package/dist_ts/detection/models/detection-types.js +5 -0
  22. package/dist_ts/detection/models/interfaces.d.ts +97 -0
  23. package/dist_ts/detection/models/interfaces.js +5 -0
  24. package/dist_ts/detection/protocol-detector-v2.d.ts +46 -0
  25. package/dist_ts/detection/protocol-detector-v2.js +116 -0
  26. package/dist_ts/detection/protocol-detector.d.ts +74 -0
  27. package/dist_ts/detection/protocol-detector.js +173 -0
  28. package/dist_ts/detection/utils/buffer-utils.d.ts +61 -0
  29. package/dist_ts/detection/utils/buffer-utils.js +127 -0
  30. package/dist_ts/detection/utils/fragment-manager.d.ts +31 -0
  31. package/dist_ts/detection/utils/fragment-manager.js +53 -0
  32. package/dist_ts/detection/utils/parser-utils.d.ts +42 -0
  33. package/dist_ts/detection/utils/parser-utils.js +63 -0
  34. package/dist_ts/index.d.ts +2 -1
  35. package/dist_ts/index.js +3 -2
  36. package/dist_ts/protocols/common/fragment-handler.d.ts +73 -0
  37. package/dist_ts/protocols/common/fragment-handler.js +117 -0
  38. package/dist_ts/protocols/common/index.d.ts +7 -0
  39. package/dist_ts/protocols/common/index.js +8 -0
  40. package/dist_ts/protocols/common/types.d.ts +68 -0
  41. package/dist_ts/protocols/common/types.js +7 -0
  42. package/dist_ts/protocols/http/constants.d.ts +119 -0
  43. package/dist_ts/protocols/http/constants.js +200 -0
  44. package/dist_ts/protocols/http/index.d.ts +7 -0
  45. package/dist_ts/protocols/http/index.js +8 -0
  46. package/dist_ts/protocols/http/parser.d.ts +58 -0
  47. package/dist_ts/protocols/http/parser.js +184 -0
  48. package/dist_ts/protocols/http/types.d.ts +62 -0
  49. package/dist_ts/protocols/http/types.js +5 -0
  50. package/dist_ts/protocols/index.d.ts +11 -0
  51. package/dist_ts/protocols/index.js +12 -0
  52. package/dist_ts/protocols/proxy/index.d.ts +6 -0
  53. package/dist_ts/protocols/proxy/index.js +7 -0
  54. package/dist_ts/protocols/proxy/parser.d.ts +44 -0
  55. package/dist_ts/protocols/proxy/parser.js +153 -0
  56. package/dist_ts/protocols/proxy/types.d.ts +47 -0
  57. package/dist_ts/protocols/proxy/types.js +6 -0
  58. package/dist_ts/protocols/tls/alerts/index.d.ts +4 -0
  59. package/dist_ts/protocols/tls/alerts/index.js +5 -0
  60. package/dist_ts/protocols/tls/alerts/tls-alert.d.ts +150 -0
  61. package/dist_ts/protocols/tls/alerts/tls-alert.js +226 -0
  62. package/dist_ts/protocols/tls/constants.d.ts +122 -0
  63. package/dist_ts/protocols/tls/constants.js +135 -0
  64. package/dist_ts/protocols/tls/index.d.ts +12 -0
  65. package/dist_ts/protocols/tls/index.js +27 -0
  66. package/dist_ts/protocols/tls/parser.d.ts +53 -0
  67. package/dist_ts/protocols/tls/parser.js +294 -0
  68. package/dist_ts/protocols/tls/sni/client-hello-parser.d.ts +100 -0
  69. package/dist_ts/protocols/tls/sni/client-hello-parser.js +463 -0
  70. package/dist_ts/protocols/tls/sni/index.d.ts +5 -0
  71. package/dist_ts/protocols/tls/sni/index.js +6 -0
  72. package/dist_ts/protocols/tls/sni/sni-extraction.d.ts +58 -0
  73. package/dist_ts/protocols/tls/sni/sni-extraction.js +275 -0
  74. package/dist_ts/protocols/tls/types.d.ts +65 -0
  75. package/dist_ts/protocols/tls/types.js +5 -0
  76. package/dist_ts/protocols/tls/utils/index.d.ts +4 -0
  77. package/dist_ts/protocols/tls/utils/index.js +5 -0
  78. package/dist_ts/protocols/tls/utils/tls-utils.d.ts +158 -0
  79. package/dist_ts/protocols/tls/utils/tls-utils.js +187 -0
  80. package/dist_ts/protocols/websocket/constants.d.ts +55 -0
  81. package/dist_ts/protocols/websocket/constants.js +58 -0
  82. package/dist_ts/protocols/websocket/index.d.ts +7 -0
  83. package/dist_ts/protocols/websocket/index.js +8 -0
  84. package/dist_ts/protocols/websocket/types.d.ts +47 -0
  85. package/dist_ts/protocols/websocket/types.js +5 -0
  86. package/dist_ts/protocols/websocket/utils.d.ts +25 -0
  87. package/dist_ts/protocols/websocket/utils.js +103 -0
  88. package/dist_ts/proxies/http-proxy/models/http-types.d.ts +25 -27
  89. package/dist_ts/proxies/http-proxy/models/http-types.js +24 -44
  90. package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +5 -0
  91. package/dist_ts/proxies/smart-proxy/models/route-types.js +1 -1
  92. package/dist_ts/proxies/smart-proxy/route-connection-handler.js +81 -61
  93. package/dist_ts/proxies/smart-proxy/tls-manager.js +2 -1
  94. package/dist_ts/proxies/smart-proxy/utils/index.d.ts +1 -2
  95. package/dist_ts/proxies/smart-proxy/utils/index.js +3 -4
  96. package/dist_ts/proxies/smart-proxy/utils/route-helpers.d.ts +112 -8
  97. package/dist_ts/proxies/smart-proxy/utils/route-helpers.js +231 -76
  98. package/dist_ts/tls/index.d.ts +5 -7
  99. package/dist_ts/tls/index.js +8 -11
  100. package/dist_ts/tls/sni/client-hello-parser.js +3 -2
  101. package/dist_ts/tls/sni/sni-handler.js +4 -4
  102. package/dist_ts/tls/utils/tls-utils.d.ts +1 -110
  103. package/dist_ts/tls/utils/tls-utils.js +4 -116
  104. package/package.json +17 -8
  105. package/readme.md +471 -2345
  106. package/readme.plan.md +0 -0
  107. package/ts/core/utils/proxy-protocol.ts +14 -131
  108. package/ts/core/utils/websocket-utils.ts +12 -60
  109. package/ts/detection/detectors/http-detector.ts +114 -0
  110. package/ts/detection/detectors/quick-detector.ts +148 -0
  111. package/ts/detection/detectors/routing-extractor.ts +147 -0
  112. package/ts/detection/detectors/tls-detector.ts +120 -0
  113. package/ts/detection/index.ts +25 -0
  114. package/ts/detection/models/detection-types.ts +102 -0
  115. package/ts/detection/models/interfaces.ts +115 -0
  116. package/ts/detection/protocol-detector.ts +230 -0
  117. package/ts/detection/utils/buffer-utils.ts +141 -0
  118. package/ts/detection/utils/fragment-manager.ts +64 -0
  119. package/ts/detection/utils/parser-utils.ts +77 -0
  120. package/ts/index.ts +3 -2
  121. package/ts/protocols/common/fragment-handler.ts +163 -0
  122. package/ts/protocols/common/index.ts +8 -0
  123. package/ts/protocols/common/types.ts +76 -0
  124. package/ts/protocols/http/constants.ts +219 -0
  125. package/ts/protocols/http/index.ts +8 -0
  126. package/ts/protocols/http/parser.ts +219 -0
  127. package/ts/protocols/http/types.ts +70 -0
  128. package/ts/protocols/index.ts +12 -0
  129. package/ts/protocols/proxy/index.ts +7 -0
  130. package/ts/protocols/proxy/parser.ts +183 -0
  131. package/ts/protocols/proxy/types.ts +53 -0
  132. package/ts/{tls → protocols/tls}/alerts/tls-alert.ts +1 -1
  133. package/ts/protocols/tls/index.ts +37 -0
  134. package/ts/protocols/tls/sni/index.ts +6 -0
  135. package/ts/{tls → protocols/tls}/utils/tls-utils.ts +1 -1
  136. package/ts/protocols/websocket/constants.ts +60 -0
  137. package/ts/protocols/websocket/index.ts +8 -0
  138. package/ts/protocols/websocket/types.ts +53 -0
  139. package/ts/protocols/websocket/utils.ts +98 -0
  140. package/ts/proxies/http-proxy/models/http-types.ts +29 -46
  141. package/ts/proxies/smart-proxy/models/interfaces.ts +7 -1
  142. package/ts/proxies/smart-proxy/models/route-types.ts +0 -1
  143. package/ts/proxies/smart-proxy/route-connection-handler.ts +91 -68
  144. package/ts/proxies/smart-proxy/tls-manager.ts +1 -0
  145. package/ts/proxies/smart-proxy/utils/index.ts +2 -13
  146. package/ts/proxies/smart-proxy/utils/route-helpers.ts +323 -86
  147. package/ts/tls/index.ts +8 -12
  148. package/ts/tls/sni/sni-handler.ts +3 -3
  149. package/ts/forwarding/config/forwarding-types.ts +0 -76
  150. package/ts/forwarding/config/index.ts +0 -26
  151. package/ts/forwarding/factory/forwarding-factory.ts +0 -189
  152. package/ts/forwarding/factory/index.ts +0 -5
  153. package/ts/forwarding/handlers/base-handler.ts +0 -155
  154. package/ts/forwarding/handlers/http-handler.ts +0 -163
  155. package/ts/forwarding/handlers/https-passthrough-handler.ts +0 -185
  156. package/ts/forwarding/handlers/https-terminate-to-http-handler.ts +0 -312
  157. package/ts/forwarding/handlers/https-terminate-to-https-handler.ts +0 -297
  158. package/ts/forwarding/handlers/index.ts +0 -9
  159. package/ts/forwarding/index.ts +0 -35
  160. package/ts/proxies/smart-proxy/utils/route-patterns.ts +0 -403
  161. /package/ts/{tls → protocols/tls}/alerts/index.ts +0 -0
  162. /package/ts/{tls → protocols/tls}/sni/client-hello-parser.ts +0 -0
  163. /package/ts/{tls → protocols/tls}/sni/sni-extraction.ts +0 -0
  164. /package/ts/{tls → protocols/tls}/utils/index.ts +0 -0
@@ -1,26 +0,0 @@
1
- /**
2
- * Forwarding configuration exports
3
- *
4
- * Note: The legacy domain-based configuration has been replaced by route-based configuration.
5
- * See /ts/proxies/smart-proxy/models/route-types.ts for the new route-based configuration.
6
- */
7
-
8
- export type {
9
- TForwardingType,
10
- IForwardConfig,
11
- IForwardingHandler
12
- } from './forwarding-types.js';
13
-
14
- export {
15
- ForwardingHandlerEvents
16
- } from './forwarding-types.js';
17
-
18
- // Import route helpers from route-patterns instead of deleted route-helpers
19
- export {
20
- createHttpRoute,
21
- createHttpsTerminateRoute,
22
- createHttpsPassthroughRoute,
23
- createHttpToHttpsRedirect,
24
- createCompleteHttpsServer,
25
- createLoadBalancerRoute
26
- } from '../../proxies/smart-proxy/utils/route-patterns.js';
@@ -1,189 +0,0 @@
1
- import type { IForwardConfig } from '../config/forwarding-types.js';
2
- import { ForwardingHandler } from '../handlers/base-handler.js';
3
- import { HttpForwardingHandler } from '../handlers/http-handler.js';
4
- import { HttpsPassthroughHandler } from '../handlers/https-passthrough-handler.js';
5
- import { HttpsTerminateToHttpHandler } from '../handlers/https-terminate-to-http-handler.js';
6
- import { HttpsTerminateToHttpsHandler } from '../handlers/https-terminate-to-https-handler.js';
7
-
8
- /**
9
- * Factory for creating forwarding handlers based on the configuration type
10
- */
11
- export class ForwardingHandlerFactory {
12
- /**
13
- * Create a forwarding handler based on the configuration
14
- * @param config The forwarding configuration
15
- * @returns The appropriate forwarding handler
16
- */
17
- public static createHandler(config: IForwardConfig): ForwardingHandler {
18
- // Create the appropriate handler based on the forwarding type
19
- switch (config.type) {
20
- case 'http-only':
21
- return new HttpForwardingHandler(config);
22
-
23
- case 'https-passthrough':
24
- return new HttpsPassthroughHandler(config);
25
-
26
- case 'https-terminate-to-http':
27
- return new HttpsTerminateToHttpHandler(config);
28
-
29
- case 'https-terminate-to-https':
30
- return new HttpsTerminateToHttpsHandler(config);
31
-
32
- default:
33
- // Type system should prevent this, but just in case:
34
- throw new Error(`Unknown forwarding type: ${(config as any).type}`);
35
- }
36
- }
37
-
38
- /**
39
- * Apply default values to a forwarding configuration based on its type
40
- * @param config The original forwarding configuration
41
- * @returns A configuration with defaults applied
42
- */
43
- public static applyDefaults(config: IForwardConfig): IForwardConfig {
44
- // Create a deep copy of the configuration
45
- const result: IForwardConfig = JSON.parse(JSON.stringify(config));
46
-
47
- // Apply defaults based on forwarding type
48
- switch (config.type) {
49
- case 'http-only':
50
- // Set defaults for HTTP-only mode
51
- result.http = {
52
- enabled: true,
53
- ...config.http
54
- };
55
- // Set default port and socket if not provided
56
- if (!result.port) {
57
- result.port = 80;
58
- }
59
- if (!result.socket) {
60
- result.socket = `/tmp/forwarding-${config.type}-${result.port}.sock`;
61
- }
62
- break;
63
-
64
- case 'https-passthrough':
65
- // Set defaults for HTTPS passthrough
66
- result.https = {
67
- forwardSni: true,
68
- ...config.https
69
- };
70
- // SNI forwarding doesn't do HTTP
71
- result.http = {
72
- enabled: false,
73
- ...config.http
74
- };
75
- // Set default port and socket if not provided
76
- if (!result.port) {
77
- result.port = 443;
78
- }
79
- if (!result.socket) {
80
- result.socket = `/tmp/forwarding-${config.type}-${result.port}.sock`;
81
- }
82
- break;
83
-
84
- case 'https-terminate-to-http':
85
- // Set defaults for HTTPS termination to HTTP
86
- result.https = {
87
- ...config.https
88
- };
89
- // Support HTTP access by default in this mode
90
- result.http = {
91
- enabled: true,
92
- redirectToHttps: true,
93
- ...config.http
94
- };
95
- // Enable ACME by default
96
- result.acme = {
97
- enabled: true,
98
- maintenance: true,
99
- ...config.acme
100
- };
101
- // Set default port and socket if not provided
102
- if (!result.port) {
103
- result.port = 443;
104
- }
105
- if (!result.socket) {
106
- result.socket = `/tmp/forwarding-${config.type}-${result.port}.sock`;
107
- }
108
- break;
109
-
110
- case 'https-terminate-to-https':
111
- // Similar to terminate-to-http but with different target handling
112
- result.https = {
113
- ...config.https
114
- };
115
- result.http = {
116
- enabled: true,
117
- redirectToHttps: true,
118
- ...config.http
119
- };
120
- result.acme = {
121
- enabled: true,
122
- maintenance: true,
123
- ...config.acme
124
- };
125
- // Set default port and socket if not provided
126
- if (!result.port) {
127
- result.port = 443;
128
- }
129
- if (!result.socket) {
130
- result.socket = `/tmp/forwarding-${config.type}-${result.port}.sock`;
131
- }
132
- break;
133
- }
134
-
135
- return result;
136
- }
137
-
138
- /**
139
- * Validate a forwarding configuration
140
- * @param config The configuration to validate
141
- * @throws Error if the configuration is invalid
142
- */
143
- public static validateConfig(config: IForwardConfig): void {
144
- // Validate common properties
145
- if (!config.target) {
146
- throw new Error('Forwarding configuration must include a target');
147
- }
148
-
149
- if (!config.target.host || (Array.isArray(config.target.host) && config.target.host.length === 0)) {
150
- throw new Error('Target must include a host or array of hosts');
151
- }
152
-
153
- // Validate port if it's a number
154
- if (typeof config.target.port === 'number') {
155
- if (config.target.port <= 0 || config.target.port > 65535) {
156
- throw new Error('Target must include a valid port (1-65535)');
157
- }
158
- } else if (config.target.port !== 'preserve' && typeof config.target.port !== 'function') {
159
- throw new Error('Target port must be a number, "preserve", or a function');
160
- }
161
-
162
- // Type-specific validation
163
- switch (config.type) {
164
- case 'http-only':
165
- // HTTP-only needs http.enabled to be true
166
- if (config.http?.enabled === false) {
167
- throw new Error('HTTP-only forwarding must have HTTP enabled');
168
- }
169
- break;
170
-
171
- case 'https-passthrough':
172
- // HTTPS passthrough doesn't support HTTP
173
- if (config.http?.enabled === true) {
174
- throw new Error('HTTPS passthrough does not support HTTP');
175
- }
176
-
177
- // HTTPS passthrough doesn't work with ACME
178
- if (config.acme?.enabled === true) {
179
- throw new Error('HTTPS passthrough does not support ACME');
180
- }
181
- break;
182
-
183
- case 'https-terminate-to-http':
184
- case 'https-terminate-to-https':
185
- // These modes support all options, nothing specific to validate
186
- break;
187
- }
188
- }
189
- }
@@ -1,5 +0,0 @@
1
- /**
2
- * Forwarding factory implementations
3
- */
4
-
5
- export { ForwardingHandlerFactory } from './forwarding-factory.js';
@@ -1,155 +0,0 @@
1
- import * as plugins from '../../plugins.js';
2
- import type {
3
- IForwardConfig,
4
- IForwardingHandler
5
- } from '../config/forwarding-types.js';
6
- import { ForwardingHandlerEvents } from '../config/forwarding-types.js';
7
-
8
- /**
9
- * Base class for all forwarding handlers
10
- */
11
- export abstract class ForwardingHandler extends plugins.EventEmitter implements IForwardingHandler {
12
- /**
13
- * Create a new ForwardingHandler
14
- * @param config The forwarding configuration
15
- */
16
- constructor(protected config: IForwardConfig) {
17
- super();
18
- }
19
-
20
- /**
21
- * Initialize the handler
22
- * Base implementation does nothing, subclasses should override as needed
23
- */
24
- public async initialize(): Promise<void> {
25
- // Base implementation - no initialization needed
26
- }
27
-
28
- /**
29
- * Handle a new socket connection
30
- * @param socket The incoming socket connection
31
- */
32
- public abstract handleConnection(socket: plugins.net.Socket): void;
33
-
34
- /**
35
- * Handle an HTTP request
36
- * @param req The HTTP request
37
- * @param res The HTTP response
38
- */
39
- public abstract handleHttpRequest(req: plugins.http.IncomingMessage, res: plugins.http.ServerResponse): void;
40
-
41
- /**
42
- * Get a target from the configuration, supporting round-robin selection
43
- * @param incomingPort Optional incoming port for 'preserve' mode
44
- * @returns A resolved target object with host and port
45
- */
46
- protected getTargetFromConfig(incomingPort: number = 80): { host: string, port: number } {
47
- const { target } = this.config;
48
-
49
- // Handle round-robin host selection
50
- if (Array.isArray(target.host)) {
51
- if (target.host.length === 0) {
52
- throw new Error('No target hosts specified');
53
- }
54
-
55
- // Simple round-robin selection
56
- const randomIndex = Math.floor(Math.random() * target.host.length);
57
- return {
58
- host: target.host[randomIndex],
59
- port: this.resolvePort(target.port, incomingPort)
60
- };
61
- }
62
-
63
- // Single host
64
- return {
65
- host: target.host,
66
- port: this.resolvePort(target.port, incomingPort)
67
- };
68
- }
69
-
70
- /**
71
- * Resolves a port value, handling 'preserve' and function ports
72
- * @param port The port value to resolve
73
- * @param incomingPort Optional incoming port to use for 'preserve' mode
74
- */
75
- protected resolvePort(
76
- port: number | 'preserve' | ((ctx: any) => number),
77
- incomingPort: number = 80
78
- ): number {
79
- if (typeof port === 'function') {
80
- try {
81
- // Create a minimal context for the function that includes the incoming port
82
- const ctx = { port: incomingPort };
83
- return port(ctx);
84
- } catch (err) {
85
- console.error('Error resolving port function:', err);
86
- return incomingPort; // Fall back to incoming port
87
- }
88
- } else if (port === 'preserve') {
89
- return incomingPort; // Use the actual incoming port for 'preserve'
90
- } else {
91
- return port;
92
- }
93
- }
94
-
95
- /**
96
- * Redirect an HTTP request to HTTPS
97
- * @param req The HTTP request
98
- * @param res The HTTP response
99
- */
100
- protected redirectToHttps(req: plugins.http.IncomingMessage, res: plugins.http.ServerResponse): void {
101
- const host = req.headers.host || '';
102
- const path = req.url || '/';
103
- const redirectUrl = `https://${host}${path}`;
104
-
105
- res.writeHead(301, {
106
- 'Location': redirectUrl,
107
- 'Cache-Control': 'no-cache'
108
- });
109
- res.end(`Redirecting to ${redirectUrl}`);
110
-
111
- this.emit(ForwardingHandlerEvents.HTTP_RESPONSE, {
112
- statusCode: 301,
113
- headers: { 'Location': redirectUrl },
114
- size: 0
115
- });
116
- }
117
-
118
- /**
119
- * Apply custom headers from configuration
120
- * @param headers The original headers
121
- * @param variables Variables to replace in the headers
122
- * @returns The headers with custom values applied
123
- */
124
- protected applyCustomHeaders(
125
- headers: Record<string, string | string[] | undefined>,
126
- variables: Record<string, string>
127
- ): Record<string, string | string[] | undefined> {
128
- const customHeaders = this.config.advanced?.headers || {};
129
- const result = { ...headers };
130
-
131
- // Apply custom headers with variable substitution
132
- for (const [key, value] of Object.entries(customHeaders)) {
133
- if (typeof value !== 'string') continue;
134
-
135
- let processedValue = value;
136
-
137
- // Replace variables in the header value
138
- for (const [varName, varValue] of Object.entries(variables)) {
139
- processedValue = processedValue.replace(`{${varName}}`, varValue);
140
- }
141
-
142
- result[key] = processedValue;
143
- }
144
-
145
- return result;
146
- }
147
-
148
- /**
149
- * Get the timeout for this connection from configuration
150
- * @returns Timeout in milliseconds
151
- */
152
- protected getTimeout(): number {
153
- return this.config.advanced?.timeout || 60000; // Default: 60 seconds
154
- }
155
- }
@@ -1,163 +0,0 @@
1
- import * as plugins from '../../plugins.js';
2
- import { ForwardingHandler } from './base-handler.js';
3
- import type { IForwardConfig } from '../config/forwarding-types.js';
4
- import { ForwardingHandlerEvents } from '../config/forwarding-types.js';
5
- import { setupSocketHandlers } from '../../core/utils/socket-utils.js';
6
-
7
- /**
8
- * Handler for HTTP-only forwarding
9
- */
10
- export class HttpForwardingHandler extends ForwardingHandler {
11
- /**
12
- * Create a new HTTP forwarding handler
13
- * @param config The forwarding configuration
14
- */
15
- constructor(config: IForwardConfig) {
16
- super(config);
17
-
18
- // Validate that this is an HTTP-only configuration
19
- if (config.type !== 'http-only') {
20
- throw new Error(`Invalid configuration type for HttpForwardingHandler: ${config.type}`);
21
- }
22
- }
23
-
24
- /**
25
- * Initialize the handler
26
- * HTTP handler doesn't need special initialization
27
- */
28
- public async initialize(): Promise<void> {
29
- // Basic initialization from parent class
30
- await super.initialize();
31
- }
32
-
33
- /**
34
- * Handle a raw socket connection
35
- * HTTP handler doesn't do much with raw sockets as it mainly processes
36
- * parsed HTTP requests
37
- */
38
- public handleConnection(socket: plugins.net.Socket): void {
39
- // For HTTP, we mainly handle parsed requests, but we can still set up
40
- // some basic connection tracking
41
- const remoteAddress = socket.remoteAddress || 'unknown';
42
- const localPort = socket.localPort || 80;
43
-
44
- // Set up socket handlers with proper cleanup
45
- const handleClose = (reason: string) => {
46
- this.emit(ForwardingHandlerEvents.DISCONNECTED, {
47
- remoteAddress,
48
- reason
49
- });
50
- };
51
-
52
- // Use custom timeout handler that doesn't close the socket
53
- setupSocketHandlers(socket, handleClose, () => {
54
- // For HTTP, we can be more aggressive with timeouts since connections are shorter
55
- // But still don't close immediately - let the connection finish naturally
56
- console.warn(`HTTP socket timeout from ${remoteAddress}`);
57
- }, 'http');
58
-
59
- socket.on('error', (error) => {
60
- this.emit(ForwardingHandlerEvents.ERROR, {
61
- remoteAddress,
62
- error: error.message
63
- });
64
- });
65
-
66
- this.emit(ForwardingHandlerEvents.CONNECTED, {
67
- remoteAddress,
68
- localPort
69
- });
70
- }
71
-
72
- /**
73
- * Handle an HTTP request
74
- * @param req The HTTP request
75
- * @param res The HTTP response
76
- */
77
- public handleHttpRequest(req: plugins.http.IncomingMessage, res: plugins.http.ServerResponse): void {
78
- // Get the local port from the request (for 'preserve' port handling)
79
- const localPort = req.socket.localPort || 80;
80
-
81
- // Get the target from configuration, passing the incoming port
82
- const target = this.getTargetFromConfig(localPort);
83
-
84
- // Create a custom headers object with variables for substitution
85
- const variables = {
86
- clientIp: req.socket.remoteAddress || 'unknown'
87
- };
88
-
89
- // Prepare headers, merging with any custom headers from config
90
- const headers = this.applyCustomHeaders(req.headers, variables);
91
-
92
- // Create the proxy request options
93
- const options = {
94
- hostname: target.host,
95
- port: target.port,
96
- path: req.url,
97
- method: req.method,
98
- headers
99
- };
100
-
101
- // Create the proxy request
102
- const proxyReq = plugins.http.request(options, (proxyRes) => {
103
- // Copy status code and headers from the proxied response
104
- res.writeHead(proxyRes.statusCode || 500, proxyRes.headers);
105
-
106
- // Pipe the proxy response to the client response
107
- proxyRes.pipe(res);
108
-
109
- // Track bytes for logging
110
- let responseSize = 0;
111
- proxyRes.on('data', (chunk) => {
112
- responseSize += chunk.length;
113
- });
114
-
115
- proxyRes.on('end', () => {
116
- this.emit(ForwardingHandlerEvents.HTTP_RESPONSE, {
117
- statusCode: proxyRes.statusCode,
118
- headers: proxyRes.headers,
119
- size: responseSize
120
- });
121
- });
122
- });
123
-
124
- // Handle errors in the proxy request
125
- proxyReq.on('error', (error) => {
126
- this.emit(ForwardingHandlerEvents.ERROR, {
127
- remoteAddress: req.socket.remoteAddress,
128
- error: `Proxy request error: ${error.message}`
129
- });
130
-
131
- // Send an error response if headers haven't been sent yet
132
- if (!res.headersSent) {
133
- res.writeHead(502, { 'Content-Type': 'text/plain' });
134
- res.end(`Error forwarding request: ${error.message}`);
135
- } else {
136
- // Just end the response if headers have already been sent
137
- res.end();
138
- }
139
- });
140
-
141
- // Track request details for logging
142
- let requestSize = 0;
143
- req.on('data', (chunk) => {
144
- requestSize += chunk.length;
145
- });
146
-
147
- // Log the request
148
- this.emit(ForwardingHandlerEvents.HTTP_REQUEST, {
149
- method: req.method,
150
- url: req.url,
151
- headers: req.headers,
152
- remoteAddress: req.socket.remoteAddress,
153
- target: `${target.host}:${target.port}`
154
- });
155
-
156
- // Pipe the client request to the proxy request
157
- if (req.readable) {
158
- req.pipe(proxyReq);
159
- } else {
160
- proxyReq.end();
161
- }
162
- }
163
- }