castrum 0.9.7 → 0.9.9
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/Cargo.lock +1 -1
- package/Cargo.toml +1 -1
- package/castrum.darwin-arm64.node +0 -0
- package/castrum.darwin-x64.node +0 -0
- package/castrum.linux-arm64-gnu.node +0 -0
- package/castrum.linux-arm64-musl.node +0 -0
- package/castrum.linux-x64-gnu.node +0 -0
- package/castrum.linux-x64-musl.node +0 -0
- package/castrum.linux-x64-v3-gnu.node +0 -0
- package/castrum.win32-x64-msvc.node +0 -0
- package/dist/index.d.ts +664 -8
- package/dist/index.js +2014 -1327
- package/docs/BENCHMARKS.md +13 -0
- package/docs/CASE_STUDY.md +1 -1
- package/docs/ENVIRONMENT.md +8 -1
- package/docs/FFI_BUN_GUIDE.md +1 -1
- package/docs/INGRESS.md +4 -4
- package/docs/REPO_MAP.md +7 -5
- package/docs/RND-CONCURRENCY.md +20 -4
- package/docs/superpowers/plans/2026-09-18-castrum-hardening-cleanup.md +617 -0
- package/docs/superpowers/plans/2026-09-18-elysia-learnings-adoption.md +634 -0
- package/index.ts +6 -0
- package/package.json +4 -2
- package/rust/crypto/aead.rs +44 -0
- package/rust/crypto/argon2.rs +32 -2
- package/rust/crypto/jwt/tests.rs +19 -0
- package/rust/crypto/jwt/token.rs +43 -28
- package/rust/crypto/session.rs +6 -0
- package/rust/ffi/crypto.rs +63 -32
- package/rust/ffi/hashing.rs +48 -33
- package/rust/ffi/http.rs +62 -36
- package/rust/ffi/metrics.rs +6 -2
- package/rust/ffi/payload.rs +47 -27
- package/rust/ffi/task.rs +55 -35
- package/rust/ffi/tests.rs +24 -0
- package/rust/ffi/util.rs +40 -0
- package/rust/http/headers.rs +13 -0
- package/rust/http/multipart.rs +139 -0
- package/rust/ingress/api.rs +21 -5
- package/rust/ingress/mod.rs +7 -0
- package/rust/ingress/native_route.rs +25 -5
- package/rust/ingress/schema_cache.rs +266 -0
- package/rust/task/completion.rs +7 -0
- package/rust/task/mod.rs +2 -1
- package/rust/task/runtime.rs +55 -7
- package/rust/task/tests.rs +128 -1
- package/src/ingress/abort.ts +48 -0
- package/src/ingress/body.ts +104 -8
- package/src/ingress/decode/baked-result.ts +13 -5
- package/src/ingress/decode/fast-result.ts +1 -1
- package/src/ingress/decode/result-base.ts +16 -2
- package/src/ingress/handlers.ts +104 -31
- package/src/ingress/headers/memoized-headers.ts +40 -0
- package/src/ingress/health.ts +22 -0
- package/src/ingress/index.ts +3 -1
- package/src/ingress/native-route.ts +25 -6
- package/src/ingress/options.ts +26 -2
- package/src/ingress/packing/gather-raw-headers.ts +24 -8
- package/src/ingress/response/baked-response.ts +118 -28
- package/src/ingress/router.ts +50 -3
- package/src/ingress/routes/common.ts +35 -11
- package/src/ingress/routes/echo.ts +60 -7
- package/src/ingress/routes/json-write.ts +32 -8
- package/src/ingress/routes/native.ts +24 -5
- package/src/ingress/routes/options.ts +6 -2
- package/src/ingress/routes/responder.ts +29 -9
- package/src/ingress/routes/safe-record.ts +57 -0
- package/src/ingress/server-error.ts +111 -0
- package/src/ingress/server-node.ts +135 -37
- package/src/ingress/server.ts +143 -36
- package/src/ingress/shared.ts +1 -1
- package/src/ingress/types.ts +15 -0
- package/src/integration/pipeline.ts +6 -0
- package/src/loader/ops.ts +1 -1
- package/src/native/ffi/build/codecs-selftest.ts +305 -0
- package/src/native/ffi/build/codecs.ts +0 -296
- package/src/native/ffi/build/instances-selftest.ts +264 -0
- package/src/native/ffi/build/instances.ts +10 -259
- package/src/native/ffi/build/parse-selftest.ts +238 -0
- package/src/native/ffi/build/parse.ts +11 -234
- package/src/native/ffi/build/task.ts +2 -1
- package/src/native/ffi/build.ts +5 -1
- package/src/native/ffi/selftest.ts +3 -3
- package/src/native/ffi/symbols.ts +460 -0
- package/src/native/ffi/types.ts +6 -1
- package/src/native/ffi.ts +2 -434
- package/src/native/ingress-binding.ts +39 -0
- package/src/native/types.ts +6 -0
- package/src/runtime/codec.ts +24 -0
- package/src/runtime/detect.ts +14 -0
- package/src/runtime/types.ts +11 -0
- package/src/rust-ffi/batch/build.ts +18 -8
- package/src/rust-ffi/batch/types.ts +15 -0
- package/src/rust-ffi/context.ts +46 -3
- package/src/rust-ffi/options.ts +19 -0
- package/src/rust-ffi/scalar/crypto.ts +8 -0
- package/src/rust-ffi/scalar/factories.ts +53 -20
- package/src/rust-ffi/scalar/http.ts +60 -10
- package/src/rust-ffi/scalar/interface.ts +18 -1
- package/src/rust-ffi/scalar/payload.ts +27 -1
- package/src/rust-ffi/text.ts +5 -4
- package/src/shared/buffer-pool.ts +54 -9
- package/src/shared/codec.ts +26 -0
- package/src/shared/memory.ts +68 -0
- package/src/shared/metrics.ts +86 -3
- package/src/shared/packed/parsers.ts +64 -7
- package/src/shared/runtime.ts +7 -0
- package/src/task/runtime.ts +81 -37
package/dist/index.js
CHANGED
|
@@ -36,6 +36,13 @@ function detectRuntimeName() {
|
|
|
36
36
|
function isBunRuntime() {
|
|
37
37
|
return detectedRuntime === "bun";
|
|
38
38
|
}
|
|
39
|
+
function forceGc() {
|
|
40
|
+
if (detectedRuntime === "bun") {
|
|
41
|
+
Bun.gc(true);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
globalThis.gc?.();
|
|
45
|
+
}
|
|
39
46
|
var detectedRuntime;
|
|
40
47
|
var init_detect = __esm(() => {
|
|
41
48
|
detectedRuntime = detectRuntimeName();
|
|
@@ -87,7 +94,8 @@ function createBunCodec() {
|
|
|
87
94
|
},
|
|
88
95
|
decodeUtf8: decodeUtf8Bun,
|
|
89
96
|
decodeUtf8Fatal: decodeUtf8Bun,
|
|
90
|
-
decodeUtf8Range: decodeUtf8RangeBun
|
|
97
|
+
decodeUtf8Range: decodeUtf8RangeBun,
|
|
98
|
+
decodeUtf8RangeView: decodeUtf8RangeViewBun
|
|
91
99
|
};
|
|
92
100
|
}
|
|
93
101
|
function bunEncodeUtf8Into(s, dest, offset = 0) {
|
|
@@ -122,6 +130,14 @@ function decodeUtf8RangeBun(bytes, start, end) {
|
|
|
122
130
|
}
|
|
123
131
|
return view.toString("latin1", base + start, base + end);
|
|
124
132
|
}
|
|
133
|
+
function decodeUtf8RangeViewBun(view, start, end) {
|
|
134
|
+
for (let i = start;i < end; i++) {
|
|
135
|
+
if ((view[i] ?? 0) >= 128) {
|
|
136
|
+
return view.toString("utf8", start, end);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return view.toString("latin1", start, end);
|
|
140
|
+
}
|
|
125
141
|
function createNodeCodec() {
|
|
126
142
|
return {
|
|
127
143
|
encodeUtf8(s) {
|
|
@@ -144,6 +160,14 @@ function createNodeCodec() {
|
|
|
144
160
|
}
|
|
145
161
|
}
|
|
146
162
|
return view.toString("latin1", start, end);
|
|
163
|
+
},
|
|
164
|
+
decodeUtf8RangeView(view, start, end) {
|
|
165
|
+
for (let i = start;i < end; i++) {
|
|
166
|
+
if ((view[i] ?? 0) >= 128) {
|
|
167
|
+
return view.toString("utf8", start, end);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return view.toString("latin1", start, end);
|
|
147
171
|
}
|
|
148
172
|
};
|
|
149
173
|
}
|
|
@@ -264,37 +288,382 @@ var init_builtins = __esm(() => {
|
|
|
264
288
|
runtimeBuiltins = createBuiltins(detectedRuntime);
|
|
265
289
|
});
|
|
266
290
|
|
|
291
|
+
// src/native/ffi/symbols.ts
|
|
292
|
+
function buildFFISymbolMap(useBufferLength) {
|
|
293
|
+
const inputAbi = useBufferLength ? ["buffer", "buffer_length"] : ["ptr", "usize"];
|
|
294
|
+
const abi = (shape) => {
|
|
295
|
+
if (!useBufferLength)
|
|
296
|
+
return shape;
|
|
297
|
+
const out = [];
|
|
298
|
+
for (let i = 0;i < shape.length; i++) {
|
|
299
|
+
const t = shape[i];
|
|
300
|
+
if (t === "ptr") {
|
|
301
|
+
out.push("buffer");
|
|
302
|
+
out.push("buffer_length");
|
|
303
|
+
i++;
|
|
304
|
+
} else {
|
|
305
|
+
out.push(t);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return out;
|
|
309
|
+
};
|
|
310
|
+
const U64_FAST = "u64_fast";
|
|
311
|
+
return {
|
|
312
|
+
castrum_crc32: { args: inputAbi, returns: "u32" },
|
|
313
|
+
castrum_fnv1a64: { args: inputAbi, returns: "u64" },
|
|
314
|
+
castrum_xxh3: { args: inputAbi, returns: "u64" },
|
|
315
|
+
castrum_json_valid: { args: inputAbi, returns: "u8" },
|
|
316
|
+
castrum_utf8_valid: { args: inputAbi, returns: "u8" },
|
|
317
|
+
castrum_hex_encode: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: U64_FAST },
|
|
318
|
+
castrum_hex_decode: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: U64_FAST },
|
|
319
|
+
castrum_url_encode: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: U64_FAST },
|
|
320
|
+
castrum_url_decode: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: U64_FAST },
|
|
321
|
+
castrum_validate_email: { args: ["cstring"], returns: "u8" },
|
|
322
|
+
castrum_validate_uuid: { args: ["cstring"], returns: "u8" },
|
|
323
|
+
castrum_validate_ipv4: { args: ["cstring"], returns: "u8" },
|
|
324
|
+
castrum_validate_ipv6: { args: ["cstring"], returns: "u8" },
|
|
325
|
+
castrum_validate_email_bytes: { args: inputAbi, returns: "u8" },
|
|
326
|
+
castrum_validate_uuid_bytes: { args: inputAbi, returns: "u8" },
|
|
327
|
+
castrum_validate_ipv4_bytes: { args: inputAbi, returns: "u8" },
|
|
328
|
+
castrum_validate_ipv6_bytes: { args: inputAbi, returns: "u8" },
|
|
329
|
+
castrum_json_sum_ids: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: U64_FAST },
|
|
330
|
+
castrum_hmac_sha256_verify: {
|
|
331
|
+
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
332
|
+
returns: "u8"
|
|
333
|
+
},
|
|
334
|
+
castrum_csrf_verify: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: "u8" },
|
|
335
|
+
castrum_password_verify: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: "u8" },
|
|
336
|
+
castrum_password_verify_bcrypt: {
|
|
337
|
+
args: abi(["ptr", "usize", "cstring"]),
|
|
338
|
+
returns: "u8"
|
|
339
|
+
},
|
|
340
|
+
castrum_ws_accept_key: { args: ["cstring"], returns: "cstring" },
|
|
341
|
+
castrum_ws_accept_key_into: {
|
|
342
|
+
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
343
|
+
returns: U64_FAST
|
|
344
|
+
},
|
|
345
|
+
castrum_etag: { args: abi(["ptr", "usize", "u8"]), returns: "cstring" },
|
|
346
|
+
castrum_etag_into: { args: abi(["ptr", "usize", "u8", "ptr", "usize"]), returns: U64_FAST },
|
|
347
|
+
castrum_conditional_is_not_modified: {
|
|
348
|
+
args: abi(["usize", "ptr", "usize", "ptr", "usize", "u8"]),
|
|
349
|
+
returns: "u8"
|
|
350
|
+
},
|
|
351
|
+
castrum_media_type_matcher_matches: {
|
|
352
|
+
args: abi(["usize", "ptr", "usize"]),
|
|
353
|
+
returns: "u8"
|
|
354
|
+
},
|
|
355
|
+
castrum_accept_negotiator_negotiate: {
|
|
356
|
+
args: abi(["usize", "ptr", "usize"]),
|
|
357
|
+
returns: "cstring"
|
|
358
|
+
},
|
|
359
|
+
castrum_accept_negotiator_negotiate_server: {
|
|
360
|
+
args: ["usize", "cstring"],
|
|
361
|
+
returns: "cstring"
|
|
362
|
+
},
|
|
363
|
+
castrum_jwt_signer_sign: {
|
|
364
|
+
args: abi(["usize", "ptr", "usize", "i64", "ptr", "usize"]),
|
|
365
|
+
returns: U64_FAST
|
|
366
|
+
},
|
|
367
|
+
castrum_jwt_signer_verify: {
|
|
368
|
+
args: abi(["usize", "ptr", "usize", "i64", "ptr", "usize"]),
|
|
369
|
+
returns: U64_FAST
|
|
370
|
+
},
|
|
371
|
+
castrum_template_render: {
|
|
372
|
+
args: abi(["usize", "ptr", "usize", "ptr", "usize"]),
|
|
373
|
+
returns: U64_FAST
|
|
374
|
+
},
|
|
375
|
+
castrum_schema_validator_validate: {
|
|
376
|
+
args: abi(["usize", "ptr", "usize"]),
|
|
377
|
+
returns: "u8"
|
|
378
|
+
},
|
|
379
|
+
castrum_rate_limiter_check: {
|
|
380
|
+
args: abi(["usize", "cstring", "i64", "ptr", "usize"]),
|
|
381
|
+
returns: U64_FAST
|
|
382
|
+
},
|
|
383
|
+
castrum_rate_limiter_check_key: {
|
|
384
|
+
args: abi(["usize", "i64", "i64", "ptr", "usize"]),
|
|
385
|
+
returns: U64_FAST
|
|
386
|
+
},
|
|
387
|
+
castrum_random_token: { args: ["u32"], returns: "cstring" },
|
|
388
|
+
castrum_random_token_into: { args: ["u32", ...abi(["ptr", "usize"])], returns: U64_FAST },
|
|
389
|
+
castrum_base64_encode: {
|
|
390
|
+
args: abi(["ptr", "usize", "ptr", "usize", "u8", "u8"]),
|
|
391
|
+
returns: U64_FAST
|
|
392
|
+
},
|
|
393
|
+
castrum_base64_decode: {
|
|
394
|
+
args: abi(["ptr", "usize", "ptr", "usize", "u8", "u8"]),
|
|
395
|
+
returns: U64_FAST
|
|
396
|
+
},
|
|
397
|
+
castrum_hmac_sha256: {
|
|
398
|
+
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
399
|
+
returns: U64_FAST
|
|
400
|
+
},
|
|
401
|
+
castrum_sign_cookie: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: "cstring" },
|
|
402
|
+
castrum_sign_cookie_into: {
|
|
403
|
+
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
404
|
+
returns: U64_FAST
|
|
405
|
+
},
|
|
406
|
+
castrum_verify_cookie: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: "cstring" },
|
|
407
|
+
castrum_verify_cookie_into: {
|
|
408
|
+
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
409
|
+
returns: U64_FAST
|
|
410
|
+
},
|
|
411
|
+
castrum_csrf_token: { args: abi(["ptr", "usize"]), returns: "cstring" },
|
|
412
|
+
castrum_csrf_token_into: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: U64_FAST },
|
|
413
|
+
castrum_password_hash: {
|
|
414
|
+
args: abi(["ptr", "usize", "ptr", "usize", "u32", "u32", "u32", "u32", "ptr", "usize"]),
|
|
415
|
+
returns: U64_FAST
|
|
416
|
+
},
|
|
417
|
+
castrum_password_hash_bcrypt: {
|
|
418
|
+
args: abi(["ptr", "usize", "u32", "ptr", "usize"]),
|
|
419
|
+
returns: U64_FAST
|
|
420
|
+
},
|
|
421
|
+
castrum_pbkdf2_sha256: {
|
|
422
|
+
args: abi(["ptr", "usize", "ptr", "usize", "u32", "u32", "ptr", "usize"]),
|
|
423
|
+
returns: U64_FAST
|
|
424
|
+
},
|
|
425
|
+
castrum_aead_encrypt: {
|
|
426
|
+
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize", "u8", "ptr", "usize"]),
|
|
427
|
+
returns: U64_FAST
|
|
428
|
+
},
|
|
429
|
+
castrum_aead_decrypt: {
|
|
430
|
+
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize", "u8", "ptr", "usize"]),
|
|
431
|
+
returns: U64_FAST
|
|
432
|
+
},
|
|
433
|
+
castrum_ws_frame_encode: {
|
|
434
|
+
args: abi(["u8", "ptr", "usize", "u8", "u8", "ptr", "usize"]),
|
|
435
|
+
returns: U64_FAST
|
|
436
|
+
},
|
|
437
|
+
castrum_json_patch: {
|
|
438
|
+
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
439
|
+
returns: U64_FAST
|
|
440
|
+
},
|
|
441
|
+
castrum_gzip_compress: {
|
|
442
|
+
args: abi(["ptr", "usize", "u32", "ptr", "usize"]),
|
|
443
|
+
returns: U64_FAST
|
|
444
|
+
},
|
|
445
|
+
castrum_gzip_decompress: {
|
|
446
|
+
args: abi(["ptr", "usize", "usize", "ptr", "usize"]),
|
|
447
|
+
returns: U64_FAST
|
|
448
|
+
},
|
|
449
|
+
castrum_brotli_compress: {
|
|
450
|
+
args: abi(["ptr", "usize", "u32", "ptr", "usize"]),
|
|
451
|
+
returns: U64_FAST
|
|
452
|
+
},
|
|
453
|
+
castrum_brotli_decompress: {
|
|
454
|
+
args: abi(["ptr", "usize", "usize", "ptr", "usize"]),
|
|
455
|
+
returns: U64_FAST
|
|
456
|
+
},
|
|
457
|
+
castrum_gzip_isize: { args: abi(["ptr", "usize"]), returns: "u32" },
|
|
458
|
+
castrum_http_parse_request_packed: {
|
|
459
|
+
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
460
|
+
returns: U64_FAST
|
|
461
|
+
},
|
|
462
|
+
castrum_query_parse_packed: {
|
|
463
|
+
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
464
|
+
returns: U64_FAST
|
|
465
|
+
},
|
|
466
|
+
castrum_cookie_parse_packed: {
|
|
467
|
+
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
468
|
+
returns: U64_FAST
|
|
469
|
+
},
|
|
470
|
+
castrum_http_date_into: { args: ["f64", ...abi(["ptr", "usize"])], returns: U64_FAST },
|
|
471
|
+
castrum_sse_encode_into: {
|
|
472
|
+
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize", "u8", "u32", "ptr", "usize"]),
|
|
473
|
+
returns: U64_FAST
|
|
474
|
+
},
|
|
475
|
+
castrum_jwt_sign_bytes: {
|
|
476
|
+
args: abi(["ptr", "usize", "ptr", "usize", "i64", "i64"]),
|
|
477
|
+
returns: "cstring"
|
|
478
|
+
},
|
|
479
|
+
castrum_jwt_sign_bytes_into: {
|
|
480
|
+
args: abi(["ptr", "usize", "ptr", "usize", "i64", "i64", "ptr", "usize"]),
|
|
481
|
+
returns: U64_FAST
|
|
482
|
+
},
|
|
483
|
+
castrum_ed25519_generate_keypair: {
|
|
484
|
+
args: abi(["ptr", "usize"]),
|
|
485
|
+
returns: U64_FAST
|
|
486
|
+
},
|
|
487
|
+
castrum_ed25519_sign: {
|
|
488
|
+
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
489
|
+
returns: U64_FAST
|
|
490
|
+
},
|
|
491
|
+
castrum_ed25519_verify: {
|
|
492
|
+
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
493
|
+
returns: "u32"
|
|
494
|
+
},
|
|
495
|
+
castrum_jwt_eddsa_sign: {
|
|
496
|
+
args: abi(["ptr", "usize", "ptr", "usize", "i64", "i64"]),
|
|
497
|
+
returns: "cstring"
|
|
498
|
+
},
|
|
499
|
+
castrum_jwt_eddsa_verify: {
|
|
500
|
+
args: abi(["ptr", "usize", "ptr", "usize", "i64"]),
|
|
501
|
+
returns: "cstring"
|
|
502
|
+
},
|
|
503
|
+
castrum_ws_frame_decode_packed: {
|
|
504
|
+
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
505
|
+
returns: U64_FAST
|
|
506
|
+
},
|
|
507
|
+
castrum_multipart_parse_packed: {
|
|
508
|
+
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
509
|
+
returns: U64_FAST
|
|
510
|
+
},
|
|
511
|
+
castrum_form_parse_packed: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: U64_FAST },
|
|
512
|
+
castrum_json_parse_packed: {
|
|
513
|
+
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
514
|
+
returns: U64_FAST
|
|
515
|
+
},
|
|
516
|
+
castrum_parse_media_type: {
|
|
517
|
+
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
518
|
+
returns: U64_FAST
|
|
519
|
+
},
|
|
520
|
+
castrum_parse_http_date: {
|
|
521
|
+
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
522
|
+
returns: U64_FAST
|
|
523
|
+
},
|
|
524
|
+
castrum_parse_accept_encoding: {
|
|
525
|
+
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
526
|
+
returns: U64_FAST
|
|
527
|
+
},
|
|
528
|
+
castrum_url_encode_query: { args: abi(["ptr", "usize"]), returns: "cstring" },
|
|
529
|
+
castrum_url_resolve: {
|
|
530
|
+
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
531
|
+
returns: "cstring"
|
|
532
|
+
},
|
|
533
|
+
castrum_url_builder_resolve: {
|
|
534
|
+
args: abi(["usize", "ptr", "usize", "ptr", "usize"]),
|
|
535
|
+
returns: U64_FAST
|
|
536
|
+
},
|
|
537
|
+
castrum_mime_from_extension: { args: ["cstring"], returns: "cstring" },
|
|
538
|
+
castrum_jwt_verify: {
|
|
539
|
+
args: abi(["ptr", "usize", "ptr", "usize", "i64"]),
|
|
540
|
+
returns: "cstring"
|
|
541
|
+
},
|
|
542
|
+
castrum_ingress_handle_packed: {
|
|
543
|
+
args: abi(["usize", "ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
544
|
+
returns: U64_FAST
|
|
545
|
+
},
|
|
546
|
+
castrum_ingress_handle_components: {
|
|
547
|
+
args: abi([
|
|
548
|
+
"usize",
|
|
549
|
+
"u8",
|
|
550
|
+
"cstring",
|
|
551
|
+
"cstring",
|
|
552
|
+
"ptr",
|
|
553
|
+
"usize",
|
|
554
|
+
"ptr",
|
|
555
|
+
"usize",
|
|
556
|
+
"ptr",
|
|
557
|
+
"usize",
|
|
558
|
+
"ptr",
|
|
559
|
+
"usize"
|
|
560
|
+
]),
|
|
561
|
+
returns: U64_FAST
|
|
562
|
+
},
|
|
563
|
+
castrum_ingress_layout: { args: abi(["ptr", "usize"]), returns: U64_FAST },
|
|
564
|
+
castrum_route_compile: { args: abi(["ptr", "usize"]), returns: U64_FAST },
|
|
565
|
+
castrum_route_run: {
|
|
566
|
+
args: abi(["usize", "ptr", "usize", "ptr", "usize"]),
|
|
567
|
+
returns: U64_FAST
|
|
568
|
+
},
|
|
569
|
+
castrum_route_destroy: { args: ["usize"], returns: "void" },
|
|
570
|
+
castrum_hex_validate_batch: {
|
|
571
|
+
args: abi(["ptr", "usize", "u32", "ptr", "usize"]),
|
|
572
|
+
returns: U64_FAST
|
|
573
|
+
},
|
|
574
|
+
castrum_regex_escape: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: U64_FAST },
|
|
575
|
+
castrum_metrics_create: { args: [], returns: U64_FAST },
|
|
576
|
+
castrum_metrics_counter: { args: ["usize", "cstring", "cstring"], returns: "u32" },
|
|
577
|
+
castrum_metrics_gauge: { args: ["usize", "cstring", "cstring"], returns: "u32" },
|
|
578
|
+
castrum_metrics_histogram: {
|
|
579
|
+
args: ["usize", "cstring", "cstring", "cstring"],
|
|
580
|
+
returns: "u32"
|
|
581
|
+
},
|
|
582
|
+
castrum_metrics_record: {
|
|
583
|
+
args: abi(["usize", "u32", "ptr", "usize", "f64"]),
|
|
584
|
+
returns: "u8"
|
|
585
|
+
},
|
|
586
|
+
castrum_metrics_gauge_set: {
|
|
587
|
+
args: abi(["usize", "u32", "ptr", "usize", "f64"]),
|
|
588
|
+
returns: "u8"
|
|
589
|
+
},
|
|
590
|
+
castrum_metrics_record_str: {
|
|
591
|
+
args: ["usize", "u32", "cstring", "f64"],
|
|
592
|
+
returns: "u8"
|
|
593
|
+
},
|
|
594
|
+
castrum_metrics_gauge_set_str: {
|
|
595
|
+
args: ["usize", "u32", "cstring", "f64"],
|
|
596
|
+
returns: "u8"
|
|
597
|
+
},
|
|
598
|
+
castrum_regex_escape_str: { args: ["cstring"], returns: "cstring" },
|
|
599
|
+
castrum_hex_validate_batch_str: {
|
|
600
|
+
args: abi(["cstring", "u32", "ptr", "usize"]),
|
|
601
|
+
returns: U64_FAST
|
|
602
|
+
},
|
|
603
|
+
castrum_metrics_render: { args: abi(["usize", "ptr", "usize"]), returns: U64_FAST },
|
|
604
|
+
castrum_metrics_snapshot: { args: abi(["usize", "ptr", "usize"]), returns: U64_FAST },
|
|
605
|
+
castrum_metrics_record_batch: {
|
|
606
|
+
args: abi(["usize", "ptr", "usize"]),
|
|
607
|
+
returns: "u8"
|
|
608
|
+
},
|
|
609
|
+
castrum_query_validate: { args: ["usize", "cstring"], returns: "u8" },
|
|
610
|
+
castrum_cookie_validate: { args: ["usize", "cstring"], returns: "u8" },
|
|
611
|
+
castrum_session_seal: {
|
|
612
|
+
args: ["cstring", "cstring", "i64", "cstring"],
|
|
613
|
+
returns: "cstring"
|
|
614
|
+
},
|
|
615
|
+
castrum_session_open: {
|
|
616
|
+
args: abi(["cstring", "cstring", "ptr", "usize"]),
|
|
617
|
+
returns: U64_FAST
|
|
618
|
+
},
|
|
619
|
+
castrum_session_seal_bytes: {
|
|
620
|
+
args: abi(["ptr", "usize", "ptr", "usize", "i64", "ptr", "usize"]),
|
|
621
|
+
returns: "cstring"
|
|
622
|
+
},
|
|
623
|
+
castrum_session_open_bytes: {
|
|
624
|
+
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
625
|
+
returns: U64_FAST
|
|
626
|
+
},
|
|
627
|
+
castrum_task_init: { args: ["u32"], returns: "u32" },
|
|
628
|
+
castrum_task_submit: { args: abi(["u32", "ptr", "usize", "usize"]), returns: "u32" },
|
|
629
|
+
castrum_task_submit_slice: {
|
|
630
|
+
args: abi(["u32", "ptr", "usize", "ptr", "usize", "usize"]),
|
|
631
|
+
returns: "u32"
|
|
632
|
+
},
|
|
633
|
+
castrum_task_submit_out: {
|
|
634
|
+
args: abi(["u32", "ptr", "usize", "usize", "ptr", "usize"]),
|
|
635
|
+
returns: "u32"
|
|
636
|
+
},
|
|
637
|
+
castrum_task_drain: { args: abi(["ptr", "usize"]), returns: U64_FAST },
|
|
638
|
+
castrum_task_pending: { args: [], returns: "u32" },
|
|
639
|
+
castrum_task_cancel: { args: ["usize"], returns: "u32" },
|
|
640
|
+
castrum_task_set_doorbell: { args: ["ptr"], returns: "u32" },
|
|
641
|
+
castrum_task_shutdown: { args: [], returns: "u32" },
|
|
642
|
+
castrum_task_threads: { args: [], returns: "u32" },
|
|
643
|
+
castrum_metrics_destroy: { args: ["usize"], returns: "void" }
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
|
|
267
647
|
// src/shared/runtime.ts
|
|
268
|
-
var isBun;
|
|
648
|
+
var isBun, forceGc2;
|
|
269
649
|
var init_runtime = __esm(() => {
|
|
270
650
|
init_detect();
|
|
271
651
|
isBun = isBunRuntime;
|
|
652
|
+
forceGc2 = forceGc;
|
|
272
653
|
});
|
|
273
654
|
|
|
274
655
|
// src/shared/codec.ts
|
|
275
|
-
var encodeUtf8, encodeUtf8Into, decodeUtf8, decodeUtf8Range, decodeUtf8Fatal;
|
|
656
|
+
var encodeUtf8, encodeUtf8Into, decodeUtf8, decodeUtf8Range, decodeUtf8RangeView, decodeUtf8Fatal;
|
|
276
657
|
var init_codec2 = __esm(() => {
|
|
277
658
|
init_codec();
|
|
278
659
|
encodeUtf8 = runtimeCodec.encodeUtf8;
|
|
279
660
|
encodeUtf8Into = runtimeCodec.encodeUtf8Into;
|
|
280
661
|
decodeUtf8 = runtimeCodec.decodeUtf8;
|
|
281
662
|
decodeUtf8Range = runtimeCodec.decodeUtf8Range;
|
|
663
|
+
decodeUtf8RangeView = runtimeCodec.decodeUtf8RangeView ? runtimeCodec.decodeUtf8RangeView : (view, start, end) => decodeUtf8Range(view, start, end);
|
|
282
664
|
decodeUtf8Fatal = runtimeCodec.decodeUtf8Fatal;
|
|
283
665
|
});
|
|
284
666
|
|
|
285
|
-
// src/native/ffi/constants.ts
|
|
286
|
-
var MAX_DECOMPRESSED, MAX_JSON_PATCH_OUTPUT, COMPRESS_INITIAL_CAP, COMPRESS_MAX_CAP, COMPRESS_HEADROOM = 64, DECOMPRESS_GUESS_MULTIPLIER_GZIP = 16, DECOMPRESS_GUESS_MULTIPLIER_BROTLI = 32, DECOMPRESS_FALLBACK_CAP, DECOMPRESS_MIN_INITIAL = 1024, SELFTEST_HEX, SELFTEST_JSON, EMPTY_VIEW;
|
|
287
|
-
var init_constants = __esm(() => {
|
|
288
|
-
MAX_DECOMPRESSED = 64 * 1024 * 1024;
|
|
289
|
-
MAX_JSON_PATCH_OUTPUT = 128 * 1024 * 1024;
|
|
290
|
-
COMPRESS_INITIAL_CAP = 16 * 1024;
|
|
291
|
-
COMPRESS_MAX_CAP = 1024 * 1024;
|
|
292
|
-
DECOMPRESS_FALLBACK_CAP = 4 * 1024 * 1024;
|
|
293
|
-
SELFTEST_HEX = new Uint8Array([104, 101, 108, 108, 111]);
|
|
294
|
-
SELFTEST_JSON = new Uint8Array([123, 34, 97, 34, 58, 49, 125]);
|
|
295
|
-
EMPTY_VIEW = new Uint8Array(0);
|
|
296
|
-
});
|
|
297
|
-
|
|
298
667
|
// src/shared/bytes.ts
|
|
299
668
|
function toBytes(v) {
|
|
300
669
|
return typeof v === "string" ? encodeUtf8(v) : v;
|
|
@@ -696,365 +1065,160 @@ function buildCodecs(sym, ctx) {
|
|
|
696
1065
|
}
|
|
697
1066
|
};
|
|
698
1067
|
}
|
|
699
|
-
|
|
1068
|
+
var init_codecs = __esm(() => {
|
|
1069
|
+
init_codec2();
|
|
1070
|
+
init_util();
|
|
1071
|
+
});
|
|
1072
|
+
|
|
1073
|
+
// src/native/ffi/constants.ts
|
|
1074
|
+
var MAX_DECOMPRESSED, MAX_JSON_PATCH_OUTPUT, COMPRESS_INITIAL_CAP, COMPRESS_MAX_CAP, COMPRESS_HEADROOM = 64, DECOMPRESS_GUESS_MULTIPLIER_GZIP = 16, DECOMPRESS_GUESS_MULTIPLIER_BROTLI = 32, DECOMPRESS_FALLBACK_CAP, DECOMPRESS_MIN_INITIAL = 1024, SELFTEST_HEX, SELFTEST_JSON, EMPTY_VIEW;
|
|
1075
|
+
var init_constants = __esm(() => {
|
|
1076
|
+
MAX_DECOMPRESSED = 64 * 1024 * 1024;
|
|
1077
|
+
MAX_JSON_PATCH_OUTPUT = 128 * 1024 * 1024;
|
|
1078
|
+
COMPRESS_INITIAL_CAP = 16 * 1024;
|
|
1079
|
+
COMPRESS_MAX_CAP = 1024 * 1024;
|
|
1080
|
+
DECOMPRESS_FALLBACK_CAP = 4 * 1024 * 1024;
|
|
1081
|
+
SELFTEST_HEX = new Uint8Array([104, 101, 108, 108, 111]);
|
|
1082
|
+
SELFTEST_JSON = new Uint8Array([123, 34, 97, 34, 58, 49, 125]);
|
|
1083
|
+
EMPTY_VIEW = new Uint8Array(0);
|
|
1084
|
+
});
|
|
1085
|
+
|
|
1086
|
+
// src/native/ffi/build/compress.ts
|
|
1087
|
+
function buildCompress(sym, ctx) {
|
|
1088
|
+
const { lenOrView, scratchFor } = ctx;
|
|
1089
|
+
const gzipCompress = sym.castrum_gzip_compress;
|
|
1090
|
+
const gzipDecompress = sym.castrum_gzip_decompress;
|
|
1091
|
+
const brotliCompress = sym.castrum_brotli_compress;
|
|
1092
|
+
const brotliDecompress = sym.castrum_brotli_decompress;
|
|
1093
|
+
const gzipIsize = sym.castrum_gzip_isize;
|
|
1094
|
+
const jsonPatch = sym.castrum_json_patch;
|
|
1095
|
+
return {
|
|
1096
|
+
jsonPatch(doc, patch) {
|
|
1097
|
+
let out = scratchFor(Math.min(Math.max(doc.length, patch.length) + 16, 64 * 1024));
|
|
1098
|
+
let w = Number(jsonPatch(doc, lenOrView(doc), patch, lenOrView(patch), out, lenOrView(out)));
|
|
1099
|
+
if (w > out.length && w <= MAX_JSON_PATCH_OUTPUT) {
|
|
1100
|
+
out = new Uint8Array(w);
|
|
1101
|
+
w = Number(jsonPatch(doc, lenOrView(doc), patch, lenOrView(patch), out, lenOrView(out)));
|
|
1102
|
+
}
|
|
1103
|
+
if (w === 0 || w > out.length) {
|
|
1104
|
+
throw new Error("json patch: output buffer too small or patch inapplicable");
|
|
1105
|
+
}
|
|
1106
|
+
return decodeUtf8(out.subarray(0, w));
|
|
1107
|
+
},
|
|
1108
|
+
gzipCompress(data, level = 6) {
|
|
1109
|
+
return growExact((out) => Number(gzipCompress(data, lenOrView(data), Math.min(level, 9), out, lenOrView(out))), Math.min(data.length + COMPRESS_HEADROOM, COMPRESS_INITIAL_CAP), Math.max(data.length * 2 + COMPRESS_HEADROOM, COMPRESS_MAX_CAP), "gzip compress: output buffer too small");
|
|
1110
|
+
},
|
|
1111
|
+
gzipCompressInto(data, output, level = 6) {
|
|
1112
|
+
const w = Number(gzipCompress(data, lenOrView(data), Math.min(level, 9), output, lenOrView(output)));
|
|
1113
|
+
if (w === 0) {
|
|
1114
|
+
throw new Error("gzip compress: invalid input");
|
|
1115
|
+
}
|
|
1116
|
+
if (w > output.length) {
|
|
1117
|
+
throw new Error("gzip compress: output buffer too small");
|
|
1118
|
+
}
|
|
1119
|
+
return w;
|
|
1120
|
+
},
|
|
1121
|
+
gzipDecompress(data, maxDecompressed) {
|
|
1122
|
+
const max = maxDecompressed ?? MAX_DECOMPRESSED;
|
|
1123
|
+
const isize = Number(gzipIsize(data, lenOrView(data)));
|
|
1124
|
+
const initial = isize !== 0 ? Math.min(isize, max) : Math.min(data.length * DECOMPRESS_GUESS_MULTIPLIER_GZIP, DECOMPRESS_FALLBACK_CAP);
|
|
1125
|
+
return growExact((out) => Number(gzipDecompress(data, lenOrView(data), max, out, lenOrView(out))), initial, max, "gzip decompress: invalid stream or exceeded max decompressed size");
|
|
1126
|
+
},
|
|
1127
|
+
gzipDecompressInto(data, output, maxDecompressed) {
|
|
1128
|
+
const max = maxDecompressed ?? MAX_DECOMPRESSED;
|
|
1129
|
+
const w = Number(gzipDecompress(data, lenOrView(data), max, output, lenOrView(output)));
|
|
1130
|
+
if (w === 0) {
|
|
1131
|
+
throw new Error("gzip decompress: invalid stream or exceeded max decompressed size");
|
|
1132
|
+
}
|
|
1133
|
+
if (w > output.length) {
|
|
1134
|
+
throw new Error("gzip decompress: output buffer too small");
|
|
1135
|
+
}
|
|
1136
|
+
return w;
|
|
1137
|
+
},
|
|
1138
|
+
gzipIsize(data) {
|
|
1139
|
+
return Number(gzipIsize(data, lenOrView(data)));
|
|
1140
|
+
},
|
|
1141
|
+
brotliCompress(data, quality = 5) {
|
|
1142
|
+
return growExact((out) => Number(brotliCompress(data, lenOrView(data), Math.min(quality, 11), out, lenOrView(out))), Math.min(data.length + COMPRESS_HEADROOM, COMPRESS_INITIAL_CAP), Math.max(data.length * 2 + COMPRESS_HEADROOM, COMPRESS_MAX_CAP), "brotli compress: output buffer too small");
|
|
1143
|
+
},
|
|
1144
|
+
brotliCompressInto(data, output, quality = 5) {
|
|
1145
|
+
const w = Number(brotliCompress(data, lenOrView(data), Math.min(quality, 11), output, lenOrView(output)));
|
|
1146
|
+
if (w === 0) {
|
|
1147
|
+
throw new Error("brotli compress: invalid input");
|
|
1148
|
+
}
|
|
1149
|
+
if (w > output.length) {
|
|
1150
|
+
throw new Error("brotli compress: output buffer too small");
|
|
1151
|
+
}
|
|
1152
|
+
return w;
|
|
1153
|
+
},
|
|
1154
|
+
brotliDecompress(data, maxDecompressed) {
|
|
1155
|
+
const max = maxDecompressed ?? MAX_DECOMPRESSED;
|
|
1156
|
+
return growExact((out) => Number(brotliDecompress(data, lenOrView(data), max, out, lenOrView(out))), Math.min(Math.max(data.length * DECOMPRESS_GUESS_MULTIPLIER_BROTLI, DECOMPRESS_MIN_INITIAL), DECOMPRESS_FALLBACK_CAP), max, "brotli decompress: invalid stream or exceeded max decompressed size");
|
|
1157
|
+
},
|
|
1158
|
+
brotliDecompressInto(data, output, maxDecompressed) {
|
|
1159
|
+
const max = maxDecompressed ?? MAX_DECOMPRESSED;
|
|
1160
|
+
const w = Number(brotliDecompress(data, lenOrView(data), max, output, lenOrView(output)));
|
|
1161
|
+
if (w === 0) {
|
|
1162
|
+
throw new Error("brotli decompress: invalid stream or exceeded max decompressed size");
|
|
1163
|
+
}
|
|
1164
|
+
if (w > output.length) {
|
|
1165
|
+
throw new Error("brotli decompress: output buffer too small");
|
|
1166
|
+
}
|
|
1167
|
+
return w;
|
|
1168
|
+
}
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
function selfTestCompress(b) {
|
|
700
1172
|
const enc = { encode: encodeUtf8 };
|
|
701
1173
|
const dec = { decode: decodeUtf8 };
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
if (b.fnv1a64(enc.encode("foobar")) !== 0x85944171f73967e8n)
|
|
705
|
-
return false;
|
|
706
|
-
if (b.xxh3(new Uint8Array(0)) !== 0x2d06800538d394c2n)
|
|
707
|
-
return false;
|
|
708
|
-
if (b.jsonValid(SELFTEST_JSON) !== true || b.jsonValid(enc.encode("{not json")) !== false) {
|
|
709
|
-
return false;
|
|
710
|
-
}
|
|
711
|
-
if (!b.utf8Valid(enc.encode("héllo")) || b.utf8Valid(new Uint8Array([255, 254]))) {
|
|
712
|
-
return false;
|
|
713
|
-
}
|
|
714
|
-
const hexOut = new Uint8Array(SELFTEST_HEX.length * 2);
|
|
715
|
-
if (b.hexEncodeInto(SELFTEST_HEX, hexOut) !== 10 || dec.decode(hexOut) !== "68656c6c6f") {
|
|
716
|
-
return false;
|
|
717
|
-
}
|
|
718
|
-
const urlInput = enc.encode("a b/c");
|
|
719
|
-
const urlOut = new Uint8Array(9);
|
|
720
|
-
if (b.urlEncodeInto(urlInput, urlOut) !== 9 || dec.decode(urlOut) !== "a%20b%2Fc") {
|
|
1174
|
+
const patched = b.jsonPatch(enc.encode(`{"a":"b"}`), enc.encode(`[{"op":"add","path":"/c","value":"d"}]`));
|
|
1175
|
+
if (!patched.includes(`"c":"d"`)) {
|
|
721
1176
|
return false;
|
|
722
1177
|
}
|
|
723
|
-
|
|
1178
|
+
const gz = b.gzipCompress(SELFTEST_HEX);
|
|
1179
|
+
if (dec.decode(b.gzipDecompress(gz)) !== "hello") {
|
|
724
1180
|
return false;
|
|
725
1181
|
}
|
|
726
|
-
|
|
1182
|
+
const br = b.brotliCompress(SELFTEST_HEX);
|
|
1183
|
+
if (dec.decode(b.brotliDecompress(br)) !== "hello") {
|
|
727
1184
|
return false;
|
|
728
1185
|
}
|
|
729
|
-
|
|
730
|
-
return false;
|
|
731
|
-
if (b.jsonSumIds(enc.encode(`[{"id":0},{"id":0}]`)) !== 0n)
|
|
732
|
-
return false;
|
|
733
|
-
let sumInvalidThrew = false;
|
|
1186
|
+
let decompressThrew = false;
|
|
734
1187
|
try {
|
|
735
|
-
b.
|
|
1188
|
+
b.gzipDecompress(enc.encode("not-a-gzip-stream"));
|
|
736
1189
|
} catch {
|
|
737
|
-
|
|
1190
|
+
decompressThrew = true;
|
|
738
1191
|
}
|
|
739
|
-
if (!
|
|
1192
|
+
if (!decompressThrew) {
|
|
740
1193
|
return false;
|
|
741
|
-
{
|
|
742
|
-
const ids = enc.encode(`507f1f77bcf86cd799439011
|
|
743
|
-
zz
|
|
744
|
-
507F1F77BCF86CD799439012`);
|
|
745
|
-
const tiny = new Uint8Array(2);
|
|
746
|
-
const needed = b.hexValidateBatchInto(ids, 24, tiny);
|
|
747
|
-
if (needed !== 3)
|
|
748
|
-
return false;
|
|
749
|
-
const out = new Uint8Array(needed);
|
|
750
|
-
if (b.hexValidateBatchInto(ids, 24, out) !== 3)
|
|
751
|
-
return false;
|
|
752
|
-
if (out[0] !== 1 || out[1] !== 0 || out[2] !== 1)
|
|
753
|
-
return false;
|
|
754
|
-
let widthThrew = false;
|
|
755
|
-
try {
|
|
756
|
-
b.hexValidateBatchInto(ids, 0, new Uint8Array(3));
|
|
757
|
-
} catch {
|
|
758
|
-
widthThrew = true;
|
|
759
|
-
}
|
|
760
|
-
if (!widthThrew)
|
|
761
|
-
return false;
|
|
762
|
-
}
|
|
763
|
-
{
|
|
764
|
-
const out = new Uint8Array(64);
|
|
765
|
-
const w = b.regexEscapeInto(enc.encode("a.c(x)"), out);
|
|
766
|
-
if (w !== 9 || dec.decode(out.subarray(0, w)) !== "a\\.c\\(x\\)")
|
|
767
|
-
return false;
|
|
768
|
-
const plain = new Uint8Array(16);
|
|
769
|
-
const wp = b.regexEscapeInto(enc.encode("hello"), plain);
|
|
770
|
-
if (wp !== 5 || dec.decode(plain.subarray(0, wp)) !== "hello")
|
|
771
|
-
return false;
|
|
772
|
-
if (b.regexEscapeInto(enc.encode("a.b"), new Uint8Array(2)) !== 4)
|
|
773
|
-
return false;
|
|
774
|
-
if (b.regexEscapeStr("a.c(x)") !== "a\\.c\\(x\\)")
|
|
775
|
-
return false;
|
|
776
|
-
if (b.regexEscapeStr("plain text") !== "plain text")
|
|
777
|
-
return false;
|
|
778
|
-
}
|
|
779
|
-
{
|
|
780
|
-
const out = new Uint8Array(8);
|
|
781
|
-
const w = b.hexValidateBatchStr(`507f1f77bcf86cd799439011
|
|
782
|
-
zz`, 24, out);
|
|
783
|
-
if (w !== 2 || out[0] !== 1 || out[1] !== 0)
|
|
784
|
-
return false;
|
|
785
1194
|
}
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
1195
|
+
decompressThrew = false;
|
|
1196
|
+
try {
|
|
1197
|
+
b.brotliDecompress(enc.encode("not-brotli-stream"));
|
|
1198
|
+
} catch {
|
|
1199
|
+
decompressThrew = true;
|
|
791
1200
|
}
|
|
792
|
-
if (!
|
|
1201
|
+
if (!decompressThrew) {
|
|
793
1202
|
return false;
|
|
794
1203
|
}
|
|
795
|
-
const
|
|
796
|
-
|
|
1204
|
+
const gzInto = new Uint8Array(64);
|
|
1205
|
+
const gzW = b.gzipCompressInto(SELFTEST_HEX, gzInto);
|
|
1206
|
+
if (gzW === 0 || dec.decode(b.gzipDecompress(gzInto.subarray(0, gzW))) !== "hello") {
|
|
797
1207
|
return false;
|
|
798
1208
|
}
|
|
799
|
-
|
|
1209
|
+
const brInto = new Uint8Array(64);
|
|
1210
|
+
const brW = b.brotliCompressInto(SELFTEST_HEX, brInto);
|
|
1211
|
+
if (brW === 0 || dec.decode(b.brotliDecompress(brInto.subarray(0, brW))) !== "hello") {
|
|
800
1212
|
return false;
|
|
801
1213
|
}
|
|
802
|
-
|
|
1214
|
+
const gzDst = new Uint8Array(16);
|
|
1215
|
+
const gzDW = b.gzipDecompressInto(gzInto.subarray(0, gzW), gzDst);
|
|
1216
|
+
if (gzDW === 0 || dec.decode(gzDst.subarray(0, gzDW)) !== "hello") {
|
|
803
1217
|
return false;
|
|
804
1218
|
}
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
if (dec.decode(b.base64Decode(enc.encode("aGVsbG8="))) !== "hello") {
|
|
809
|
-
return false;
|
|
810
|
-
}
|
|
811
|
-
const secret = enc.encode("s3cr3t-secret");
|
|
812
|
-
const signed = b.signCookie(SELFTEST_HEX, secret);
|
|
813
|
-
const verified = b.verifyCookie(enc.encode(signed), secret);
|
|
814
|
-
if (verified === null || verified !== "hello") {
|
|
815
|
-
return false;
|
|
816
|
-
}
|
|
817
|
-
if (b.verifyCookie(enc.encode("tampered.0000"), secret) !== null) {
|
|
818
|
-
return false;
|
|
819
|
-
}
|
|
820
|
-
const csrfTokenStr = b.csrfToken(secret);
|
|
821
|
-
if (csrfTokenStr.length !== 129 || !b.csrfVerify(enc.encode(csrfTokenStr), secret)) {
|
|
822
|
-
return false;
|
|
823
|
-
}
|
|
824
|
-
const pw = enc.encode("correct horse battery staple");
|
|
825
|
-
const salt = enc.encode("salty-salt-16b");
|
|
826
|
-
const phc = b.passwordHash(pw, salt, 8, 1, 1, 16);
|
|
827
|
-
if (phc.length === 0 || !b.passwordVerify(pw, enc.encode(phc))) {
|
|
828
|
-
return false;
|
|
829
|
-
}
|
|
830
|
-
const bcryptPhc = b.passwordHashBcrypt(pw, 4);
|
|
831
|
-
if (bcryptPhc.length === 0 || !b.passwordVerifyBcrypt(pw, bcryptPhc)) {
|
|
832
|
-
return false;
|
|
833
|
-
}
|
|
834
|
-
const dk = b.pbkdf2Sha256(enc.encode("password"), enc.encode("salt"), 1, 32);
|
|
835
|
-
if (b.hexEncode(dk) !== "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b") {
|
|
836
|
-
return false;
|
|
837
|
-
}
|
|
838
|
-
const aeadKey = new Uint8Array(32).fill(66);
|
|
839
|
-
const nonce = new Uint8Array(12).fill(7);
|
|
840
|
-
const ct = b.aeadEncrypt(aeadKey, nonce, SELFTEST_HEX, 0);
|
|
841
|
-
const pt = b.aeadDecrypt(aeadKey, nonce, ct, 0);
|
|
842
|
-
if (pt === null || dec.decode(pt) !== "hello") {
|
|
843
|
-
return false;
|
|
844
|
-
}
|
|
845
|
-
const rtOut = new Uint8Array(32);
|
|
846
|
-
const rtW = b.randomTokenInto(16, rtOut);
|
|
847
|
-
if (rtW !== 32 || !/^[0-9a-f]{32}$/.test(dec.decode(rtOut))) {
|
|
848
|
-
return false;
|
|
849
|
-
}
|
|
850
|
-
try {
|
|
851
|
-
b.randomTokenInto(16, new Uint8Array(8));
|
|
852
|
-
return false;
|
|
853
|
-
} catch {}
|
|
854
|
-
const waOut = new Uint8Array(28);
|
|
855
|
-
const waW = b.wsAcceptKeyInto(enc.encode("dGhlIHNhbXBsZSBub25jZQ=="), waOut);
|
|
856
|
-
const waExpected = b.wsAcceptKey("dGhlIHNhbXBsZSBub25jZQ==");
|
|
857
|
-
if (waW !== 28 || dec.decode(waOut) !== waExpected) {
|
|
858
|
-
return false;
|
|
859
|
-
}
|
|
860
|
-
const etagData = enc.encode("hello");
|
|
861
|
-
const etagOut = new Uint8Array(16);
|
|
862
|
-
const etagW = b.etagInto(etagData, etagOut);
|
|
863
|
-
if (etagW !== 10 || dec.decode(etagOut.subarray(0, etagW)) !== b.etag(etagData)) {
|
|
864
|
-
return false;
|
|
865
|
-
}
|
|
866
|
-
const csrfOut = new Uint8Array(129);
|
|
867
|
-
const csrfW = b.csrfTokenInto(enc.encode("csrf-secret"), csrfOut);
|
|
868
|
-
if (csrfW !== 129 || csrfOut[64] !== 46) {
|
|
869
|
-
return false;
|
|
870
|
-
}
|
|
871
|
-
const ckVal = enc.encode("session-value");
|
|
872
|
-
const ckSec = enc.encode("s3cr3t-secret");
|
|
873
|
-
const ckOut = new Uint8Array(256);
|
|
874
|
-
const ckW = b.signCookieInto(ckVal, ckSec, ckOut);
|
|
875
|
-
if (ckW !== ckVal.length + 65) {
|
|
876
|
-
return false;
|
|
877
|
-
}
|
|
878
|
-
const ckVerifyOut = new Uint8Array(256);
|
|
879
|
-
const ckV = b.verifyCookieInto(ckOut.subarray(0, ckW), ckSec, ckVerifyOut);
|
|
880
|
-
if (ckV !== ckVal.length || dec.decode(ckVerifyOut.subarray(0, ckV)) !== "session-value") {
|
|
881
|
-
return false;
|
|
882
|
-
}
|
|
883
|
-
if (b.urlEncode(enc.encode("a b/c")) !== "a%20b%2Fc") {
|
|
884
|
-
return false;
|
|
885
|
-
}
|
|
886
|
-
const hdInto = new Uint8Array(8);
|
|
887
|
-
if (b.hexDecodeInto(enc.encode("68656c6c6f"), hdInto) !== 5 || dec.decode(hdInto.subarray(0, 5)) !== "hello") {
|
|
888
|
-
return false;
|
|
889
|
-
}
|
|
890
|
-
const udInto = new Uint8Array(16);
|
|
891
|
-
if (b.urlDecodeInto(enc.encode("a%20b%2Fc"), udInto) !== 5 || dec.decode(udInto.subarray(0, 5)) !== "a b/c") {
|
|
892
|
-
return false;
|
|
893
|
-
}
|
|
894
|
-
const b64Into = new Uint8Array(16);
|
|
895
|
-
if (b.base64EncodeInto(SELFTEST_HEX, b64Into) !== 8 || dec.decode(b64Into.subarray(0, 8)) !== "aGVsbG8=") {
|
|
896
|
-
return false;
|
|
897
|
-
}
|
|
898
|
-
const bdInto = new Uint8Array(8);
|
|
899
|
-
if (b.base64DecodeInto(enc.encode("aGVsbG8="), bdInto) !== 5 || dec.decode(bdInto.subarray(0, 5)) !== "hello") {
|
|
900
|
-
return false;
|
|
901
|
-
}
|
|
902
|
-
if (!/^[0-9a-f]{32}$/.test(b.randomToken(16))) {
|
|
903
|
-
return false;
|
|
904
|
-
}
|
|
905
|
-
const hmacInto = new Uint8Array(64);
|
|
906
|
-
if (b.hmacSha256Into(hmacKey, hmacData, hmacInto) !== 64 || dec.decode(hmacInto) !== "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7") {
|
|
907
|
-
return false;
|
|
908
|
-
}
|
|
909
|
-
const ctInto = new Uint8Array(64);
|
|
910
|
-
const ctW = b.aeadEncryptInto(aeadKey, nonce, SELFTEST_HEX, ctInto, 0);
|
|
911
|
-
if (ctW === 0 || b.aeadDecrypt(aeadKey, nonce, ctInto.subarray(0, ctW), 0) === null) {
|
|
912
|
-
return false;
|
|
913
|
-
}
|
|
914
|
-
return true;
|
|
915
|
-
}
|
|
916
|
-
var init_codecs = __esm(() => {
|
|
917
|
-
init_codec2();
|
|
918
|
-
init_constants();
|
|
919
|
-
init_util();
|
|
920
|
-
});
|
|
921
|
-
|
|
922
|
-
// src/native/ffi/build/compress.ts
|
|
923
|
-
function buildCompress(sym, ctx) {
|
|
924
|
-
const { lenOrView, scratchFor } = ctx;
|
|
925
|
-
const gzipCompress = sym.castrum_gzip_compress;
|
|
926
|
-
const gzipDecompress = sym.castrum_gzip_decompress;
|
|
927
|
-
const brotliCompress = sym.castrum_brotli_compress;
|
|
928
|
-
const brotliDecompress = sym.castrum_brotli_decompress;
|
|
929
|
-
const gzipIsize = sym.castrum_gzip_isize;
|
|
930
|
-
const jsonPatch = sym.castrum_json_patch;
|
|
931
|
-
return {
|
|
932
|
-
jsonPatch(doc, patch) {
|
|
933
|
-
let out = scratchFor(Math.min(Math.max(doc.length, patch.length) + 16, 64 * 1024));
|
|
934
|
-
let w = Number(jsonPatch(doc, lenOrView(doc), patch, lenOrView(patch), out, lenOrView(out)));
|
|
935
|
-
if (w > out.length && w <= MAX_JSON_PATCH_OUTPUT) {
|
|
936
|
-
out = new Uint8Array(w);
|
|
937
|
-
w = Number(jsonPatch(doc, lenOrView(doc), patch, lenOrView(patch), out, lenOrView(out)));
|
|
938
|
-
}
|
|
939
|
-
if (w === 0 || w > out.length) {
|
|
940
|
-
throw new Error("json patch: output buffer too small or patch inapplicable");
|
|
941
|
-
}
|
|
942
|
-
return decodeUtf8(out.subarray(0, w));
|
|
943
|
-
},
|
|
944
|
-
gzipCompress(data, level = 6) {
|
|
945
|
-
return growExact((out) => Number(gzipCompress(data, lenOrView(data), Math.min(level, 9), out, lenOrView(out))), Math.min(data.length + COMPRESS_HEADROOM, COMPRESS_INITIAL_CAP), Math.max(data.length * 2 + COMPRESS_HEADROOM, COMPRESS_MAX_CAP), "gzip compress: output buffer too small");
|
|
946
|
-
},
|
|
947
|
-
gzipCompressInto(data, output, level = 6) {
|
|
948
|
-
const w = Number(gzipCompress(data, lenOrView(data), Math.min(level, 9), output, lenOrView(output)));
|
|
949
|
-
if (w === 0) {
|
|
950
|
-
throw new Error("gzip compress: invalid input");
|
|
951
|
-
}
|
|
952
|
-
if (w > output.length) {
|
|
953
|
-
throw new Error("gzip compress: output buffer too small");
|
|
954
|
-
}
|
|
955
|
-
return w;
|
|
956
|
-
},
|
|
957
|
-
gzipDecompress(data, maxDecompressed) {
|
|
958
|
-
const max = maxDecompressed ?? MAX_DECOMPRESSED;
|
|
959
|
-
const isize = Number(gzipIsize(data, lenOrView(data)));
|
|
960
|
-
const initial = isize !== 0 ? Math.min(isize, max) : Math.min(data.length * DECOMPRESS_GUESS_MULTIPLIER_GZIP, DECOMPRESS_FALLBACK_CAP);
|
|
961
|
-
return growExact((out) => Number(gzipDecompress(data, lenOrView(data), max, out, lenOrView(out))), initial, max, "gzip decompress: invalid stream or exceeded max decompressed size");
|
|
962
|
-
},
|
|
963
|
-
gzipDecompressInto(data, output, maxDecompressed) {
|
|
964
|
-
const max = maxDecompressed ?? MAX_DECOMPRESSED;
|
|
965
|
-
const w = Number(gzipDecompress(data, lenOrView(data), max, output, lenOrView(output)));
|
|
966
|
-
if (w === 0) {
|
|
967
|
-
throw new Error("gzip decompress: invalid stream or exceeded max decompressed size");
|
|
968
|
-
}
|
|
969
|
-
if (w > output.length) {
|
|
970
|
-
throw new Error("gzip decompress: output buffer too small");
|
|
971
|
-
}
|
|
972
|
-
return w;
|
|
973
|
-
},
|
|
974
|
-
gzipIsize(data) {
|
|
975
|
-
return Number(gzipIsize(data, lenOrView(data)));
|
|
976
|
-
},
|
|
977
|
-
brotliCompress(data, quality = 5) {
|
|
978
|
-
return growExact((out) => Number(brotliCompress(data, lenOrView(data), Math.min(quality, 11), out, lenOrView(out))), Math.min(data.length + COMPRESS_HEADROOM, COMPRESS_INITIAL_CAP), Math.max(data.length * 2 + COMPRESS_HEADROOM, COMPRESS_MAX_CAP), "brotli compress: output buffer too small");
|
|
979
|
-
},
|
|
980
|
-
brotliCompressInto(data, output, quality = 5) {
|
|
981
|
-
const w = Number(brotliCompress(data, lenOrView(data), Math.min(quality, 11), output, lenOrView(output)));
|
|
982
|
-
if (w === 0) {
|
|
983
|
-
throw new Error("brotli compress: invalid input");
|
|
984
|
-
}
|
|
985
|
-
if (w > output.length) {
|
|
986
|
-
throw new Error("brotli compress: output buffer too small");
|
|
987
|
-
}
|
|
988
|
-
return w;
|
|
989
|
-
},
|
|
990
|
-
brotliDecompress(data, maxDecompressed) {
|
|
991
|
-
const max = maxDecompressed ?? MAX_DECOMPRESSED;
|
|
992
|
-
return growExact((out) => Number(brotliDecompress(data, lenOrView(data), max, out, lenOrView(out))), Math.min(Math.max(data.length * DECOMPRESS_GUESS_MULTIPLIER_BROTLI, DECOMPRESS_MIN_INITIAL), DECOMPRESS_FALLBACK_CAP), max, "brotli decompress: invalid stream or exceeded max decompressed size");
|
|
993
|
-
},
|
|
994
|
-
brotliDecompressInto(data, output, maxDecompressed) {
|
|
995
|
-
const max = maxDecompressed ?? MAX_DECOMPRESSED;
|
|
996
|
-
const w = Number(brotliDecompress(data, lenOrView(data), max, output, lenOrView(output)));
|
|
997
|
-
if (w === 0) {
|
|
998
|
-
throw new Error("brotli decompress: invalid stream or exceeded max decompressed size");
|
|
999
|
-
}
|
|
1000
|
-
if (w > output.length) {
|
|
1001
|
-
throw new Error("brotli decompress: output buffer too small");
|
|
1002
|
-
}
|
|
1003
|
-
return w;
|
|
1004
|
-
}
|
|
1005
|
-
};
|
|
1006
|
-
}
|
|
1007
|
-
function selfTestCompress(b) {
|
|
1008
|
-
const enc = { encode: encodeUtf8 };
|
|
1009
|
-
const dec = { decode: decodeUtf8 };
|
|
1010
|
-
const patched = b.jsonPatch(enc.encode(`{"a":"b"}`), enc.encode(`[{"op":"add","path":"/c","value":"d"}]`));
|
|
1011
|
-
if (!patched.includes(`"c":"d"`)) {
|
|
1012
|
-
return false;
|
|
1013
|
-
}
|
|
1014
|
-
const gz = b.gzipCompress(SELFTEST_HEX);
|
|
1015
|
-
if (dec.decode(b.gzipDecompress(gz)) !== "hello") {
|
|
1016
|
-
return false;
|
|
1017
|
-
}
|
|
1018
|
-
const br = b.brotliCompress(SELFTEST_HEX);
|
|
1019
|
-
if (dec.decode(b.brotliDecompress(br)) !== "hello") {
|
|
1020
|
-
return false;
|
|
1021
|
-
}
|
|
1022
|
-
let decompressThrew = false;
|
|
1023
|
-
try {
|
|
1024
|
-
b.gzipDecompress(enc.encode("not-a-gzip-stream"));
|
|
1025
|
-
} catch {
|
|
1026
|
-
decompressThrew = true;
|
|
1027
|
-
}
|
|
1028
|
-
if (!decompressThrew) {
|
|
1029
|
-
return false;
|
|
1030
|
-
}
|
|
1031
|
-
decompressThrew = false;
|
|
1032
|
-
try {
|
|
1033
|
-
b.brotliDecompress(enc.encode("not-brotli-stream"));
|
|
1034
|
-
} catch {
|
|
1035
|
-
decompressThrew = true;
|
|
1036
|
-
}
|
|
1037
|
-
if (!decompressThrew) {
|
|
1038
|
-
return false;
|
|
1039
|
-
}
|
|
1040
|
-
const gzInto = new Uint8Array(64);
|
|
1041
|
-
const gzW = b.gzipCompressInto(SELFTEST_HEX, gzInto);
|
|
1042
|
-
if (gzW === 0 || dec.decode(b.gzipDecompress(gzInto.subarray(0, gzW))) !== "hello") {
|
|
1043
|
-
return false;
|
|
1044
|
-
}
|
|
1045
|
-
const brInto = new Uint8Array(64);
|
|
1046
|
-
const brW = b.brotliCompressInto(SELFTEST_HEX, brInto);
|
|
1047
|
-
if (brW === 0 || dec.decode(b.brotliDecompress(brInto.subarray(0, brW))) !== "hello") {
|
|
1048
|
-
return false;
|
|
1049
|
-
}
|
|
1050
|
-
const gzDst = new Uint8Array(16);
|
|
1051
|
-
const gzDW = b.gzipDecompressInto(gzInto.subarray(0, gzW), gzDst);
|
|
1052
|
-
if (gzDW === 0 || dec.decode(gzDst.subarray(0, gzDW)) !== "hello") {
|
|
1053
|
-
return false;
|
|
1054
|
-
}
|
|
1055
|
-
const brDst = new Uint8Array(16);
|
|
1056
|
-
const brDW = b.brotliDecompressInto(brInto.subarray(0, brW), brDst);
|
|
1057
|
-
if (brDW === 0 || dec.decode(brDst.subarray(0, brDW)) !== "hello") {
|
|
1219
|
+
const brDst = new Uint8Array(16);
|
|
1220
|
+
const brDW = b.brotliDecompressInto(brInto.subarray(0, brW), brDst);
|
|
1221
|
+
if (brDW === 0 || dec.decode(brDst.subarray(0, brDW)) !== "hello") {
|
|
1058
1222
|
return false;
|
|
1059
1223
|
}
|
|
1060
1224
|
return true;
|
|
@@ -1113,7 +1277,10 @@ function buildInstances(sym, ctx) {
|
|
|
1113
1277
|
return acceptNegotiatorNegotiateRaw(inner, header, lenOrView(header));
|
|
1114
1278
|
},
|
|
1115
1279
|
acceptNegotiatorNegotiateServer(inner, header) {
|
|
1116
|
-
|
|
1280
|
+
const text = decodeUtf8(header);
|
|
1281
|
+
if (hasNul(text))
|
|
1282
|
+
return null;
|
|
1283
|
+
return acceptNegotiatorNegotiateServerRaw(inner, text);
|
|
1117
1284
|
},
|
|
1118
1285
|
jwtSignerSign(inner, claimsJson, nowSeconds) {
|
|
1119
1286
|
return growExact((out) => Number(jwtSignerSignRaw(inner, claimsJson, lenOrView(claimsJson), BigInt(nowSeconds), out, lenOrView(out))), Math.min(claimsJson.length + 128, 64 * 1024), 1024 * 1024, "jwt signer: invalid claims JSON or output buffer too small");
|
|
@@ -1160,6 +1327,8 @@ function buildInstances(sym, ctx) {
|
|
|
1160
1327
|
return Number(sessionOpenBytesSym(token, lenOrView(token), secret, lenOrView(secret), output, lenOrView(output)));
|
|
1161
1328
|
},
|
|
1162
1329
|
rateLimiterCheck(inner, key, nowMs) {
|
|
1330
|
+
if (hasNul(key))
|
|
1331
|
+
return { allowed: false, remaining: 0, resetMs: 0 };
|
|
1163
1332
|
const out = rateScratch;
|
|
1164
1333
|
const w = Number(rateLimiterCheckRaw(inner, key, BigInt(Math.trunc(nowMs)), out, lenOrView(out)));
|
|
1165
1334
|
if (w === 0)
|
|
@@ -1252,190 +1421,6 @@ function buildInstances(sym, ctx) {
|
|
|
1252
1421
|
}
|
|
1253
1422
|
};
|
|
1254
1423
|
}
|
|
1255
|
-
function selfTestInstances(b) {
|
|
1256
|
-
const enc = { encode: encodeUtf8 };
|
|
1257
|
-
const dec = { decode: decodeUtf8 };
|
|
1258
|
-
const layoutBuf = new Uint8Array(38 * 4);
|
|
1259
|
-
b.ingressLayout(layoutBuf);
|
|
1260
|
-
const layoutView = new DataView(layoutBuf.buffer, layoutBuf.byteOffset, layoutBuf.byteLength);
|
|
1261
|
-
if (layoutView.getUint32(0, true) !== 0 || layoutView.getUint32(2 * 4, true) !== 2 || layoutView.getUint32(12 * 4, true) !== 48 || layoutView.getUint32(13 * 4, true) !== 1 || layoutView.getUint32(28 * 4, true) !== 32 || layoutView.getUint32(37 * 4, true) !== 8) {
|
|
1262
|
-
return false;
|
|
1263
|
-
}
|
|
1264
|
-
try {
|
|
1265
|
-
b.ingressHandlePacked(0, enc.encode("/"), null, new Uint8Array(64));
|
|
1266
|
-
return false;
|
|
1267
|
-
} catch {}
|
|
1268
|
-
try {
|
|
1269
|
-
b.ingressHandleComponents(0, 0, "/", "", enc.encode("rid"), new Uint8Array(2), null, new Uint8Array(64));
|
|
1270
|
-
return false;
|
|
1271
|
-
} catch {}
|
|
1272
|
-
const routeDesc = new Uint8Array(33);
|
|
1273
|
-
const rd = new DataView(routeDesc.buffer);
|
|
1274
|
-
rd.setUint32(0, 1380930900, true);
|
|
1275
|
-
rd.setUint32(4, 3, true);
|
|
1276
|
-
rd.setUint32(8, 2 * 1024 * 1024, true);
|
|
1277
|
-
rd.setUint32(12, 8192, true);
|
|
1278
|
-
rd.setUint32(16, 8192, true);
|
|
1279
|
-
rd.setUint32(20, 0, true);
|
|
1280
|
-
rd.setUint32(24, 1, true);
|
|
1281
|
-
routeDesc[28] = 0;
|
|
1282
|
-
rd.setUint32(29, 0, true);
|
|
1283
|
-
const routeHandle = b.routeCompile(routeDesc);
|
|
1284
|
-
if (routeHandle === 0) {
|
|
1285
|
-
return false;
|
|
1286
|
-
}
|
|
1287
|
-
const routeFrame = new Uint8Array(15);
|
|
1288
|
-
const rf = new DataView(routeFrame.buffer);
|
|
1289
|
-
rf.setUint32(0, 0, true);
|
|
1290
|
-
rf.setUint32(4, 3, true);
|
|
1291
|
-
routeFrame.set(enc.encode("a=1"), 8);
|
|
1292
|
-
rf.setUint32(11, 0, true);
|
|
1293
|
-
const routeOut = new Uint8Array(64);
|
|
1294
|
-
const routeW = b.routeRun(routeHandle, routeFrame, routeOut);
|
|
1295
|
-
if (routeW <= 8) {
|
|
1296
|
-
return false;
|
|
1297
|
-
}
|
|
1298
|
-
const rv = new DataView(routeOut.buffer);
|
|
1299
|
-
const rFlags = rv.getUint32(0, true);
|
|
1300
|
-
if ((rFlags & 1) === 0 || (rFlags & 4) === 0) {
|
|
1301
|
-
return false;
|
|
1302
|
-
}
|
|
1303
|
-
b.routeDestroy(routeHandle);
|
|
1304
|
-
if (b.conditionalIsNotModified(0, null, null) !== false) {
|
|
1305
|
-
return false;
|
|
1306
|
-
}
|
|
1307
|
-
if (b.mediaTypeMatcherMatches(0, enc.encode("x")) !== false)
|
|
1308
|
-
return false;
|
|
1309
|
-
if (b.acceptNegotiatorNegotiate(0, enc.encode("gzip")) !== null)
|
|
1310
|
-
return false;
|
|
1311
|
-
if (b.acceptNegotiatorNegotiateServer(0, enc.encode("gzip")) !== null)
|
|
1312
|
-
return false;
|
|
1313
|
-
if (b.schemaValidatorValidate(0, enc.encode("{}")) !== false)
|
|
1314
|
-
return false;
|
|
1315
|
-
if (b.jwtSignerVerify(0, enc.encode("a.b.c"), 0) !== null)
|
|
1316
|
-
return false;
|
|
1317
|
-
let phase6Threw = false;
|
|
1318
|
-
try {
|
|
1319
|
-
b.jwtSignerSign(0, enc.encode("{}"), 0);
|
|
1320
|
-
} catch {
|
|
1321
|
-
phase6Threw = true;
|
|
1322
|
-
}
|
|
1323
|
-
if (!phase6Threw)
|
|
1324
|
-
return false;
|
|
1325
|
-
phase6Threw = false;
|
|
1326
|
-
try {
|
|
1327
|
-
b.templateRender(0, enc.encode("{}"));
|
|
1328
|
-
} catch {
|
|
1329
|
-
phase6Threw = true;
|
|
1330
|
-
}
|
|
1331
|
-
if (!phase6Threw)
|
|
1332
|
-
return false;
|
|
1333
|
-
phase6Threw = false;
|
|
1334
|
-
try {
|
|
1335
|
-
b.rateLimiterCheck(0, "k", 0);
|
|
1336
|
-
} catch {
|
|
1337
|
-
phase6Threw = true;
|
|
1338
|
-
}
|
|
1339
|
-
if (!phase6Threw)
|
|
1340
|
-
return false;
|
|
1341
|
-
const jwtClaims = enc.encode('{"sub":"user-1"}');
|
|
1342
|
-
const jwtSecret2 = enc.encode("my-secret");
|
|
1343
|
-
const jwtOut = new Uint8Array(512);
|
|
1344
|
-
const jwtW = b.jwtSignBytesInto(jwtClaims, jwtSecret2, 0, 0, jwtOut);
|
|
1345
|
-
if (jwtW === 0 || dec.decode(jwtOut.subarray(0, jwtW)).split(".").length !== 3) {
|
|
1346
|
-
return false;
|
|
1347
|
-
}
|
|
1348
|
-
const jwtSecret = enc.encode("my-secret");
|
|
1349
|
-
const jwt = b.jwtSignBytes(enc.encode('{"sub":"user-1"}'), jwtSecret, 0, 0);
|
|
1350
|
-
const jwtStr = jwt;
|
|
1351
|
-
const segs = jwtStr.split(".");
|
|
1352
|
-
if (segs.length !== 3 || segs[0] === "" || segs[1] === "" || segs[2] === "") {
|
|
1353
|
-
return false;
|
|
1354
|
-
}
|
|
1355
|
-
const signingInput = enc.encode(`${segs[0]}.${segs[1]}`);
|
|
1356
|
-
const sigHex = b.hmacSha256(jwtSecret, signingInput);
|
|
1357
|
-
const sigBytes = b.base64Decode(enc.encode(segs[2] ?? ""), true, false);
|
|
1358
|
-
if (sigBytes === null || b.hexEncode(sigBytes) !== sigHex) {
|
|
1359
|
-
return false;
|
|
1360
|
-
}
|
|
1361
|
-
const vjwtSecret = enc.encode("verify-secret");
|
|
1362
|
-
const vjwt = b.jwtSignBytes(enc.encode('{"sub":"u-1"}'), vjwtSecret, 0, 0);
|
|
1363
|
-
const vjwtClaims = b.jwtVerify(enc.encode(vjwt), vjwtSecret, 0);
|
|
1364
|
-
if (vjwtClaims === null || !vjwtClaims.includes('"sub":"u-1"')) {
|
|
1365
|
-
return false;
|
|
1366
|
-
}
|
|
1367
|
-
if (b.jwtVerify(enc.encode("tampered.token.value"), vjwtSecret, 0) !== null) {
|
|
1368
|
-
return false;
|
|
1369
|
-
}
|
|
1370
|
-
const edKp = b.ed25519GenerateKeypair();
|
|
1371
|
-
const edMsg = enc.encode("ed25519 bind-time self-test");
|
|
1372
|
-
const edSig = b.ed25519Sign(edMsg, edKp.privateKey);
|
|
1373
|
-
if (edSig.byteLength !== 64 || !b.ed25519Verify(edMsg, edSig, edKp.publicKey)) {
|
|
1374
|
-
return false;
|
|
1375
|
-
}
|
|
1376
|
-
const edTampered = edSig.slice();
|
|
1377
|
-
edTampered[0] = (edTampered[0] ?? 0) ^ 255;
|
|
1378
|
-
if (b.ed25519Verify(edMsg, edTampered, edKp.publicKey)) {
|
|
1379
|
-
return false;
|
|
1380
|
-
}
|
|
1381
|
-
const edToken = b.jwtEdDSASign(enc.encode('{"sub":"ffi-self-test"}'), edKp.privateKey, 0, 0);
|
|
1382
|
-
if (edToken === null || edToken.split(".").length !== 3) {
|
|
1383
|
-
return false;
|
|
1384
|
-
}
|
|
1385
|
-
const edClaims = b.jwtEdDSAVerify(enc.encode(edToken), edKp.publicKey, 0);
|
|
1386
|
-
if (edClaims === null || !edClaims.includes('"sub":"ffi-self-test"')) {
|
|
1387
|
-
return false;
|
|
1388
|
-
}
|
|
1389
|
-
if (b.jwtEdDSAVerify(enc.encode("tampered.token.value"), edKp.publicKey, 0) !== null) {
|
|
1390
|
-
return false;
|
|
1391
|
-
}
|
|
1392
|
-
let urlBuilderThrew = false;
|
|
1393
|
-
try {
|
|
1394
|
-
b.urlBuilderResolve(0, enc.encode("g"));
|
|
1395
|
-
} catch {
|
|
1396
|
-
urlBuilderThrew = true;
|
|
1397
|
-
}
|
|
1398
|
-
if (!urlBuilderThrew) {
|
|
1399
|
-
return false;
|
|
1400
|
-
}
|
|
1401
|
-
if (b.queryValidate(0, "route=/a") !== false)
|
|
1402
|
-
return false;
|
|
1403
|
-
if (b.cookieValidate(0, "route=/a") !== false)
|
|
1404
|
-
return false;
|
|
1405
|
-
{
|
|
1406
|
-
const tok = b.sessionSeal("sess-9", '{"n":1}', 1234567, "sekrit");
|
|
1407
|
-
if (tok === null || !tok.includes(".") || !tok.startsWith('{"id":"sess-9"'))
|
|
1408
|
-
return false;
|
|
1409
|
-
const out = new Uint8Array(256);
|
|
1410
|
-
const w = b.sessionOpen(tok, "sekrit", out);
|
|
1411
|
-
if (w <= 13 || out[0] !== 1)
|
|
1412
|
-
return false;
|
|
1413
|
-
if (b.sessionOpen(tok, "wrong", out) !== 0)
|
|
1414
|
-
return false;
|
|
1415
|
-
const enc = new TextEncoder;
|
|
1416
|
-
const tokB = b.sessionSealBytes(enc.encode("sess-9"), enc.encode('{"n":1}'), 1234567, enc.encode("sekrit"));
|
|
1417
|
-
if (tokB === null || tokB !== tok)
|
|
1418
|
-
return false;
|
|
1419
|
-
const outB = new Uint8Array(256);
|
|
1420
|
-
const wB = b.sessionOpenBytes(enc.encode(tokB), enc.encode("sekrit"), outB);
|
|
1421
|
-
if (wB !== w || outB[0] !== 1)
|
|
1422
|
-
return false;
|
|
1423
|
-
if (b.sessionOpenBytes(enc.encode(tokB), enc.encode("wrong"), outB) !== 0)
|
|
1424
|
-
return false;
|
|
1425
|
-
if (b.sessionOpenBytes(enc.encode(tokB), enc.encode("sekrit"), outB.subarray(0, 4)) !== wB)
|
|
1426
|
-
return false;
|
|
1427
|
-
}
|
|
1428
|
-
let rlKeyThrew = false;
|
|
1429
|
-
try {
|
|
1430
|
-
b.rateLimiterCheckKey(0, 12345, 0);
|
|
1431
|
-
} catch {
|
|
1432
|
-
rlKeyThrew = true;
|
|
1433
|
-
}
|
|
1434
|
-
if (!rlKeyThrew) {
|
|
1435
|
-
return false;
|
|
1436
|
-
}
|
|
1437
|
-
return true;
|
|
1438
|
-
}
|
|
1439
1424
|
var init_instances = __esm(() => {
|
|
1440
1425
|
init_codec2();
|
|
1441
1426
|
init_constants();
|
|
@@ -1634,123 +1619,14 @@ var init_metrics = __esm(() => {
|
|
|
1634
1619
|
EMPTY = new Uint8Array(0);
|
|
1635
1620
|
});
|
|
1636
1621
|
|
|
1637
|
-
// src/
|
|
1638
|
-
function
|
|
1639
|
-
if (
|
|
1640
|
-
return
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
bunFfiCodec2 = __require("bun:ffi");
|
|
1646
|
-
} catch {
|
|
1647
|
-
bunFfiCodec2 = null;
|
|
1648
|
-
}
|
|
1649
|
-
}
|
|
1650
|
-
}
|
|
1651
|
-
if (bunFfiCodec2) {
|
|
1652
|
-
return new bunFfiCodec2.CString(bunFfiCodec2.ptr(bytes), 0, bytes.byteLength).toString();
|
|
1653
|
-
}
|
|
1654
|
-
return decodeUtf8(bytes);
|
|
1655
|
-
}
|
|
1656
|
-
function decodeJsonPacked(bytes) {
|
|
1657
|
-
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
1658
|
-
let p = 0;
|
|
1659
|
-
const u32 = () => {
|
|
1660
|
-
const v = view.getUint32(p, true);
|
|
1661
|
-
p += 4;
|
|
1662
|
-
return v;
|
|
1663
|
-
};
|
|
1664
|
-
const strCount = u32();
|
|
1665
|
-
const strings = new Array(strCount);
|
|
1666
|
-
for (let i = 0;i < strCount; i++) {
|
|
1667
|
-
const n = u32();
|
|
1668
|
-
strings[i] = fastDecodeUtf8(bytes.subarray(p, p + n));
|
|
1669
|
-
p += n;
|
|
1670
|
-
}
|
|
1671
|
-
const treeLen = u32();
|
|
1672
|
-
const end = p + treeLen;
|
|
1673
|
-
let root;
|
|
1674
|
-
const frames = [];
|
|
1675
|
-
const popFrame = () => {
|
|
1676
|
-
const f = frames.pop();
|
|
1677
|
-
if (f === undefined)
|
|
1678
|
-
throw new Error("json parse: malformed packed stream");
|
|
1679
|
-
return f;
|
|
1680
|
-
};
|
|
1681
|
-
const attach = (v) => {
|
|
1682
|
-
const f = frames[frames.length - 1];
|
|
1683
|
-
if (f === undefined) {
|
|
1684
|
-
root = v;
|
|
1685
|
-
return;
|
|
1686
|
-
}
|
|
1687
|
-
if (f.isObj)
|
|
1688
|
-
f.obj[f.key] = v;
|
|
1689
|
-
else
|
|
1690
|
-
f.arr.push(v);
|
|
1691
|
-
};
|
|
1692
|
-
while (p < end) {
|
|
1693
|
-
const t = view.getUint8(p);
|
|
1694
|
-
p += 1;
|
|
1695
|
-
switch (t) {
|
|
1696
|
-
case TAG_NULL:
|
|
1697
|
-
attach(null);
|
|
1698
|
-
break;
|
|
1699
|
-
case TAG_FALSE:
|
|
1700
|
-
attach(false);
|
|
1701
|
-
break;
|
|
1702
|
-
case TAG_TRUE:
|
|
1703
|
-
attach(true);
|
|
1704
|
-
break;
|
|
1705
|
-
case TAG_NUMBER: {
|
|
1706
|
-
const v = view.getFloat64(p, true);
|
|
1707
|
-
p += 8;
|
|
1708
|
-
attach(v);
|
|
1709
|
-
break;
|
|
1710
|
-
}
|
|
1711
|
-
case TAG_STRING:
|
|
1712
|
-
attach(strings[u32()]);
|
|
1713
|
-
break;
|
|
1714
|
-
case TAG_ARRAY_START:
|
|
1715
|
-
frames.push({ isObj: false, arr: [], obj: {}, key: "" });
|
|
1716
|
-
break;
|
|
1717
|
-
case TAG_OBJECT_START:
|
|
1718
|
-
frames.push({ isObj: true, arr: [], obj: {}, key: "" });
|
|
1719
|
-
break;
|
|
1720
|
-
case TAG_ARRAY_END:
|
|
1721
|
-
attach(popFrame().arr);
|
|
1722
|
-
break;
|
|
1723
|
-
case TAG_OBJECT_END:
|
|
1724
|
-
attach(popFrame().obj);
|
|
1725
|
-
break;
|
|
1726
|
-
case TAG_KEY: {
|
|
1727
|
-
const f = frames[frames.length - 1];
|
|
1728
|
-
f.key = strings[u32()];
|
|
1729
|
-
break;
|
|
1730
|
-
}
|
|
1731
|
-
default:
|
|
1732
|
-
throw new Error("json parse: malformed packed token");
|
|
1733
|
-
}
|
|
1734
|
-
}
|
|
1735
|
-
if (p !== end || frames.length !== 0) {
|
|
1736
|
-
throw new Error("json parse: malformed packed stream");
|
|
1737
|
-
}
|
|
1738
|
-
return root;
|
|
1739
|
-
}
|
|
1740
|
-
var TAG_NULL = 0, TAG_FALSE = 1, TAG_TRUE = 2, TAG_NUMBER = 3, TAG_STRING = 4, TAG_ARRAY_START = 5, TAG_OBJECT_START = 6, TAG_ARRAY_END = 7, TAG_OBJECT_END = 8, TAG_KEY = 9, bunFfiCodec2;
|
|
1741
|
-
var init_json_packed = __esm(() => {
|
|
1742
|
-
init_codec2();
|
|
1743
|
-
init_runtime();
|
|
1744
|
-
});
|
|
1745
|
-
|
|
1746
|
-
// src/native/ffi/build/parse.ts
|
|
1747
|
-
function sseMemoEncode(slot, s) {
|
|
1748
|
-
if (s === slot.str)
|
|
1749
|
-
return slot.bytes;
|
|
1750
|
-
const bytes = encodeUtf8(s);
|
|
1751
|
-
slot.str = s;
|
|
1752
|
-
slot.bytes = bytes;
|
|
1753
|
-
return bytes;
|
|
1622
|
+
// src/native/ffi/build/parse.ts
|
|
1623
|
+
function sseMemoEncode(slot, s) {
|
|
1624
|
+
if (s === slot.str)
|
|
1625
|
+
return slot.bytes;
|
|
1626
|
+
const bytes = encodeUtf8(s);
|
|
1627
|
+
slot.str = s;
|
|
1628
|
+
slot.bytes = bytes;
|
|
1629
|
+
return bytes;
|
|
1754
1630
|
}
|
|
1755
1631
|
function buildParse(sym, ctx) {
|
|
1756
1632
|
const { lenOrView, scratchFor, dateScratch, dateScratchView } = ctx;
|
|
@@ -1911,13 +1787,635 @@ function buildParse(sym, ctx) {
|
|
|
1911
1787
|
if (w === 0) {
|
|
1912
1788
|
throw new Error("sse encode: invalid UTF-8 in event/id");
|
|
1913
1789
|
}
|
|
1914
|
-
if (w > output.length) {
|
|
1915
|
-
throw new Error("sse encode: output buffer too small");
|
|
1790
|
+
if (w > output.length) {
|
|
1791
|
+
throw new Error("sse encode: output buffer too small");
|
|
1792
|
+
}
|
|
1793
|
+
return w;
|
|
1794
|
+
}
|
|
1795
|
+
};
|
|
1796
|
+
}
|
|
1797
|
+
var sseMemoEvent, sseMemoId;
|
|
1798
|
+
var init_parse = __esm(() => {
|
|
1799
|
+
init_codec2();
|
|
1800
|
+
init_constants();
|
|
1801
|
+
init_util();
|
|
1802
|
+
sseMemoEvent = { str: null, bytes: EMPTY_VIEW };
|
|
1803
|
+
sseMemoId = { str: null, bytes: EMPTY_VIEW };
|
|
1804
|
+
});
|
|
1805
|
+
|
|
1806
|
+
// src/native/ffi/build/task.ts
|
|
1807
|
+
function buildTask(sym, ctx) {
|
|
1808
|
+
const { lenOrView } = ctx;
|
|
1809
|
+
const init = sym.castrum_task_init;
|
|
1810
|
+
const submit = sym.castrum_task_submit;
|
|
1811
|
+
const submitOut = sym.castrum_task_submit_out;
|
|
1812
|
+
const submitSlice = sym.castrum_task_submit_slice;
|
|
1813
|
+
const drain = sym.castrum_task_drain;
|
|
1814
|
+
const pending = sym.castrum_task_pending;
|
|
1815
|
+
const cancel = sym.castrum_task_cancel;
|
|
1816
|
+
const setDoorbell = sym.castrum_task_set_doorbell;
|
|
1817
|
+
const shutdown = sym.castrum_task_shutdown;
|
|
1818
|
+
const threads = sym.castrum_task_threads;
|
|
1819
|
+
return {
|
|
1820
|
+
taskInit: (n) => Number(init(n)),
|
|
1821
|
+
taskSubmit: (op, args, taskId) => Number(submit(op, args, lenOrView(args), taskId)),
|
|
1822
|
+
taskSubmitOut: (op, args, taskId, output) => Number(submitOut(op, args, lenOrView(args), taskId, output, lenOrView(output))),
|
|
1823
|
+
taskSubmitSlice: (op, hdr, data, taskId) => Number(submitSlice(op, hdr, lenOrView(hdr), data, lenOrView(data), taskId)),
|
|
1824
|
+
taskDrain: (output) => Number(drain(output, lenOrView(output))),
|
|
1825
|
+
taskPending: () => Number(pending()),
|
|
1826
|
+
taskCancel: (taskId) => Number(cancel(taskId)),
|
|
1827
|
+
taskSetDoorbell: (ptr) => Number(setDoorbell(ptr)),
|
|
1828
|
+
taskShutdown: () => Number(shutdown()),
|
|
1829
|
+
taskThreads: () => Number(threads())
|
|
1830
|
+
};
|
|
1831
|
+
}
|
|
1832
|
+
function selfTestTask(b) {
|
|
1833
|
+
try {
|
|
1834
|
+
if (typeof b.taskPending() !== "number")
|
|
1835
|
+
return false;
|
|
1836
|
+
if (typeof b.taskThreads() !== "number" || b.taskThreads() < 0)
|
|
1837
|
+
return false;
|
|
1838
|
+
if (b.taskSetDoorbell(0) !== 1)
|
|
1839
|
+
return false;
|
|
1840
|
+
if (typeof b.taskDrain(new Uint8Array(4)) !== "number")
|
|
1841
|
+
return false;
|
|
1842
|
+
if (typeof b.taskSubmitOut !== "function")
|
|
1843
|
+
return false;
|
|
1844
|
+
if (typeof b.taskSubmitSlice !== "function")
|
|
1845
|
+
return false;
|
|
1846
|
+
return true;
|
|
1847
|
+
} catch {
|
|
1848
|
+
return false;
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
// src/native/ffi/build.ts
|
|
1853
|
+
function build(sym, useBufferLength) {
|
|
1854
|
+
const oneArg = (raw, v) => useBufferLength ? raw(v, v) : raw(v, v.length);
|
|
1855
|
+
const lenOrView = (v) => useBufferLength ? v : v.length;
|
|
1856
|
+
let encodeScratch = new Uint8Array(0);
|
|
1857
|
+
const scratchFor = (size) => {
|
|
1858
|
+
if (encodeScratch.byteLength < size)
|
|
1859
|
+
encodeScratch = new Uint8Array(size);
|
|
1860
|
+
return encodeScratch;
|
|
1861
|
+
};
|
|
1862
|
+
const jsonSumOut = new Uint8Array(9);
|
|
1863
|
+
const jsonSumView = new DataView(jsonSumOut.buffer);
|
|
1864
|
+
const dateScratch = new Uint8Array(9);
|
|
1865
|
+
const dateScratchView = new DataView(dateScratch.buffer);
|
|
1866
|
+
const rateScratch = new Uint8Array(13);
|
|
1867
|
+
const rateScratchView = new DataView(rateScratch.buffer);
|
|
1868
|
+
const ctx = {
|
|
1869
|
+
useBufferLength,
|
|
1870
|
+
lenOrView,
|
|
1871
|
+
oneArg,
|
|
1872
|
+
scratchFor,
|
|
1873
|
+
jsonSumOut,
|
|
1874
|
+
jsonSumView,
|
|
1875
|
+
dateScratch,
|
|
1876
|
+
dateScratchView,
|
|
1877
|
+
rateScratch,
|
|
1878
|
+
rateScratchView
|
|
1879
|
+
};
|
|
1880
|
+
return {
|
|
1881
|
+
...buildCodecs(sym, ctx),
|
|
1882
|
+
...buildCompress(sym, ctx),
|
|
1883
|
+
...buildParse(sym, ctx),
|
|
1884
|
+
...buildInstances(sym, ctx),
|
|
1885
|
+
...buildMetrics(sym, ctx),
|
|
1886
|
+
...buildTask(sym, ctx)
|
|
1887
|
+
};
|
|
1888
|
+
}
|
|
1889
|
+
var init_build = __esm(() => {
|
|
1890
|
+
init_codecs();
|
|
1891
|
+
init_compress();
|
|
1892
|
+
init_instances();
|
|
1893
|
+
init_metrics();
|
|
1894
|
+
init_parse();
|
|
1895
|
+
});
|
|
1896
|
+
|
|
1897
|
+
// src/native/ffi/build/codecs-selftest.ts
|
|
1898
|
+
function selfTestCodecs(b) {
|
|
1899
|
+
const enc = { encode: encodeUtf8 };
|
|
1900
|
+
const dec = { decode: decodeUtf8 };
|
|
1901
|
+
if (b.crc32(enc.encode("123456789")) !== 3421780262)
|
|
1902
|
+
return false;
|
|
1903
|
+
if (b.fnv1a64(enc.encode("foobar")) !== 0x85944171f73967e8n)
|
|
1904
|
+
return false;
|
|
1905
|
+
if (b.xxh3(new Uint8Array(0)) !== 0x2d06800538d394c2n)
|
|
1906
|
+
return false;
|
|
1907
|
+
if (b.jsonValid(SELFTEST_JSON) !== true || b.jsonValid(enc.encode("{not json")) !== false) {
|
|
1908
|
+
return false;
|
|
1909
|
+
}
|
|
1910
|
+
if (!b.utf8Valid(enc.encode("héllo")) || b.utf8Valid(new Uint8Array([255, 254]))) {
|
|
1911
|
+
return false;
|
|
1912
|
+
}
|
|
1913
|
+
const hexOut = new Uint8Array(SELFTEST_HEX.length * 2);
|
|
1914
|
+
if (b.hexEncodeInto(SELFTEST_HEX, hexOut) !== 10 || dec.decode(hexOut) !== "68656c6c6f") {
|
|
1915
|
+
return false;
|
|
1916
|
+
}
|
|
1917
|
+
const urlInput = enc.encode("a b/c");
|
|
1918
|
+
const urlOut = new Uint8Array(9);
|
|
1919
|
+
if (b.urlEncodeInto(urlInput, urlOut) !== 9 || dec.decode(urlOut) !== "a%20b%2Fc") {
|
|
1920
|
+
return false;
|
|
1921
|
+
}
|
|
1922
|
+
if (!b.validateEmail("a@b.com") || !b.validateUuid("550e8400-e29b-41d4-a716-446655440000") || !b.validateIpv4("192.168.0.1") || !b.validateIpv6("2001:db8::1") || b.validateEmail("not-an-email") || b.validateUuid("not-a-uuid")) {
|
|
1923
|
+
return false;
|
|
1924
|
+
}
|
|
1925
|
+
if (!b.validateEmailBytes(enc.encode("a@b.com")) || !b.validateUuidBytes(enc.encode("550e8400-e29b-41d4-a716-446655440000")) || !b.validateIpv4Bytes(enc.encode("192.168.0.1")) || !b.validateIpv6Bytes(enc.encode("2001:db8::1")) || b.validateEmailBytes(enc.encode("not-an-email")) || b.validateIpv6Bytes(enc.encode("999"))) {
|
|
1926
|
+
return false;
|
|
1927
|
+
}
|
|
1928
|
+
if (b.jsonSumIds(enc.encode(`[{"id":1},{"id":2}]`)) !== 3n)
|
|
1929
|
+
return false;
|
|
1930
|
+
if (b.jsonSumIds(enc.encode(`[{"id":0},{"id":0}]`)) !== 0n)
|
|
1931
|
+
return false;
|
|
1932
|
+
let sumInvalidThrew = false;
|
|
1933
|
+
try {
|
|
1934
|
+
b.jsonSumIds(enc.encode("nope"));
|
|
1935
|
+
} catch {
|
|
1936
|
+
sumInvalidThrew = true;
|
|
1937
|
+
}
|
|
1938
|
+
if (!sumInvalidThrew)
|
|
1939
|
+
return false;
|
|
1940
|
+
{
|
|
1941
|
+
const ids = enc.encode(`507f1f77bcf86cd799439011
|
|
1942
|
+
zz
|
|
1943
|
+
507F1F77BCF86CD799439012`);
|
|
1944
|
+
const tiny = new Uint8Array(2);
|
|
1945
|
+
const needed = b.hexValidateBatchInto(ids, 24, tiny);
|
|
1946
|
+
if (needed !== 3)
|
|
1947
|
+
return false;
|
|
1948
|
+
const out = new Uint8Array(needed);
|
|
1949
|
+
if (b.hexValidateBatchInto(ids, 24, out) !== 3)
|
|
1950
|
+
return false;
|
|
1951
|
+
if (out[0] !== 1 || out[1] !== 0 || out[2] !== 1)
|
|
1952
|
+
return false;
|
|
1953
|
+
let widthThrew = false;
|
|
1954
|
+
try {
|
|
1955
|
+
b.hexValidateBatchInto(ids, 0, new Uint8Array(3));
|
|
1956
|
+
} catch {
|
|
1957
|
+
widthThrew = true;
|
|
1958
|
+
}
|
|
1959
|
+
if (!widthThrew)
|
|
1960
|
+
return false;
|
|
1961
|
+
}
|
|
1962
|
+
{
|
|
1963
|
+
const out = new Uint8Array(64);
|
|
1964
|
+
const w = b.regexEscapeInto(enc.encode("a.c(x)"), out);
|
|
1965
|
+
if (w !== 9 || dec.decode(out.subarray(0, w)) !== "a\\.c\\(x\\)")
|
|
1966
|
+
return false;
|
|
1967
|
+
const plain = new Uint8Array(16);
|
|
1968
|
+
const wp = b.regexEscapeInto(enc.encode("hello"), plain);
|
|
1969
|
+
if (wp !== 5 || dec.decode(plain.subarray(0, wp)) !== "hello")
|
|
1970
|
+
return false;
|
|
1971
|
+
if (b.regexEscapeInto(enc.encode("a.b"), new Uint8Array(2)) !== 4)
|
|
1972
|
+
return false;
|
|
1973
|
+
if (b.regexEscapeStr("a.c(x)") !== "a\\.c\\(x\\)")
|
|
1974
|
+
return false;
|
|
1975
|
+
if (b.regexEscapeStr("plain text") !== "plain text")
|
|
1976
|
+
return false;
|
|
1977
|
+
}
|
|
1978
|
+
{
|
|
1979
|
+
const out = new Uint8Array(8);
|
|
1980
|
+
const w = b.hexValidateBatchStr(`507f1f77bcf86cd799439011
|
|
1981
|
+
zz`, 24, out);
|
|
1982
|
+
if (w !== 2 || out[0] !== 1 || out[1] !== 0)
|
|
1983
|
+
return false;
|
|
1984
|
+
}
|
|
1985
|
+
const hmacKey = new Uint8Array(20).fill(11);
|
|
1986
|
+
const hmacData = enc.encode("Hi There");
|
|
1987
|
+
const hmacSig = enc.encode("b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7");
|
|
1988
|
+
if (b.hmacSha256(hmacKey, hmacData) !== "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7") {
|
|
1989
|
+
return false;
|
|
1990
|
+
}
|
|
1991
|
+
if (!b.hmacSha256Verify(hmacKey, hmacData, hmacSig)) {
|
|
1992
|
+
return false;
|
|
1993
|
+
}
|
|
1994
|
+
const decoded = b.hexDecode(enc.encode("68656c6c6f"));
|
|
1995
|
+
if (dec.decode(decoded) !== "hello" || dec.decode(b.urlDecode(enc.encode("a%20b%2Fc"))) !== "a b/c") {
|
|
1996
|
+
return false;
|
|
1997
|
+
}
|
|
1998
|
+
if (b.wsAcceptKey("dGhlIHNhbXBsZSBub25jZQ==") !== "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=") {
|
|
1999
|
+
return false;
|
|
2000
|
+
}
|
|
2001
|
+
if (b.etag(SELFTEST_HEX).length !== 10 || b.etag(SELFTEST_HEX, true).length !== 12) {
|
|
2002
|
+
return false;
|
|
2003
|
+
}
|
|
2004
|
+
if (b.base64Encode(SELFTEST_HEX) !== "aGVsbG8=") {
|
|
2005
|
+
return false;
|
|
2006
|
+
}
|
|
2007
|
+
if (dec.decode(b.base64Decode(enc.encode("aGVsbG8="))) !== "hello") {
|
|
2008
|
+
return false;
|
|
2009
|
+
}
|
|
2010
|
+
const secret = enc.encode("s3cr3t-secret");
|
|
2011
|
+
const signed = b.signCookie(SELFTEST_HEX, secret);
|
|
2012
|
+
const verified = b.verifyCookie(enc.encode(signed), secret);
|
|
2013
|
+
if (verified === null || verified !== "hello") {
|
|
2014
|
+
return false;
|
|
2015
|
+
}
|
|
2016
|
+
if (b.verifyCookie(enc.encode("tampered.0000"), secret) !== null) {
|
|
2017
|
+
return false;
|
|
2018
|
+
}
|
|
2019
|
+
const csrfTokenStr = b.csrfToken(secret);
|
|
2020
|
+
if (csrfTokenStr.length !== 129 || !b.csrfVerify(enc.encode(csrfTokenStr), secret)) {
|
|
2021
|
+
return false;
|
|
2022
|
+
}
|
|
2023
|
+
const pw = enc.encode("correct horse battery staple");
|
|
2024
|
+
const salt = enc.encode("salty-salt-16b");
|
|
2025
|
+
const phc = b.passwordHash(pw, salt, 8, 1, 1, 16);
|
|
2026
|
+
if (phc.length === 0 || !b.passwordVerify(pw, enc.encode(phc))) {
|
|
2027
|
+
return false;
|
|
2028
|
+
}
|
|
2029
|
+
const bcryptPhc = b.passwordHashBcrypt(pw, 4);
|
|
2030
|
+
if (bcryptPhc.length === 0 || !b.passwordVerifyBcrypt(pw, bcryptPhc)) {
|
|
2031
|
+
return false;
|
|
2032
|
+
}
|
|
2033
|
+
const dk = b.pbkdf2Sha256(enc.encode("password"), enc.encode("salt"), 1, 32);
|
|
2034
|
+
if (b.hexEncode(dk) !== "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b") {
|
|
2035
|
+
return false;
|
|
2036
|
+
}
|
|
2037
|
+
const aeadKey = new Uint8Array(32).fill(66);
|
|
2038
|
+
const nonce = new Uint8Array(12).fill(7);
|
|
2039
|
+
const ct = b.aeadEncrypt(aeadKey, nonce, SELFTEST_HEX, 0);
|
|
2040
|
+
const pt = b.aeadDecrypt(aeadKey, nonce, ct, 0);
|
|
2041
|
+
if (pt === null || dec.decode(pt) !== "hello") {
|
|
2042
|
+
return false;
|
|
2043
|
+
}
|
|
2044
|
+
const rtOut = new Uint8Array(32);
|
|
2045
|
+
const rtW = b.randomTokenInto(16, rtOut);
|
|
2046
|
+
if (rtW !== 32 || !/^[0-9a-f]{32}$/.test(dec.decode(rtOut))) {
|
|
2047
|
+
return false;
|
|
2048
|
+
}
|
|
2049
|
+
try {
|
|
2050
|
+
b.randomTokenInto(16, new Uint8Array(8));
|
|
2051
|
+
return false;
|
|
2052
|
+
} catch {}
|
|
2053
|
+
const waOut = new Uint8Array(28);
|
|
2054
|
+
const waW = b.wsAcceptKeyInto(enc.encode("dGhlIHNhbXBsZSBub25jZQ=="), waOut);
|
|
2055
|
+
const waExpected = b.wsAcceptKey("dGhlIHNhbXBsZSBub25jZQ==");
|
|
2056
|
+
if (waW !== 28 || dec.decode(waOut) !== waExpected) {
|
|
2057
|
+
return false;
|
|
2058
|
+
}
|
|
2059
|
+
const etagData = enc.encode("hello");
|
|
2060
|
+
const etagOut = new Uint8Array(16);
|
|
2061
|
+
const etagW = b.etagInto(etagData, etagOut);
|
|
2062
|
+
if (etagW !== 10 || dec.decode(etagOut.subarray(0, etagW)) !== b.etag(etagData)) {
|
|
2063
|
+
return false;
|
|
2064
|
+
}
|
|
2065
|
+
const csrfOut = new Uint8Array(129);
|
|
2066
|
+
const csrfW = b.csrfTokenInto(enc.encode("csrf-secret"), csrfOut);
|
|
2067
|
+
if (csrfW !== 129 || csrfOut[64] !== 46) {
|
|
2068
|
+
return false;
|
|
2069
|
+
}
|
|
2070
|
+
const ckVal = enc.encode("session-value");
|
|
2071
|
+
const ckSec = enc.encode("s3cr3t-secret");
|
|
2072
|
+
const ckOut = new Uint8Array(256);
|
|
2073
|
+
const ckW = b.signCookieInto(ckVal, ckSec, ckOut);
|
|
2074
|
+
if (ckW !== ckVal.length + 65) {
|
|
2075
|
+
return false;
|
|
2076
|
+
}
|
|
2077
|
+
const ckVerifyOut = new Uint8Array(256);
|
|
2078
|
+
const ckV = b.verifyCookieInto(ckOut.subarray(0, ckW), ckSec, ckVerifyOut);
|
|
2079
|
+
if (ckV !== ckVal.length || dec.decode(ckVerifyOut.subarray(0, ckV)) !== "session-value") {
|
|
2080
|
+
return false;
|
|
2081
|
+
}
|
|
2082
|
+
if (b.urlEncode(enc.encode("a b/c")) !== "a%20b%2Fc") {
|
|
2083
|
+
return false;
|
|
2084
|
+
}
|
|
2085
|
+
const hdInto = new Uint8Array(8);
|
|
2086
|
+
if (b.hexDecodeInto(enc.encode("68656c6c6f"), hdInto) !== 5 || dec.decode(hdInto.subarray(0, 5)) !== "hello") {
|
|
2087
|
+
return false;
|
|
2088
|
+
}
|
|
2089
|
+
const udInto = new Uint8Array(16);
|
|
2090
|
+
if (b.urlDecodeInto(enc.encode("a%20b%2Fc"), udInto) !== 5 || dec.decode(udInto.subarray(0, 5)) !== "a b/c") {
|
|
2091
|
+
return false;
|
|
2092
|
+
}
|
|
2093
|
+
const b64Into = new Uint8Array(16);
|
|
2094
|
+
if (b.base64EncodeInto(SELFTEST_HEX, b64Into) !== 8 || dec.decode(b64Into.subarray(0, 8)) !== "aGVsbG8=") {
|
|
2095
|
+
return false;
|
|
2096
|
+
}
|
|
2097
|
+
const bdInto = new Uint8Array(8);
|
|
2098
|
+
if (b.base64DecodeInto(enc.encode("aGVsbG8="), bdInto) !== 5 || dec.decode(bdInto.subarray(0, 5)) !== "hello") {
|
|
2099
|
+
return false;
|
|
2100
|
+
}
|
|
2101
|
+
if (!/^[0-9a-f]{32}$/.test(b.randomToken(16))) {
|
|
2102
|
+
return false;
|
|
2103
|
+
}
|
|
2104
|
+
const hmacInto = new Uint8Array(64);
|
|
2105
|
+
if (b.hmacSha256Into(hmacKey, hmacData, hmacInto) !== 64 || dec.decode(hmacInto) !== "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7") {
|
|
2106
|
+
return false;
|
|
2107
|
+
}
|
|
2108
|
+
const ctInto = new Uint8Array(64);
|
|
2109
|
+
const ctW = b.aeadEncryptInto(aeadKey, nonce, SELFTEST_HEX, ctInto, 0);
|
|
2110
|
+
if (ctW === 0 || b.aeadDecrypt(aeadKey, nonce, ctInto.subarray(0, ctW), 0) === null) {
|
|
2111
|
+
return false;
|
|
2112
|
+
}
|
|
2113
|
+
return true;
|
|
2114
|
+
}
|
|
2115
|
+
var init_codecs_selftest = __esm(() => {
|
|
2116
|
+
init_codec2();
|
|
2117
|
+
init_constants();
|
|
2118
|
+
});
|
|
2119
|
+
|
|
2120
|
+
// src/native/ffi/build/instances-selftest.ts
|
|
2121
|
+
function selfTestInstances(b) {
|
|
2122
|
+
const enc = { encode: encodeUtf8 };
|
|
2123
|
+
const dec = { decode: decodeUtf8 };
|
|
2124
|
+
const layoutBuf = new Uint8Array(38 * 4);
|
|
2125
|
+
b.ingressLayout(layoutBuf);
|
|
2126
|
+
const layoutView = new DataView(layoutBuf.buffer, layoutBuf.byteOffset, layoutBuf.byteLength);
|
|
2127
|
+
if (layoutView.getUint32(0, true) !== 0 || layoutView.getUint32(2 * 4, true) !== 2 || layoutView.getUint32(12 * 4, true) !== 48 || layoutView.getUint32(13 * 4, true) !== 1 || layoutView.getUint32(28 * 4, true) !== 32 || layoutView.getUint32(37 * 4, true) !== 8) {
|
|
2128
|
+
return false;
|
|
2129
|
+
}
|
|
2130
|
+
try {
|
|
2131
|
+
b.ingressHandlePacked(0, enc.encode("/"), null, new Uint8Array(64));
|
|
2132
|
+
return false;
|
|
2133
|
+
} catch {}
|
|
2134
|
+
try {
|
|
2135
|
+
b.ingressHandleComponents(0, 0, "/", "", enc.encode("rid"), new Uint8Array(2), null, new Uint8Array(64));
|
|
2136
|
+
return false;
|
|
2137
|
+
} catch {}
|
|
2138
|
+
const routeDesc = new Uint8Array(33);
|
|
2139
|
+
const rd = new DataView(routeDesc.buffer);
|
|
2140
|
+
rd.setUint32(0, 1380930900, true);
|
|
2141
|
+
rd.setUint32(4, 3, true);
|
|
2142
|
+
rd.setUint32(8, 2 * 1024 * 1024, true);
|
|
2143
|
+
rd.setUint32(12, 8192, true);
|
|
2144
|
+
rd.setUint32(16, 8192, true);
|
|
2145
|
+
rd.setUint32(20, 0, true);
|
|
2146
|
+
rd.setUint32(24, 1, true);
|
|
2147
|
+
routeDesc[28] = 0;
|
|
2148
|
+
rd.setUint32(29, 0, true);
|
|
2149
|
+
const routeHandle = b.routeCompile(routeDesc);
|
|
2150
|
+
if (routeHandle === 0) {
|
|
2151
|
+
return false;
|
|
2152
|
+
}
|
|
2153
|
+
const routeFrame = new Uint8Array(15);
|
|
2154
|
+
const rf = new DataView(routeFrame.buffer);
|
|
2155
|
+
rf.setUint32(0, 0, true);
|
|
2156
|
+
rf.setUint32(4, 3, true);
|
|
2157
|
+
routeFrame.set(enc.encode("a=1"), 8);
|
|
2158
|
+
rf.setUint32(11, 0, true);
|
|
2159
|
+
const routeOut = new Uint8Array(64);
|
|
2160
|
+
const routeW = b.routeRun(routeHandle, routeFrame, routeOut);
|
|
2161
|
+
if (routeW <= 8) {
|
|
2162
|
+
return false;
|
|
2163
|
+
}
|
|
2164
|
+
const rv = new DataView(routeOut.buffer);
|
|
2165
|
+
const rFlags = rv.getUint32(0, true);
|
|
2166
|
+
if ((rFlags & 1) === 0 || (rFlags & 4) === 0) {
|
|
2167
|
+
return false;
|
|
2168
|
+
}
|
|
2169
|
+
b.routeDestroy(routeHandle);
|
|
2170
|
+
if (b.conditionalIsNotModified(0, null, null) !== false) {
|
|
2171
|
+
return false;
|
|
2172
|
+
}
|
|
2173
|
+
if (b.mediaTypeMatcherMatches(0, enc.encode("x")) !== false)
|
|
2174
|
+
return false;
|
|
2175
|
+
if (b.acceptNegotiatorNegotiate(0, enc.encode("gzip")) !== null)
|
|
2176
|
+
return false;
|
|
2177
|
+
if (b.acceptNegotiatorNegotiateServer(0, enc.encode("gzip")) !== null)
|
|
2178
|
+
return false;
|
|
2179
|
+
if (b.schemaValidatorValidate(0, enc.encode("{}")) !== false)
|
|
2180
|
+
return false;
|
|
2181
|
+
if (b.jwtSignerVerify(0, enc.encode("a.b.c"), 0) !== null)
|
|
2182
|
+
return false;
|
|
2183
|
+
let phase6Threw = false;
|
|
2184
|
+
try {
|
|
2185
|
+
b.jwtSignerSign(0, enc.encode("{}"), 0);
|
|
2186
|
+
} catch {
|
|
2187
|
+
phase6Threw = true;
|
|
2188
|
+
}
|
|
2189
|
+
if (!phase6Threw)
|
|
2190
|
+
return false;
|
|
2191
|
+
phase6Threw = false;
|
|
2192
|
+
try {
|
|
2193
|
+
b.templateRender(0, enc.encode("{}"));
|
|
2194
|
+
} catch {
|
|
2195
|
+
phase6Threw = true;
|
|
2196
|
+
}
|
|
2197
|
+
if (!phase6Threw)
|
|
2198
|
+
return false;
|
|
2199
|
+
phase6Threw = false;
|
|
2200
|
+
try {
|
|
2201
|
+
b.rateLimiterCheck(0, "k", 0);
|
|
2202
|
+
} catch {
|
|
2203
|
+
phase6Threw = true;
|
|
2204
|
+
}
|
|
2205
|
+
if (!phase6Threw)
|
|
2206
|
+
return false;
|
|
2207
|
+
const jwtClaims = enc.encode('{"sub":"user-1"}');
|
|
2208
|
+
const jwtSecret2 = enc.encode("my-secret");
|
|
2209
|
+
const jwtOut = new Uint8Array(512);
|
|
2210
|
+
const jwtW = b.jwtSignBytesInto(jwtClaims, jwtSecret2, 0, 0, jwtOut);
|
|
2211
|
+
if (jwtW === 0 || dec.decode(jwtOut.subarray(0, jwtW)).split(".").length !== 3) {
|
|
2212
|
+
return false;
|
|
2213
|
+
}
|
|
2214
|
+
const jwtSecret = enc.encode("my-secret");
|
|
2215
|
+
const jwt = b.jwtSignBytes(enc.encode('{"sub":"user-1"}'), jwtSecret, 0, 0);
|
|
2216
|
+
const jwtStr = jwt;
|
|
2217
|
+
const segs = jwtStr.split(".");
|
|
2218
|
+
if (segs.length !== 3 || segs[0] === "" || segs[1] === "" || segs[2] === "") {
|
|
2219
|
+
return false;
|
|
2220
|
+
}
|
|
2221
|
+
const signingInput = enc.encode(`${segs[0]}.${segs[1]}`);
|
|
2222
|
+
const sigHex = b.hmacSha256(jwtSecret, signingInput);
|
|
2223
|
+
const sigBytes = b.base64Decode(enc.encode(segs[2] ?? ""), true, false);
|
|
2224
|
+
if (sigBytes === null || b.hexEncode(sigBytes) !== sigHex) {
|
|
2225
|
+
return false;
|
|
2226
|
+
}
|
|
2227
|
+
const vjwtSecret = enc.encode("verify-secret");
|
|
2228
|
+
const vjwt = b.jwtSignBytes(enc.encode('{"sub":"u-1"}'), vjwtSecret, 0, 0);
|
|
2229
|
+
const vjwtClaims = b.jwtVerify(enc.encode(vjwt), vjwtSecret, 0);
|
|
2230
|
+
if (vjwtClaims === null || !vjwtClaims.includes('"sub":"u-1"')) {
|
|
2231
|
+
return false;
|
|
2232
|
+
}
|
|
2233
|
+
if (b.jwtVerify(enc.encode("tampered.token.value"), vjwtSecret, 0) !== null) {
|
|
2234
|
+
return false;
|
|
2235
|
+
}
|
|
2236
|
+
const edKp = b.ed25519GenerateKeypair();
|
|
2237
|
+
const edMsg = enc.encode("ed25519 bind-time self-test");
|
|
2238
|
+
const edSig = b.ed25519Sign(edMsg, edKp.privateKey);
|
|
2239
|
+
if (edSig.byteLength !== 64 || !b.ed25519Verify(edMsg, edSig, edKp.publicKey)) {
|
|
2240
|
+
return false;
|
|
2241
|
+
}
|
|
2242
|
+
const edTampered = edSig.slice();
|
|
2243
|
+
edTampered[0] = (edTampered[0] ?? 0) ^ 255;
|
|
2244
|
+
if (b.ed25519Verify(edMsg, edTampered, edKp.publicKey)) {
|
|
2245
|
+
return false;
|
|
2246
|
+
}
|
|
2247
|
+
const edToken = b.jwtEdDSASign(enc.encode('{"sub":"ffi-self-test"}'), edKp.privateKey, 0, 0);
|
|
2248
|
+
if (edToken === null || edToken.split(".").length !== 3) {
|
|
2249
|
+
return false;
|
|
2250
|
+
}
|
|
2251
|
+
const edClaims = b.jwtEdDSAVerify(enc.encode(edToken), edKp.publicKey, 0);
|
|
2252
|
+
if (edClaims === null || !edClaims.includes('"sub":"ffi-self-test"')) {
|
|
2253
|
+
return false;
|
|
2254
|
+
}
|
|
2255
|
+
if (b.jwtEdDSAVerify(enc.encode("tampered.token.value"), edKp.publicKey, 0) !== null) {
|
|
2256
|
+
return false;
|
|
2257
|
+
}
|
|
2258
|
+
let urlBuilderThrew = false;
|
|
2259
|
+
try {
|
|
2260
|
+
b.urlBuilderResolve(0, enc.encode("g"));
|
|
2261
|
+
} catch {
|
|
2262
|
+
urlBuilderThrew = true;
|
|
2263
|
+
}
|
|
2264
|
+
if (!urlBuilderThrew) {
|
|
2265
|
+
return false;
|
|
2266
|
+
}
|
|
2267
|
+
if (b.queryValidate(0, "route=/a") !== false)
|
|
2268
|
+
return false;
|
|
2269
|
+
if (b.cookieValidate(0, "route=/a") !== false)
|
|
2270
|
+
return false;
|
|
2271
|
+
{
|
|
2272
|
+
const tok = b.sessionSeal("sess-9", '{"n":1}', 1234567, "sekrit");
|
|
2273
|
+
if (tok === null || !tok.includes(".") || !tok.startsWith('{"id":"sess-9"'))
|
|
2274
|
+
return false;
|
|
2275
|
+
const out = new Uint8Array(256);
|
|
2276
|
+
const w = b.sessionOpen(tok, "sekrit", out);
|
|
2277
|
+
if (w <= 13 || out[0] !== 1)
|
|
2278
|
+
return false;
|
|
2279
|
+
if (b.sessionOpen(tok, "wrong", out) !== 0)
|
|
2280
|
+
return false;
|
|
2281
|
+
const enc = new TextEncoder;
|
|
2282
|
+
const tokB = b.sessionSealBytes(enc.encode("sess-9"), enc.encode('{"n":1}'), 1234567, enc.encode("sekrit"));
|
|
2283
|
+
if (tokB === null || tokB !== tok)
|
|
2284
|
+
return false;
|
|
2285
|
+
const outB = new Uint8Array(256);
|
|
2286
|
+
const wB = b.sessionOpenBytes(enc.encode(tokB), enc.encode("sekrit"), outB);
|
|
2287
|
+
if (wB !== w || outB[0] !== 1)
|
|
2288
|
+
return false;
|
|
2289
|
+
if (b.sessionOpenBytes(enc.encode(tokB), enc.encode("wrong"), outB) !== 0)
|
|
2290
|
+
return false;
|
|
2291
|
+
if (b.sessionOpenBytes(enc.encode(tokB), enc.encode("sekrit"), outB.subarray(0, 4)) !== wB)
|
|
2292
|
+
return false;
|
|
2293
|
+
}
|
|
2294
|
+
let rlKeyThrew = false;
|
|
2295
|
+
try {
|
|
2296
|
+
b.rateLimiterCheckKey(0, 12345, 0);
|
|
2297
|
+
} catch {
|
|
2298
|
+
rlKeyThrew = true;
|
|
2299
|
+
}
|
|
2300
|
+
if (!rlKeyThrew) {
|
|
2301
|
+
return false;
|
|
2302
|
+
}
|
|
2303
|
+
return true;
|
|
2304
|
+
}
|
|
2305
|
+
var init_instances_selftest = __esm(() => {
|
|
2306
|
+
init_codec2();
|
|
2307
|
+
});
|
|
2308
|
+
|
|
2309
|
+
// src/rust-ffi/scalar/json-packed.ts
|
|
2310
|
+
function fastDecodeUtf8(bytes) {
|
|
2311
|
+
if (bytes.byteLength === 0)
|
|
2312
|
+
return "";
|
|
2313
|
+
if (bunFfiCodec2 === undefined) {
|
|
2314
|
+
bunFfiCodec2 = null;
|
|
2315
|
+
if (isBun()) {
|
|
2316
|
+
try {
|
|
2317
|
+
bunFfiCodec2 = __require("bun:ffi");
|
|
2318
|
+
} catch {
|
|
2319
|
+
bunFfiCodec2 = null;
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
}
|
|
2323
|
+
if (bunFfiCodec2) {
|
|
2324
|
+
return new bunFfiCodec2.CString(bunFfiCodec2.ptr(bytes), 0, bytes.byteLength).toString();
|
|
2325
|
+
}
|
|
2326
|
+
return decodeUtf8(bytes);
|
|
2327
|
+
}
|
|
2328
|
+
function decodeJsonPacked(bytes) {
|
|
2329
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
2330
|
+
let p = 0;
|
|
2331
|
+
const u32 = () => {
|
|
2332
|
+
const v = view.getUint32(p, true);
|
|
2333
|
+
p += 4;
|
|
2334
|
+
return v;
|
|
2335
|
+
};
|
|
2336
|
+
const strCount = u32();
|
|
2337
|
+
const strings = new Array(strCount);
|
|
2338
|
+
for (let i = 0;i < strCount; i++) {
|
|
2339
|
+
const n = u32();
|
|
2340
|
+
strings[i] = fastDecodeUtf8(bytes.subarray(p, p + n));
|
|
2341
|
+
p += n;
|
|
2342
|
+
}
|
|
2343
|
+
const treeLen = u32();
|
|
2344
|
+
const end = p + treeLen;
|
|
2345
|
+
let root;
|
|
2346
|
+
const frames = [];
|
|
2347
|
+
const popFrame = () => {
|
|
2348
|
+
const f = frames.pop();
|
|
2349
|
+
if (f === undefined)
|
|
2350
|
+
throw new Error("json parse: malformed packed stream");
|
|
2351
|
+
return f;
|
|
2352
|
+
};
|
|
2353
|
+
const attach = (v) => {
|
|
2354
|
+
const f = frames[frames.length - 1];
|
|
2355
|
+
if (f === undefined) {
|
|
2356
|
+
root = v;
|
|
2357
|
+
return;
|
|
2358
|
+
}
|
|
2359
|
+
if (f.isObj)
|
|
2360
|
+
f.obj[f.key] = v;
|
|
2361
|
+
else
|
|
2362
|
+
f.arr.push(v);
|
|
2363
|
+
};
|
|
2364
|
+
while (p < end) {
|
|
2365
|
+
const t = view.getUint8(p);
|
|
2366
|
+
p += 1;
|
|
2367
|
+
switch (t) {
|
|
2368
|
+
case TAG_NULL:
|
|
2369
|
+
attach(null);
|
|
2370
|
+
break;
|
|
2371
|
+
case TAG_FALSE:
|
|
2372
|
+
attach(false);
|
|
2373
|
+
break;
|
|
2374
|
+
case TAG_TRUE:
|
|
2375
|
+
attach(true);
|
|
2376
|
+
break;
|
|
2377
|
+
case TAG_NUMBER: {
|
|
2378
|
+
const v = view.getFloat64(p, true);
|
|
2379
|
+
p += 8;
|
|
2380
|
+
attach(v);
|
|
2381
|
+
break;
|
|
2382
|
+
}
|
|
2383
|
+
case TAG_STRING:
|
|
2384
|
+
attach(strings[u32()]);
|
|
2385
|
+
break;
|
|
2386
|
+
case TAG_ARRAY_START:
|
|
2387
|
+
frames.push({ isObj: false, arr: [], obj: {}, key: "" });
|
|
2388
|
+
break;
|
|
2389
|
+
case TAG_OBJECT_START:
|
|
2390
|
+
frames.push({ isObj: true, arr: [], obj: {}, key: "" });
|
|
2391
|
+
break;
|
|
2392
|
+
case TAG_ARRAY_END:
|
|
2393
|
+
attach(popFrame().arr);
|
|
2394
|
+
break;
|
|
2395
|
+
case TAG_OBJECT_END:
|
|
2396
|
+
attach(popFrame().obj);
|
|
2397
|
+
break;
|
|
2398
|
+
case TAG_KEY: {
|
|
2399
|
+
const f = frames[frames.length - 1];
|
|
2400
|
+
f.key = strings[u32()];
|
|
2401
|
+
break;
|
|
1916
2402
|
}
|
|
1917
|
-
|
|
2403
|
+
default:
|
|
2404
|
+
throw new Error("json parse: malformed packed token");
|
|
1918
2405
|
}
|
|
1919
|
-
}
|
|
2406
|
+
}
|
|
2407
|
+
if (p !== end || frames.length !== 0) {
|
|
2408
|
+
throw new Error("json parse: malformed packed stream");
|
|
2409
|
+
}
|
|
2410
|
+
return root;
|
|
1920
2411
|
}
|
|
2412
|
+
var TAG_NULL = 0, TAG_FALSE = 1, TAG_TRUE = 2, TAG_NUMBER = 3, TAG_STRING = 4, TAG_ARRAY_START = 5, TAG_OBJECT_START = 6, TAG_ARRAY_END = 7, TAG_OBJECT_END = 8, TAG_KEY = 9, bunFfiCodec2;
|
|
2413
|
+
var init_json_packed = __esm(() => {
|
|
2414
|
+
init_codec2();
|
|
2415
|
+
init_runtime();
|
|
2416
|
+
});
|
|
2417
|
+
|
|
2418
|
+
// src/native/ffi/build/parse-selftest.ts
|
|
1921
2419
|
function selfTestParse(b) {
|
|
1922
2420
|
const enc = { encode: encodeUtf8 };
|
|
1923
2421
|
const dec = { decode: decodeUtf8 };
|
|
@@ -2096,105 +2594,10 @@ data: hello
|
|
|
2096
2594
|
}
|
|
2097
2595
|
return true;
|
|
2098
2596
|
}
|
|
2099
|
-
var
|
|
2100
|
-
var init_parse = __esm(() => {
|
|
2597
|
+
var init_parse_selftest = __esm(() => {
|
|
2101
2598
|
init_json_packed();
|
|
2102
2599
|
init_codec2();
|
|
2103
2600
|
init_constants();
|
|
2104
|
-
init_util();
|
|
2105
|
-
sseMemoEvent = { str: null, bytes: EMPTY_VIEW };
|
|
2106
|
-
sseMemoId = { str: null, bytes: EMPTY_VIEW };
|
|
2107
|
-
});
|
|
2108
|
-
|
|
2109
|
-
// src/native/ffi/build/task.ts
|
|
2110
|
-
function buildTask(sym, ctx) {
|
|
2111
|
-
const { lenOrView } = ctx;
|
|
2112
|
-
const init = sym.castrum_task_init;
|
|
2113
|
-
const submit = sym.castrum_task_submit;
|
|
2114
|
-
const submitOut = sym.castrum_task_submit_out;
|
|
2115
|
-
const submitSlice = sym.castrum_task_submit_slice;
|
|
2116
|
-
const drain = sym.castrum_task_drain;
|
|
2117
|
-
const pending = sym.castrum_task_pending;
|
|
2118
|
-
const cancel = sym.castrum_task_cancel;
|
|
2119
|
-
const setDoorbell = sym.castrum_task_set_doorbell;
|
|
2120
|
-
const shutdown = sym.castrum_task_shutdown;
|
|
2121
|
-
const threads = sym.castrum_task_threads;
|
|
2122
|
-
return {
|
|
2123
|
-
taskInit: (n) => Number(init(n)),
|
|
2124
|
-
taskSubmit: (op, args, taskId) => Number(submit(op, args, lenOrView(args), taskId)),
|
|
2125
|
-
taskSubmitOut: (op, args, taskId, output) => Number(submitOut(op, args, lenOrView(args), taskId, output, lenOrView(output))),
|
|
2126
|
-
taskSubmitSlice: (op, hdr, data, taskId) => Number(submitSlice(op, hdr, lenOrView(hdr), data, lenOrView(data), taskId)),
|
|
2127
|
-
taskDrain: (output) => Number(drain(output, lenOrView(output))),
|
|
2128
|
-
taskPending: () => Number(pending()),
|
|
2129
|
-
taskCancel: (taskId) => Number(cancel(taskId)),
|
|
2130
|
-
taskSetDoorbell: (ptr) => Number(setDoorbell(ptr)),
|
|
2131
|
-
taskShutdown: () => Number(shutdown()),
|
|
2132
|
-
taskThreads: () => Number(threads())
|
|
2133
|
-
};
|
|
2134
|
-
}
|
|
2135
|
-
function selfTestTask(b) {
|
|
2136
|
-
try {
|
|
2137
|
-
if (typeof b.taskPending() !== "number")
|
|
2138
|
-
return false;
|
|
2139
|
-
if (typeof b.taskThreads() !== "number" || b.taskThreads() < 0)
|
|
2140
|
-
return false;
|
|
2141
|
-
if (b.taskSetDoorbell(0) !== 1)
|
|
2142
|
-
return false;
|
|
2143
|
-
if (typeof b.taskDrain(new Uint8Array(4)) !== "number")
|
|
2144
|
-
return false;
|
|
2145
|
-
if (typeof b.taskSubmitOut !== "function")
|
|
2146
|
-
return false;
|
|
2147
|
-
if (typeof b.taskSubmitSlice !== "function")
|
|
2148
|
-
return false;
|
|
2149
|
-
return true;
|
|
2150
|
-
} catch {
|
|
2151
|
-
return false;
|
|
2152
|
-
}
|
|
2153
|
-
}
|
|
2154
|
-
|
|
2155
|
-
// src/native/ffi/build.ts
|
|
2156
|
-
function build(sym, useBufferLength) {
|
|
2157
|
-
const oneArg = (raw, v) => useBufferLength ? raw(v, v) : raw(v, v.length);
|
|
2158
|
-
const lenOrView = (v) => useBufferLength ? v : v.length;
|
|
2159
|
-
let encodeScratch = new Uint8Array(0);
|
|
2160
|
-
const scratchFor = (size) => {
|
|
2161
|
-
if (encodeScratch.byteLength < size)
|
|
2162
|
-
encodeScratch = new Uint8Array(size);
|
|
2163
|
-
return encodeScratch;
|
|
2164
|
-
};
|
|
2165
|
-
const jsonSumOut = new Uint8Array(9);
|
|
2166
|
-
const jsonSumView = new DataView(jsonSumOut.buffer);
|
|
2167
|
-
const dateScratch = new Uint8Array(9);
|
|
2168
|
-
const dateScratchView = new DataView(dateScratch.buffer);
|
|
2169
|
-
const rateScratch = new Uint8Array(13);
|
|
2170
|
-
const rateScratchView = new DataView(rateScratch.buffer);
|
|
2171
|
-
const ctx = {
|
|
2172
|
-
useBufferLength,
|
|
2173
|
-
lenOrView,
|
|
2174
|
-
oneArg,
|
|
2175
|
-
scratchFor,
|
|
2176
|
-
jsonSumOut,
|
|
2177
|
-
jsonSumView,
|
|
2178
|
-
dateScratch,
|
|
2179
|
-
dateScratchView,
|
|
2180
|
-
rateScratch,
|
|
2181
|
-
rateScratchView
|
|
2182
|
-
};
|
|
2183
|
-
return {
|
|
2184
|
-
...buildCodecs(sym, ctx),
|
|
2185
|
-
...buildCompress(sym, ctx),
|
|
2186
|
-
...buildParse(sym, ctx),
|
|
2187
|
-
...buildInstances(sym, ctx),
|
|
2188
|
-
...buildMetrics(sym, ctx),
|
|
2189
|
-
...buildTask(sym, ctx)
|
|
2190
|
-
};
|
|
2191
|
-
}
|
|
2192
|
-
var init_build = __esm(() => {
|
|
2193
|
-
init_codecs();
|
|
2194
|
-
init_compress();
|
|
2195
|
-
init_instances();
|
|
2196
|
-
init_metrics();
|
|
2197
|
-
init_parse();
|
|
2198
2601
|
});
|
|
2199
2602
|
|
|
2200
2603
|
// src/native/ffi/selftest.ts
|
|
@@ -2202,11 +2605,11 @@ function selfTest(b) {
|
|
|
2202
2605
|
return selfTestCodecs(b) && selfTestCompress(b) && selfTestParse(b) && selfTestInstances(b) && selfTestMetrics(b) && selfTestTask(b);
|
|
2203
2606
|
}
|
|
2204
2607
|
var init_selftest = __esm(() => {
|
|
2205
|
-
|
|
2608
|
+
init_codecs_selftest();
|
|
2206
2609
|
init_compress();
|
|
2207
|
-
|
|
2610
|
+
init_instances_selftest();
|
|
2208
2611
|
init_metrics();
|
|
2209
|
-
|
|
2612
|
+
init_parse_selftest();
|
|
2210
2613
|
});
|
|
2211
2614
|
|
|
2212
2615
|
// src/native/loader.ts
|
|
@@ -2366,6 +2769,12 @@ function getBunFFI() {
|
|
|
2366
2769
|
cached = bind();
|
|
2367
2770
|
return cached;
|
|
2368
2771
|
}
|
|
2772
|
+
function ffiAddonPath() {
|
|
2773
|
+
if (cached === undefined) {
|
|
2774
|
+
getBunFFI();
|
|
2775
|
+
}
|
|
2776
|
+
return boundAddonPath;
|
|
2777
|
+
}
|
|
2369
2778
|
function probeBufferLength(dlopen, path) {
|
|
2370
2779
|
try {
|
|
2371
2780
|
const { symbols, close } = dlopen(path, {
|
|
@@ -2396,361 +2805,10 @@ function bind(forcedPath, tried = []) {
|
|
|
2396
2805
|
}
|
|
2397
2806
|
const path = forcedPath ?? getAddonPath();
|
|
2398
2807
|
try {
|
|
2399
|
-
const { dlopen } = __require("bun:ffi");
|
|
2400
|
-
const useBufferLength = probeBufferLength(dlopen, path);
|
|
2401
|
-
bufferAbiMode = useBufferLength ? "buffer-pair" : "ptr-len";
|
|
2402
|
-
const
|
|
2403
|
-
const abi = (shape) => {
|
|
2404
|
-
if (!useBufferLength)
|
|
2405
|
-
return shape;
|
|
2406
|
-
const out = [];
|
|
2407
|
-
for (let i = 0;i < shape.length; i++) {
|
|
2408
|
-
const t = shape[i];
|
|
2409
|
-
if (t === "ptr") {
|
|
2410
|
-
out.push("buffer");
|
|
2411
|
-
out.push("buffer_length");
|
|
2412
|
-
i++;
|
|
2413
|
-
} else {
|
|
2414
|
-
out.push(t);
|
|
2415
|
-
}
|
|
2416
|
-
}
|
|
2417
|
-
return out;
|
|
2418
|
-
};
|
|
2419
|
-
const U64_FAST = "u64_fast";
|
|
2420
|
-
const { symbols } = dlopen(path, {
|
|
2421
|
-
castrum_crc32: { args: inputAbi, returns: "u32" },
|
|
2422
|
-
castrum_fnv1a64: { args: inputAbi, returns: "u64" },
|
|
2423
|
-
castrum_xxh3: { args: inputAbi, returns: "u64" },
|
|
2424
|
-
castrum_json_valid: { args: inputAbi, returns: "u8" },
|
|
2425
|
-
castrum_utf8_valid: { args: inputAbi, returns: "u8" },
|
|
2426
|
-
castrum_hex_encode: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: U64_FAST },
|
|
2427
|
-
castrum_hex_decode: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: U64_FAST },
|
|
2428
|
-
castrum_url_encode: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: U64_FAST },
|
|
2429
|
-
castrum_url_decode: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: U64_FAST },
|
|
2430
|
-
castrum_validate_email: { args: ["cstring"], returns: "u8" },
|
|
2431
|
-
castrum_validate_uuid: { args: ["cstring"], returns: "u8" },
|
|
2432
|
-
castrum_validate_ipv4: { args: ["cstring"], returns: "u8" },
|
|
2433
|
-
castrum_validate_ipv6: { args: ["cstring"], returns: "u8" },
|
|
2434
|
-
castrum_validate_email_bytes: { args: inputAbi, returns: "u8" },
|
|
2435
|
-
castrum_validate_uuid_bytes: { args: inputAbi, returns: "u8" },
|
|
2436
|
-
castrum_validate_ipv4_bytes: { args: inputAbi, returns: "u8" },
|
|
2437
|
-
castrum_validate_ipv6_bytes: { args: inputAbi, returns: "u8" },
|
|
2438
|
-
castrum_json_sum_ids: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: U64_FAST },
|
|
2439
|
-
castrum_hmac_sha256_verify: {
|
|
2440
|
-
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
2441
|
-
returns: "u8"
|
|
2442
|
-
},
|
|
2443
|
-
castrum_csrf_verify: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: "u8" },
|
|
2444
|
-
castrum_password_verify: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: "u8" },
|
|
2445
|
-
castrum_password_verify_bcrypt: {
|
|
2446
|
-
args: abi(["ptr", "usize", "cstring"]),
|
|
2447
|
-
returns: "u8"
|
|
2448
|
-
},
|
|
2449
|
-
castrum_ws_accept_key: { args: ["cstring"], returns: "cstring" },
|
|
2450
|
-
castrum_ws_accept_key_into: {
|
|
2451
|
-
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
2452
|
-
returns: U64_FAST
|
|
2453
|
-
},
|
|
2454
|
-
castrum_etag: { args: abi(["ptr", "usize", "u8"]), returns: "cstring" },
|
|
2455
|
-
castrum_etag_into: { args: abi(["ptr", "usize", "u8", "ptr", "usize"]), returns: U64_FAST },
|
|
2456
|
-
castrum_conditional_is_not_modified: {
|
|
2457
|
-
args: abi(["usize", "ptr", "usize", "ptr", "usize", "u8"]),
|
|
2458
|
-
returns: "u8"
|
|
2459
|
-
},
|
|
2460
|
-
castrum_media_type_matcher_matches: {
|
|
2461
|
-
args: abi(["usize", "ptr", "usize"]),
|
|
2462
|
-
returns: "u8"
|
|
2463
|
-
},
|
|
2464
|
-
castrum_accept_negotiator_negotiate: {
|
|
2465
|
-
args: abi(["usize", "ptr", "usize"]),
|
|
2466
|
-
returns: "cstring"
|
|
2467
|
-
},
|
|
2468
|
-
castrum_accept_negotiator_negotiate_server: {
|
|
2469
|
-
args: ["usize", "cstring"],
|
|
2470
|
-
returns: "cstring"
|
|
2471
|
-
},
|
|
2472
|
-
castrum_jwt_signer_sign: {
|
|
2473
|
-
args: abi(["usize", "ptr", "usize", "i64", "ptr", "usize"]),
|
|
2474
|
-
returns: U64_FAST
|
|
2475
|
-
},
|
|
2476
|
-
castrum_jwt_signer_verify: {
|
|
2477
|
-
args: abi(["usize", "ptr", "usize", "i64", "ptr", "usize"]),
|
|
2478
|
-
returns: U64_FAST
|
|
2479
|
-
},
|
|
2480
|
-
castrum_template_render: {
|
|
2481
|
-
args: abi(["usize", "ptr", "usize", "ptr", "usize"]),
|
|
2482
|
-
returns: U64_FAST
|
|
2483
|
-
},
|
|
2484
|
-
castrum_schema_validator_validate: {
|
|
2485
|
-
args: abi(["usize", "ptr", "usize"]),
|
|
2486
|
-
returns: "u8"
|
|
2487
|
-
},
|
|
2488
|
-
castrum_rate_limiter_check: {
|
|
2489
|
-
args: abi(["usize", "cstring", "i64", "ptr", "usize"]),
|
|
2490
|
-
returns: U64_FAST
|
|
2491
|
-
},
|
|
2492
|
-
castrum_rate_limiter_check_key: {
|
|
2493
|
-
args: abi(["usize", "i64", "i64", "ptr", "usize"]),
|
|
2494
|
-
returns: U64_FAST
|
|
2495
|
-
},
|
|
2496
|
-
castrum_random_token: { args: ["u32"], returns: "cstring" },
|
|
2497
|
-
castrum_random_token_into: { args: ["u32", ...abi(["ptr", "usize"])], returns: U64_FAST },
|
|
2498
|
-
castrum_base64_encode: {
|
|
2499
|
-
args: abi(["ptr", "usize", "ptr", "usize", "u8", "u8"]),
|
|
2500
|
-
returns: U64_FAST
|
|
2501
|
-
},
|
|
2502
|
-
castrum_base64_decode: {
|
|
2503
|
-
args: abi(["ptr", "usize", "ptr", "usize", "u8", "u8"]),
|
|
2504
|
-
returns: U64_FAST
|
|
2505
|
-
},
|
|
2506
|
-
castrum_hmac_sha256: {
|
|
2507
|
-
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
2508
|
-
returns: U64_FAST
|
|
2509
|
-
},
|
|
2510
|
-
castrum_sign_cookie: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: "cstring" },
|
|
2511
|
-
castrum_sign_cookie_into: {
|
|
2512
|
-
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
2513
|
-
returns: U64_FAST
|
|
2514
|
-
},
|
|
2515
|
-
castrum_verify_cookie: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: "cstring" },
|
|
2516
|
-
castrum_verify_cookie_into: {
|
|
2517
|
-
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
2518
|
-
returns: U64_FAST
|
|
2519
|
-
},
|
|
2520
|
-
castrum_csrf_token: { args: abi(["ptr", "usize"]), returns: "cstring" },
|
|
2521
|
-
castrum_csrf_token_into: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: U64_FAST },
|
|
2522
|
-
castrum_password_hash: {
|
|
2523
|
-
args: abi(["ptr", "usize", "ptr", "usize", "u32", "u32", "u32", "u32", "ptr", "usize"]),
|
|
2524
|
-
returns: U64_FAST
|
|
2525
|
-
},
|
|
2526
|
-
castrum_password_hash_bcrypt: {
|
|
2527
|
-
args: abi(["ptr", "usize", "u32", "ptr", "usize"]),
|
|
2528
|
-
returns: U64_FAST
|
|
2529
|
-
},
|
|
2530
|
-
castrum_pbkdf2_sha256: {
|
|
2531
|
-
args: abi(["ptr", "usize", "ptr", "usize", "u32", "u32", "ptr", "usize"]),
|
|
2532
|
-
returns: U64_FAST
|
|
2533
|
-
},
|
|
2534
|
-
castrum_aead_encrypt: {
|
|
2535
|
-
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize", "u8", "ptr", "usize"]),
|
|
2536
|
-
returns: U64_FAST
|
|
2537
|
-
},
|
|
2538
|
-
castrum_aead_decrypt: {
|
|
2539
|
-
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize", "u8", "ptr", "usize"]),
|
|
2540
|
-
returns: U64_FAST
|
|
2541
|
-
},
|
|
2542
|
-
castrum_ws_frame_encode: {
|
|
2543
|
-
args: abi(["u8", "ptr", "usize", "u8", "u8", "ptr", "usize"]),
|
|
2544
|
-
returns: U64_FAST
|
|
2545
|
-
},
|
|
2546
|
-
castrum_json_patch: {
|
|
2547
|
-
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
2548
|
-
returns: U64_FAST
|
|
2549
|
-
},
|
|
2550
|
-
castrum_gzip_compress: {
|
|
2551
|
-
args: abi(["ptr", "usize", "u32", "ptr", "usize"]),
|
|
2552
|
-
returns: U64_FAST
|
|
2553
|
-
},
|
|
2554
|
-
castrum_gzip_decompress: {
|
|
2555
|
-
args: abi(["ptr", "usize", "usize", "ptr", "usize"]),
|
|
2556
|
-
returns: U64_FAST
|
|
2557
|
-
},
|
|
2558
|
-
castrum_brotli_compress: {
|
|
2559
|
-
args: abi(["ptr", "usize", "u32", "ptr", "usize"]),
|
|
2560
|
-
returns: U64_FAST
|
|
2561
|
-
},
|
|
2562
|
-
castrum_brotli_decompress: {
|
|
2563
|
-
args: abi(["ptr", "usize", "usize", "ptr", "usize"]),
|
|
2564
|
-
returns: U64_FAST
|
|
2565
|
-
},
|
|
2566
|
-
castrum_gzip_isize: { args: abi(["ptr", "usize"]), returns: "u32" },
|
|
2567
|
-
castrum_http_parse_request_packed: {
|
|
2568
|
-
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
2569
|
-
returns: U64_FAST
|
|
2570
|
-
},
|
|
2571
|
-
castrum_query_parse_packed: {
|
|
2572
|
-
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
2573
|
-
returns: U64_FAST
|
|
2574
|
-
},
|
|
2575
|
-
castrum_cookie_parse_packed: {
|
|
2576
|
-
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
2577
|
-
returns: U64_FAST
|
|
2578
|
-
},
|
|
2579
|
-
castrum_http_date_into: { args: ["f64", ...abi(["ptr", "usize"])], returns: U64_FAST },
|
|
2580
|
-
castrum_sse_encode_into: {
|
|
2581
|
-
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize", "u8", "u32", "ptr", "usize"]),
|
|
2582
|
-
returns: U64_FAST
|
|
2583
|
-
},
|
|
2584
|
-
castrum_jwt_sign_bytes: {
|
|
2585
|
-
args: abi(["ptr", "usize", "ptr", "usize", "i64", "i64"]),
|
|
2586
|
-
returns: "cstring"
|
|
2587
|
-
},
|
|
2588
|
-
castrum_jwt_sign_bytes_into: {
|
|
2589
|
-
args: abi(["ptr", "usize", "ptr", "usize", "i64", "i64", "ptr", "usize"]),
|
|
2590
|
-
returns: U64_FAST
|
|
2591
|
-
},
|
|
2592
|
-
castrum_ed25519_generate_keypair: {
|
|
2593
|
-
args: abi(["ptr", "usize"]),
|
|
2594
|
-
returns: U64_FAST
|
|
2595
|
-
},
|
|
2596
|
-
castrum_ed25519_sign: {
|
|
2597
|
-
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
2598
|
-
returns: U64_FAST
|
|
2599
|
-
},
|
|
2600
|
-
castrum_ed25519_verify: {
|
|
2601
|
-
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
2602
|
-
returns: "u32"
|
|
2603
|
-
},
|
|
2604
|
-
castrum_jwt_eddsa_sign: {
|
|
2605
|
-
args: abi(["ptr", "usize", "ptr", "usize", "i64", "i64"]),
|
|
2606
|
-
returns: "cstring"
|
|
2607
|
-
},
|
|
2608
|
-
castrum_jwt_eddsa_verify: {
|
|
2609
|
-
args: abi(["ptr", "usize", "ptr", "usize", "i64"]),
|
|
2610
|
-
returns: "cstring"
|
|
2611
|
-
},
|
|
2612
|
-
castrum_ws_frame_decode_packed: {
|
|
2613
|
-
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
2614
|
-
returns: U64_FAST
|
|
2615
|
-
},
|
|
2616
|
-
castrum_multipart_parse_packed: {
|
|
2617
|
-
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
2618
|
-
returns: U64_FAST
|
|
2619
|
-
},
|
|
2620
|
-
castrum_form_parse_packed: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: U64_FAST },
|
|
2621
|
-
castrum_json_parse_packed: {
|
|
2622
|
-
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
2623
|
-
returns: U64_FAST
|
|
2624
|
-
},
|
|
2625
|
-
castrum_parse_media_type: {
|
|
2626
|
-
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
2627
|
-
returns: U64_FAST
|
|
2628
|
-
},
|
|
2629
|
-
castrum_parse_http_date: {
|
|
2630
|
-
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
2631
|
-
returns: U64_FAST
|
|
2632
|
-
},
|
|
2633
|
-
castrum_parse_accept_encoding: {
|
|
2634
|
-
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
2635
|
-
returns: U64_FAST
|
|
2636
|
-
},
|
|
2637
|
-
castrum_url_encode_query: { args: abi(["ptr", "usize"]), returns: "cstring" },
|
|
2638
|
-
castrum_url_resolve: {
|
|
2639
|
-
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
2640
|
-
returns: "cstring"
|
|
2641
|
-
},
|
|
2642
|
-
castrum_url_builder_resolve: {
|
|
2643
|
-
args: abi(["usize", "ptr", "usize", "ptr", "usize"]),
|
|
2644
|
-
returns: U64_FAST
|
|
2645
|
-
},
|
|
2646
|
-
castrum_mime_from_extension: { args: ["cstring"], returns: "cstring" },
|
|
2647
|
-
castrum_jwt_verify: {
|
|
2648
|
-
args: abi(["ptr", "usize", "ptr", "usize", "i64"]),
|
|
2649
|
-
returns: "cstring"
|
|
2650
|
-
},
|
|
2651
|
-
castrum_ingress_handle_packed: {
|
|
2652
|
-
args: abi(["usize", "ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
2653
|
-
returns: U64_FAST
|
|
2654
|
-
},
|
|
2655
|
-
castrum_ingress_handle_components: {
|
|
2656
|
-
args: abi([
|
|
2657
|
-
"usize",
|
|
2658
|
-
"u8",
|
|
2659
|
-
"cstring",
|
|
2660
|
-
"cstring",
|
|
2661
|
-
"ptr",
|
|
2662
|
-
"usize",
|
|
2663
|
-
"ptr",
|
|
2664
|
-
"usize",
|
|
2665
|
-
"ptr",
|
|
2666
|
-
"usize",
|
|
2667
|
-
"ptr",
|
|
2668
|
-
"usize"
|
|
2669
|
-
]),
|
|
2670
|
-
returns: U64_FAST
|
|
2671
|
-
},
|
|
2672
|
-
castrum_ingress_layout: { args: abi(["ptr", "usize"]), returns: U64_FAST },
|
|
2673
|
-
castrum_route_compile: { args: abi(["ptr", "usize"]), returns: U64_FAST },
|
|
2674
|
-
castrum_route_run: {
|
|
2675
|
-
args: abi(["usize", "ptr", "usize", "ptr", "usize"]),
|
|
2676
|
-
returns: U64_FAST
|
|
2677
|
-
},
|
|
2678
|
-
castrum_route_destroy: { args: ["usize"], returns: "void" },
|
|
2679
|
-
castrum_hex_validate_batch: {
|
|
2680
|
-
args: abi(["ptr", "usize", "u32", "ptr", "usize"]),
|
|
2681
|
-
returns: U64_FAST
|
|
2682
|
-
},
|
|
2683
|
-
castrum_regex_escape: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: U64_FAST },
|
|
2684
|
-
castrum_metrics_create: { args: [], returns: U64_FAST },
|
|
2685
|
-
castrum_metrics_counter: { args: ["usize", "cstring", "cstring"], returns: "u32" },
|
|
2686
|
-
castrum_metrics_gauge: { args: ["usize", "cstring", "cstring"], returns: "u32" },
|
|
2687
|
-
castrum_metrics_histogram: {
|
|
2688
|
-
args: ["usize", "cstring", "cstring", "cstring"],
|
|
2689
|
-
returns: "u32"
|
|
2690
|
-
},
|
|
2691
|
-
castrum_metrics_record: {
|
|
2692
|
-
args: abi(["usize", "u32", "ptr", "usize", "f64"]),
|
|
2693
|
-
returns: "u8"
|
|
2694
|
-
},
|
|
2695
|
-
castrum_metrics_gauge_set: {
|
|
2696
|
-
args: abi(["usize", "u32", "ptr", "usize", "f64"]),
|
|
2697
|
-
returns: "u8"
|
|
2698
|
-
},
|
|
2699
|
-
castrum_metrics_record_str: {
|
|
2700
|
-
args: ["usize", "u32", "cstring", "f64"],
|
|
2701
|
-
returns: "u8"
|
|
2702
|
-
},
|
|
2703
|
-
castrum_metrics_gauge_set_str: {
|
|
2704
|
-
args: ["usize", "u32", "cstring", "f64"],
|
|
2705
|
-
returns: "u8"
|
|
2706
|
-
},
|
|
2707
|
-
castrum_regex_escape_str: { args: ["cstring"], returns: "cstring" },
|
|
2708
|
-
castrum_hex_validate_batch_str: {
|
|
2709
|
-
args: abi(["cstring", "u32", "ptr", "usize"]),
|
|
2710
|
-
returns: U64_FAST
|
|
2711
|
-
},
|
|
2712
|
-
castrum_metrics_render: { args: abi(["usize", "ptr", "usize"]), returns: U64_FAST },
|
|
2713
|
-
castrum_metrics_snapshot: { args: abi(["usize", "ptr", "usize"]), returns: U64_FAST },
|
|
2714
|
-
castrum_metrics_record_batch: {
|
|
2715
|
-
args: abi(["usize", "ptr", "usize"]),
|
|
2716
|
-
returns: "u8"
|
|
2717
|
-
},
|
|
2718
|
-
castrum_query_validate: { args: ["usize", "cstring"], returns: "u8" },
|
|
2719
|
-
castrum_cookie_validate: { args: ["usize", "cstring"], returns: "u8" },
|
|
2720
|
-
castrum_session_seal: {
|
|
2721
|
-
args: ["cstring", "cstring", "i64", "cstring"],
|
|
2722
|
-
returns: "cstring"
|
|
2723
|
-
},
|
|
2724
|
-
castrum_session_open: {
|
|
2725
|
-
args: abi(["cstring", "cstring", "ptr", "usize"]),
|
|
2726
|
-
returns: U64_FAST
|
|
2727
|
-
},
|
|
2728
|
-
castrum_session_seal_bytes: {
|
|
2729
|
-
args: abi(["ptr", "usize", "ptr", "usize", "i64", "ptr", "usize"]),
|
|
2730
|
-
returns: "cstring"
|
|
2731
|
-
},
|
|
2732
|
-
castrum_session_open_bytes: {
|
|
2733
|
-
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
2734
|
-
returns: U64_FAST
|
|
2735
|
-
},
|
|
2736
|
-
castrum_task_init: { args: ["u32"], returns: "u32" },
|
|
2737
|
-
castrum_task_submit: { args: abi(["u32", "ptr", "usize", "usize"]), returns: "u32" },
|
|
2738
|
-
castrum_task_submit_slice: {
|
|
2739
|
-
args: abi(["u32", "ptr", "usize", "ptr", "usize", "usize"]),
|
|
2740
|
-
returns: "u32"
|
|
2741
|
-
},
|
|
2742
|
-
castrum_task_submit_out: {
|
|
2743
|
-
args: abi(["u32", "ptr", "usize", "usize", "ptr", "usize"]),
|
|
2744
|
-
returns: "u32"
|
|
2745
|
-
},
|
|
2746
|
-
castrum_task_drain: { args: abi(["ptr", "usize"]), returns: U64_FAST },
|
|
2747
|
-
castrum_task_pending: { args: [], returns: "u32" },
|
|
2748
|
-
castrum_task_cancel: { args: ["usize"], returns: "u32" },
|
|
2749
|
-
castrum_task_set_doorbell: { args: ["ptr"], returns: "u32" },
|
|
2750
|
-
castrum_task_shutdown: { args: [], returns: "u32" },
|
|
2751
|
-
castrum_task_threads: { args: [], returns: "u32" },
|
|
2752
|
-
castrum_metrics_destroy: { args: ["usize"], returns: "void" }
|
|
2753
|
-
});
|
|
2808
|
+
const { dlopen } = __require("bun:ffi");
|
|
2809
|
+
const useBufferLength = probeBufferLength(dlopen, path);
|
|
2810
|
+
bufferAbiMode = useBufferLength ? "buffer-pair" : "ptr-len";
|
|
2811
|
+
const { symbols } = dlopen(path, buildFFISymbolMap(useBufferLength));
|
|
2754
2812
|
const bindings = build(symbols, useBufferLength);
|
|
2755
2813
|
if (!selfTest(bindings)) {
|
|
2756
2814
|
throw new Error(`bun:ffi bind-time self-test failed on ${path}`);
|
|
@@ -3425,24 +3483,53 @@ var init_wire = __esm(() => {
|
|
|
3425
3483
|
});
|
|
3426
3484
|
|
|
3427
3485
|
// src/shared/packed/parsers.ts
|
|
3428
|
-
function
|
|
3429
|
-
const
|
|
3486
|
+
function scratchFor(kind, input) {
|
|
3487
|
+
const need = input.length * 9 + 16;
|
|
3488
|
+
let s = ffiCaches[kind];
|
|
3489
|
+
if (s === null || s.length < need) {
|
|
3490
|
+
s = new Uint8Array(need);
|
|
3491
|
+
ffiCaches[kind] = s;
|
|
3492
|
+
}
|
|
3493
|
+
return s;
|
|
3494
|
+
}
|
|
3495
|
+
function parsePackedInto(kind, input) {
|
|
3496
|
+
const f = getBunFFI();
|
|
3497
|
+
if (!f)
|
|
3498
|
+
return null;
|
|
3499
|
+
const out = scratchFor(kind, input);
|
|
3500
|
+
const w = kind === "query" ? f.queryParsePackedInto(input, out) : kind === "cookie" ? f.cookieParsePackedInto(input, out) : f.formParsePackedInto(input, out);
|
|
3501
|
+
if (w === 0 || w > out.length)
|
|
3502
|
+
return null;
|
|
3503
|
+
return pairsToObject(readPairsPacked(out.subarray(0, w)));
|
|
3504
|
+
}
|
|
3505
|
+
function parseVia(kind, input) {
|
|
3506
|
+
const fast = parsePackedInto(kind, input);
|
|
3507
|
+
if (fast)
|
|
3508
|
+
return fast;
|
|
3509
|
+
const packed = kind === "query" ? addon2.queryParsePacked(input) : kind === "cookie" ? addon2.cookieParsePacked(input) : addon2.formParsePacked(input);
|
|
3430
3510
|
return pairsToObject(readPairsPacked(packed));
|
|
3431
3511
|
}
|
|
3512
|
+
function parseQueryString(query) {
|
|
3513
|
+
return parseVia("query", encoder.encode(query));
|
|
3514
|
+
}
|
|
3432
3515
|
function parseCookieHeader(header) {
|
|
3433
|
-
|
|
3434
|
-
return pairsToObject(readPairsPacked(packed));
|
|
3516
|
+
return parseVia("cookie", encoder.encode(header));
|
|
3435
3517
|
}
|
|
3436
3518
|
function parseFormBody(body) {
|
|
3437
|
-
|
|
3438
|
-
return pairsToObject(readPairsPacked(packed));
|
|
3519
|
+
return parseVia("form", body);
|
|
3439
3520
|
}
|
|
3440
|
-
var addon2;
|
|
3521
|
+
var addon2, ffiCaches;
|
|
3441
3522
|
var init_parsers = __esm(() => {
|
|
3523
|
+
init_ffi();
|
|
3442
3524
|
init_native();
|
|
3443
3525
|
init_bytes();
|
|
3444
3526
|
init_wire();
|
|
3445
3527
|
addon2 = lazyAddon(getAddon);
|
|
3528
|
+
ffiCaches = {
|
|
3529
|
+
query: null,
|
|
3530
|
+
cookie: null,
|
|
3531
|
+
form: null
|
|
3532
|
+
};
|
|
3446
3533
|
});
|
|
3447
3534
|
|
|
3448
3535
|
// src/shared/packed/schema.ts
|
|
@@ -3507,6 +3594,11 @@ function asNumber(value) {
|
|
|
3507
3594
|
}
|
|
3508
3595
|
return 0;
|
|
3509
3596
|
}
|
|
3597
|
+
function assertNonEmptySecret(secret, op) {
|
|
3598
|
+
if (secret.byteLength === 0) {
|
|
3599
|
+
throw new Error(`${op}: secret must not be empty`);
|
|
3600
|
+
}
|
|
3601
|
+
}
|
|
3510
3602
|
function normalizeExt(ext) {
|
|
3511
3603
|
let s;
|
|
3512
3604
|
try {
|
|
@@ -3525,6 +3617,24 @@ var init_options = __esm(() => {
|
|
|
3525
3617
|
});
|
|
3526
3618
|
|
|
3527
3619
|
// src/rust-ffi/context.ts
|
|
3620
|
+
function evictOldestHalf(map) {
|
|
3621
|
+
if (map.size < MIME_CACHE_MAX)
|
|
3622
|
+
return [];
|
|
3623
|
+
const drop = Math.ceil(map.size / 2);
|
|
3624
|
+
const dropped = [];
|
|
3625
|
+
for (const key of map.keys()) {
|
|
3626
|
+
if (dropped.length >= drop)
|
|
3627
|
+
break;
|
|
3628
|
+
dropped.push(key);
|
|
3629
|
+
}
|
|
3630
|
+
for (const key of dropped)
|
|
3631
|
+
map.delete(key);
|
|
3632
|
+
return dropped;
|
|
3633
|
+
}
|
|
3634
|
+
function clearMimeCaches() {
|
|
3635
|
+
mimeByText.clear();
|
|
3636
|
+
mimeStrCache.clear();
|
|
3637
|
+
}
|
|
3528
3638
|
function resolveNative(ctx, name) {
|
|
3529
3639
|
let f = nativeFnCache.get(name);
|
|
3530
3640
|
if (f === undefined) {
|
|
@@ -3553,7 +3663,6 @@ function memoizeFfi(transport) {
|
|
|
3553
3663
|
};
|
|
3554
3664
|
}
|
|
3555
3665
|
function createContext(options) {
|
|
3556
|
-
const mimeByText = new Map;
|
|
3557
3666
|
const hmacSigners = new WeakMap;
|
|
3558
3667
|
const state = {
|
|
3559
3668
|
mimeCache: options.mimeCache !== false,
|
|
@@ -3583,6 +3692,7 @@ function createContext(options) {
|
|
|
3583
3692
|
const key = normalizeExt(ext);
|
|
3584
3693
|
let val = mimeByText.get(key);
|
|
3585
3694
|
if (!val) {
|
|
3695
|
+
evictOldestHalf(mimeByText);
|
|
3586
3696
|
val = addon.mimeFromExtension(ext);
|
|
3587
3697
|
mimeByText.set(key, val);
|
|
3588
3698
|
}
|
|
@@ -3603,7 +3713,6 @@ function createContext(options) {
|
|
|
3603
3713
|
addon,
|
|
3604
3714
|
runtime: runtimeNative,
|
|
3605
3715
|
state,
|
|
3606
|
-
mimeByText,
|
|
3607
3716
|
hmacSigners,
|
|
3608
3717
|
ensurePool,
|
|
3609
3718
|
isPoolInitialized,
|
|
@@ -3613,12 +3722,14 @@ function createContext(options) {
|
|
|
3613
3722
|
hmacSigner
|
|
3614
3723
|
};
|
|
3615
3724
|
}
|
|
3616
|
-
var nativeFnCache;
|
|
3725
|
+
var nativeFnCache, MIME_CACHE_MAX = 1024, mimeByText, mimeStrCache;
|
|
3617
3726
|
var init_context = __esm(() => {
|
|
3618
3727
|
init_native2();
|
|
3619
3728
|
init_addon();
|
|
3620
3729
|
init_options();
|
|
3621
3730
|
nativeFnCache = new Map;
|
|
3731
|
+
mimeByText = new Map;
|
|
3732
|
+
mimeStrCache = new Map;
|
|
3622
3733
|
});
|
|
3623
3734
|
|
|
3624
3735
|
// src/rust-ffi/batch/build.ts
|
|
@@ -3674,17 +3785,29 @@ function buildBatch(ctx) {
|
|
|
3674
3785
|
gzipDecompress: (items, maxDecompressed) => via(ctx, "gzipDecompressBatchPacked", unpackByteResults, [maxDecompressed ?? null])(items),
|
|
3675
3786
|
brotliCompress: (items, quality) => via(ctx, "brotliCompressBatchPacked", unpackByteResults, [quality ?? null])(items),
|
|
3676
3787
|
brotliDecompress: (items, maxDecompressed) => via(ctx, "brotliDecompressBatchPacked", unpackByteResults, [maxDecompressed ?? null])(items),
|
|
3677
|
-
jwtVerify: (tokens, secret, nowSeconds) =>
|
|
3678
|
-
|
|
3679
|
-
|
|
3788
|
+
jwtVerify: (tokens, secret, nowSeconds) => {
|
|
3789
|
+
assertNonEmptySecret(secret, "batch.jwtVerify");
|
|
3790
|
+
return via(ctx, "jwtVerifyBatchPacked", unpackBitset, [secret, nowSeconds])(tokens);
|
|
3791
|
+
},
|
|
3792
|
+
hmacSha256: (items, key) => {
|
|
3793
|
+
assertNonEmptySecret(key, "batch.hmacSha256");
|
|
3794
|
+
return via(ctx, "hmacSha256BatchPacked", unpackByteResults, [key])(items);
|
|
3795
|
+
},
|
|
3796
|
+
hmacSha256Verify: (items, sigs, key) => {
|
|
3797
|
+
assertNonEmptySecret(key, "batch.hmacSha256Verify");
|
|
3798
|
+
return via2(ctx, "hmacSha256VerifyBatchPacked", unpackBitset, [key])(items, sigs);
|
|
3799
|
+
},
|
|
3680
3800
|
passwordVerify: (items, phcs) => via2(ctx, "passwordVerifyBatchPacked", unpackBitset)(items, phcs),
|
|
3681
3801
|
urlResolve: (bases, references) => via2(ctx, "urlResolveBatchPacked", unpackByteResults)(bases, references),
|
|
3682
3802
|
templateRender: (source, contexts) => via(ctx, "templateRenderBatchPacked", unpackByteResults, [source])(contexts),
|
|
3683
|
-
jwtSign: (items, secret, ttlSeconds, nowSeconds) =>
|
|
3684
|
-
secret,
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3803
|
+
jwtSign: (items, secret, ttlSeconds, nowSeconds) => {
|
|
3804
|
+
assertNonEmptySecret(secret, "batch.jwtSign");
|
|
3805
|
+
return via(ctx, "jwtSignBatchPacked", unpackByteResults, [
|
|
3806
|
+
secret,
|
|
3807
|
+
ttlSeconds ?? null,
|
|
3808
|
+
nowSeconds ?? Math.floor(Date.now() / 1000)
|
|
3809
|
+
])(items);
|
|
3810
|
+
},
|
|
3688
3811
|
sseEncode: (items, event, id, retry) => via(ctx, "sseEncodeBatchPacked", unpackByteResults, [
|
|
3689
3812
|
event ?? null,
|
|
3690
3813
|
id ?? null,
|
|
@@ -3698,6 +3821,7 @@ function buildBatch(ctx) {
|
|
|
3698
3821
|
var init_build2 = __esm(() => {
|
|
3699
3822
|
init_packed();
|
|
3700
3823
|
init_context();
|
|
3824
|
+
init_options();
|
|
3701
3825
|
});
|
|
3702
3826
|
|
|
3703
3827
|
// src/rust-ffi/batch/index.ts
|
|
@@ -3959,18 +4083,22 @@ function buildCrypto(ctx) {
|
|
|
3959
4083
|
return writeInto("verify cookie", output, value);
|
|
3960
4084
|
},
|
|
3961
4085
|
csrfToken(secret) {
|
|
4086
|
+
assertNonEmptySecret(secret, "csrfToken");
|
|
3962
4087
|
return resolveNative(ctx, "csrfToken")(secret);
|
|
3963
4088
|
},
|
|
3964
4089
|
csrfTokenInto(secret, output) {
|
|
4090
|
+
assertNonEmptySecret(secret, "csrfTokenInto");
|
|
3965
4091
|
const f = ffi();
|
|
3966
4092
|
if (f)
|
|
3967
4093
|
return f.csrfTokenInto(secret, output);
|
|
3968
4094
|
return writeInto("csrf token", output, addon.csrfToken(secret));
|
|
3969
4095
|
},
|
|
3970
4096
|
csrfVerify(token, secret) {
|
|
4097
|
+
assertNonEmptySecret(secret, "csrfVerify");
|
|
3971
4098
|
return resolveNative(ctx, "csrfVerify")(token, secret);
|
|
3972
4099
|
},
|
|
3973
4100
|
jwtSign(claims, secret, ttlSeconds, nowSeconds) {
|
|
4101
|
+
assertNonEmptySecret(secret, "jwtSign");
|
|
3974
4102
|
const f = ffi();
|
|
3975
4103
|
if (f) {
|
|
3976
4104
|
const token = f.jwtSignBytes(encoder.encode(JSON.stringify(claims)), secret, ttlSeconds ?? 0, nowSeconds ?? Math.floor(Date.now() / 1000));
|
|
@@ -3979,6 +4107,7 @@ function buildCrypto(ctx) {
|
|
|
3979
4107
|
return addon.jwtSign(claims, secret, ttlSeconds ?? null, nowSeconds ?? Math.floor(Date.now() / 1000));
|
|
3980
4108
|
},
|
|
3981
4109
|
jwtSignBytes(claimsJson, secret, ttlSeconds, nowSeconds) {
|
|
4110
|
+
assertNonEmptySecret(secret, "jwtSignBytes");
|
|
3982
4111
|
const f = ffi();
|
|
3983
4112
|
if (f) {
|
|
3984
4113
|
return f.jwtSignBytes(claimsJson, secret, ttlSeconds ?? 0, nowSeconds ?? Math.floor(Date.now() / 1000));
|
|
@@ -3986,6 +4115,7 @@ function buildCrypto(ctx) {
|
|
|
3986
4115
|
return addon.jwtSignBytes(claimsJson, secret, ttlSeconds ?? null, nowSeconds ?? Math.floor(Date.now() / 1000));
|
|
3987
4116
|
},
|
|
3988
4117
|
jwtSignBytesInto(claimsJson, secret, output, ttlSeconds, nowSeconds) {
|
|
4118
|
+
assertNonEmptySecret(secret, "jwtSignBytesInto");
|
|
3989
4119
|
const f = ffi();
|
|
3990
4120
|
if (f) {
|
|
3991
4121
|
return f.jwtSignBytesInto(claimsJson, secret, ttlSeconds ?? 0, nowSeconds ?? Math.floor(Date.now() / 1000), output);
|
|
@@ -3993,6 +4123,7 @@ function buildCrypto(ctx) {
|
|
|
3993
4123
|
return writeInto("jwt sign", output, addon.jwtSignBytes(claimsJson, secret, ttlSeconds ?? null, nowSeconds ?? Math.floor(Date.now() / 1000)));
|
|
3994
4124
|
},
|
|
3995
4125
|
jwtVerify(token, secret, nowSeconds) {
|
|
4126
|
+
assertNonEmptySecret(secret, "jwtVerify");
|
|
3996
4127
|
const f = ffi();
|
|
3997
4128
|
if (f) {
|
|
3998
4129
|
const claims = f.jwtVerify(token, secret, nowSeconds ?? Math.floor(Date.now() / 1000));
|
|
@@ -4053,9 +4184,17 @@ function buildCrypto(ctx) {
|
|
|
4053
4184
|
var init_crypto = __esm(() => {
|
|
4054
4185
|
init_bytes();
|
|
4055
4186
|
init_context();
|
|
4187
|
+
init_options();
|
|
4056
4188
|
});
|
|
4057
4189
|
|
|
4058
4190
|
// src/rust-ffi/scalar/factories.ts
|
|
4191
|
+
function handlePtr(inner) {
|
|
4192
|
+
const v = inner ?? 0n;
|
|
4193
|
+
if (v < 0n || v > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
4194
|
+
throw new Error("castrum: native handle exceeds Number.MAX_SAFE_INTEGER");
|
|
4195
|
+
}
|
|
4196
|
+
return Number(v);
|
|
4197
|
+
}
|
|
4059
4198
|
function ffiHmacSigner(key, ffi) {
|
|
4060
4199
|
return {
|
|
4061
4200
|
sign(data) {
|
|
@@ -4236,47 +4375,55 @@ function ffiFormParser(ffi) {
|
|
|
4236
4375
|
};
|
|
4237
4376
|
}
|
|
4238
4377
|
function ffiMetricsRegistry(ffi) {
|
|
4239
|
-
|
|
4378
|
+
let handle = ffi.metricsCreate();
|
|
4379
|
+
const live = () => {
|
|
4380
|
+
if (handle === 0)
|
|
4381
|
+
throw new Error("metrics registry: already destroyed");
|
|
4382
|
+
return handle;
|
|
4383
|
+
};
|
|
4240
4384
|
return {
|
|
4241
4385
|
counter(name, labelKeys) {
|
|
4242
|
-
return ffi.metricsCounter(
|
|
4386
|
+
return ffi.metricsCounter(live(), name, (labelKeys ?? []).join("\x1F"));
|
|
4243
4387
|
},
|
|
4244
4388
|
gauge(name, labelKeys) {
|
|
4245
|
-
return ffi.metricsGauge(
|
|
4389
|
+
return ffi.metricsGauge(live(), name, (labelKeys ?? []).join("\x1F"));
|
|
4246
4390
|
},
|
|
4247
4391
|
histogram(name, labelKeys, buckets) {
|
|
4248
|
-
return ffi.metricsHistogram(
|
|
4392
|
+
return ffi.metricsHistogram(live(), name, (labelKeys ?? []).join("\x1F"), (buckets ?? []).join(","));
|
|
4249
4393
|
},
|
|
4250
4394
|
record(series, values, amount) {
|
|
4251
4395
|
const joined = (values ?? []).join("\x1F");
|
|
4252
|
-
if (!ffi.metricsRecordStr(
|
|
4396
|
+
if (!ffi.metricsRecordStr(live(), series, joined, amount ?? 1)) {
|
|
4253
4397
|
throw new Error("metrics record: unknown series / arity mismatch / invalid amount");
|
|
4254
4398
|
}
|
|
4255
4399
|
},
|
|
4256
4400
|
gaugeSet(series, values, value) {
|
|
4257
4401
|
const joined = (values ?? []).join("\x1F");
|
|
4258
|
-
if (!ffi.metricsGaugeSetStr(
|
|
4402
|
+
if (!ffi.metricsGaugeSetStr(live(), series, joined, value)) {
|
|
4259
4403
|
throw new Error("metrics gauge set: unknown series / arity mismatch");
|
|
4260
4404
|
}
|
|
4261
4405
|
},
|
|
4262
4406
|
render() {
|
|
4263
4407
|
let out = new Uint8Array(8192);
|
|
4264
|
-
let w = ffi.metricsRender(
|
|
4408
|
+
let w = ffi.metricsRender(live(), out);
|
|
4265
4409
|
if (w > out.length) {
|
|
4266
4410
|
out = new Uint8Array(w);
|
|
4267
|
-
w = ffi.metricsRender(
|
|
4411
|
+
w = ffi.metricsRender(live(), out);
|
|
4268
4412
|
}
|
|
4269
4413
|
return decodeUtf8(out.subarray(0, w));
|
|
4270
4414
|
},
|
|
4271
4415
|
destroy() {
|
|
4272
|
-
|
|
4416
|
+
if (handle !== 0) {
|
|
4417
|
+
ffi.metricsDestroy(handle);
|
|
4418
|
+
handle = 0;
|
|
4419
|
+
}
|
|
4273
4420
|
},
|
|
4274
4421
|
snapshot() {
|
|
4275
4422
|
let out = new Uint8Array(4096);
|
|
4276
|
-
let w = ffi.metricsSnapshot(
|
|
4423
|
+
let w = ffi.metricsSnapshot(live(), out);
|
|
4277
4424
|
if (w > out.length) {
|
|
4278
4425
|
out = new Uint8Array(w);
|
|
4279
|
-
w = ffi.metricsSnapshot(
|
|
4426
|
+
w = ffi.metricsSnapshot(live(), out);
|
|
4280
4427
|
}
|
|
4281
4428
|
return out.subarray(0, w);
|
|
4282
4429
|
}
|
|
@@ -4290,11 +4437,12 @@ function buildFactories(ctx) {
|
|
|
4290
4437
|
const ffi = transport.ffi;
|
|
4291
4438
|
if (ffi) {
|
|
4292
4439
|
const napi = new addon.SchemaValidator(schema);
|
|
4293
|
-
return ffiSchemaValidator(napi,
|
|
4440
|
+
return ffiSchemaValidator(napi, handlePtr(napi.innerPtr?.()), ffi);
|
|
4294
4441
|
}
|
|
4295
4442
|
return new addon.SchemaValidator(schema);
|
|
4296
4443
|
},
|
|
4297
4444
|
createHmacSigner(key) {
|
|
4445
|
+
assertNonEmptySecret(key, "createHmacSigner");
|
|
4298
4446
|
const ffi = transport.ffi;
|
|
4299
4447
|
if (ffi)
|
|
4300
4448
|
return ffiHmacSigner(key, ffi);
|
|
@@ -4304,7 +4452,7 @@ function buildFactories(ctx) {
|
|
|
4304
4452
|
const ffi = transport.ffi;
|
|
4305
4453
|
if (ffi) {
|
|
4306
4454
|
const napi = new addon.TemplateRenderer(source);
|
|
4307
|
-
return ffiTemplateRenderer(napi,
|
|
4455
|
+
return ffiTemplateRenderer(napi, handlePtr(napi.innerPtr?.()), ffi);
|
|
4308
4456
|
}
|
|
4309
4457
|
return new addon.TemplateRenderer(source);
|
|
4310
4458
|
},
|
|
@@ -4321,7 +4469,7 @@ function buildFactories(ctx) {
|
|
|
4321
4469
|
const ffi = transport.ffi;
|
|
4322
4470
|
if (ffi) {
|
|
4323
4471
|
const napi = new addon.ConditionalRequest(etagValue, lastModifiedSecs ?? undefined);
|
|
4324
|
-
return ffiConditionalRequest(napi,
|
|
4472
|
+
return ffiConditionalRequest(napi, handlePtr(napi.innerPtr?.()), ffi);
|
|
4325
4473
|
}
|
|
4326
4474
|
return new addon.ConditionalRequest(etagValue, lastModifiedSecs ?? undefined);
|
|
4327
4475
|
},
|
|
@@ -4329,7 +4477,7 @@ function buildFactories(ctx) {
|
|
|
4329
4477
|
const ffi = transport.ffi;
|
|
4330
4478
|
if (ffi) {
|
|
4331
4479
|
const napi = new addon.AcceptNegotiator(supported);
|
|
4332
|
-
return ffiAcceptNegotiator(napi,
|
|
4480
|
+
return ffiAcceptNegotiator(napi, handlePtr(napi.innerPtr?.()), ffi);
|
|
4333
4481
|
}
|
|
4334
4482
|
return new addon.AcceptNegotiator(supported);
|
|
4335
4483
|
},
|
|
@@ -4340,12 +4488,14 @@ function buildFactories(ctx) {
|
|
|
4340
4488
|
return new addon.Base64Codec(urlSafe ?? undefined, padding ?? undefined);
|
|
4341
4489
|
},
|
|
4342
4490
|
createCookieSigner(secret) {
|
|
4491
|
+
assertNonEmptySecret(secret, "createCookieSigner");
|
|
4343
4492
|
const ffi = transport.ffi;
|
|
4344
4493
|
if (ffi)
|
|
4345
4494
|
return ffiCookieSigner(secret, ffi);
|
|
4346
4495
|
return new addon.CookieSigner(secret);
|
|
4347
4496
|
},
|
|
4348
4497
|
createCsrfProtector(secret) {
|
|
4498
|
+
assertNonEmptySecret(secret, "createCsrfProtector");
|
|
4349
4499
|
const ffi = transport.ffi;
|
|
4350
4500
|
if (ffi)
|
|
4351
4501
|
return ffiCsrfProtector(secret, ffi);
|
|
@@ -4355,15 +4505,16 @@ function buildFactories(ctx) {
|
|
|
4355
4505
|
const ffi = transport.ffi;
|
|
4356
4506
|
if (ffi) {
|
|
4357
4507
|
const napi = new addon.UrlBuilder(base);
|
|
4358
|
-
return ffiUrlBuilder(napi,
|
|
4508
|
+
return ffiUrlBuilder(napi, handlePtr(napi.innerPtr?.()), ffi);
|
|
4359
4509
|
}
|
|
4360
4510
|
return new addon.UrlBuilder(base);
|
|
4361
4511
|
},
|
|
4362
4512
|
createJwtSigner(secret, ttlSeconds) {
|
|
4513
|
+
assertNonEmptySecret(secret, "createJwtSigner");
|
|
4363
4514
|
const ffi = transport.ffi;
|
|
4364
4515
|
if (ffi) {
|
|
4365
4516
|
const napi = new addon.JwtSigner(secret, ttlSeconds ?? undefined);
|
|
4366
|
-
return ffiJwtSigner(napi,
|
|
4517
|
+
return ffiJwtSigner(napi, handlePtr(napi.innerPtr?.()), ffi);
|
|
4367
4518
|
}
|
|
4368
4519
|
return new addon.JwtSigner(secret, ttlSeconds ?? undefined);
|
|
4369
4520
|
},
|
|
@@ -4383,7 +4534,7 @@ function buildFactories(ctx) {
|
|
|
4383
4534
|
const ffi = transport.ffi;
|
|
4384
4535
|
if (ffi) {
|
|
4385
4536
|
const napi = new addon.MediaTypeMatcher(expected);
|
|
4386
|
-
return ffiMediaTypeMatcher(napi,
|
|
4537
|
+
return ffiMediaTypeMatcher(napi, handlePtr(napi.innerPtr?.()), ffi);
|
|
4387
4538
|
}
|
|
4388
4539
|
return new addon.MediaTypeMatcher(expected);
|
|
4389
4540
|
},
|
|
@@ -4391,7 +4542,7 @@ function buildFactories(ctx) {
|
|
|
4391
4542
|
const ffi = transport.ffi;
|
|
4392
4543
|
if (ffi) {
|
|
4393
4544
|
const napi = new addon.RateLimiter(limit, windowMs, maxEntries ?? undefined);
|
|
4394
|
-
return ffiRateLimiter(napi,
|
|
4545
|
+
return ffiRateLimiter(napi, handlePtr(napi.innerPtr?.()), ffi);
|
|
4395
4546
|
}
|
|
4396
4547
|
return new addon.RateLimiter(limit, windowMs, maxEntries ?? undefined);
|
|
4397
4548
|
},
|
|
@@ -4409,6 +4560,10 @@ function buildFactories(ctx) {
|
|
|
4409
4560
|
},
|
|
4410
4561
|
rayonNumThreads() {
|
|
4411
4562
|
return asNumber(addon.rayonNumThreads());
|
|
4563
|
+
},
|
|
4564
|
+
clearSchemaCache() {
|
|
4565
|
+
const native = addon;
|
|
4566
|
+
native.clearSchemaCache?.();
|
|
4412
4567
|
}
|
|
4413
4568
|
};
|
|
4414
4569
|
}
|
|
@@ -4492,37 +4647,63 @@ function ensureValidUtf8(bytes, ffi) {
|
|
|
4492
4647
|
function u32LE(b, off) {
|
|
4493
4648
|
return ((b[off] ?? 0) | (b[off + 1] ?? 0) << 8 | (b[off + 2] ?? 0) << 16 | (b[off + 3] ?? 0) << 24) >>> 0;
|
|
4494
4649
|
}
|
|
4650
|
+
function keyBytesEqual(b, off, lit) {
|
|
4651
|
+
for (let i = 0;i < lit.length; i++) {
|
|
4652
|
+
if ((b[off + i] ?? 0) !== (lit[i] ?? 0))
|
|
4653
|
+
return false;
|
|
4654
|
+
}
|
|
4655
|
+
return true;
|
|
4656
|
+
}
|
|
4495
4657
|
function unpackMediaType(packed) {
|
|
4658
|
+
const view = Buffer.from(packed.buffer, packed.byteOffset, packed.byteLength);
|
|
4496
4659
|
let off = 0;
|
|
4497
4660
|
const mtLen = u32LE(packed, off);
|
|
4498
4661
|
off += 4;
|
|
4499
|
-
const mediaType =
|
|
4662
|
+
const mediaType = decodeUtf8RangeView(view, off, off + mtLen);
|
|
4500
4663
|
off += mtLen;
|
|
4501
4664
|
let charset = null;
|
|
4502
4665
|
const csLen = u32LE(packed, off);
|
|
4503
4666
|
off += 4;
|
|
4504
4667
|
if (csLen !== 4294967295) {
|
|
4505
|
-
charset =
|
|
4668
|
+
charset = decodeUtf8RangeView(view, off, off + csLen);
|
|
4506
4669
|
off += csLen;
|
|
4507
4670
|
}
|
|
4508
4671
|
let boundary = null;
|
|
4509
4672
|
const bLen = u32LE(packed, off);
|
|
4510
4673
|
off += 4;
|
|
4511
4674
|
if (bLen !== 4294967295) {
|
|
4512
|
-
boundary =
|
|
4675
|
+
boundary = decodeUtf8RangeView(view, off, off + bLen);
|
|
4513
4676
|
off += bLen;
|
|
4514
4677
|
}
|
|
4515
4678
|
const count = u32LE(packed, off);
|
|
4516
4679
|
off += 4;
|
|
4517
4680
|
const params = {};
|
|
4681
|
+
let charsetTaken = charset === null;
|
|
4682
|
+
let boundaryTaken = boundary === null;
|
|
4518
4683
|
for (let i = 0;i < count; i++) {
|
|
4519
4684
|
const kLen = u32LE(packed, off);
|
|
4520
4685
|
off += 4;
|
|
4521
|
-
|
|
4686
|
+
let key;
|
|
4687
|
+
if (kLen === 7 && keyBytesEqual(packed, off, CHARSET_KEY_BYTES)) {
|
|
4688
|
+
key = "charset";
|
|
4689
|
+
} else if (kLen === 8 && keyBytesEqual(packed, off, BOUNDARY_KEY_BYTES)) {
|
|
4690
|
+
key = "boundary";
|
|
4691
|
+
} else {
|
|
4692
|
+
key = decodeUtf8RangeView(view, off, off + kLen);
|
|
4693
|
+
}
|
|
4522
4694
|
off += kLen;
|
|
4523
4695
|
const vLen = u32LE(packed, off);
|
|
4524
4696
|
off += 4;
|
|
4525
|
-
|
|
4697
|
+
let val;
|
|
4698
|
+
if (!charsetTaken && key === "charset" && charset !== null) {
|
|
4699
|
+
val = charset;
|
|
4700
|
+
charsetTaken = true;
|
|
4701
|
+
} else if (!boundaryTaken && key === "boundary" && boundary !== null) {
|
|
4702
|
+
val = boundary;
|
|
4703
|
+
boundaryTaken = true;
|
|
4704
|
+
} else {
|
|
4705
|
+
val = decodeUtf8RangeView(view, off, off + vLen);
|
|
4706
|
+
}
|
|
4526
4707
|
off += vLen;
|
|
4527
4708
|
params[key] = val;
|
|
4528
4709
|
}
|
|
@@ -4653,7 +4834,7 @@ function buildHttp(ctx) {
|
|
|
4653
4834
|
queryParsePacked(input) {
|
|
4654
4835
|
const f = ffi();
|
|
4655
4836
|
if (f) {
|
|
4656
|
-
const out = new Uint8Array(input.length *
|
|
4837
|
+
const out = new Uint8Array(input.length * 5 + 8);
|
|
4657
4838
|
const w = f.queryParsePackedInto(input, out);
|
|
4658
4839
|
return out.subarray(0, w);
|
|
4659
4840
|
}
|
|
@@ -4665,7 +4846,7 @@ function buildHttp(ctx) {
|
|
|
4665
4846
|
cookieParsePacked(input) {
|
|
4666
4847
|
const f = ffi();
|
|
4667
4848
|
if (f) {
|
|
4668
|
-
const out = new Uint8Array(input.length *
|
|
4849
|
+
const out = new Uint8Array(input.length * 5 + 8);
|
|
4669
4850
|
const w = f.cookieParsePackedInto(input, out);
|
|
4670
4851
|
return out.subarray(0, w);
|
|
4671
4852
|
}
|
|
@@ -4677,7 +4858,7 @@ function buildHttp(ctx) {
|
|
|
4677
4858
|
formParsePacked(input) {
|
|
4678
4859
|
const f = ffi();
|
|
4679
4860
|
if (f) {
|
|
4680
|
-
const out = new Uint8Array(input.length *
|
|
4861
|
+
const out = new Uint8Array(input.length * 5 + 8);
|
|
4681
4862
|
const w = f.formParsePackedInto(input, out);
|
|
4682
4863
|
return out.subarray(0, w);
|
|
4683
4864
|
}
|
|
@@ -4749,13 +4930,15 @@ function buildHttp(ctx) {
|
|
|
4749
4930
|
}
|
|
4750
4931
|
};
|
|
4751
4932
|
}
|
|
4752
|
-
var WS_ACCEPT_SCRATCH, f32Bits, f32BitsU32;
|
|
4933
|
+
var WS_ACCEPT_SCRATCH, CHARSET_KEY_BYTES, BOUNDARY_KEY_BYTES, f32Bits, f32BitsU32;
|
|
4753
4934
|
var init_http = __esm(() => {
|
|
4754
4935
|
init_bytes();
|
|
4755
4936
|
init_codec2();
|
|
4756
4937
|
init_packed();
|
|
4757
4938
|
init_context();
|
|
4758
4939
|
WS_ACCEPT_SCRATCH = new Uint8Array(64);
|
|
4940
|
+
CHARSET_KEY_BYTES = new Uint8Array([99, 104, 97, 114, 115, 101, 116]);
|
|
4941
|
+
BOUNDARY_KEY_BYTES = new Uint8Array([98, 111, 117, 110, 100, 97, 114, 121]);
|
|
4759
4942
|
f32Bits = new Float32Array(1);
|
|
4760
4943
|
f32BitsU32 = new Uint32Array(f32Bits.buffer);
|
|
4761
4944
|
});
|
|
@@ -4835,6 +5018,7 @@ function buildPayload(ctx) {
|
|
|
4835
5018
|
const { builtins, transport } = ctx.runtime;
|
|
4836
5019
|
const HAS = { gzipCompress: builtins.has("gzipCompress") };
|
|
4837
5020
|
const ffi = memoizeFfi(transport);
|
|
5021
|
+
let SCRATCH = null;
|
|
4838
5022
|
return {
|
|
4839
5023
|
gzipCompress(data, level) {
|
|
4840
5024
|
if (HAS.gzipCompress)
|
|
@@ -4888,8 +5072,20 @@ function buildPayload(ctx) {
|
|
|
4888
5072
|
},
|
|
4889
5073
|
multipartParse(body, boundary) {
|
|
4890
5074
|
const f = ffi();
|
|
4891
|
-
if (f)
|
|
4892
|
-
|
|
5075
|
+
if (f) {
|
|
5076
|
+
const need = body.length + boundary.length + 64;
|
|
5077
|
+
if (need > 64 * 1024)
|
|
5078
|
+
return unpackMultipart(f.multipartParsePacked(body, boundary));
|
|
5079
|
+
if (!SCRATCH || SCRATCH.length < need)
|
|
5080
|
+
SCRATCH = new Uint8Array(need);
|
|
5081
|
+
let w;
|
|
5082
|
+
try {
|
|
5083
|
+
w = f.multipartParsePackedInto(body, boundary, SCRATCH);
|
|
5084
|
+
} catch {
|
|
5085
|
+
return unpackMultipart(f.multipartParsePacked(body, boundary));
|
|
5086
|
+
}
|
|
5087
|
+
return unpackMultipart(SCRATCH.subarray(0, w));
|
|
5088
|
+
}
|
|
4893
5089
|
return addon.multipartParse(body, boundary).map((p) => ({
|
|
4894
5090
|
name: p.name,
|
|
4895
5091
|
filename: p.filename ?? null,
|
|
@@ -5053,13 +5249,13 @@ var init_scalar = __esm(() => {
|
|
|
5053
5249
|
// src/rust-ffi/text.ts
|
|
5054
5250
|
function buildText(ctx) {
|
|
5055
5251
|
const { builtins, transport } = ctx.runtime;
|
|
5056
|
-
const mimeStrCache = new Map;
|
|
5057
5252
|
return {
|
|
5058
5253
|
mimeFromExtension(ext) {
|
|
5059
5254
|
let mime = mimeStrCache.get(ext);
|
|
5060
5255
|
if (mime === undefined) {
|
|
5061
5256
|
const f = transport.ffi;
|
|
5062
5257
|
mime = f ? f.mimeFromExtension(ext) ?? "application/octet-stream" : decoder.decode(ctx.cachedMime(encoder.encode(ext)));
|
|
5258
|
+
evictOldestHalf(mimeStrCache);
|
|
5063
5259
|
mimeStrCache.set(ext, mime);
|
|
5064
5260
|
}
|
|
5065
5261
|
return mime;
|
|
@@ -5318,10 +5514,13 @@ function createNativeRoute(plan = {}) {
|
|
|
5318
5514
|
const parseQuery = plan.parseQuery === true;
|
|
5319
5515
|
const parseCookies = plan.parseCookies === true;
|
|
5320
5516
|
const bunFFI = getBunFFI();
|
|
5321
|
-
|
|
5322
|
-
|
|
5517
|
+
let ffiHandle = bunFFI !== null ? compileFfi(bunFFI, descriptor) : 0;
|
|
5518
|
+
let napiRoute = bunFFI === null || ffiHandle === 0 ? compileNapi(descriptor) : null;
|
|
5323
5519
|
let out = new Uint8Array(256);
|
|
5324
5520
|
const runFrame = (frame) => {
|
|
5521
|
+
if (ffiHandle === 0 && napiRoute === null) {
|
|
5522
|
+
throw new Error("native route: already destroyed");
|
|
5523
|
+
}
|
|
5325
5524
|
let written;
|
|
5326
5525
|
if (ffiHandle !== 0 && bunFFI !== null) {
|
|
5327
5526
|
written = bunFFI.routeRun(ffiHandle, frame, out);
|
|
@@ -5354,7 +5553,10 @@ function createNativeRoute(plan = {}) {
|
|
|
5354
5553
|
destroy: () => {
|
|
5355
5554
|
if (ffiHandle !== 0 && bunFFI !== null) {
|
|
5356
5555
|
bunFFI.routeDestroy(ffiHandle);
|
|
5556
|
+
ffiHandle = 0;
|
|
5357
5557
|
}
|
|
5558
|
+
napiRoute?.destroy?.();
|
|
5559
|
+
napiRoute = null;
|
|
5358
5560
|
}
|
|
5359
5561
|
};
|
|
5360
5562
|
}
|
|
@@ -5378,6 +5580,26 @@ function compileNapi(descriptor) {
|
|
|
5378
5580
|
}
|
|
5379
5581
|
}
|
|
5380
5582
|
|
|
5583
|
+
// src/ingress/abort.ts
|
|
5584
|
+
var ABORT_CODE = "REQUEST_ABORTED";
|
|
5585
|
+
function isAbortError(err) {
|
|
5586
|
+
return err?.code === ABORT_CODE;
|
|
5587
|
+
}
|
|
5588
|
+
function abortResponse() {
|
|
5589
|
+
return new Response(null, { status: 499 });
|
|
5590
|
+
}
|
|
5591
|
+
|
|
5592
|
+
// src/ingress/headers/memoized-headers.ts
|
|
5593
|
+
var CACHE = new WeakMap;
|
|
5594
|
+
function memoizedHeaders(entries) {
|
|
5595
|
+
const existing = CACHE.get(entries);
|
|
5596
|
+
if (existing !== undefined)
|
|
5597
|
+
return existing;
|
|
5598
|
+
const built = new Headers(entries);
|
|
5599
|
+
CACHE.set(entries, built);
|
|
5600
|
+
return built;
|
|
5601
|
+
}
|
|
5602
|
+
|
|
5381
5603
|
// src/ingress/shared.ts
|
|
5382
5604
|
var DEFAULT_MAX_BODY_BYTES = 1048576;
|
|
5383
5605
|
var DEFAULT_FAST_OUTPUT_BUFFER_SIZE = 262144;
|
|
@@ -5420,13 +5642,16 @@ function resolveIp(req, srv, opts) {
|
|
|
5420
5642
|
return opts.getIp ? opts.getIp(req, srv) : undefined;
|
|
5421
5643
|
}
|
|
5422
5644
|
function buildSuccessInit(ingress, result, ctx, status = 200) {
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
};
|
|
5645
|
+
const rateResetSecs = result.rateResetMs > 0 ? secondsFromMs(result.rateResetMs) : undefined;
|
|
5646
|
+
const headers = ingress.successHeaders ? ingress.successHeaders(result.headerVariant, ctx.requestIdHeader, ctx.origin, result.rateRemaining, rateResetSecs) : memoizedHeaders(ingress.responseHeaders(result.headerVariant, ctx.requestIdHeader, ctx.origin, result.rateRemaining, rateResetSecs));
|
|
5647
|
+
return { status, headers };
|
|
5427
5648
|
}
|
|
5428
5649
|
function runBaked(ingress, opts, respond) {
|
|
5429
|
-
return (req, srv) =>
|
|
5650
|
+
return (req, srv) => {
|
|
5651
|
+
if (req.signal?.aborted)
|
|
5652
|
+
return abortResponse();
|
|
5653
|
+
return ingress.run(req, resolveIp(req, srv, opts), null, respond);
|
|
5654
|
+
};
|
|
5430
5655
|
}
|
|
5431
5656
|
// src/ingress/routes/read.ts
|
|
5432
5657
|
function readHandler(ingress, opts = {}) {
|
|
@@ -5477,6 +5702,44 @@ function bodyTooLargeError() {
|
|
|
5477
5702
|
err.code = "BODY_TOO_LARGE";
|
|
5478
5703
|
return err;
|
|
5479
5704
|
}
|
|
5705
|
+
function abortError() {
|
|
5706
|
+
const err = new Error(ABORT_CODE);
|
|
5707
|
+
err.code = ABORT_CODE;
|
|
5708
|
+
return err;
|
|
5709
|
+
}
|
|
5710
|
+
function throwIfAborted(signal) {
|
|
5711
|
+
if (signal?.aborted)
|
|
5712
|
+
throw abortError();
|
|
5713
|
+
}
|
|
5714
|
+
function createAbortGuard(signal) {
|
|
5715
|
+
if (!signal)
|
|
5716
|
+
return null;
|
|
5717
|
+
if (signal.aborted) {
|
|
5718
|
+
return { promise: Promise.reject(abortError()), cancel: () => {} };
|
|
5719
|
+
}
|
|
5720
|
+
let listener = null;
|
|
5721
|
+
const promise = new Promise((_resolve, reject) => {
|
|
5722
|
+
listener = () => reject(abortError());
|
|
5723
|
+
signal.addEventListener("abort", listener, { once: true });
|
|
5724
|
+
});
|
|
5725
|
+
return {
|
|
5726
|
+
promise,
|
|
5727
|
+
cancel: () => {
|
|
5728
|
+
if (listener !== null) {
|
|
5729
|
+
signal.removeEventListener("abort", listener);
|
|
5730
|
+
listener = null;
|
|
5731
|
+
}
|
|
5732
|
+
}
|
|
5733
|
+
};
|
|
5734
|
+
}
|
|
5735
|
+
function raceRead(read, guards) {
|
|
5736
|
+
if (guards.length === 0)
|
|
5737
|
+
return read;
|
|
5738
|
+
const racers = [read];
|
|
5739
|
+
for (const guard of guards)
|
|
5740
|
+
racers.push(guard.promise);
|
|
5741
|
+
return Promise.race(racers);
|
|
5742
|
+
}
|
|
5480
5743
|
var bodyWatchdog = (() => {
|
|
5481
5744
|
const inflight = new Set;
|
|
5482
5745
|
let timer = null;
|
|
@@ -5528,6 +5791,7 @@ function createDeadline(deadlineMs) {
|
|
|
5528
5791
|
return { promise, cancel: () => bodyWatchdog.untrack(entry) };
|
|
5529
5792
|
}
|
|
5530
5793
|
async function readBodyWithLimit(req, maxBytes, guard, timeoutMs) {
|
|
5794
|
+
throwIfAborted(req.signal);
|
|
5531
5795
|
const deadline = timeoutMs && timeoutMs > 0 ? timeoutMs : 0;
|
|
5532
5796
|
const declared = req.headers.get("content-length");
|
|
5533
5797
|
if (declared !== null) {
|
|
@@ -5537,45 +5801,67 @@ async function readBodyWithLimit(req, maxBytes, guard, timeoutMs) {
|
|
|
5537
5801
|
throw bodyTooLargeError();
|
|
5538
5802
|
}
|
|
5539
5803
|
if (deadline <= 0) {
|
|
5540
|
-
const
|
|
5541
|
-
if (
|
|
5542
|
-
|
|
5804
|
+
const buffered = peekBufferedBody(req);
|
|
5805
|
+
if (buffered !== false && "bytes" in buffered) {
|
|
5806
|
+
throwIfAborted(req.signal);
|
|
5807
|
+
if (guard && buffered.bytes.byteLength > maxBytes) {
|
|
5808
|
+
throw bodyTooLargeError();
|
|
5809
|
+
}
|
|
5810
|
+
return buffered.bytes;
|
|
5811
|
+
}
|
|
5812
|
+
const abort = createAbortGuard(req.signal);
|
|
5813
|
+
try {
|
|
5814
|
+
const bytes = await raceRead(buffered === false ? readBodyBytes(req) : buffered, abort !== null ? [abort] : []);
|
|
5815
|
+
throwIfAborted(req.signal);
|
|
5816
|
+
if (guard && bytes.byteLength > maxBytes) {
|
|
5817
|
+
throw bodyTooLargeError();
|
|
5818
|
+
}
|
|
5819
|
+
return bytes;
|
|
5820
|
+
} finally {
|
|
5821
|
+
abort?.cancel();
|
|
5543
5822
|
}
|
|
5544
|
-
return bytes;
|
|
5545
5823
|
}
|
|
5546
5824
|
const buffered = peekBufferedBody(req);
|
|
5547
5825
|
if (buffered === false) {
|
|
5548
5826
|
const dl = createDeadline(deadline);
|
|
5827
|
+
const abort = createAbortGuard(req.signal);
|
|
5549
5828
|
try {
|
|
5550
|
-
const bytes = await
|
|
5829
|
+
const bytes = await raceRead(readBodyBytes(req), abort !== null ? [dl, abort] : [dl]);
|
|
5830
|
+
throwIfAborted(req.signal);
|
|
5551
5831
|
if (guard && bytes.byteLength > maxBytes) {
|
|
5552
5832
|
throw bodyTooLargeError();
|
|
5553
5833
|
}
|
|
5554
5834
|
return bytes;
|
|
5555
5835
|
} finally {
|
|
5556
5836
|
dl.cancel();
|
|
5837
|
+
abort?.cancel();
|
|
5557
5838
|
}
|
|
5558
5839
|
}
|
|
5559
5840
|
if ("bytes" in buffered) {
|
|
5841
|
+
throwIfAborted(req.signal);
|
|
5560
5842
|
if (guard && buffered.bytes.byteLength > maxBytes) {
|
|
5561
5843
|
throw bodyTooLargeError();
|
|
5562
5844
|
}
|
|
5563
5845
|
return buffered.bytes;
|
|
5564
5846
|
}
|
|
5565
5847
|
const dl = createDeadline(deadline);
|
|
5848
|
+
const abort = createAbortGuard(req.signal);
|
|
5566
5849
|
try {
|
|
5567
|
-
const bytes = await
|
|
5850
|
+
const bytes = await raceRead(buffered, abort !== null ? [dl, abort] : [dl]);
|
|
5851
|
+
throwIfAborted(req.signal);
|
|
5568
5852
|
if (guard && bytes.byteLength > maxBytes) {
|
|
5569
5853
|
throw bodyTooLargeError();
|
|
5570
5854
|
}
|
|
5571
5855
|
return bytes;
|
|
5572
5856
|
} finally {
|
|
5573
5857
|
dl.cancel();
|
|
5858
|
+
abort?.cancel();
|
|
5574
5859
|
}
|
|
5575
5860
|
}
|
|
5576
5861
|
}
|
|
5577
5862
|
const body = req.body;
|
|
5578
5863
|
if (!body) {
|
|
5864
|
+
throwIfAborted(req.signal);
|
|
5579
5865
|
return EMPTY_BODY;
|
|
5580
5866
|
}
|
|
5581
5867
|
const reader = body.getReader();
|
|
@@ -5583,9 +5869,15 @@ async function readBodyWithLimit(req, maxBytes, guard, timeoutMs) {
|
|
|
5583
5869
|
let total = 0;
|
|
5584
5870
|
let completed = false;
|
|
5585
5871
|
const dl = deadline > 0 ? createDeadline(deadline) : null;
|
|
5872
|
+
const abort = createAbortGuard(req.signal);
|
|
5873
|
+
const guards = [];
|
|
5874
|
+
if (dl !== null)
|
|
5875
|
+
guards.push(dl);
|
|
5876
|
+
if (abort !== null)
|
|
5877
|
+
guards.push(abort);
|
|
5586
5878
|
try {
|
|
5587
5879
|
for (;; ) {
|
|
5588
|
-
const { done, value } =
|
|
5880
|
+
const { done, value } = await raceRead(reader.read(), guards);
|
|
5589
5881
|
if (done) {
|
|
5590
5882
|
completed = true;
|
|
5591
5883
|
break;
|
|
@@ -5600,6 +5892,7 @@ async function readBodyWithLimit(req, maxBytes, guard, timeoutMs) {
|
|
|
5600
5892
|
}
|
|
5601
5893
|
} finally {
|
|
5602
5894
|
dl?.cancel();
|
|
5895
|
+
abort?.cancel();
|
|
5603
5896
|
if (!completed) {
|
|
5604
5897
|
await reader.cancel().catch(() => {});
|
|
5605
5898
|
}
|
|
@@ -5802,11 +6095,25 @@ function rateLimitedBody(retryAfterMs) {
|
|
|
5802
6095
|
}
|
|
5803
6096
|
|
|
5804
6097
|
// src/ingress/routes/echo.ts
|
|
6098
|
+
var SAFE_ECHO_CONTENT_TYPES = new Set([
|
|
6099
|
+
"application/json",
|
|
6100
|
+
"application/octet-stream",
|
|
6101
|
+
"text/plain"
|
|
6102
|
+
]);
|
|
6103
|
+
function echoMediaTypeOf(contentType) {
|
|
6104
|
+
const semi = contentType.indexOf(";");
|
|
6105
|
+
return (semi >= 0 ? contentType.slice(0, semi) : contentType).trim().toLowerCase();
|
|
6106
|
+
}
|
|
6107
|
+
function safeEchoContentType(contentType) {
|
|
6108
|
+
return SAFE_ECHO_CONTENT_TYPES.has(echoMediaTypeOf(contentType)) ? contentType : "application/octet-stream";
|
|
6109
|
+
}
|
|
5805
6110
|
function echoHandler(ingress, opts = {}) {
|
|
5806
6111
|
const maxBodyBytes = opts.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
|
|
5807
6112
|
const bodyTimeoutMs = opts.bodyTimeoutMs ?? DEFAULT_BODY_TIMEOUT_MS;
|
|
5808
6113
|
return async (req, srv) => {
|
|
5809
6114
|
const ip = resolveIp(req, srv, opts);
|
|
6115
|
+
if (req.signal?.aborted)
|
|
6116
|
+
return abortResponse();
|
|
5810
6117
|
const prep = ingress.run(req, ip, null, (result, ctx) => {
|
|
5811
6118
|
const terminal = ingress.terminalResponse(req, result, ctx);
|
|
5812
6119
|
if (terminal)
|
|
@@ -5821,41 +6128,54 @@ function echoHandler(ingress, opts = {}) {
|
|
|
5821
6128
|
});
|
|
5822
6129
|
if (prep.terminal)
|
|
5823
6130
|
return prep.terminal;
|
|
6131
|
+
if (req.signal?.aborted)
|
|
6132
|
+
return abortResponse();
|
|
5824
6133
|
const baseHeaders = prep.headers ?? [];
|
|
5825
|
-
const requestedContentType = req.headers.get("content-type") ?? "application/octet-stream";
|
|
6134
|
+
const requestedContentType = safeEchoContentType(req.headers.get("content-type") ?? "application/octet-stream");
|
|
6135
|
+
const withEchoHeaders = (contentType) => {
|
|
6136
|
+
const headers = ingress.withContentType(baseHeaders, contentType);
|
|
6137
|
+
if (!headers.some(([name]) => name.toLowerCase() === "x-content-type-options")) {
|
|
6138
|
+
headers.push(["x-content-type-options", "nosniff"]);
|
|
6139
|
+
}
|
|
6140
|
+
return headers;
|
|
6141
|
+
};
|
|
5826
6142
|
const contentLengthHeader = req.headers.get("content-length");
|
|
5827
6143
|
const contentLength = contentLengthHeader === null ? NaN : Number(contentLengthHeader);
|
|
5828
6144
|
if (Number.isFinite(contentLength)) {
|
|
5829
6145
|
if (contentLength > maxBodyBytes) {
|
|
5830
6146
|
return new Response(ERROR_BODIES.body_too_large, {
|
|
5831
6147
|
status: 413,
|
|
5832
|
-
headers:
|
|
6148
|
+
headers: withEchoHeaders("application/json")
|
|
5833
6149
|
});
|
|
5834
6150
|
}
|
|
5835
6151
|
if (contentLength <= 0 || req.body === null) {
|
|
5836
6152
|
return new Response(null, {
|
|
5837
6153
|
status: 200,
|
|
5838
|
-
headers:
|
|
6154
|
+
headers: withEchoHeaders(requestedContentType)
|
|
5839
6155
|
});
|
|
5840
6156
|
}
|
|
5841
6157
|
return new Response(req.body, {
|
|
5842
6158
|
status: 200,
|
|
5843
|
-
headers:
|
|
6159
|
+
headers: withEchoHeaders(requestedContentType)
|
|
5844
6160
|
});
|
|
5845
6161
|
}
|
|
5846
6162
|
try {
|
|
5847
6163
|
const bodyBytes = await readBodyWithLimit(req, maxBodyBytes, true, bodyTimeoutMs);
|
|
6164
|
+
if (req.signal?.aborted)
|
|
6165
|
+
return abortResponse();
|
|
5848
6166
|
return new Response(bodyBytes.byteLength > 0 ? bodyBytes : null, {
|
|
5849
6167
|
status: 200,
|
|
5850
|
-
headers:
|
|
6168
|
+
headers: withEchoHeaders(requestedContentType)
|
|
5851
6169
|
});
|
|
5852
6170
|
} catch (err) {
|
|
6171
|
+
if (isAbortError(err))
|
|
6172
|
+
return abortResponse();
|
|
5853
6173
|
const code = err?.code;
|
|
5854
6174
|
const isTooLarge = code === "BODY_TOO_LARGE";
|
|
5855
6175
|
const isTimeout = code === "REQUEST_TIMEOUT";
|
|
5856
6176
|
return new Response(isTooLarge ? ERROR_BODIES.body_too_large : isTimeout ? ERROR_BODIES.request_timeout : ERROR_BODIES.bad_request, {
|
|
5857
6177
|
status: isTooLarge ? 413 : isTimeout ? 408 : 400,
|
|
5858
|
-
headers:
|
|
6178
|
+
headers: withEchoHeaders("application/json")
|
|
5859
6179
|
});
|
|
5860
6180
|
}
|
|
5861
6181
|
};
|
|
@@ -5893,6 +6213,11 @@ function defaultJsonValid(bytes) {
|
|
|
5893
6213
|
return false;
|
|
5894
6214
|
}
|
|
5895
6215
|
}
|
|
6216
|
+
function isJsonContentType(contentType) {
|
|
6217
|
+
const semi = contentType.indexOf(";");
|
|
6218
|
+
const mediaType = (semi >= 0 ? contentType.slice(0, semi) : contentType).trim().toLowerCase();
|
|
6219
|
+
return mediaType === "application/json" || mediaType.endsWith("+json");
|
|
6220
|
+
}
|
|
5896
6221
|
function jsonWriteHandler(ingress, opts = {}) {
|
|
5897
6222
|
const maxBodyBytes = opts.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
|
|
5898
6223
|
const fallback = opts.fallback ?? ingress;
|
|
@@ -5901,19 +6226,18 @@ function jsonWriteHandler(ingress, opts = {}) {
|
|
|
5901
6226
|
const jsonValid = opts.jsonValid ?? ingress.jsonValid ?? defaultJsonValid;
|
|
5902
6227
|
return async (req, srv) => {
|
|
5903
6228
|
const ip = resolveIp(req, srv, opts);
|
|
6229
|
+
if (req.signal?.aborted)
|
|
6230
|
+
return abortResponse();
|
|
5904
6231
|
const contentType = req.headers.get("content-type") ?? "";
|
|
5905
|
-
if (!contentType
|
|
5906
|
-
return fallback.run(req, ip, null, (result, ctx) =>
|
|
5907
|
-
const terminal = fallback.terminalResponse(req, result, ctx);
|
|
5908
|
-
if (terminal)
|
|
5909
|
-
return terminal;
|
|
5910
|
-
return fallback.errorResponse(req, result, 415, "unsupported_media_type", "Content-Type must be application/json", ctx);
|
|
5911
|
-
});
|
|
6232
|
+
if (!isJsonContentType(contentType)) {
|
|
6233
|
+
return fallback.run(req, ip, null, (result, ctx) => fallback.errorResponse(req, result, 415, "unsupported_media_type", "Content-Type must be application/json", ctx));
|
|
5912
6234
|
}
|
|
5913
6235
|
let bodyBytes;
|
|
5914
6236
|
try {
|
|
5915
6237
|
bodyBytes = await readBodyWithLimit(req, maxBodyBytes, true, bodyTimeoutMs);
|
|
5916
6238
|
} catch (err) {
|
|
6239
|
+
if (isAbortError(err))
|
|
6240
|
+
return abortResponse();
|
|
5917
6241
|
const code = err?.code;
|
|
5918
6242
|
const isTooLarge = code === "BODY_TOO_LARGE";
|
|
5919
6243
|
return fallback.run(req, ip, null, (result, ctx) => {
|
|
@@ -5923,6 +6247,8 @@ function jsonWriteHandler(ingress, opts = {}) {
|
|
|
5923
6247
|
return fallback.errorResponse(req, result, isTooLarge ? 413 : 408, isTooLarge ? "body_too_large" : "request_timeout", isTooLarge ? "Request body is too large" : "Request body read timed out", ctx);
|
|
5924
6248
|
});
|
|
5925
6249
|
}
|
|
6250
|
+
if (req.signal?.aborted)
|
|
6251
|
+
return abortResponse();
|
|
5926
6252
|
return ingress.run(req, ip, bodyBytes, (result, ctx) => {
|
|
5927
6253
|
const terminal = ingress.terminalResponse(req, result, ctx);
|
|
5928
6254
|
if (terminal)
|
|
@@ -5944,12 +6270,16 @@ function jsonWriteHandler(ingress, opts = {}) {
|
|
|
5944
6270
|
}
|
|
5945
6271
|
// src/ingress/routes/options.ts
|
|
5946
6272
|
function optionsHandler(ingress, opts = {}) {
|
|
5947
|
-
return (req, srv) =>
|
|
5948
|
-
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
6273
|
+
return (req, srv) => {
|
|
6274
|
+
if (req.signal?.aborted)
|
|
6275
|
+
return abortResponse();
|
|
6276
|
+
return ingress.run(req, resolveIp(req, srv, opts), null, (result, ctx) => {
|
|
6277
|
+
const terminal = ingress.terminalResponse(req, result, ctx);
|
|
6278
|
+
if (terminal)
|
|
6279
|
+
return terminal;
|
|
6280
|
+
return new Response(null, buildSuccessInit(ingress, result, ctx, 204));
|
|
6281
|
+
});
|
|
6282
|
+
};
|
|
5953
6283
|
}
|
|
5954
6284
|
// src/ingress/routes/responder.ts
|
|
5955
6285
|
init_bytes();
|
|
@@ -6093,7 +6423,7 @@ function safeTerminalStatus(r) {
|
|
|
6093
6423
|
}
|
|
6094
6424
|
|
|
6095
6425
|
// src/ingress/routes/responder.ts
|
|
6096
|
-
var
|
|
6426
|
+
var IGNEX_SECURITY_HEADERS = [
|
|
6097
6427
|
["x-frame-options", "DENY"],
|
|
6098
6428
|
["x-content-type-options", "nosniff"],
|
|
6099
6429
|
["referrer-policy", "no-referrer"]
|
|
@@ -6101,7 +6431,7 @@ var IGNGEX_SECURITY_HEADERS = [
|
|
|
6101
6431
|
function buildIgngexTerminal(result, _ctx) {
|
|
6102
6432
|
const preflightAllowed = result.isPreflight && result.corsAllowed;
|
|
6103
6433
|
if (preflightAllowed) {
|
|
6104
|
-
return new Response(null, { status: 204, headers:
|
|
6434
|
+
return new Response(null, { status: 204, headers: IGNEX_SECURITY_HEADERS });
|
|
6105
6435
|
}
|
|
6106
6436
|
const status = safeTerminalStatus(result);
|
|
6107
6437
|
const body = JSON.stringify({
|
|
@@ -6109,14 +6439,14 @@ function buildIgngexTerminal(result, _ctx) {
|
|
|
6109
6439
|
status,
|
|
6110
6440
|
code: errorCodeName(result.errorCode)
|
|
6111
6441
|
});
|
|
6112
|
-
const headers = new Headers(
|
|
6442
|
+
const headers = new Headers(IGNEX_SECURITY_HEADERS);
|
|
6113
6443
|
headers.set("content-type", "application/json; charset=utf-8");
|
|
6114
6444
|
return new Response(body, { status, headers });
|
|
6115
6445
|
}
|
|
6116
6446
|
function parseSection(json) {
|
|
6117
6447
|
try {
|
|
6118
|
-
const
|
|
6119
|
-
return
|
|
6448
|
+
const parsed = JSON.parse(json);
|
|
6449
|
+
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
6120
6450
|
} catch {
|
|
6121
6451
|
return {};
|
|
6122
6452
|
}
|
|
@@ -6128,19 +6458,25 @@ function nativeResponderRoute(ingress, responder, opts = {}) {
|
|
|
6128
6458
|
const bodyTimeoutMs = opts.bodyTimeoutMs ?? DEFAULT_BODY_TIMEOUT_MS;
|
|
6129
6459
|
return async (req, srv, _params) => {
|
|
6130
6460
|
const ip = resolveIp(req, srv, opts);
|
|
6461
|
+
if (req.signal?.aborted)
|
|
6462
|
+
return abortResponse();
|
|
6131
6463
|
const requestId = decoder.decode(generateRequestId());
|
|
6132
6464
|
let body = null;
|
|
6133
6465
|
if (readBody) {
|
|
6134
6466
|
try {
|
|
6135
6467
|
body = await readBodyWithLimit(req, maxBodyBytes, true, bodyTimeoutMs);
|
|
6136
6468
|
} catch (err) {
|
|
6469
|
+
if (isAbortError(err))
|
|
6470
|
+
return abortResponse();
|
|
6137
6471
|
const code = err.code;
|
|
6138
6472
|
const status = code === "REQUEST_TIMEOUT" ? 408 : code === "BODY_TOO_LARGE" ? 413 : 400;
|
|
6139
6473
|
const payload = JSON.stringify({ error: "Bad Request", status, code: "BAD_REQUEST" });
|
|
6140
|
-
const headers = new Headers(
|
|
6474
|
+
const headers = new Headers(IGNEX_SECURITY_HEADERS);
|
|
6141
6475
|
headers.set("content-type", "application/json; charset=utf-8");
|
|
6142
6476
|
return new Response(payload, { status, headers });
|
|
6143
6477
|
}
|
|
6478
|
+
if (req.signal?.aborted)
|
|
6479
|
+
return abortResponse();
|
|
6144
6480
|
}
|
|
6145
6481
|
let terminal = null;
|
|
6146
6482
|
let snapshot = null;
|
|
@@ -6175,10 +6511,30 @@ function nativeResponderRoute(ingress, responder, opts = {}) {
|
|
|
6175
6511
|
}
|
|
6176
6512
|
// src/ingress/routes/native.ts
|
|
6177
6513
|
init_bytes();
|
|
6514
|
+
|
|
6515
|
+
// src/ingress/routes/safe-record.ts
|
|
6516
|
+
var PROTO_KEY = "__proto__";
|
|
6517
|
+
function safeRecord() {
|
|
6518
|
+
return {};
|
|
6519
|
+
}
|
|
6520
|
+
function assignOwn(target, key, value) {
|
|
6521
|
+
if (key === PROTO_KEY) {
|
|
6522
|
+
Object.defineProperty(target, key, {
|
|
6523
|
+
value,
|
|
6524
|
+
enumerable: true,
|
|
6525
|
+
writable: true,
|
|
6526
|
+
configurable: true
|
|
6527
|
+
});
|
|
6528
|
+
return;
|
|
6529
|
+
}
|
|
6530
|
+
target[key] = value;
|
|
6531
|
+
}
|
|
6532
|
+
|
|
6533
|
+
// src/ingress/routes/native.ts
|
|
6178
6534
|
function pairsToRecord(pairs) {
|
|
6179
|
-
const out =
|
|
6535
|
+
const out = safeRecord();
|
|
6180
6536
|
for (const [k, v] of pairs)
|
|
6181
|
-
out
|
|
6537
|
+
assignOwn(out, k, v);
|
|
6182
6538
|
return out;
|
|
6183
6539
|
}
|
|
6184
6540
|
function nativeRouteHandler(route, responder, opts = {}) {
|
|
@@ -6190,16 +6546,22 @@ function nativeRouteHandler(route, responder, opts = {}) {
|
|
|
6190
6546
|
const terminal = (status, code, message) => Response.json({ ok: false, error: { code, message } }, { status, headers: { "content-type": "application/json" } });
|
|
6191
6547
|
return async (req, srv, _params) => {
|
|
6192
6548
|
const ip = resolveIp(req, srv, opts);
|
|
6549
|
+
if (req.signal?.aborted)
|
|
6550
|
+
return abortResponse();
|
|
6193
6551
|
const requestId = decoder.decode(generateRequestId());
|
|
6194
6552
|
let body = null;
|
|
6195
6553
|
if (readBody) {
|
|
6196
6554
|
try {
|
|
6197
6555
|
body = await readBodyWithLimit(req, maxBodyBytes, true, bodyTimeoutMs);
|
|
6198
6556
|
} catch (err) {
|
|
6557
|
+
if (isAbortError(err))
|
|
6558
|
+
return abortResponse();
|
|
6199
6559
|
const code = err.code;
|
|
6200
6560
|
const status = code === "REQUEST_TIMEOUT" ? 408 : code === "BODY_TOO_LARGE" ? 413 : 400;
|
|
6201
6561
|
return terminal(status, "BAD_REQUEST", "Request body read failed");
|
|
6202
6562
|
}
|
|
6563
|
+
if (req.signal?.aborted)
|
|
6564
|
+
return abortResponse();
|
|
6203
6565
|
}
|
|
6204
6566
|
const url = req.url;
|
|
6205
6567
|
const qIndex = url.indexOf("?");
|
|
@@ -6235,6 +6597,49 @@ function nativeRouteHandler(route, responder, opts = {}) {
|
|
|
6235
6597
|
};
|
|
6236
6598
|
}
|
|
6237
6599
|
|
|
6600
|
+
// src/ingress/server-error.ts
|
|
6601
|
+
function toError(value) {
|
|
6602
|
+
return value instanceof Error ? value : new Error(String(value));
|
|
6603
|
+
}
|
|
6604
|
+
var INTERNAL_HEADERS = [
|
|
6605
|
+
["content-type", "application/json; charset=utf-8"]
|
|
6606
|
+
];
|
|
6607
|
+
function createServerErrorHandler(opts) {
|
|
6608
|
+
const headers = memoizedHeaders(INTERNAL_HEADERS);
|
|
6609
|
+
return (error, req) => {
|
|
6610
|
+
const err = toError(error);
|
|
6611
|
+
if (opts.onError) {
|
|
6612
|
+
try {
|
|
6613
|
+
opts.onError({ error: err, request: req });
|
|
6614
|
+
} catch {}
|
|
6615
|
+
}
|
|
6616
|
+
if (opts.logger) {
|
|
6617
|
+
try {
|
|
6618
|
+
opts.logger(JSON.stringify({
|
|
6619
|
+
level: "error",
|
|
6620
|
+
msg: "unhandled_handler_error",
|
|
6621
|
+
error: err.message
|
|
6622
|
+
}));
|
|
6623
|
+
} catch {}
|
|
6624
|
+
}
|
|
6625
|
+
return new Response(ERROR_BODIES.internal, { status: 500, headers });
|
|
6626
|
+
};
|
|
6627
|
+
}
|
|
6628
|
+
function guardRouteHandler(handler, onServerError) {
|
|
6629
|
+
return (req, srv, params) => {
|
|
6630
|
+
try {
|
|
6631
|
+
const out = handler(req, srv, params);
|
|
6632
|
+
const thenable = out;
|
|
6633
|
+
if (thenable !== null && thenable !== undefined && typeof thenable.then === "function") {
|
|
6634
|
+
return thenable.catch((e) => onServerError(e, req));
|
|
6635
|
+
}
|
|
6636
|
+
return out;
|
|
6637
|
+
} catch (e) {
|
|
6638
|
+
return onServerError(e, req);
|
|
6639
|
+
}
|
|
6640
|
+
};
|
|
6641
|
+
}
|
|
6642
|
+
|
|
6238
6643
|
// src/ingress/path-matcher.ts
|
|
6239
6644
|
function buildPathMatcher(routes) {
|
|
6240
6645
|
const exact = new Map;
|
|
@@ -6342,6 +6747,10 @@ function buildRouteHandlers(options) {
|
|
|
6342
6747
|
getIp: options.getIp,
|
|
6343
6748
|
copyBody: options.copyBody
|
|
6344
6749
|
};
|
|
6750
|
+
const onServerError = createServerErrorHandler({
|
|
6751
|
+
onError: options.onError,
|
|
6752
|
+
logger: options.logger
|
|
6753
|
+
});
|
|
6345
6754
|
const serverRoutes = {};
|
|
6346
6755
|
for (const [path, spec] of Object.entries(options.routes)) {
|
|
6347
6756
|
const routeOpts = {
|
|
@@ -6350,9 +6759,12 @@ function buildRouteHandlers(options) {
|
|
|
6350
6759
|
bodyTimeoutMs: spec.bodyTimeoutMs
|
|
6351
6760
|
};
|
|
6352
6761
|
const methods = {};
|
|
6353
|
-
|
|
6762
|
+
const hasStatic = spec.static !== undefined;
|
|
6763
|
+
if (hasStatic) {
|
|
6764
|
+
methods.GET = typeof spec.static === "function" ? guardRouteHandler(spec.static, onServerError) : spec.static;
|
|
6765
|
+
} else if (spec.read) {
|
|
6354
6766
|
if (typeof spec.read === "function") {
|
|
6355
|
-
methods.GET = spec.read;
|
|
6767
|
+
methods.GET = guardRouteHandler(spec.read, onServerError);
|
|
6356
6768
|
} else {
|
|
6357
6769
|
methods.GET = readHandler(spec.read, routeOpts);
|
|
6358
6770
|
methods.HEAD = headHandler(spec.read, routeOpts);
|
|
@@ -6370,34 +6782,40 @@ function buildRouteHandlers(options) {
|
|
|
6370
6782
|
if (spec.echo) {
|
|
6371
6783
|
methods.POST = echoHandler(spec.echo, routeOpts);
|
|
6372
6784
|
}
|
|
6373
|
-
if (spec.cookies) {
|
|
6785
|
+
if (spec.cookies && !hasStatic) {
|
|
6374
6786
|
methods.GET = readHandler(spec.cookies, routeOpts);
|
|
6375
6787
|
}
|
|
6376
6788
|
if (spec.delete) {
|
|
6377
6789
|
methods.DELETE = deleteHandler(spec.delete, routeOpts);
|
|
6378
6790
|
}
|
|
6379
6791
|
if (spec.responder) {
|
|
6380
|
-
const
|
|
6381
|
-
|
|
6382
|
-
|
|
6383
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6792
|
+
const responderMethods = (spec.responder.methods ?? ["GET"]).filter((m) => !(hasStatic && m === "GET"));
|
|
6793
|
+
if (responderMethods.length > 0) {
|
|
6794
|
+
const responderRoute = nativeResponderRoute(spec.responder.ingress, spec.responder.handler, {
|
|
6795
|
+
...routeOpts,
|
|
6796
|
+
terminalStyle: spec.responder.terminalStyle,
|
|
6797
|
+
readBody: spec.responder.readBody
|
|
6798
|
+
});
|
|
6799
|
+
const guardedResponderRoute = guardRouteHandler(responderRoute, onServerError);
|
|
6800
|
+
for (const m of responderMethods) {
|
|
6801
|
+
methods[m] = guardedResponderRoute;
|
|
6802
|
+
}
|
|
6388
6803
|
}
|
|
6389
6804
|
}
|
|
6390
6805
|
if (spec.native) {
|
|
6391
|
-
const
|
|
6392
|
-
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
|
|
6396
|
-
|
|
6397
|
-
|
|
6806
|
+
const nativeMethods = (spec.native.methods ?? ["GET"]).filter((m) => !(hasStatic && m === "GET"));
|
|
6807
|
+
if (nativeMethods.length > 0) {
|
|
6808
|
+
const nativeRoute = nativeRouteHandler(createNativeRoute(spec.native.plan), spec.native.handler, {
|
|
6809
|
+
...routeOpts,
|
|
6810
|
+
readBody: spec.native.readBody
|
|
6811
|
+
});
|
|
6812
|
+
const guardedNativeRoute = guardRouteHandler(nativeRoute, onServerError);
|
|
6813
|
+
for (const m of nativeMethods) {
|
|
6814
|
+
methods[m] = guardedNativeRoute;
|
|
6815
|
+
}
|
|
6398
6816
|
}
|
|
6399
6817
|
}
|
|
6400
|
-
const primary = spec.delete ?? (spec.read && typeof spec.read !== "function" ? spec.read : undefined) ?? spec.cookies ?? spec.write ?? spec.echo;
|
|
6818
|
+
const primary = spec.delete ?? (!hasStatic && spec.read && typeof spec.read !== "function" ? spec.read : undefined) ?? (!hasStatic ? spec.cookies : undefined) ?? spec.write ?? spec.echo;
|
|
6401
6819
|
if (primary) {
|
|
6402
6820
|
methods.OPTIONS = optionsHandler(primary, routeOpts);
|
|
6403
6821
|
}
|
|
@@ -6410,12 +6828,17 @@ function createIngressServer(options) {
|
|
|
6410
6828
|
throw new TypeError("createIngressServer is Bun-only (it builds a Bun.serve config). " + "On Node.js use createIngressServerNode with the same route handlers.");
|
|
6411
6829
|
}
|
|
6412
6830
|
const { routes: serverRoutes, baseOpts } = buildRouteHandlers(options);
|
|
6831
|
+
const onServerError = createServerErrorHandler({
|
|
6832
|
+
onError: options.onError,
|
|
6833
|
+
logger: options.logger
|
|
6834
|
+
});
|
|
6413
6835
|
const serverOptions = {
|
|
6414
6836
|
hostname: options.hostname ?? "0.0.0.0",
|
|
6415
6837
|
port: options.port,
|
|
6416
6838
|
idleTimeout: options.idleTimeout ?? 30,
|
|
6417
6839
|
routes: serverRoutes,
|
|
6418
|
-
maxRequestBodySize: options.maxRequestBodySize ?? DEFAULT_MAX_REQUEST_BODY_SIZE
|
|
6840
|
+
maxRequestBodySize: options.maxRequestBodySize ?? DEFAULT_MAX_REQUEST_BODY_SIZE,
|
|
6841
|
+
error: (error, req) => onServerError(error, req)
|
|
6419
6842
|
};
|
|
6420
6843
|
if (options.reusePort) {
|
|
6421
6844
|
serverOptions.reusePort = true;
|
|
@@ -6468,8 +6891,15 @@ function nodeRequestToWebRequest(req) {
|
|
|
6468
6891
|
}
|
|
6469
6892
|
const method = req.method ?? "GET";
|
|
6470
6893
|
const bodyForbidden = method === "GET" || method === "HEAD";
|
|
6471
|
-
const hasBody =
|
|
6894
|
+
const hasBody = requestHasBody(req);
|
|
6472
6895
|
const init = { method, headers };
|
|
6896
|
+
const abort = new AbortController;
|
|
6897
|
+
req.on("aborted", () => abort.abort());
|
|
6898
|
+
req.on("close", () => {
|
|
6899
|
+
if (!req.complete)
|
|
6900
|
+
abort.abort();
|
|
6901
|
+
});
|
|
6902
|
+
init.signal = abort.signal;
|
|
6473
6903
|
if (hasBody && !bodyForbidden) {
|
|
6474
6904
|
init.body = Readable.toWeb(req);
|
|
6475
6905
|
init.duplex = "half";
|
|
@@ -6512,7 +6942,7 @@ async function writeResponse(res, response) {
|
|
|
6512
6942
|
}
|
|
6513
6943
|
function drainUnreadBody(res) {
|
|
6514
6944
|
const req = res.req;
|
|
6515
|
-
if (req !== undefined && req !== null && !req.complete &&
|
|
6945
|
+
if (req !== undefined && req !== null && !req.complete && requestHasBody(req)) {
|
|
6516
6946
|
req.resume();
|
|
6517
6947
|
res.shouldKeepAlive = false;
|
|
6518
6948
|
if (!res.headersSent) {
|
|
@@ -6520,11 +6950,39 @@ function drainUnreadBody(res) {
|
|
|
6520
6950
|
}
|
|
6521
6951
|
}
|
|
6522
6952
|
}
|
|
6523
|
-
function
|
|
6953
|
+
function requestHasBody(req) {
|
|
6524
6954
|
return Number(req.headers["content-length"] ?? 0) > 0 || req.headers["transfer-encoding"] !== undefined;
|
|
6525
6955
|
}
|
|
6956
|
+
var STATIC_RESPONSE_CACHE = new WeakMap;
|
|
6957
|
+
function materializeStaticResponse(response) {
|
|
6958
|
+
let cached = STATIC_RESPONSE_CACHE.get(response);
|
|
6959
|
+
if (cached === undefined) {
|
|
6960
|
+
cached = (async () => {
|
|
6961
|
+
const body = response.body === null ? null : new Uint8Array(await response.arrayBuffer());
|
|
6962
|
+
const headers = new Headers(response.headers);
|
|
6963
|
+
headers.delete("content-length");
|
|
6964
|
+
headers.delete("transfer-encoding");
|
|
6965
|
+
return {
|
|
6966
|
+
status: response.status,
|
|
6967
|
+
statusText: response.statusText,
|
|
6968
|
+
headers,
|
|
6969
|
+
body
|
|
6970
|
+
};
|
|
6971
|
+
})();
|
|
6972
|
+
STATIC_RESPONSE_CACHE.set(response, cached);
|
|
6973
|
+
}
|
|
6974
|
+
return cached.then((c) => new Response(c.body, {
|
|
6975
|
+
status: c.status,
|
|
6976
|
+
statusText: c.statusText,
|
|
6977
|
+
headers: new Headers(c.headers)
|
|
6978
|
+
}));
|
|
6979
|
+
}
|
|
6526
6980
|
function makeRequestListener(options, routes, baseOpts) {
|
|
6527
6981
|
const matchPath = buildPathMatcher(routes);
|
|
6982
|
+
const onServerError = createServerErrorHandler({
|
|
6983
|
+
onError: options.onError,
|
|
6984
|
+
logger: options.logger
|
|
6985
|
+
});
|
|
6528
6986
|
return async (req, res) => {
|
|
6529
6987
|
try {
|
|
6530
6988
|
const contentLengthHeader = req.headers["content-length"];
|
|
@@ -6545,10 +7003,19 @@ function makeRequestListener(options, routes, baseOpts) {
|
|
|
6545
7003
|
const pathname = new URL(webReq.url).pathname;
|
|
6546
7004
|
const method = webReq.method ?? "GET";
|
|
6547
7005
|
const matched = matchPath(pathname);
|
|
6548
|
-
const
|
|
7006
|
+
const entry = matched?.methods?.[method];
|
|
6549
7007
|
let response;
|
|
6550
|
-
if (
|
|
6551
|
-
|
|
7008
|
+
if (entry !== undefined && matched !== undefined) {
|
|
7009
|
+
if (typeof entry === "function") {
|
|
7010
|
+
response = await entry(webReq, req, matched.params);
|
|
7011
|
+
} else if (entry instanceof Response) {
|
|
7012
|
+
response = await materializeStaticResponse(entry);
|
|
7013
|
+
} else if (options.fallback !== undefined) {
|
|
7014
|
+
const fallback = fallbackHandler(options.fallback, baseOpts);
|
|
7015
|
+
response = await fallback(webReq, req);
|
|
7016
|
+
} else {
|
|
7017
|
+
response = new Response("Not Found", { status: 404 });
|
|
7018
|
+
}
|
|
6552
7019
|
} else if (options.fallback !== undefined) {
|
|
6553
7020
|
const fallback = fallbackHandler(options.fallback, baseOpts);
|
|
6554
7021
|
response = await fallback(webReq, req);
|
|
@@ -6558,24 +7025,31 @@ function makeRequestListener(options, routes, baseOpts) {
|
|
|
6558
7025
|
await writeResponse(res, response);
|
|
6559
7026
|
} catch (err) {
|
|
6560
7027
|
if (!res.headersSent) {
|
|
6561
|
-
res
|
|
6562
|
-
res.setHeader("content-type", "application/json");
|
|
6563
|
-
res.end(JSON.stringify({
|
|
6564
|
-
error: { code: "internal_error", message: "Internal Server Error" }
|
|
6565
|
-
}));
|
|
7028
|
+
await writeResponse(res, onServerError(err));
|
|
6566
7029
|
} else {
|
|
7030
|
+
onServerError(err);
|
|
6567
7031
|
res.destroy();
|
|
6568
7032
|
}
|
|
6569
|
-
if (options.onError) {
|
|
6570
|
-
try {
|
|
6571
|
-
options.onError({
|
|
6572
|
-
error: err instanceof Error ? err : new Error(String(err))
|
|
6573
|
-
});
|
|
6574
|
-
} catch {}
|
|
6575
|
-
}
|
|
6576
7033
|
}
|
|
6577
7034
|
};
|
|
6578
7035
|
}
|
|
7036
|
+
var WS_PROTOCOL_TOKEN = /^[A-Za-z0-9!#$%&'*+\-.^_`|~]+$/;
|
|
7037
|
+
function formatWebSocketHandshake(accept, protocol) {
|
|
7038
|
+
if (/[\r\n]/.test(accept)) {
|
|
7039
|
+
throw new Error("invalid Sec-WebSocket-Accept value");
|
|
7040
|
+
}
|
|
7041
|
+
let raw = `HTTP/1.1 101 Switching Protocols\r
|
|
7042
|
+
` + `Upgrade: websocket\r
|
|
7043
|
+
` + `Connection: Upgrade\r
|
|
7044
|
+
` + `Sec-WebSocket-Accept: ${accept}\r
|
|
7045
|
+
`;
|
|
7046
|
+
if (protocol && WS_PROTOCOL_TOKEN.test(protocol)) {
|
|
7047
|
+
raw += `Sec-WebSocket-Protocol: ${protocol}\r
|
|
7048
|
+
`;
|
|
7049
|
+
}
|
|
7050
|
+
return `${raw}\r
|
|
7051
|
+
`;
|
|
7052
|
+
}
|
|
6579
7053
|
function makeUpgradeListener(options) {
|
|
6580
7054
|
return async (req, socket, head) => {
|
|
6581
7055
|
try {
|
|
@@ -6585,18 +7059,7 @@ function makeUpgradeListener(options) {
|
|
|
6585
7059
|
socket.destroy();
|
|
6586
7060
|
return;
|
|
6587
7061
|
}
|
|
6588
|
-
|
|
6589
|
-
` + `Upgrade: websocket\r
|
|
6590
|
-
` + `Connection: Upgrade\r
|
|
6591
|
-
` + `Sec-WebSocket-Accept: ${handshake.accept}\r
|
|
6592
|
-
`;
|
|
6593
|
-
if (handshake.protocol) {
|
|
6594
|
-
raw += `Sec-WebSocket-Protocol: ${handshake.protocol}\r
|
|
6595
|
-
`;
|
|
6596
|
-
}
|
|
6597
|
-
raw += `\r
|
|
6598
|
-
`;
|
|
6599
|
-
socket.write(raw);
|
|
7062
|
+
socket.write(formatWebSocketHandshake(handshake.accept, handshake.protocol));
|
|
6600
7063
|
options.onUpgrade?.(socket, req, head);
|
|
6601
7064
|
} catch {
|
|
6602
7065
|
socket.destroy();
|
|
@@ -6820,6 +7283,7 @@ class IngressResultBase {
|
|
|
6820
7283
|
bodyTruncated = false;
|
|
6821
7284
|
body = EMPTY_BODY2;
|
|
6822
7285
|
_buf = EMPTY_BODY2;
|
|
7286
|
+
_len = 0;
|
|
6823
7287
|
_bodyJsonStart = OUT_DATA_START;
|
|
6824
7288
|
_bodyJsonLen = 0;
|
|
6825
7289
|
_cookiesBuf = null;
|
|
@@ -6845,6 +7309,7 @@ class IngressResultBase {
|
|
|
6845
7309
|
this.bodyTruncated = false;
|
|
6846
7310
|
this.body = EMPTY_BODY2;
|
|
6847
7311
|
this._buf = EMPTY_BODY2;
|
|
7312
|
+
this._len = 0;
|
|
6848
7313
|
this._bodyJsonStart = OUT_DATA_START;
|
|
6849
7314
|
this._bodyJsonLen = 0;
|
|
6850
7315
|
this._cookiesBuf = null;
|
|
@@ -6869,8 +7334,9 @@ class IngressResultBase {
|
|
|
6869
7334
|
this.retryAfterMs = 0;
|
|
6870
7335
|
}
|
|
6871
7336
|
}
|
|
6872
|
-
setSections(buf, layout, bodyJsonLen) {
|
|
7337
|
+
setSections(buf, layout, bodyJsonLen, len = buf.byteLength) {
|
|
6873
7338
|
this._buf = buf;
|
|
7339
|
+
this._len = len;
|
|
6874
7340
|
this._bodyJsonStart = layout.bodyJsonStart;
|
|
6875
7341
|
this._bodyJsonLen = bodyJsonLen;
|
|
6876
7342
|
this._cookiesBuf = layout.safeCookiesLen > 0 ? buf.subarray(OUT_DATA_START, OUT_DATA_START + layout.safeCookiesLen) : null;
|
|
@@ -6900,7 +7366,7 @@ class IngressResultBase {
|
|
|
6900
7366
|
if (this._bodyJsonLen === 0)
|
|
6901
7367
|
return EMPTY_BODY2;
|
|
6902
7368
|
const end = this._bodyJsonStart + this._bodyJsonLen;
|
|
6903
|
-
if (end > this.
|
|
7369
|
+
if (end > this._len)
|
|
6904
7370
|
return EMPTY_BODY2;
|
|
6905
7371
|
return this._buf.subarray(this._bodyJsonStart, end);
|
|
6906
7372
|
}
|
|
@@ -6964,7 +7430,7 @@ class FastIngressResult extends IngressResultBase {
|
|
|
6964
7430
|
this.isPreflight = (flags & FLAG_IS_PREFLIGHT) !== 0;
|
|
6965
7431
|
this.rateLimited = (flags & FLAG_RATE_LIMITED) !== 0;
|
|
6966
7432
|
const layout = sectionLayout(buf.byteLength, cookiesJsonLen, queryJsonLen, bodyJsonLen);
|
|
6967
|
-
this.setSections(buf, layout, bodyJsonLen);
|
|
7433
|
+
this.setSections(buf, layout, bodyJsonLen, buf.byteLength);
|
|
6968
7434
|
this.bodyTruncated = (flags & FLAG_BODY_TRUNCATED) !== 0 || layout.truncated;
|
|
6969
7435
|
}
|
|
6970
7436
|
invalidate() {
|
|
@@ -7056,7 +7522,14 @@ function warnTrustProxyDeprecated() {
|
|
|
7056
7522
|
if (trustProxyWarned)
|
|
7057
7523
|
return;
|
|
7058
7524
|
trustProxyWarned = true;
|
|
7059
|
-
console.warn("[castrum] WARN: `trustProxy: true` is deprecated and trusts EVERY hop — " + "clients can spoof X-Forwarded-For / X-Real-IP to bypass IP-based rate " + "limiting. Use `trustedProxies: { enabled: true, networks: [...] }`
|
|
7525
|
+
console.warn("[castrum] WARN: `trustProxy: true` is deprecated and trusts EVERY hop — " + "clients can spoof X-Forwarded-For / X-Real-IP to bypass IP-based rate " + "limiting. Use `trustedProxies: { enabled: true, networks: [...] }` " + "(which takes precedence) and only enable proxy trust behind a trusted edge.");
|
|
7526
|
+
}
|
|
7527
|
+
var rateLimitNoIpWarned = false;
|
|
7528
|
+
function warnRateLimitWithoutGetIp() {
|
|
7529
|
+
if (rateLimitNoIpWarned)
|
|
7530
|
+
return;
|
|
7531
|
+
rateLimitNoIpWarned = true;
|
|
7532
|
+
console.warn("[castrum] WARN: rate limiting is enabled without `getIp` — every client " + "shares ONE bucket, so one client can exhaust it for everyone. Provide " + "`getIp` for per-client limits (or use a global limit deliberately).");
|
|
7060
7533
|
}
|
|
7061
7534
|
|
|
7062
7535
|
// src/ingress/packing/header-packing.ts
|
|
@@ -7622,6 +8095,11 @@ class BufferPool {
|
|
|
7622
8095
|
this.estimate = options.adaptive === true ? new AdaptiveEstimate({ alpha: 0.25, min: this.initialSize }) : null;
|
|
7623
8096
|
this.free.push(new Uint8Array(this.initialSize));
|
|
7624
8097
|
this.created = 1;
|
|
8098
|
+
const prefill = Math.min(Math.max(0, Math.floor(options.prefill ?? 0)), this.maxBuffers - 1, options.prefillBytes !== undefined ? Math.max(0, Math.floor(options.prefillBytes / this.initialSize)) : Number.POSITIVE_INFINITY);
|
|
8099
|
+
for (let i = 0;i < prefill; i++) {
|
|
8100
|
+
this.free.push(new Uint8Array(this.initialSize));
|
|
8101
|
+
this.created++;
|
|
8102
|
+
}
|
|
7625
8103
|
}
|
|
7626
8104
|
get freeCount() {
|
|
7627
8105
|
return this.free.length;
|
|
@@ -7629,6 +8107,9 @@ class BufferPool {
|
|
|
7629
8107
|
get createdCount() {
|
|
7630
8108
|
return this.created;
|
|
7631
8109
|
}
|
|
8110
|
+
shrink() {
|
|
8111
|
+
this.free.length = 0;
|
|
8112
|
+
}
|
|
7632
8113
|
acquire(minSize = 0) {
|
|
7633
8114
|
if (this.maxInFlight > 0 && this.inFlight >= this.maxInFlight) {
|
|
7634
8115
|
throw new RangeError(`BufferPool: maxInFlight (${this.maxInFlight}) exceeded — too many ` + "buffers borrowed at once (unreleased zero-copy responses?). " + "Raise maxInFlight or consume/release responses faster.");
|
|
@@ -7655,7 +8136,9 @@ class BufferPool {
|
|
|
7655
8136
|
for (let i = 0;i < this.free.length; i++) {
|
|
7656
8137
|
const candidate = this.free[i];
|
|
7657
8138
|
if (candidate.byteLength >= minSize) {
|
|
7658
|
-
this.free.
|
|
8139
|
+
const last = this.free.pop();
|
|
8140
|
+
if (i < this.free.length)
|
|
8141
|
+
this.free[i] = last;
|
|
7659
8142
|
return candidate;
|
|
7660
8143
|
}
|
|
7661
8144
|
}
|
|
@@ -7670,7 +8153,9 @@ class BufferPool {
|
|
|
7670
8153
|
}
|
|
7671
8154
|
}
|
|
7672
8155
|
if (largestBuf !== null) {
|
|
7673
|
-
this.free.
|
|
8156
|
+
const last = this.free.pop();
|
|
8157
|
+
if (largest < this.free.length)
|
|
8158
|
+
this.free[largest] = last;
|
|
7674
8159
|
this.created++;
|
|
7675
8160
|
return new Uint8Array(target);
|
|
7676
8161
|
}
|
|
@@ -7679,16 +8164,15 @@ class BufferPool {
|
|
|
7679
8164
|
}
|
|
7680
8165
|
releaseBuffer(buffer) {
|
|
7681
8166
|
if (this.free.length >= this.maxBuffers) {
|
|
7682
|
-
let smallestBuf = null;
|
|
7683
8167
|
let smallest = 0;
|
|
7684
|
-
for (let i =
|
|
7685
|
-
|
|
7686
|
-
if (smallestBuf === null || candidate.byteLength < smallestBuf.byteLength) {
|
|
7687
|
-
smallestBuf = candidate;
|
|
8168
|
+
for (let i = 1;i < this.free.length; i++) {
|
|
8169
|
+
if (this.free[i].byteLength < this.free[smallest].byteLength) {
|
|
7688
8170
|
smallest = i;
|
|
7689
8171
|
}
|
|
7690
8172
|
}
|
|
7691
|
-
this.free.
|
|
8173
|
+
const last = this.free.pop();
|
|
8174
|
+
if (smallest < this.free.length)
|
|
8175
|
+
this.free[smallest] = last;
|
|
7692
8176
|
}
|
|
7693
8177
|
this.free.push(buffer);
|
|
7694
8178
|
}
|
|
@@ -7748,8 +8232,8 @@ function createStructuredLogger(stream = process.stderr, env = process.env) {
|
|
|
7748
8232
|
|
|
7749
8233
|
// src/ingress/decode/baked-result.ts
|
|
7750
8234
|
class BakedIngressResult extends IngressResultBase {
|
|
7751
|
-
refresh(buf, body, view) {
|
|
7752
|
-
if (
|
|
8235
|
+
refresh(buf, body, view, len = buf.byteLength) {
|
|
8236
|
+
if (len < OUT_DATA_START) {
|
|
7753
8237
|
this.setInternalError();
|
|
7754
8238
|
return;
|
|
7755
8239
|
}
|
|
@@ -7762,7 +8246,7 @@ class BakedIngressResult extends IngressResultBase {
|
|
|
7762
8246
|
const queryLenRaw = view.getUint32(OUT_QUERY_JSON_LEN, true);
|
|
7763
8247
|
const headerVariant = view.getUint8(OUT_HEADER_VARIANT);
|
|
7764
8248
|
const bodyJsonLenRaw = view.getUint32(OUT_BODY_JSON_LEN, true);
|
|
7765
|
-
const layout = sectionLayout(
|
|
8249
|
+
const layout = sectionLayout(len, cookiesLenRaw, queryLenRaw, bodyJsonLenRaw);
|
|
7766
8250
|
if (h0 === 0 && h1 === 0) {
|
|
7767
8251
|
this.verdict = 1;
|
|
7768
8252
|
this.errorCode = ERR_CODE_INTERNAL;
|
|
@@ -7777,7 +8261,7 @@ class BakedIngressResult extends IngressResultBase {
|
|
|
7777
8261
|
this.rateRemaining = h3;
|
|
7778
8262
|
this.setRateWindow(h2, (flags & FLAG_RATE_LIMITED) !== 0, view);
|
|
7779
8263
|
this.headerVariant = headerVariant;
|
|
7780
|
-
this.setSections(buf, layout, layout.safeBodyJsonLen);
|
|
8264
|
+
this.setSections(buf, layout, layout.safeBodyJsonLen, len);
|
|
7781
8265
|
this.updateOkTerminal();
|
|
7782
8266
|
this.isPreflight = (flags & FLAG_IS_PREFLIGHT) !== 0;
|
|
7783
8267
|
this.corsAllowed = (flags & FLAG_CORS_ALLOWED) !== 0;
|
|
@@ -7800,8 +8284,16 @@ class BakedIngressResult extends IngressResultBase {
|
|
|
7800
8284
|
this.ok = false;
|
|
7801
8285
|
}
|
|
7802
8286
|
bodyJson(copy) {
|
|
8287
|
+
if (copy) {
|
|
8288
|
+
if (this._bodyJsonLen === 0)
|
|
8289
|
+
return this._buf.slice(0, 0);
|
|
8290
|
+
const end = this._bodyJsonStart + this._bodyJsonLen;
|
|
8291
|
+
if (end > this._len)
|
|
8292
|
+
return this._buf.slice(0, 0);
|
|
8293
|
+
return this._buf.slice(this._bodyJsonStart, end);
|
|
8294
|
+
}
|
|
7803
8295
|
const slice = this.bodyJsonSlice();
|
|
7804
|
-
return
|
|
8296
|
+
return slice;
|
|
7805
8297
|
}
|
|
7806
8298
|
}
|
|
7807
8299
|
|
|
@@ -7925,6 +8417,13 @@ function cachedOriginBlock(origin) {
|
|
|
7925
8417
|
ORIGIN_BLOCK_CACHE.set(origin, block);
|
|
7926
8418
|
return block;
|
|
7927
8419
|
}
|
|
8420
|
+
function prewarmOriginBlocks(origins) {
|
|
8421
|
+
for (const origin of origins) {
|
|
8422
|
+
if (typeof origin === "string" && origin.length > 0 && origin.length <= MAX_SMALL_HEADER_BYTES && !origin.includes("*")) {
|
|
8423
|
+
cachedOriginBlock(origin);
|
|
8424
|
+
}
|
|
8425
|
+
}
|
|
8426
|
+
}
|
|
7928
8427
|
|
|
7929
8428
|
// src/ingress/response/baked-response.ts
|
|
7930
8429
|
init_bytes();
|
|
@@ -7977,6 +8476,12 @@ function pooledBodyResponse(handle, bytes, init = {}, timeoutMs = 0) {
|
|
|
7977
8476
|
|
|
7978
8477
|
// src/ingress/response/baked-response.ts
|
|
7979
8478
|
var EMPTY_BODY4 = new Uint8Array(0);
|
|
8479
|
+
var ORIGIN_HEADER_CACHE_MAX = 64;
|
|
8480
|
+
function prewarmOriginHeaders(responseHeaders, origins, variant) {
|
|
8481
|
+
for (const origin of origins) {
|
|
8482
|
+
memoizedHeaders(responseHeaders(variant, null, origin));
|
|
8483
|
+
}
|
|
8484
|
+
}
|
|
7980
8485
|
function buildBakedResponseBuilders(deps) {
|
|
7981
8486
|
const {
|
|
7982
8487
|
headerTemplates,
|
|
@@ -7986,6 +8491,45 @@ function buildBakedResponseBuilders(deps) {
|
|
|
7986
8491
|
originHeaderCache,
|
|
7987
8492
|
state
|
|
7988
8493
|
} = deps;
|
|
8494
|
+
function originBaseEntries(variant, origin) {
|
|
8495
|
+
const key = `${variant & 31}\x00${origin}`;
|
|
8496
|
+
const cached = originHeaderCache.get(key);
|
|
8497
|
+
if (cached !== undefined) {
|
|
8498
|
+
return cached;
|
|
8499
|
+
}
|
|
8500
|
+
const template = headerTemplates[variant & 31] ?? headerTemplates[0] ?? [];
|
|
8501
|
+
const entries = new Array(template.length + 1);
|
|
8502
|
+
let i = 0;
|
|
8503
|
+
for (const pair of template) {
|
|
8504
|
+
entries[i++] = pair;
|
|
8505
|
+
}
|
|
8506
|
+
entries[i] = ["access-control-allow-origin", origin];
|
|
8507
|
+
if (originHeaderCache.size >= ORIGIN_HEADER_CACHE_MAX) {
|
|
8508
|
+
const oldest = originHeaderCache.keys().next().value;
|
|
8509
|
+
if (oldest !== undefined)
|
|
8510
|
+
originHeaderCache.delete(oldest);
|
|
8511
|
+
}
|
|
8512
|
+
originHeaderCache.set(key, entries);
|
|
8513
|
+
return entries;
|
|
8514
|
+
}
|
|
8515
|
+
function successHeaders(variant, requestIdHeader, origin, rateRemaining, rateResetSecs) {
|
|
8516
|
+
const needsRequestId = emitRequestIdHeader && requestIdHeader !== null;
|
|
8517
|
+
const needsOrigin = ((variant & HV_CORS_SIMPLE) !== 0 || (variant & HV_CORS_PREFLIGHT) !== 0) && origin !== null;
|
|
8518
|
+
const needsRate = (variant & HV_RATE_ACTIVE) !== 0;
|
|
8519
|
+
const base = needsOrigin ? memoizedHeaders(originBaseEntries(variant, origin)) : memoizedHeaders(headerTemplates[variant & 31] ?? headerTemplates[0] ?? []);
|
|
8520
|
+
if (!needsRequestId && !needsRate) {
|
|
8521
|
+
return base;
|
|
8522
|
+
}
|
|
8523
|
+
const headers = new Headers(base);
|
|
8524
|
+
if (needsRequestId) {
|
|
8525
|
+
headers.set("x-request-id", requestIdHeader);
|
|
8526
|
+
}
|
|
8527
|
+
if (needsRate) {
|
|
8528
|
+
headers.set("ratelimit-remaining", String(rateRemaining ?? 0));
|
|
8529
|
+
headers.set("ratelimit-reset", String(rateResetSecs ?? 0));
|
|
8530
|
+
}
|
|
8531
|
+
return headers;
|
|
8532
|
+
}
|
|
7989
8533
|
function responseHeaders(variant, requestIdHeader, origin, rateRemaining, rateResetSecs, retryAfterSecs) {
|
|
7990
8534
|
const template = headerTemplates[variant & 31] ?? headerTemplates[0] ?? [];
|
|
7991
8535
|
const needsRequestId = emitRequestIdHeader && requestIdHeader !== null;
|
|
@@ -7996,19 +8540,7 @@ function buildBakedResponseBuilders(deps) {
|
|
|
7996
8540
|
return template;
|
|
7997
8541
|
}
|
|
7998
8542
|
if (!needsRequestId && !needsRate && !needsRetry && needsOrigin) {
|
|
7999
|
-
|
|
8000
|
-
const cached = originHeaderCache.get(key);
|
|
8001
|
-
if (cached !== undefined) {
|
|
8002
|
-
return cached;
|
|
8003
|
-
}
|
|
8004
|
-
const entries = new Array(template.length + 1);
|
|
8005
|
-
let i = 0;
|
|
8006
|
-
for (const pair of template) {
|
|
8007
|
-
entries[i++] = pair;
|
|
8008
|
-
}
|
|
8009
|
-
entries[i] = ["access-control-allow-origin", origin];
|
|
8010
|
-
originHeaderCache.set(key, entries);
|
|
8011
|
-
return entries;
|
|
8543
|
+
return originBaseEntries(variant, origin);
|
|
8012
8544
|
}
|
|
8013
8545
|
let extra = 0;
|
|
8014
8546
|
if (needsRequestId)
|
|
@@ -8069,27 +8601,27 @@ function buildBakedResponseBuilders(deps) {
|
|
|
8069
8601
|
if (preflightAllowed) {
|
|
8070
8602
|
return new Response(null, {
|
|
8071
8603
|
status: 204,
|
|
8072
|
-
headers: responseHeaders(result.headerVariant, ctx.requestIdHeader, ctx.origin, result.rateRemaining, result.rateResetMs > 0 ? secondsFromMs(result.rateResetMs) : undefined, result.retryAfterMs > 0 ? secondsFromMs(result.retryAfterMs) : undefined)
|
|
8604
|
+
headers: memoizedHeaders(responseHeaders(result.headerVariant, ctx.requestIdHeader, ctx.origin, result.rateRemaining, result.rateResetMs > 0 ? secondsFromMs(result.rateResetMs) : undefined, result.retryAfterMs > 0 ? secondsFromMs(result.retryAfterMs) : undefined))
|
|
8073
8605
|
});
|
|
8074
8606
|
}
|
|
8075
8607
|
const status = safeTerminalStatus(result);
|
|
8076
8608
|
const body = result.errorCode === ERR_CODE_RATE_LIMITED ? rateLimitedBody(result.retryAfterMs) : ERROR_CODE_BODIES[result.errorCode] ?? ERROR_BODIES.internal ?? EMPTY_BODY4;
|
|
8077
8609
|
return new Response(body, {
|
|
8078
8610
|
status,
|
|
8079
|
-
headers: terminalHeaders(result.headerVariant, ctx, result)
|
|
8611
|
+
headers: memoizedHeaders(terminalHeaders(result.headerVariant, ctx, result))
|
|
8080
8612
|
});
|
|
8081
8613
|
}
|
|
8082
8614
|
function errorResponse(_req, result, status, code, message, ctx) {
|
|
8083
8615
|
const body = ERROR_BODIES[code] ?? encoder.encode(JSON.stringify({ ok: false, error: { code, message } }));
|
|
8084
8616
|
return new Response(body, {
|
|
8085
8617
|
status,
|
|
8086
|
-
headers: terminalHeaders(result?.headerVariant ?? HV_JSON, ctx, result)
|
|
8618
|
+
headers: memoizedHeaders(terminalHeaders(result?.headerVariant ?? HV_JSON, ctx, result))
|
|
8087
8619
|
});
|
|
8088
8620
|
}
|
|
8089
8621
|
function internalErrorResponse(ctx, result) {
|
|
8090
8622
|
return new Response(ERROR_BODIES.internal, {
|
|
8091
8623
|
status: 500,
|
|
8092
|
-
headers: terminalHeaders(result?.headerVariant ?? HV_JSON, ctx, result ?? null)
|
|
8624
|
+
headers: memoizedHeaders(terminalHeaders(result?.headerVariant ?? HV_JSON, ctx, result ?? null))
|
|
8093
8625
|
});
|
|
8094
8626
|
}
|
|
8095
8627
|
function withContentType(headers, contentType) {
|
|
@@ -8110,6 +8642,7 @@ function buildBakedResponseBuilders(deps) {
|
|
|
8110
8642
|
}
|
|
8111
8643
|
return {
|
|
8112
8644
|
responseHeaders,
|
|
8645
|
+
successHeaders,
|
|
8113
8646
|
terminalHeaders,
|
|
8114
8647
|
terminalResponse,
|
|
8115
8648
|
errorResponse,
|
|
@@ -8124,6 +8657,8 @@ var EMPTY_BODY5 = new Uint8Array(0);
|
|
|
8124
8657
|
var EMPTY_IP = "0.0.0.0";
|
|
8125
8658
|
var RATE_LIMIT_U32_MAX = 4294967295;
|
|
8126
8659
|
var MAX_FFI_FAILURES = 3;
|
|
8660
|
+
var PREWARM_POOL_BUFFERS = 16;
|
|
8661
|
+
var PREWARM_POOL_BYTES = 4 * 1024 * 1024;
|
|
8127
8662
|
function pathForLog(req) {
|
|
8128
8663
|
try {
|
|
8129
8664
|
return new URL(req.url).pathname;
|
|
@@ -8160,14 +8695,24 @@ function createIngressHandler(options = {}, runtime = {}) {
|
|
|
8160
8695
|
const outputBufferSize = clampIngressBufferSize(runtime.outputBufferSize ?? DEFAULT_BAKED_OUTPUT_BUFFER_SIZE, OUT_DATA_START);
|
|
8161
8696
|
const logger = runtime.logger ?? (runtime.structuredLog === true ? createStructuredLogger() : null);
|
|
8162
8697
|
const needRequestIdString = !!(emitRequestIdHeader || runtime.onRequest || runtime.onError || runtime.onResponse || logger);
|
|
8698
|
+
const hasOnRequest = runtime.onRequest !== undefined;
|
|
8699
|
+
const hasOnResponse = runtime.onResponse !== undefined;
|
|
8163
8700
|
const outputPool = new BufferPool({
|
|
8164
8701
|
initialSize: outputBufferSize,
|
|
8165
|
-
maxInFlight: runtime.maxInFlight
|
|
8702
|
+
maxInFlight: runtime.maxInFlight,
|
|
8703
|
+
prefill: PREWARM_POOL_BUFFERS,
|
|
8704
|
+
prefillBytes: PREWARM_POOL_BYTES
|
|
8166
8705
|
});
|
|
8167
8706
|
const inputPacker = new IngressInputPacker;
|
|
8168
8707
|
const responseState = { currentHandle: null, responseBorrowsBuffer: false };
|
|
8169
8708
|
let ffiFailures = 0;
|
|
8170
8709
|
let ffiDisabled = false;
|
|
8710
|
+
const noteFfiFailure = () => {
|
|
8711
|
+
ffiFailures++;
|
|
8712
|
+
if (ffiFailures >= MAX_FFI_FAILURES) {
|
|
8713
|
+
ffiDisabled = true;
|
|
8714
|
+
}
|
|
8715
|
+
};
|
|
8171
8716
|
const originHeaderCache = new Map;
|
|
8172
8717
|
const cors = options.cors;
|
|
8173
8718
|
const securityEntries = runtime.enableSecurityHeaders === false ? Object.freeze([]) : Object.freeze(buildBakedSecurityEntries(options.security, options.https, runtime.securityHeaders));
|
|
@@ -8193,6 +8738,17 @@ function createIngressHandler(options = {}, runtime = {}) {
|
|
|
8193
8738
|
originHeaderCache,
|
|
8194
8739
|
state: responseState
|
|
8195
8740
|
});
|
|
8741
|
+
if (headerPlan.cors && typeof cors?.allowOrigin === "object") {
|
|
8742
|
+
const exactOrigins = [];
|
|
8743
|
+
for (const origin of cors.allowOrigin) {
|
|
8744
|
+
if (typeof origin === "string" && origin.length > 0 && origin.length <= 512 && !origin.includes("*")) {
|
|
8745
|
+
exactOrigins.push(origin);
|
|
8746
|
+
}
|
|
8747
|
+
}
|
|
8748
|
+
prewarmOriginBlocks(exactOrigins);
|
|
8749
|
+
const successVariant = HV_JSON | HV_CORS_SIMPLE | (rateEnabled ? HV_RATE_ACTIVE : 0);
|
|
8750
|
+
prewarmOriginHeaders(responseBuilders.responseHeaders, exactOrigins, successVariant);
|
|
8751
|
+
}
|
|
8196
8752
|
const result = new BakedIngressResult;
|
|
8197
8753
|
const ctx = {
|
|
8198
8754
|
requestIdHeader: null,
|
|
@@ -8205,7 +8761,8 @@ function createIngressHandler(options = {}, runtime = {}) {
|
|
|
8205
8761
|
const requestIdStr = needRequestIdString ? decoder.decode(ridBytes) : "";
|
|
8206
8762
|
ctx.requestIdHeader = emitRequestIdHeader ? requestIdStr : null;
|
|
8207
8763
|
ctx.origin = headerPlan.cors ? req.headers.get("origin") : null;
|
|
8208
|
-
|
|
8764
|
+
if (hasOnRequest)
|
|
8765
|
+
runtime.onRequest?.(req, requestIdStr, ip);
|
|
8209
8766
|
const ipStr = ip ?? EMPTY_IP;
|
|
8210
8767
|
let handle = null;
|
|
8211
8768
|
responseState.currentHandle = null;
|
|
@@ -8223,10 +8780,7 @@ function createIngressHandler(options = {}, runtime = {}) {
|
|
|
8223
8780
|
written = bunFFI.ingressHandleComponents(ingressPtr, methodKind, packUrl, packIp ?? "", ridBytes, packedHeaders, body, handle.buffer);
|
|
8224
8781
|
ffiFailures = 0;
|
|
8225
8782
|
} catch {
|
|
8226
|
-
|
|
8227
|
-
if (ffiFailures >= MAX_FFI_FAILURES) {
|
|
8228
|
-
ffiDisabled = true;
|
|
8229
|
-
}
|
|
8783
|
+
noteFfiFailure();
|
|
8230
8784
|
const input = inputPacker.packParts(methodKind, packUrl, packIp, ridBytes, packedHeaders);
|
|
8231
8785
|
written = handler.handleRequestPacked(input, body, handle.buffer);
|
|
8232
8786
|
}
|
|
@@ -8236,18 +8790,14 @@ function createIngressHandler(options = {}, runtime = {}) {
|
|
|
8236
8790
|
written = bunFFI.ingressHandlePacked(ingressPtr, input, body, handle.buffer);
|
|
8237
8791
|
ffiFailures = 0;
|
|
8238
8792
|
} catch {
|
|
8239
|
-
|
|
8240
|
-
if (ffiFailures >= MAX_FFI_FAILURES) {
|
|
8241
|
-
ffiDisabled = true;
|
|
8242
|
-
}
|
|
8793
|
+
noteFfiFailure();
|
|
8243
8794
|
written = handler.handleRequestPacked(input, body, handle.buffer);
|
|
8244
8795
|
}
|
|
8245
8796
|
} else {
|
|
8246
8797
|
const input = inputPacker.packParts(methodKind, packUrl, packIp, ridBytes, packedHeaders);
|
|
8247
8798
|
written = handler.handleRequestPacked(input, body, handle.buffer);
|
|
8248
8799
|
}
|
|
8249
|
-
|
|
8250
|
-
result.refresh(used, body ?? EMPTY_BODY5, viewForArrayBuffer(used.buffer, used.byteOffset));
|
|
8800
|
+
result.refresh(handle.buffer, body ?? EMPTY_BODY5, viewForArrayBuffer(handle.buffer.buffer, handle.buffer.byteOffset), written);
|
|
8251
8801
|
} catch (err) {
|
|
8252
8802
|
result.setInternalError();
|
|
8253
8803
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
@@ -8263,17 +8813,20 @@ function createIngressHandler(options = {}, runtime = {}) {
|
|
|
8263
8813
|
try {
|
|
8264
8814
|
const out = fn(result, ctx);
|
|
8265
8815
|
assertSyncCallback(out, "createIngressHandler().run()");
|
|
8266
|
-
|
|
8267
|
-
|
|
8268
|
-
|
|
8269
|
-
|
|
8270
|
-
|
|
8271
|
-
|
|
8272
|
-
|
|
8273
|
-
|
|
8274
|
-
|
|
8275
|
-
|
|
8276
|
-
|
|
8816
|
+
if (hasOnResponse || logger !== null) {
|
|
8817
|
+
const status = out instanceof Response ? out.status : safeTerminalStatus(result);
|
|
8818
|
+
if (hasOnResponse)
|
|
8819
|
+
runtime.onResponse?.(req, result, status, requestIdStr);
|
|
8820
|
+
if (logger !== null) {
|
|
8821
|
+
logger.request({
|
|
8822
|
+
requestId: requestIdStr,
|
|
8823
|
+
method: req.method,
|
|
8824
|
+
path: pathForLog(req),
|
|
8825
|
+
status,
|
|
8826
|
+
durationMs: Math.round((performance.now() - startedAt) * 1000) / 1000,
|
|
8827
|
+
ip: ipStr
|
|
8828
|
+
});
|
|
8829
|
+
}
|
|
8277
8830
|
}
|
|
8278
8831
|
return out;
|
|
8279
8832
|
} finally {
|
|
@@ -8321,6 +8874,9 @@ function jsonResponse(status, body) {
|
|
|
8321
8874
|
function livenessHandler() {
|
|
8322
8875
|
return (_req) => jsonResponse(200, { status: "ok" });
|
|
8323
8876
|
}
|
|
8877
|
+
function staticLiveness() {
|
|
8878
|
+
return jsonResponse(200, { status: "ok" });
|
|
8879
|
+
}
|
|
8324
8880
|
function readinessHandler(check) {
|
|
8325
8881
|
return async (_req) => {
|
|
8326
8882
|
if (!check)
|
|
@@ -8354,6 +8910,8 @@ var DEFAULT_BUCKETS = [
|
|
|
8354
8910
|
5,
|
|
8355
8911
|
10
|
|
8356
8912
|
];
|
|
8913
|
+
var MAX_SERIES_PER_METRIC = 1e4;
|
|
8914
|
+
var SERIES_DROPPED_METRIC = "castrum_metrics_series_dropped_total";
|
|
8357
8915
|
function labelKey(names, values) {
|
|
8358
8916
|
if (names.length === 0)
|
|
8359
8917
|
return "";
|
|
@@ -8366,10 +8924,25 @@ function labelKey(names, values) {
|
|
|
8366
8924
|
function escapeLabel(v) {
|
|
8367
8925
|
return v.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n");
|
|
8368
8926
|
}
|
|
8927
|
+
function evictOldestHalf2(map) {
|
|
8928
|
+
if (map.size < MAX_SERIES_PER_METRIC)
|
|
8929
|
+
return [];
|
|
8930
|
+
const drop = Math.ceil(map.size / 2);
|
|
8931
|
+
const dropped = [];
|
|
8932
|
+
for (const key of map.keys()) {
|
|
8933
|
+
if (dropped.length >= drop)
|
|
8934
|
+
break;
|
|
8935
|
+
dropped.push(key);
|
|
8936
|
+
}
|
|
8937
|
+
for (const key of dropped)
|
|
8938
|
+
map.delete(key);
|
|
8939
|
+
return dropped;
|
|
8940
|
+
}
|
|
8369
8941
|
function createMetrics() {
|
|
8370
8942
|
const counters = new Map;
|
|
8371
8943
|
const gauges = new Map;
|
|
8372
8944
|
const histograms = new Map;
|
|
8945
|
+
let seriesDropped = 0;
|
|
8373
8946
|
const bucketUpper = (buckets) => [
|
|
8374
8947
|
...buckets.map((b) => b),
|
|
8375
8948
|
Number.POSITIVE_INFINITY
|
|
@@ -8414,6 +8987,11 @@ function createMetrics() {
|
|
|
8414
8987
|
out.push(...renderGauge(e));
|
|
8415
8988
|
for (const e of histograms.values())
|
|
8416
8989
|
out.push(...renderHistogram(e));
|
|
8990
|
+
if (seriesDropped > 0 && !counters.has(SERIES_DROPPED_METRIC) && !gauges.has(SERIES_DROPPED_METRIC) && !histograms.has(SERIES_DROPPED_METRIC)) {
|
|
8991
|
+
out.push(`# HELP ${SERIES_DROPPED_METRIC} Total metric series evicted by the per-family cardinality cap.`);
|
|
8992
|
+
out.push(`# TYPE ${SERIES_DROPPED_METRIC} counter`);
|
|
8993
|
+
out.push(`${SERIES_DROPPED_METRIC} ${seriesDropped}`);
|
|
8994
|
+
}
|
|
8417
8995
|
return `${out.join(`
|
|
8418
8996
|
`)}
|
|
8419
8997
|
`;
|
|
@@ -8422,6 +9000,7 @@ function createMetrics() {
|
|
|
8422
9000
|
counters.clear();
|
|
8423
9001
|
gauges.clear();
|
|
8424
9002
|
histograms.clear();
|
|
9003
|
+
seriesDropped = 0;
|
|
8425
9004
|
};
|
|
8426
9005
|
return {
|
|
8427
9006
|
counter(name, help, labelNames = []) {
|
|
@@ -8438,7 +9017,13 @@ function createMetrics() {
|
|
|
8438
9017
|
return {
|
|
8439
9018
|
inc(labels, by = 1) {
|
|
8440
9019
|
const key = labelKey(names, names.map((n) => labels?.[n] ?? ""));
|
|
8441
|
-
|
|
9020
|
+
const prev = entry.values.get(key);
|
|
9021
|
+
if (prev === undefined) {
|
|
9022
|
+
seriesDropped += evictOldestHalf2(entry.values).length;
|
|
9023
|
+
entry.values.set(key, by);
|
|
9024
|
+
} else {
|
|
9025
|
+
entry.values.set(key, prev + by);
|
|
9026
|
+
}
|
|
8442
9027
|
}
|
|
8443
9028
|
};
|
|
8444
9029
|
},
|
|
@@ -8454,14 +9039,27 @@ function createMetrics() {
|
|
|
8454
9039
|
gauges.set(name, entry);
|
|
8455
9040
|
const names = entry.labelNames;
|
|
8456
9041
|
const keyOf = (labels) => labelKey(names, names.map((n) => labels?.[n] ?? ""));
|
|
9042
|
+
const add = (labels, delta) => {
|
|
9043
|
+
const key = keyOf(labels);
|
|
9044
|
+
const prev = entry.values.get(key);
|
|
9045
|
+
if (prev === undefined) {
|
|
9046
|
+
seriesDropped += evictOldestHalf2(entry.values).length;
|
|
9047
|
+
entry.values.set(key, delta);
|
|
9048
|
+
} else {
|
|
9049
|
+
entry.values.set(key, prev + delta);
|
|
9050
|
+
}
|
|
9051
|
+
};
|
|
8457
9052
|
return {
|
|
8458
9053
|
inc(labels, by = 1) {
|
|
8459
|
-
|
|
9054
|
+
add(labels, by);
|
|
8460
9055
|
},
|
|
8461
9056
|
dec(labels, by = 1) {
|
|
8462
|
-
|
|
9057
|
+
add(labels, -by);
|
|
8463
9058
|
},
|
|
8464
9059
|
set(labels, value) {
|
|
9060
|
+
if (!entry.values.has(keyOf(labels))) {
|
|
9061
|
+
seriesDropped += evictOldestHalf2(entry.values).length;
|
|
9062
|
+
}
|
|
8465
9063
|
entry.values.set(keyOf(labels), value);
|
|
8466
9064
|
}
|
|
8467
9065
|
};
|
|
@@ -8484,6 +9082,10 @@ function createMetrics() {
|
|
|
8484
9082
|
const key = labelKey(names, names.map((n) => labels?.[n] ?? ""));
|
|
8485
9083
|
let counts = entry.counts.get(key);
|
|
8486
9084
|
if (!counts) {
|
|
9085
|
+
const dropped = evictOldestHalf2(entry.counts);
|
|
9086
|
+
for (const k of dropped)
|
|
9087
|
+
entry.sums.delete(k);
|
|
9088
|
+
seriesDropped += dropped.length;
|
|
8487
9089
|
counts = new Array(entry.buckets.length + 1).fill(0);
|
|
8488
9090
|
entry.counts.set(key, counts);
|
|
8489
9091
|
}
|
|
@@ -8568,6 +9170,14 @@ function createIngressRouter(options) {
|
|
|
8568
9170
|
if (options.copyBody !== undefined)
|
|
8569
9171
|
baseOpts.copyBody = options.copyBody;
|
|
8570
9172
|
for (const [path, spec] of Object.entries(options.routes)) {
|
|
9173
|
+
if (spec.static !== undefined) {
|
|
9174
|
+
bakedRoutes[path] = {
|
|
9175
|
+
static: spec.static,
|
|
9176
|
+
maxBodyBytes: spec.maxBodyBytes,
|
|
9177
|
+
bodyTimeoutMs: spec.bodyTimeoutMs
|
|
9178
|
+
};
|
|
9179
|
+
continue;
|
|
9180
|
+
}
|
|
8571
9181
|
if (spec.raw) {
|
|
8572
9182
|
bakedRoutes[path] = { read: spec.raw };
|
|
8573
9183
|
continue;
|
|
@@ -8587,6 +9197,10 @@ function createIngressRouter(options) {
|
|
|
8587
9197
|
}
|
|
8588
9198
|
const handler = createIngressHandler(spec.options ?? {}, runtime);
|
|
8589
9199
|
compiled[path] = handler;
|
|
9200
|
+
const routeLimit = spec.options?.rateLimit?.limit;
|
|
9201
|
+
if (typeof routeLimit === "number" && routeLimit > 0 && routeLimit !== RATE_LIMIT_U32_MAX && options.getIp === undefined) {
|
|
9202
|
+
warnRateLimitWithoutGetIp();
|
|
9203
|
+
}
|
|
8590
9204
|
if (spec.responder) {
|
|
8591
9205
|
bakedRoutes[path] = {
|
|
8592
9206
|
responder: {
|
|
@@ -8638,6 +9252,9 @@ function createIngressRouter(options) {
|
|
|
8638
9252
|
if (typeof methodHandler === "function") {
|
|
8639
9253
|
return methodHandler(req, srv, matched.params);
|
|
8640
9254
|
}
|
|
9255
|
+
if (methodHandler instanceof Response) {
|
|
9256
|
+
return methodHandler.clone();
|
|
9257
|
+
}
|
|
8641
9258
|
if (req.method === "OPTIONS" && typeof matched.methods.OPTIONS === "function") {
|
|
8642
9259
|
return matched.methods.OPTIONS(req, srv, matched.params);
|
|
8643
9260
|
}
|
|
@@ -8811,6 +9428,22 @@ function createIngress(options = {}) {
|
|
|
8811
9428
|
}
|
|
8812
9429
|
};
|
|
8813
9430
|
}
|
|
9431
|
+
// src/native/ingress-binding.ts
|
|
9432
|
+
init_ffi();
|
|
9433
|
+
var cached2;
|
|
9434
|
+
function getIngressBinding() {
|
|
9435
|
+
if (cached2 !== undefined)
|
|
9436
|
+
return cached2;
|
|
9437
|
+
const ffi = getBunFFI();
|
|
9438
|
+
const addonPath = ffiAddonPath();
|
|
9439
|
+
cached2 = ffi && addonPath ? {
|
|
9440
|
+
addonPath,
|
|
9441
|
+
ingressHandleComponents: ffi.ingressHandleComponents,
|
|
9442
|
+
ingressHandlePacked: ffi.ingressHandlePacked,
|
|
9443
|
+
ingressLayout: ffi.ingressLayout
|
|
9444
|
+
} : null;
|
|
9445
|
+
return cached2;
|
|
9446
|
+
}
|
|
8814
9447
|
// src/loader/index.ts
|
|
8815
9448
|
init_rust_ffi();
|
|
8816
9449
|
init_bytes();
|
|
@@ -9921,6 +10554,9 @@ function createPipeline(opts = {}) {
|
|
|
9921
10554
|
try {
|
|
9922
10555
|
body = await readBodyWithLimit(req, maxBodyBytes, true, bodyTimeoutMs);
|
|
9923
10556
|
} catch (err) {
|
|
10557
|
+
if (isAbortError(err)) {
|
|
10558
|
+
return { terminal: true, response: abortResponse(), result: null, ctx };
|
|
10559
|
+
}
|
|
9924
10560
|
return {
|
|
9925
10561
|
terminal: true,
|
|
9926
10562
|
response: bodyErrorResponse(ingress, req, requestId, err),
|
|
@@ -10088,6 +10724,19 @@ function cancelledError() {
|
|
|
10088
10724
|
err.name = "TaskCancelledError";
|
|
10089
10725
|
return err;
|
|
10090
10726
|
}
|
|
10727
|
+
var TASK_SUBMIT_ACCEPTED = 1;
|
|
10728
|
+
var TASK_SUBMIT_OVERLOADED = 2;
|
|
10729
|
+
function taskSubmitError(code) {
|
|
10730
|
+
if (code === TASK_SUBMIT_ACCEPTED)
|
|
10731
|
+
return null;
|
|
10732
|
+
if (code === TASK_SUBMIT_OVERLOADED) {
|
|
10733
|
+
const err = new Error("task rejected: native work queue is full");
|
|
10734
|
+
err.name = "TaskOverloadedError";
|
|
10735
|
+
err.code = "OVERLOADED";
|
|
10736
|
+
return err;
|
|
10737
|
+
}
|
|
10738
|
+
return new Error("task rejected by the native runtime");
|
|
10739
|
+
}
|
|
10091
10740
|
var shared = null;
|
|
10092
10741
|
function createTaskRuntime(options = {}) {
|
|
10093
10742
|
if (shared)
|
|
@@ -10228,14 +10877,17 @@ function createTaskRuntime(options = {}) {
|
|
|
10228
10877
|
queueMicrotask(drainNow);
|
|
10229
10878
|
}
|
|
10230
10879
|
function submit(op, args, runOptions) {
|
|
10880
|
+
ensureDoorbell();
|
|
10231
10881
|
const id = nextId++;
|
|
10232
10882
|
return new Promise((resolve, reject) => {
|
|
10233
10883
|
inflight.set(id, { out: null, keep: null, resolve, reject });
|
|
10234
10884
|
retain();
|
|
10235
|
-
|
|
10885
|
+
const rejected = taskSubmitError(ffi.taskSubmit(op, args, id));
|
|
10886
|
+
if (rejected) {
|
|
10236
10887
|
inflight.delete(id);
|
|
10237
|
-
|
|
10238
|
-
|
|
10888
|
+
if (inflight.size === 0)
|
|
10889
|
+
release();
|
|
10890
|
+
reject(rejected);
|
|
10239
10891
|
return;
|
|
10240
10892
|
}
|
|
10241
10893
|
const signal = runOptions?.signal;
|
|
@@ -10249,14 +10901,17 @@ function createTaskRuntime(options = {}) {
|
|
|
10249
10901
|
});
|
|
10250
10902
|
}
|
|
10251
10903
|
function submitInto(op, args, output, runOptions) {
|
|
10904
|
+
ensureDoorbell();
|
|
10252
10905
|
const id = nextId++;
|
|
10253
10906
|
return new Promise((resolve, reject) => {
|
|
10254
10907
|
inflight.set(id, { out: output, keep: null, resolve, reject });
|
|
10255
10908
|
retain();
|
|
10256
|
-
|
|
10909
|
+
const rejected = taskSubmitError(ffi.taskSubmitOut(op, args, id, output));
|
|
10910
|
+
if (rejected) {
|
|
10257
10911
|
inflight.delete(id);
|
|
10258
|
-
|
|
10259
|
-
|
|
10912
|
+
if (inflight.size === 0)
|
|
10913
|
+
release();
|
|
10914
|
+
reject(rejected);
|
|
10260
10915
|
return;
|
|
10261
10916
|
}
|
|
10262
10917
|
const signal = runOptions?.signal;
|
|
@@ -10270,14 +10925,17 @@ function createTaskRuntime(options = {}) {
|
|
|
10270
10925
|
});
|
|
10271
10926
|
}
|
|
10272
10927
|
function submitSlice(op, hdr, data, runOptions) {
|
|
10928
|
+
ensureDoorbell();
|
|
10273
10929
|
const id = nextId++;
|
|
10274
10930
|
return new Promise((resolve, reject) => {
|
|
10275
10931
|
inflight.set(id, { out: null, keep: data, resolve, reject });
|
|
10276
10932
|
retain();
|
|
10277
|
-
|
|
10933
|
+
const rejected = taskSubmitError(ffi.taskSubmitSlice(op, hdr, data, id));
|
|
10934
|
+
if (rejected) {
|
|
10278
10935
|
inflight.delete(id);
|
|
10279
|
-
|
|
10280
|
-
|
|
10936
|
+
if (inflight.size === 0)
|
|
10937
|
+
release();
|
|
10938
|
+
reject(rejected);
|
|
10281
10939
|
return;
|
|
10282
10940
|
}
|
|
10283
10941
|
const signal = runOptions?.signal;
|
|
@@ -10291,11 +10949,16 @@ function createTaskRuntime(options = {}) {
|
|
|
10291
10949
|
});
|
|
10292
10950
|
}
|
|
10293
10951
|
const { JSCallback } = __require("bun:ffi");
|
|
10294
|
-
|
|
10295
|
-
|
|
10296
|
-
|
|
10297
|
-
|
|
10298
|
-
|
|
10952
|
+
function ensureDoorbell() {
|
|
10953
|
+
if (doorbell !== null)
|
|
10954
|
+
return;
|
|
10955
|
+
const cb = new JSCallback(() => {
|
|
10956
|
+
drainNow();
|
|
10957
|
+
}, { args: [], returns: "void", threadsafe: true });
|
|
10958
|
+
doorbell = cb;
|
|
10959
|
+
ffi.taskSetDoorbell(Number(cb.ptr));
|
|
10960
|
+
}
|
|
10961
|
+
ensureDoorbell();
|
|
10299
10962
|
schedule();
|
|
10300
10963
|
const runtime = {
|
|
10301
10964
|
gzipDecompress(data, runOptions) {
|
|
@@ -10339,6 +11002,7 @@ function createTaskRuntime(options = {}) {
|
|
|
10339
11002
|
deferred.reject(cancelledError());
|
|
10340
11003
|
}
|
|
10341
11004
|
inflight.clear();
|
|
11005
|
+
ffi.taskSetDoorbell(0);
|
|
10342
11006
|
ffi.taskShutdown();
|
|
10343
11007
|
release();
|
|
10344
11008
|
doorbell?.close();
|
|
@@ -10373,12 +11037,30 @@ var opDecision = (op) => {
|
|
|
10373
11037
|
|
|
10374
11038
|
// index.ts
|
|
10375
11039
|
init_bytes();
|
|
11040
|
+
|
|
11041
|
+
// src/shared/memory.ts
|
|
11042
|
+
init_rust_ffi();
|
|
11043
|
+
init_context();
|
|
11044
|
+
init_runtime();
|
|
11045
|
+
function flushMemory(options = {}) {
|
|
11046
|
+
loader.clear();
|
|
11047
|
+
clearMimeCaches();
|
|
11048
|
+
try {
|
|
11049
|
+
rust.clearSchemaCache();
|
|
11050
|
+
} catch {}
|
|
11051
|
+
if (options.gc !== false) {
|
|
11052
|
+
forceGc2();
|
|
11053
|
+
}
|
|
11054
|
+
}
|
|
11055
|
+
|
|
11056
|
+
// index.ts
|
|
10376
11057
|
init_packed();
|
|
10377
11058
|
|
|
10378
11059
|
// src/shared/uuid.ts
|
|
10379
11060
|
init_uuid();
|
|
10380
11061
|
var uuidv7 = runtimeUuid.uuidv7;
|
|
10381
11062
|
export {
|
|
11063
|
+
ABORT_CODE,
|
|
10382
11064
|
AdaptiveEstimate,
|
|
10383
11065
|
BakedIngressResult,
|
|
10384
11066
|
DEFAULT_BODY_TIMEOUT_MS,
|
|
@@ -10440,6 +11122,7 @@ export {
|
|
|
10440
11122
|
TASK_STATUS_CANCELLED,
|
|
10441
11123
|
TASK_STATUS_ERROR,
|
|
10442
11124
|
TASK_STATUS_OK,
|
|
11125
|
+
abortResponse,
|
|
10443
11126
|
brotliCapacityGuess,
|
|
10444
11127
|
buildResponseContext,
|
|
10445
11128
|
buildTerminalResponse,
|
|
@@ -10474,12 +11157,15 @@ export {
|
|
|
10474
11157
|
errorCodeName,
|
|
10475
11158
|
errorMessage,
|
|
10476
11159
|
fallbackHandler,
|
|
11160
|
+
flushMemory,
|
|
10477
11161
|
generateRequestId,
|
|
11162
|
+
getIngressBinding,
|
|
10478
11163
|
gracefulShutdown,
|
|
10479
11164
|
gzipCompressUpperBound,
|
|
10480
11165
|
headHandler,
|
|
10481
11166
|
headersForResult,
|
|
10482
11167
|
healthHandler,
|
|
11168
|
+
isAbortError,
|
|
10483
11169
|
isNativeOp,
|
|
10484
11170
|
isProven,
|
|
10485
11171
|
isValidResponseStatus,
|
|
@@ -10516,6 +11202,7 @@ export {
|
|
|
10516
11202
|
safeTerminalStatus,
|
|
10517
11203
|
serializeTraceParent,
|
|
10518
11204
|
sseResponse,
|
|
11205
|
+
staticLiveness,
|
|
10519
11206
|
statusForErrorCode,
|
|
10520
11207
|
unpackBitset,
|
|
10521
11208
|
unpackByteResults,
|