@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,185 +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 { createIndependentSocketHandlers, setupSocketHandlers, createSocketWithErrorHandler } from '../../core/utils/socket-utils.js';
6
-
7
- /**
8
- * Handler for HTTPS passthrough (SNI forwarding without termination)
9
- */
10
- export class HttpsPassthroughHandler extends ForwardingHandler {
11
- /**
12
- * Create a new HTTPS passthrough handler
13
- * @param config The forwarding configuration
14
- */
15
- constructor(config: IForwardConfig) {
16
- super(config);
17
-
18
- // Validate that this is an HTTPS passthrough configuration
19
- if (config.type !== 'https-passthrough') {
20
- throw new Error(`Invalid configuration type for HttpsPassthroughHandler: ${config.type}`);
21
- }
22
- }
23
-
24
- /**
25
- * Initialize the handler
26
- * HTTPS passthrough 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 TLS/SSL socket connection by forwarding it without termination
35
- * @param clientSocket The incoming socket from the client
36
- */
37
- public handleConnection(clientSocket: plugins.net.Socket): void {
38
- // Get the target from configuration
39
- const target = this.getTargetFromConfig();
40
-
41
- // Log the connection
42
- const remoteAddress = clientSocket.remoteAddress || 'unknown';
43
- const remotePort = clientSocket.remotePort || 0;
44
-
45
- this.emit(ForwardingHandlerEvents.CONNECTED, {
46
- remoteAddress,
47
- remotePort,
48
- target: `${target.host}:${target.port}`
49
- });
50
-
51
- // Track data transfer for logging
52
- let bytesSent = 0;
53
- let bytesReceived = 0;
54
- let serverSocket: plugins.net.Socket | null = null;
55
- let cleanupClient: ((reason: string) => Promise<void>) | null = null;
56
- let cleanupServer: ((reason: string) => Promise<void>) | null = null;
57
-
58
- // Create a connection to the target server with immediate error handling
59
- serverSocket = createSocketWithErrorHandler({
60
- port: target.port,
61
- host: target.host,
62
- onError: async (error) => {
63
- // Server connection failed - clean up client socket immediately
64
- this.emit(ForwardingHandlerEvents.ERROR, {
65
- error: error.message,
66
- code: (error as any).code || 'UNKNOWN',
67
- remoteAddress,
68
- target: `${target.host}:${target.port}`
69
- });
70
-
71
- // Clean up the client socket since we can't forward
72
- if (!clientSocket.destroyed) {
73
- clientSocket.destroy();
74
- }
75
-
76
- this.emit(ForwardingHandlerEvents.DISCONNECTED, {
77
- remoteAddress,
78
- bytesSent: 0,
79
- bytesReceived: 0,
80
- reason: `server_connection_failed: ${error.message}`
81
- });
82
- },
83
- onConnect: () => {
84
- // Connection successful - set up forwarding handlers
85
- const handlers = createIndependentSocketHandlers(
86
- clientSocket,
87
- serverSocket!,
88
- (reason) => {
89
- this.emit(ForwardingHandlerEvents.DISCONNECTED, {
90
- remoteAddress,
91
- bytesSent,
92
- bytesReceived,
93
- reason
94
- });
95
- }
96
- );
97
-
98
- cleanupClient = handlers.cleanupClient;
99
- cleanupServer = handlers.cleanupServer;
100
-
101
- // Setup handlers with custom timeout handling that doesn't close connections
102
- const timeout = this.getTimeout();
103
-
104
- setupSocketHandlers(clientSocket, cleanupClient, (socket) => {
105
- // Just reset timeout, don't close
106
- socket.setTimeout(timeout);
107
- }, 'client');
108
-
109
- setupSocketHandlers(serverSocket!, cleanupServer, (socket) => {
110
- // Just reset timeout, don't close
111
- socket.setTimeout(timeout);
112
- }, 'server');
113
-
114
- // Forward data from client to server
115
- clientSocket.on('data', (data) => {
116
- bytesSent += data.length;
117
-
118
- // Check if server socket is writable
119
- if (serverSocket && serverSocket.writable) {
120
- const flushed = serverSocket.write(data);
121
-
122
- // Handle backpressure
123
- if (!flushed) {
124
- clientSocket.pause();
125
- serverSocket.once('drain', () => {
126
- clientSocket.resume();
127
- });
128
- }
129
- }
130
-
131
- this.emit(ForwardingHandlerEvents.DATA_FORWARDED, {
132
- direction: 'outbound',
133
- bytes: data.length,
134
- total: bytesSent
135
- });
136
- });
137
-
138
- // Forward data from server to client
139
- serverSocket!.on('data', (data) => {
140
- bytesReceived += data.length;
141
-
142
- // Check if client socket is writable
143
- if (clientSocket.writable) {
144
- const flushed = clientSocket.write(data);
145
-
146
- // Handle backpressure
147
- if (!flushed) {
148
- serverSocket!.pause();
149
- clientSocket.once('drain', () => {
150
- serverSocket!.resume();
151
- });
152
- }
153
- }
154
-
155
- this.emit(ForwardingHandlerEvents.DATA_FORWARDED, {
156
- direction: 'inbound',
157
- bytes: data.length,
158
- total: bytesReceived
159
- });
160
- });
161
-
162
- // Set initial timeouts - they will be reset on each timeout event
163
- clientSocket.setTimeout(timeout);
164
- serverSocket!.setTimeout(timeout);
165
- }
166
- });
167
- }
168
-
169
- /**
170
- * Handle an HTTP request - HTTPS passthrough doesn't support HTTP
171
- * @param req The HTTP request
172
- * @param res The HTTP response
173
- */
174
- public handleHttpRequest(_req: plugins.http.IncomingMessage, res: plugins.http.ServerResponse): void {
175
- // HTTPS passthrough doesn't support HTTP requests
176
- res.writeHead(404, { 'Content-Type': 'text/plain' });
177
- res.end('HTTP not supported for this domain');
178
-
179
- this.emit(ForwardingHandlerEvents.HTTP_RESPONSE, {
180
- statusCode: 404,
181
- headers: { 'Content-Type': 'text/plain' },
182
- size: 'HTTP not supported for this domain'.length
183
- });
184
- }
185
- }
@@ -1,312 +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, createSocketWithErrorHandler, setupBidirectionalForwarding } from '../../core/utils/socket-utils.js';
6
-
7
- /**
8
- * Handler for HTTPS termination with HTTP backend
9
- */
10
- export class HttpsTerminateToHttpHandler extends ForwardingHandler {
11
- private tlsServer: plugins.tls.Server | null = null;
12
- private secureContext: plugins.tls.SecureContext | null = null;
13
-
14
- /**
15
- * Create a new HTTPS termination with HTTP backend handler
16
- * @param config The forwarding configuration
17
- */
18
- constructor(config: IForwardConfig) {
19
- super(config);
20
-
21
- // Validate that this is an HTTPS terminate to HTTP configuration
22
- if (config.type !== 'https-terminate-to-http') {
23
- throw new Error(`Invalid configuration type for HttpsTerminateToHttpHandler: ${config.type}`);
24
- }
25
- }
26
-
27
- /**
28
- * Initialize the handler, setting up TLS context
29
- */
30
- public async initialize(): Promise<void> {
31
- // We need to load or create TLS certificates
32
- if (this.config.https?.customCert) {
33
- // Use custom certificate from configuration
34
- this.secureContext = plugins.tls.createSecureContext({
35
- key: this.config.https.customCert.key,
36
- cert: this.config.https.customCert.cert
37
- });
38
-
39
- this.emit(ForwardingHandlerEvents.CERTIFICATE_LOADED, {
40
- source: 'config',
41
- domain: this.config.target.host
42
- });
43
- } else if (this.config.acme?.enabled) {
44
- // Request certificate through ACME if needed
45
- this.emit(ForwardingHandlerEvents.CERTIFICATE_NEEDED, {
46
- domain: Array.isArray(this.config.target.host)
47
- ? this.config.target.host[0]
48
- : this.config.target.host,
49
- useProduction: this.config.acme.production || false
50
- });
51
-
52
- // In a real implementation, we would wait for the certificate to be issued
53
- // For now, we'll use a dummy context
54
- this.secureContext = plugins.tls.createSecureContext({
55
- key: '-----BEGIN PRIVATE KEY-----\nDummy key\n-----END PRIVATE KEY-----',
56
- cert: '-----BEGIN CERTIFICATE-----\nDummy cert\n-----END CERTIFICATE-----'
57
- });
58
- } else {
59
- throw new Error('HTTPS termination requires either a custom certificate or ACME enabled');
60
- }
61
- }
62
-
63
- /**
64
- * Set the secure context for TLS termination
65
- * Called when a certificate is available
66
- * @param context The secure context
67
- */
68
- public setSecureContext(context: plugins.tls.SecureContext): void {
69
- this.secureContext = context;
70
- }
71
-
72
- /**
73
- * Handle a TLS/SSL socket connection by terminating TLS and forwarding to HTTP backend
74
- * @param clientSocket The incoming socket from the client
75
- */
76
- public handleConnection(clientSocket: plugins.net.Socket): void {
77
- // Make sure we have a secure context
78
- if (!this.secureContext) {
79
- clientSocket.destroy(new Error('TLS secure context not initialized'));
80
- return;
81
- }
82
-
83
- const remoteAddress = clientSocket.remoteAddress || 'unknown';
84
- const remotePort = clientSocket.remotePort || 0;
85
-
86
- // Create a TLS socket using our secure context
87
- const tlsSocket = new plugins.tls.TLSSocket(clientSocket, {
88
- secureContext: this.secureContext,
89
- isServer: true,
90
- server: this.tlsServer || undefined
91
- });
92
-
93
- this.emit(ForwardingHandlerEvents.CONNECTED, {
94
- remoteAddress,
95
- remotePort,
96
- tls: true
97
- });
98
-
99
- // Variables to track connections
100
- let backendSocket: plugins.net.Socket | null = null;
101
- let dataBuffer = Buffer.alloc(0);
102
- let connectionEstablished = false;
103
- let forwardingSetup = false;
104
-
105
- // Set up initial error handling for TLS socket
106
- const tlsCleanupHandler = (reason: string) => {
107
- if (!forwardingSetup) {
108
- // If forwarding not set up yet, emit disconnected and cleanup
109
- this.emit(ForwardingHandlerEvents.DISCONNECTED, {
110
- remoteAddress,
111
- reason
112
- });
113
- dataBuffer = Buffer.alloc(0);
114
- connectionEstablished = false;
115
-
116
- if (!tlsSocket.destroyed) {
117
- tlsSocket.destroy();
118
- }
119
- if (backendSocket && !backendSocket.destroyed) {
120
- backendSocket.destroy();
121
- }
122
- }
123
- // If forwarding is setup, setupBidirectionalForwarding will handle cleanup
124
- };
125
-
126
- setupSocketHandlers(tlsSocket, tlsCleanupHandler, undefined, 'tls');
127
-
128
- // Set timeout
129
- const timeout = this.getTimeout();
130
- tlsSocket.setTimeout(timeout);
131
-
132
- tlsSocket.on('timeout', () => {
133
- this.emit(ForwardingHandlerEvents.ERROR, {
134
- remoteAddress,
135
- error: 'TLS connection timeout'
136
- });
137
- tlsCleanupHandler('timeout');
138
- });
139
-
140
- // Handle TLS data
141
- tlsSocket.on('data', (data) => {
142
- // If backend connection already established, just forward the data
143
- if (connectionEstablished && backendSocket && !backendSocket.destroyed) {
144
- backendSocket.write(data);
145
- return;
146
- }
147
-
148
- // Append to buffer
149
- dataBuffer = Buffer.concat([dataBuffer, data]);
150
-
151
- // Very basic HTTP parsing - in a real implementation, use http-parser
152
- if (dataBuffer.includes(Buffer.from('\r\n\r\n')) && !connectionEstablished) {
153
- const target = this.getTargetFromConfig();
154
-
155
- // Create backend connection with immediate error handling
156
- backendSocket = createSocketWithErrorHandler({
157
- port: target.port,
158
- host: target.host,
159
- onError: (error) => {
160
- this.emit(ForwardingHandlerEvents.ERROR, {
161
- error: error.message,
162
- code: (error as any).code || 'UNKNOWN',
163
- remoteAddress,
164
- target: `${target.host}:${target.port}`
165
- });
166
-
167
- // Clean up the TLS socket since we can't forward
168
- if (!tlsSocket.destroyed) {
169
- tlsSocket.destroy();
170
- }
171
-
172
- this.emit(ForwardingHandlerEvents.DISCONNECTED, {
173
- remoteAddress,
174
- reason: `backend_connection_failed: ${error.message}`
175
- });
176
- },
177
- onConnect: () => {
178
- connectionEstablished = true;
179
-
180
- // Send buffered data
181
- if (dataBuffer.length > 0) {
182
- backendSocket!.write(dataBuffer);
183
- dataBuffer = Buffer.alloc(0);
184
- }
185
-
186
- // Now set up bidirectional forwarding with proper cleanup
187
- forwardingSetup = true;
188
- setupBidirectionalForwarding(tlsSocket, backendSocket!, {
189
- onCleanup: (reason) => {
190
- this.emit(ForwardingHandlerEvents.DISCONNECTED, {
191
- remoteAddress,
192
- reason
193
- });
194
- dataBuffer = Buffer.alloc(0);
195
- connectionEstablished = false;
196
- forwardingSetup = false;
197
- },
198
- enableHalfOpen: false // Close both when one closes
199
- });
200
- }
201
- });
202
-
203
- // Additional error logging for backend socket
204
- backendSocket.on('error', (error) => {
205
- if (!connectionEstablished) {
206
- // Connection failed during setup
207
- this.emit(ForwardingHandlerEvents.ERROR, {
208
- remoteAddress,
209
- error: `Target connection error: ${error.message}`
210
- });
211
- }
212
- // If connected, setupBidirectionalForwarding handles cleanup
213
- });
214
- }
215
- });
216
- }
217
-
218
- /**
219
- * Handle an HTTP request by forwarding to the HTTP backend
220
- * @param req The HTTP request
221
- * @param res The HTTP response
222
- */
223
- public handleHttpRequest(req: plugins.http.IncomingMessage, res: plugins.http.ServerResponse): void {
224
- // Check if we should redirect to HTTPS
225
- if (this.config.http?.redirectToHttps) {
226
- this.redirectToHttps(req, res);
227
- return;
228
- }
229
-
230
- // Get the target from configuration
231
- const target = this.getTargetFromConfig();
232
-
233
- // Create custom headers with variable substitution
234
- const variables = {
235
- clientIp: req.socket.remoteAddress || 'unknown'
236
- };
237
-
238
- // Prepare headers, merging with any custom headers from config
239
- const headers = this.applyCustomHeaders(req.headers, variables);
240
-
241
- // Create the proxy request options
242
- const options = {
243
- hostname: target.host,
244
- port: target.port,
245
- path: req.url,
246
- method: req.method,
247
- headers
248
- };
249
-
250
- // Create the proxy request
251
- const proxyReq = plugins.http.request(options, (proxyRes) => {
252
- // Copy status code and headers from the proxied response
253
- res.writeHead(proxyRes.statusCode || 500, proxyRes.headers);
254
-
255
- // Pipe the proxy response to the client response
256
- proxyRes.pipe(res);
257
-
258
- // Track response size for logging
259
- let responseSize = 0;
260
- proxyRes.on('data', (chunk) => {
261
- responseSize += chunk.length;
262
- });
263
-
264
- proxyRes.on('end', () => {
265
- this.emit(ForwardingHandlerEvents.HTTP_RESPONSE, {
266
- statusCode: proxyRes.statusCode,
267
- headers: proxyRes.headers,
268
- size: responseSize
269
- });
270
- });
271
- });
272
-
273
- // Handle errors in the proxy request
274
- proxyReq.on('error', (error) => {
275
- this.emit(ForwardingHandlerEvents.ERROR, {
276
- remoteAddress: req.socket.remoteAddress,
277
- error: `Proxy request error: ${error.message}`
278
- });
279
-
280
- // Send an error response if headers haven't been sent yet
281
- if (!res.headersSent) {
282
- res.writeHead(502, { 'Content-Type': 'text/plain' });
283
- res.end(`Error forwarding request: ${error.message}`);
284
- } else {
285
- // Just end the response if headers have already been sent
286
- res.end();
287
- }
288
- });
289
-
290
- // Track request details for logging
291
- let requestSize = 0;
292
- req.on('data', (chunk) => {
293
- requestSize += chunk.length;
294
- });
295
-
296
- // Log the request
297
- this.emit(ForwardingHandlerEvents.HTTP_REQUEST, {
298
- method: req.method,
299
- url: req.url,
300
- headers: req.headers,
301
- remoteAddress: req.socket.remoteAddress,
302
- target: `${target.host}:${target.port}`
303
- });
304
-
305
- // Pipe the client request to the proxy request
306
- if (req.readable) {
307
- req.pipe(proxyReq);
308
- } else {
309
- proxyReq.end();
310
- }
311
- }
312
- }