@modelprofile.com/browser-runtime 1.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.
- package/.smartconfig.json +34 -0
- package/changelog.md +11 -0
- package/dist_ts/00_commitinfo_data.d.ts +8 -0
- package/dist_ts/00_commitinfo_data.js +9 -0
- package/dist_ts/actions.d.ts +3 -0
- package/dist_ts/actions.js +215 -0
- package/dist_ts/classes.artifactstore.d.ts +38 -0
- package/dist_ts/classes.artifactstore.js +344 -0
- package/dist_ts/classes.egressproxy.d.ts +67 -0
- package/dist_ts/classes.egressproxy.js +830 -0
- package/dist_ts/classes.flexprovider.d.ts +9 -0
- package/dist_ts/classes.flexprovider.js +117 -0
- package/dist_ts/classes.framed.d.ts +52 -0
- package/dist_ts/classes.framed.js +557 -0
- package/dist_ts/classes.runtime.d.ts +202 -0
- package/dist_ts/classes.runtime.js +1667 -0
- package/dist_ts/confinement.d.ts +2 -0
- package/dist_ts/confinement.js +63 -0
- package/dist_ts/errors.d.ts +7 -0
- package/dist_ts/errors.js +40 -0
- package/dist_ts/index.d.ts +11 -0
- package/dist_ts/index.js +9 -0
- package/dist_ts/interfaces.d.ts +287 -0
- package/dist_ts/interfaces.js +2 -0
- package/dist_ts/internal.testing.d.ts +9 -0
- package/dist_ts/internal.testing.js +2 -0
- package/dist_ts/mcp.d.ts +4 -0
- package/dist_ts/mcp.js +196 -0
- package/dist_ts/plugins.d.ts +20 -0
- package/dist_ts/plugins.js +24 -0
- package/dist_ts/utils.d.ts +25 -0
- package/dist_ts/utils.js +143 -0
- package/license.md +21 -0
- package/package.json +59 -0
- package/readme.hints.md +35 -0
- package/readme.md +181 -0
- package/ts/00_commitinfo_data.ts +8 -0
- package/ts/actions.ts +241 -0
- package/ts/classes.artifactstore.ts +432 -0
- package/ts/classes.egressproxy.ts +1005 -0
- package/ts/classes.flexprovider.ts +134 -0
- package/ts/classes.framed.ts +649 -0
- package/ts/classes.runtime.ts +2135 -0
- package/ts/confinement.ts +90 -0
- package/ts/errors.ts +63 -0
- package/ts/index.ts +52 -0
- package/ts/interfaces.ts +375 -0
- package/ts/internal.testing.ts +18 -0
- package/ts/mcp.ts +230 -0
- package/ts/plugins.ts +28 -0
- package/ts/utils.ts +188 -0
|
@@ -0,0 +1,830 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import { BrowserRuntimeError } from './errors.js';
|
|
3
|
+
import { randomId, validateBoundedString, validateInteger, validateOptionalInteger, waitBounded, } from './utils.js';
|
|
4
|
+
const hopByHopHeaders = new Set([
|
|
5
|
+
'connection',
|
|
6
|
+
'keep-alive',
|
|
7
|
+
'proxy-authenticate',
|
|
8
|
+
'proxy-authorization',
|
|
9
|
+
'proxy-connection',
|
|
10
|
+
'te',
|
|
11
|
+
'trailer',
|
|
12
|
+
'transfer-encoding',
|
|
13
|
+
'upgrade',
|
|
14
|
+
]);
|
|
15
|
+
export class BrowserEgressProxy {
|
|
16
|
+
projectId;
|
|
17
|
+
allowedPorts;
|
|
18
|
+
maxConnections;
|
|
19
|
+
maxActiveRequests;
|
|
20
|
+
maxHeaderBytes;
|
|
21
|
+
connectTimeoutMs;
|
|
22
|
+
idleTimeoutMs;
|
|
23
|
+
tunnelLifetimeMs;
|
|
24
|
+
requestTimeoutMs;
|
|
25
|
+
maxRequestBytes;
|
|
26
|
+
maxResponseBytes;
|
|
27
|
+
maxTunnelBytes;
|
|
28
|
+
resolver;
|
|
29
|
+
connector;
|
|
30
|
+
username = randomId(18);
|
|
31
|
+
password = randomId(32);
|
|
32
|
+
expectedAuthorization;
|
|
33
|
+
clientSockets = new Set();
|
|
34
|
+
upstreamSockets = new Set();
|
|
35
|
+
activeOperations = new Set();
|
|
36
|
+
server;
|
|
37
|
+
listenPort;
|
|
38
|
+
startPromise;
|
|
39
|
+
stopPromise;
|
|
40
|
+
lifecycleState = 'stopped';
|
|
41
|
+
lifecycleController = new AbortController();
|
|
42
|
+
ordinaryRequests = 0;
|
|
43
|
+
upgradeRequests = 0;
|
|
44
|
+
connectRequests = 0;
|
|
45
|
+
rejectedRequests = 0;
|
|
46
|
+
constructor(options) {
|
|
47
|
+
this.projectId = validateBoundedString(options.projectId, 'projectId', 1, 128);
|
|
48
|
+
const ports = options.allowedPorts ?? [80, 443];
|
|
49
|
+
if (!Array.isArray(ports) || ports.length < 1 || ports.length > 32) {
|
|
50
|
+
throw new BrowserRuntimeError('INVALID_INPUT', 'allowedPorts must contain 1 to 32 ports');
|
|
51
|
+
}
|
|
52
|
+
this.allowedPorts = new Set(ports.map((port) => validateInteger(port, 'allowedPort', 1, 65535)));
|
|
53
|
+
if (this.allowedPorts.size !== ports.length) {
|
|
54
|
+
throw new BrowserRuntimeError('INVALID_INPUT', 'allowedPorts must not contain duplicates');
|
|
55
|
+
}
|
|
56
|
+
this.maxConnections = validateOptionalInteger(options.maxConnections, 'maxConnections', 1, 1024, 128);
|
|
57
|
+
this.maxActiveRequests = validateOptionalInteger(options.maxActiveRequests, 'maxActiveRequests', 1, 1024, this.maxConnections);
|
|
58
|
+
this.maxHeaderBytes = validateOptionalInteger(options.maxHeaderBytes, 'maxHeaderBytes', 1024, 128 * 1024, 32 * 1024);
|
|
59
|
+
this.connectTimeoutMs = validateOptionalInteger(options.connectTimeoutMs, 'connectTimeoutMs', 100, 60_000, 10_000);
|
|
60
|
+
this.idleTimeoutMs = validateOptionalInteger(options.idleTimeoutMs, 'idleTimeoutMs', 1000, 10 * 60_000, 60_000);
|
|
61
|
+
this.tunnelLifetimeMs = validateOptionalInteger(options.tunnelLifetimeMs, 'tunnelLifetimeMs', 1000, 60 * 60_000, 10 * 60_000);
|
|
62
|
+
this.requestTimeoutMs = validateOptionalInteger(options.requestTimeoutMs, 'requestTimeoutMs', 1000, 60 * 60_000, Math.min(this.tunnelLifetimeMs, 5 * 60_000));
|
|
63
|
+
this.maxRequestBytes = validateOptionalInteger(options.maxRequestBytes, 'maxRequestBytes', 1024, 256 * 1024 * 1024, 16 * 1024 * 1024);
|
|
64
|
+
this.maxResponseBytes = validateOptionalInteger(options.maxResponseBytes, 'maxResponseBytes', 1024, 1024 * 1024 * 1024, 64 * 1024 * 1024);
|
|
65
|
+
this.maxTunnelBytes = validateOptionalInteger(options.maxTunnelBytes, 'maxTunnelBytes', 1024, 2 * 1024 * 1024 * 1024, 256 * 1024 * 1024);
|
|
66
|
+
this.resolver = options.resolver ?? (async (hostname, lookupOptions) => (plugins.dns.promises.lookup(hostname, {
|
|
67
|
+
all: lookupOptions.all,
|
|
68
|
+
verbatim: lookupOptions.verbatim,
|
|
69
|
+
})));
|
|
70
|
+
this.connector = options.connector ?? ((connectionOptions) => plugins.net.connect({
|
|
71
|
+
host: connectionOptions.address,
|
|
72
|
+
family: connectionOptions.family,
|
|
73
|
+
port: connectionOptions.port,
|
|
74
|
+
}));
|
|
75
|
+
this.expectedAuthorization = plugins.Buffer.from(`Basic ${plugins.Buffer.from(`${this.username}:${this.password}`, 'utf8').toString('base64')}`, 'utf8');
|
|
76
|
+
}
|
|
77
|
+
get credentials() {
|
|
78
|
+
return { username: this.username, password: this.password };
|
|
79
|
+
}
|
|
80
|
+
get port() {
|
|
81
|
+
if (this.listenPort === undefined)
|
|
82
|
+
throw new BrowserRuntimeError('NOT_RUNNING');
|
|
83
|
+
return this.listenPort;
|
|
84
|
+
}
|
|
85
|
+
get project() {
|
|
86
|
+
return this.projectId;
|
|
87
|
+
}
|
|
88
|
+
get allowedTargetPorts() {
|
|
89
|
+
return [...this.allowedPorts];
|
|
90
|
+
}
|
|
91
|
+
getStats() {
|
|
92
|
+
return {
|
|
93
|
+
ordinaryRequests: this.ordinaryRequests,
|
|
94
|
+
upgradeRequests: this.upgradeRequests,
|
|
95
|
+
connectRequests: this.connectRequests,
|
|
96
|
+
rejectedRequests: this.rejectedRequests,
|
|
97
|
+
activeConnections: this.clientSockets.size,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
start() {
|
|
101
|
+
if (this.lifecycleState === 'running')
|
|
102
|
+
return Promise.resolve();
|
|
103
|
+
if (this.startPromise)
|
|
104
|
+
return this.startPromise;
|
|
105
|
+
if (this.stopPromise)
|
|
106
|
+
return this.stopPromise.then(() => this.start());
|
|
107
|
+
this.stopPromise = undefined;
|
|
108
|
+
this.lifecycleState = 'starting';
|
|
109
|
+
this.lifecycleController = new AbortController();
|
|
110
|
+
this.startPromise = this.startInternal().then(() => {
|
|
111
|
+
if (this.lifecycleState !== 'starting')
|
|
112
|
+
throw new BrowserRuntimeError('ABORTED');
|
|
113
|
+
this.lifecycleState = 'running';
|
|
114
|
+
}).catch((error) => {
|
|
115
|
+
if (this.lifecycleState === 'starting')
|
|
116
|
+
this.lifecycleState = 'stopped';
|
|
117
|
+
throw error;
|
|
118
|
+
}).finally(() => {
|
|
119
|
+
this.startPromise = undefined;
|
|
120
|
+
});
|
|
121
|
+
return this.startPromise;
|
|
122
|
+
}
|
|
123
|
+
stop() {
|
|
124
|
+
if (this.stopPromise)
|
|
125
|
+
return this.stopPromise;
|
|
126
|
+
if (this.lifecycleState === 'stopped' && !this.server && !this.startPromise) {
|
|
127
|
+
return Promise.resolve();
|
|
128
|
+
}
|
|
129
|
+
this.lifecycleState = 'stopping';
|
|
130
|
+
this.lifecycleController.abort(new BrowserRuntimeError('ABORTED'));
|
|
131
|
+
const startup = this.startPromise;
|
|
132
|
+
this.stopPromise = (async () => {
|
|
133
|
+
await startup?.catch(() => undefined);
|
|
134
|
+
await this.stopInternal();
|
|
135
|
+
this.lifecycleState = 'stopped';
|
|
136
|
+
})().finally(() => {
|
|
137
|
+
this.stopPromise = undefined;
|
|
138
|
+
});
|
|
139
|
+
return this.stopPromise;
|
|
140
|
+
}
|
|
141
|
+
async startInternal() {
|
|
142
|
+
const server = plugins.http.createServer({ maxHeaderSize: this.maxHeaderBytes }, (request, response) => {
|
|
143
|
+
if (!this.admit()) {
|
|
144
|
+
this.rejectedRequests += 1;
|
|
145
|
+
this.sendSafeFailure(response, 503);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
this.track(this.handleHttpRequest(request, response));
|
|
149
|
+
});
|
|
150
|
+
this.server = server;
|
|
151
|
+
server.on('connection', (socket) => {
|
|
152
|
+
if (this.clientSockets.size >= this.maxConnections) {
|
|
153
|
+
socket.destroy();
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
this.clientSockets.add(socket);
|
|
157
|
+
socket.on('error', () => socket.destroy());
|
|
158
|
+
socket.setTimeout(this.idleTimeoutMs, () => socket.destroy());
|
|
159
|
+
socket.once('close', () => this.clientSockets.delete(socket));
|
|
160
|
+
});
|
|
161
|
+
server.on('connect', (request, socket, head) => {
|
|
162
|
+
if (!this.admit()) {
|
|
163
|
+
this.rejectedRequests += 1;
|
|
164
|
+
this.rejectRawSocket(socket, 502, false);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
this.track(this.handleConnect(request, socket, head));
|
|
168
|
+
});
|
|
169
|
+
server.on('upgrade', (request, socket, head) => {
|
|
170
|
+
if (!this.admit()) {
|
|
171
|
+
this.rejectedRequests += 1;
|
|
172
|
+
this.rejectRawSocket(socket, 502, false);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
this.track(this.handleUpgrade(request, socket, head));
|
|
176
|
+
});
|
|
177
|
+
server.on('clientError', (_error, socket) => {
|
|
178
|
+
this.rejectedRequests += 1;
|
|
179
|
+
if (socket.writable) {
|
|
180
|
+
socket.end('HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n');
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
socket.destroy();
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
server.on('error', () => {
|
|
187
|
+
if (this.lifecycleState === 'running')
|
|
188
|
+
void this.stop().catch(() => undefined);
|
|
189
|
+
});
|
|
190
|
+
server.headersTimeout = this.requestTimeoutMs;
|
|
191
|
+
server.requestTimeout = this.requestTimeoutMs;
|
|
192
|
+
server.maxRequestsPerSocket = this.maxActiveRequests;
|
|
193
|
+
await new Promise((resolve, reject) => {
|
|
194
|
+
const onError = (error) => {
|
|
195
|
+
server.off('listening', onListening);
|
|
196
|
+
reject(error);
|
|
197
|
+
};
|
|
198
|
+
const onListening = () => {
|
|
199
|
+
server.off('error', onError);
|
|
200
|
+
resolve();
|
|
201
|
+
};
|
|
202
|
+
server.once('error', onError);
|
|
203
|
+
server.once('listening', onListening);
|
|
204
|
+
server.listen(0, '127.0.0.1');
|
|
205
|
+
});
|
|
206
|
+
const address = server.address();
|
|
207
|
+
if (!address || typeof address === 'string' || address.address !== '127.0.0.1') {
|
|
208
|
+
await this.stopInternal();
|
|
209
|
+
throw new BrowserRuntimeError('FENCED', 'proxy did not bind to IPv4 loopback');
|
|
210
|
+
}
|
|
211
|
+
this.listenPort = address.port;
|
|
212
|
+
}
|
|
213
|
+
async stopInternal() {
|
|
214
|
+
const server = this.server;
|
|
215
|
+
this.listenPort = undefined;
|
|
216
|
+
for (const socket of this.clientSockets)
|
|
217
|
+
socket.destroy();
|
|
218
|
+
for (const socket of this.upstreamSockets)
|
|
219
|
+
socket.destroy();
|
|
220
|
+
if (server) {
|
|
221
|
+
await new Promise((resolve, reject) => {
|
|
222
|
+
server.close((error) => {
|
|
223
|
+
if (error && error.code !== 'ERR_SERVER_NOT_RUNNING') {
|
|
224
|
+
reject(error);
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
resolve();
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
const settled = await waitBounded(Promise.allSettled([...this.activeOperations]).then(() => undefined), this.requestTimeoutMs);
|
|
233
|
+
if (!settled.settled)
|
|
234
|
+
throw new BrowserRuntimeError('TIMEOUT');
|
|
235
|
+
this.server = undefined;
|
|
236
|
+
this.startPromise = undefined;
|
|
237
|
+
}
|
|
238
|
+
track(operation) {
|
|
239
|
+
const observed = operation.catch(() => undefined).finally(() => {
|
|
240
|
+
this.activeOperations.delete(observed);
|
|
241
|
+
});
|
|
242
|
+
this.activeOperations.add(observed);
|
|
243
|
+
}
|
|
244
|
+
admit() {
|
|
245
|
+
return this.lifecycleState !== 'stopping'
|
|
246
|
+
&& this.activeOperations.size < this.maxActiveRequests;
|
|
247
|
+
}
|
|
248
|
+
async handleHttpRequest(request, response) {
|
|
249
|
+
this.ordinaryRequests += 1;
|
|
250
|
+
if (!this.authorize(request)) {
|
|
251
|
+
this.sendProxyAuthenticationRequired(response);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
request.pause();
|
|
255
|
+
let upstreamRequest;
|
|
256
|
+
let upstreamSocket;
|
|
257
|
+
let upstreamResponse;
|
|
258
|
+
let agent;
|
|
259
|
+
const operation = this.createOperationSignal();
|
|
260
|
+
const abort = () => operation.controller.abort(new BrowserRuntimeError('ABORTED'));
|
|
261
|
+
request.once('aborted', abort);
|
|
262
|
+
request.socket.once('close', abort);
|
|
263
|
+
response.once('close', () => {
|
|
264
|
+
if (!response.writableFinished)
|
|
265
|
+
abort();
|
|
266
|
+
});
|
|
267
|
+
try {
|
|
268
|
+
const contentLength = Number(request.headers['content-length']);
|
|
269
|
+
if (Number.isFinite(contentLength)
|
|
270
|
+
&& contentLength > this.maxRequestBytes)
|
|
271
|
+
throw new BrowserRuntimeError('QUOTA_EXCEEDED');
|
|
272
|
+
const target = await this.resolveAbsoluteTarget(request.url, false, operation.signal);
|
|
273
|
+
operation.signal.throwIfAborted();
|
|
274
|
+
upstreamSocket = this.openUpstream(target, operation.signal);
|
|
275
|
+
await this.waitForConnect(upstreamSocket, operation.signal);
|
|
276
|
+
const headers = this.sanitizeHeaders(request.headers);
|
|
277
|
+
headers.host = target.hostHeader;
|
|
278
|
+
agent = new plugins.http.Agent({ keepAlive: false });
|
|
279
|
+
agent.createConnection = () => upstreamSocket;
|
|
280
|
+
upstreamRequest = plugins.http.request({
|
|
281
|
+
method: request.method,
|
|
282
|
+
host: target.address,
|
|
283
|
+
family: target.family,
|
|
284
|
+
port: target.port,
|
|
285
|
+
path: target.path,
|
|
286
|
+
headers,
|
|
287
|
+
agent,
|
|
288
|
+
maxHeaderSize: this.maxHeaderBytes,
|
|
289
|
+
});
|
|
290
|
+
const onAbort = () => {
|
|
291
|
+
upstreamRequest?.destroy(operation.signal.reason);
|
|
292
|
+
upstreamResponse?.destroy(operation.signal.reason);
|
|
293
|
+
upstreamSocket?.destroy(operation.signal.reason);
|
|
294
|
+
};
|
|
295
|
+
operation.signal.addEventListener('abort', onAbort, { once: true });
|
|
296
|
+
let requestBytes = 0;
|
|
297
|
+
request.on('data', (chunk) => {
|
|
298
|
+
requestBytes += chunk.byteLength;
|
|
299
|
+
if (requestBytes > this.maxRequestBytes) {
|
|
300
|
+
operation.controller.abort(new BrowserRuntimeError('QUOTA_EXCEEDED'));
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
const upstreamResponsePromise = new Promise((resolve, reject) => {
|
|
304
|
+
upstreamRequest.once('response', resolve);
|
|
305
|
+
upstreamRequest.once('error', reject);
|
|
306
|
+
});
|
|
307
|
+
request.pipe(upstreamRequest);
|
|
308
|
+
upstreamResponse = await this.raceAbort(upstreamResponsePromise, operation.signal);
|
|
309
|
+
const responseLength = Number(upstreamResponse.headers['content-length']);
|
|
310
|
+
if (Number.isFinite(responseLength) && responseLength > this.maxResponseBytes) {
|
|
311
|
+
throw new BrowserRuntimeError('QUOTA_EXCEEDED');
|
|
312
|
+
}
|
|
313
|
+
const responseHeaders = this.sanitizeHeaders(upstreamResponse.headers);
|
|
314
|
+
response.writeHead(upstreamResponse.statusCode ?? 502, responseHeaders);
|
|
315
|
+
let responseBytes = 0;
|
|
316
|
+
upstreamResponse.on('data', (chunk) => {
|
|
317
|
+
responseBytes += chunk.byteLength;
|
|
318
|
+
if (responseBytes > this.maxResponseBytes) {
|
|
319
|
+
operation.controller.abort(new BrowserRuntimeError('QUOTA_EXCEEDED'));
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
upstreamResponse.once('aborted', abort);
|
|
323
|
+
const responseFailure = new Promise((_resolve, reject) => {
|
|
324
|
+
upstreamResponse.once('error', reject);
|
|
325
|
+
});
|
|
326
|
+
upstreamResponse.pipe(response);
|
|
327
|
+
await Promise.race([this.waitForResponseCompletion(response), responseFailure]);
|
|
328
|
+
operation.signal.throwIfAborted();
|
|
329
|
+
}
|
|
330
|
+
catch {
|
|
331
|
+
this.rejectedRequests += 1;
|
|
332
|
+
upstreamRequest?.destroy();
|
|
333
|
+
upstreamSocket?.destroy();
|
|
334
|
+
if (!response.headersSent)
|
|
335
|
+
this.sendSafeFailure(response, 502);
|
|
336
|
+
else
|
|
337
|
+
response.destroy();
|
|
338
|
+
}
|
|
339
|
+
finally {
|
|
340
|
+
operation.dispose();
|
|
341
|
+
request.off('aborted', abort);
|
|
342
|
+
request.socket.off('close', abort);
|
|
343
|
+
upstreamResponse?.destroy();
|
|
344
|
+
upstreamRequest?.destroy();
|
|
345
|
+
upstreamSocket?.destroy();
|
|
346
|
+
agent?.destroy();
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
async handleConnect(request, clientSocket, head) {
|
|
350
|
+
this.connectRequests += 1;
|
|
351
|
+
if (!this.authorize(request)) {
|
|
352
|
+
this.rejectRawSocket(clientSocket, 407, true);
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
clientSocket.pause();
|
|
356
|
+
const operation = this.createOperationSignal();
|
|
357
|
+
const abort = () => operation.controller.abort(new BrowserRuntimeError('ABORTED'));
|
|
358
|
+
clientSocket.once('close', abort);
|
|
359
|
+
let upstream;
|
|
360
|
+
try {
|
|
361
|
+
if (head.byteLength > this.maxTunnelBytes)
|
|
362
|
+
throw new BrowserRuntimeError('QUOTA_EXCEEDED');
|
|
363
|
+
const target = await this.resolveAuthority(request.url, operation.signal);
|
|
364
|
+
upstream = this.openUpstream(target, operation.signal);
|
|
365
|
+
await this.waitForConnect(upstream, operation.signal);
|
|
366
|
+
operation.signal.throwIfAborted();
|
|
367
|
+
clientSocket.write('HTTP/1.1 200 Connection Established\r\n\r\n');
|
|
368
|
+
await this.pipeTunnel(clientSocket, upstream, {
|
|
369
|
+
toUpstream: head,
|
|
370
|
+
toClient: plugins.Buffer.alloc(0),
|
|
371
|
+
}, operation.signal);
|
|
372
|
+
}
|
|
373
|
+
catch {
|
|
374
|
+
this.rejectedRequests += 1;
|
|
375
|
+
upstream?.destroy();
|
|
376
|
+
this.rejectRawSocket(clientSocket, 502, false);
|
|
377
|
+
}
|
|
378
|
+
finally {
|
|
379
|
+
operation.dispose();
|
|
380
|
+
clientSocket.off('close', abort);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
async handleUpgrade(request, clientSocket, head) {
|
|
384
|
+
this.upgradeRequests += 1;
|
|
385
|
+
if (!this.authorize(request)) {
|
|
386
|
+
this.rejectRawSocket(clientSocket, 407, true);
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
clientSocket.pause();
|
|
390
|
+
const operation = this.createOperationSignal();
|
|
391
|
+
const abort = () => operation.controller.abort(new BrowserRuntimeError('ABORTED'));
|
|
392
|
+
clientSocket.once('close', abort);
|
|
393
|
+
let upstream;
|
|
394
|
+
try {
|
|
395
|
+
if (request.method !== 'GET'
|
|
396
|
+
|| String(request.headers.upgrade).toLowerCase() !== 'websocket'
|
|
397
|
+
|| !String(request.headers.connection).toLowerCase().split(',')
|
|
398
|
+
.map((value) => value.trim()).includes('upgrade'))
|
|
399
|
+
throw new BrowserRuntimeError('EGRESS_DENIED');
|
|
400
|
+
const webSocketKey = validateBoundedString(request.headers['sec-websocket-key'], 'sec-websocket-key', 20, 32);
|
|
401
|
+
if (request.headers['sec-websocket-version'] !== '13'
|
|
402
|
+
|| !/^[A-Za-z0-9+/]{22}==$/.test(webSocketKey)
|
|
403
|
+
|| plugins.Buffer.from(webSocketKey, 'base64').toString('base64') !== webSocketKey)
|
|
404
|
+
throw new BrowserRuntimeError('EGRESS_DENIED');
|
|
405
|
+
const expectedAccept = plugins.crypto
|
|
406
|
+
.createHash('sha1')
|
|
407
|
+
.update(`${webSocketKey}258EAFA5-E914-47DA-95CA-C5AB0DC85B11`, 'ascii')
|
|
408
|
+
.digest('base64');
|
|
409
|
+
if (head.byteLength > this.maxTunnelBytes)
|
|
410
|
+
throw new BrowserRuntimeError('QUOTA_EXCEEDED');
|
|
411
|
+
const target = await this.resolveAbsoluteTarget(request.url, true, operation.signal);
|
|
412
|
+
upstream = this.openUpstream(target, operation.signal);
|
|
413
|
+
await this.waitForConnect(upstream, operation.signal);
|
|
414
|
+
const headers = this.sanitizeHeaders(request.headers);
|
|
415
|
+
headers.host = target.hostHeader;
|
|
416
|
+
headers.connection = 'Upgrade';
|
|
417
|
+
headers.upgrade = 'websocket';
|
|
418
|
+
const headerLines = Object.entries(headers).flatMap(([name, value]) => (Array.isArray(value)
|
|
419
|
+
? value.map((entry) => `${name}: ${entry}`)
|
|
420
|
+
: value === undefined
|
|
421
|
+
? []
|
|
422
|
+
: [`${name}: ${value}`]));
|
|
423
|
+
upstream.write(`${request.method ?? 'GET'} ${target.path} HTTP/1.1\r\n${headerLines.join('\r\n')}\r\n\r\n`);
|
|
424
|
+
const handshake = await this.readWebSocketHandshake(upstream, operation.signal, expectedAccept);
|
|
425
|
+
clientSocket.write(handshake.header);
|
|
426
|
+
await this.pipeTunnel(clientSocket, upstream, { toUpstream: head, toClient: handshake.remaining }, operation.signal);
|
|
427
|
+
}
|
|
428
|
+
catch {
|
|
429
|
+
this.rejectedRequests += 1;
|
|
430
|
+
upstream?.destroy();
|
|
431
|
+
this.rejectRawSocket(clientSocket, 502, false);
|
|
432
|
+
}
|
|
433
|
+
finally {
|
|
434
|
+
operation.dispose();
|
|
435
|
+
clientSocket.off('close', abort);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
authorize(request) {
|
|
439
|
+
const value = request.headers['proxy-authorization'];
|
|
440
|
+
if (typeof value !== 'string') {
|
|
441
|
+
this.rejectedRequests += 1;
|
|
442
|
+
return false;
|
|
443
|
+
}
|
|
444
|
+
const supplied = plugins.Buffer.from(value, 'utf8');
|
|
445
|
+
const accepted = supplied.byteLength === this.expectedAuthorization.byteLength
|
|
446
|
+
&& plugins.crypto.timingSafeEqual(supplied, this.expectedAuthorization);
|
|
447
|
+
if (!accepted)
|
|
448
|
+
this.rejectedRequests += 1;
|
|
449
|
+
return accepted;
|
|
450
|
+
}
|
|
451
|
+
sendProxyAuthenticationRequired(response) {
|
|
452
|
+
response.writeHead(407, {
|
|
453
|
+
connection: 'close',
|
|
454
|
+
'content-length': '0',
|
|
455
|
+
'proxy-authenticate': 'Basic realm="browser-runtime"',
|
|
456
|
+
});
|
|
457
|
+
response.end();
|
|
458
|
+
}
|
|
459
|
+
sendSafeFailure(response, status) {
|
|
460
|
+
response.writeHead(status, { connection: 'close', 'content-length': '0' });
|
|
461
|
+
response.end();
|
|
462
|
+
}
|
|
463
|
+
rejectRawSocket(socket, status, authenticate) {
|
|
464
|
+
if (!socket.writable) {
|
|
465
|
+
socket.destroy();
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
const statusText = status === 407 ? 'Proxy Authentication Required' : 'Bad Gateway';
|
|
469
|
+
const challenge = authenticate
|
|
470
|
+
? 'Proxy-Authenticate: Basic realm="browser-runtime"\r\n'
|
|
471
|
+
: '';
|
|
472
|
+
socket.end(`HTTP/1.1 ${status} ${statusText}\r\n${challenge}Connection: close\r\nContent-Length: 0\r\n\r\n`);
|
|
473
|
+
}
|
|
474
|
+
sanitizeHeaders(headers) {
|
|
475
|
+
const connectionTokens = new Set((typeof headers.connection === 'string' ? headers.connection : '')
|
|
476
|
+
.split(',')
|
|
477
|
+
.map((token) => token.trim().toLowerCase())
|
|
478
|
+
.filter(Boolean));
|
|
479
|
+
const result = {};
|
|
480
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
481
|
+
const normalizedName = name.toLowerCase();
|
|
482
|
+
if (hopByHopHeaders.has(normalizedName) || connectionTokens.has(normalizedName))
|
|
483
|
+
continue;
|
|
484
|
+
result[normalizedName] = value;
|
|
485
|
+
}
|
|
486
|
+
return result;
|
|
487
|
+
}
|
|
488
|
+
async resolveAbsoluteTarget(rawUrl, upgrade, signal) {
|
|
489
|
+
if (!rawUrl || plugins.Buffer.byteLength(rawUrl, 'utf8') > 8192) {
|
|
490
|
+
throw new BrowserRuntimeError('EGRESS_DENIED');
|
|
491
|
+
}
|
|
492
|
+
let parsed;
|
|
493
|
+
try {
|
|
494
|
+
parsed = new URL(rawUrl);
|
|
495
|
+
}
|
|
496
|
+
catch {
|
|
497
|
+
throw new BrowserRuntimeError('EGRESS_DENIED');
|
|
498
|
+
}
|
|
499
|
+
const allowedProtocols = upgrade ? new Set(['http:', 'ws:']) : new Set(['http:']);
|
|
500
|
+
if (!allowedProtocols.has(parsed.protocol)
|
|
501
|
+
|| parsed.username
|
|
502
|
+
|| parsed.password
|
|
503
|
+
|| parsed.hash) {
|
|
504
|
+
throw new BrowserRuntimeError('EGRESS_DENIED');
|
|
505
|
+
}
|
|
506
|
+
const hostname = this.canonicalizeHostname(parsed.hostname);
|
|
507
|
+
const port = parsed.port
|
|
508
|
+
? validateInteger(Number(parsed.port), 'target port', 1, 65535)
|
|
509
|
+
: 80;
|
|
510
|
+
const resolved = await this.resolveHost(hostname, port, signal);
|
|
511
|
+
return {
|
|
512
|
+
...resolved,
|
|
513
|
+
path: `${parsed.pathname || '/'}${parsed.search}`,
|
|
514
|
+
hostHeader: parsed.host,
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
async resolveAuthority(rawAuthority, signal) {
|
|
518
|
+
if (!rawAuthority
|
|
519
|
+
|| rawAuthority.length > 512
|
|
520
|
+
|| /[\/?#@]/.test(rawAuthority)) {
|
|
521
|
+
throw new BrowserRuntimeError('EGRESS_DENIED');
|
|
522
|
+
}
|
|
523
|
+
let hostnameValue;
|
|
524
|
+
let portValue;
|
|
525
|
+
if (rawAuthority.startsWith('[')) {
|
|
526
|
+
const closingBracket = rawAuthority.indexOf(']');
|
|
527
|
+
if (closingBracket < 2 || rawAuthority[closingBracket + 1] !== ':') {
|
|
528
|
+
throw new BrowserRuntimeError('EGRESS_DENIED');
|
|
529
|
+
}
|
|
530
|
+
hostnameValue = rawAuthority.slice(1, closingBracket);
|
|
531
|
+
portValue = rawAuthority.slice(closingBracket + 2);
|
|
532
|
+
}
|
|
533
|
+
else {
|
|
534
|
+
const separator = rawAuthority.lastIndexOf(':');
|
|
535
|
+
if (separator < 1 || rawAuthority.indexOf(':') !== separator) {
|
|
536
|
+
throw new BrowserRuntimeError('EGRESS_DENIED');
|
|
537
|
+
}
|
|
538
|
+
hostnameValue = rawAuthority.slice(0, separator);
|
|
539
|
+
portValue = rawAuthority.slice(separator + 1);
|
|
540
|
+
}
|
|
541
|
+
if (!/^\d{1,5}$/.test(portValue))
|
|
542
|
+
throw new BrowserRuntimeError('EGRESS_DENIED');
|
|
543
|
+
const hostname = this.canonicalizeHostname(hostnameValue);
|
|
544
|
+
const port = validateInteger(Number(portValue), 'target port', 1, 65535);
|
|
545
|
+
const resolved = await this.resolveHost(hostname, port, signal);
|
|
546
|
+
return { ...resolved, path: '', hostHeader: rawAuthority };
|
|
547
|
+
}
|
|
548
|
+
canonicalizeHostname(hostnameArg) {
|
|
549
|
+
const unbracketed = hostnameArg.startsWith('[') && hostnameArg.endsWith(']')
|
|
550
|
+
? hostnameArg.slice(1, -1)
|
|
551
|
+
: hostnameArg;
|
|
552
|
+
if (!unbracketed || unbracketed.length > 253 || unbracketed.includes('%')) {
|
|
553
|
+
throw new BrowserRuntimeError('EGRESS_DENIED');
|
|
554
|
+
}
|
|
555
|
+
if (plugins.ipaddr.isValid(unbracketed)) {
|
|
556
|
+
return plugins.ipaddr.parse(unbracketed).toNormalizedString();
|
|
557
|
+
}
|
|
558
|
+
const withoutTrailingDot = unbracketed.endsWith('.') ? unbracketed.slice(0, -1) : unbracketed;
|
|
559
|
+
const ascii = plugins.url.domainToASCII(withoutTrailingDot).toLowerCase();
|
|
560
|
+
if (!ascii
|
|
561
|
+
|| ascii.length > 253
|
|
562
|
+
|| !ascii.includes('.')
|
|
563
|
+
|| ascii.split('.').some((label) => (label.length < 1
|
|
564
|
+
|| label.length > 63
|
|
565
|
+
|| !/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/.test(label)))) {
|
|
566
|
+
throw new BrowserRuntimeError('EGRESS_DENIED');
|
|
567
|
+
}
|
|
568
|
+
return ascii;
|
|
569
|
+
}
|
|
570
|
+
async resolveHost(hostname, port, signal) {
|
|
571
|
+
if (!this.allowedPorts.has(port)) {
|
|
572
|
+
throw new BrowserRuntimeError('EGRESS_DENIED');
|
|
573
|
+
}
|
|
574
|
+
const answers = plugins.ipaddr.isValid(hostname)
|
|
575
|
+
? [{ address: hostname, family: plugins.ipaddr.parse(hostname).kind() === 'ipv4' ? 4 : 6 }]
|
|
576
|
+
: await this.raceAbort(this.resolver(hostname, { all: true, verbatim: true, signal }), signal);
|
|
577
|
+
signal.throwIfAborted();
|
|
578
|
+
if (!Array.isArray(answers) || answers.length < 1 || answers.length > 64) {
|
|
579
|
+
throw new BrowserRuntimeError('EGRESS_DENIED');
|
|
580
|
+
}
|
|
581
|
+
const validated = answers.map((answer) => {
|
|
582
|
+
if (!answer
|
|
583
|
+
|| (answer.family !== 4 && answer.family !== 6)
|
|
584
|
+
|| typeof answer.address !== 'string'
|
|
585
|
+
|| answer.address.includes('%')
|
|
586
|
+
|| !plugins.ipaddr.isValid(answer.address)) {
|
|
587
|
+
throw new BrowserRuntimeError('EGRESS_DENIED');
|
|
588
|
+
}
|
|
589
|
+
const parsed = plugins.ipaddr.parse(answer.address);
|
|
590
|
+
if ((parsed.kind() === 'ipv6'
|
|
591
|
+
&& parsed.isIPv4MappedAddress())
|
|
592
|
+
|| parsed.range() !== 'unicast'
|
|
593
|
+
|| (parsed.kind() === 'ipv6'
|
|
594
|
+
&& !parsed.match(plugins.ipaddr.parse('2000::'), 3))) {
|
|
595
|
+
throw new BrowserRuntimeError('EGRESS_DENIED');
|
|
596
|
+
}
|
|
597
|
+
const family = parsed.kind() === 'ipv4' ? 4 : 6;
|
|
598
|
+
if (family !== answer.family)
|
|
599
|
+
throw new BrowserRuntimeError('EGRESS_DENIED');
|
|
600
|
+
return { address: parsed.toNormalizedString(), family };
|
|
601
|
+
});
|
|
602
|
+
return { ...validated[0], hostname, port };
|
|
603
|
+
}
|
|
604
|
+
openUpstream(target, signal) {
|
|
605
|
+
const options = {
|
|
606
|
+
address: target.address,
|
|
607
|
+
family: target.family,
|
|
608
|
+
port: target.port,
|
|
609
|
+
hostname: target.hostname,
|
|
610
|
+
signal,
|
|
611
|
+
};
|
|
612
|
+
const socket = this.connector(options);
|
|
613
|
+
if (!(socket instanceof plugins.net.Socket)) {
|
|
614
|
+
throw new BrowserRuntimeError('EGRESS_DENIED');
|
|
615
|
+
}
|
|
616
|
+
this.upstreamSockets.add(socket);
|
|
617
|
+
socket.on('error', () => socket.destroy());
|
|
618
|
+
socket.setTimeout(this.idleTimeoutMs, () => socket.destroy());
|
|
619
|
+
socket.once('close', () => this.upstreamSockets.delete(socket));
|
|
620
|
+
if (signal.aborted)
|
|
621
|
+
socket.destroy(signal.reason);
|
|
622
|
+
else
|
|
623
|
+
signal.addEventListener('abort', () => socket.destroy(signal.reason), { once: true });
|
|
624
|
+
return socket;
|
|
625
|
+
}
|
|
626
|
+
async waitForConnect(socket, signal) {
|
|
627
|
+
if (!socket.connecting
|
|
628
|
+
&& !socket.pending
|
|
629
|
+
&& !socket.destroyed
|
|
630
|
+
&& socket.remoteAddress)
|
|
631
|
+
return;
|
|
632
|
+
if (!socket.connecting || socket.destroyed)
|
|
633
|
+
throw new BrowserRuntimeError('EGRESS_DENIED');
|
|
634
|
+
await new Promise((resolve, reject) => {
|
|
635
|
+
const timer = setTimeout(() => {
|
|
636
|
+
cleanup();
|
|
637
|
+
socket.destroy();
|
|
638
|
+
reject(new BrowserRuntimeError('TIMEOUT'));
|
|
639
|
+
}, this.connectTimeoutMs);
|
|
640
|
+
timer.unref();
|
|
641
|
+
const cleanup = () => {
|
|
642
|
+
clearTimeout(timer);
|
|
643
|
+
socket.off('connect', onConnect);
|
|
644
|
+
socket.off('error', onError);
|
|
645
|
+
socket.off('close', onClose);
|
|
646
|
+
signal.removeEventListener('abort', onAbort);
|
|
647
|
+
};
|
|
648
|
+
const onConnect = () => {
|
|
649
|
+
cleanup();
|
|
650
|
+
resolve();
|
|
651
|
+
};
|
|
652
|
+
const onError = () => {
|
|
653
|
+
cleanup();
|
|
654
|
+
reject(new BrowserRuntimeError('EGRESS_DENIED'));
|
|
655
|
+
};
|
|
656
|
+
const onClose = () => {
|
|
657
|
+
cleanup();
|
|
658
|
+
reject(new BrowserRuntimeError('EGRESS_DENIED'));
|
|
659
|
+
};
|
|
660
|
+
const onAbort = () => {
|
|
661
|
+
cleanup();
|
|
662
|
+
socket.destroy(signal.reason);
|
|
663
|
+
reject(signal.reason);
|
|
664
|
+
};
|
|
665
|
+
socket.once('connect', onConnect);
|
|
666
|
+
socket.once('error', onError);
|
|
667
|
+
socket.once('close', onClose);
|
|
668
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
async pipeTunnel(clientSocket, upstream, initial, signal) {
|
|
672
|
+
let transferred = initial.toUpstream.byteLength + initial.toClient.byteLength;
|
|
673
|
+
if (transferred > this.maxTunnelBytes)
|
|
674
|
+
throw new BrowserRuntimeError('QUOTA_EXCEEDED');
|
|
675
|
+
const lifetimeTimer = setTimeout(() => {
|
|
676
|
+
clientSocket.destroy();
|
|
677
|
+
upstream.destroy();
|
|
678
|
+
}, this.tunnelLifetimeMs);
|
|
679
|
+
lifetimeTimer.unref();
|
|
680
|
+
const count = (chunk) => {
|
|
681
|
+
transferred += chunk.byteLength;
|
|
682
|
+
if (transferred > this.maxTunnelBytes) {
|
|
683
|
+
clientSocket.destroy();
|
|
684
|
+
upstream.destroy();
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
clientSocket.on('data', count);
|
|
688
|
+
upstream.on('data', count);
|
|
689
|
+
const onAbort = () => {
|
|
690
|
+
clientSocket.destroy(signal.reason);
|
|
691
|
+
upstream.destroy(signal.reason);
|
|
692
|
+
};
|
|
693
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
694
|
+
if (initial.toUpstream.byteLength > 0)
|
|
695
|
+
upstream.write(initial.toUpstream);
|
|
696
|
+
if (initial.toClient.byteLength > 0)
|
|
697
|
+
clientSocket.write(initial.toClient);
|
|
698
|
+
clientSocket.pipe(upstream);
|
|
699
|
+
upstream.pipe(clientSocket);
|
|
700
|
+
clientSocket.resume();
|
|
701
|
+
await Promise.race([
|
|
702
|
+
new Promise((resolve) => clientSocket.once('close', resolve)),
|
|
703
|
+
new Promise((resolve) => upstream.once('close', resolve)),
|
|
704
|
+
]);
|
|
705
|
+
clearTimeout(lifetimeTimer);
|
|
706
|
+
clientSocket.off('data', count);
|
|
707
|
+
upstream.off('data', count);
|
|
708
|
+
signal.removeEventListener('abort', onAbort);
|
|
709
|
+
clientSocket.destroy();
|
|
710
|
+
upstream.destroy();
|
|
711
|
+
}
|
|
712
|
+
async readWebSocketHandshake(upstream, signal, expectedAccept) {
|
|
713
|
+
const data = await new Promise((resolve, reject) => {
|
|
714
|
+
let buffered = plugins.Buffer.alloc(0);
|
|
715
|
+
const cleanup = () => {
|
|
716
|
+
upstream.off('data', onData);
|
|
717
|
+
upstream.off('error', onError);
|
|
718
|
+
upstream.off('close', onClose);
|
|
719
|
+
signal.removeEventListener('abort', onAbort);
|
|
720
|
+
};
|
|
721
|
+
const onData = (chunk) => {
|
|
722
|
+
buffered = plugins.Buffer.concat([buffered, chunk]);
|
|
723
|
+
const boundary = buffered.indexOf('\r\n\r\n');
|
|
724
|
+
if (boundary < 0 && buffered.byteLength > this.maxHeaderBytes) {
|
|
725
|
+
cleanup();
|
|
726
|
+
reject(new BrowserRuntimeError('QUOTA_EXCEEDED'));
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
if (boundary < 0)
|
|
730
|
+
return;
|
|
731
|
+
if (boundary + 4 > this.maxHeaderBytes) {
|
|
732
|
+
cleanup();
|
|
733
|
+
reject(new BrowserRuntimeError('QUOTA_EXCEEDED'));
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
cleanup();
|
|
737
|
+
resolve(buffered);
|
|
738
|
+
};
|
|
739
|
+
const onError = () => {
|
|
740
|
+
cleanup();
|
|
741
|
+
reject(new BrowserRuntimeError('EGRESS_DENIED'));
|
|
742
|
+
};
|
|
743
|
+
const onClose = () => {
|
|
744
|
+
cleanup();
|
|
745
|
+
reject(new BrowserRuntimeError('EGRESS_DENIED'));
|
|
746
|
+
};
|
|
747
|
+
const onAbort = () => {
|
|
748
|
+
cleanup();
|
|
749
|
+
reject(signal.reason);
|
|
750
|
+
};
|
|
751
|
+
upstream.on('data', onData);
|
|
752
|
+
upstream.once('error', onError);
|
|
753
|
+
upstream.once('close', onClose);
|
|
754
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
755
|
+
});
|
|
756
|
+
const boundary = data.indexOf('\r\n\r\n');
|
|
757
|
+
const header = data.subarray(0, boundary + 4);
|
|
758
|
+
const statusLine = header.subarray(0, header.indexOf('\r\n')).toString('latin1');
|
|
759
|
+
if (!/^HTTP\/1\.[01] 101(?: |$)/.test(statusLine)) {
|
|
760
|
+
throw new BrowserRuntimeError('EGRESS_DENIED');
|
|
761
|
+
}
|
|
762
|
+
const headerLines = header.toString('latin1').split('\r\n').slice(1, -2);
|
|
763
|
+
const headers = new Map();
|
|
764
|
+
for (const headerLine of headerLines) {
|
|
765
|
+
const separator = headerLine.indexOf(':');
|
|
766
|
+
if (separator < 1)
|
|
767
|
+
throw new BrowserRuntimeError('EGRESS_DENIED');
|
|
768
|
+
const name = headerLine.slice(0, separator).trim().toLowerCase();
|
|
769
|
+
const value = headerLine.slice(separator + 1).trim();
|
|
770
|
+
const values = headers.get(name) ?? [];
|
|
771
|
+
values.push(value);
|
|
772
|
+
headers.set(name, values);
|
|
773
|
+
}
|
|
774
|
+
const connectionTokens = (headers.get('connection') ?? [])
|
|
775
|
+
.flatMap((value) => value.split(','))
|
|
776
|
+
.map((value) => value.trim().toLowerCase());
|
|
777
|
+
if (!connectionTokens.includes('upgrade')
|
|
778
|
+
|| headers.get('upgrade')?.length !== 1
|
|
779
|
+
|| headers.get('upgrade')?.[0]?.toLowerCase() !== 'websocket'
|
|
780
|
+
|| headers.get('sec-websocket-accept')?.length !== 1
|
|
781
|
+
|| headers.get('sec-websocket-accept')?.[0] !== expectedAccept)
|
|
782
|
+
throw new BrowserRuntimeError('EGRESS_DENIED');
|
|
783
|
+
return { header, remaining: data.subarray(boundary + 4) };
|
|
784
|
+
}
|
|
785
|
+
createOperationSignal() {
|
|
786
|
+
const controller = new AbortController();
|
|
787
|
+
const timeoutController = new AbortController();
|
|
788
|
+
const timeout = setTimeout(() => {
|
|
789
|
+
timeoutController.abort(new BrowserRuntimeError('TIMEOUT'));
|
|
790
|
+
}, this.requestTimeoutMs);
|
|
791
|
+
timeout.unref();
|
|
792
|
+
return {
|
|
793
|
+
controller,
|
|
794
|
+
signal: AbortSignal.any([
|
|
795
|
+
controller.signal,
|
|
796
|
+
timeoutController.signal,
|
|
797
|
+
this.lifecycleController.signal,
|
|
798
|
+
]),
|
|
799
|
+
dispose: () => clearTimeout(timeout),
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
async raceAbort(promise, signal) {
|
|
803
|
+
signal.throwIfAborted();
|
|
804
|
+
let onAbort;
|
|
805
|
+
const aborted = new Promise((_resolve, reject) => {
|
|
806
|
+
onAbort = () => reject(signal.reason);
|
|
807
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
808
|
+
});
|
|
809
|
+
try {
|
|
810
|
+
return await Promise.race([promise, aborted]);
|
|
811
|
+
}
|
|
812
|
+
finally {
|
|
813
|
+
signal.removeEventListener('abort', onAbort);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
async waitForResponseCompletion(response) {
|
|
817
|
+
if (response.writableFinished || response.destroyed)
|
|
818
|
+
return;
|
|
819
|
+
await new Promise((resolve) => {
|
|
820
|
+
const settle = () => {
|
|
821
|
+
response.off('finish', settle);
|
|
822
|
+
response.off('close', settle);
|
|
823
|
+
resolve();
|
|
824
|
+
};
|
|
825
|
+
response.once('finish', settle);
|
|
826
|
+
response.once('close', settle);
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5lZ3Jlc3Nwcm94eS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2NsYXNzZXMuZWdyZXNzcHJveHkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFReEMsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ2xELE9BQU8sRUFDTCxRQUFRLEVBQ1IscUJBQXFCLEVBQ3JCLGVBQWUsRUFDZix1QkFBdUIsRUFDdkIsV0FBVyxHQUNaLE1BQU0sWUFBWSxDQUFDO0FBV3BCLE1BQU0sZUFBZSxHQUFHLElBQUksR0FBRyxDQUFDO0lBQzlCLFlBQVk7SUFDWixZQUFZO0lBQ1osb0JBQW9CO0lBQ3BCLHFCQUFxQjtJQUNyQixrQkFBa0I7SUFDbEIsSUFBSTtJQUNKLFNBQVM7SUFDVCxtQkFBbUI7SUFDbkIsU0FBUztDQUNWLENBQUMsQ0FBQztBQUVILE1BQU0sT0FBTyxrQkFBa0I7SUFDWixTQUFTLENBQVM7SUFDbEIsWUFBWSxDQUFzQjtJQUNsQyxjQUFjLENBQVM7SUFDdkIsaUJBQWlCLENBQVM7SUFDMUIsY0FBYyxDQUFTO0lBQ3ZCLGdCQUFnQixDQUFTO0lBQ3pCLGFBQWEsQ0FBUztJQUN0QixnQkFBZ0IsQ0FBUztJQUN6QixnQkFBZ0IsQ0FBUztJQUN6QixlQUFlLENBQVM7SUFDeEIsZ0JBQWdCLENBQVM7SUFDekIsY0FBYyxDQUFTO0lBQ3ZCLFFBQVEsQ0FBc0I7SUFDOUIsU0FBUyxDQUEwQjtJQUNuQyxRQUFRLEdBQUcsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3hCLFFBQVEsR0FBRyxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDeEIscUJBQXFCLENBQWlCO0lBQ3RDLGFBQWEsR0FBRyxJQUFJLEdBQUcsRUFBc0IsQ0FBQztJQUM5QyxlQUFlLEdBQUcsSUFBSSxHQUFHLEVBQXNCLENBQUM7SUFDaEQsZ0JBQWdCLEdBQUcsSUFB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
|