@ai-ecoverse/slicc-kernel 1.90.0 → 1.91.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/README.md +2 -1
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +481 -70
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-process-worker.js +117 -86
- package/dist/node-process-worker.js.map +4 -4
- package/dist/node.js +498 -87
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +79 -48
- package/dist/process-worker.js.map +3 -3
- package/dist/testing.js.map +1 -1
- package/package.json +2 -2
package/dist/kernel-worker.js
CHANGED
|
@@ -2299,8 +2299,8 @@ async function access(fs, cred, path, want, options = {}) {
|
|
|
2299
2299
|
if (await present(fs, walked.path, false)) return { ...walked, denied: walked.path };
|
|
2300
2300
|
return { ...walked, missing: true };
|
|
2301
2301
|
}
|
|
2302
|
-
function refused(path,
|
|
2303
|
-
return fsError(
|
|
2302
|
+
function refused(path, errno2 = "EACCES") {
|
|
2303
|
+
return fsError(errno2, path);
|
|
2304
2304
|
}
|
|
2305
2305
|
|
|
2306
2306
|
// src/fs/dac.ts
|
|
@@ -2360,9 +2360,9 @@ var Created = class {
|
|
|
2360
2360
|
function linked(g, options) {
|
|
2361
2361
|
return g.links === void 0 ? options : { ...options, links: g.links };
|
|
2362
2362
|
}
|
|
2363
|
-
function deny(g, op, path,
|
|
2363
|
+
function deny(g, op, path, errno2 = "EACCES") {
|
|
2364
2364
|
const tag = g.tag === void 0 ? {} : { tag: g.tag };
|
|
2365
|
-
g.dac.denied({ pid: g.pid, uid: g.cred.euid, op, path, errno, ...tag });
|
|
2365
|
+
g.dac.denied({ pid: g.pid, uid: g.cred.euid, op, path, errno: errno2, ...tag });
|
|
2366
2366
|
}
|
|
2367
2367
|
var TTY_MODE = 400;
|
|
2368
2368
|
function ttyOpenable(g, tty) {
|
|
@@ -3029,7 +3029,7 @@ var WASI_SIGNAL_TO_POSIX = Object.fromEntries(
|
|
|
3029
3029
|
|
|
3030
3030
|
// src/process/wasi-errno.ts
|
|
3031
3031
|
var WASI_ERRNO = {
|
|
3032
|
-
...Object.fromEntries(Object.entries(E).map(([name2,
|
|
3032
|
+
...Object.fromEntries(Object.entries(E).map(([name2, errno2]) => [`E${name2}`, errno2])),
|
|
3033
3033
|
EWOULDBLOCK: E.AGAIN,
|
|
3034
3034
|
ENOTSUP: 138,
|
|
3035
3035
|
EOPNOTSUPP: 138,
|
|
@@ -3126,7 +3126,7 @@ function dialError(e, timedOut, closed) {
|
|
|
3126
3126
|
if (timedOut) return new KernelError("ETIMEDOUT");
|
|
3127
3127
|
if (closed) return new KernelError("ECONNABORTED");
|
|
3128
3128
|
const code = e?.code;
|
|
3129
|
-
const known = DIAL_ERRORS.find((
|
|
3129
|
+
const known = DIAL_ERRORS.find((errno2) => errno2 === code);
|
|
3130
3130
|
return new KernelError(known ?? "EHOSTUNREACH");
|
|
3131
3131
|
}
|
|
3132
3132
|
function isLoopback(host) {
|
|
@@ -3793,11 +3793,11 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS } = {}) {
|
|
|
3793
3793
|
};
|
|
3794
3794
|
const sockets = /* @__PURE__ */ new Map();
|
|
3795
3795
|
const credit = /* @__PURE__ */ new Map();
|
|
3796
|
-
const refill = (nid, n,
|
|
3796
|
+
const refill = (nid, n, closing2 = false) => {
|
|
3797
3797
|
const flow = credit.get(nid);
|
|
3798
3798
|
if (!flow) return;
|
|
3799
3799
|
flow.inflight -= n;
|
|
3800
|
-
if (
|
|
3800
|
+
if (closing2 && !flow.closing) {
|
|
3801
3801
|
flow.closing = true;
|
|
3802
3802
|
flow.deadline();
|
|
3803
3803
|
}
|
|
@@ -4928,6 +4928,33 @@ function toHostLoopback(href) {
|
|
|
4928
4928
|
url.hostname = "127.0.0.1";
|
|
4929
4929
|
return url.href;
|
|
4930
4930
|
}
|
|
4931
|
+
var LOOPBACK_V4 = /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
|
|
4932
|
+
var LOOPBACK_V6 = /* @__PURE__ */ new Set(["::1", "::", "0:0:0:0:0:0:0:1"]);
|
|
4933
|
+
var MAPPED_V4 = /^::ffff:7f[0-9a-f]{2}:[0-9a-f]{1,4}$/;
|
|
4934
|
+
var KERNEL_PORT = /^(\d{1,5})\.kernel\.localhost$/;
|
|
4935
|
+
var SCHEMES = {
|
|
4936
|
+
"http:": 80,
|
|
4937
|
+
"ws:": 80,
|
|
4938
|
+
"https:": 443,
|
|
4939
|
+
"wss:": 443
|
|
4940
|
+
};
|
|
4941
|
+
function isKernelLoopbackHost(hostname) {
|
|
4942
|
+
const host = hostname.replace(/^\[(.*)\]$/, "$1").replace(/\.$/, "").toLowerCase();
|
|
4943
|
+
return host === "localhost" || host.endsWith(".localhost") || host === "0.0.0.0" || LOOPBACK_V4.test(host) || LOOPBACK_V6.has(host) || MAPPED_V4.test(host);
|
|
4944
|
+
}
|
|
4945
|
+
function kernelLoopbackPort(href) {
|
|
4946
|
+
let url;
|
|
4947
|
+
try {
|
|
4948
|
+
url = new URL(href);
|
|
4949
|
+
} catch {
|
|
4950
|
+
return void 0;
|
|
4951
|
+
}
|
|
4952
|
+
const fallback = SCHEMES[url.protocol];
|
|
4953
|
+
if (fallback === void 0 || !isKernelLoopbackHost(url.hostname)) return void 0;
|
|
4954
|
+
const named = KERNEL_PORT.exec(url.hostname.replace(/\.$/, "").toLowerCase())?.[1];
|
|
4955
|
+
const port = Number(named ?? (url.port || fallback));
|
|
4956
|
+
return port >= 1 && port <= 65535 ? port : void 0;
|
|
4957
|
+
}
|
|
4931
4958
|
var DEFAULT_HOSTNAME = "slicc";
|
|
4932
4959
|
var HOSTNAME_ADDRESS = "127.0.1.1";
|
|
4933
4960
|
var LIBC_HOSTNAMES = ["emscripten", "wasmer.sh"];
|
|
@@ -5233,6 +5260,9 @@ async function acceptKey(headers) {
|
|
|
5233
5260
|
}
|
|
5234
5261
|
const key = field(headers, "sec-websocket-key") ?? "";
|
|
5235
5262
|
if (!/^[A-Za-z0-9+/]{22}==$/.test(key)) throw new HttpError(400, "bad Sec-WebSocket-Key");
|
|
5263
|
+
return acceptFor(key);
|
|
5264
|
+
}
|
|
5265
|
+
async function acceptFor(key) {
|
|
5236
5266
|
const digest = await crypto.subtle.digest("SHA-1", new TextEncoder().encode(key + GUID));
|
|
5237
5267
|
return btoa(String.fromCharCode(...new Uint8Array(digest)));
|
|
5238
5268
|
}
|
|
@@ -5256,6 +5286,19 @@ function frame(opcode, payload) {
|
|
|
5256
5286
|
out.set(payload, size);
|
|
5257
5287
|
return out;
|
|
5258
5288
|
}
|
|
5289
|
+
function clientFrame(opcode, payload) {
|
|
5290
|
+
const plain = frame(opcode, payload);
|
|
5291
|
+
const head = plain.length - payload.length;
|
|
5292
|
+
const mask = crypto.getRandomValues(new Uint8Array(4));
|
|
5293
|
+
const out = new Uint8Array(plain.length + 4);
|
|
5294
|
+
out.set(plain.subarray(0, head));
|
|
5295
|
+
out[1] = out[1] | 128;
|
|
5296
|
+
out.set(mask, head);
|
|
5297
|
+
for (let i = 0; i < payload.length; i++) {
|
|
5298
|
+
out[head + 4 + i] = payload[i] ^ mask[i & 3];
|
|
5299
|
+
}
|
|
5300
|
+
return out;
|
|
5301
|
+
}
|
|
5259
5302
|
function closeFrame(code, reason = "") {
|
|
5260
5303
|
let bytes = new TextEncoder().encode(reason);
|
|
5261
5304
|
if (bytes.length > 123) {
|
|
@@ -5295,10 +5338,12 @@ var WsReader = class {
|
|
|
5295
5338
|
continuing = false;
|
|
5296
5339
|
binaryMessage = false;
|
|
5297
5340
|
binary;
|
|
5298
|
-
|
|
5341
|
+
fromServer;
|
|
5342
|
+
constructor(incoming, max = MAX_MESSAGE, binary, fromServer = false) {
|
|
5299
5343
|
this.incoming = incoming;
|
|
5300
5344
|
this.max = max;
|
|
5301
5345
|
this.binary = binary;
|
|
5346
|
+
this.fromServer = fromServer;
|
|
5302
5347
|
}
|
|
5303
5348
|
async next(signal) {
|
|
5304
5349
|
for (; ; ) {
|
|
@@ -5310,7 +5355,7 @@ var WsReader = class {
|
|
|
5310
5355
|
const fin = (head[0] & 128) !== 0;
|
|
5311
5356
|
const opcode = head[0] & 15;
|
|
5312
5357
|
if ((head[0] & 112) !== 0) throw new WsError(CLOSE.protocol, "reserved bits are set");
|
|
5313
|
-
|
|
5358
|
+
const masked = this.masking(head[1]);
|
|
5314
5359
|
const length2 = await this.length(head[1] & 127, signal);
|
|
5315
5360
|
const control = opcode >= 8;
|
|
5316
5361
|
if (control && (length2 > 125 || !fin)) {
|
|
@@ -5319,15 +5364,19 @@ var WsReader = class {
|
|
|
5319
5364
|
if (!control && this.size + length2 > this.max) {
|
|
5320
5365
|
throw new WsError(CLOSE.tooBig, `a message is over ${this.max} bytes`);
|
|
5321
5366
|
}
|
|
5322
|
-
const
|
|
5323
|
-
await fill(this.incoming, mask, signal);
|
|
5324
|
-
const payload = new Uint8Array(length2);
|
|
5325
|
-
await fill(this.incoming, payload, signal);
|
|
5326
|
-
for (let i = 0; i < length2; i++) payload[i] ^= mask[i & 3];
|
|
5367
|
+
const payload = await this.payload(length2, masked, signal);
|
|
5327
5368
|
const event = this.take(opcode, fin, payload);
|
|
5328
5369
|
if (event) return event;
|
|
5329
5370
|
}
|
|
5330
5371
|
}
|
|
5372
|
+
masking(second) {
|
|
5373
|
+
const masked = (second & 128) !== 0;
|
|
5374
|
+
if (masked !== this.fromServer) return masked;
|
|
5375
|
+
throw new WsError(
|
|
5376
|
+
CLOSE.protocol,
|
|
5377
|
+
this.fromServer ? "server frames must not be masked" : "client frames must be masked"
|
|
5378
|
+
);
|
|
5379
|
+
}
|
|
5331
5380
|
data(opcode, fin, payload) {
|
|
5332
5381
|
if (opcode === OP.continuation !== this.continuing) {
|
|
5333
5382
|
throw new WsError(CLOSE.protocol, "unexpected continuation frame");
|
|
@@ -5342,6 +5391,14 @@ var WsReader = class {
|
|
|
5342
5391
|
this.size = 0;
|
|
5343
5392
|
return this.binaryMessage ? { kind: "binary", bytes: whole } : { kind: "text", text: decode(whole) };
|
|
5344
5393
|
}
|
|
5394
|
+
async payload(length2, masked, signal) {
|
|
5395
|
+
const mask = new Uint8Array(4);
|
|
5396
|
+
if (masked) await fill(this.incoming, mask, signal);
|
|
5397
|
+
const payload = new Uint8Array(length2);
|
|
5398
|
+
await fill(this.incoming, payload, signal);
|
|
5399
|
+
if (masked) for (let i = 0; i < length2; i++) payload[i] ^= mask[i & 3];
|
|
5400
|
+
return payload;
|
|
5401
|
+
}
|
|
5345
5402
|
async length(short, signal) {
|
|
5346
5403
|
if (short < 126) return short;
|
|
5347
5404
|
const ext = new Uint8Array(short === 126 ? 2 : 8);
|
|
@@ -5777,10 +5834,10 @@ var RealmProxy = class {
|
|
|
5777
5834
|
encodedBodies: this.options.transport.traits.encodedBodies,
|
|
5778
5835
|
bodiless: bodiless2
|
|
5779
5836
|
});
|
|
5780
|
-
const
|
|
5781
|
-
const keep2 = keepAlive && (bodiless2 ||
|
|
5837
|
+
const chunked2 = !bodiless2 && minor >= 1;
|
|
5838
|
+
const keep2 = keepAlive && (bodiless2 || chunked2);
|
|
5782
5839
|
headers.push(["Connection", keep2 ? "keep-alive" : "close"]);
|
|
5783
|
-
if (
|
|
5840
|
+
if (chunked2) headers.push(["Transfer-Encoding", "chunked"]);
|
|
5784
5841
|
const signal = this.stop.signal;
|
|
5785
5842
|
await conn.write(
|
|
5786
5843
|
responseHead(status, response.statusText || REASON[status] || "", headers),
|
|
@@ -5792,13 +5849,13 @@ var RealmProxy = class {
|
|
|
5792
5849
|
}
|
|
5793
5850
|
try {
|
|
5794
5851
|
for await (const piece of response.body) {
|
|
5795
|
-
if (piece.length > 0) await conn.write(
|
|
5852
|
+
if (piece.length > 0) await conn.write(chunked2 ? chunk(piece) : piece, signal);
|
|
5796
5853
|
}
|
|
5797
5854
|
} catch {
|
|
5798
5855
|
await response.cancel().catch(() => void 0);
|
|
5799
5856
|
return false;
|
|
5800
5857
|
}
|
|
5801
|
-
if (
|
|
5858
|
+
if (chunked2) await conn.write(LAST_CHUNK, signal);
|
|
5802
5859
|
return keep2;
|
|
5803
5860
|
}
|
|
5804
5861
|
async connect(conn, incoming, req, idle) {
|
|
@@ -8225,15 +8282,15 @@ var UnlinkedKeeper = class {
|
|
|
8225
8282
|
wrap(fs = this.fs) {
|
|
8226
8283
|
const keeper = this;
|
|
8227
8284
|
const visible = (names) => names.filter((name2) => name2 !== UNLINKED_DIR);
|
|
8228
|
-
const
|
|
8285
|
+
const counted2 = (st) => {
|
|
8229
8286
|
const hidden = keeper.links.get(`${st.dev ?? 0}:${st.ino}`) ?? 0;
|
|
8230
8287
|
return hidden === 0 || st.nlink === void 0 ? st : { ...st, nlink: Math.max(0, st.nlink - hidden) };
|
|
8231
8288
|
};
|
|
8232
8289
|
return {
|
|
8233
8290
|
...fs,
|
|
8234
8291
|
links: (path) => mayLink(fs, path),
|
|
8235
|
-
stat: async (path) =>
|
|
8236
|
-
lstat: async (path) =>
|
|
8292
|
+
stat: async (path) => counted2(await fs.stat(path)),
|
|
8293
|
+
lstat: async (path) => counted2(await fs.lstat(path)),
|
|
8237
8294
|
async rm(path, options) {
|
|
8238
8295
|
const target = fs.resolvePath("/", path);
|
|
8239
8296
|
const pinned = await keeper.pin(target);
|
|
@@ -8247,7 +8304,7 @@ var UnlinkedKeeper = class {
|
|
|
8247
8304
|
await keeper.settle(pinned, () => fs.rename(from, to));
|
|
8248
8305
|
},
|
|
8249
8306
|
readdir: async (path) => visible(await fs.readdir(path)),
|
|
8250
|
-
readdirStat: async (path) => (await fs.readdirStat(path)).filter(([name2]) => name2 !== UNLINKED_DIR).map(([name2, st]) => [name2, st &&
|
|
8307
|
+
readdirStat: async (path) => (await fs.readdirStat(path)).filter(([name2]) => name2 !== UNLINKED_DIR).map(([name2, st]) => [name2, st && counted2(st)])
|
|
8251
8308
|
};
|
|
8252
8309
|
}
|
|
8253
8310
|
async settle(pinned, op) {
|
|
@@ -11079,7 +11136,7 @@ function mountTable(mounts = []) {
|
|
|
11079
11136
|
}
|
|
11080
11137
|
|
|
11081
11138
|
// src/version.ts
|
|
11082
|
-
var KERNEL_VERSION = true ? "1.
|
|
11139
|
+
var KERNEL_VERSION = true ? "1.91.0" : "0.0.0-dev";
|
|
11083
11140
|
var OS_RELEASE = "6.0.0-slicc";
|
|
11084
11141
|
function procVersion() {
|
|
11085
11142
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -11667,6 +11724,339 @@ async function hostSyscall(req, ctx) {
|
|
|
11667
11724
|
}
|
|
11668
11725
|
}
|
|
11669
11726
|
|
|
11727
|
+
// src/kernel/net/loopback-transport.ts
|
|
11728
|
+
var LOOPBACK_TRAITS = {
|
|
11729
|
+
manualRedirects: true,
|
|
11730
|
+
encodedBodies: true,
|
|
11731
|
+
maxRequestBody: 64 * 1024 * 1024,
|
|
11732
|
+
crossOrigin: "any",
|
|
11733
|
+
websocket: true
|
|
11734
|
+
};
|
|
11735
|
+
var MAX_HEAD2 = 64 * 1024;
|
|
11736
|
+
var OWN_HEADERS = /* @__PURE__ */ new Set([
|
|
11737
|
+
"host",
|
|
11738
|
+
"connection",
|
|
11739
|
+
"content-length",
|
|
11740
|
+
"transfer-encoding",
|
|
11741
|
+
"upgrade",
|
|
11742
|
+
"sec-websocket-key",
|
|
11743
|
+
"sec-websocket-version",
|
|
11744
|
+
"sec-websocket-protocol",
|
|
11745
|
+
"sec-websocket-extensions"
|
|
11746
|
+
]);
|
|
11747
|
+
var OP_CLOSE = 8;
|
|
11748
|
+
var OP_PONG = 10;
|
|
11749
|
+
var TOKEN3 = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
|
|
11750
|
+
var SAFE_VALUE = /^[^\r\n\0]*$/;
|
|
11751
|
+
var CLOSE_WAIT_MS3 = 5e3;
|
|
11752
|
+
var MAX_UNREAD = 16 * 1024 * 1024;
|
|
11753
|
+
function errno(code, message3) {
|
|
11754
|
+
return Object.assign(new Error(`${code}: ${message3}`), { code });
|
|
11755
|
+
}
|
|
11756
|
+
function requestHead(method, url, headers, extra) {
|
|
11757
|
+
if (!TOKEN3.test(method)) throw errno("EINVAL", `method ${method}`);
|
|
11758
|
+
const lines2 = [`${method} ${url.pathname}${url.search} HTTP/1.1`, `Host: ${url.host}`];
|
|
11759
|
+
for (const [name2, value] of headers) {
|
|
11760
|
+
if (OWN_HEADERS.has(name2.toLowerCase())) continue;
|
|
11761
|
+
if (!TOKEN3.test(name2) || !SAFE_VALUE.test(value)) throw errno("EINVAL", `header ${name2}`);
|
|
11762
|
+
lines2.push(`${name2}: ${value}`);
|
|
11763
|
+
}
|
|
11764
|
+
for (const [name2, value] of extra) lines2.push(`${name2}: ${value}`);
|
|
11765
|
+
return latin1Bytes(`${lines2.join("\r\n")}\r
|
|
11766
|
+
\r
|
|
11767
|
+
`);
|
|
11768
|
+
}
|
|
11769
|
+
function parseHead(bytes) {
|
|
11770
|
+
const [statusLine = "", ...lines2] = latin1(bytes).split(/\r?\n/);
|
|
11771
|
+
const match = /^HTTP\/1\.[01] (\d{3})(?: (.*))?$/.exec(statusLine);
|
|
11772
|
+
if (!match) throw errno("EPROTO", `not an HTTP/1.x response: ${statusLine.slice(0, 80)}`);
|
|
11773
|
+
const headers = [];
|
|
11774
|
+
for (const line of lines2) {
|
|
11775
|
+
const colon = line.indexOf(":");
|
|
11776
|
+
if (colon > 0) headers.push([line.slice(0, colon).trim(), line.slice(colon + 1).trim()]);
|
|
11777
|
+
}
|
|
11778
|
+
return { status: Number(match[1]), statusText: match[2] ?? "", headers };
|
|
11779
|
+
}
|
|
11780
|
+
async function readHead(incoming, signal) {
|
|
11781
|
+
for (; ; ) {
|
|
11782
|
+
let raw;
|
|
11783
|
+
try {
|
|
11784
|
+
raw = await incoming.head(MAX_HEAD2, signal);
|
|
11785
|
+
} catch (err) {
|
|
11786
|
+
if (err instanceof KernelError) throw err;
|
|
11787
|
+
throw errno("EPROTO", "the response head is malformed or too large");
|
|
11788
|
+
}
|
|
11789
|
+
if (!raw) throw errno("ECONNRESET", "the connection closed before a response");
|
|
11790
|
+
const head = parseHead(raw);
|
|
11791
|
+
if (head.status < 100 || head.status >= 200 || head.status === 101) return head;
|
|
11792
|
+
}
|
|
11793
|
+
}
|
|
11794
|
+
async function* chunked(incoming, signal) {
|
|
11795
|
+
for (; ; ) {
|
|
11796
|
+
const line = await incoming.line(4096, signal);
|
|
11797
|
+
const size = /^([0-9A-Fa-f]{1,12})[ \t]*(;.*)?$/.exec(line);
|
|
11798
|
+
if (!size) throw errno("EPROTO", "a malformed chunk size");
|
|
11799
|
+
const n = Number.parseInt(size[1], 16);
|
|
11800
|
+
if (n === 0) {
|
|
11801
|
+
while (await incoming.line(MAX_HEAD2, signal) !== "") ;
|
|
11802
|
+
return;
|
|
11803
|
+
}
|
|
11804
|
+
yield await incoming.exactly(n, signal);
|
|
11805
|
+
if (await incoming.line(2, signal) !== "") throw errno("EPROTO", "a malformed chunk");
|
|
11806
|
+
}
|
|
11807
|
+
}
|
|
11808
|
+
async function* counted(incoming, length2, signal) {
|
|
11809
|
+
for (let left = length2; left > 0; ) {
|
|
11810
|
+
const data = await incoming.some(Math.min(left, 64 * 1024), signal);
|
|
11811
|
+
if (data.length === 0) throw errno("EPROTO", "the body ended early");
|
|
11812
|
+
left -= data.length;
|
|
11813
|
+
yield data;
|
|
11814
|
+
}
|
|
11815
|
+
}
|
|
11816
|
+
async function* untilClose(incoming, signal) {
|
|
11817
|
+
for (; ; ) {
|
|
11818
|
+
const data = await incoming.some(64 * 1024, signal);
|
|
11819
|
+
if (data.length === 0) return;
|
|
11820
|
+
yield data;
|
|
11821
|
+
}
|
|
11822
|
+
}
|
|
11823
|
+
function bodyOf(incoming, head, method, signal) {
|
|
11824
|
+
if (method === "HEAD" || head.status === 204 || head.status === 304) return [];
|
|
11825
|
+
if (fieldTokens(head.headers, "transfer-encoding").includes("chunked")) {
|
|
11826
|
+
return chunked(incoming, signal);
|
|
11827
|
+
}
|
|
11828
|
+
const lengths = fieldValues(head.headers, "content-length");
|
|
11829
|
+
if (lengths.length === 0) return untilClose(incoming, signal);
|
|
11830
|
+
const length2 = lengths[0]?.trim() ?? "";
|
|
11831
|
+
if (!/^\d{1,15}$/.test(length2) || lengths.some((l) => l.trim() !== length2)) {
|
|
11832
|
+
throw errno("EPROTO", `a malformed Content-Length: ${lengths.join(", ")}`);
|
|
11833
|
+
}
|
|
11834
|
+
return counted(incoming, Number(length2), signal);
|
|
11835
|
+
}
|
|
11836
|
+
var KernelLoopback = class {
|
|
11837
|
+
net;
|
|
11838
|
+
cred;
|
|
11839
|
+
constructor(net, cred) {
|
|
11840
|
+
this.net = net;
|
|
11841
|
+
this.cred = cred;
|
|
11842
|
+
}
|
|
11843
|
+
port(url) {
|
|
11844
|
+
return kernelLoopbackPort(url);
|
|
11845
|
+
}
|
|
11846
|
+
connect(url, port, signal) {
|
|
11847
|
+
if (url.protocol === "https:" || url.protocol === "wss:") {
|
|
11848
|
+
throw errno("ENOTSUP", `TLS to the kernel's loopback is not supported: ${url.origin}`);
|
|
11849
|
+
}
|
|
11850
|
+
signal.throwIfAborted();
|
|
11851
|
+
const socket = this.net.socket("inet");
|
|
11852
|
+
try {
|
|
11853
|
+
void socket.connect({ family: "inet", host: "127.0.0.1", port }, false, this.cred());
|
|
11854
|
+
} catch (err) {
|
|
11855
|
+
socket.close();
|
|
11856
|
+
const refused2 = err instanceof KernelError && err.code === "ECONNREFUSED";
|
|
11857
|
+
throw refused2 ? errno("ECONNREFUSED", `nothing listens on the kernel's port ${port}`) : err;
|
|
11858
|
+
}
|
|
11859
|
+
signal.addEventListener("abort", () => socket.close(), { once: true });
|
|
11860
|
+
return socket;
|
|
11861
|
+
}
|
|
11862
|
+
async fetch(req, port) {
|
|
11863
|
+
const url = new URL(req.url);
|
|
11864
|
+
const body = req.body ?? (/^(POST|PUT|PATCH)$/i.test(req.method) ? new Uint8Array(0) : void 0);
|
|
11865
|
+
const length2 = body ? [["Content-Length", String(body.length)]] : [];
|
|
11866
|
+
const head = requestHead(req.method, url, req.headers, [...length2, ["Connection", "close"]]);
|
|
11867
|
+
const socket = this.connect(url, port, req.signal);
|
|
11868
|
+
try {
|
|
11869
|
+
await writeAll2(socket, body ? concat([head, body]) : head, req.signal);
|
|
11870
|
+
const incoming = new Incoming(socket);
|
|
11871
|
+
const response = await readHead(incoming, req.signal);
|
|
11872
|
+
const chunks = bodyOf(incoming, response, req.method, req.signal);
|
|
11873
|
+
return {
|
|
11874
|
+
url: req.url,
|
|
11875
|
+
status: response.status,
|
|
11876
|
+
statusText: response.statusText,
|
|
11877
|
+
headers: response.headers,
|
|
11878
|
+
body: closing(chunks, socket),
|
|
11879
|
+
cancel: async () => socket.close()
|
|
11880
|
+
};
|
|
11881
|
+
} catch (err) {
|
|
11882
|
+
socket.close();
|
|
11883
|
+
throw err;
|
|
11884
|
+
}
|
|
11885
|
+
}
|
|
11886
|
+
async websocket(req, port) {
|
|
11887
|
+
const url = new URL(req.url);
|
|
11888
|
+
const socket = this.connect(url, port, req.signal);
|
|
11889
|
+
try {
|
|
11890
|
+
const key = btoa(String.fromCharCode(...crypto.getRandomValues(new Uint8Array(16))));
|
|
11891
|
+
const extra = [
|
|
11892
|
+
["Upgrade", "websocket"],
|
|
11893
|
+
["Connection", "Upgrade"],
|
|
11894
|
+
["Sec-WebSocket-Key", key],
|
|
11895
|
+
["Sec-WebSocket-Version", "13"]
|
|
11896
|
+
];
|
|
11897
|
+
if (req.protocols.length > 0)
|
|
11898
|
+
extra.push(["Sec-WebSocket-Protocol", req.protocols.join(", ")]);
|
|
11899
|
+
await writeAll2(socket, requestHead("GET", url, req.headers, extra), req.signal);
|
|
11900
|
+
const incoming = new Incoming(socket);
|
|
11901
|
+
const head = await readHead(incoming, req.signal);
|
|
11902
|
+
if (head.status !== 101) {
|
|
11903
|
+
throw errno(
|
|
11904
|
+
"EPROTO",
|
|
11905
|
+
`the server answered ${head.status} ${head.statusText}, not an upgrade`
|
|
11906
|
+
);
|
|
11907
|
+
}
|
|
11908
|
+
const upgraded = fieldTokens(head.headers, "upgrade").includes("websocket") && fieldTokens(head.headers, "connection").includes("upgrade");
|
|
11909
|
+
const accept2 = fieldValues(head.headers, "sec-websocket-accept")[0];
|
|
11910
|
+
if (!upgraded || accept2 !== await acceptFor(key)) {
|
|
11911
|
+
throw errno("EPROTO", "the server did not accept the WebSocket key");
|
|
11912
|
+
}
|
|
11913
|
+
const protocol = fieldValues(head.headers, "sec-websocket-protocol")[0] ?? "";
|
|
11914
|
+
return new LoopbackWebSocket(socket, incoming, protocol);
|
|
11915
|
+
} catch (err) {
|
|
11916
|
+
socket.close();
|
|
11917
|
+
throw err;
|
|
11918
|
+
}
|
|
11919
|
+
}
|
|
11920
|
+
};
|
|
11921
|
+
async function writeAll2(socket, bytes, signal) {
|
|
11922
|
+
for (let at = 0; at < bytes.length; ) at += await socket.write(bytes.subarray(at), signal);
|
|
11923
|
+
}
|
|
11924
|
+
async function* closing(chunks, socket) {
|
|
11925
|
+
try {
|
|
11926
|
+
yield* chunks;
|
|
11927
|
+
} catch (err) {
|
|
11928
|
+
if (typeof err?.code === "string") throw err;
|
|
11929
|
+
throw errno("EPROTO", err instanceof Error ? err.message : String(err));
|
|
11930
|
+
} finally {
|
|
11931
|
+
socket.close();
|
|
11932
|
+
}
|
|
11933
|
+
}
|
|
11934
|
+
var LoopbackWebSocket = class {
|
|
11935
|
+
protocol;
|
|
11936
|
+
messages;
|
|
11937
|
+
closed;
|
|
11938
|
+
pending = 0;
|
|
11939
|
+
writes = Promise.resolve();
|
|
11940
|
+
sentClose = false;
|
|
11941
|
+
stop = new AbortController();
|
|
11942
|
+
socket;
|
|
11943
|
+
settle;
|
|
11944
|
+
unread = 0;
|
|
11945
|
+
room;
|
|
11946
|
+
constructor(socket, incoming, protocol) {
|
|
11947
|
+
this.socket = socket;
|
|
11948
|
+
this.protocol = protocol;
|
|
11949
|
+
this.closed = new Promise((resolve2) => {
|
|
11950
|
+
this.settle = resolve2;
|
|
11951
|
+
});
|
|
11952
|
+
this.stop.signal.addEventListener("abort", () => this.room?.(), { once: true });
|
|
11953
|
+
const queue = [];
|
|
11954
|
+
let wake;
|
|
11955
|
+
let ended = false;
|
|
11956
|
+
void this.pump(new WsReader(incoming, void 0, true, true), (message3) => {
|
|
11957
|
+
queue.push(message3);
|
|
11958
|
+
this.unread += message3.length;
|
|
11959
|
+
wake?.();
|
|
11960
|
+
}).finally(() => {
|
|
11961
|
+
ended = true;
|
|
11962
|
+
wake?.();
|
|
11963
|
+
});
|
|
11964
|
+
const taken = (message3) => {
|
|
11965
|
+
this.unread -= message3.length;
|
|
11966
|
+
const room = this.room;
|
|
11967
|
+
this.room = void 0;
|
|
11968
|
+
room?.();
|
|
11969
|
+
};
|
|
11970
|
+
this.messages = {
|
|
11971
|
+
[Symbol.asyncIterator]: async function* () {
|
|
11972
|
+
for (; ; ) {
|
|
11973
|
+
const next2 = queue.shift();
|
|
11974
|
+
if (next2 !== void 0) {
|
|
11975
|
+
taken(next2);
|
|
11976
|
+
yield next2;
|
|
11977
|
+
continue;
|
|
11978
|
+
}
|
|
11979
|
+
if (ended) return;
|
|
11980
|
+
await new Promise((resolve2) => {
|
|
11981
|
+
wake = resolve2;
|
|
11982
|
+
});
|
|
11983
|
+
wake = void 0;
|
|
11984
|
+
}
|
|
11985
|
+
}
|
|
11986
|
+
};
|
|
11987
|
+
}
|
|
11988
|
+
async space() {
|
|
11989
|
+
while (this.unread > MAX_UNREAD && !this.stop.signal.aborted) {
|
|
11990
|
+
await new Promise((resolve2) => {
|
|
11991
|
+
this.room = resolve2;
|
|
11992
|
+
});
|
|
11993
|
+
}
|
|
11994
|
+
}
|
|
11995
|
+
get buffered() {
|
|
11996
|
+
return this.pending;
|
|
11997
|
+
}
|
|
11998
|
+
write(bytes) {
|
|
11999
|
+
this.pending += bytes.length;
|
|
12000
|
+
const previous = this.writes;
|
|
12001
|
+
this.writes = (async () => {
|
|
12002
|
+
await previous;
|
|
12003
|
+
try {
|
|
12004
|
+
await writeAll2(this.socket, bytes, this.stop.signal);
|
|
12005
|
+
} catch {
|
|
12006
|
+
this.stop.abort();
|
|
12007
|
+
}
|
|
12008
|
+
this.pending -= bytes.length;
|
|
12009
|
+
})();
|
|
12010
|
+
}
|
|
12011
|
+
async pump(reader, deliver) {
|
|
12012
|
+
let close = { code: 1006, reason: "" };
|
|
12013
|
+
try {
|
|
12014
|
+
for (; ; ) {
|
|
12015
|
+
await this.space();
|
|
12016
|
+
const event = await reader.next(this.stop.signal);
|
|
12017
|
+
if (!event) break;
|
|
12018
|
+
if (event.kind === "text") deliver(event.text);
|
|
12019
|
+
else if (event.kind === "binary") deliver(event.bytes);
|
|
12020
|
+
else if (event.kind === "ping") this.write(clientFrame(OP_PONG, event.payload));
|
|
12021
|
+
else {
|
|
12022
|
+
close = { code: event.code, reason: event.reason };
|
|
12023
|
+
if (!this.sentClose) this.sendClose(event.code === 1005 ? 1e3 : event.code, "");
|
|
12024
|
+
break;
|
|
12025
|
+
}
|
|
12026
|
+
}
|
|
12027
|
+
} catch (err) {
|
|
12028
|
+
if (err instanceof WsError) this.sendClose(err.code, err.message);
|
|
12029
|
+
close = { code: err instanceof WsError ? err.code : 1006, reason: "" };
|
|
12030
|
+
} finally {
|
|
12031
|
+
const late = setTimeout(() => this.stop.abort(), CLOSE_WAIT_MS3);
|
|
12032
|
+
await this.writes;
|
|
12033
|
+
clearTimeout(late);
|
|
12034
|
+
this.socket.close();
|
|
12035
|
+
this.settle(close);
|
|
12036
|
+
}
|
|
12037
|
+
}
|
|
12038
|
+
sendClose(code, reason) {
|
|
12039
|
+
if (this.sentClose) return;
|
|
12040
|
+
this.sentClose = true;
|
|
12041
|
+
const late = setTimeout(() => this.stop.abort(), CLOSE_WAIT_MS3);
|
|
12042
|
+
void this.closed.then(() => clearTimeout(late));
|
|
12043
|
+
const bytes = new TextEncoder().encode(reason).subarray(0, 123);
|
|
12044
|
+
const payload = new Uint8Array(2 + bytes.length);
|
|
12045
|
+
new DataView(payload.buffer).setUint16(0, sendableCode(code) ? code : CLOSE.error);
|
|
12046
|
+
payload.set(bytes, 2);
|
|
12047
|
+
this.write(clientFrame(OP_CLOSE, payload));
|
|
12048
|
+
}
|
|
12049
|
+
send(data) {
|
|
12050
|
+
if (this.sentClose) throw errno("EPIPE", "the websocket is closing");
|
|
12051
|
+
const text = typeof data === "string";
|
|
12052
|
+
const payload = text ? new TextEncoder().encode(data) : data;
|
|
12053
|
+
this.write(clientFrame(text ? OP_TEXT : OP_BINARY, payload));
|
|
12054
|
+
}
|
|
12055
|
+
close(code = 1e3, reason = "") {
|
|
12056
|
+
this.sendClose(code, reason);
|
|
12057
|
+
}
|
|
12058
|
+
};
|
|
12059
|
+
|
|
11670
12060
|
// src/kernel/net/ws-syscalls.ts
|
|
11671
12061
|
var WS_OPS = [
|
|
11672
12062
|
"net-ws-open",
|
|
@@ -11676,7 +12066,7 @@ var WS_OPS = [
|
|
|
11676
12066
|
"net-ws-send",
|
|
11677
12067
|
"net-ws-close"
|
|
11678
12068
|
];
|
|
11679
|
-
var
|
|
12069
|
+
var TOKEN4 = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
|
|
11680
12070
|
function message(e) {
|
|
11681
12071
|
return e instanceof Error ? e.message : String(e);
|
|
11682
12072
|
}
|
|
@@ -11685,16 +12075,18 @@ function errnoOf(e) {
|
|
|
11685
12075
|
const code = e?.code;
|
|
11686
12076
|
return typeof code === "string" && ERRNO.test(code) ? code : "ECONNREFUSED";
|
|
11687
12077
|
}
|
|
11688
|
-
function fail(
|
|
11689
|
-
return { ok: false, errno, message: text };
|
|
12078
|
+
function fail(errno2, text) {
|
|
12079
|
+
return { ok: false, errno: errno2, message: text };
|
|
11690
12080
|
}
|
|
11691
12081
|
var WsHandles = class {
|
|
11692
12082
|
transport;
|
|
11693
12083
|
open = /* @__PURE__ */ new Map();
|
|
11694
12084
|
next;
|
|
11695
|
-
|
|
12085
|
+
local;
|
|
12086
|
+
constructor(transport, next2, local) {
|
|
11696
12087
|
this.transport = transport;
|
|
11697
12088
|
this.next = next2;
|
|
12089
|
+
this.local = local;
|
|
11698
12090
|
}
|
|
11699
12091
|
owns(handle) {
|
|
11700
12092
|
return this.open.has(handle);
|
|
@@ -11723,16 +12115,18 @@ var WsHandles = class {
|
|
|
11723
12115
|
return { ok: true, kind: "json", json: handle };
|
|
11724
12116
|
}
|
|
11725
12117
|
async connect(handle, req, entry) {
|
|
11726
|
-
const { transport } = this;
|
|
11727
|
-
|
|
12118
|
+
const { transport, local } = this;
|
|
12119
|
+
const port = local?.port(req.url);
|
|
12120
|
+
const open = { protocols: req.protocols, headers: req.headers, signal: entry.abort.signal };
|
|
12121
|
+
if (port === void 0 && (!transport.traits.websocket || !transport.websocket)) {
|
|
12122
|
+
return fail("ENOTSUP", NO_WEBSOCKET2);
|
|
12123
|
+
}
|
|
11728
12124
|
let socket;
|
|
11729
12125
|
try {
|
|
11730
|
-
socket = await transport.websocket({
|
|
12126
|
+
socket = port === void 0 ? await transport.websocket({
|
|
11731
12127
|
url: toHostLoopback(req.url),
|
|
11732
|
-
|
|
11733
|
-
|
|
11734
|
-
signal: entry.abort.signal
|
|
11735
|
-
});
|
|
12128
|
+
...open
|
|
12129
|
+
}) : await local.websocket({ url: req.url, ...open }, port);
|
|
11736
12130
|
} catch (e) {
|
|
11737
12131
|
return fail(errnoOf(e), message(e));
|
|
11738
12132
|
}
|
|
@@ -11740,7 +12134,7 @@ var WsHandles = class {
|
|
|
11740
12134
|
socket.close(1001, "the program went away");
|
|
11741
12135
|
return fail("EBADF", `no websocket ${handle}`);
|
|
11742
12136
|
}
|
|
11743
|
-
if (socket.protocol && !(req.protocols.includes(socket.protocol) &&
|
|
12137
|
+
if (socket.protocol && !(req.protocols.includes(socket.protocol) && TOKEN4.test(socket.protocol))) {
|
|
11744
12138
|
socket.close(1002, "subprotocol not offered");
|
|
11745
12139
|
return fail("EPROTO", "the far end chose a subprotocol the program did not offer");
|
|
11746
12140
|
}
|
|
@@ -11803,6 +12197,10 @@ var EMPTY = new Uint8Array(0);
|
|
|
11803
12197
|
function message2(e) {
|
|
11804
12198
|
return e instanceof Error ? e.message : String(e);
|
|
11805
12199
|
}
|
|
12200
|
+
function codeOf2(e) {
|
|
12201
|
+
const code = e?.code;
|
|
12202
|
+
return typeof code === "string" && /^E[A-Z]+$/.test(code) ? code : "EIO";
|
|
12203
|
+
}
|
|
11806
12204
|
async function* once(bytes) {
|
|
11807
12205
|
yield bytes;
|
|
11808
12206
|
}
|
|
@@ -11812,10 +12210,12 @@ var HttpHandles = class {
|
|
|
11812
12210
|
nextHandle = 0;
|
|
11813
12211
|
ws;
|
|
11814
12212
|
owner;
|
|
11815
|
-
|
|
12213
|
+
local;
|
|
12214
|
+
constructor(transport, owner, local) {
|
|
11816
12215
|
this.transport = transport;
|
|
11817
12216
|
this.owner = owner;
|
|
11818
|
-
this.
|
|
12217
|
+
this.local = local;
|
|
12218
|
+
this.ws = new WsHandles(transport, () => ++this.nextHandle, local);
|
|
11819
12219
|
}
|
|
11820
12220
|
syscall(req) {
|
|
11821
12221
|
if (req.op.startsWith("net-ws-")) return this.ws.syscall(req);
|
|
@@ -11823,10 +12223,13 @@ var HttpHandles = class {
|
|
|
11823
12223
|
if (req.op === "net-open") return Promise.resolve(this.opened(req));
|
|
11824
12224
|
if (req.op === "net-head") return this.head(req.handle);
|
|
11825
12225
|
if (req.op === "net-read") return this.read(req.handle, req.max);
|
|
11826
|
-
if (req.op === "net-traits") return Promise.resolve(this.traits());
|
|
12226
|
+
if (req.op === "net-traits") return Promise.resolve(this.traits(req.url));
|
|
11827
12227
|
return this.close(req.handle);
|
|
11828
12228
|
}
|
|
11829
|
-
traits() {
|
|
12229
|
+
traits(url) {
|
|
12230
|
+
if (url !== void 0 && this.local?.port(url) !== void 0) {
|
|
12231
|
+
return { ok: true, kind: "json", json: LOOPBACK_TRAITS };
|
|
12232
|
+
}
|
|
11830
12233
|
const { unavailable, crossOrigin = "any", ...rest2 } = this.transport.traits;
|
|
11831
12234
|
if (unavailable) return { ok: false, errno: "ENETUNREACH", message: NO_TRANSPORT };
|
|
11832
12235
|
return { ok: true, kind: "json", json: { ...rest2, crossOrigin } };
|
|
@@ -11857,28 +12260,30 @@ var HttpHandles = class {
|
|
|
11857
12260
|
return { handle, head: entry.head };
|
|
11858
12261
|
}
|
|
11859
12262
|
async respond(handle, req, entry) {
|
|
12263
|
+
const port = this.local?.port(req.url);
|
|
11860
12264
|
try {
|
|
11861
|
-
const
|
|
11862
|
-
|
|
11863
|
-
|
|
11864
|
-
|
|
11865
|
-
|
|
11866
|
-
|
|
11867
|
-
|
|
11868
|
-
|
|
11869
|
-
|
|
11870
|
-
);
|
|
12265
|
+
const target = port === void 0 ? toHostLoopback(req.url) : req.url;
|
|
12266
|
+
const request2 = {
|
|
12267
|
+
url: target,
|
|
12268
|
+
method: req.method,
|
|
12269
|
+
headers: req.headers,
|
|
12270
|
+
...req.body ? { body: req.body } : {},
|
|
12271
|
+
signal: entry.abort.signal
|
|
12272
|
+
};
|
|
12273
|
+
const response = port === void 0 ? await this.transport.fetch(request2, this.owner) : await this.local.fetch(request2, port);
|
|
11871
12274
|
entry.body = response.body[Symbol.asyncIterator]();
|
|
11872
12275
|
entry.cancel = () => response.cancel();
|
|
11873
12276
|
if (!this.open.has(handle)) await entry.cancel().catch(() => void 0);
|
|
11874
|
-
const
|
|
12277
|
+
const shown = response.url && response.url !== target ? response.url : req.url;
|
|
12278
|
+
const head = this.headOf(handle, shown, response);
|
|
11875
12279
|
return response.redirected ? { ...head, json: { ...head.json, redirected: true } } : head;
|
|
11876
12280
|
} catch (e) {
|
|
11877
12281
|
const text = message2(e);
|
|
12282
|
+
if (port !== void 0) return { ok: false, errno: codeOf2(e), message: text };
|
|
11878
12283
|
const status = e.status;
|
|
11879
12284
|
if (text === NO_TRANSPORT || typeof status !== "number" || status === 502) {
|
|
11880
|
-
const
|
|
11881
|
-
return { ok: false, errno, message: text };
|
|
12285
|
+
const errno2 = text === NO_TRANSPORT ? "ENETUNREACH" : "ECONNREFUSED";
|
|
12286
|
+
return { ok: false, errno: errno2, message: text };
|
|
11882
12287
|
}
|
|
11883
12288
|
entry.body = once(new TextEncoder().encode(text))[Symbol.asyncIterator]();
|
|
11884
12289
|
return this.headOf(handle, req.url, {
|
|
@@ -15614,7 +16019,7 @@ function scrubberOf(secrets) {
|
|
|
15614
16019
|
const usable = secrets.filter((s) => encoder5.encode(s.value).length >= MIN_VALUE);
|
|
15615
16020
|
return usable.length > 0 ? compile(usable, { idleMs: SCRUB_IDLE_MS }) : void 0;
|
|
15616
16021
|
}
|
|
15617
|
-
async function
|
|
16022
|
+
async function writeAll3(file, bytes) {
|
|
15618
16023
|
const write = file.write;
|
|
15619
16024
|
for (let at = 0; at < bytes.length; ) at += await write.call(file, bytes.subarray(at));
|
|
15620
16025
|
}
|
|
@@ -15648,7 +16053,7 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
|
|
|
15648
16053
|
const later = (bytes) => {
|
|
15649
16054
|
if (bytes.length === 0) return;
|
|
15650
16055
|
pending += 1;
|
|
15651
|
-
tail = tail.then(() =>
|
|
16056
|
+
tail = tail.then(() => writeAll3(file, bytes)).catch((err) => {
|
|
15652
16057
|
if (failed3 === void 0) failed3 = err;
|
|
15653
16058
|
}).finally(() => {
|
|
15654
16059
|
pending -= 1;
|
|
@@ -16279,8 +16684,8 @@ var FSA_CAPABILITIES = {
|
|
|
16279
16684
|
ranges: true,
|
|
16280
16685
|
sessions: true
|
|
16281
16686
|
};
|
|
16282
|
-
var
|
|
16283
|
-
var denied = (err) =>
|
|
16687
|
+
var codeOf3 = (err) => err?.code;
|
|
16688
|
+
var denied = (err) => codeOf3(err) === "EACCES" || err?.name === "NotAllowedError";
|
|
16284
16689
|
function attrOf(st) {
|
|
16285
16690
|
return {
|
|
16286
16691
|
kind: st.isDirectory ? "directory" : st.isSymbolicLink ? "symlink" : "file",
|
|
@@ -16302,7 +16707,7 @@ function kernelFsHandlers(fs) {
|
|
|
16302
16707
|
try {
|
|
16303
16708
|
return await fs.stat(path);
|
|
16304
16709
|
} catch (err) {
|
|
16305
|
-
if (
|
|
16710
|
+
if (codeOf3(err) === "ENOENT") return void 0;
|
|
16306
16711
|
throw err;
|
|
16307
16712
|
}
|
|
16308
16713
|
}
|
|
@@ -16495,7 +16900,7 @@ function parseFstab(text) {
|
|
|
16495
16900
|
});
|
|
16496
16901
|
return lines2;
|
|
16497
16902
|
}
|
|
16498
|
-
function
|
|
16903
|
+
function codeOf4(err) {
|
|
16499
16904
|
const code = err?.code;
|
|
16500
16905
|
return typeof code === "string" ? code : "EIO";
|
|
16501
16906
|
}
|
|
@@ -16533,18 +16938,18 @@ async function mountLine({ line, spec, invalid }, mount, signal, retries, discar
|
|
|
16533
16938
|
break;
|
|
16534
16939
|
} catch (err) {
|
|
16535
16940
|
failed3 = err;
|
|
16536
|
-
if (FINAL.has(
|
|
16941
|
+
if (FINAL.has(codeOf4(err)) || attempt === retries.length) break;
|
|
16537
16942
|
await wait(retries[attempt], signal);
|
|
16538
16943
|
}
|
|
16539
16944
|
}
|
|
16540
|
-
const code =
|
|
16945
|
+
const code = codeOf4(failed3);
|
|
16541
16946
|
return { line, target: spec.target, code, error: String(failed3?.message ?? code) };
|
|
16542
16947
|
}
|
|
16543
16948
|
|
|
16544
16949
|
// src/mount/hostfs.ts
|
|
16545
16950
|
var HOSTFS_IO = 16 * 1024 * 1024;
|
|
16546
|
-
var
|
|
16547
|
-
var unreachable = (err) =>
|
|
16951
|
+
var codeOf5 = (err) => err?.code;
|
|
16952
|
+
var unreachable = (err) => codeOf5(err) === "ENOTCONN";
|
|
16548
16953
|
function rel(path) {
|
|
16549
16954
|
return path.replace(/^\/+/, "");
|
|
16550
16955
|
}
|
|
@@ -16604,9 +17009,9 @@ var HostfsClient = class {
|
|
|
16604
17009
|
throw fsError2("ESTALE", "the folder was granted again, so its open files are gone");
|
|
16605
17010
|
return this.send(path, init, false, true);
|
|
16606
17011
|
}
|
|
16607
|
-
const
|
|
17012
|
+
const errno2 = response.headers.get("X-Hostfs-Errno") ?? "EIO";
|
|
16608
17013
|
const body = await response.json().catch(() => ({}));
|
|
16609
|
-
throw fsError2(
|
|
17014
|
+
throw fsError2(errno2, typeof body.message === "string" ? body.message : errno2);
|
|
16610
17015
|
}
|
|
16611
17016
|
async call(op, body = {}, handle = false) {
|
|
16612
17017
|
const response = await this.send(
|
|
@@ -16721,7 +17126,7 @@ function hostfsHandlers(current, againMs = RESTORE_AGAIN_MS) {
|
|
|
16721
17126
|
try {
|
|
16722
17127
|
return { opened: await opening2(), restore: void 0 };
|
|
16723
17128
|
} catch (err) {
|
|
16724
|
-
if (!flags2.write ||
|
|
17129
|
+
if (!flags2.write || codeOf5(err) !== "EACCES") throw err;
|
|
16725
17130
|
const was = await client.call("stat", { path: rel(path) });
|
|
16726
17131
|
const mode = was.mode ?? 0;
|
|
16727
17132
|
if (mode & 128) throw err;
|
|
@@ -17634,8 +18039,8 @@ var RULE = new RegExp(
|
|
|
17634
18039
|
var TERM = /^[A-Za-z0-9._+-]+$/;
|
|
17635
18040
|
var PLAIN = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
17636
18041
|
var USAGE = "usage: sudo [-n] [-u user] [--] command [args...]\n sudo -l";
|
|
17637
|
-
function failed2(
|
|
17638
|
-
return { error, errno };
|
|
18042
|
+
function failed2(errno2, error) {
|
|
18043
|
+
return { error, errno: errno2 };
|
|
17639
18044
|
}
|
|
17640
18045
|
function unescaped(double) {
|
|
17641
18046
|
return double.replace(/\\(["\\$`])/g, "$1");
|
|
@@ -18929,6 +19334,12 @@ var Launcher = class {
|
|
|
18929
19334
|
groupSession(pgid) {
|
|
18930
19335
|
return this.jobs.sessionOf(pgid);
|
|
18931
19336
|
}
|
|
19337
|
+
loopbackFor(pid) {
|
|
19338
|
+
return new KernelLoopback(this.net, () => {
|
|
19339
|
+
const cred = this.credOf(pid);
|
|
19340
|
+
return { pid, uid: cred.euid, gid: cred.egid };
|
|
19341
|
+
});
|
|
19342
|
+
}
|
|
18932
19343
|
treeScrubs(req) {
|
|
18933
19344
|
const inherited2 = req.ppid !== void 0 ? this.scrubs.get(req.ppid) : void 0;
|
|
18934
19345
|
return req.scrub ? [...inherited2 ?? [], req.scrub] : inherited2;
|
|
@@ -19006,7 +19417,7 @@ var Launcher = class {
|
|
|
19006
19417
|
jobs: this.jobs,
|
|
19007
19418
|
ptys: this.ptys,
|
|
19008
19419
|
net: this.net,
|
|
19009
|
-
http: new HttpHandles(this.transport, pid),
|
|
19420
|
+
http: new HttpHandles(this.transport, pid, this.loopbackFor(pid)),
|
|
19010
19421
|
locks: this.locks,
|
|
19011
19422
|
resolver: this.resolver,
|
|
19012
19423
|
onReap: (child) => this.reaped(child, pid),
|