castrum 0.9.7 → 0.9.8
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 +501 -5
- package/dist/index.js +1648 -1325
- package/docs/BENCHMARKS.md +13 -0
- package/docs/CASE_STUDY.md +1 -1
- package/docs/ENVIRONMENT.md +1 -1
- package/docs/FFI_BUN_GUIDE.md +1 -1
- package/docs/INGRESS.md +4 -4
- package/docs/REPO_MAP.md +7 -5
- package/docs/superpowers/plans/2026-09-18-castrum-hardening-cleanup.md +617 -0
- package/index.ts +1 -0
- package/package.json +3 -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 +51 -32
- 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/native_route.rs +21 -3
- package/rust/task/completion.rs +7 -0
- package/rust/task/mod.rs +1 -1
- package/rust/task/tests.rs +30 -0
- 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 +103 -31
- package/src/ingress/headers/memoized-headers.ts +40 -0
- 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 +14 -2
- package/src/ingress/routes/common.ts +26 -10
- package/src/ingress/routes/echo.ts +50 -7
- package/src/ingress/routes/json-write.ts +21 -8
- package/src/ingress/routes/responder.ts +4 -4
- package/src/ingress/server-node.ts +33 -14
- package/src/ingress/server.ts +3 -4
- package/src/ingress/shared.ts +1 -1
- package/src/ingress/types.ts +15 -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.ts +5 -1
- package/src/native/ffi/selftest.ts +3 -3
- package/src/native/ffi/symbols.ts +460 -0
- package/src/native/ffi.ts +2 -434
- package/src/native/ingress-binding.ts +39 -0
- package/src/runtime/codec.ts +24 -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/options.ts +19 -0
- package/src/rust-ffi/scalar/crypto.ts +8 -0
- package/src/rust-ffi/scalar/factories.ts +47 -20
- package/src/rust-ffi/scalar/http.ts +60 -10
- package/src/rust-ffi/scalar/interface.ts +4 -1
- package/src/rust-ffi/scalar/payload.ts +27 -1
- package/src/shared/buffer-pool.ts +44 -9
- package/src/shared/codec.ts +26 -0
- package/src/shared/packed/parsers.ts +64 -7
- package/src/task/runtime.ts +29 -28
package/dist/index.js
CHANGED
|
@@ -87,7 +87,8 @@ function createBunCodec() {
|
|
|
87
87
|
},
|
|
88
88
|
decodeUtf8: decodeUtf8Bun,
|
|
89
89
|
decodeUtf8Fatal: decodeUtf8Bun,
|
|
90
|
-
decodeUtf8Range: decodeUtf8RangeBun
|
|
90
|
+
decodeUtf8Range: decodeUtf8RangeBun,
|
|
91
|
+
decodeUtf8RangeView: decodeUtf8RangeViewBun
|
|
91
92
|
};
|
|
92
93
|
}
|
|
93
94
|
function bunEncodeUtf8Into(s, dest, offset = 0) {
|
|
@@ -122,6 +123,14 @@ function decodeUtf8RangeBun(bytes, start, end) {
|
|
|
122
123
|
}
|
|
123
124
|
return view.toString("latin1", base + start, base + end);
|
|
124
125
|
}
|
|
126
|
+
function decodeUtf8RangeViewBun(view, start, end) {
|
|
127
|
+
for (let i = start;i < end; i++) {
|
|
128
|
+
if ((view[i] ?? 0) >= 128) {
|
|
129
|
+
return view.toString("utf8", start, end);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return view.toString("latin1", start, end);
|
|
133
|
+
}
|
|
125
134
|
function createNodeCodec() {
|
|
126
135
|
return {
|
|
127
136
|
encodeUtf8(s) {
|
|
@@ -144,6 +153,14 @@ function createNodeCodec() {
|
|
|
144
153
|
}
|
|
145
154
|
}
|
|
146
155
|
return view.toString("latin1", start, end);
|
|
156
|
+
},
|
|
157
|
+
decodeUtf8RangeView(view, start, end) {
|
|
158
|
+
for (let i = start;i < end; i++) {
|
|
159
|
+
if ((view[i] ?? 0) >= 128) {
|
|
160
|
+
return view.toString("utf8", start, end);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return view.toString("latin1", start, end);
|
|
147
164
|
}
|
|
148
165
|
};
|
|
149
166
|
}
|
|
@@ -264,6 +281,362 @@ var init_builtins = __esm(() => {
|
|
|
264
281
|
runtimeBuiltins = createBuiltins(detectedRuntime);
|
|
265
282
|
});
|
|
266
283
|
|
|
284
|
+
// src/native/ffi/symbols.ts
|
|
285
|
+
function buildFFISymbolMap(useBufferLength) {
|
|
286
|
+
const inputAbi = useBufferLength ? ["buffer", "buffer_length"] : ["ptr", "usize"];
|
|
287
|
+
const abi = (shape) => {
|
|
288
|
+
if (!useBufferLength)
|
|
289
|
+
return shape;
|
|
290
|
+
const out = [];
|
|
291
|
+
for (let i = 0;i < shape.length; i++) {
|
|
292
|
+
const t = shape[i];
|
|
293
|
+
if (t === "ptr") {
|
|
294
|
+
out.push("buffer");
|
|
295
|
+
out.push("buffer_length");
|
|
296
|
+
i++;
|
|
297
|
+
} else {
|
|
298
|
+
out.push(t);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return out;
|
|
302
|
+
};
|
|
303
|
+
const U64_FAST = "u64_fast";
|
|
304
|
+
return {
|
|
305
|
+
castrum_crc32: { args: inputAbi, returns: "u32" },
|
|
306
|
+
castrum_fnv1a64: { args: inputAbi, returns: "u64" },
|
|
307
|
+
castrum_xxh3: { args: inputAbi, returns: "u64" },
|
|
308
|
+
castrum_json_valid: { args: inputAbi, returns: "u8" },
|
|
309
|
+
castrum_utf8_valid: { args: inputAbi, returns: "u8" },
|
|
310
|
+
castrum_hex_encode: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: U64_FAST },
|
|
311
|
+
castrum_hex_decode: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: U64_FAST },
|
|
312
|
+
castrum_url_encode: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: U64_FAST },
|
|
313
|
+
castrum_url_decode: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: U64_FAST },
|
|
314
|
+
castrum_validate_email: { args: ["cstring"], returns: "u8" },
|
|
315
|
+
castrum_validate_uuid: { args: ["cstring"], returns: "u8" },
|
|
316
|
+
castrum_validate_ipv4: { args: ["cstring"], returns: "u8" },
|
|
317
|
+
castrum_validate_ipv6: { args: ["cstring"], returns: "u8" },
|
|
318
|
+
castrum_validate_email_bytes: { args: inputAbi, returns: "u8" },
|
|
319
|
+
castrum_validate_uuid_bytes: { args: inputAbi, returns: "u8" },
|
|
320
|
+
castrum_validate_ipv4_bytes: { args: inputAbi, returns: "u8" },
|
|
321
|
+
castrum_validate_ipv6_bytes: { args: inputAbi, returns: "u8" },
|
|
322
|
+
castrum_json_sum_ids: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: U64_FAST },
|
|
323
|
+
castrum_hmac_sha256_verify: {
|
|
324
|
+
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
325
|
+
returns: "u8"
|
|
326
|
+
},
|
|
327
|
+
castrum_csrf_verify: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: "u8" },
|
|
328
|
+
castrum_password_verify: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: "u8" },
|
|
329
|
+
castrum_password_verify_bcrypt: {
|
|
330
|
+
args: abi(["ptr", "usize", "cstring"]),
|
|
331
|
+
returns: "u8"
|
|
332
|
+
},
|
|
333
|
+
castrum_ws_accept_key: { args: ["cstring"], returns: "cstring" },
|
|
334
|
+
castrum_ws_accept_key_into: {
|
|
335
|
+
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
336
|
+
returns: U64_FAST
|
|
337
|
+
},
|
|
338
|
+
castrum_etag: { args: abi(["ptr", "usize", "u8"]), returns: "cstring" },
|
|
339
|
+
castrum_etag_into: { args: abi(["ptr", "usize", "u8", "ptr", "usize"]), returns: U64_FAST },
|
|
340
|
+
castrum_conditional_is_not_modified: {
|
|
341
|
+
args: abi(["usize", "ptr", "usize", "ptr", "usize", "u8"]),
|
|
342
|
+
returns: "u8"
|
|
343
|
+
},
|
|
344
|
+
castrum_media_type_matcher_matches: {
|
|
345
|
+
args: abi(["usize", "ptr", "usize"]),
|
|
346
|
+
returns: "u8"
|
|
347
|
+
},
|
|
348
|
+
castrum_accept_negotiator_negotiate: {
|
|
349
|
+
args: abi(["usize", "ptr", "usize"]),
|
|
350
|
+
returns: "cstring"
|
|
351
|
+
},
|
|
352
|
+
castrum_accept_negotiator_negotiate_server: {
|
|
353
|
+
args: ["usize", "cstring"],
|
|
354
|
+
returns: "cstring"
|
|
355
|
+
},
|
|
356
|
+
castrum_jwt_signer_sign: {
|
|
357
|
+
args: abi(["usize", "ptr", "usize", "i64", "ptr", "usize"]),
|
|
358
|
+
returns: U64_FAST
|
|
359
|
+
},
|
|
360
|
+
castrum_jwt_signer_verify: {
|
|
361
|
+
args: abi(["usize", "ptr", "usize", "i64", "ptr", "usize"]),
|
|
362
|
+
returns: U64_FAST
|
|
363
|
+
},
|
|
364
|
+
castrum_template_render: {
|
|
365
|
+
args: abi(["usize", "ptr", "usize", "ptr", "usize"]),
|
|
366
|
+
returns: U64_FAST
|
|
367
|
+
},
|
|
368
|
+
castrum_schema_validator_validate: {
|
|
369
|
+
args: abi(["usize", "ptr", "usize"]),
|
|
370
|
+
returns: "u8"
|
|
371
|
+
},
|
|
372
|
+
castrum_rate_limiter_check: {
|
|
373
|
+
args: abi(["usize", "cstring", "i64", "ptr", "usize"]),
|
|
374
|
+
returns: U64_FAST
|
|
375
|
+
},
|
|
376
|
+
castrum_rate_limiter_check_key: {
|
|
377
|
+
args: abi(["usize", "i64", "i64", "ptr", "usize"]),
|
|
378
|
+
returns: U64_FAST
|
|
379
|
+
},
|
|
380
|
+
castrum_random_token: { args: ["u32"], returns: "cstring" },
|
|
381
|
+
castrum_random_token_into: { args: ["u32", ...abi(["ptr", "usize"])], returns: U64_FAST },
|
|
382
|
+
castrum_base64_encode: {
|
|
383
|
+
args: abi(["ptr", "usize", "ptr", "usize", "u8", "u8"]),
|
|
384
|
+
returns: U64_FAST
|
|
385
|
+
},
|
|
386
|
+
castrum_base64_decode: {
|
|
387
|
+
args: abi(["ptr", "usize", "ptr", "usize", "u8", "u8"]),
|
|
388
|
+
returns: U64_FAST
|
|
389
|
+
},
|
|
390
|
+
castrum_hmac_sha256: {
|
|
391
|
+
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
392
|
+
returns: U64_FAST
|
|
393
|
+
},
|
|
394
|
+
castrum_sign_cookie: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: "cstring" },
|
|
395
|
+
castrum_sign_cookie_into: {
|
|
396
|
+
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
397
|
+
returns: U64_FAST
|
|
398
|
+
},
|
|
399
|
+
castrum_verify_cookie: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: "cstring" },
|
|
400
|
+
castrum_verify_cookie_into: {
|
|
401
|
+
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
402
|
+
returns: U64_FAST
|
|
403
|
+
},
|
|
404
|
+
castrum_csrf_token: { args: abi(["ptr", "usize"]), returns: "cstring" },
|
|
405
|
+
castrum_csrf_token_into: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: U64_FAST },
|
|
406
|
+
castrum_password_hash: {
|
|
407
|
+
args: abi(["ptr", "usize", "ptr", "usize", "u32", "u32", "u32", "u32", "ptr", "usize"]),
|
|
408
|
+
returns: U64_FAST
|
|
409
|
+
},
|
|
410
|
+
castrum_password_hash_bcrypt: {
|
|
411
|
+
args: abi(["ptr", "usize", "u32", "ptr", "usize"]),
|
|
412
|
+
returns: U64_FAST
|
|
413
|
+
},
|
|
414
|
+
castrum_pbkdf2_sha256: {
|
|
415
|
+
args: abi(["ptr", "usize", "ptr", "usize", "u32", "u32", "ptr", "usize"]),
|
|
416
|
+
returns: U64_FAST
|
|
417
|
+
},
|
|
418
|
+
castrum_aead_encrypt: {
|
|
419
|
+
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize", "u8", "ptr", "usize"]),
|
|
420
|
+
returns: U64_FAST
|
|
421
|
+
},
|
|
422
|
+
castrum_aead_decrypt: {
|
|
423
|
+
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize", "u8", "ptr", "usize"]),
|
|
424
|
+
returns: U64_FAST
|
|
425
|
+
},
|
|
426
|
+
castrum_ws_frame_encode: {
|
|
427
|
+
args: abi(["u8", "ptr", "usize", "u8", "u8", "ptr", "usize"]),
|
|
428
|
+
returns: U64_FAST
|
|
429
|
+
},
|
|
430
|
+
castrum_json_patch: {
|
|
431
|
+
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
432
|
+
returns: U64_FAST
|
|
433
|
+
},
|
|
434
|
+
castrum_gzip_compress: {
|
|
435
|
+
args: abi(["ptr", "usize", "u32", "ptr", "usize"]),
|
|
436
|
+
returns: U64_FAST
|
|
437
|
+
},
|
|
438
|
+
castrum_gzip_decompress: {
|
|
439
|
+
args: abi(["ptr", "usize", "usize", "ptr", "usize"]),
|
|
440
|
+
returns: U64_FAST
|
|
441
|
+
},
|
|
442
|
+
castrum_brotli_compress: {
|
|
443
|
+
args: abi(["ptr", "usize", "u32", "ptr", "usize"]),
|
|
444
|
+
returns: U64_FAST
|
|
445
|
+
},
|
|
446
|
+
castrum_brotli_decompress: {
|
|
447
|
+
args: abi(["ptr", "usize", "usize", "ptr", "usize"]),
|
|
448
|
+
returns: U64_FAST
|
|
449
|
+
},
|
|
450
|
+
castrum_gzip_isize: { args: abi(["ptr", "usize"]), returns: "u32" },
|
|
451
|
+
castrum_http_parse_request_packed: {
|
|
452
|
+
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
453
|
+
returns: U64_FAST
|
|
454
|
+
},
|
|
455
|
+
castrum_query_parse_packed: {
|
|
456
|
+
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
457
|
+
returns: U64_FAST
|
|
458
|
+
},
|
|
459
|
+
castrum_cookie_parse_packed: {
|
|
460
|
+
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
461
|
+
returns: U64_FAST
|
|
462
|
+
},
|
|
463
|
+
castrum_http_date_into: { args: ["f64", ...abi(["ptr", "usize"])], returns: U64_FAST },
|
|
464
|
+
castrum_sse_encode_into: {
|
|
465
|
+
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize", "u8", "u32", "ptr", "usize"]),
|
|
466
|
+
returns: U64_FAST
|
|
467
|
+
},
|
|
468
|
+
castrum_jwt_sign_bytes: {
|
|
469
|
+
args: abi(["ptr", "usize", "ptr", "usize", "i64", "i64"]),
|
|
470
|
+
returns: "cstring"
|
|
471
|
+
},
|
|
472
|
+
castrum_jwt_sign_bytes_into: {
|
|
473
|
+
args: abi(["ptr", "usize", "ptr", "usize", "i64", "i64", "ptr", "usize"]),
|
|
474
|
+
returns: U64_FAST
|
|
475
|
+
},
|
|
476
|
+
castrum_ed25519_generate_keypair: {
|
|
477
|
+
args: abi(["ptr", "usize"]),
|
|
478
|
+
returns: U64_FAST
|
|
479
|
+
},
|
|
480
|
+
castrum_ed25519_sign: {
|
|
481
|
+
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
482
|
+
returns: U64_FAST
|
|
483
|
+
},
|
|
484
|
+
castrum_ed25519_verify: {
|
|
485
|
+
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
486
|
+
returns: "u32"
|
|
487
|
+
},
|
|
488
|
+
castrum_jwt_eddsa_sign: {
|
|
489
|
+
args: abi(["ptr", "usize", "ptr", "usize", "i64", "i64"]),
|
|
490
|
+
returns: "cstring"
|
|
491
|
+
},
|
|
492
|
+
castrum_jwt_eddsa_verify: {
|
|
493
|
+
args: abi(["ptr", "usize", "ptr", "usize", "i64"]),
|
|
494
|
+
returns: "cstring"
|
|
495
|
+
},
|
|
496
|
+
castrum_ws_frame_decode_packed: {
|
|
497
|
+
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
498
|
+
returns: U64_FAST
|
|
499
|
+
},
|
|
500
|
+
castrum_multipart_parse_packed: {
|
|
501
|
+
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
502
|
+
returns: U64_FAST
|
|
503
|
+
},
|
|
504
|
+
castrum_form_parse_packed: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: U64_FAST },
|
|
505
|
+
castrum_json_parse_packed: {
|
|
506
|
+
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
507
|
+
returns: U64_FAST
|
|
508
|
+
},
|
|
509
|
+
castrum_parse_media_type: {
|
|
510
|
+
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
511
|
+
returns: U64_FAST
|
|
512
|
+
},
|
|
513
|
+
castrum_parse_http_date: {
|
|
514
|
+
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
515
|
+
returns: U64_FAST
|
|
516
|
+
},
|
|
517
|
+
castrum_parse_accept_encoding: {
|
|
518
|
+
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
519
|
+
returns: U64_FAST
|
|
520
|
+
},
|
|
521
|
+
castrum_url_encode_query: { args: abi(["ptr", "usize"]), returns: "cstring" },
|
|
522
|
+
castrum_url_resolve: {
|
|
523
|
+
args: abi(["ptr", "usize", "ptr", "usize"]),
|
|
524
|
+
returns: "cstring"
|
|
525
|
+
},
|
|
526
|
+
castrum_url_builder_resolve: {
|
|
527
|
+
args: abi(["usize", "ptr", "usize", "ptr", "usize"]),
|
|
528
|
+
returns: U64_FAST
|
|
529
|
+
},
|
|
530
|
+
castrum_mime_from_extension: { args: ["cstring"], returns: "cstring" },
|
|
531
|
+
castrum_jwt_verify: {
|
|
532
|
+
args: abi(["ptr", "usize", "ptr", "usize", "i64"]),
|
|
533
|
+
returns: "cstring"
|
|
534
|
+
},
|
|
535
|
+
castrum_ingress_handle_packed: {
|
|
536
|
+
args: abi(["usize", "ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
537
|
+
returns: U64_FAST
|
|
538
|
+
},
|
|
539
|
+
castrum_ingress_handle_components: {
|
|
540
|
+
args: abi([
|
|
541
|
+
"usize",
|
|
542
|
+
"u8",
|
|
543
|
+
"cstring",
|
|
544
|
+
"cstring",
|
|
545
|
+
"ptr",
|
|
546
|
+
"usize",
|
|
547
|
+
"ptr",
|
|
548
|
+
"usize",
|
|
549
|
+
"ptr",
|
|
550
|
+
"usize",
|
|
551
|
+
"ptr",
|
|
552
|
+
"usize"
|
|
553
|
+
]),
|
|
554
|
+
returns: U64_FAST
|
|
555
|
+
},
|
|
556
|
+
castrum_ingress_layout: { args: abi(["ptr", "usize"]), returns: U64_FAST },
|
|
557
|
+
castrum_route_compile: { args: abi(["ptr", "usize"]), returns: U64_FAST },
|
|
558
|
+
castrum_route_run: {
|
|
559
|
+
args: abi(["usize", "ptr", "usize", "ptr", "usize"]),
|
|
560
|
+
returns: U64_FAST
|
|
561
|
+
},
|
|
562
|
+
castrum_route_destroy: { args: ["usize"], returns: "void" },
|
|
563
|
+
castrum_hex_validate_batch: {
|
|
564
|
+
args: abi(["ptr", "usize", "u32", "ptr", "usize"]),
|
|
565
|
+
returns: U64_FAST
|
|
566
|
+
},
|
|
567
|
+
castrum_regex_escape: { args: abi(["ptr", "usize", "ptr", "usize"]), returns: U64_FAST },
|
|
568
|
+
castrum_metrics_create: { args: [], returns: U64_FAST },
|
|
569
|
+
castrum_metrics_counter: { args: ["usize", "cstring", "cstring"], returns: "u32" },
|
|
570
|
+
castrum_metrics_gauge: { args: ["usize", "cstring", "cstring"], returns: "u32" },
|
|
571
|
+
castrum_metrics_histogram: {
|
|
572
|
+
args: ["usize", "cstring", "cstring", "cstring"],
|
|
573
|
+
returns: "u32"
|
|
574
|
+
},
|
|
575
|
+
castrum_metrics_record: {
|
|
576
|
+
args: abi(["usize", "u32", "ptr", "usize", "f64"]),
|
|
577
|
+
returns: "u8"
|
|
578
|
+
},
|
|
579
|
+
castrum_metrics_gauge_set: {
|
|
580
|
+
args: abi(["usize", "u32", "ptr", "usize", "f64"]),
|
|
581
|
+
returns: "u8"
|
|
582
|
+
},
|
|
583
|
+
castrum_metrics_record_str: {
|
|
584
|
+
args: ["usize", "u32", "cstring", "f64"],
|
|
585
|
+
returns: "u8"
|
|
586
|
+
},
|
|
587
|
+
castrum_metrics_gauge_set_str: {
|
|
588
|
+
args: ["usize", "u32", "cstring", "f64"],
|
|
589
|
+
returns: "u8"
|
|
590
|
+
},
|
|
591
|
+
castrum_regex_escape_str: { args: ["cstring"], returns: "cstring" },
|
|
592
|
+
castrum_hex_validate_batch_str: {
|
|
593
|
+
args: abi(["cstring", "u32", "ptr", "usize"]),
|
|
594
|
+
returns: U64_FAST
|
|
595
|
+
},
|
|
596
|
+
castrum_metrics_render: { args: abi(["usize", "ptr", "usize"]), returns: U64_FAST },
|
|
597
|
+
castrum_metrics_snapshot: { args: abi(["usize", "ptr", "usize"]), returns: U64_FAST },
|
|
598
|
+
castrum_metrics_record_batch: {
|
|
599
|
+
args: abi(["usize", "ptr", "usize"]),
|
|
600
|
+
returns: "u8"
|
|
601
|
+
},
|
|
602
|
+
castrum_query_validate: { args: ["usize", "cstring"], returns: "u8" },
|
|
603
|
+
castrum_cookie_validate: { args: ["usize", "cstring"], returns: "u8" },
|
|
604
|
+
castrum_session_seal: {
|
|
605
|
+
args: ["cstring", "cstring", "i64", "cstring"],
|
|
606
|
+
returns: "cstring"
|
|
607
|
+
},
|
|
608
|
+
castrum_session_open: {
|
|
609
|
+
args: abi(["cstring", "cstring", "ptr", "usize"]),
|
|
610
|
+
returns: U64_FAST
|
|
611
|
+
},
|
|
612
|
+
castrum_session_seal_bytes: {
|
|
613
|
+
args: abi(["ptr", "usize", "ptr", "usize", "i64", "ptr", "usize"]),
|
|
614
|
+
returns: "cstring"
|
|
615
|
+
},
|
|
616
|
+
castrum_session_open_bytes: {
|
|
617
|
+
args: abi(["ptr", "usize", "ptr", "usize", "ptr", "usize"]),
|
|
618
|
+
returns: U64_FAST
|
|
619
|
+
},
|
|
620
|
+
castrum_task_init: { args: ["u32"], returns: "u32" },
|
|
621
|
+
castrum_task_submit: { args: abi(["u32", "ptr", "usize", "usize"]), returns: "u32" },
|
|
622
|
+
castrum_task_submit_slice: {
|
|
623
|
+
args: abi(["u32", "ptr", "usize", "ptr", "usize", "usize"]),
|
|
624
|
+
returns: "u32"
|
|
625
|
+
},
|
|
626
|
+
castrum_task_submit_out: {
|
|
627
|
+
args: abi(["u32", "ptr", "usize", "usize", "ptr", "usize"]),
|
|
628
|
+
returns: "u32"
|
|
629
|
+
},
|
|
630
|
+
castrum_task_drain: { args: abi(["ptr", "usize"]), returns: U64_FAST },
|
|
631
|
+
castrum_task_pending: { args: [], returns: "u32" },
|
|
632
|
+
castrum_task_cancel: { args: ["usize"], returns: "u32" },
|
|
633
|
+
castrum_task_set_doorbell: { args: ["ptr"], returns: "u32" },
|
|
634
|
+
castrum_task_shutdown: { args: [], returns: "u32" },
|
|
635
|
+
castrum_task_threads: { args: [], returns: "u32" },
|
|
636
|
+
castrum_metrics_destroy: { args: ["usize"], returns: "void" }
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
|
|
267
640
|
// src/shared/runtime.ts
|
|
268
641
|
var isBun;
|
|
269
642
|
var init_runtime = __esm(() => {
|
|
@@ -272,29 +645,17 @@ var init_runtime = __esm(() => {
|
|
|
272
645
|
});
|
|
273
646
|
|
|
274
647
|
// src/shared/codec.ts
|
|
275
|
-
var encodeUtf8, encodeUtf8Into, decodeUtf8, decodeUtf8Range, decodeUtf8Fatal;
|
|
648
|
+
var encodeUtf8, encodeUtf8Into, decodeUtf8, decodeUtf8Range, decodeUtf8RangeView, decodeUtf8Fatal;
|
|
276
649
|
var init_codec2 = __esm(() => {
|
|
277
650
|
init_codec();
|
|
278
651
|
encodeUtf8 = runtimeCodec.encodeUtf8;
|
|
279
652
|
encodeUtf8Into = runtimeCodec.encodeUtf8Into;
|
|
280
653
|
decodeUtf8 = runtimeCodec.decodeUtf8;
|
|
281
654
|
decodeUtf8Range = runtimeCodec.decodeUtf8Range;
|
|
655
|
+
decodeUtf8RangeView = runtimeCodec.decodeUtf8RangeView ? runtimeCodec.decodeUtf8RangeView : (view, start, end) => decodeUtf8Range(view, start, end);
|
|
282
656
|
decodeUtf8Fatal = runtimeCodec.decodeUtf8Fatal;
|
|
283
657
|
});
|
|
284
658
|
|
|
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
659
|
// src/shared/bytes.ts
|
|
299
660
|
function toBytes(v) {
|
|
300
661
|
return typeof v === "string" ? encodeUtf8(v) : v;
|
|
@@ -696,365 +1057,160 @@ function buildCodecs(sym, ctx) {
|
|
|
696
1057
|
}
|
|
697
1058
|
};
|
|
698
1059
|
}
|
|
699
|
-
|
|
1060
|
+
var init_codecs = __esm(() => {
|
|
1061
|
+
init_codec2();
|
|
1062
|
+
init_util();
|
|
1063
|
+
});
|
|
1064
|
+
|
|
1065
|
+
// src/native/ffi/constants.ts
|
|
1066
|
+
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;
|
|
1067
|
+
var init_constants = __esm(() => {
|
|
1068
|
+
MAX_DECOMPRESSED = 64 * 1024 * 1024;
|
|
1069
|
+
MAX_JSON_PATCH_OUTPUT = 128 * 1024 * 1024;
|
|
1070
|
+
COMPRESS_INITIAL_CAP = 16 * 1024;
|
|
1071
|
+
COMPRESS_MAX_CAP = 1024 * 1024;
|
|
1072
|
+
DECOMPRESS_FALLBACK_CAP = 4 * 1024 * 1024;
|
|
1073
|
+
SELFTEST_HEX = new Uint8Array([104, 101, 108, 108, 111]);
|
|
1074
|
+
SELFTEST_JSON = new Uint8Array([123, 34, 97, 34, 58, 49, 125]);
|
|
1075
|
+
EMPTY_VIEW = new Uint8Array(0);
|
|
1076
|
+
});
|
|
1077
|
+
|
|
1078
|
+
// src/native/ffi/build/compress.ts
|
|
1079
|
+
function buildCompress(sym, ctx) {
|
|
1080
|
+
const { lenOrView, scratchFor } = ctx;
|
|
1081
|
+
const gzipCompress = sym.castrum_gzip_compress;
|
|
1082
|
+
const gzipDecompress = sym.castrum_gzip_decompress;
|
|
1083
|
+
const brotliCompress = sym.castrum_brotli_compress;
|
|
1084
|
+
const brotliDecompress = sym.castrum_brotli_decompress;
|
|
1085
|
+
const gzipIsize = sym.castrum_gzip_isize;
|
|
1086
|
+
const jsonPatch = sym.castrum_json_patch;
|
|
1087
|
+
return {
|
|
1088
|
+
jsonPatch(doc, patch) {
|
|
1089
|
+
let out = scratchFor(Math.min(Math.max(doc.length, patch.length) + 16, 64 * 1024));
|
|
1090
|
+
let w = Number(jsonPatch(doc, lenOrView(doc), patch, lenOrView(patch), out, lenOrView(out)));
|
|
1091
|
+
if (w > out.length && w <= MAX_JSON_PATCH_OUTPUT) {
|
|
1092
|
+
out = new Uint8Array(w);
|
|
1093
|
+
w = Number(jsonPatch(doc, lenOrView(doc), patch, lenOrView(patch), out, lenOrView(out)));
|
|
1094
|
+
}
|
|
1095
|
+
if (w === 0 || w > out.length) {
|
|
1096
|
+
throw new Error("json patch: output buffer too small or patch inapplicable");
|
|
1097
|
+
}
|
|
1098
|
+
return decodeUtf8(out.subarray(0, w));
|
|
1099
|
+
},
|
|
1100
|
+
gzipCompress(data, level = 6) {
|
|
1101
|
+
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");
|
|
1102
|
+
},
|
|
1103
|
+
gzipCompressInto(data, output, level = 6) {
|
|
1104
|
+
const w = Number(gzipCompress(data, lenOrView(data), Math.min(level, 9), output, lenOrView(output)));
|
|
1105
|
+
if (w === 0) {
|
|
1106
|
+
throw new Error("gzip compress: invalid input");
|
|
1107
|
+
}
|
|
1108
|
+
if (w > output.length) {
|
|
1109
|
+
throw new Error("gzip compress: output buffer too small");
|
|
1110
|
+
}
|
|
1111
|
+
return w;
|
|
1112
|
+
},
|
|
1113
|
+
gzipDecompress(data, maxDecompressed) {
|
|
1114
|
+
const max = maxDecompressed ?? MAX_DECOMPRESSED;
|
|
1115
|
+
const isize = Number(gzipIsize(data, lenOrView(data)));
|
|
1116
|
+
const initial = isize !== 0 ? Math.min(isize, max) : Math.min(data.length * DECOMPRESS_GUESS_MULTIPLIER_GZIP, DECOMPRESS_FALLBACK_CAP);
|
|
1117
|
+
return growExact((out) => Number(gzipDecompress(data, lenOrView(data), max, out, lenOrView(out))), initial, max, "gzip decompress: invalid stream or exceeded max decompressed size");
|
|
1118
|
+
},
|
|
1119
|
+
gzipDecompressInto(data, output, maxDecompressed) {
|
|
1120
|
+
const max = maxDecompressed ?? MAX_DECOMPRESSED;
|
|
1121
|
+
const w = Number(gzipDecompress(data, lenOrView(data), max, output, lenOrView(output)));
|
|
1122
|
+
if (w === 0) {
|
|
1123
|
+
throw new Error("gzip decompress: invalid stream or exceeded max decompressed size");
|
|
1124
|
+
}
|
|
1125
|
+
if (w > output.length) {
|
|
1126
|
+
throw new Error("gzip decompress: output buffer too small");
|
|
1127
|
+
}
|
|
1128
|
+
return w;
|
|
1129
|
+
},
|
|
1130
|
+
gzipIsize(data) {
|
|
1131
|
+
return Number(gzipIsize(data, lenOrView(data)));
|
|
1132
|
+
},
|
|
1133
|
+
brotliCompress(data, quality = 5) {
|
|
1134
|
+
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");
|
|
1135
|
+
},
|
|
1136
|
+
brotliCompressInto(data, output, quality = 5) {
|
|
1137
|
+
const w = Number(brotliCompress(data, lenOrView(data), Math.min(quality, 11), output, lenOrView(output)));
|
|
1138
|
+
if (w === 0) {
|
|
1139
|
+
throw new Error("brotli compress: invalid input");
|
|
1140
|
+
}
|
|
1141
|
+
if (w > output.length) {
|
|
1142
|
+
throw new Error("brotli compress: output buffer too small");
|
|
1143
|
+
}
|
|
1144
|
+
return w;
|
|
1145
|
+
},
|
|
1146
|
+
brotliDecompress(data, maxDecompressed) {
|
|
1147
|
+
const max = maxDecompressed ?? MAX_DECOMPRESSED;
|
|
1148
|
+
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");
|
|
1149
|
+
},
|
|
1150
|
+
brotliDecompressInto(data, output, maxDecompressed) {
|
|
1151
|
+
const max = maxDecompressed ?? MAX_DECOMPRESSED;
|
|
1152
|
+
const w = Number(brotliDecompress(data, lenOrView(data), max, output, lenOrView(output)));
|
|
1153
|
+
if (w === 0) {
|
|
1154
|
+
throw new Error("brotli decompress: invalid stream or exceeded max decompressed size");
|
|
1155
|
+
}
|
|
1156
|
+
if (w > output.length) {
|
|
1157
|
+
throw new Error("brotli decompress: output buffer too small");
|
|
1158
|
+
}
|
|
1159
|
+
return w;
|
|
1160
|
+
}
|
|
1161
|
+
};
|
|
1162
|
+
}
|
|
1163
|
+
function selfTestCompress(b) {
|
|
700
1164
|
const enc = { encode: encodeUtf8 };
|
|
701
1165
|
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") {
|
|
1166
|
+
const patched = b.jsonPatch(enc.encode(`{"a":"b"}`), enc.encode(`[{"op":"add","path":"/c","value":"d"}]`));
|
|
1167
|
+
if (!patched.includes(`"c":"d"`)) {
|
|
721
1168
|
return false;
|
|
722
1169
|
}
|
|
723
|
-
|
|
1170
|
+
const gz = b.gzipCompress(SELFTEST_HEX);
|
|
1171
|
+
if (dec.decode(b.gzipDecompress(gz)) !== "hello") {
|
|
724
1172
|
return false;
|
|
725
1173
|
}
|
|
726
|
-
|
|
1174
|
+
const br = b.brotliCompress(SELFTEST_HEX);
|
|
1175
|
+
if (dec.decode(b.brotliDecompress(br)) !== "hello") {
|
|
727
1176
|
return false;
|
|
728
1177
|
}
|
|
729
|
-
|
|
730
|
-
return false;
|
|
731
|
-
if (b.jsonSumIds(enc.encode(`[{"id":0},{"id":0}]`)) !== 0n)
|
|
732
|
-
return false;
|
|
733
|
-
let sumInvalidThrew = false;
|
|
1178
|
+
let decompressThrew = false;
|
|
734
1179
|
try {
|
|
735
|
-
b.
|
|
1180
|
+
b.gzipDecompress(enc.encode("not-a-gzip-stream"));
|
|
736
1181
|
} catch {
|
|
737
|
-
|
|
738
|
-
}
|
|
739
|
-
if (!sumInvalidThrew)
|
|
740
|
-
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;
|
|
1182
|
+
decompressThrew = true;
|
|
785
1183
|
}
|
|
786
|
-
|
|
787
|
-
const hmacData = enc.encode("Hi There");
|
|
788
|
-
const hmacSig = enc.encode("b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7");
|
|
789
|
-
if (b.hmacSha256(hmacKey, hmacData) !== "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7") {
|
|
1184
|
+
if (!decompressThrew) {
|
|
790
1185
|
return false;
|
|
791
1186
|
}
|
|
792
|
-
|
|
793
|
-
|
|
1187
|
+
decompressThrew = false;
|
|
1188
|
+
try {
|
|
1189
|
+
b.brotliDecompress(enc.encode("not-brotli-stream"));
|
|
1190
|
+
} catch {
|
|
1191
|
+
decompressThrew = true;
|
|
794
1192
|
}
|
|
795
|
-
|
|
796
|
-
if (dec.decode(decoded) !== "hello" || dec.decode(b.urlDecode(enc.encode("a%20b%2Fc"))) !== "a b/c") {
|
|
1193
|
+
if (!decompressThrew) {
|
|
797
1194
|
return false;
|
|
798
1195
|
}
|
|
799
|
-
|
|
1196
|
+
const gzInto = new Uint8Array(64);
|
|
1197
|
+
const gzW = b.gzipCompressInto(SELFTEST_HEX, gzInto);
|
|
1198
|
+
if (gzW === 0 || dec.decode(b.gzipDecompress(gzInto.subarray(0, gzW))) !== "hello") {
|
|
800
1199
|
return false;
|
|
801
1200
|
}
|
|
802
|
-
|
|
1201
|
+
const brInto = new Uint8Array(64);
|
|
1202
|
+
const brW = b.brotliCompressInto(SELFTEST_HEX, brInto);
|
|
1203
|
+
if (brW === 0 || dec.decode(b.brotliDecompress(brInto.subarray(0, brW))) !== "hello") {
|
|
803
1204
|
return false;
|
|
804
1205
|
}
|
|
805
|
-
|
|
1206
|
+
const gzDst = new Uint8Array(16);
|
|
1207
|
+
const gzDW = b.gzipDecompressInto(gzInto.subarray(0, gzW), gzDst);
|
|
1208
|
+
if (gzDW === 0 || dec.decode(gzDst.subarray(0, gzDW)) !== "hello") {
|
|
806
1209
|
return false;
|
|
807
1210
|
}
|
|
808
|
-
|
|
809
|
-
|
|
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") {
|
|
1211
|
+
const brDst = new Uint8Array(16);
|
|
1212
|
+
const brDW = b.brotliDecompressInto(brInto.subarray(0, brW), brDst);
|
|
1213
|
+
if (brDW === 0 || dec.decode(brDst.subarray(0, brDW)) !== "hello") {
|
|
1058
1214
|
return false;
|
|
1059
1215
|
}
|
|
1060
1216
|
return true;
|
|
@@ -1113,7 +1269,10 @@ function buildInstances(sym, ctx) {
|
|
|
1113
1269
|
return acceptNegotiatorNegotiateRaw(inner, header, lenOrView(header));
|
|
1114
1270
|
},
|
|
1115
1271
|
acceptNegotiatorNegotiateServer(inner, header) {
|
|
1116
|
-
|
|
1272
|
+
const text = decodeUtf8(header);
|
|
1273
|
+
if (hasNul(text))
|
|
1274
|
+
return null;
|
|
1275
|
+
return acceptNegotiatorNegotiateServerRaw(inner, text);
|
|
1117
1276
|
},
|
|
1118
1277
|
jwtSignerSign(inner, claimsJson, nowSeconds) {
|
|
1119
1278
|
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 +1319,8 @@ function buildInstances(sym, ctx) {
|
|
|
1160
1319
|
return Number(sessionOpenBytesSym(token, lenOrView(token), secret, lenOrView(secret), output, lenOrView(output)));
|
|
1161
1320
|
},
|
|
1162
1321
|
rateLimiterCheck(inner, key, nowMs) {
|
|
1322
|
+
if (hasNul(key))
|
|
1323
|
+
return { allowed: false, remaining: 0, resetMs: 0 };
|
|
1163
1324
|
const out = rateScratch;
|
|
1164
1325
|
const w = Number(rateLimiterCheckRaw(inner, key, BigInt(Math.trunc(nowMs)), out, lenOrView(out)));
|
|
1165
1326
|
if (w === 0)
|
|
@@ -1252,190 +1413,6 @@ function buildInstances(sym, ctx) {
|
|
|
1252
1413
|
}
|
|
1253
1414
|
};
|
|
1254
1415
|
}
|
|
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
1416
|
var init_instances = __esm(() => {
|
|
1440
1417
|
init_codec2();
|
|
1441
1418
|
init_constants();
|
|
@@ -1623,15 +1600,702 @@ function selfTestMetrics(b) {
|
|
|
1623
1600
|
} catch (err) {
|
|
1624
1601
|
console.error("METRICS SELFTEST THROW:", err);
|
|
1625
1602
|
return false;
|
|
1626
|
-
} finally {
|
|
1627
|
-
b.metricsDestroy(handle);
|
|
1603
|
+
} finally {
|
|
1604
|
+
b.metricsDestroy(handle);
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
var METRICS_DECLARE_ERR = 4294967295, EMPTY;
|
|
1608
|
+
var init_metrics = __esm(() => {
|
|
1609
|
+
init_codec2();
|
|
1610
|
+
init_util();
|
|
1611
|
+
EMPTY = new Uint8Array(0);
|
|
1612
|
+
});
|
|
1613
|
+
|
|
1614
|
+
// src/native/ffi/build/parse.ts
|
|
1615
|
+
function sseMemoEncode(slot, s) {
|
|
1616
|
+
if (s === slot.str)
|
|
1617
|
+
return slot.bytes;
|
|
1618
|
+
const bytes = encodeUtf8(s);
|
|
1619
|
+
slot.str = s;
|
|
1620
|
+
slot.bytes = bytes;
|
|
1621
|
+
return bytes;
|
|
1622
|
+
}
|
|
1623
|
+
function buildParse(sym, ctx) {
|
|
1624
|
+
const { lenOrView, scratchFor, dateScratch, dateScratchView } = ctx;
|
|
1625
|
+
const httpParsePacked = sym.castrum_http_parse_request_packed;
|
|
1626
|
+
const queryParsePacked = sym.castrum_query_parse_packed;
|
|
1627
|
+
const cookieParsePacked = sym.castrum_cookie_parse_packed;
|
|
1628
|
+
const httpDateIntoRaw = sym.castrum_http_date_into;
|
|
1629
|
+
const sseEncodeIntoRaw = sym.castrum_sse_encode_into;
|
|
1630
|
+
const jsonParsePackedSym = sym.castrum_json_parse_packed;
|
|
1631
|
+
const wsFrameDecodePacked = sym.castrum_ws_frame_decode_packed;
|
|
1632
|
+
const multipartParsePacked = sym.castrum_multipart_parse_packed;
|
|
1633
|
+
const formParsePacked = sym.castrum_form_parse_packed;
|
|
1634
|
+
const wsFrameEncode = sym.castrum_ws_frame_encode;
|
|
1635
|
+
const parseMediaTypeSym = sym.castrum_parse_media_type;
|
|
1636
|
+
const parseHttpDateSym = sym.castrum_parse_http_date;
|
|
1637
|
+
const parseAcceptEncodingSym = sym.castrum_parse_accept_encoding;
|
|
1638
|
+
const urlEncodeQuerySym = sym.castrum_url_encode_query;
|
|
1639
|
+
const urlResolveSym = sym.castrum_url_resolve;
|
|
1640
|
+
const mimeFromExtensionSym = sym.castrum_mime_from_extension;
|
|
1641
|
+
return {
|
|
1642
|
+
httpParseRequestPackedInto(input, output) {
|
|
1643
|
+
const w = Number(httpParsePacked(input, lenOrView(input), output, lenOrView(output)));
|
|
1644
|
+
if (w === 0 && input.length !== 0) {
|
|
1645
|
+
throw new Error("http parse: output buffer too small or malformed request");
|
|
1646
|
+
}
|
|
1647
|
+
return w;
|
|
1648
|
+
},
|
|
1649
|
+
queryParsePackedInto(input, output) {
|
|
1650
|
+
const w = Number(queryParsePacked(input, lenOrView(input), output, lenOrView(output)));
|
|
1651
|
+
if (w === 0 || w > output.length) {
|
|
1652
|
+
throw new Error("query parse: output buffer too small");
|
|
1653
|
+
}
|
|
1654
|
+
return w;
|
|
1655
|
+
},
|
|
1656
|
+
cookieParsePackedInto(input, output) {
|
|
1657
|
+
const w = Number(cookieParsePacked(input, lenOrView(input), output, lenOrView(output)));
|
|
1658
|
+
if (w === 0 || w > output.length) {
|
|
1659
|
+
throw new Error("cookie parse: output buffer too small");
|
|
1660
|
+
}
|
|
1661
|
+
return w;
|
|
1662
|
+
},
|
|
1663
|
+
wsFrameEncode(opcode, payload, mask, fin) {
|
|
1664
|
+
const out = allocOut(payload.length + 14);
|
|
1665
|
+
const w = Number(wsFrameEncode(opcode, payload, lenOrView(payload), flag(mask), flag(fin), out, lenOrView(out)));
|
|
1666
|
+
if (w === 0) {
|
|
1667
|
+
throw new Error("ws frame encode: output buffer too small");
|
|
1668
|
+
}
|
|
1669
|
+
return out.subarray(0, w);
|
|
1670
|
+
},
|
|
1671
|
+
wsFrameEncodeInto(opcode, payload, mask, fin, output) {
|
|
1672
|
+
const need = payload.length + 14;
|
|
1673
|
+
if (output.length < need) {
|
|
1674
|
+
throw new Error("ws frame encode: output buffer too small");
|
|
1675
|
+
}
|
|
1676
|
+
const w = Number(wsFrameEncode(opcode, payload, lenOrView(payload), flag(mask), flag(fin), output, lenOrView(output)));
|
|
1677
|
+
if (w === 0) {
|
|
1678
|
+
throw new Error("ws frame encode: output buffer too small");
|
|
1679
|
+
}
|
|
1680
|
+
return w;
|
|
1681
|
+
},
|
|
1682
|
+
wsFrameDecodePacked(data) {
|
|
1683
|
+
const out = new Uint8Array(data.length + 6);
|
|
1684
|
+
const w = Number(wsFrameDecodePacked(data, lenOrView(data), out, lenOrView(out)));
|
|
1685
|
+
return w === 0 ? null : out.subarray(0, w);
|
|
1686
|
+
},
|
|
1687
|
+
wsFrameDecodePackedInto(data, output) {
|
|
1688
|
+
const w = Number(wsFrameDecodePacked(data, lenOrView(data), output, lenOrView(output)));
|
|
1689
|
+
return w === 0 ? null : w;
|
|
1690
|
+
},
|
|
1691
|
+
multipartParsePacked(body, boundary) {
|
|
1692
|
+
return growExact((out) => Number(multipartParsePacked(body, lenOrView(body), boundary, lenOrView(boundary), out, lenOrView(out))), Math.min(body.length + boundary.length + 64, 64 * 1024), 128 * 1024 * 1024, "multipart parse: output buffer too small");
|
|
1693
|
+
},
|
|
1694
|
+
multipartParsePackedInto(body, boundary, output) {
|
|
1695
|
+
const w = Number(multipartParsePacked(body, lenOrView(body), boundary, lenOrView(boundary), output, lenOrView(output)));
|
|
1696
|
+
if (w === 0 || w > output.length) {
|
|
1697
|
+
throw new Error("multipart parse: output buffer too small or malformed body");
|
|
1698
|
+
}
|
|
1699
|
+
return w;
|
|
1700
|
+
},
|
|
1701
|
+
formParsePackedInto(input, output) {
|
|
1702
|
+
const w = Number(formParsePacked(input, lenOrView(input), output, lenOrView(output)));
|
|
1703
|
+
if (w === 0 || w > output.length) {
|
|
1704
|
+
throw new Error("form parse: output buffer too small");
|
|
1705
|
+
}
|
|
1706
|
+
return w;
|
|
1707
|
+
},
|
|
1708
|
+
jsonParsePacked(input) {
|
|
1709
|
+
return growExact((out) => Number(jsonParsePackedSym(input, lenOrView(input), out, lenOrView(out))), Math.min(input.length + (input.length >> 1), 16 * 1024 * 1024), Math.max(1024 * 1024, input.length * 16), "json parse packed: invalid JSON or output buffer too small");
|
|
1710
|
+
},
|
|
1711
|
+
parseMediaType(input) {
|
|
1712
|
+
let out = scratchFor(input.length * 2 + 128);
|
|
1713
|
+
let w = Number(parseMediaTypeSym(input, lenOrView(input), out, lenOrView(out)));
|
|
1714
|
+
if (w > out.length) {
|
|
1715
|
+
out = new Uint8Array(w);
|
|
1716
|
+
w = Number(parseMediaTypeSym(input, lenOrView(input), out, lenOrView(out)));
|
|
1717
|
+
}
|
|
1718
|
+
if (w === 0 || w > out.length) {
|
|
1719
|
+
throw new Error("media type parse: invalid media type or output buffer too small");
|
|
1720
|
+
}
|
|
1721
|
+
return out.subarray(0, w);
|
|
1722
|
+
},
|
|
1723
|
+
parseHttpDate(input) {
|
|
1724
|
+
const out = dateScratch;
|
|
1725
|
+
const w = Number(parseHttpDateSym(input, lenOrView(input), out, lenOrView(out)));
|
|
1726
|
+
if (w === 0) {
|
|
1727
|
+
throw new Error("http date parse: output buffer too small");
|
|
1728
|
+
}
|
|
1729
|
+
if (out[0] === 0)
|
|
1730
|
+
return null;
|
|
1731
|
+
return dateScratchView.getBigInt64(1, true);
|
|
1732
|
+
},
|
|
1733
|
+
parseAcceptEncoding(input) {
|
|
1734
|
+
let out = scratchFor(input.length * 2 + 128);
|
|
1735
|
+
let w = Number(parseAcceptEncodingSym(input, lenOrView(input), out, lenOrView(out)));
|
|
1736
|
+
if (w > out.length) {
|
|
1737
|
+
out = new Uint8Array(w);
|
|
1738
|
+
w = Number(parseAcceptEncodingSym(input, lenOrView(input), out, lenOrView(out)));
|
|
1739
|
+
}
|
|
1740
|
+
if (w === 0 || w > out.length) {
|
|
1741
|
+
throw new Error("accept encoding parse: output buffer too small");
|
|
1742
|
+
}
|
|
1743
|
+
return out.subarray(0, w);
|
|
1744
|
+
},
|
|
1745
|
+
urlEncodeQuery(input) {
|
|
1746
|
+
return urlEncodeQuerySym(input, lenOrView(input));
|
|
1747
|
+
},
|
|
1748
|
+
urlResolve(base, reference) {
|
|
1749
|
+
return urlResolveSym(base, lenOrView(base), reference, lenOrView(reference));
|
|
1750
|
+
},
|
|
1751
|
+
mimeFromExtension(ext) {
|
|
1752
|
+
return mimeFromExtensionSym(ext);
|
|
1753
|
+
},
|
|
1754
|
+
httpDateInto(secs, output) {
|
|
1755
|
+
const w = Number(httpDateIntoRaw(secs, output, lenOrView(output)));
|
|
1756
|
+
if (w === 0) {
|
|
1757
|
+
throw new Error("http date: output buffer too small or year out of range");
|
|
1758
|
+
}
|
|
1759
|
+
return w;
|
|
1760
|
+
},
|
|
1761
|
+
httpDate(secs) {
|
|
1762
|
+
const out = scratchFor(32);
|
|
1763
|
+
const w = Number(httpDateIntoRaw(secs ?? 0, out, lenOrView(out)));
|
|
1764
|
+
if (w !== 0)
|
|
1765
|
+
return decodeUtf8(out.subarray(0, w));
|
|
1766
|
+
return new Date((secs ?? 0) * 1000).toUTCString();
|
|
1767
|
+
},
|
|
1768
|
+
sseEncodeEvent(event, data, id, retry) {
|
|
1769
|
+
const ev = event === null ? EMPTY_VIEW : sseMemoEncode(sseMemoEvent, event);
|
|
1770
|
+
const idv = id === null ? EMPTY_VIEW : sseMemoEncode(sseMemoId, id);
|
|
1771
|
+
const flags = (event === null ? 0 : 1) | (id === null ? 0 : 2) | (retry === null ? 0 : 4);
|
|
1772
|
+
return growExact((out) => Number(sseEncodeIntoRaw(ev, lenOrView(ev), data, lenOrView(data), idv, lenOrView(idv), flags, retry ?? 0, out, lenOrView(out))), data.length + 64, 1 << 20, "sse encode: output buffer too small");
|
|
1773
|
+
},
|
|
1774
|
+
sseEncodeEventInto(event, data, id, retry, output) {
|
|
1775
|
+
const ev = event === null ? EMPTY_VIEW : sseMemoEncode(sseMemoEvent, event);
|
|
1776
|
+
const idv = id === null ? EMPTY_VIEW : sseMemoEncode(sseMemoId, id);
|
|
1777
|
+
const flags = (event === null ? 0 : 1) | (id === null ? 0 : 2) | (retry === null ? 0 : 4);
|
|
1778
|
+
const w = Number(sseEncodeIntoRaw(ev, lenOrView(ev), data, lenOrView(data), idv, lenOrView(idv), flags, retry ?? 0, output, lenOrView(output)));
|
|
1779
|
+
if (w === 0) {
|
|
1780
|
+
throw new Error("sse encode: invalid UTF-8 in event/id");
|
|
1781
|
+
}
|
|
1782
|
+
if (w > output.length) {
|
|
1783
|
+
throw new Error("sse encode: output buffer too small");
|
|
1784
|
+
}
|
|
1785
|
+
return w;
|
|
1786
|
+
}
|
|
1787
|
+
};
|
|
1788
|
+
}
|
|
1789
|
+
var sseMemoEvent, sseMemoId;
|
|
1790
|
+
var init_parse = __esm(() => {
|
|
1791
|
+
init_codec2();
|
|
1792
|
+
init_constants();
|
|
1793
|
+
init_util();
|
|
1794
|
+
sseMemoEvent = { str: null, bytes: EMPTY_VIEW };
|
|
1795
|
+
sseMemoId = { str: null, bytes: EMPTY_VIEW };
|
|
1796
|
+
});
|
|
1797
|
+
|
|
1798
|
+
// src/native/ffi/build/task.ts
|
|
1799
|
+
function buildTask(sym, ctx) {
|
|
1800
|
+
const { lenOrView } = ctx;
|
|
1801
|
+
const init = sym.castrum_task_init;
|
|
1802
|
+
const submit = sym.castrum_task_submit;
|
|
1803
|
+
const submitOut = sym.castrum_task_submit_out;
|
|
1804
|
+
const submitSlice = sym.castrum_task_submit_slice;
|
|
1805
|
+
const drain = sym.castrum_task_drain;
|
|
1806
|
+
const pending = sym.castrum_task_pending;
|
|
1807
|
+
const cancel = sym.castrum_task_cancel;
|
|
1808
|
+
const setDoorbell = sym.castrum_task_set_doorbell;
|
|
1809
|
+
const shutdown = sym.castrum_task_shutdown;
|
|
1810
|
+
const threads = sym.castrum_task_threads;
|
|
1811
|
+
return {
|
|
1812
|
+
taskInit: (n) => Number(init(n)),
|
|
1813
|
+
taskSubmit: (op, args, taskId) => Number(submit(op, args, lenOrView(args), taskId)),
|
|
1814
|
+
taskSubmitOut: (op, args, taskId, output) => Number(submitOut(op, args, lenOrView(args), taskId, output, lenOrView(output))),
|
|
1815
|
+
taskSubmitSlice: (op, hdr, data, taskId) => Number(submitSlice(op, hdr, lenOrView(hdr), data, lenOrView(data), taskId)),
|
|
1816
|
+
taskDrain: (output) => Number(drain(output, lenOrView(output))),
|
|
1817
|
+
taskPending: () => Number(pending()),
|
|
1818
|
+
taskCancel: (taskId) => Number(cancel(taskId)),
|
|
1819
|
+
taskSetDoorbell: (ptr) => Number(setDoorbell(ptr)),
|
|
1820
|
+
taskShutdown: () => Number(shutdown()),
|
|
1821
|
+
taskThreads: () => Number(threads())
|
|
1822
|
+
};
|
|
1823
|
+
}
|
|
1824
|
+
function selfTestTask(b) {
|
|
1825
|
+
try {
|
|
1826
|
+
if (typeof b.taskPending() !== "number")
|
|
1827
|
+
return false;
|
|
1828
|
+
if (typeof b.taskThreads() !== "number" || b.taskThreads() < 0)
|
|
1829
|
+
return false;
|
|
1830
|
+
if (b.taskSetDoorbell(0) !== 1)
|
|
1831
|
+
return false;
|
|
1832
|
+
if (typeof b.taskDrain(new Uint8Array(4)) !== "number")
|
|
1833
|
+
return false;
|
|
1834
|
+
if (typeof b.taskSubmitOut !== "function")
|
|
1835
|
+
return false;
|
|
1836
|
+
if (typeof b.taskSubmitSlice !== "function")
|
|
1837
|
+
return false;
|
|
1838
|
+
return true;
|
|
1839
|
+
} catch {
|
|
1840
|
+
return false;
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
// src/native/ffi/build.ts
|
|
1845
|
+
function build(sym, useBufferLength) {
|
|
1846
|
+
const oneArg = (raw, v) => useBufferLength ? raw(v, v) : raw(v, v.length);
|
|
1847
|
+
const lenOrView = (v) => useBufferLength ? v : v.length;
|
|
1848
|
+
let encodeScratch = new Uint8Array(0);
|
|
1849
|
+
const scratchFor = (size) => {
|
|
1850
|
+
if (encodeScratch.byteLength < size)
|
|
1851
|
+
encodeScratch = new Uint8Array(size);
|
|
1852
|
+
return encodeScratch;
|
|
1853
|
+
};
|
|
1854
|
+
const jsonSumOut = new Uint8Array(9);
|
|
1855
|
+
const jsonSumView = new DataView(jsonSumOut.buffer);
|
|
1856
|
+
const dateScratch = new Uint8Array(9);
|
|
1857
|
+
const dateScratchView = new DataView(dateScratch.buffer);
|
|
1858
|
+
const rateScratch = new Uint8Array(13);
|
|
1859
|
+
const rateScratchView = new DataView(rateScratch.buffer);
|
|
1860
|
+
const ctx = {
|
|
1861
|
+
useBufferLength,
|
|
1862
|
+
lenOrView,
|
|
1863
|
+
oneArg,
|
|
1864
|
+
scratchFor,
|
|
1865
|
+
jsonSumOut,
|
|
1866
|
+
jsonSumView,
|
|
1867
|
+
dateScratch,
|
|
1868
|
+
dateScratchView,
|
|
1869
|
+
rateScratch,
|
|
1870
|
+
rateScratchView
|
|
1871
|
+
};
|
|
1872
|
+
return {
|
|
1873
|
+
...buildCodecs(sym, ctx),
|
|
1874
|
+
...buildCompress(sym, ctx),
|
|
1875
|
+
...buildParse(sym, ctx),
|
|
1876
|
+
...buildInstances(sym, ctx),
|
|
1877
|
+
...buildMetrics(sym, ctx),
|
|
1878
|
+
...buildTask(sym, ctx)
|
|
1879
|
+
};
|
|
1880
|
+
}
|
|
1881
|
+
var init_build = __esm(() => {
|
|
1882
|
+
init_codecs();
|
|
1883
|
+
init_compress();
|
|
1884
|
+
init_instances();
|
|
1885
|
+
init_metrics();
|
|
1886
|
+
init_parse();
|
|
1887
|
+
});
|
|
1888
|
+
|
|
1889
|
+
// src/native/ffi/build/codecs-selftest.ts
|
|
1890
|
+
function selfTestCodecs(b) {
|
|
1891
|
+
const enc = { encode: encodeUtf8 };
|
|
1892
|
+
const dec = { decode: decodeUtf8 };
|
|
1893
|
+
if (b.crc32(enc.encode("123456789")) !== 3421780262)
|
|
1894
|
+
return false;
|
|
1895
|
+
if (b.fnv1a64(enc.encode("foobar")) !== 0x85944171f73967e8n)
|
|
1896
|
+
return false;
|
|
1897
|
+
if (b.xxh3(new Uint8Array(0)) !== 0x2d06800538d394c2n)
|
|
1898
|
+
return false;
|
|
1899
|
+
if (b.jsonValid(SELFTEST_JSON) !== true || b.jsonValid(enc.encode("{not json")) !== false) {
|
|
1900
|
+
return false;
|
|
1901
|
+
}
|
|
1902
|
+
if (!b.utf8Valid(enc.encode("héllo")) || b.utf8Valid(new Uint8Array([255, 254]))) {
|
|
1903
|
+
return false;
|
|
1904
|
+
}
|
|
1905
|
+
const hexOut = new Uint8Array(SELFTEST_HEX.length * 2);
|
|
1906
|
+
if (b.hexEncodeInto(SELFTEST_HEX, hexOut) !== 10 || dec.decode(hexOut) !== "68656c6c6f") {
|
|
1907
|
+
return false;
|
|
1908
|
+
}
|
|
1909
|
+
const urlInput = enc.encode("a b/c");
|
|
1910
|
+
const urlOut = new Uint8Array(9);
|
|
1911
|
+
if (b.urlEncodeInto(urlInput, urlOut) !== 9 || dec.decode(urlOut) !== "a%20b%2Fc") {
|
|
1912
|
+
return false;
|
|
1913
|
+
}
|
|
1914
|
+
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")) {
|
|
1915
|
+
return false;
|
|
1916
|
+
}
|
|
1917
|
+
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"))) {
|
|
1918
|
+
return false;
|
|
1919
|
+
}
|
|
1920
|
+
if (b.jsonSumIds(enc.encode(`[{"id":1},{"id":2}]`)) !== 3n)
|
|
1921
|
+
return false;
|
|
1922
|
+
if (b.jsonSumIds(enc.encode(`[{"id":0},{"id":0}]`)) !== 0n)
|
|
1923
|
+
return false;
|
|
1924
|
+
let sumInvalidThrew = false;
|
|
1925
|
+
try {
|
|
1926
|
+
b.jsonSumIds(enc.encode("nope"));
|
|
1927
|
+
} catch {
|
|
1928
|
+
sumInvalidThrew = true;
|
|
1929
|
+
}
|
|
1930
|
+
if (!sumInvalidThrew)
|
|
1931
|
+
return false;
|
|
1932
|
+
{
|
|
1933
|
+
const ids = enc.encode(`507f1f77bcf86cd799439011
|
|
1934
|
+
zz
|
|
1935
|
+
507F1F77BCF86CD799439012`);
|
|
1936
|
+
const tiny = new Uint8Array(2);
|
|
1937
|
+
const needed = b.hexValidateBatchInto(ids, 24, tiny);
|
|
1938
|
+
if (needed !== 3)
|
|
1939
|
+
return false;
|
|
1940
|
+
const out = new Uint8Array(needed);
|
|
1941
|
+
if (b.hexValidateBatchInto(ids, 24, out) !== 3)
|
|
1942
|
+
return false;
|
|
1943
|
+
if (out[0] !== 1 || out[1] !== 0 || out[2] !== 1)
|
|
1944
|
+
return false;
|
|
1945
|
+
let widthThrew = false;
|
|
1946
|
+
try {
|
|
1947
|
+
b.hexValidateBatchInto(ids, 0, new Uint8Array(3));
|
|
1948
|
+
} catch {
|
|
1949
|
+
widthThrew = true;
|
|
1950
|
+
}
|
|
1951
|
+
if (!widthThrew)
|
|
1952
|
+
return false;
|
|
1953
|
+
}
|
|
1954
|
+
{
|
|
1955
|
+
const out = new Uint8Array(64);
|
|
1956
|
+
const w = b.regexEscapeInto(enc.encode("a.c(x)"), out);
|
|
1957
|
+
if (w !== 9 || dec.decode(out.subarray(0, w)) !== "a\\.c\\(x\\)")
|
|
1958
|
+
return false;
|
|
1959
|
+
const plain = new Uint8Array(16);
|
|
1960
|
+
const wp = b.regexEscapeInto(enc.encode("hello"), plain);
|
|
1961
|
+
if (wp !== 5 || dec.decode(plain.subarray(0, wp)) !== "hello")
|
|
1962
|
+
return false;
|
|
1963
|
+
if (b.regexEscapeInto(enc.encode("a.b"), new Uint8Array(2)) !== 4)
|
|
1964
|
+
return false;
|
|
1965
|
+
if (b.regexEscapeStr("a.c(x)") !== "a\\.c\\(x\\)")
|
|
1966
|
+
return false;
|
|
1967
|
+
if (b.regexEscapeStr("plain text") !== "plain text")
|
|
1968
|
+
return false;
|
|
1969
|
+
}
|
|
1970
|
+
{
|
|
1971
|
+
const out = new Uint8Array(8);
|
|
1972
|
+
const w = b.hexValidateBatchStr(`507f1f77bcf86cd799439011
|
|
1973
|
+
zz`, 24, out);
|
|
1974
|
+
if (w !== 2 || out[0] !== 1 || out[1] !== 0)
|
|
1975
|
+
return false;
|
|
1976
|
+
}
|
|
1977
|
+
const hmacKey = new Uint8Array(20).fill(11);
|
|
1978
|
+
const hmacData = enc.encode("Hi There");
|
|
1979
|
+
const hmacSig = enc.encode("b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7");
|
|
1980
|
+
if (b.hmacSha256(hmacKey, hmacData) !== "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7") {
|
|
1981
|
+
return false;
|
|
1982
|
+
}
|
|
1983
|
+
if (!b.hmacSha256Verify(hmacKey, hmacData, hmacSig)) {
|
|
1984
|
+
return false;
|
|
1985
|
+
}
|
|
1986
|
+
const decoded = b.hexDecode(enc.encode("68656c6c6f"));
|
|
1987
|
+
if (dec.decode(decoded) !== "hello" || dec.decode(b.urlDecode(enc.encode("a%20b%2Fc"))) !== "a b/c") {
|
|
1988
|
+
return false;
|
|
1989
|
+
}
|
|
1990
|
+
if (b.wsAcceptKey("dGhlIHNhbXBsZSBub25jZQ==") !== "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=") {
|
|
1991
|
+
return false;
|
|
1992
|
+
}
|
|
1993
|
+
if (b.etag(SELFTEST_HEX).length !== 10 || b.etag(SELFTEST_HEX, true).length !== 12) {
|
|
1994
|
+
return false;
|
|
1995
|
+
}
|
|
1996
|
+
if (b.base64Encode(SELFTEST_HEX) !== "aGVsbG8=") {
|
|
1997
|
+
return false;
|
|
1998
|
+
}
|
|
1999
|
+
if (dec.decode(b.base64Decode(enc.encode("aGVsbG8="))) !== "hello") {
|
|
2000
|
+
return false;
|
|
2001
|
+
}
|
|
2002
|
+
const secret = enc.encode("s3cr3t-secret");
|
|
2003
|
+
const signed = b.signCookie(SELFTEST_HEX, secret);
|
|
2004
|
+
const verified = b.verifyCookie(enc.encode(signed), secret);
|
|
2005
|
+
if (verified === null || verified !== "hello") {
|
|
2006
|
+
return false;
|
|
2007
|
+
}
|
|
2008
|
+
if (b.verifyCookie(enc.encode("tampered.0000"), secret) !== null) {
|
|
2009
|
+
return false;
|
|
2010
|
+
}
|
|
2011
|
+
const csrfTokenStr = b.csrfToken(secret);
|
|
2012
|
+
if (csrfTokenStr.length !== 129 || !b.csrfVerify(enc.encode(csrfTokenStr), secret)) {
|
|
2013
|
+
return false;
|
|
2014
|
+
}
|
|
2015
|
+
const pw = enc.encode("correct horse battery staple");
|
|
2016
|
+
const salt = enc.encode("salty-salt-16b");
|
|
2017
|
+
const phc = b.passwordHash(pw, salt, 8, 1, 1, 16);
|
|
2018
|
+
if (phc.length === 0 || !b.passwordVerify(pw, enc.encode(phc))) {
|
|
2019
|
+
return false;
|
|
2020
|
+
}
|
|
2021
|
+
const bcryptPhc = b.passwordHashBcrypt(pw, 4);
|
|
2022
|
+
if (bcryptPhc.length === 0 || !b.passwordVerifyBcrypt(pw, bcryptPhc)) {
|
|
2023
|
+
return false;
|
|
2024
|
+
}
|
|
2025
|
+
const dk = b.pbkdf2Sha256(enc.encode("password"), enc.encode("salt"), 1, 32);
|
|
2026
|
+
if (b.hexEncode(dk) !== "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b") {
|
|
2027
|
+
return false;
|
|
2028
|
+
}
|
|
2029
|
+
const aeadKey = new Uint8Array(32).fill(66);
|
|
2030
|
+
const nonce = new Uint8Array(12).fill(7);
|
|
2031
|
+
const ct = b.aeadEncrypt(aeadKey, nonce, SELFTEST_HEX, 0);
|
|
2032
|
+
const pt = b.aeadDecrypt(aeadKey, nonce, ct, 0);
|
|
2033
|
+
if (pt === null || dec.decode(pt) !== "hello") {
|
|
2034
|
+
return false;
|
|
2035
|
+
}
|
|
2036
|
+
const rtOut = new Uint8Array(32);
|
|
2037
|
+
const rtW = b.randomTokenInto(16, rtOut);
|
|
2038
|
+
if (rtW !== 32 || !/^[0-9a-f]{32}$/.test(dec.decode(rtOut))) {
|
|
2039
|
+
return false;
|
|
2040
|
+
}
|
|
2041
|
+
try {
|
|
2042
|
+
b.randomTokenInto(16, new Uint8Array(8));
|
|
2043
|
+
return false;
|
|
2044
|
+
} catch {}
|
|
2045
|
+
const waOut = new Uint8Array(28);
|
|
2046
|
+
const waW = b.wsAcceptKeyInto(enc.encode("dGhlIHNhbXBsZSBub25jZQ=="), waOut);
|
|
2047
|
+
const waExpected = b.wsAcceptKey("dGhlIHNhbXBsZSBub25jZQ==");
|
|
2048
|
+
if (waW !== 28 || dec.decode(waOut) !== waExpected) {
|
|
2049
|
+
return false;
|
|
2050
|
+
}
|
|
2051
|
+
const etagData = enc.encode("hello");
|
|
2052
|
+
const etagOut = new Uint8Array(16);
|
|
2053
|
+
const etagW = b.etagInto(etagData, etagOut);
|
|
2054
|
+
if (etagW !== 10 || dec.decode(etagOut.subarray(0, etagW)) !== b.etag(etagData)) {
|
|
2055
|
+
return false;
|
|
2056
|
+
}
|
|
2057
|
+
const csrfOut = new Uint8Array(129);
|
|
2058
|
+
const csrfW = b.csrfTokenInto(enc.encode("csrf-secret"), csrfOut);
|
|
2059
|
+
if (csrfW !== 129 || csrfOut[64] !== 46) {
|
|
2060
|
+
return false;
|
|
2061
|
+
}
|
|
2062
|
+
const ckVal = enc.encode("session-value");
|
|
2063
|
+
const ckSec = enc.encode("s3cr3t-secret");
|
|
2064
|
+
const ckOut = new Uint8Array(256);
|
|
2065
|
+
const ckW = b.signCookieInto(ckVal, ckSec, ckOut);
|
|
2066
|
+
if (ckW !== ckVal.length + 65) {
|
|
2067
|
+
return false;
|
|
2068
|
+
}
|
|
2069
|
+
const ckVerifyOut = new Uint8Array(256);
|
|
2070
|
+
const ckV = b.verifyCookieInto(ckOut.subarray(0, ckW), ckSec, ckVerifyOut);
|
|
2071
|
+
if (ckV !== ckVal.length || dec.decode(ckVerifyOut.subarray(0, ckV)) !== "session-value") {
|
|
2072
|
+
return false;
|
|
2073
|
+
}
|
|
2074
|
+
if (b.urlEncode(enc.encode("a b/c")) !== "a%20b%2Fc") {
|
|
2075
|
+
return false;
|
|
2076
|
+
}
|
|
2077
|
+
const hdInto = new Uint8Array(8);
|
|
2078
|
+
if (b.hexDecodeInto(enc.encode("68656c6c6f"), hdInto) !== 5 || dec.decode(hdInto.subarray(0, 5)) !== "hello") {
|
|
2079
|
+
return false;
|
|
2080
|
+
}
|
|
2081
|
+
const udInto = new Uint8Array(16);
|
|
2082
|
+
if (b.urlDecodeInto(enc.encode("a%20b%2Fc"), udInto) !== 5 || dec.decode(udInto.subarray(0, 5)) !== "a b/c") {
|
|
2083
|
+
return false;
|
|
2084
|
+
}
|
|
2085
|
+
const b64Into = new Uint8Array(16);
|
|
2086
|
+
if (b.base64EncodeInto(SELFTEST_HEX, b64Into) !== 8 || dec.decode(b64Into.subarray(0, 8)) !== "aGVsbG8=") {
|
|
2087
|
+
return false;
|
|
2088
|
+
}
|
|
2089
|
+
const bdInto = new Uint8Array(8);
|
|
2090
|
+
if (b.base64DecodeInto(enc.encode("aGVsbG8="), bdInto) !== 5 || dec.decode(bdInto.subarray(0, 5)) !== "hello") {
|
|
2091
|
+
return false;
|
|
2092
|
+
}
|
|
2093
|
+
if (!/^[0-9a-f]{32}$/.test(b.randomToken(16))) {
|
|
2094
|
+
return false;
|
|
2095
|
+
}
|
|
2096
|
+
const hmacInto = new Uint8Array(64);
|
|
2097
|
+
if (b.hmacSha256Into(hmacKey, hmacData, hmacInto) !== 64 || dec.decode(hmacInto) !== "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7") {
|
|
2098
|
+
return false;
|
|
2099
|
+
}
|
|
2100
|
+
const ctInto = new Uint8Array(64);
|
|
2101
|
+
const ctW = b.aeadEncryptInto(aeadKey, nonce, SELFTEST_HEX, ctInto, 0);
|
|
2102
|
+
if (ctW === 0 || b.aeadDecrypt(aeadKey, nonce, ctInto.subarray(0, ctW), 0) === null) {
|
|
2103
|
+
return false;
|
|
2104
|
+
}
|
|
2105
|
+
return true;
|
|
2106
|
+
}
|
|
2107
|
+
var init_codecs_selftest = __esm(() => {
|
|
2108
|
+
init_codec2();
|
|
2109
|
+
init_constants();
|
|
2110
|
+
});
|
|
2111
|
+
|
|
2112
|
+
// src/native/ffi/build/instances-selftest.ts
|
|
2113
|
+
function selfTestInstances(b) {
|
|
2114
|
+
const enc = { encode: encodeUtf8 };
|
|
2115
|
+
const dec = { decode: decodeUtf8 };
|
|
2116
|
+
const layoutBuf = new Uint8Array(38 * 4);
|
|
2117
|
+
b.ingressLayout(layoutBuf);
|
|
2118
|
+
const layoutView = new DataView(layoutBuf.buffer, layoutBuf.byteOffset, layoutBuf.byteLength);
|
|
2119
|
+
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) {
|
|
2120
|
+
return false;
|
|
2121
|
+
}
|
|
2122
|
+
try {
|
|
2123
|
+
b.ingressHandlePacked(0, enc.encode("/"), null, new Uint8Array(64));
|
|
2124
|
+
return false;
|
|
2125
|
+
} catch {}
|
|
2126
|
+
try {
|
|
2127
|
+
b.ingressHandleComponents(0, 0, "/", "", enc.encode("rid"), new Uint8Array(2), null, new Uint8Array(64));
|
|
2128
|
+
return false;
|
|
2129
|
+
} catch {}
|
|
2130
|
+
const routeDesc = new Uint8Array(33);
|
|
2131
|
+
const rd = new DataView(routeDesc.buffer);
|
|
2132
|
+
rd.setUint32(0, 1380930900, true);
|
|
2133
|
+
rd.setUint32(4, 3, true);
|
|
2134
|
+
rd.setUint32(8, 2 * 1024 * 1024, true);
|
|
2135
|
+
rd.setUint32(12, 8192, true);
|
|
2136
|
+
rd.setUint32(16, 8192, true);
|
|
2137
|
+
rd.setUint32(20, 0, true);
|
|
2138
|
+
rd.setUint32(24, 1, true);
|
|
2139
|
+
routeDesc[28] = 0;
|
|
2140
|
+
rd.setUint32(29, 0, true);
|
|
2141
|
+
const routeHandle = b.routeCompile(routeDesc);
|
|
2142
|
+
if (routeHandle === 0) {
|
|
2143
|
+
return false;
|
|
2144
|
+
}
|
|
2145
|
+
const routeFrame = new Uint8Array(15);
|
|
2146
|
+
const rf = new DataView(routeFrame.buffer);
|
|
2147
|
+
rf.setUint32(0, 0, true);
|
|
2148
|
+
rf.setUint32(4, 3, true);
|
|
2149
|
+
routeFrame.set(enc.encode("a=1"), 8);
|
|
2150
|
+
rf.setUint32(11, 0, true);
|
|
2151
|
+
const routeOut = new Uint8Array(64);
|
|
2152
|
+
const routeW = b.routeRun(routeHandle, routeFrame, routeOut);
|
|
2153
|
+
if (routeW <= 8) {
|
|
2154
|
+
return false;
|
|
2155
|
+
}
|
|
2156
|
+
const rv = new DataView(routeOut.buffer);
|
|
2157
|
+
const rFlags = rv.getUint32(0, true);
|
|
2158
|
+
if ((rFlags & 1) === 0 || (rFlags & 4) === 0) {
|
|
2159
|
+
return false;
|
|
2160
|
+
}
|
|
2161
|
+
b.routeDestroy(routeHandle);
|
|
2162
|
+
if (b.conditionalIsNotModified(0, null, null) !== false) {
|
|
2163
|
+
return false;
|
|
2164
|
+
}
|
|
2165
|
+
if (b.mediaTypeMatcherMatches(0, enc.encode("x")) !== false)
|
|
2166
|
+
return false;
|
|
2167
|
+
if (b.acceptNegotiatorNegotiate(0, enc.encode("gzip")) !== null)
|
|
2168
|
+
return false;
|
|
2169
|
+
if (b.acceptNegotiatorNegotiateServer(0, enc.encode("gzip")) !== null)
|
|
2170
|
+
return false;
|
|
2171
|
+
if (b.schemaValidatorValidate(0, enc.encode("{}")) !== false)
|
|
2172
|
+
return false;
|
|
2173
|
+
if (b.jwtSignerVerify(0, enc.encode("a.b.c"), 0) !== null)
|
|
2174
|
+
return false;
|
|
2175
|
+
let phase6Threw = false;
|
|
2176
|
+
try {
|
|
2177
|
+
b.jwtSignerSign(0, enc.encode("{}"), 0);
|
|
2178
|
+
} catch {
|
|
2179
|
+
phase6Threw = true;
|
|
2180
|
+
}
|
|
2181
|
+
if (!phase6Threw)
|
|
2182
|
+
return false;
|
|
2183
|
+
phase6Threw = false;
|
|
2184
|
+
try {
|
|
2185
|
+
b.templateRender(0, enc.encode("{}"));
|
|
2186
|
+
} catch {
|
|
2187
|
+
phase6Threw = true;
|
|
2188
|
+
}
|
|
2189
|
+
if (!phase6Threw)
|
|
2190
|
+
return false;
|
|
2191
|
+
phase6Threw = false;
|
|
2192
|
+
try {
|
|
2193
|
+
b.rateLimiterCheck(0, "k", 0);
|
|
2194
|
+
} catch {
|
|
2195
|
+
phase6Threw = true;
|
|
2196
|
+
}
|
|
2197
|
+
if (!phase6Threw)
|
|
2198
|
+
return false;
|
|
2199
|
+
const jwtClaims = enc.encode('{"sub":"user-1"}');
|
|
2200
|
+
const jwtSecret2 = enc.encode("my-secret");
|
|
2201
|
+
const jwtOut = new Uint8Array(512);
|
|
2202
|
+
const jwtW = b.jwtSignBytesInto(jwtClaims, jwtSecret2, 0, 0, jwtOut);
|
|
2203
|
+
if (jwtW === 0 || dec.decode(jwtOut.subarray(0, jwtW)).split(".").length !== 3) {
|
|
2204
|
+
return false;
|
|
2205
|
+
}
|
|
2206
|
+
const jwtSecret = enc.encode("my-secret");
|
|
2207
|
+
const jwt = b.jwtSignBytes(enc.encode('{"sub":"user-1"}'), jwtSecret, 0, 0);
|
|
2208
|
+
const jwtStr = jwt;
|
|
2209
|
+
const segs = jwtStr.split(".");
|
|
2210
|
+
if (segs.length !== 3 || segs[0] === "" || segs[1] === "" || segs[2] === "") {
|
|
2211
|
+
return false;
|
|
2212
|
+
}
|
|
2213
|
+
const signingInput = enc.encode(`${segs[0]}.${segs[1]}`);
|
|
2214
|
+
const sigHex = b.hmacSha256(jwtSecret, signingInput);
|
|
2215
|
+
const sigBytes = b.base64Decode(enc.encode(segs[2] ?? ""), true, false);
|
|
2216
|
+
if (sigBytes === null || b.hexEncode(sigBytes) !== sigHex) {
|
|
2217
|
+
return false;
|
|
2218
|
+
}
|
|
2219
|
+
const vjwtSecret = enc.encode("verify-secret");
|
|
2220
|
+
const vjwt = b.jwtSignBytes(enc.encode('{"sub":"u-1"}'), vjwtSecret, 0, 0);
|
|
2221
|
+
const vjwtClaims = b.jwtVerify(enc.encode(vjwt), vjwtSecret, 0);
|
|
2222
|
+
if (vjwtClaims === null || !vjwtClaims.includes('"sub":"u-1"')) {
|
|
2223
|
+
return false;
|
|
2224
|
+
}
|
|
2225
|
+
if (b.jwtVerify(enc.encode("tampered.token.value"), vjwtSecret, 0) !== null) {
|
|
2226
|
+
return false;
|
|
2227
|
+
}
|
|
2228
|
+
const edKp = b.ed25519GenerateKeypair();
|
|
2229
|
+
const edMsg = enc.encode("ed25519 bind-time self-test");
|
|
2230
|
+
const edSig = b.ed25519Sign(edMsg, edKp.privateKey);
|
|
2231
|
+
if (edSig.byteLength !== 64 || !b.ed25519Verify(edMsg, edSig, edKp.publicKey)) {
|
|
2232
|
+
return false;
|
|
2233
|
+
}
|
|
2234
|
+
const edTampered = edSig.slice();
|
|
2235
|
+
edTampered[0] = (edTampered[0] ?? 0) ^ 255;
|
|
2236
|
+
if (b.ed25519Verify(edMsg, edTampered, edKp.publicKey)) {
|
|
2237
|
+
return false;
|
|
2238
|
+
}
|
|
2239
|
+
const edToken = b.jwtEdDSASign(enc.encode('{"sub":"ffi-self-test"}'), edKp.privateKey, 0, 0);
|
|
2240
|
+
if (edToken === null || edToken.split(".").length !== 3) {
|
|
2241
|
+
return false;
|
|
2242
|
+
}
|
|
2243
|
+
const edClaims = b.jwtEdDSAVerify(enc.encode(edToken), edKp.publicKey, 0);
|
|
2244
|
+
if (edClaims === null || !edClaims.includes('"sub":"ffi-self-test"')) {
|
|
2245
|
+
return false;
|
|
2246
|
+
}
|
|
2247
|
+
if (b.jwtEdDSAVerify(enc.encode("tampered.token.value"), edKp.publicKey, 0) !== null) {
|
|
2248
|
+
return false;
|
|
2249
|
+
}
|
|
2250
|
+
let urlBuilderThrew = false;
|
|
2251
|
+
try {
|
|
2252
|
+
b.urlBuilderResolve(0, enc.encode("g"));
|
|
2253
|
+
} catch {
|
|
2254
|
+
urlBuilderThrew = true;
|
|
2255
|
+
}
|
|
2256
|
+
if (!urlBuilderThrew) {
|
|
2257
|
+
return false;
|
|
2258
|
+
}
|
|
2259
|
+
if (b.queryValidate(0, "route=/a") !== false)
|
|
2260
|
+
return false;
|
|
2261
|
+
if (b.cookieValidate(0, "route=/a") !== false)
|
|
2262
|
+
return false;
|
|
2263
|
+
{
|
|
2264
|
+
const tok = b.sessionSeal("sess-9", '{"n":1}', 1234567, "sekrit");
|
|
2265
|
+
if (tok === null || !tok.includes(".") || !tok.startsWith('{"id":"sess-9"'))
|
|
2266
|
+
return false;
|
|
2267
|
+
const out = new Uint8Array(256);
|
|
2268
|
+
const w = b.sessionOpen(tok, "sekrit", out);
|
|
2269
|
+
if (w <= 13 || out[0] !== 1)
|
|
2270
|
+
return false;
|
|
2271
|
+
if (b.sessionOpen(tok, "wrong", out) !== 0)
|
|
2272
|
+
return false;
|
|
2273
|
+
const enc = new TextEncoder;
|
|
2274
|
+
const tokB = b.sessionSealBytes(enc.encode("sess-9"), enc.encode('{"n":1}'), 1234567, enc.encode("sekrit"));
|
|
2275
|
+
if (tokB === null || tokB !== tok)
|
|
2276
|
+
return false;
|
|
2277
|
+
const outB = new Uint8Array(256);
|
|
2278
|
+
const wB = b.sessionOpenBytes(enc.encode(tokB), enc.encode("sekrit"), outB);
|
|
2279
|
+
if (wB !== w || outB[0] !== 1)
|
|
2280
|
+
return false;
|
|
2281
|
+
if (b.sessionOpenBytes(enc.encode(tokB), enc.encode("wrong"), outB) !== 0)
|
|
2282
|
+
return false;
|
|
2283
|
+
if (b.sessionOpenBytes(enc.encode(tokB), enc.encode("sekrit"), outB.subarray(0, 4)) !== wB)
|
|
2284
|
+
return false;
|
|
2285
|
+
}
|
|
2286
|
+
let rlKeyThrew = false;
|
|
2287
|
+
try {
|
|
2288
|
+
b.rateLimiterCheckKey(0, 12345, 0);
|
|
2289
|
+
} catch {
|
|
2290
|
+
rlKeyThrew = true;
|
|
2291
|
+
}
|
|
2292
|
+
if (!rlKeyThrew) {
|
|
2293
|
+
return false;
|
|
1628
2294
|
}
|
|
2295
|
+
return true;
|
|
1629
2296
|
}
|
|
1630
|
-
var
|
|
1631
|
-
var init_metrics = __esm(() => {
|
|
2297
|
+
var init_instances_selftest = __esm(() => {
|
|
1632
2298
|
init_codec2();
|
|
1633
|
-
init_util();
|
|
1634
|
-
EMPTY = new Uint8Array(0);
|
|
1635
2299
|
});
|
|
1636
2300
|
|
|
1637
2301
|
// src/rust-ffi/scalar/json-packed.ts
|
|
@@ -1743,181 +2407,7 @@ var init_json_packed = __esm(() => {
|
|
|
1743
2407
|
init_runtime();
|
|
1744
2408
|
});
|
|
1745
2409
|
|
|
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;
|
|
1754
|
-
}
|
|
1755
|
-
function buildParse(sym, ctx) {
|
|
1756
|
-
const { lenOrView, scratchFor, dateScratch, dateScratchView } = ctx;
|
|
1757
|
-
const httpParsePacked = sym.castrum_http_parse_request_packed;
|
|
1758
|
-
const queryParsePacked = sym.castrum_query_parse_packed;
|
|
1759
|
-
const cookieParsePacked = sym.castrum_cookie_parse_packed;
|
|
1760
|
-
const httpDateIntoRaw = sym.castrum_http_date_into;
|
|
1761
|
-
const sseEncodeIntoRaw = sym.castrum_sse_encode_into;
|
|
1762
|
-
const jsonParsePackedSym = sym.castrum_json_parse_packed;
|
|
1763
|
-
const wsFrameDecodePacked = sym.castrum_ws_frame_decode_packed;
|
|
1764
|
-
const multipartParsePacked = sym.castrum_multipart_parse_packed;
|
|
1765
|
-
const formParsePacked = sym.castrum_form_parse_packed;
|
|
1766
|
-
const wsFrameEncode = sym.castrum_ws_frame_encode;
|
|
1767
|
-
const parseMediaTypeSym = sym.castrum_parse_media_type;
|
|
1768
|
-
const parseHttpDateSym = sym.castrum_parse_http_date;
|
|
1769
|
-
const parseAcceptEncodingSym = sym.castrum_parse_accept_encoding;
|
|
1770
|
-
const urlEncodeQuerySym = sym.castrum_url_encode_query;
|
|
1771
|
-
const urlResolveSym = sym.castrum_url_resolve;
|
|
1772
|
-
const mimeFromExtensionSym = sym.castrum_mime_from_extension;
|
|
1773
|
-
return {
|
|
1774
|
-
httpParseRequestPackedInto(input, output) {
|
|
1775
|
-
const w = Number(httpParsePacked(input, lenOrView(input), output, lenOrView(output)));
|
|
1776
|
-
if (w === 0 && input.length !== 0) {
|
|
1777
|
-
throw new Error("http parse: output buffer too small or malformed request");
|
|
1778
|
-
}
|
|
1779
|
-
return w;
|
|
1780
|
-
},
|
|
1781
|
-
queryParsePackedInto(input, output) {
|
|
1782
|
-
const w = Number(queryParsePacked(input, lenOrView(input), output, lenOrView(output)));
|
|
1783
|
-
if (w === 0 || w > output.length) {
|
|
1784
|
-
throw new Error("query parse: output buffer too small");
|
|
1785
|
-
}
|
|
1786
|
-
return w;
|
|
1787
|
-
},
|
|
1788
|
-
cookieParsePackedInto(input, output) {
|
|
1789
|
-
const w = Number(cookieParsePacked(input, lenOrView(input), output, lenOrView(output)));
|
|
1790
|
-
if (w === 0 || w > output.length) {
|
|
1791
|
-
throw new Error("cookie parse: output buffer too small");
|
|
1792
|
-
}
|
|
1793
|
-
return w;
|
|
1794
|
-
},
|
|
1795
|
-
wsFrameEncode(opcode, payload, mask, fin) {
|
|
1796
|
-
const out = allocOut(payload.length + 14);
|
|
1797
|
-
const w = Number(wsFrameEncode(opcode, payload, lenOrView(payload), flag(mask), flag(fin), out, lenOrView(out)));
|
|
1798
|
-
if (w === 0) {
|
|
1799
|
-
throw new Error("ws frame encode: output buffer too small");
|
|
1800
|
-
}
|
|
1801
|
-
return out.subarray(0, w);
|
|
1802
|
-
},
|
|
1803
|
-
wsFrameEncodeInto(opcode, payload, mask, fin, output) {
|
|
1804
|
-
const need = payload.length + 14;
|
|
1805
|
-
if (output.length < need) {
|
|
1806
|
-
throw new Error("ws frame encode: output buffer too small");
|
|
1807
|
-
}
|
|
1808
|
-
const w = Number(wsFrameEncode(opcode, payload, lenOrView(payload), flag(mask), flag(fin), output, lenOrView(output)));
|
|
1809
|
-
if (w === 0) {
|
|
1810
|
-
throw new Error("ws frame encode: output buffer too small");
|
|
1811
|
-
}
|
|
1812
|
-
return w;
|
|
1813
|
-
},
|
|
1814
|
-
wsFrameDecodePacked(data) {
|
|
1815
|
-
const out = new Uint8Array(data.length + 6);
|
|
1816
|
-
const w = Number(wsFrameDecodePacked(data, lenOrView(data), out, lenOrView(out)));
|
|
1817
|
-
return w === 0 ? null : out.subarray(0, w);
|
|
1818
|
-
},
|
|
1819
|
-
wsFrameDecodePackedInto(data, output) {
|
|
1820
|
-
const w = Number(wsFrameDecodePacked(data, lenOrView(data), output, lenOrView(output)));
|
|
1821
|
-
return w === 0 ? null : w;
|
|
1822
|
-
},
|
|
1823
|
-
multipartParsePacked(body, boundary) {
|
|
1824
|
-
return growExact((out) => Number(multipartParsePacked(body, lenOrView(body), boundary, lenOrView(boundary), out, lenOrView(out))), Math.min(body.length + boundary.length + 64, 64 * 1024), 128 * 1024 * 1024, "multipart parse: output buffer too small");
|
|
1825
|
-
},
|
|
1826
|
-
multipartParsePackedInto(body, boundary, output) {
|
|
1827
|
-
const w = Number(multipartParsePacked(body, lenOrView(body), boundary, lenOrView(boundary), output, lenOrView(output)));
|
|
1828
|
-
if (w === 0 || w > output.length) {
|
|
1829
|
-
throw new Error("multipart parse: output buffer too small or malformed body");
|
|
1830
|
-
}
|
|
1831
|
-
return w;
|
|
1832
|
-
},
|
|
1833
|
-
formParsePackedInto(input, output) {
|
|
1834
|
-
const w = Number(formParsePacked(input, lenOrView(input), output, lenOrView(output)));
|
|
1835
|
-
if (w === 0 || w > output.length) {
|
|
1836
|
-
throw new Error("form parse: output buffer too small");
|
|
1837
|
-
}
|
|
1838
|
-
return w;
|
|
1839
|
-
},
|
|
1840
|
-
jsonParsePacked(input) {
|
|
1841
|
-
return growExact((out) => Number(jsonParsePackedSym(input, lenOrView(input), out, lenOrView(out))), Math.min(input.length + (input.length >> 1), 16 * 1024 * 1024), Math.max(1024 * 1024, input.length * 16), "json parse packed: invalid JSON or output buffer too small");
|
|
1842
|
-
},
|
|
1843
|
-
parseMediaType(input) {
|
|
1844
|
-
let out = scratchFor(input.length * 2 + 128);
|
|
1845
|
-
let w = Number(parseMediaTypeSym(input, lenOrView(input), out, lenOrView(out)));
|
|
1846
|
-
if (w > out.length) {
|
|
1847
|
-
out = new Uint8Array(w);
|
|
1848
|
-
w = Number(parseMediaTypeSym(input, lenOrView(input), out, lenOrView(out)));
|
|
1849
|
-
}
|
|
1850
|
-
if (w === 0 || w > out.length) {
|
|
1851
|
-
throw new Error("media type parse: invalid media type or output buffer too small");
|
|
1852
|
-
}
|
|
1853
|
-
return out.subarray(0, w);
|
|
1854
|
-
},
|
|
1855
|
-
parseHttpDate(input) {
|
|
1856
|
-
const out = dateScratch;
|
|
1857
|
-
const w = Number(parseHttpDateSym(input, lenOrView(input), out, lenOrView(out)));
|
|
1858
|
-
if (w === 0) {
|
|
1859
|
-
throw new Error("http date parse: output buffer too small");
|
|
1860
|
-
}
|
|
1861
|
-
if (out[0] === 0)
|
|
1862
|
-
return null;
|
|
1863
|
-
return dateScratchView.getBigInt64(1, true);
|
|
1864
|
-
},
|
|
1865
|
-
parseAcceptEncoding(input) {
|
|
1866
|
-
let out = scratchFor(input.length * 2 + 128);
|
|
1867
|
-
let w = Number(parseAcceptEncodingSym(input, lenOrView(input), out, lenOrView(out)));
|
|
1868
|
-
if (w > out.length) {
|
|
1869
|
-
out = new Uint8Array(w);
|
|
1870
|
-
w = Number(parseAcceptEncodingSym(input, lenOrView(input), out, lenOrView(out)));
|
|
1871
|
-
}
|
|
1872
|
-
if (w === 0 || w > out.length) {
|
|
1873
|
-
throw new Error("accept encoding parse: output buffer too small");
|
|
1874
|
-
}
|
|
1875
|
-
return out.subarray(0, w);
|
|
1876
|
-
},
|
|
1877
|
-
urlEncodeQuery(input) {
|
|
1878
|
-
return urlEncodeQuerySym(input, lenOrView(input));
|
|
1879
|
-
},
|
|
1880
|
-
urlResolve(base, reference) {
|
|
1881
|
-
return urlResolveSym(base, lenOrView(base), reference, lenOrView(reference));
|
|
1882
|
-
},
|
|
1883
|
-
mimeFromExtension(ext) {
|
|
1884
|
-
return mimeFromExtensionSym(ext);
|
|
1885
|
-
},
|
|
1886
|
-
httpDateInto(secs, output) {
|
|
1887
|
-
const w = Number(httpDateIntoRaw(secs, output, lenOrView(output)));
|
|
1888
|
-
if (w === 0) {
|
|
1889
|
-
throw new Error("http date: output buffer too small or year out of range");
|
|
1890
|
-
}
|
|
1891
|
-
return w;
|
|
1892
|
-
},
|
|
1893
|
-
httpDate(secs) {
|
|
1894
|
-
const out = scratchFor(32);
|
|
1895
|
-
const w = Number(httpDateIntoRaw(secs ?? 0, out, lenOrView(out)));
|
|
1896
|
-
if (w !== 0)
|
|
1897
|
-
return decodeUtf8(out.subarray(0, w));
|
|
1898
|
-
return new Date((secs ?? 0) * 1000).toUTCString();
|
|
1899
|
-
},
|
|
1900
|
-
sseEncodeEvent(event, data, id, retry) {
|
|
1901
|
-
const ev = event === null ? EMPTY_VIEW : sseMemoEncode(sseMemoEvent, event);
|
|
1902
|
-
const idv = id === null ? EMPTY_VIEW : sseMemoEncode(sseMemoId, id);
|
|
1903
|
-
const flags = (event === null ? 0 : 1) | (id === null ? 0 : 2) | (retry === null ? 0 : 4);
|
|
1904
|
-
return growExact((out) => Number(sseEncodeIntoRaw(ev, lenOrView(ev), data, lenOrView(data), idv, lenOrView(idv), flags, retry ?? 0, out, lenOrView(out))), data.length + 64, 1 << 20, "sse encode: output buffer too small");
|
|
1905
|
-
},
|
|
1906
|
-
sseEncodeEventInto(event, data, id, retry, output) {
|
|
1907
|
-
const ev = event === null ? EMPTY_VIEW : sseMemoEncode(sseMemoEvent, event);
|
|
1908
|
-
const idv = id === null ? EMPTY_VIEW : sseMemoEncode(sseMemoId, id);
|
|
1909
|
-
const flags = (event === null ? 0 : 1) | (id === null ? 0 : 2) | (retry === null ? 0 : 4);
|
|
1910
|
-
const w = Number(sseEncodeIntoRaw(ev, lenOrView(ev), data, lenOrView(data), idv, lenOrView(idv), flags, retry ?? 0, output, lenOrView(output)));
|
|
1911
|
-
if (w === 0) {
|
|
1912
|
-
throw new Error("sse encode: invalid UTF-8 in event/id");
|
|
1913
|
-
}
|
|
1914
|
-
if (w > output.length) {
|
|
1915
|
-
throw new Error("sse encode: output buffer too small");
|
|
1916
|
-
}
|
|
1917
|
-
return w;
|
|
1918
|
-
}
|
|
1919
|
-
};
|
|
1920
|
-
}
|
|
2410
|
+
// src/native/ffi/build/parse-selftest.ts
|
|
1921
2411
|
function selfTestParse(b) {
|
|
1922
2412
|
const enc = { encode: encodeUtf8 };
|
|
1923
2413
|
const dec = { decode: decodeUtf8 };
|
|
@@ -2087,114 +2577,19 @@ data: hello
|
|
|
2087
2577
|
if (b.mimeFromExtension("nope") !== "application/octet-stream") {
|
|
2088
2578
|
return false;
|
|
2089
2579
|
}
|
|
2090
|
-
if (b.httpDate(784111777) !== "Sun, 06 Nov 1994 08:49:37 GMT") {
|
|
2091
|
-
return false;
|
|
2092
|
-
}
|
|
2093
|
-
const frameInto = new Uint8Array(64);
|
|
2094
|
-
if (b.wsFrameEncodeInto(1, SELFTEST_HEX, false, true, frameInto) === 0 || frameInto[0] !== 129) {
|
|
2095
|
-
return false;
|
|
2096
|
-
}
|
|
2097
|
-
return true;
|
|
2098
|
-
}
|
|
2099
|
-
var sseMemoEvent, sseMemoId;
|
|
2100
|
-
var init_parse = __esm(() => {
|
|
2101
|
-
init_json_packed();
|
|
2102
|
-
init_codec2();
|
|
2103
|
-
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
|
-
};
|
|
2580
|
+
if (b.httpDate(784111777) !== "Sun, 06 Nov 1994 08:49:37 GMT") {
|
|
2581
|
+
return false;
|
|
2582
|
+
}
|
|
2583
|
+
const frameInto = new Uint8Array(64);
|
|
2584
|
+
if (b.wsFrameEncodeInto(1, SELFTEST_HEX, false, true, frameInto) === 0 || frameInto[0] !== 129) {
|
|
2585
|
+
return false;
|
|
2586
|
+
}
|
|
2587
|
+
return true;
|
|
2191
2588
|
}
|
|
2192
|
-
var
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
init_metrics();
|
|
2197
|
-
init_parse();
|
|
2589
|
+
var init_parse_selftest = __esm(() => {
|
|
2590
|
+
init_json_packed();
|
|
2591
|
+
init_codec2();
|
|
2592
|
+
init_constants();
|
|
2198
2593
|
});
|
|
2199
2594
|
|
|
2200
2595
|
// src/native/ffi/selftest.ts
|
|
@@ -2202,11 +2597,11 @@ function selfTest(b) {
|
|
|
2202
2597
|
return selfTestCodecs(b) && selfTestCompress(b) && selfTestParse(b) && selfTestInstances(b) && selfTestMetrics(b) && selfTestTask(b);
|
|
2203
2598
|
}
|
|
2204
2599
|
var init_selftest = __esm(() => {
|
|
2205
|
-
|
|
2600
|
+
init_codecs_selftest();
|
|
2206
2601
|
init_compress();
|
|
2207
|
-
|
|
2602
|
+
init_instances_selftest();
|
|
2208
2603
|
init_metrics();
|
|
2209
|
-
|
|
2604
|
+
init_parse_selftest();
|
|
2210
2605
|
});
|
|
2211
2606
|
|
|
2212
2607
|
// src/native/loader.ts
|
|
@@ -2366,6 +2761,12 @@ function getBunFFI() {
|
|
|
2366
2761
|
cached = bind();
|
|
2367
2762
|
return cached;
|
|
2368
2763
|
}
|
|
2764
|
+
function ffiAddonPath() {
|
|
2765
|
+
if (cached === undefined) {
|
|
2766
|
+
getBunFFI();
|
|
2767
|
+
}
|
|
2768
|
+
return boundAddonPath;
|
|
2769
|
+
}
|
|
2369
2770
|
function probeBufferLength(dlopen, path) {
|
|
2370
2771
|
try {
|
|
2371
2772
|
const { symbols, close } = dlopen(path, {
|
|
@@ -2399,358 +2800,7 @@ function bind(forcedPath, tried = []) {
|
|
|
2399
2800
|
const { dlopen } = __require("bun:ffi");
|
|
2400
2801
|
const useBufferLength = probeBufferLength(dlopen, path);
|
|
2401
2802
|
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
|
-
});
|
|
2803
|
+
const { symbols } = dlopen(path, buildFFISymbolMap(useBufferLength));
|
|
2754
2804
|
const bindings = build(symbols, useBufferLength);
|
|
2755
2805
|
if (!selfTest(bindings)) {
|
|
2756
2806
|
throw new Error(`bun:ffi bind-time self-test failed on ${path}`);
|
|
@@ -3425,24 +3475,53 @@ var init_wire = __esm(() => {
|
|
|
3425
3475
|
});
|
|
3426
3476
|
|
|
3427
3477
|
// src/shared/packed/parsers.ts
|
|
3428
|
-
function
|
|
3429
|
-
const
|
|
3478
|
+
function scratchFor(kind, input) {
|
|
3479
|
+
const need = input.length * 9 + 16;
|
|
3480
|
+
let s = ffiCaches[kind];
|
|
3481
|
+
if (s === null || s.length < need) {
|
|
3482
|
+
s = new Uint8Array(need);
|
|
3483
|
+
ffiCaches[kind] = s;
|
|
3484
|
+
}
|
|
3485
|
+
return s;
|
|
3486
|
+
}
|
|
3487
|
+
function parsePackedInto(kind, input) {
|
|
3488
|
+
const f = getBunFFI();
|
|
3489
|
+
if (!f)
|
|
3490
|
+
return null;
|
|
3491
|
+
const out = scratchFor(kind, input);
|
|
3492
|
+
const w = kind === "query" ? f.queryParsePackedInto(input, out) : kind === "cookie" ? f.cookieParsePackedInto(input, out) : f.formParsePackedInto(input, out);
|
|
3493
|
+
if (w === 0 || w > out.length)
|
|
3494
|
+
return null;
|
|
3495
|
+
return pairsToObject(readPairsPacked(out.subarray(0, w)));
|
|
3496
|
+
}
|
|
3497
|
+
function parseVia(kind, input) {
|
|
3498
|
+
const fast = parsePackedInto(kind, input);
|
|
3499
|
+
if (fast)
|
|
3500
|
+
return fast;
|
|
3501
|
+
const packed = kind === "query" ? addon2.queryParsePacked(input) : kind === "cookie" ? addon2.cookieParsePacked(input) : addon2.formParsePacked(input);
|
|
3430
3502
|
return pairsToObject(readPairsPacked(packed));
|
|
3431
3503
|
}
|
|
3504
|
+
function parseQueryString(query) {
|
|
3505
|
+
return parseVia("query", encoder.encode(query));
|
|
3506
|
+
}
|
|
3432
3507
|
function parseCookieHeader(header) {
|
|
3433
|
-
|
|
3434
|
-
return pairsToObject(readPairsPacked(packed));
|
|
3508
|
+
return parseVia("cookie", encoder.encode(header));
|
|
3435
3509
|
}
|
|
3436
3510
|
function parseFormBody(body) {
|
|
3437
|
-
|
|
3438
|
-
return pairsToObject(readPairsPacked(packed));
|
|
3511
|
+
return parseVia("form", body);
|
|
3439
3512
|
}
|
|
3440
|
-
var addon2;
|
|
3513
|
+
var addon2, ffiCaches;
|
|
3441
3514
|
var init_parsers = __esm(() => {
|
|
3515
|
+
init_ffi();
|
|
3442
3516
|
init_native();
|
|
3443
3517
|
init_bytes();
|
|
3444
3518
|
init_wire();
|
|
3445
3519
|
addon2 = lazyAddon(getAddon);
|
|
3520
|
+
ffiCaches = {
|
|
3521
|
+
query: null,
|
|
3522
|
+
cookie: null,
|
|
3523
|
+
form: null
|
|
3524
|
+
};
|
|
3446
3525
|
});
|
|
3447
3526
|
|
|
3448
3527
|
// src/shared/packed/schema.ts
|
|
@@ -3507,6 +3586,11 @@ function asNumber(value) {
|
|
|
3507
3586
|
}
|
|
3508
3587
|
return 0;
|
|
3509
3588
|
}
|
|
3589
|
+
function assertNonEmptySecret(secret, op) {
|
|
3590
|
+
if (secret.byteLength === 0) {
|
|
3591
|
+
throw new Error(`${op}: secret must not be empty`);
|
|
3592
|
+
}
|
|
3593
|
+
}
|
|
3510
3594
|
function normalizeExt(ext) {
|
|
3511
3595
|
let s;
|
|
3512
3596
|
try {
|
|
@@ -3674,17 +3758,29 @@ function buildBatch(ctx) {
|
|
|
3674
3758
|
gzipDecompress: (items, maxDecompressed) => via(ctx, "gzipDecompressBatchPacked", unpackByteResults, [maxDecompressed ?? null])(items),
|
|
3675
3759
|
brotliCompress: (items, quality) => via(ctx, "brotliCompressBatchPacked", unpackByteResults, [quality ?? null])(items),
|
|
3676
3760
|
brotliDecompress: (items, maxDecompressed) => via(ctx, "brotliDecompressBatchPacked", unpackByteResults, [maxDecompressed ?? null])(items),
|
|
3677
|
-
jwtVerify: (tokens, secret, nowSeconds) =>
|
|
3678
|
-
|
|
3679
|
-
|
|
3761
|
+
jwtVerify: (tokens, secret, nowSeconds) => {
|
|
3762
|
+
assertNonEmptySecret(secret, "batch.jwtVerify");
|
|
3763
|
+
return via(ctx, "jwtVerifyBatchPacked", unpackBitset, [secret, nowSeconds])(tokens);
|
|
3764
|
+
},
|
|
3765
|
+
hmacSha256: (items, key) => {
|
|
3766
|
+
assertNonEmptySecret(key, "batch.hmacSha256");
|
|
3767
|
+
return via(ctx, "hmacSha256BatchPacked", unpackByteResults, [key])(items);
|
|
3768
|
+
},
|
|
3769
|
+
hmacSha256Verify: (items, sigs, key) => {
|
|
3770
|
+
assertNonEmptySecret(key, "batch.hmacSha256Verify");
|
|
3771
|
+
return via2(ctx, "hmacSha256VerifyBatchPacked", unpackBitset, [key])(items, sigs);
|
|
3772
|
+
},
|
|
3680
3773
|
passwordVerify: (items, phcs) => via2(ctx, "passwordVerifyBatchPacked", unpackBitset)(items, phcs),
|
|
3681
3774
|
urlResolve: (bases, references) => via2(ctx, "urlResolveBatchPacked", unpackByteResults)(bases, references),
|
|
3682
3775
|
templateRender: (source, contexts) => via(ctx, "templateRenderBatchPacked", unpackByteResults, [source])(contexts),
|
|
3683
|
-
jwtSign: (items, secret, ttlSeconds, nowSeconds) =>
|
|
3684
|
-
secret,
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3776
|
+
jwtSign: (items, secret, ttlSeconds, nowSeconds) => {
|
|
3777
|
+
assertNonEmptySecret(secret, "batch.jwtSign");
|
|
3778
|
+
return via(ctx, "jwtSignBatchPacked", unpackByteResults, [
|
|
3779
|
+
secret,
|
|
3780
|
+
ttlSeconds ?? null,
|
|
3781
|
+
nowSeconds ?? Math.floor(Date.now() / 1000)
|
|
3782
|
+
])(items);
|
|
3783
|
+
},
|
|
3688
3784
|
sseEncode: (items, event, id, retry) => via(ctx, "sseEncodeBatchPacked", unpackByteResults, [
|
|
3689
3785
|
event ?? null,
|
|
3690
3786
|
id ?? null,
|
|
@@ -3698,6 +3794,7 @@ function buildBatch(ctx) {
|
|
|
3698
3794
|
var init_build2 = __esm(() => {
|
|
3699
3795
|
init_packed();
|
|
3700
3796
|
init_context();
|
|
3797
|
+
init_options();
|
|
3701
3798
|
});
|
|
3702
3799
|
|
|
3703
3800
|
// src/rust-ffi/batch/index.ts
|
|
@@ -3959,18 +4056,22 @@ function buildCrypto(ctx) {
|
|
|
3959
4056
|
return writeInto("verify cookie", output, value);
|
|
3960
4057
|
},
|
|
3961
4058
|
csrfToken(secret) {
|
|
4059
|
+
assertNonEmptySecret(secret, "csrfToken");
|
|
3962
4060
|
return resolveNative(ctx, "csrfToken")(secret);
|
|
3963
4061
|
},
|
|
3964
4062
|
csrfTokenInto(secret, output) {
|
|
4063
|
+
assertNonEmptySecret(secret, "csrfTokenInto");
|
|
3965
4064
|
const f = ffi();
|
|
3966
4065
|
if (f)
|
|
3967
4066
|
return f.csrfTokenInto(secret, output);
|
|
3968
4067
|
return writeInto("csrf token", output, addon.csrfToken(secret));
|
|
3969
4068
|
},
|
|
3970
4069
|
csrfVerify(token, secret) {
|
|
4070
|
+
assertNonEmptySecret(secret, "csrfVerify");
|
|
3971
4071
|
return resolveNative(ctx, "csrfVerify")(token, secret);
|
|
3972
4072
|
},
|
|
3973
4073
|
jwtSign(claims, secret, ttlSeconds, nowSeconds) {
|
|
4074
|
+
assertNonEmptySecret(secret, "jwtSign");
|
|
3974
4075
|
const f = ffi();
|
|
3975
4076
|
if (f) {
|
|
3976
4077
|
const token = f.jwtSignBytes(encoder.encode(JSON.stringify(claims)), secret, ttlSeconds ?? 0, nowSeconds ?? Math.floor(Date.now() / 1000));
|
|
@@ -3979,6 +4080,7 @@ function buildCrypto(ctx) {
|
|
|
3979
4080
|
return addon.jwtSign(claims, secret, ttlSeconds ?? null, nowSeconds ?? Math.floor(Date.now() / 1000));
|
|
3980
4081
|
},
|
|
3981
4082
|
jwtSignBytes(claimsJson, secret, ttlSeconds, nowSeconds) {
|
|
4083
|
+
assertNonEmptySecret(secret, "jwtSignBytes");
|
|
3982
4084
|
const f = ffi();
|
|
3983
4085
|
if (f) {
|
|
3984
4086
|
return f.jwtSignBytes(claimsJson, secret, ttlSeconds ?? 0, nowSeconds ?? Math.floor(Date.now() / 1000));
|
|
@@ -3986,6 +4088,7 @@ function buildCrypto(ctx) {
|
|
|
3986
4088
|
return addon.jwtSignBytes(claimsJson, secret, ttlSeconds ?? null, nowSeconds ?? Math.floor(Date.now() / 1000));
|
|
3987
4089
|
},
|
|
3988
4090
|
jwtSignBytesInto(claimsJson, secret, output, ttlSeconds, nowSeconds) {
|
|
4091
|
+
assertNonEmptySecret(secret, "jwtSignBytesInto");
|
|
3989
4092
|
const f = ffi();
|
|
3990
4093
|
if (f) {
|
|
3991
4094
|
return f.jwtSignBytesInto(claimsJson, secret, ttlSeconds ?? 0, nowSeconds ?? Math.floor(Date.now() / 1000), output);
|
|
@@ -3993,6 +4096,7 @@ function buildCrypto(ctx) {
|
|
|
3993
4096
|
return writeInto("jwt sign", output, addon.jwtSignBytes(claimsJson, secret, ttlSeconds ?? null, nowSeconds ?? Math.floor(Date.now() / 1000)));
|
|
3994
4097
|
},
|
|
3995
4098
|
jwtVerify(token, secret, nowSeconds) {
|
|
4099
|
+
assertNonEmptySecret(secret, "jwtVerify");
|
|
3996
4100
|
const f = ffi();
|
|
3997
4101
|
if (f) {
|
|
3998
4102
|
const claims = f.jwtVerify(token, secret, nowSeconds ?? Math.floor(Date.now() / 1000));
|
|
@@ -4053,9 +4157,17 @@ function buildCrypto(ctx) {
|
|
|
4053
4157
|
var init_crypto = __esm(() => {
|
|
4054
4158
|
init_bytes();
|
|
4055
4159
|
init_context();
|
|
4160
|
+
init_options();
|
|
4056
4161
|
});
|
|
4057
4162
|
|
|
4058
4163
|
// src/rust-ffi/scalar/factories.ts
|
|
4164
|
+
function handlePtr(inner) {
|
|
4165
|
+
const v = inner ?? 0n;
|
|
4166
|
+
if (v < 0n || v > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
4167
|
+
throw new Error("castrum: native handle exceeds Number.MAX_SAFE_INTEGER");
|
|
4168
|
+
}
|
|
4169
|
+
return Number(v);
|
|
4170
|
+
}
|
|
4059
4171
|
function ffiHmacSigner(key, ffi) {
|
|
4060
4172
|
return {
|
|
4061
4173
|
sign(data) {
|
|
@@ -4236,47 +4348,55 @@ function ffiFormParser(ffi) {
|
|
|
4236
4348
|
};
|
|
4237
4349
|
}
|
|
4238
4350
|
function ffiMetricsRegistry(ffi) {
|
|
4239
|
-
|
|
4351
|
+
let handle = ffi.metricsCreate();
|
|
4352
|
+
const live = () => {
|
|
4353
|
+
if (handle === 0)
|
|
4354
|
+
throw new Error("metrics registry: already destroyed");
|
|
4355
|
+
return handle;
|
|
4356
|
+
};
|
|
4240
4357
|
return {
|
|
4241
4358
|
counter(name, labelKeys) {
|
|
4242
|
-
return ffi.metricsCounter(
|
|
4359
|
+
return ffi.metricsCounter(live(), name, (labelKeys ?? []).join("\x1F"));
|
|
4243
4360
|
},
|
|
4244
4361
|
gauge(name, labelKeys) {
|
|
4245
|
-
return ffi.metricsGauge(
|
|
4362
|
+
return ffi.metricsGauge(live(), name, (labelKeys ?? []).join("\x1F"));
|
|
4246
4363
|
},
|
|
4247
4364
|
histogram(name, labelKeys, buckets) {
|
|
4248
|
-
return ffi.metricsHistogram(
|
|
4365
|
+
return ffi.metricsHistogram(live(), name, (labelKeys ?? []).join("\x1F"), (buckets ?? []).join(","));
|
|
4249
4366
|
},
|
|
4250
4367
|
record(series, values, amount) {
|
|
4251
4368
|
const joined = (values ?? []).join("\x1F");
|
|
4252
|
-
if (!ffi.metricsRecordStr(
|
|
4369
|
+
if (!ffi.metricsRecordStr(live(), series, joined, amount ?? 1)) {
|
|
4253
4370
|
throw new Error("metrics record: unknown series / arity mismatch / invalid amount");
|
|
4254
4371
|
}
|
|
4255
4372
|
},
|
|
4256
4373
|
gaugeSet(series, values, value) {
|
|
4257
4374
|
const joined = (values ?? []).join("\x1F");
|
|
4258
|
-
if (!ffi.metricsGaugeSetStr(
|
|
4375
|
+
if (!ffi.metricsGaugeSetStr(live(), series, joined, value)) {
|
|
4259
4376
|
throw new Error("metrics gauge set: unknown series / arity mismatch");
|
|
4260
4377
|
}
|
|
4261
4378
|
},
|
|
4262
4379
|
render() {
|
|
4263
4380
|
let out = new Uint8Array(8192);
|
|
4264
|
-
let w = ffi.metricsRender(
|
|
4381
|
+
let w = ffi.metricsRender(live(), out);
|
|
4265
4382
|
if (w > out.length) {
|
|
4266
4383
|
out = new Uint8Array(w);
|
|
4267
|
-
w = ffi.metricsRender(
|
|
4384
|
+
w = ffi.metricsRender(live(), out);
|
|
4268
4385
|
}
|
|
4269
4386
|
return decodeUtf8(out.subarray(0, w));
|
|
4270
4387
|
},
|
|
4271
4388
|
destroy() {
|
|
4272
|
-
|
|
4389
|
+
if (handle !== 0) {
|
|
4390
|
+
ffi.metricsDestroy(handle);
|
|
4391
|
+
handle = 0;
|
|
4392
|
+
}
|
|
4273
4393
|
},
|
|
4274
4394
|
snapshot() {
|
|
4275
4395
|
let out = new Uint8Array(4096);
|
|
4276
|
-
let w = ffi.metricsSnapshot(
|
|
4396
|
+
let w = ffi.metricsSnapshot(live(), out);
|
|
4277
4397
|
if (w > out.length) {
|
|
4278
4398
|
out = new Uint8Array(w);
|
|
4279
|
-
w = ffi.metricsSnapshot(
|
|
4399
|
+
w = ffi.metricsSnapshot(live(), out);
|
|
4280
4400
|
}
|
|
4281
4401
|
return out.subarray(0, w);
|
|
4282
4402
|
}
|
|
@@ -4290,11 +4410,12 @@ function buildFactories(ctx) {
|
|
|
4290
4410
|
const ffi = transport.ffi;
|
|
4291
4411
|
if (ffi) {
|
|
4292
4412
|
const napi = new addon.SchemaValidator(schema);
|
|
4293
|
-
return ffiSchemaValidator(napi,
|
|
4413
|
+
return ffiSchemaValidator(napi, handlePtr(napi.innerPtr?.()), ffi);
|
|
4294
4414
|
}
|
|
4295
4415
|
return new addon.SchemaValidator(schema);
|
|
4296
4416
|
},
|
|
4297
4417
|
createHmacSigner(key) {
|
|
4418
|
+
assertNonEmptySecret(key, "createHmacSigner");
|
|
4298
4419
|
const ffi = transport.ffi;
|
|
4299
4420
|
if (ffi)
|
|
4300
4421
|
return ffiHmacSigner(key, ffi);
|
|
@@ -4304,7 +4425,7 @@ function buildFactories(ctx) {
|
|
|
4304
4425
|
const ffi = transport.ffi;
|
|
4305
4426
|
if (ffi) {
|
|
4306
4427
|
const napi = new addon.TemplateRenderer(source);
|
|
4307
|
-
return ffiTemplateRenderer(napi,
|
|
4428
|
+
return ffiTemplateRenderer(napi, handlePtr(napi.innerPtr?.()), ffi);
|
|
4308
4429
|
}
|
|
4309
4430
|
return new addon.TemplateRenderer(source);
|
|
4310
4431
|
},
|
|
@@ -4321,7 +4442,7 @@ function buildFactories(ctx) {
|
|
|
4321
4442
|
const ffi = transport.ffi;
|
|
4322
4443
|
if (ffi) {
|
|
4323
4444
|
const napi = new addon.ConditionalRequest(etagValue, lastModifiedSecs ?? undefined);
|
|
4324
|
-
return ffiConditionalRequest(napi,
|
|
4445
|
+
return ffiConditionalRequest(napi, handlePtr(napi.innerPtr?.()), ffi);
|
|
4325
4446
|
}
|
|
4326
4447
|
return new addon.ConditionalRequest(etagValue, lastModifiedSecs ?? undefined);
|
|
4327
4448
|
},
|
|
@@ -4329,7 +4450,7 @@ function buildFactories(ctx) {
|
|
|
4329
4450
|
const ffi = transport.ffi;
|
|
4330
4451
|
if (ffi) {
|
|
4331
4452
|
const napi = new addon.AcceptNegotiator(supported);
|
|
4332
|
-
return ffiAcceptNegotiator(napi,
|
|
4453
|
+
return ffiAcceptNegotiator(napi, handlePtr(napi.innerPtr?.()), ffi);
|
|
4333
4454
|
}
|
|
4334
4455
|
return new addon.AcceptNegotiator(supported);
|
|
4335
4456
|
},
|
|
@@ -4340,12 +4461,14 @@ function buildFactories(ctx) {
|
|
|
4340
4461
|
return new addon.Base64Codec(urlSafe ?? undefined, padding ?? undefined);
|
|
4341
4462
|
},
|
|
4342
4463
|
createCookieSigner(secret) {
|
|
4464
|
+
assertNonEmptySecret(secret, "createCookieSigner");
|
|
4343
4465
|
const ffi = transport.ffi;
|
|
4344
4466
|
if (ffi)
|
|
4345
4467
|
return ffiCookieSigner(secret, ffi);
|
|
4346
4468
|
return new addon.CookieSigner(secret);
|
|
4347
4469
|
},
|
|
4348
4470
|
createCsrfProtector(secret) {
|
|
4471
|
+
assertNonEmptySecret(secret, "createCsrfProtector");
|
|
4349
4472
|
const ffi = transport.ffi;
|
|
4350
4473
|
if (ffi)
|
|
4351
4474
|
return ffiCsrfProtector(secret, ffi);
|
|
@@ -4355,15 +4478,16 @@ function buildFactories(ctx) {
|
|
|
4355
4478
|
const ffi = transport.ffi;
|
|
4356
4479
|
if (ffi) {
|
|
4357
4480
|
const napi = new addon.UrlBuilder(base);
|
|
4358
|
-
return ffiUrlBuilder(napi,
|
|
4481
|
+
return ffiUrlBuilder(napi, handlePtr(napi.innerPtr?.()), ffi);
|
|
4359
4482
|
}
|
|
4360
4483
|
return new addon.UrlBuilder(base);
|
|
4361
4484
|
},
|
|
4362
4485
|
createJwtSigner(secret, ttlSeconds) {
|
|
4486
|
+
assertNonEmptySecret(secret, "createJwtSigner");
|
|
4363
4487
|
const ffi = transport.ffi;
|
|
4364
4488
|
if (ffi) {
|
|
4365
4489
|
const napi = new addon.JwtSigner(secret, ttlSeconds ?? undefined);
|
|
4366
|
-
return ffiJwtSigner(napi,
|
|
4490
|
+
return ffiJwtSigner(napi, handlePtr(napi.innerPtr?.()), ffi);
|
|
4367
4491
|
}
|
|
4368
4492
|
return new addon.JwtSigner(secret, ttlSeconds ?? undefined);
|
|
4369
4493
|
},
|
|
@@ -4383,7 +4507,7 @@ function buildFactories(ctx) {
|
|
|
4383
4507
|
const ffi = transport.ffi;
|
|
4384
4508
|
if (ffi) {
|
|
4385
4509
|
const napi = new addon.MediaTypeMatcher(expected);
|
|
4386
|
-
return ffiMediaTypeMatcher(napi,
|
|
4510
|
+
return ffiMediaTypeMatcher(napi, handlePtr(napi.innerPtr?.()), ffi);
|
|
4387
4511
|
}
|
|
4388
4512
|
return new addon.MediaTypeMatcher(expected);
|
|
4389
4513
|
},
|
|
@@ -4391,7 +4515,7 @@ function buildFactories(ctx) {
|
|
|
4391
4515
|
const ffi = transport.ffi;
|
|
4392
4516
|
if (ffi) {
|
|
4393
4517
|
const napi = new addon.RateLimiter(limit, windowMs, maxEntries ?? undefined);
|
|
4394
|
-
return ffiRateLimiter(napi,
|
|
4518
|
+
return ffiRateLimiter(napi, handlePtr(napi.innerPtr?.()), ffi);
|
|
4395
4519
|
}
|
|
4396
4520
|
return new addon.RateLimiter(limit, windowMs, maxEntries ?? undefined);
|
|
4397
4521
|
},
|
|
@@ -4492,37 +4616,63 @@ function ensureValidUtf8(bytes, ffi) {
|
|
|
4492
4616
|
function u32LE(b, off) {
|
|
4493
4617
|
return ((b[off] ?? 0) | (b[off + 1] ?? 0) << 8 | (b[off + 2] ?? 0) << 16 | (b[off + 3] ?? 0) << 24) >>> 0;
|
|
4494
4618
|
}
|
|
4619
|
+
function keyBytesEqual(b, off, lit) {
|
|
4620
|
+
for (let i = 0;i < lit.length; i++) {
|
|
4621
|
+
if ((b[off + i] ?? 0) !== (lit[i] ?? 0))
|
|
4622
|
+
return false;
|
|
4623
|
+
}
|
|
4624
|
+
return true;
|
|
4625
|
+
}
|
|
4495
4626
|
function unpackMediaType(packed) {
|
|
4627
|
+
const view = Buffer.from(packed.buffer, packed.byteOffset, packed.byteLength);
|
|
4496
4628
|
let off = 0;
|
|
4497
4629
|
const mtLen = u32LE(packed, off);
|
|
4498
4630
|
off += 4;
|
|
4499
|
-
const mediaType =
|
|
4631
|
+
const mediaType = decodeUtf8RangeView(view, off, off + mtLen);
|
|
4500
4632
|
off += mtLen;
|
|
4501
4633
|
let charset = null;
|
|
4502
4634
|
const csLen = u32LE(packed, off);
|
|
4503
4635
|
off += 4;
|
|
4504
4636
|
if (csLen !== 4294967295) {
|
|
4505
|
-
charset =
|
|
4637
|
+
charset = decodeUtf8RangeView(view, off, off + csLen);
|
|
4506
4638
|
off += csLen;
|
|
4507
4639
|
}
|
|
4508
4640
|
let boundary = null;
|
|
4509
4641
|
const bLen = u32LE(packed, off);
|
|
4510
4642
|
off += 4;
|
|
4511
4643
|
if (bLen !== 4294967295) {
|
|
4512
|
-
boundary =
|
|
4644
|
+
boundary = decodeUtf8RangeView(view, off, off + bLen);
|
|
4513
4645
|
off += bLen;
|
|
4514
4646
|
}
|
|
4515
4647
|
const count = u32LE(packed, off);
|
|
4516
4648
|
off += 4;
|
|
4517
4649
|
const params = {};
|
|
4650
|
+
let charsetTaken = charset === null;
|
|
4651
|
+
let boundaryTaken = boundary === null;
|
|
4518
4652
|
for (let i = 0;i < count; i++) {
|
|
4519
4653
|
const kLen = u32LE(packed, off);
|
|
4520
4654
|
off += 4;
|
|
4521
|
-
|
|
4655
|
+
let key;
|
|
4656
|
+
if (kLen === 7 && keyBytesEqual(packed, off, CHARSET_KEY_BYTES)) {
|
|
4657
|
+
key = "charset";
|
|
4658
|
+
} else if (kLen === 8 && keyBytesEqual(packed, off, BOUNDARY_KEY_BYTES)) {
|
|
4659
|
+
key = "boundary";
|
|
4660
|
+
} else {
|
|
4661
|
+
key = decodeUtf8RangeView(view, off, off + kLen);
|
|
4662
|
+
}
|
|
4522
4663
|
off += kLen;
|
|
4523
4664
|
const vLen = u32LE(packed, off);
|
|
4524
4665
|
off += 4;
|
|
4525
|
-
|
|
4666
|
+
let val;
|
|
4667
|
+
if (!charsetTaken && key === "charset" && charset !== null) {
|
|
4668
|
+
val = charset;
|
|
4669
|
+
charsetTaken = true;
|
|
4670
|
+
} else if (!boundaryTaken && key === "boundary" && boundary !== null) {
|
|
4671
|
+
val = boundary;
|
|
4672
|
+
boundaryTaken = true;
|
|
4673
|
+
} else {
|
|
4674
|
+
val = decodeUtf8RangeView(view, off, off + vLen);
|
|
4675
|
+
}
|
|
4526
4676
|
off += vLen;
|
|
4527
4677
|
params[key] = val;
|
|
4528
4678
|
}
|
|
@@ -4653,7 +4803,7 @@ function buildHttp(ctx) {
|
|
|
4653
4803
|
queryParsePacked(input) {
|
|
4654
4804
|
const f = ffi();
|
|
4655
4805
|
if (f) {
|
|
4656
|
-
const out = new Uint8Array(input.length *
|
|
4806
|
+
const out = new Uint8Array(input.length * 5 + 8);
|
|
4657
4807
|
const w = f.queryParsePackedInto(input, out);
|
|
4658
4808
|
return out.subarray(0, w);
|
|
4659
4809
|
}
|
|
@@ -4665,7 +4815,7 @@ function buildHttp(ctx) {
|
|
|
4665
4815
|
cookieParsePacked(input) {
|
|
4666
4816
|
const f = ffi();
|
|
4667
4817
|
if (f) {
|
|
4668
|
-
const out = new Uint8Array(input.length *
|
|
4818
|
+
const out = new Uint8Array(input.length * 5 + 8);
|
|
4669
4819
|
const w = f.cookieParsePackedInto(input, out);
|
|
4670
4820
|
return out.subarray(0, w);
|
|
4671
4821
|
}
|
|
@@ -4677,7 +4827,7 @@ function buildHttp(ctx) {
|
|
|
4677
4827
|
formParsePacked(input) {
|
|
4678
4828
|
const f = ffi();
|
|
4679
4829
|
if (f) {
|
|
4680
|
-
const out = new Uint8Array(input.length *
|
|
4830
|
+
const out = new Uint8Array(input.length * 5 + 8);
|
|
4681
4831
|
const w = f.formParsePackedInto(input, out);
|
|
4682
4832
|
return out.subarray(0, w);
|
|
4683
4833
|
}
|
|
@@ -4749,13 +4899,15 @@ function buildHttp(ctx) {
|
|
|
4749
4899
|
}
|
|
4750
4900
|
};
|
|
4751
4901
|
}
|
|
4752
|
-
var WS_ACCEPT_SCRATCH, f32Bits, f32BitsU32;
|
|
4902
|
+
var WS_ACCEPT_SCRATCH, CHARSET_KEY_BYTES, BOUNDARY_KEY_BYTES, f32Bits, f32BitsU32;
|
|
4753
4903
|
var init_http = __esm(() => {
|
|
4754
4904
|
init_bytes();
|
|
4755
4905
|
init_codec2();
|
|
4756
4906
|
init_packed();
|
|
4757
4907
|
init_context();
|
|
4758
4908
|
WS_ACCEPT_SCRATCH = new Uint8Array(64);
|
|
4909
|
+
CHARSET_KEY_BYTES = new Uint8Array([99, 104, 97, 114, 115, 101, 116]);
|
|
4910
|
+
BOUNDARY_KEY_BYTES = new Uint8Array([98, 111, 117, 110, 100, 97, 114, 121]);
|
|
4759
4911
|
f32Bits = new Float32Array(1);
|
|
4760
4912
|
f32BitsU32 = new Uint32Array(f32Bits.buffer);
|
|
4761
4913
|
});
|
|
@@ -4835,6 +4987,7 @@ function buildPayload(ctx) {
|
|
|
4835
4987
|
const { builtins, transport } = ctx.runtime;
|
|
4836
4988
|
const HAS = { gzipCompress: builtins.has("gzipCompress") };
|
|
4837
4989
|
const ffi = memoizeFfi(transport);
|
|
4990
|
+
let SCRATCH = null;
|
|
4838
4991
|
return {
|
|
4839
4992
|
gzipCompress(data, level) {
|
|
4840
4993
|
if (HAS.gzipCompress)
|
|
@@ -4888,8 +5041,20 @@ function buildPayload(ctx) {
|
|
|
4888
5041
|
},
|
|
4889
5042
|
multipartParse(body, boundary) {
|
|
4890
5043
|
const f = ffi();
|
|
4891
|
-
if (f)
|
|
4892
|
-
|
|
5044
|
+
if (f) {
|
|
5045
|
+
const need = body.length + boundary.length + 64;
|
|
5046
|
+
if (need > 64 * 1024)
|
|
5047
|
+
return unpackMultipart(f.multipartParsePacked(body, boundary));
|
|
5048
|
+
if (!SCRATCH || SCRATCH.length < need)
|
|
5049
|
+
SCRATCH = new Uint8Array(need);
|
|
5050
|
+
let w;
|
|
5051
|
+
try {
|
|
5052
|
+
w = f.multipartParsePackedInto(body, boundary, SCRATCH);
|
|
5053
|
+
} catch {
|
|
5054
|
+
return unpackMultipart(f.multipartParsePacked(body, boundary));
|
|
5055
|
+
}
|
|
5056
|
+
return unpackMultipart(SCRATCH.subarray(0, w));
|
|
5057
|
+
}
|
|
4893
5058
|
return addon.multipartParse(body, boundary).map((p) => ({
|
|
4894
5059
|
name: p.name,
|
|
4895
5060
|
filename: p.filename ?? null,
|
|
@@ -5318,10 +5483,13 @@ function createNativeRoute(plan = {}) {
|
|
|
5318
5483
|
const parseQuery = plan.parseQuery === true;
|
|
5319
5484
|
const parseCookies = plan.parseCookies === true;
|
|
5320
5485
|
const bunFFI = getBunFFI();
|
|
5321
|
-
|
|
5322
|
-
|
|
5486
|
+
let ffiHandle = bunFFI !== null ? compileFfi(bunFFI, descriptor) : 0;
|
|
5487
|
+
let napiRoute = bunFFI === null || ffiHandle === 0 ? compileNapi(descriptor) : null;
|
|
5323
5488
|
let out = new Uint8Array(256);
|
|
5324
5489
|
const runFrame = (frame) => {
|
|
5490
|
+
if (ffiHandle === 0 && napiRoute === null) {
|
|
5491
|
+
throw new Error("native route: already destroyed");
|
|
5492
|
+
}
|
|
5325
5493
|
let written;
|
|
5326
5494
|
if (ffiHandle !== 0 && bunFFI !== null) {
|
|
5327
5495
|
written = bunFFI.routeRun(ffiHandle, frame, out);
|
|
@@ -5354,7 +5522,10 @@ function createNativeRoute(plan = {}) {
|
|
|
5354
5522
|
destroy: () => {
|
|
5355
5523
|
if (ffiHandle !== 0 && bunFFI !== null) {
|
|
5356
5524
|
bunFFI.routeDestroy(ffiHandle);
|
|
5525
|
+
ffiHandle = 0;
|
|
5357
5526
|
}
|
|
5527
|
+
napiRoute?.destroy?.();
|
|
5528
|
+
napiRoute = null;
|
|
5358
5529
|
}
|
|
5359
5530
|
};
|
|
5360
5531
|
}
|
|
@@ -5378,6 +5549,17 @@ function compileNapi(descriptor) {
|
|
|
5378
5549
|
}
|
|
5379
5550
|
}
|
|
5380
5551
|
|
|
5552
|
+
// src/ingress/headers/memoized-headers.ts
|
|
5553
|
+
var CACHE = new WeakMap;
|
|
5554
|
+
function memoizedHeaders(entries) {
|
|
5555
|
+
const existing = CACHE.get(entries);
|
|
5556
|
+
if (existing !== undefined)
|
|
5557
|
+
return existing;
|
|
5558
|
+
const built = new Headers(entries);
|
|
5559
|
+
CACHE.set(entries, built);
|
|
5560
|
+
return built;
|
|
5561
|
+
}
|
|
5562
|
+
|
|
5381
5563
|
// src/ingress/shared.ts
|
|
5382
5564
|
var DEFAULT_MAX_BODY_BYTES = 1048576;
|
|
5383
5565
|
var DEFAULT_FAST_OUTPUT_BUFFER_SIZE = 262144;
|
|
@@ -5420,10 +5602,9 @@ function resolveIp(req, srv, opts) {
|
|
|
5420
5602
|
return opts.getIp ? opts.getIp(req, srv) : undefined;
|
|
5421
5603
|
}
|
|
5422
5604
|
function buildSuccessInit(ingress, result, ctx, status = 200) {
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
};
|
|
5605
|
+
const rateResetSecs = result.rateResetMs > 0 ? secondsFromMs(result.rateResetMs) : undefined;
|
|
5606
|
+
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));
|
|
5607
|
+
return { status, headers };
|
|
5427
5608
|
}
|
|
5428
5609
|
function runBaked(ingress, opts, respond) {
|
|
5429
5610
|
return (req, srv) => ingress.run(req, resolveIp(req, srv, opts), null, respond);
|
|
@@ -5802,6 +5983,18 @@ function rateLimitedBody(retryAfterMs) {
|
|
|
5802
5983
|
}
|
|
5803
5984
|
|
|
5804
5985
|
// src/ingress/routes/echo.ts
|
|
5986
|
+
var SAFE_ECHO_CONTENT_TYPES = new Set([
|
|
5987
|
+
"application/json",
|
|
5988
|
+
"application/octet-stream",
|
|
5989
|
+
"text/plain"
|
|
5990
|
+
]);
|
|
5991
|
+
function echoMediaTypeOf(contentType) {
|
|
5992
|
+
const semi = contentType.indexOf(";");
|
|
5993
|
+
return (semi >= 0 ? contentType.slice(0, semi) : contentType).trim().toLowerCase();
|
|
5994
|
+
}
|
|
5995
|
+
function safeEchoContentType(contentType) {
|
|
5996
|
+
return SAFE_ECHO_CONTENT_TYPES.has(echoMediaTypeOf(contentType)) ? contentType : "application/octet-stream";
|
|
5997
|
+
}
|
|
5805
5998
|
function echoHandler(ingress, opts = {}) {
|
|
5806
5999
|
const maxBodyBytes = opts.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
|
|
5807
6000
|
const bodyTimeoutMs = opts.bodyTimeoutMs ?? DEFAULT_BODY_TIMEOUT_MS;
|
|
@@ -5822,32 +6015,39 @@ function echoHandler(ingress, opts = {}) {
|
|
|
5822
6015
|
if (prep.terminal)
|
|
5823
6016
|
return prep.terminal;
|
|
5824
6017
|
const baseHeaders = prep.headers ?? [];
|
|
5825
|
-
const requestedContentType = req.headers.get("content-type") ?? "application/octet-stream";
|
|
6018
|
+
const requestedContentType = safeEchoContentType(req.headers.get("content-type") ?? "application/octet-stream");
|
|
6019
|
+
const withEchoHeaders = (contentType) => {
|
|
6020
|
+
const headers = ingress.withContentType(baseHeaders, contentType);
|
|
6021
|
+
if (!headers.some(([name]) => name.toLowerCase() === "x-content-type-options")) {
|
|
6022
|
+
headers.push(["x-content-type-options", "nosniff"]);
|
|
6023
|
+
}
|
|
6024
|
+
return headers;
|
|
6025
|
+
};
|
|
5826
6026
|
const contentLengthHeader = req.headers.get("content-length");
|
|
5827
6027
|
const contentLength = contentLengthHeader === null ? NaN : Number(contentLengthHeader);
|
|
5828
6028
|
if (Number.isFinite(contentLength)) {
|
|
5829
6029
|
if (contentLength > maxBodyBytes) {
|
|
5830
6030
|
return new Response(ERROR_BODIES.body_too_large, {
|
|
5831
6031
|
status: 413,
|
|
5832
|
-
headers:
|
|
6032
|
+
headers: withEchoHeaders("application/json")
|
|
5833
6033
|
});
|
|
5834
6034
|
}
|
|
5835
6035
|
if (contentLength <= 0 || req.body === null) {
|
|
5836
6036
|
return new Response(null, {
|
|
5837
6037
|
status: 200,
|
|
5838
|
-
headers:
|
|
6038
|
+
headers: withEchoHeaders(requestedContentType)
|
|
5839
6039
|
});
|
|
5840
6040
|
}
|
|
5841
6041
|
return new Response(req.body, {
|
|
5842
6042
|
status: 200,
|
|
5843
|
-
headers:
|
|
6043
|
+
headers: withEchoHeaders(requestedContentType)
|
|
5844
6044
|
});
|
|
5845
6045
|
}
|
|
5846
6046
|
try {
|
|
5847
6047
|
const bodyBytes = await readBodyWithLimit(req, maxBodyBytes, true, bodyTimeoutMs);
|
|
5848
6048
|
return new Response(bodyBytes.byteLength > 0 ? bodyBytes : null, {
|
|
5849
6049
|
status: 200,
|
|
5850
|
-
headers:
|
|
6050
|
+
headers: withEchoHeaders(requestedContentType)
|
|
5851
6051
|
});
|
|
5852
6052
|
} catch (err) {
|
|
5853
6053
|
const code = err?.code;
|
|
@@ -5855,7 +6055,7 @@ function echoHandler(ingress, opts = {}) {
|
|
|
5855
6055
|
const isTimeout = code === "REQUEST_TIMEOUT";
|
|
5856
6056
|
return new Response(isTooLarge ? ERROR_BODIES.body_too_large : isTimeout ? ERROR_BODIES.request_timeout : ERROR_BODIES.bad_request, {
|
|
5857
6057
|
status: isTooLarge ? 413 : isTimeout ? 408 : 400,
|
|
5858
|
-
headers:
|
|
6058
|
+
headers: withEchoHeaders("application/json")
|
|
5859
6059
|
});
|
|
5860
6060
|
}
|
|
5861
6061
|
};
|
|
@@ -5893,6 +6093,11 @@ function defaultJsonValid(bytes) {
|
|
|
5893
6093
|
return false;
|
|
5894
6094
|
}
|
|
5895
6095
|
}
|
|
6096
|
+
function isJsonContentType(contentType) {
|
|
6097
|
+
const semi = contentType.indexOf(";");
|
|
6098
|
+
const mediaType = (semi >= 0 ? contentType.slice(0, semi) : contentType).trim().toLowerCase();
|
|
6099
|
+
return mediaType === "application/json" || mediaType.endsWith("+json");
|
|
6100
|
+
}
|
|
5896
6101
|
function jsonWriteHandler(ingress, opts = {}) {
|
|
5897
6102
|
const maxBodyBytes = opts.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
|
|
5898
6103
|
const fallback = opts.fallback ?? ingress;
|
|
@@ -5902,13 +6107,8 @@ function jsonWriteHandler(ingress, opts = {}) {
|
|
|
5902
6107
|
return async (req, srv) => {
|
|
5903
6108
|
const ip = resolveIp(req, srv, opts);
|
|
5904
6109
|
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
|
-
});
|
|
6110
|
+
if (!isJsonContentType(contentType)) {
|
|
6111
|
+
return fallback.run(req, ip, null, (result, ctx) => fallback.errorResponse(req, result, 415, "unsupported_media_type", "Content-Type must be application/json", ctx));
|
|
5912
6112
|
}
|
|
5913
6113
|
let bodyBytes;
|
|
5914
6114
|
try {
|
|
@@ -6093,7 +6293,7 @@ function safeTerminalStatus(r) {
|
|
|
6093
6293
|
}
|
|
6094
6294
|
|
|
6095
6295
|
// src/ingress/routes/responder.ts
|
|
6096
|
-
var
|
|
6296
|
+
var IGNEX_SECURITY_HEADERS = [
|
|
6097
6297
|
["x-frame-options", "DENY"],
|
|
6098
6298
|
["x-content-type-options", "nosniff"],
|
|
6099
6299
|
["referrer-policy", "no-referrer"]
|
|
@@ -6101,7 +6301,7 @@ var IGNGEX_SECURITY_HEADERS = [
|
|
|
6101
6301
|
function buildIgngexTerminal(result, _ctx) {
|
|
6102
6302
|
const preflightAllowed = result.isPreflight && result.corsAllowed;
|
|
6103
6303
|
if (preflightAllowed) {
|
|
6104
|
-
return new Response(null, { status: 204, headers:
|
|
6304
|
+
return new Response(null, { status: 204, headers: IGNEX_SECURITY_HEADERS });
|
|
6105
6305
|
}
|
|
6106
6306
|
const status = safeTerminalStatus(result);
|
|
6107
6307
|
const body = JSON.stringify({
|
|
@@ -6109,7 +6309,7 @@ function buildIgngexTerminal(result, _ctx) {
|
|
|
6109
6309
|
status,
|
|
6110
6310
|
code: errorCodeName(result.errorCode)
|
|
6111
6311
|
});
|
|
6112
|
-
const headers = new Headers(
|
|
6312
|
+
const headers = new Headers(IGNEX_SECURITY_HEADERS);
|
|
6113
6313
|
headers.set("content-type", "application/json; charset=utf-8");
|
|
6114
6314
|
return new Response(body, { status, headers });
|
|
6115
6315
|
}
|
|
@@ -6137,7 +6337,7 @@ function nativeResponderRoute(ingress, responder, opts = {}) {
|
|
|
6137
6337
|
const code = err.code;
|
|
6138
6338
|
const status = code === "REQUEST_TIMEOUT" ? 408 : code === "BODY_TOO_LARGE" ? 413 : 400;
|
|
6139
6339
|
const payload = JSON.stringify({ error: "Bad Request", status, code: "BAD_REQUEST" });
|
|
6140
|
-
const headers = new Headers(
|
|
6340
|
+
const headers = new Headers(IGNEX_SECURITY_HEADERS);
|
|
6141
6341
|
headers.set("content-type", "application/json; charset=utf-8");
|
|
6142
6342
|
return new Response(payload, { status, headers });
|
|
6143
6343
|
}
|
|
@@ -6468,7 +6668,7 @@ function nodeRequestToWebRequest(req) {
|
|
|
6468
6668
|
}
|
|
6469
6669
|
const method = req.method ?? "GET";
|
|
6470
6670
|
const bodyForbidden = method === "GET" || method === "HEAD";
|
|
6471
|
-
const hasBody =
|
|
6671
|
+
const hasBody = requestHasBody(req);
|
|
6472
6672
|
const init = { method, headers };
|
|
6473
6673
|
if (hasBody && !bodyForbidden) {
|
|
6474
6674
|
init.body = Readable.toWeb(req);
|
|
@@ -6512,7 +6712,7 @@ async function writeResponse(res, response) {
|
|
|
6512
6712
|
}
|
|
6513
6713
|
function drainUnreadBody(res) {
|
|
6514
6714
|
const req = res.req;
|
|
6515
|
-
if (req !== undefined && req !== null && !req.complete &&
|
|
6715
|
+
if (req !== undefined && req !== null && !req.complete && requestHasBody(req)) {
|
|
6516
6716
|
req.resume();
|
|
6517
6717
|
res.shouldKeepAlive = false;
|
|
6518
6718
|
if (!res.headersSent) {
|
|
@@ -6520,7 +6720,7 @@ function drainUnreadBody(res) {
|
|
|
6520
6720
|
}
|
|
6521
6721
|
}
|
|
6522
6722
|
}
|
|
6523
|
-
function
|
|
6723
|
+
function requestHasBody(req) {
|
|
6524
6724
|
return Number(req.headers["content-length"] ?? 0) > 0 || req.headers["transfer-encoding"] !== undefined;
|
|
6525
6725
|
}
|
|
6526
6726
|
function makeRequestListener(options, routes, baseOpts) {
|
|
@@ -6576,6 +6776,23 @@ function makeRequestListener(options, routes, baseOpts) {
|
|
|
6576
6776
|
}
|
|
6577
6777
|
};
|
|
6578
6778
|
}
|
|
6779
|
+
var WS_PROTOCOL_TOKEN = /^[A-Za-z0-9!#$%&'*+\-.^_`|~]+$/;
|
|
6780
|
+
function formatWebSocketHandshake(accept, protocol) {
|
|
6781
|
+
if (/[\r\n]/.test(accept)) {
|
|
6782
|
+
throw new Error("invalid Sec-WebSocket-Accept value");
|
|
6783
|
+
}
|
|
6784
|
+
let raw = `HTTP/1.1 101 Switching Protocols\r
|
|
6785
|
+
` + `Upgrade: websocket\r
|
|
6786
|
+
` + `Connection: Upgrade\r
|
|
6787
|
+
` + `Sec-WebSocket-Accept: ${accept}\r
|
|
6788
|
+
`;
|
|
6789
|
+
if (protocol && WS_PROTOCOL_TOKEN.test(protocol)) {
|
|
6790
|
+
raw += `Sec-WebSocket-Protocol: ${protocol}\r
|
|
6791
|
+
`;
|
|
6792
|
+
}
|
|
6793
|
+
return `${raw}\r
|
|
6794
|
+
`;
|
|
6795
|
+
}
|
|
6579
6796
|
function makeUpgradeListener(options) {
|
|
6580
6797
|
return async (req, socket, head) => {
|
|
6581
6798
|
try {
|
|
@@ -6585,18 +6802,7 @@ function makeUpgradeListener(options) {
|
|
|
6585
6802
|
socket.destroy();
|
|
6586
6803
|
return;
|
|
6587
6804
|
}
|
|
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);
|
|
6805
|
+
socket.write(formatWebSocketHandshake(handshake.accept, handshake.protocol));
|
|
6600
6806
|
options.onUpgrade?.(socket, req, head);
|
|
6601
6807
|
} catch {
|
|
6602
6808
|
socket.destroy();
|
|
@@ -6820,6 +7026,7 @@ class IngressResultBase {
|
|
|
6820
7026
|
bodyTruncated = false;
|
|
6821
7027
|
body = EMPTY_BODY2;
|
|
6822
7028
|
_buf = EMPTY_BODY2;
|
|
7029
|
+
_len = 0;
|
|
6823
7030
|
_bodyJsonStart = OUT_DATA_START;
|
|
6824
7031
|
_bodyJsonLen = 0;
|
|
6825
7032
|
_cookiesBuf = null;
|
|
@@ -6845,6 +7052,7 @@ class IngressResultBase {
|
|
|
6845
7052
|
this.bodyTruncated = false;
|
|
6846
7053
|
this.body = EMPTY_BODY2;
|
|
6847
7054
|
this._buf = EMPTY_BODY2;
|
|
7055
|
+
this._len = 0;
|
|
6848
7056
|
this._bodyJsonStart = OUT_DATA_START;
|
|
6849
7057
|
this._bodyJsonLen = 0;
|
|
6850
7058
|
this._cookiesBuf = null;
|
|
@@ -6869,8 +7077,9 @@ class IngressResultBase {
|
|
|
6869
7077
|
this.retryAfterMs = 0;
|
|
6870
7078
|
}
|
|
6871
7079
|
}
|
|
6872
|
-
setSections(buf, layout, bodyJsonLen) {
|
|
7080
|
+
setSections(buf, layout, bodyJsonLen, len = buf.byteLength) {
|
|
6873
7081
|
this._buf = buf;
|
|
7082
|
+
this._len = len;
|
|
6874
7083
|
this._bodyJsonStart = layout.bodyJsonStart;
|
|
6875
7084
|
this._bodyJsonLen = bodyJsonLen;
|
|
6876
7085
|
this._cookiesBuf = layout.safeCookiesLen > 0 ? buf.subarray(OUT_DATA_START, OUT_DATA_START + layout.safeCookiesLen) : null;
|
|
@@ -6900,7 +7109,7 @@ class IngressResultBase {
|
|
|
6900
7109
|
if (this._bodyJsonLen === 0)
|
|
6901
7110
|
return EMPTY_BODY2;
|
|
6902
7111
|
const end = this._bodyJsonStart + this._bodyJsonLen;
|
|
6903
|
-
if (end > this.
|
|
7112
|
+
if (end > this._len)
|
|
6904
7113
|
return EMPTY_BODY2;
|
|
6905
7114
|
return this._buf.subarray(this._bodyJsonStart, end);
|
|
6906
7115
|
}
|
|
@@ -6964,7 +7173,7 @@ class FastIngressResult extends IngressResultBase {
|
|
|
6964
7173
|
this.isPreflight = (flags & FLAG_IS_PREFLIGHT) !== 0;
|
|
6965
7174
|
this.rateLimited = (flags & FLAG_RATE_LIMITED) !== 0;
|
|
6966
7175
|
const layout = sectionLayout(buf.byteLength, cookiesJsonLen, queryJsonLen, bodyJsonLen);
|
|
6967
|
-
this.setSections(buf, layout, bodyJsonLen);
|
|
7176
|
+
this.setSections(buf, layout, bodyJsonLen, buf.byteLength);
|
|
6968
7177
|
this.bodyTruncated = (flags & FLAG_BODY_TRUNCATED) !== 0 || layout.truncated;
|
|
6969
7178
|
}
|
|
6970
7179
|
invalidate() {
|
|
@@ -7056,7 +7265,14 @@ function warnTrustProxyDeprecated() {
|
|
|
7056
7265
|
if (trustProxyWarned)
|
|
7057
7266
|
return;
|
|
7058
7267
|
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: [...] }`
|
|
7268
|
+
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.");
|
|
7269
|
+
}
|
|
7270
|
+
var rateLimitNoIpWarned = false;
|
|
7271
|
+
function warnRateLimitWithoutGetIp() {
|
|
7272
|
+
if (rateLimitNoIpWarned)
|
|
7273
|
+
return;
|
|
7274
|
+
rateLimitNoIpWarned = true;
|
|
7275
|
+
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
7276
|
}
|
|
7061
7277
|
|
|
7062
7278
|
// src/ingress/packing/header-packing.ts
|
|
@@ -7622,6 +7838,11 @@ class BufferPool {
|
|
|
7622
7838
|
this.estimate = options.adaptive === true ? new AdaptiveEstimate({ alpha: 0.25, min: this.initialSize }) : null;
|
|
7623
7839
|
this.free.push(new Uint8Array(this.initialSize));
|
|
7624
7840
|
this.created = 1;
|
|
7841
|
+
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);
|
|
7842
|
+
for (let i = 0;i < prefill; i++) {
|
|
7843
|
+
this.free.push(new Uint8Array(this.initialSize));
|
|
7844
|
+
this.created++;
|
|
7845
|
+
}
|
|
7625
7846
|
}
|
|
7626
7847
|
get freeCount() {
|
|
7627
7848
|
return this.free.length;
|
|
@@ -7655,7 +7876,9 @@ class BufferPool {
|
|
|
7655
7876
|
for (let i = 0;i < this.free.length; i++) {
|
|
7656
7877
|
const candidate = this.free[i];
|
|
7657
7878
|
if (candidate.byteLength >= minSize) {
|
|
7658
|
-
this.free.
|
|
7879
|
+
const last = this.free.pop();
|
|
7880
|
+
if (i < this.free.length)
|
|
7881
|
+
this.free[i] = last;
|
|
7659
7882
|
return candidate;
|
|
7660
7883
|
}
|
|
7661
7884
|
}
|
|
@@ -7670,7 +7893,9 @@ class BufferPool {
|
|
|
7670
7893
|
}
|
|
7671
7894
|
}
|
|
7672
7895
|
if (largestBuf !== null) {
|
|
7673
|
-
this.free.
|
|
7896
|
+
const last = this.free.pop();
|
|
7897
|
+
if (largest < this.free.length)
|
|
7898
|
+
this.free[largest] = last;
|
|
7674
7899
|
this.created++;
|
|
7675
7900
|
return new Uint8Array(target);
|
|
7676
7901
|
}
|
|
@@ -7679,16 +7904,15 @@ class BufferPool {
|
|
|
7679
7904
|
}
|
|
7680
7905
|
releaseBuffer(buffer) {
|
|
7681
7906
|
if (this.free.length >= this.maxBuffers) {
|
|
7682
|
-
let smallestBuf = null;
|
|
7683
7907
|
let smallest = 0;
|
|
7684
|
-
for (let i =
|
|
7685
|
-
|
|
7686
|
-
if (smallestBuf === null || candidate.byteLength < smallestBuf.byteLength) {
|
|
7687
|
-
smallestBuf = candidate;
|
|
7908
|
+
for (let i = 1;i < this.free.length; i++) {
|
|
7909
|
+
if (this.free[i].byteLength < this.free[smallest].byteLength) {
|
|
7688
7910
|
smallest = i;
|
|
7689
7911
|
}
|
|
7690
7912
|
}
|
|
7691
|
-
this.free.
|
|
7913
|
+
const last = this.free.pop();
|
|
7914
|
+
if (smallest < this.free.length)
|
|
7915
|
+
this.free[smallest] = last;
|
|
7692
7916
|
}
|
|
7693
7917
|
this.free.push(buffer);
|
|
7694
7918
|
}
|
|
@@ -7748,8 +7972,8 @@ function createStructuredLogger(stream = process.stderr, env = process.env) {
|
|
|
7748
7972
|
|
|
7749
7973
|
// src/ingress/decode/baked-result.ts
|
|
7750
7974
|
class BakedIngressResult extends IngressResultBase {
|
|
7751
|
-
refresh(buf, body, view) {
|
|
7752
|
-
if (
|
|
7975
|
+
refresh(buf, body, view, len = buf.byteLength) {
|
|
7976
|
+
if (len < OUT_DATA_START) {
|
|
7753
7977
|
this.setInternalError();
|
|
7754
7978
|
return;
|
|
7755
7979
|
}
|
|
@@ -7762,7 +7986,7 @@ class BakedIngressResult extends IngressResultBase {
|
|
|
7762
7986
|
const queryLenRaw = view.getUint32(OUT_QUERY_JSON_LEN, true);
|
|
7763
7987
|
const headerVariant = view.getUint8(OUT_HEADER_VARIANT);
|
|
7764
7988
|
const bodyJsonLenRaw = view.getUint32(OUT_BODY_JSON_LEN, true);
|
|
7765
|
-
const layout = sectionLayout(
|
|
7989
|
+
const layout = sectionLayout(len, cookiesLenRaw, queryLenRaw, bodyJsonLenRaw);
|
|
7766
7990
|
if (h0 === 0 && h1 === 0) {
|
|
7767
7991
|
this.verdict = 1;
|
|
7768
7992
|
this.errorCode = ERR_CODE_INTERNAL;
|
|
@@ -7777,7 +8001,7 @@ class BakedIngressResult extends IngressResultBase {
|
|
|
7777
8001
|
this.rateRemaining = h3;
|
|
7778
8002
|
this.setRateWindow(h2, (flags & FLAG_RATE_LIMITED) !== 0, view);
|
|
7779
8003
|
this.headerVariant = headerVariant;
|
|
7780
|
-
this.setSections(buf, layout, layout.safeBodyJsonLen);
|
|
8004
|
+
this.setSections(buf, layout, layout.safeBodyJsonLen, len);
|
|
7781
8005
|
this.updateOkTerminal();
|
|
7782
8006
|
this.isPreflight = (flags & FLAG_IS_PREFLIGHT) !== 0;
|
|
7783
8007
|
this.corsAllowed = (flags & FLAG_CORS_ALLOWED) !== 0;
|
|
@@ -7800,8 +8024,16 @@ class BakedIngressResult extends IngressResultBase {
|
|
|
7800
8024
|
this.ok = false;
|
|
7801
8025
|
}
|
|
7802
8026
|
bodyJson(copy) {
|
|
8027
|
+
if (copy) {
|
|
8028
|
+
if (this._bodyJsonLen === 0)
|
|
8029
|
+
return this._buf.slice(0, 0);
|
|
8030
|
+
const end = this._bodyJsonStart + this._bodyJsonLen;
|
|
8031
|
+
if (end > this._len)
|
|
8032
|
+
return this._buf.slice(0, 0);
|
|
8033
|
+
return this._buf.slice(this._bodyJsonStart, end);
|
|
8034
|
+
}
|
|
7803
8035
|
const slice = this.bodyJsonSlice();
|
|
7804
|
-
return
|
|
8036
|
+
return slice;
|
|
7805
8037
|
}
|
|
7806
8038
|
}
|
|
7807
8039
|
|
|
@@ -7925,6 +8157,13 @@ function cachedOriginBlock(origin) {
|
|
|
7925
8157
|
ORIGIN_BLOCK_CACHE.set(origin, block);
|
|
7926
8158
|
return block;
|
|
7927
8159
|
}
|
|
8160
|
+
function prewarmOriginBlocks(origins) {
|
|
8161
|
+
for (const origin of origins) {
|
|
8162
|
+
if (typeof origin === "string" && origin.length > 0 && origin.length <= MAX_SMALL_HEADER_BYTES && !origin.includes("*")) {
|
|
8163
|
+
cachedOriginBlock(origin);
|
|
8164
|
+
}
|
|
8165
|
+
}
|
|
8166
|
+
}
|
|
7928
8167
|
|
|
7929
8168
|
// src/ingress/response/baked-response.ts
|
|
7930
8169
|
init_bytes();
|
|
@@ -7977,6 +8216,12 @@ function pooledBodyResponse(handle, bytes, init = {}, timeoutMs = 0) {
|
|
|
7977
8216
|
|
|
7978
8217
|
// src/ingress/response/baked-response.ts
|
|
7979
8218
|
var EMPTY_BODY4 = new Uint8Array(0);
|
|
8219
|
+
var ORIGIN_HEADER_CACHE_MAX = 64;
|
|
8220
|
+
function prewarmOriginHeaders(responseHeaders, origins, variant) {
|
|
8221
|
+
for (const origin of origins) {
|
|
8222
|
+
memoizedHeaders(responseHeaders(variant, null, origin));
|
|
8223
|
+
}
|
|
8224
|
+
}
|
|
7980
8225
|
function buildBakedResponseBuilders(deps) {
|
|
7981
8226
|
const {
|
|
7982
8227
|
headerTemplates,
|
|
@@ -7986,6 +8231,45 @@ function buildBakedResponseBuilders(deps) {
|
|
|
7986
8231
|
originHeaderCache,
|
|
7987
8232
|
state
|
|
7988
8233
|
} = deps;
|
|
8234
|
+
function originBaseEntries(variant, origin) {
|
|
8235
|
+
const key = `${variant & 31}\x00${origin}`;
|
|
8236
|
+
const cached = originHeaderCache.get(key);
|
|
8237
|
+
if (cached !== undefined) {
|
|
8238
|
+
return cached;
|
|
8239
|
+
}
|
|
8240
|
+
const template = headerTemplates[variant & 31] ?? headerTemplates[0] ?? [];
|
|
8241
|
+
const entries = new Array(template.length + 1);
|
|
8242
|
+
let i = 0;
|
|
8243
|
+
for (const pair of template) {
|
|
8244
|
+
entries[i++] = pair;
|
|
8245
|
+
}
|
|
8246
|
+
entries[i] = ["access-control-allow-origin", origin];
|
|
8247
|
+
if (originHeaderCache.size >= ORIGIN_HEADER_CACHE_MAX) {
|
|
8248
|
+
const oldest = originHeaderCache.keys().next().value;
|
|
8249
|
+
if (oldest !== undefined)
|
|
8250
|
+
originHeaderCache.delete(oldest);
|
|
8251
|
+
}
|
|
8252
|
+
originHeaderCache.set(key, entries);
|
|
8253
|
+
return entries;
|
|
8254
|
+
}
|
|
8255
|
+
function successHeaders(variant, requestIdHeader, origin, rateRemaining, rateResetSecs) {
|
|
8256
|
+
const needsRequestId = emitRequestIdHeader && requestIdHeader !== null;
|
|
8257
|
+
const needsOrigin = ((variant & HV_CORS_SIMPLE) !== 0 || (variant & HV_CORS_PREFLIGHT) !== 0) && origin !== null;
|
|
8258
|
+
const needsRate = (variant & HV_RATE_ACTIVE) !== 0;
|
|
8259
|
+
const base = needsOrigin ? memoizedHeaders(originBaseEntries(variant, origin)) : memoizedHeaders(headerTemplates[variant & 31] ?? headerTemplates[0] ?? []);
|
|
8260
|
+
if (!needsRequestId && !needsRate) {
|
|
8261
|
+
return base;
|
|
8262
|
+
}
|
|
8263
|
+
const headers = new Headers(base);
|
|
8264
|
+
if (needsRequestId) {
|
|
8265
|
+
headers.set("x-request-id", requestIdHeader);
|
|
8266
|
+
}
|
|
8267
|
+
if (needsRate) {
|
|
8268
|
+
headers.set("ratelimit-remaining", String(rateRemaining ?? 0));
|
|
8269
|
+
headers.set("ratelimit-reset", String(rateResetSecs ?? 0));
|
|
8270
|
+
}
|
|
8271
|
+
return headers;
|
|
8272
|
+
}
|
|
7989
8273
|
function responseHeaders(variant, requestIdHeader, origin, rateRemaining, rateResetSecs, retryAfterSecs) {
|
|
7990
8274
|
const template = headerTemplates[variant & 31] ?? headerTemplates[0] ?? [];
|
|
7991
8275
|
const needsRequestId = emitRequestIdHeader && requestIdHeader !== null;
|
|
@@ -7996,19 +8280,7 @@ function buildBakedResponseBuilders(deps) {
|
|
|
7996
8280
|
return template;
|
|
7997
8281
|
}
|
|
7998
8282
|
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;
|
|
8283
|
+
return originBaseEntries(variant, origin);
|
|
8012
8284
|
}
|
|
8013
8285
|
let extra = 0;
|
|
8014
8286
|
if (needsRequestId)
|
|
@@ -8069,27 +8341,27 @@ function buildBakedResponseBuilders(deps) {
|
|
|
8069
8341
|
if (preflightAllowed) {
|
|
8070
8342
|
return new Response(null, {
|
|
8071
8343
|
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)
|
|
8344
|
+
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
8345
|
});
|
|
8074
8346
|
}
|
|
8075
8347
|
const status = safeTerminalStatus(result);
|
|
8076
8348
|
const body = result.errorCode === ERR_CODE_RATE_LIMITED ? rateLimitedBody(result.retryAfterMs) : ERROR_CODE_BODIES[result.errorCode] ?? ERROR_BODIES.internal ?? EMPTY_BODY4;
|
|
8077
8349
|
return new Response(body, {
|
|
8078
8350
|
status,
|
|
8079
|
-
headers: terminalHeaders(result.headerVariant, ctx, result)
|
|
8351
|
+
headers: memoizedHeaders(terminalHeaders(result.headerVariant, ctx, result))
|
|
8080
8352
|
});
|
|
8081
8353
|
}
|
|
8082
8354
|
function errorResponse(_req, result, status, code, message, ctx) {
|
|
8083
8355
|
const body = ERROR_BODIES[code] ?? encoder.encode(JSON.stringify({ ok: false, error: { code, message } }));
|
|
8084
8356
|
return new Response(body, {
|
|
8085
8357
|
status,
|
|
8086
|
-
headers: terminalHeaders(result?.headerVariant ?? HV_JSON, ctx, result)
|
|
8358
|
+
headers: memoizedHeaders(terminalHeaders(result?.headerVariant ?? HV_JSON, ctx, result))
|
|
8087
8359
|
});
|
|
8088
8360
|
}
|
|
8089
8361
|
function internalErrorResponse(ctx, result) {
|
|
8090
8362
|
return new Response(ERROR_BODIES.internal, {
|
|
8091
8363
|
status: 500,
|
|
8092
|
-
headers: terminalHeaders(result?.headerVariant ?? HV_JSON, ctx, result ?? null)
|
|
8364
|
+
headers: memoizedHeaders(terminalHeaders(result?.headerVariant ?? HV_JSON, ctx, result ?? null))
|
|
8093
8365
|
});
|
|
8094
8366
|
}
|
|
8095
8367
|
function withContentType(headers, contentType) {
|
|
@@ -8110,6 +8382,7 @@ function buildBakedResponseBuilders(deps) {
|
|
|
8110
8382
|
}
|
|
8111
8383
|
return {
|
|
8112
8384
|
responseHeaders,
|
|
8385
|
+
successHeaders,
|
|
8113
8386
|
terminalHeaders,
|
|
8114
8387
|
terminalResponse,
|
|
8115
8388
|
errorResponse,
|
|
@@ -8124,6 +8397,8 @@ var EMPTY_BODY5 = new Uint8Array(0);
|
|
|
8124
8397
|
var EMPTY_IP = "0.0.0.0";
|
|
8125
8398
|
var RATE_LIMIT_U32_MAX = 4294967295;
|
|
8126
8399
|
var MAX_FFI_FAILURES = 3;
|
|
8400
|
+
var PREWARM_POOL_BUFFERS = 16;
|
|
8401
|
+
var PREWARM_POOL_BYTES = 4 * 1024 * 1024;
|
|
8127
8402
|
function pathForLog(req) {
|
|
8128
8403
|
try {
|
|
8129
8404
|
return new URL(req.url).pathname;
|
|
@@ -8160,14 +8435,24 @@ function createIngressHandler(options = {}, runtime = {}) {
|
|
|
8160
8435
|
const outputBufferSize = clampIngressBufferSize(runtime.outputBufferSize ?? DEFAULT_BAKED_OUTPUT_BUFFER_SIZE, OUT_DATA_START);
|
|
8161
8436
|
const logger = runtime.logger ?? (runtime.structuredLog === true ? createStructuredLogger() : null);
|
|
8162
8437
|
const needRequestIdString = !!(emitRequestIdHeader || runtime.onRequest || runtime.onError || runtime.onResponse || logger);
|
|
8438
|
+
const hasOnRequest = runtime.onRequest !== undefined;
|
|
8439
|
+
const hasOnResponse = runtime.onResponse !== undefined;
|
|
8163
8440
|
const outputPool = new BufferPool({
|
|
8164
8441
|
initialSize: outputBufferSize,
|
|
8165
|
-
maxInFlight: runtime.maxInFlight
|
|
8442
|
+
maxInFlight: runtime.maxInFlight,
|
|
8443
|
+
prefill: PREWARM_POOL_BUFFERS,
|
|
8444
|
+
prefillBytes: PREWARM_POOL_BYTES
|
|
8166
8445
|
});
|
|
8167
8446
|
const inputPacker = new IngressInputPacker;
|
|
8168
8447
|
const responseState = { currentHandle: null, responseBorrowsBuffer: false };
|
|
8169
8448
|
let ffiFailures = 0;
|
|
8170
8449
|
let ffiDisabled = false;
|
|
8450
|
+
const noteFfiFailure = () => {
|
|
8451
|
+
ffiFailures++;
|
|
8452
|
+
if (ffiFailures >= MAX_FFI_FAILURES) {
|
|
8453
|
+
ffiDisabled = true;
|
|
8454
|
+
}
|
|
8455
|
+
};
|
|
8171
8456
|
const originHeaderCache = new Map;
|
|
8172
8457
|
const cors = options.cors;
|
|
8173
8458
|
const securityEntries = runtime.enableSecurityHeaders === false ? Object.freeze([]) : Object.freeze(buildBakedSecurityEntries(options.security, options.https, runtime.securityHeaders));
|
|
@@ -8193,6 +8478,17 @@ function createIngressHandler(options = {}, runtime = {}) {
|
|
|
8193
8478
|
originHeaderCache,
|
|
8194
8479
|
state: responseState
|
|
8195
8480
|
});
|
|
8481
|
+
if (headerPlan.cors && typeof cors?.allowOrigin === "object") {
|
|
8482
|
+
const exactOrigins = [];
|
|
8483
|
+
for (const origin of cors.allowOrigin) {
|
|
8484
|
+
if (typeof origin === "string" && origin.length > 0 && origin.length <= 512 && !origin.includes("*")) {
|
|
8485
|
+
exactOrigins.push(origin);
|
|
8486
|
+
}
|
|
8487
|
+
}
|
|
8488
|
+
prewarmOriginBlocks(exactOrigins);
|
|
8489
|
+
const successVariant = HV_JSON | HV_CORS_SIMPLE | (rateEnabled ? HV_RATE_ACTIVE : 0);
|
|
8490
|
+
prewarmOriginHeaders(responseBuilders.responseHeaders, exactOrigins, successVariant);
|
|
8491
|
+
}
|
|
8196
8492
|
const result = new BakedIngressResult;
|
|
8197
8493
|
const ctx = {
|
|
8198
8494
|
requestIdHeader: null,
|
|
@@ -8205,7 +8501,8 @@ function createIngressHandler(options = {}, runtime = {}) {
|
|
|
8205
8501
|
const requestIdStr = needRequestIdString ? decoder.decode(ridBytes) : "";
|
|
8206
8502
|
ctx.requestIdHeader = emitRequestIdHeader ? requestIdStr : null;
|
|
8207
8503
|
ctx.origin = headerPlan.cors ? req.headers.get("origin") : null;
|
|
8208
|
-
|
|
8504
|
+
if (hasOnRequest)
|
|
8505
|
+
runtime.onRequest?.(req, requestIdStr, ip);
|
|
8209
8506
|
const ipStr = ip ?? EMPTY_IP;
|
|
8210
8507
|
let handle = null;
|
|
8211
8508
|
responseState.currentHandle = null;
|
|
@@ -8223,10 +8520,7 @@ function createIngressHandler(options = {}, runtime = {}) {
|
|
|
8223
8520
|
written = bunFFI.ingressHandleComponents(ingressPtr, methodKind, packUrl, packIp ?? "", ridBytes, packedHeaders, body, handle.buffer);
|
|
8224
8521
|
ffiFailures = 0;
|
|
8225
8522
|
} catch {
|
|
8226
|
-
|
|
8227
|
-
if (ffiFailures >= MAX_FFI_FAILURES) {
|
|
8228
|
-
ffiDisabled = true;
|
|
8229
|
-
}
|
|
8523
|
+
noteFfiFailure();
|
|
8230
8524
|
const input = inputPacker.packParts(methodKind, packUrl, packIp, ridBytes, packedHeaders);
|
|
8231
8525
|
written = handler.handleRequestPacked(input, body, handle.buffer);
|
|
8232
8526
|
}
|
|
@@ -8236,18 +8530,14 @@ function createIngressHandler(options = {}, runtime = {}) {
|
|
|
8236
8530
|
written = bunFFI.ingressHandlePacked(ingressPtr, input, body, handle.buffer);
|
|
8237
8531
|
ffiFailures = 0;
|
|
8238
8532
|
} catch {
|
|
8239
|
-
|
|
8240
|
-
if (ffiFailures >= MAX_FFI_FAILURES) {
|
|
8241
|
-
ffiDisabled = true;
|
|
8242
|
-
}
|
|
8533
|
+
noteFfiFailure();
|
|
8243
8534
|
written = handler.handleRequestPacked(input, body, handle.buffer);
|
|
8244
8535
|
}
|
|
8245
8536
|
} else {
|
|
8246
8537
|
const input = inputPacker.packParts(methodKind, packUrl, packIp, ridBytes, packedHeaders);
|
|
8247
8538
|
written = handler.handleRequestPacked(input, body, handle.buffer);
|
|
8248
8539
|
}
|
|
8249
|
-
|
|
8250
|
-
result.refresh(used, body ?? EMPTY_BODY5, viewForArrayBuffer(used.buffer, used.byteOffset));
|
|
8540
|
+
result.refresh(handle.buffer, body ?? EMPTY_BODY5, viewForArrayBuffer(handle.buffer.buffer, handle.buffer.byteOffset), written);
|
|
8251
8541
|
} catch (err) {
|
|
8252
8542
|
result.setInternalError();
|
|
8253
8543
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
@@ -8263,17 +8553,20 @@ function createIngressHandler(options = {}, runtime = {}) {
|
|
|
8263
8553
|
try {
|
|
8264
8554
|
const out = fn(result, ctx);
|
|
8265
8555
|
assertSyncCallback(out, "createIngressHandler().run()");
|
|
8266
|
-
|
|
8267
|
-
|
|
8268
|
-
|
|
8269
|
-
|
|
8270
|
-
|
|
8271
|
-
|
|
8272
|
-
|
|
8273
|
-
|
|
8274
|
-
|
|
8275
|
-
|
|
8276
|
-
|
|
8556
|
+
if (hasOnResponse || logger !== null) {
|
|
8557
|
+
const status = out instanceof Response ? out.status : safeTerminalStatus(result);
|
|
8558
|
+
if (hasOnResponse)
|
|
8559
|
+
runtime.onResponse?.(req, result, status, requestIdStr);
|
|
8560
|
+
if (logger !== null) {
|
|
8561
|
+
logger.request({
|
|
8562
|
+
requestId: requestIdStr,
|
|
8563
|
+
method: req.method,
|
|
8564
|
+
path: pathForLog(req),
|
|
8565
|
+
status,
|
|
8566
|
+
durationMs: Math.round((performance.now() - startedAt) * 1000) / 1000,
|
|
8567
|
+
ip: ipStr
|
|
8568
|
+
});
|
|
8569
|
+
}
|
|
8277
8570
|
}
|
|
8278
8571
|
return out;
|
|
8279
8572
|
} finally {
|
|
@@ -8587,6 +8880,10 @@ function createIngressRouter(options) {
|
|
|
8587
8880
|
}
|
|
8588
8881
|
const handler = createIngressHandler(spec.options ?? {}, runtime);
|
|
8589
8882
|
compiled[path] = handler;
|
|
8883
|
+
const routeLimit = spec.options?.rateLimit?.limit;
|
|
8884
|
+
if (typeof routeLimit === "number" && routeLimit > 0 && routeLimit !== RATE_LIMIT_U32_MAX && options.getIp === undefined) {
|
|
8885
|
+
warnRateLimitWithoutGetIp();
|
|
8886
|
+
}
|
|
8590
8887
|
if (spec.responder) {
|
|
8591
8888
|
bakedRoutes[path] = {
|
|
8592
8889
|
responder: {
|
|
@@ -8811,6 +9108,22 @@ function createIngress(options = {}) {
|
|
|
8811
9108
|
}
|
|
8812
9109
|
};
|
|
8813
9110
|
}
|
|
9111
|
+
// src/native/ingress-binding.ts
|
|
9112
|
+
init_ffi();
|
|
9113
|
+
var cached2;
|
|
9114
|
+
function getIngressBinding() {
|
|
9115
|
+
if (cached2 !== undefined)
|
|
9116
|
+
return cached2;
|
|
9117
|
+
const ffi = getBunFFI();
|
|
9118
|
+
const addonPath = ffiAddonPath();
|
|
9119
|
+
cached2 = ffi && addonPath ? {
|
|
9120
|
+
addonPath,
|
|
9121
|
+
ingressHandleComponents: ffi.ingressHandleComponents,
|
|
9122
|
+
ingressHandlePacked: ffi.ingressHandlePacked,
|
|
9123
|
+
ingressLayout: ffi.ingressLayout
|
|
9124
|
+
} : null;
|
|
9125
|
+
return cached2;
|
|
9126
|
+
}
|
|
8814
9127
|
// src/loader/index.ts
|
|
8815
9128
|
init_rust_ffi();
|
|
8816
9129
|
init_bytes();
|
|
@@ -10228,6 +10541,7 @@ function createTaskRuntime(options = {}) {
|
|
|
10228
10541
|
queueMicrotask(drainNow);
|
|
10229
10542
|
}
|
|
10230
10543
|
function submit(op, args, runOptions) {
|
|
10544
|
+
ensureDoorbell();
|
|
10231
10545
|
const id = nextId++;
|
|
10232
10546
|
return new Promise((resolve, reject) => {
|
|
10233
10547
|
inflight.set(id, { out: null, keep: null, resolve, reject });
|
|
@@ -10249,6 +10563,7 @@ function createTaskRuntime(options = {}) {
|
|
|
10249
10563
|
});
|
|
10250
10564
|
}
|
|
10251
10565
|
function submitInto(op, args, output, runOptions) {
|
|
10566
|
+
ensureDoorbell();
|
|
10252
10567
|
const id = nextId++;
|
|
10253
10568
|
return new Promise((resolve, reject) => {
|
|
10254
10569
|
inflight.set(id, { out: output, keep: null, resolve, reject });
|
|
@@ -10270,6 +10585,7 @@ function createTaskRuntime(options = {}) {
|
|
|
10270
10585
|
});
|
|
10271
10586
|
}
|
|
10272
10587
|
function submitSlice(op, hdr, data, runOptions) {
|
|
10588
|
+
ensureDoorbell();
|
|
10273
10589
|
const id = nextId++;
|
|
10274
10590
|
return new Promise((resolve, reject) => {
|
|
10275
10591
|
inflight.set(id, { out: null, keep: data, resolve, reject });
|
|
@@ -10291,11 +10607,16 @@ function createTaskRuntime(options = {}) {
|
|
|
10291
10607
|
});
|
|
10292
10608
|
}
|
|
10293
10609
|
const { JSCallback } = __require("bun:ffi");
|
|
10294
|
-
|
|
10295
|
-
|
|
10296
|
-
|
|
10297
|
-
|
|
10298
|
-
|
|
10610
|
+
function ensureDoorbell() {
|
|
10611
|
+
if (doorbell !== null)
|
|
10612
|
+
return;
|
|
10613
|
+
const cb = new JSCallback(() => {
|
|
10614
|
+
drainNow();
|
|
10615
|
+
}, { args: [], returns: "void", threadsafe: true });
|
|
10616
|
+
doorbell = cb;
|
|
10617
|
+
ffi.taskSetDoorbell(Number(cb.ptr));
|
|
10618
|
+
}
|
|
10619
|
+
ensureDoorbell();
|
|
10299
10620
|
schedule();
|
|
10300
10621
|
const runtime = {
|
|
10301
10622
|
gzipDecompress(data, runOptions) {
|
|
@@ -10339,6 +10660,7 @@ function createTaskRuntime(options = {}) {
|
|
|
10339
10660
|
deferred.reject(cancelledError());
|
|
10340
10661
|
}
|
|
10341
10662
|
inflight.clear();
|
|
10663
|
+
ffi.taskSetDoorbell(0);
|
|
10342
10664
|
ffi.taskShutdown();
|
|
10343
10665
|
release();
|
|
10344
10666
|
doorbell?.close();
|
|
@@ -10475,6 +10797,7 @@ export {
|
|
|
10475
10797
|
errorMessage,
|
|
10476
10798
|
fallbackHandler,
|
|
10477
10799
|
generateRequestId,
|
|
10800
|
+
getIngressBinding,
|
|
10478
10801
|
gracefulShutdown,
|
|
10479
10802
|
gzipCompressUpperBound,
|
|
10480
10803
|
headHandler,
|