@push.rocks/smartproxy 10.2.0 → 12.0.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 (59) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/common/port80-adapter.d.ts +11 -0
  3. package/dist_ts/common/port80-adapter.js +61 -0
  4. package/dist_ts/examples/forwarding-example.d.ts +1 -0
  5. package/dist_ts/examples/forwarding-example.js +96 -0
  6. package/dist_ts/index.d.ts +1 -0
  7. package/dist_ts/index.js +3 -1
  8. package/dist_ts/smartproxy/classes.pp.connectionhandler.js +179 -30
  9. package/dist_ts/smartproxy/classes.pp.domainconfigmanager.d.ts +39 -0
  10. package/dist_ts/smartproxy/classes.pp.domainconfigmanager.js +172 -20
  11. package/dist_ts/smartproxy/classes.pp.interfaces.d.ts +3 -11
  12. package/dist_ts/smartproxy/classes.pp.portrangemanager.js +17 -10
  13. package/dist_ts/smartproxy/classes.pp.securitymanager.d.ts +19 -2
  14. package/dist_ts/smartproxy/classes.pp.securitymanager.js +27 -4
  15. package/dist_ts/smartproxy/classes.pp.timeoutmanager.js +3 -3
  16. package/dist_ts/smartproxy/classes.smartproxy.js +45 -13
  17. package/dist_ts/smartproxy/forwarding/domain-config.d.ts +12 -0
  18. package/dist_ts/smartproxy/forwarding/domain-config.js +12 -0
  19. package/dist_ts/smartproxy/forwarding/domain-manager.d.ts +86 -0
  20. package/dist_ts/smartproxy/forwarding/domain-manager.js +241 -0
  21. package/dist_ts/smartproxy/forwarding/forwarding.factory.d.ts +24 -0
  22. package/dist_ts/smartproxy/forwarding/forwarding.factory.js +137 -0
  23. package/dist_ts/smartproxy/forwarding/forwarding.handler.d.ts +55 -0
  24. package/dist_ts/smartproxy/forwarding/forwarding.handler.js +94 -0
  25. package/dist_ts/smartproxy/forwarding/http.handler.d.ts +25 -0
  26. package/dist_ts/smartproxy/forwarding/http.handler.js +123 -0
  27. package/dist_ts/smartproxy/forwarding/https-passthrough.handler.d.ts +24 -0
  28. package/dist_ts/smartproxy/forwarding/https-passthrough.handler.js +154 -0
  29. package/dist_ts/smartproxy/forwarding/https-terminate-to-http.handler.d.ts +36 -0
  30. package/dist_ts/smartproxy/forwarding/https-terminate-to-http.handler.js +229 -0
  31. package/dist_ts/smartproxy/forwarding/https-terminate-to-https.handler.d.ts +35 -0
  32. package/dist_ts/smartproxy/forwarding/https-terminate-to-https.handler.js +254 -0
  33. package/dist_ts/smartproxy/forwarding/index.d.ts +16 -0
  34. package/dist_ts/smartproxy/forwarding/index.js +23 -0
  35. package/dist_ts/smartproxy/types/forwarding.types.d.ts +104 -0
  36. package/dist_ts/smartproxy/types/forwarding.types.js +50 -0
  37. package/package.json +2 -2
  38. package/readme.md +158 -8
  39. package/readme.plan.md +471 -42
  40. package/ts/00_commitinfo_data.ts +1 -1
  41. package/ts/common/port80-adapter.ts +87 -0
  42. package/ts/index.ts +3 -0
  43. package/ts/smartproxy/classes.pp.connectionhandler.ts +231 -44
  44. package/ts/smartproxy/classes.pp.domainconfigmanager.ts +198 -24
  45. package/ts/smartproxy/classes.pp.interfaces.ts +3 -11
  46. package/ts/smartproxy/classes.pp.portrangemanager.ts +17 -10
  47. package/ts/smartproxy/classes.pp.securitymanager.ts +29 -5
  48. package/ts/smartproxy/classes.pp.timeoutmanager.ts +3 -3
  49. package/ts/smartproxy/classes.smartproxy.ts +68 -15
  50. package/ts/smartproxy/forwarding/domain-config.ts +28 -0
  51. package/ts/smartproxy/forwarding/domain-manager.ts +283 -0
  52. package/ts/smartproxy/forwarding/forwarding.factory.ts +155 -0
  53. package/ts/smartproxy/forwarding/forwarding.handler.ts +127 -0
  54. package/ts/smartproxy/forwarding/http.handler.ts +140 -0
  55. package/ts/smartproxy/forwarding/https-passthrough.handler.ts +182 -0
  56. package/ts/smartproxy/forwarding/https-terminate-to-http.handler.ts +264 -0
  57. package/ts/smartproxy/forwarding/https-terminate-to-https.handler.ts +292 -0
  58. package/ts/smartproxy/forwarding/index.ts +52 -0
  59. package/ts/smartproxy/types/forwarding.types.ts +162 -0
@@ -0,0 +1,155 @@
1
+ import type { IForwardConfig, IForwardingHandler } from '../types/forwarding.types.js';
2
+ import { HttpForwardingHandler } from './http.handler.js';
3
+ import { HttpsPassthroughHandler } from './https-passthrough.handler.js';
4
+ import { HttpsTerminateToHttpHandler } from './https-terminate-to-http.handler.js';
5
+ import { HttpsTerminateToHttpsHandler } from './https-terminate-to-https.handler.js';
6
+
7
+ /**
8
+ * Factory for creating forwarding handlers based on the configuration type
9
+ */
10
+ export class ForwardingHandlerFactory {
11
+ /**
12
+ * Create a forwarding handler based on the configuration
13
+ * @param config The forwarding configuration
14
+ * @returns The appropriate forwarding handler
15
+ */
16
+ public static createHandler(config: IForwardConfig): IForwardingHandler {
17
+ // Create the appropriate handler based on the forwarding type
18
+ switch (config.type) {
19
+ case 'http-only':
20
+ return new HttpForwardingHandler(config);
21
+
22
+ case 'https-passthrough':
23
+ return new HttpsPassthroughHandler(config);
24
+
25
+ case 'https-terminate-to-http':
26
+ return new HttpsTerminateToHttpHandler(config);
27
+
28
+ case 'https-terminate-to-https':
29
+ return new HttpsTerminateToHttpsHandler(config);
30
+
31
+ default:
32
+ // Type system should prevent this, but just in case:
33
+ throw new Error(`Unknown forwarding type: ${(config as any).type}`);
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Apply default values to a forwarding configuration based on its type
39
+ * @param config The original forwarding configuration
40
+ * @returns A configuration with defaults applied
41
+ */
42
+ public static applyDefaults(config: IForwardConfig): IForwardConfig {
43
+ // Create a deep copy of the configuration
44
+ const result: IForwardConfig = JSON.parse(JSON.stringify(config));
45
+
46
+ // Apply defaults based on forwarding type
47
+ switch (config.type) {
48
+ case 'http-only':
49
+ // Set defaults for HTTP-only mode
50
+ result.http = {
51
+ enabled: true,
52
+ ...config.http
53
+ };
54
+ break;
55
+
56
+ case 'https-passthrough':
57
+ // Set defaults for HTTPS passthrough
58
+ result.https = {
59
+ forwardSni: true,
60
+ ...config.https
61
+ };
62
+ // SNI forwarding doesn't do HTTP
63
+ result.http = {
64
+ enabled: false,
65
+ ...config.http
66
+ };
67
+ break;
68
+
69
+ case 'https-terminate-to-http':
70
+ // Set defaults for HTTPS termination to HTTP
71
+ result.https = {
72
+ ...config.https
73
+ };
74
+ // Support HTTP access by default in this mode
75
+ result.http = {
76
+ enabled: true,
77
+ redirectToHttps: true,
78
+ ...config.http
79
+ };
80
+ // Enable ACME by default
81
+ result.acme = {
82
+ enabled: true,
83
+ maintenance: true,
84
+ ...config.acme
85
+ };
86
+ break;
87
+
88
+ case 'https-terminate-to-https':
89
+ // Similar to terminate-to-http but with different target handling
90
+ result.https = {
91
+ ...config.https
92
+ };
93
+ result.http = {
94
+ enabled: true,
95
+ redirectToHttps: true,
96
+ ...config.http
97
+ };
98
+ result.acme = {
99
+ enabled: true,
100
+ maintenance: true,
101
+ ...config.acme
102
+ };
103
+ break;
104
+ }
105
+
106
+ return result;
107
+ }
108
+
109
+ /**
110
+ * Validate a forwarding configuration
111
+ * @param config The configuration to validate
112
+ * @throws Error if the configuration is invalid
113
+ */
114
+ public static validateConfig(config: IForwardConfig): void {
115
+ // Validate common properties
116
+ if (!config.target) {
117
+ throw new Error('Forwarding configuration must include a target');
118
+ }
119
+
120
+ if (!config.target.host || (Array.isArray(config.target.host) && config.target.host.length === 0)) {
121
+ throw new Error('Target must include a host or array of hosts');
122
+ }
123
+
124
+ if (!config.target.port || config.target.port <= 0 || config.target.port > 65535) {
125
+ throw new Error('Target must include a valid port (1-65535)');
126
+ }
127
+
128
+ // Type-specific validation
129
+ switch (config.type) {
130
+ case 'http-only':
131
+ // HTTP-only needs http.enabled to be true
132
+ if (config.http?.enabled === false) {
133
+ throw new Error('HTTP-only forwarding must have HTTP enabled');
134
+ }
135
+ break;
136
+
137
+ case 'https-passthrough':
138
+ // HTTPS passthrough doesn't support HTTP
139
+ if (config.http?.enabled === true) {
140
+ throw new Error('HTTPS passthrough does not support HTTP');
141
+ }
142
+
143
+ // HTTPS passthrough doesn't work with ACME
144
+ if (config.acme?.enabled === true) {
145
+ throw new Error('HTTPS passthrough does not support ACME');
146
+ }
147
+ break;
148
+
149
+ case 'https-terminate-to-http':
150
+ case 'https-terminate-to-https':
151
+ // These modes support all options, nothing specific to validate
152
+ break;
153
+ }
154
+ }
155
+ }
@@ -0,0 +1,127 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import type {
3
+ IForwardConfig,
4
+ IForwardingHandler
5
+ } from '../types/forwarding.types.js';
6
+ import { ForwardingHandlerEvents } from '../types/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
+ * @returns A resolved target object with host and port
44
+ */
45
+ protected getTargetFromConfig(): { host: string, port: number } {
46
+ const { target } = this.config;
47
+
48
+ // Handle round-robin host selection
49
+ if (Array.isArray(target.host)) {
50
+ if (target.host.length === 0) {
51
+ throw new Error('No target hosts specified');
52
+ }
53
+
54
+ // Simple round-robin selection
55
+ const randomIndex = Math.floor(Math.random() * target.host.length);
56
+ return {
57
+ host: target.host[randomIndex],
58
+ port: target.port
59
+ };
60
+ }
61
+
62
+ // Single host
63
+ return {
64
+ host: target.host,
65
+ port: target.port
66
+ };
67
+ }
68
+
69
+ /**
70
+ * Redirect an HTTP request to HTTPS
71
+ * @param req The HTTP request
72
+ * @param res The HTTP response
73
+ */
74
+ protected redirectToHttps(req: plugins.http.IncomingMessage, res: plugins.http.ServerResponse): void {
75
+ const host = req.headers.host || '';
76
+ const path = req.url || '/';
77
+ const redirectUrl = `https://${host}${path}`;
78
+
79
+ res.writeHead(301, {
80
+ 'Location': redirectUrl,
81
+ 'Cache-Control': 'no-cache'
82
+ });
83
+ res.end(`Redirecting to ${redirectUrl}`);
84
+
85
+ this.emit(ForwardingHandlerEvents.HTTP_RESPONSE, {
86
+ statusCode: 301,
87
+ headers: { 'Location': redirectUrl },
88
+ size: 0
89
+ });
90
+ }
91
+
92
+ /**
93
+ * Apply custom headers from configuration
94
+ * @param headers The original headers
95
+ * @param variables Variables to replace in the headers
96
+ * @returns The headers with custom values applied
97
+ */
98
+ protected applyCustomHeaders(
99
+ headers: Record<string, string | string[] | undefined>,
100
+ variables: Record<string, string>
101
+ ): Record<string, string | string[] | undefined> {
102
+ const customHeaders = this.config.advanced?.headers || {};
103
+ const result = { ...headers };
104
+
105
+ // Apply custom headers with variable substitution
106
+ for (const [key, value] of Object.entries(customHeaders)) {
107
+ let processedValue = value;
108
+
109
+ // Replace variables in the header value
110
+ for (const [varName, varValue] of Object.entries(variables)) {
111
+ processedValue = processedValue.replace(`{${varName}}`, varValue);
112
+ }
113
+
114
+ result[key] = processedValue;
115
+ }
116
+
117
+ return result;
118
+ }
119
+
120
+ /**
121
+ * Get the timeout for this connection from configuration
122
+ * @returns Timeout in milliseconds
123
+ */
124
+ protected getTimeout(): number {
125
+ return this.config.advanced?.timeout || 60000; // Default: 60 seconds
126
+ }
127
+ }
@@ -0,0 +1,140 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import { ForwardingHandler } from './forwarding.handler.js';
3
+ import type { IForwardConfig } from '../types/forwarding.types.js';
4
+ import { ForwardingHandlerEvents } from '../types/forwarding.types.js';
5
+
6
+ /**
7
+ * Handler for HTTP-only forwarding
8
+ */
9
+ export class HttpForwardingHandler extends ForwardingHandler {
10
+ /**
11
+ * Create a new HTTP forwarding handler
12
+ * @param config The forwarding configuration
13
+ */
14
+ constructor(config: IForwardConfig) {
15
+ super(config);
16
+
17
+ // Validate that this is an HTTP-only configuration
18
+ if (config.type !== 'http-only') {
19
+ throw new Error(`Invalid configuration type for HttpForwardingHandler: ${config.type}`);
20
+ }
21
+ }
22
+
23
+ /**
24
+ * Handle a raw socket connection
25
+ * HTTP handler doesn't do much with raw sockets as it mainly processes
26
+ * parsed HTTP requests
27
+ */
28
+ public handleConnection(socket: plugins.net.Socket): void {
29
+ // For HTTP, we mainly handle parsed requests, but we can still set up
30
+ // some basic connection tracking
31
+ const remoteAddress = socket.remoteAddress || 'unknown';
32
+
33
+ socket.on('close', (hadError) => {
34
+ this.emit(ForwardingHandlerEvents.DISCONNECTED, {
35
+ remoteAddress,
36
+ hadError
37
+ });
38
+ });
39
+
40
+ socket.on('error', (error) => {
41
+ this.emit(ForwardingHandlerEvents.ERROR, {
42
+ remoteAddress,
43
+ error: error.message
44
+ });
45
+ });
46
+
47
+ this.emit(ForwardingHandlerEvents.CONNECTED, {
48
+ remoteAddress
49
+ });
50
+ }
51
+
52
+ /**
53
+ * Handle an HTTP request
54
+ * @param req The HTTP request
55
+ * @param res The HTTP response
56
+ */
57
+ public handleHttpRequest(req: plugins.http.IncomingMessage, res: plugins.http.ServerResponse): void {
58
+ // Get the target from configuration
59
+ const target = this.getTargetFromConfig();
60
+
61
+ // Create a custom headers object with variables for substitution
62
+ const variables = {
63
+ clientIp: req.socket.remoteAddress || 'unknown'
64
+ };
65
+
66
+ // Prepare headers, merging with any custom headers from config
67
+ const headers = this.applyCustomHeaders(req.headers, variables);
68
+
69
+ // Create the proxy request options
70
+ const options = {
71
+ hostname: target.host,
72
+ port: target.port,
73
+ path: req.url,
74
+ method: req.method,
75
+ headers
76
+ };
77
+
78
+ // Create the proxy request
79
+ const proxyReq = plugins.http.request(options, (proxyRes) => {
80
+ // Copy status code and headers from the proxied response
81
+ res.writeHead(proxyRes.statusCode || 500, proxyRes.headers);
82
+
83
+ // Pipe the proxy response to the client response
84
+ proxyRes.pipe(res);
85
+
86
+ // Track bytes for logging
87
+ let responseSize = 0;
88
+ proxyRes.on('data', (chunk) => {
89
+ responseSize += chunk.length;
90
+ });
91
+
92
+ proxyRes.on('end', () => {
93
+ this.emit(ForwardingHandlerEvents.HTTP_RESPONSE, {
94
+ statusCode: proxyRes.statusCode,
95
+ headers: proxyRes.headers,
96
+ size: responseSize
97
+ });
98
+ });
99
+ });
100
+
101
+ // Handle errors in the proxy request
102
+ proxyReq.on('error', (error) => {
103
+ this.emit(ForwardingHandlerEvents.ERROR, {
104
+ remoteAddress: req.socket.remoteAddress,
105
+ error: `Proxy request error: ${error.message}`
106
+ });
107
+
108
+ // Send an error response if headers haven't been sent yet
109
+ if (!res.headersSent) {
110
+ res.writeHead(502, { 'Content-Type': 'text/plain' });
111
+ res.end(`Error forwarding request: ${error.message}`);
112
+ } else {
113
+ // Just end the response if headers have already been sent
114
+ res.end();
115
+ }
116
+ });
117
+
118
+ // Track request details for logging
119
+ let requestSize = 0;
120
+ req.on('data', (chunk) => {
121
+ requestSize += chunk.length;
122
+ });
123
+
124
+ // Log the request
125
+ this.emit(ForwardingHandlerEvents.HTTP_REQUEST, {
126
+ method: req.method,
127
+ url: req.url,
128
+ headers: req.headers,
129
+ remoteAddress: req.socket.remoteAddress,
130
+ target: `${target.host}:${target.port}`
131
+ });
132
+
133
+ // Pipe the client request to the proxy request
134
+ if (req.readable) {
135
+ req.pipe(proxyReq);
136
+ } else {
137
+ proxyReq.end();
138
+ }
139
+ }
140
+ }
@@ -0,0 +1,182 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import { ForwardingHandler } from './forwarding.handler.js';
3
+ import type { IForwardConfig } from '../types/forwarding.types.js';
4
+ import { ForwardingHandlerEvents } from '../types/forwarding.types.js';
5
+
6
+ /**
7
+ * Handler for HTTPS passthrough (SNI forwarding without termination)
8
+ */
9
+ export class HttpsPassthroughHandler extends ForwardingHandler {
10
+ /**
11
+ * Create a new HTTPS passthrough handler
12
+ * @param config The forwarding configuration
13
+ */
14
+ constructor(config: IForwardConfig) {
15
+ super(config);
16
+
17
+ // Validate that this is an HTTPS passthrough configuration
18
+ if (config.type !== 'https-passthrough') {
19
+ throw new Error(`Invalid configuration type for HttpsPassthroughHandler: ${config.type}`);
20
+ }
21
+ }
22
+
23
+ /**
24
+ * Handle a TLS/SSL socket connection by forwarding it without termination
25
+ * @param clientSocket The incoming socket from the client
26
+ */
27
+ public handleConnection(clientSocket: plugins.net.Socket): void {
28
+ // Get the target from configuration
29
+ const target = this.getTargetFromConfig();
30
+
31
+ // Log the connection
32
+ const remoteAddress = clientSocket.remoteAddress || 'unknown';
33
+ const remotePort = clientSocket.remotePort || 0;
34
+
35
+ this.emit(ForwardingHandlerEvents.CONNECTED, {
36
+ remoteAddress,
37
+ remotePort,
38
+ target: `${target.host}:${target.port}`
39
+ });
40
+
41
+ // Create a connection to the target server
42
+ const serverSocket = plugins.net.connect(target.port, target.host);
43
+
44
+ // Handle errors on the server socket
45
+ serverSocket.on('error', (error) => {
46
+ this.emit(ForwardingHandlerEvents.ERROR, {
47
+ remoteAddress,
48
+ error: `Target connection error: ${error.message}`
49
+ });
50
+
51
+ // Close the client socket if it's still open
52
+ if (!clientSocket.destroyed) {
53
+ clientSocket.destroy();
54
+ }
55
+ });
56
+
57
+ // Handle errors on the client socket
58
+ clientSocket.on('error', (error) => {
59
+ this.emit(ForwardingHandlerEvents.ERROR, {
60
+ remoteAddress,
61
+ error: `Client connection error: ${error.message}`
62
+ });
63
+
64
+ // Close the server socket if it's still open
65
+ if (!serverSocket.destroyed) {
66
+ serverSocket.destroy();
67
+ }
68
+ });
69
+
70
+ // Track data transfer for logging
71
+ let bytesSent = 0;
72
+ let bytesReceived = 0;
73
+
74
+ // Forward data from client to server
75
+ clientSocket.on('data', (data) => {
76
+ bytesSent += data.length;
77
+
78
+ // Check if server socket is writable
79
+ if (serverSocket.writable) {
80
+ const flushed = serverSocket.write(data);
81
+
82
+ // Handle backpressure
83
+ if (!flushed) {
84
+ clientSocket.pause();
85
+ serverSocket.once('drain', () => {
86
+ clientSocket.resume();
87
+ });
88
+ }
89
+ }
90
+
91
+ this.emit(ForwardingHandlerEvents.DATA_FORWARDED, {
92
+ direction: 'outbound',
93
+ bytes: data.length,
94
+ total: bytesSent
95
+ });
96
+ });
97
+
98
+ // Forward data from server to client
99
+ serverSocket.on('data', (data) => {
100
+ bytesReceived += data.length;
101
+
102
+ // Check if client socket is writable
103
+ if (clientSocket.writable) {
104
+ const flushed = clientSocket.write(data);
105
+
106
+ // Handle backpressure
107
+ if (!flushed) {
108
+ serverSocket.pause();
109
+ clientSocket.once('drain', () => {
110
+ serverSocket.resume();
111
+ });
112
+ }
113
+ }
114
+
115
+ this.emit(ForwardingHandlerEvents.DATA_FORWARDED, {
116
+ direction: 'inbound',
117
+ bytes: data.length,
118
+ total: bytesReceived
119
+ });
120
+ });
121
+
122
+ // Handle connection close
123
+ const handleClose = () => {
124
+ if (!clientSocket.destroyed) {
125
+ clientSocket.destroy();
126
+ }
127
+
128
+ if (!serverSocket.destroyed) {
129
+ serverSocket.destroy();
130
+ }
131
+
132
+ this.emit(ForwardingHandlerEvents.DISCONNECTED, {
133
+ remoteAddress,
134
+ bytesSent,
135
+ bytesReceived
136
+ });
137
+ };
138
+
139
+ // Set up close handlers
140
+ clientSocket.on('close', handleClose);
141
+ serverSocket.on('close', handleClose);
142
+
143
+ // Set timeouts
144
+ const timeout = this.getTimeout();
145
+ clientSocket.setTimeout(timeout);
146
+ serverSocket.setTimeout(timeout);
147
+
148
+ // Handle timeouts
149
+ clientSocket.on('timeout', () => {
150
+ this.emit(ForwardingHandlerEvents.ERROR, {
151
+ remoteAddress,
152
+ error: 'Client connection timeout'
153
+ });
154
+ handleClose();
155
+ });
156
+
157
+ serverSocket.on('timeout', () => {
158
+ this.emit(ForwardingHandlerEvents.ERROR, {
159
+ remoteAddress,
160
+ error: 'Server connection timeout'
161
+ });
162
+ handleClose();
163
+ });
164
+ }
165
+
166
+ /**
167
+ * Handle an HTTP request - HTTPS passthrough doesn't support HTTP
168
+ * @param req The HTTP request
169
+ * @param res The HTTP response
170
+ */
171
+ public handleHttpRequest(req: plugins.http.IncomingMessage, res: plugins.http.ServerResponse): void {
172
+ // HTTPS passthrough doesn't support HTTP requests
173
+ res.writeHead(404, { 'Content-Type': 'text/plain' });
174
+ res.end('HTTP not supported for this domain');
175
+
176
+ this.emit(ForwardingHandlerEvents.HTTP_RESPONSE, {
177
+ statusCode: 404,
178
+ headers: { 'Content-Type': 'text/plain' },
179
+ size: 'HTTP not supported for this domain'.length
180
+ });
181
+ }
182
+ }