@push.rocks/smartproxy 19.5.4 → 19.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_ts/core/utils/async-utils.d.ts +81 -0
- package/dist_ts/core/utils/async-utils.js +216 -0
- package/dist_ts/core/utils/binary-heap.d.ts +73 -0
- package/dist_ts/core/utils/binary-heap.js +193 -0
- package/dist_ts/core/utils/enhanced-connection-pool.d.ts +110 -0
- package/dist_ts/core/utils/enhanced-connection-pool.js +320 -0
- package/dist_ts/core/utils/fs-utils.d.ts +144 -0
- package/dist_ts/core/utils/fs-utils.js +252 -0
- package/dist_ts/core/utils/index.d.ts +6 -2
- package/dist_ts/core/utils/index.js +7 -3
- package/dist_ts/core/utils/lifecycle-component.d.ts +59 -0
- package/dist_ts/core/utils/lifecycle-component.js +195 -0
- package/dist_ts/core/utils/socket-utils.d.ts +28 -0
- package/dist_ts/core/utils/socket-utils.js +77 -0
- package/dist_ts/forwarding/handlers/http-handler.js +7 -4
- package/dist_ts/forwarding/handlers/https-passthrough-handler.js +14 -55
- package/dist_ts/forwarding/handlers/https-terminate-to-http-handler.js +52 -40
- package/dist_ts/forwarding/handlers/https-terminate-to-https-handler.js +31 -43
- package/dist_ts/plugins.d.ts +2 -1
- package/dist_ts/plugins.js +3 -2
- package/dist_ts/proxies/http-proxy/certificate-manager.d.ts +15 -0
- package/dist_ts/proxies/http-proxy/certificate-manager.js +49 -2
- package/dist_ts/proxies/http-proxy/connection-pool.js +4 -19
- package/dist_ts/proxies/http-proxy/http-proxy.js +3 -7
- package/dist_ts/proxies/nftables-proxy/nftables-proxy.d.ts +10 -0
- package/dist_ts/proxies/nftables-proxy/nftables-proxy.js +53 -43
- package/dist_ts/proxies/smart-proxy/cert-store.js +22 -20
- package/dist_ts/proxies/smart-proxy/connection-manager.d.ts +35 -9
- package/dist_ts/proxies/smart-proxy/connection-manager.js +243 -189
- package/dist_ts/proxies/smart-proxy/http-proxy-bridge.js +13 -2
- package/dist_ts/proxies/smart-proxy/port-manager.js +3 -3
- package/dist_ts/proxies/smart-proxy/route-connection-handler.js +35 -4
- package/package.json +2 -2
- package/readme.hints.md +96 -1
- package/readme.plan.md +1135 -221
- package/readme.problems.md +167 -83
- package/ts/core/utils/async-utils.ts +275 -0
- package/ts/core/utils/binary-heap.ts +225 -0
- package/ts/core/utils/enhanced-connection-pool.ts +420 -0
- package/ts/core/utils/fs-utils.ts +270 -0
- package/ts/core/utils/index.ts +6 -2
- package/ts/core/utils/lifecycle-component.ts +231 -0
- package/ts/core/utils/socket-utils.ts +96 -0
- package/ts/forwarding/handlers/http-handler.ts +7 -3
- package/ts/forwarding/handlers/https-passthrough-handler.ts +13 -62
- package/ts/forwarding/handlers/https-terminate-to-http-handler.ts +58 -46
- package/ts/forwarding/handlers/https-terminate-to-https-handler.ts +38 -53
- package/ts/plugins.ts +2 -1
- package/ts/proxies/http-proxy/certificate-manager.ts +52 -1
- package/ts/proxies/http-proxy/connection-pool.ts +3 -16
- package/ts/proxies/http-proxy/http-proxy.ts +2 -5
- package/ts/proxies/nftables-proxy/nftables-proxy.ts +64 -79
- package/ts/proxies/smart-proxy/cert-store.ts +26 -20
- package/ts/proxies/smart-proxy/connection-manager.ts +277 -197
- package/ts/proxies/smart-proxy/http-proxy-bridge.ts +15 -1
- package/ts/proxies/smart-proxy/port-manager.ts +2 -2
- package/ts/proxies/smart-proxy/route-connection-handler.ts +39 -4
- package/readme.plan2.md +0 -764
- package/ts/common/eventUtils.ts +0 -34
- package/ts/common/types.ts +0 -91
- package/ts/core/utils/event-system.ts +0 -376
- package/ts/core/utils/event-utils.ts +0 -25
|
@@ -2,6 +2,7 @@ import * as plugins from '../../plugins.js';
|
|
|
2
2
|
import { ForwardingHandler } from './base-handler.js';
|
|
3
3
|
import type { IForwardConfig } from '../config/forwarding-types.js';
|
|
4
4
|
import { ForwardingHandlerEvents } from '../config/forwarding-types.js';
|
|
5
|
+
import { createSocketCleanupHandler, setupSocketHandlers, pipeSockets } from '../../core/utils/socket-utils.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Handler for HTTPS passthrough (SNI forwarding without termination)
|
|
@@ -50,35 +51,23 @@ export class HttpsPassthroughHandler extends ForwardingHandler {
|
|
|
50
51
|
// Create a connection to the target server
|
|
51
52
|
const serverSocket = plugins.net.connect(target.port, target.host);
|
|
52
53
|
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
remoteAddress,
|
|
57
|
-
error: `Target connection error: ${error.message}`
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
// Close the client socket if it's still open
|
|
61
|
-
if (!clientSocket.destroyed) {
|
|
62
|
-
clientSocket.destroy();
|
|
63
|
-
}
|
|
64
|
-
});
|
|
54
|
+
// Track data transfer for logging
|
|
55
|
+
let bytesSent = 0;
|
|
56
|
+
let bytesReceived = 0;
|
|
65
57
|
|
|
66
|
-
//
|
|
67
|
-
clientSocket
|
|
68
|
-
this.emit(ForwardingHandlerEvents.
|
|
58
|
+
// Create cleanup handler with our utility
|
|
59
|
+
const handleClose = createSocketCleanupHandler(clientSocket, serverSocket, (reason) => {
|
|
60
|
+
this.emit(ForwardingHandlerEvents.DISCONNECTED, {
|
|
69
61
|
remoteAddress,
|
|
70
|
-
|
|
62
|
+
bytesSent,
|
|
63
|
+
bytesReceived,
|
|
64
|
+
reason
|
|
71
65
|
});
|
|
72
|
-
|
|
73
|
-
// Close the server socket if it's still open
|
|
74
|
-
if (!serverSocket.destroyed) {
|
|
75
|
-
serverSocket.destroy();
|
|
76
|
-
}
|
|
77
66
|
});
|
|
78
67
|
|
|
79
|
-
//
|
|
80
|
-
|
|
81
|
-
|
|
68
|
+
// Setup error and close handlers for both sockets
|
|
69
|
+
setupSocketHandlers(serverSocket, handleClose, 'server');
|
|
70
|
+
setupSocketHandlers(clientSocket, handleClose, 'client');
|
|
82
71
|
|
|
83
72
|
// Forward data from client to server
|
|
84
73
|
clientSocket.on('data', (data) => {
|
|
@@ -128,48 +117,10 @@ export class HttpsPassthroughHandler extends ForwardingHandler {
|
|
|
128
117
|
});
|
|
129
118
|
});
|
|
130
119
|
|
|
131
|
-
// Handle connection close
|
|
132
|
-
const handleClose = () => {
|
|
133
|
-
if (!clientSocket.destroyed) {
|
|
134
|
-
clientSocket.destroy();
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
if (!serverSocket.destroyed) {
|
|
138
|
-
serverSocket.destroy();
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
this.emit(ForwardingHandlerEvents.DISCONNECTED, {
|
|
142
|
-
remoteAddress,
|
|
143
|
-
bytesSent,
|
|
144
|
-
bytesReceived
|
|
145
|
-
});
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
// Set up close handlers
|
|
149
|
-
clientSocket.on('close', handleClose);
|
|
150
|
-
serverSocket.on('close', handleClose);
|
|
151
|
-
|
|
152
120
|
// Set timeouts
|
|
153
121
|
const timeout = this.getTimeout();
|
|
154
122
|
clientSocket.setTimeout(timeout);
|
|
155
123
|
serverSocket.setTimeout(timeout);
|
|
156
|
-
|
|
157
|
-
// Handle timeouts
|
|
158
|
-
clientSocket.on('timeout', () => {
|
|
159
|
-
this.emit(ForwardingHandlerEvents.ERROR, {
|
|
160
|
-
remoteAddress,
|
|
161
|
-
error: 'Client connection timeout'
|
|
162
|
-
});
|
|
163
|
-
handleClose();
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
serverSocket.on('timeout', () => {
|
|
167
|
-
this.emit(ForwardingHandlerEvents.ERROR, {
|
|
168
|
-
remoteAddress,
|
|
169
|
-
error: 'Server connection timeout'
|
|
170
|
-
});
|
|
171
|
-
handleClose();
|
|
172
|
-
});
|
|
173
124
|
}
|
|
174
125
|
|
|
175
126
|
/**
|
|
@@ -2,6 +2,7 @@ import * as plugins from '../../plugins.js';
|
|
|
2
2
|
import { ForwardingHandler } from './base-handler.js';
|
|
3
3
|
import type { IForwardConfig } from '../config/forwarding-types.js';
|
|
4
4
|
import { ForwardingHandlerEvents } from '../config/forwarding-types.js';
|
|
5
|
+
import { createSocketCleanupHandler, setupSocketHandlers } from '../../core/utils/socket-utils.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Handler for HTTPS termination with HTTP backend
|
|
@@ -95,76 +96,87 @@ export class HttpsTerminateToHttpHandler extends ForwardingHandler {
|
|
|
95
96
|
tls: true
|
|
96
97
|
});
|
|
97
98
|
|
|
98
|
-
//
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
// Variables to track connections
|
|
100
|
+
let backendSocket: plugins.net.Socket | null = null;
|
|
101
|
+
let dataBuffer = Buffer.alloc(0);
|
|
102
|
+
let connectionEstablished = false;
|
|
103
|
+
|
|
104
|
+
// Create cleanup handler for all sockets
|
|
105
|
+
const handleClose = createSocketCleanupHandler(tlsSocket, backendSocket, (reason) => {
|
|
106
|
+
this.emit(ForwardingHandlerEvents.DISCONNECTED, {
|
|
101
107
|
remoteAddress,
|
|
102
|
-
|
|
108
|
+
reason
|
|
103
109
|
});
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
tlsSocket.destroy();
|
|
107
|
-
}
|
|
110
|
+
dataBuffer = Buffer.alloc(0);
|
|
111
|
+
connectionEstablished = false;
|
|
108
112
|
});
|
|
109
113
|
|
|
110
|
-
//
|
|
111
|
-
|
|
112
|
-
// the requests here, but for simplicity, we'll just log the data
|
|
114
|
+
// Set up error handling with our cleanup utility
|
|
115
|
+
setupSocketHandlers(tlsSocket, handleClose, 'tls');
|
|
113
116
|
|
|
114
|
-
|
|
117
|
+
// Set timeout
|
|
118
|
+
const timeout = this.getTimeout();
|
|
119
|
+
tlsSocket.setTimeout(timeout);
|
|
120
|
+
|
|
121
|
+
tlsSocket.on('timeout', () => {
|
|
122
|
+
this.emit(ForwardingHandlerEvents.ERROR, {
|
|
123
|
+
remoteAddress,
|
|
124
|
+
error: 'TLS connection timeout'
|
|
125
|
+
});
|
|
126
|
+
handleClose('timeout');
|
|
127
|
+
});
|
|
115
128
|
|
|
129
|
+
// Handle TLS data
|
|
116
130
|
tlsSocket.on('data', (data) => {
|
|
131
|
+
// If backend connection already established, just forward the data
|
|
132
|
+
if (connectionEstablished && backendSocket && !backendSocket.destroyed) {
|
|
133
|
+
backendSocket.write(data);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
117
137
|
// Append to buffer
|
|
118
138
|
dataBuffer = Buffer.concat([dataBuffer, data]);
|
|
119
139
|
|
|
120
140
|
// Very basic HTTP parsing - in a real implementation, use http-parser
|
|
121
|
-
if (dataBuffer.includes(Buffer.from('\r\n\r\n'))) {
|
|
141
|
+
if (dataBuffer.includes(Buffer.from('\r\n\r\n')) && !connectionEstablished) {
|
|
122
142
|
const target = this.getTargetFromConfig();
|
|
123
143
|
|
|
124
|
-
//
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
144
|
+
// Create backend connection
|
|
145
|
+
backendSocket = plugins.net.connect(target.port, target.host, () => {
|
|
146
|
+
connectionEstablished = true;
|
|
147
|
+
|
|
148
|
+
// Send buffered data
|
|
149
|
+
if (dataBuffer.length > 0) {
|
|
150
|
+
backendSocket!.write(dataBuffer);
|
|
151
|
+
dataBuffer = Buffer.alloc(0);
|
|
152
|
+
}
|
|
128
153
|
|
|
129
154
|
// Set up bidirectional data flow
|
|
130
|
-
tlsSocket.pipe(
|
|
131
|
-
|
|
155
|
+
tlsSocket.pipe(backendSocket!);
|
|
156
|
+
backendSocket!.pipe(tlsSocket);
|
|
132
157
|
});
|
|
133
158
|
|
|
134
|
-
|
|
159
|
+
// Update the cleanup handler with the backend socket
|
|
160
|
+
const newHandleClose = createSocketCleanupHandler(tlsSocket, backendSocket, (reason) => {
|
|
161
|
+
this.emit(ForwardingHandlerEvents.DISCONNECTED, {
|
|
162
|
+
remoteAddress,
|
|
163
|
+
reason
|
|
164
|
+
});
|
|
165
|
+
dataBuffer = Buffer.alloc(0);
|
|
166
|
+
connectionEstablished = false;
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Set up handlers for backend socket
|
|
170
|
+
setupSocketHandlers(backendSocket, newHandleClose, 'backend');
|
|
171
|
+
|
|
172
|
+
backendSocket.on('error', (error) => {
|
|
135
173
|
this.emit(ForwardingHandlerEvents.ERROR, {
|
|
136
174
|
remoteAddress,
|
|
137
175
|
error: `Target connection error: ${error.message}`
|
|
138
176
|
});
|
|
139
|
-
|
|
140
|
-
if (!tlsSocket.destroyed) {
|
|
141
|
-
tlsSocket.destroy();
|
|
142
|
-
}
|
|
143
177
|
});
|
|
144
178
|
}
|
|
145
179
|
});
|
|
146
|
-
|
|
147
|
-
// Handle close
|
|
148
|
-
tlsSocket.on('close', () => {
|
|
149
|
-
this.emit(ForwardingHandlerEvents.DISCONNECTED, {
|
|
150
|
-
remoteAddress
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
// Set timeout
|
|
155
|
-
const timeout = this.getTimeout();
|
|
156
|
-
tlsSocket.setTimeout(timeout);
|
|
157
|
-
|
|
158
|
-
tlsSocket.on('timeout', () => {
|
|
159
|
-
this.emit(ForwardingHandlerEvents.ERROR, {
|
|
160
|
-
remoteAddress,
|
|
161
|
-
error: 'TLS connection timeout'
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
if (!tlsSocket.destroyed) {
|
|
165
|
-
tlsSocket.destroy();
|
|
166
|
-
}
|
|
167
|
-
});
|
|
168
180
|
}
|
|
169
181
|
|
|
170
182
|
/**
|
|
@@ -2,6 +2,7 @@ import * as plugins from '../../plugins.js';
|
|
|
2
2
|
import { ForwardingHandler } from './base-handler.js';
|
|
3
3
|
import type { IForwardConfig } from '../config/forwarding-types.js';
|
|
4
4
|
import { ForwardingHandlerEvents } from '../config/forwarding-types.js';
|
|
5
|
+
import { createSocketCleanupHandler, setupSocketHandlers } from '../../core/utils/socket-utils.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Handler for HTTPS termination with HTTPS backend
|
|
@@ -93,28 +94,38 @@ export class HttpsTerminateToHttpsHandler extends ForwardingHandler {
|
|
|
93
94
|
tls: true
|
|
94
95
|
});
|
|
95
96
|
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
// Variable to track backend socket
|
|
98
|
+
let backendSocket: plugins.tls.TLSSocket | null = null;
|
|
99
|
+
|
|
100
|
+
// Create cleanup handler for both sockets
|
|
101
|
+
const handleClose = createSocketCleanupHandler(tlsSocket, backendSocket, (reason) => {
|
|
102
|
+
this.emit(ForwardingHandlerEvents.DISCONNECTED, {
|
|
99
103
|
remoteAddress,
|
|
100
|
-
|
|
104
|
+
reason
|
|
101
105
|
});
|
|
102
|
-
|
|
103
|
-
if (!tlsSocket.destroyed) {
|
|
104
|
-
tlsSocket.destroy();
|
|
105
|
-
}
|
|
106
106
|
});
|
|
107
107
|
|
|
108
|
-
//
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
// Set up error handling with our cleanup utility
|
|
109
|
+
setupSocketHandlers(tlsSocket, handleClose, 'tls');
|
|
110
|
+
|
|
111
|
+
// Set timeout
|
|
112
|
+
const timeout = this.getTimeout();
|
|
113
|
+
tlsSocket.setTimeout(timeout);
|
|
114
|
+
|
|
115
|
+
tlsSocket.on('timeout', () => {
|
|
116
|
+
this.emit(ForwardingHandlerEvents.ERROR, {
|
|
117
|
+
remoteAddress,
|
|
118
|
+
error: 'TLS connection timeout'
|
|
119
|
+
});
|
|
120
|
+
handleClose('timeout');
|
|
121
|
+
});
|
|
111
122
|
|
|
112
123
|
// Get the target from configuration
|
|
113
124
|
const target = this.getTargetFromConfig();
|
|
114
125
|
|
|
115
126
|
// Set up the connection to the HTTPS backend
|
|
116
127
|
const connectToBackend = () => {
|
|
117
|
-
|
|
128
|
+
backendSocket = plugins.tls.connect({
|
|
118
129
|
host: target.host,
|
|
119
130
|
port: target.port,
|
|
120
131
|
// In a real implementation, we would configure TLS options
|
|
@@ -127,30 +138,29 @@ export class HttpsTerminateToHttpsHandler extends ForwardingHandler {
|
|
|
127
138
|
});
|
|
128
139
|
|
|
129
140
|
// Set up bidirectional data flow
|
|
130
|
-
tlsSocket.pipe(backendSocket);
|
|
131
|
-
backendSocket
|
|
141
|
+
tlsSocket.pipe(backendSocket!);
|
|
142
|
+
backendSocket!.pipe(tlsSocket);
|
|
132
143
|
});
|
|
133
144
|
|
|
145
|
+
// Update the cleanup handler with the backend socket
|
|
146
|
+
const newHandleClose = createSocketCleanupHandler(tlsSocket, backendSocket, (reason) => {
|
|
147
|
+
this.emit(ForwardingHandlerEvents.DISCONNECTED, {
|
|
148
|
+
remoteAddress,
|
|
149
|
+
reason
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Set up handlers for backend socket
|
|
154
|
+
setupSocketHandlers(backendSocket, newHandleClose, 'backend');
|
|
155
|
+
|
|
134
156
|
backendSocket.on('error', (error) => {
|
|
135
157
|
this.emit(ForwardingHandlerEvents.ERROR, {
|
|
136
158
|
remoteAddress,
|
|
137
159
|
error: `Backend connection error: ${error.message}`
|
|
138
160
|
});
|
|
139
|
-
|
|
140
|
-
if (!tlsSocket.destroyed) {
|
|
141
|
-
tlsSocket.destroy();
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
// Handle close
|
|
146
|
-
backendSocket.on('close', () => {
|
|
147
|
-
if (!tlsSocket.destroyed) {
|
|
148
|
-
tlsSocket.destroy();
|
|
149
|
-
}
|
|
150
161
|
});
|
|
151
162
|
|
|
152
|
-
// Set timeout
|
|
153
|
-
const timeout = this.getTimeout();
|
|
163
|
+
// Set timeout for backend socket
|
|
154
164
|
backendSocket.setTimeout(timeout);
|
|
155
165
|
|
|
156
166
|
backendSocket.on('timeout', () => {
|
|
@@ -158,10 +168,7 @@ export class HttpsTerminateToHttpsHandler extends ForwardingHandler {
|
|
|
158
168
|
remoteAddress,
|
|
159
169
|
error: 'Backend connection timeout'
|
|
160
170
|
});
|
|
161
|
-
|
|
162
|
-
if (!backendSocket.destroyed) {
|
|
163
|
-
backendSocket.destroy();
|
|
164
|
-
}
|
|
171
|
+
newHandleClose('backend_timeout');
|
|
165
172
|
});
|
|
166
173
|
};
|
|
167
174
|
|
|
@@ -169,28 +176,6 @@ export class HttpsTerminateToHttpsHandler extends ForwardingHandler {
|
|
|
169
176
|
tlsSocket.on('secure', () => {
|
|
170
177
|
connectToBackend();
|
|
171
178
|
});
|
|
172
|
-
|
|
173
|
-
// Handle close
|
|
174
|
-
tlsSocket.on('close', () => {
|
|
175
|
-
this.emit(ForwardingHandlerEvents.DISCONNECTED, {
|
|
176
|
-
remoteAddress
|
|
177
|
-
});
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
// Set timeout
|
|
181
|
-
const timeout = this.getTimeout();
|
|
182
|
-
tlsSocket.setTimeout(timeout);
|
|
183
|
-
|
|
184
|
-
tlsSocket.on('timeout', () => {
|
|
185
|
-
this.emit(ForwardingHandlerEvents.ERROR, {
|
|
186
|
-
remoteAddress,
|
|
187
|
-
error: 'TLS connection timeout'
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
if (!tlsSocket.destroyed) {
|
|
191
|
-
tlsSocket.destroy();
|
|
192
|
-
}
|
|
193
|
-
});
|
|
194
179
|
}
|
|
195
180
|
|
|
196
181
|
/**
|
package/ts/plugins.ts
CHANGED
|
@@ -4,11 +4,12 @@ import * as fs from 'fs';
|
|
|
4
4
|
import * as http from 'http';
|
|
5
5
|
import * as https from 'https';
|
|
6
6
|
import * as net from 'net';
|
|
7
|
+
import * as path from 'path';
|
|
7
8
|
import * as tls from 'tls';
|
|
8
9
|
import * as url from 'url';
|
|
9
10
|
import * as http2 from 'http2';
|
|
10
11
|
|
|
11
|
-
export { EventEmitter, fs, http, https, net, tls, url, http2 };
|
|
12
|
+
export { EventEmitter, fs, http, https, net, path, tls, url, http2 };
|
|
12
13
|
|
|
13
14
|
// tsclass scope
|
|
14
15
|
import * as tsclass from '@tsclass/tsclass';
|
|
@@ -2,6 +2,7 @@ import * as plugins from '../../plugins.js';
|
|
|
2
2
|
import * as fs from 'fs';
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
|
+
import { AsyncFileSystem } from '../../core/utils/fs-utils.js';
|
|
5
6
|
import { type IHttpProxyOptions, type ICertificateEntry, type ILogger, createLogger } from './models/types.js';
|
|
6
7
|
import type { IRouteConfig } from '../smart-proxy/models/route-types.js';
|
|
7
8
|
|
|
@@ -17,6 +18,7 @@ export class CertificateManager {
|
|
|
17
18
|
private certificateStoreDir: string;
|
|
18
19
|
private logger: ILogger;
|
|
19
20
|
private httpsServer: plugins.https.Server | null = null;
|
|
21
|
+
private initialized = false;
|
|
20
22
|
|
|
21
23
|
constructor(private options: IHttpProxyOptions) {
|
|
22
24
|
this.certificateStoreDir = path.resolve(options.acme?.certificateStore || './certs');
|
|
@@ -24,6 +26,15 @@ export class CertificateManager {
|
|
|
24
26
|
|
|
25
27
|
this.logger.warn('CertificateManager is deprecated - use SmartCertManager instead');
|
|
26
28
|
|
|
29
|
+
// Initialize synchronously for backward compatibility but log warning
|
|
30
|
+
this.initializeSync();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Synchronous initialization for backward compatibility
|
|
35
|
+
* @deprecated This uses sync filesystem operations which block the event loop
|
|
36
|
+
*/
|
|
37
|
+
private initializeSync(): void {
|
|
27
38
|
// Ensure certificate store directory exists
|
|
28
39
|
try {
|
|
29
40
|
if (!fs.existsSync(this.certificateStoreDir)) {
|
|
@@ -36,9 +47,28 @@ export class CertificateManager {
|
|
|
36
47
|
|
|
37
48
|
this.loadDefaultCertificates();
|
|
38
49
|
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Async initialization - preferred method
|
|
53
|
+
*/
|
|
54
|
+
public async initialize(): Promise<void> {
|
|
55
|
+
if (this.initialized) return;
|
|
56
|
+
|
|
57
|
+
// Ensure certificate store directory exists
|
|
58
|
+
try {
|
|
59
|
+
await AsyncFileSystem.ensureDir(this.certificateStoreDir);
|
|
60
|
+
this.logger.info(`Ensured certificate store directory: ${this.certificateStoreDir}`);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
this.logger.warn(`Failed to create certificate store directory: ${error}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
await this.loadDefaultCertificatesAsync();
|
|
66
|
+
this.initialized = true;
|
|
67
|
+
}
|
|
39
68
|
|
|
40
69
|
/**
|
|
41
70
|
* Loads default certificates from the filesystem
|
|
71
|
+
* @deprecated This uses sync filesystem operations which block the event loop
|
|
42
72
|
*/
|
|
43
73
|
public loadDefaultCertificates(): void {
|
|
44
74
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -49,7 +79,28 @@ export class CertificateManager {
|
|
|
49
79
|
key: fs.readFileSync(path.join(certPath, 'key.pem'), 'utf8'),
|
|
50
80
|
cert: fs.readFileSync(path.join(certPath, 'cert.pem'), 'utf8')
|
|
51
81
|
};
|
|
52
|
-
this.logger.info('Loaded default certificates from filesystem');
|
|
82
|
+
this.logger.info('Loaded default certificates from filesystem (sync - deprecated)');
|
|
83
|
+
} catch (error) {
|
|
84
|
+
this.logger.error(`Failed to load default certificates: ${error}`);
|
|
85
|
+
this.generateSelfSignedCertificate();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Loads default certificates from the filesystem asynchronously
|
|
91
|
+
*/
|
|
92
|
+
public async loadDefaultCertificatesAsync(): Promise<void> {
|
|
93
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
94
|
+
const certPath = path.join(__dirname, '..', '..', '..', 'assets', 'certs');
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
const [key, cert] = await Promise.all([
|
|
98
|
+
AsyncFileSystem.readFile(path.join(certPath, 'key.pem')),
|
|
99
|
+
AsyncFileSystem.readFile(path.join(certPath, 'cert.pem'))
|
|
100
|
+
]);
|
|
101
|
+
|
|
102
|
+
this.defaultCertificates = { key, cert };
|
|
103
|
+
this.logger.info('Loaded default certificates from filesystem (async)');
|
|
53
104
|
} catch (error) {
|
|
54
105
|
this.logger.error(`Failed to load default certificates: ${error}`);
|
|
55
106
|
this.generateSelfSignedCertificate();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as plugins from '../../plugins.js';
|
|
2
2
|
import { type IHttpProxyOptions, type IConnectionEntry, type ILogger, createLogger } from './models/types.js';
|
|
3
|
+
import { cleanupSocket } from '../../core/utils/socket-utils.js';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Manages a pool of backend connections for efficient reuse
|
|
@@ -133,14 +134,7 @@ export class ConnectionPool {
|
|
|
133
134
|
if ((connection.isIdle && now - connection.lastUsed > idleTimeout) ||
|
|
134
135
|
connections.length > (this.options.connectionPoolSize || 50)) {
|
|
135
136
|
|
|
136
|
-
|
|
137
|
-
if (!connection.socket.destroyed) {
|
|
138
|
-
connection.socket.end();
|
|
139
|
-
connection.socket.destroy();
|
|
140
|
-
}
|
|
141
|
-
} catch (err) {
|
|
142
|
-
this.logger.error(`Error destroying pooled connection to ${host}`, err);
|
|
143
|
-
}
|
|
137
|
+
cleanupSocket(connection.socket, `pool-${host}-idle`);
|
|
144
138
|
|
|
145
139
|
connections.shift(); // Remove from pool
|
|
146
140
|
removed++;
|
|
@@ -170,14 +164,7 @@ export class ConnectionPool {
|
|
|
170
164
|
this.logger.debug(`Closing ${connections.length} connections to ${host}`);
|
|
171
165
|
|
|
172
166
|
for (const connection of connections) {
|
|
173
|
-
|
|
174
|
-
if (!connection.socket.destroyed) {
|
|
175
|
-
connection.socket.end();
|
|
176
|
-
connection.socket.destroy();
|
|
177
|
-
}
|
|
178
|
-
} catch (error) {
|
|
179
|
-
this.logger.error(`Error closing connection to ${host}:`, error);
|
|
180
|
-
}
|
|
167
|
+
cleanupSocket(connection.socket, `pool-${host}-close`);
|
|
181
168
|
}
|
|
182
169
|
}
|
|
183
170
|
|
|
@@ -18,6 +18,7 @@ import { RequestHandler, type IMetricsTracker } from './request-handler.js';
|
|
|
18
18
|
import { WebSocketHandler } from './websocket-handler.js';
|
|
19
19
|
import { ProxyRouter } from '../../routing/router/index.js';
|
|
20
20
|
import { RouteRouter } from '../../routing/router/route-router.js';
|
|
21
|
+
import { cleanupSocket } from '../../core/utils/socket-utils.js';
|
|
21
22
|
import { FunctionCache } from './function-cache.js';
|
|
22
23
|
|
|
23
24
|
/**
|
|
@@ -520,11 +521,7 @@ export class HttpProxy implements IMetricsTracker {
|
|
|
520
521
|
|
|
521
522
|
// Close all tracked sockets
|
|
522
523
|
for (const socket of this.socketMap.getArray()) {
|
|
523
|
-
|
|
524
|
-
socket.destroy();
|
|
525
|
-
} catch (error) {
|
|
526
|
-
this.logger.error('Error destroying socket', error);
|
|
527
|
-
}
|
|
524
|
+
cleanupSocket(socket, 'http-proxy-stop');
|
|
528
525
|
}
|
|
529
526
|
|
|
530
527
|
// Close all connection pool connections
|