@sproutboat/toolchain 0.4.1 → 0.4.2
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/CHANGELOG.md +6 -0
- package/package.json +1 -1
- package/src/acquire.ts +40 -11
- package/src/patch.test.ts +19 -64
- package/src/patch.ts +25 -77
- package/src/pin.ts +5 -4
- package/vendor/porffor-038f415.tar.gz +0 -0
- package/vendor/porffor-1f4ae4a.tar.gz +0 -0
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
package/src/acquire.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { homedir } from "node:os";
|
|
|
5
5
|
import { resolve } from "node:path";
|
|
6
6
|
// @ts-expect-error Bun's file loader supplies a path; see the pinned-commit
|
|
7
7
|
// check below for why this is safe to trust unconditionally.
|
|
8
|
-
import vendoredPorfforArchive from "../vendor/porffor-
|
|
8
|
+
import vendoredPorfforArchive from "../vendor/porffor-038f415.tar.gz" with { type: "file" };
|
|
9
9
|
import { ensurePorfforPatched } from "./patch";
|
|
10
10
|
import { PORFFOR_ARCHIVE_SHA256, PORFFOR_ARCHIVE_URL, PORFFOR_COMMIT_FULL } from "./pin";
|
|
11
11
|
|
|
@@ -26,7 +26,12 @@ type AcquireOptions = {
|
|
|
26
26
|
timeoutMs?: number;
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
const required = [
|
|
29
|
+
const required = [
|
|
30
|
+
"runtime/index.js",
|
|
31
|
+
"compiler/render.js",
|
|
32
|
+
"compiler/index.js",
|
|
33
|
+
"compiler/uwebsockets.js",
|
|
34
|
+
];
|
|
30
35
|
async function digest(path: string): Promise<string> {
|
|
31
36
|
return createHash("sha256")
|
|
32
37
|
.update(await readFile(path))
|
|
@@ -42,9 +47,11 @@ async function complete(dir: string, expectedArchive = PORFFOR_ARCHIVE_SHA256):
|
|
|
42
47
|
archiveSha256?: string;
|
|
43
48
|
files?: Record<string, string>;
|
|
44
49
|
};
|
|
45
|
-
if (manifest.commit !== PORFFOR_COMMIT_FULL || manifest.archiveSha256 !== expectedArchive)
|
|
50
|
+
if (manifest.commit !== PORFFOR_COMMIT_FULL || manifest.archiveSha256 !== expectedArchive)
|
|
51
|
+
return false;
|
|
46
52
|
for (const file of required)
|
|
47
|
-
if (!manifest.files?.[file] || (await digest(resolve(dir, file))) !== manifest.files[file])
|
|
53
|
+
if (!manifest.files?.[file] || (await digest(resolve(dir, file))) !== manifest.files[file])
|
|
54
|
+
return false;
|
|
48
55
|
return true;
|
|
49
56
|
} catch {
|
|
50
57
|
return false;
|
|
@@ -81,10 +88,16 @@ async function extract(archive: string, stage: string): Promise<void> {
|
|
|
81
88
|
});
|
|
82
89
|
const [code, stderr] = await Promise.all([child.exited, new Response(child.stderr).text()]);
|
|
83
90
|
if (code !== 0)
|
|
84
|
-
throw new PorfforToolchainError(
|
|
91
|
+
throw new PorfforToolchainError(
|
|
92
|
+
"archive",
|
|
93
|
+
`could not extract pinned Porffor archive: ${stderr.trim()}`,
|
|
94
|
+
);
|
|
85
95
|
for (const file of required)
|
|
86
96
|
if (!existsSync(resolve(stage, file)))
|
|
87
|
-
throw new PorfforToolchainError(
|
|
97
|
+
throw new PorfforToolchainError(
|
|
98
|
+
"archive",
|
|
99
|
+
`Porffor archive is missing required file ${file}`,
|
|
100
|
+
);
|
|
88
101
|
}
|
|
89
102
|
|
|
90
103
|
async function waitForPublisher(dir: string, lock: string): Promise<string | null> {
|
|
@@ -113,7 +126,9 @@ export async function ensurePorffor(options: AcquireOptions = {}): Promise<strin
|
|
|
113
126
|
return dir;
|
|
114
127
|
}
|
|
115
128
|
const root = resolve(
|
|
116
|
-
options.cacheRoot ??
|
|
129
|
+
options.cacheRoot ??
|
|
130
|
+
process.env.SPROUTBOAT_TOOLCHAIN_CACHE ??
|
|
131
|
+
resolve(homedir(), ".cache/sproutboat"),
|
|
117
132
|
);
|
|
118
133
|
const dir = resolve(root, `porffor-${PORFFOR_COMMIT_FULL}`);
|
|
119
134
|
const expected = options.expectedSha256 ?? PORFFOR_ARCHIVE_SHA256;
|
|
@@ -127,7 +142,10 @@ export async function ensurePorffor(options: AcquireOptions = {}): Promise<strin
|
|
|
127
142
|
if (published) return published;
|
|
128
143
|
return ensurePorffor(options);
|
|
129
144
|
}
|
|
130
|
-
const stage = resolve(
|
|
145
|
+
const stage = resolve(
|
|
146
|
+
root,
|
|
147
|
+
`.porffor-${PORFFOR_COMMIT_FULL}-${process.pid}-${crypto.randomUUID()}`,
|
|
148
|
+
);
|
|
131
149
|
try {
|
|
132
150
|
if (await complete(dir, expected)) return dir;
|
|
133
151
|
await rm(dir, { recursive: true, force: true });
|
|
@@ -139,9 +157,18 @@ export async function ensurePorffor(options: AcquireOptions = {}): Promise<strin
|
|
|
139
157
|
// left stale by a pin bump (checksum below still catches a wrong file
|
|
140
158
|
// rather than silently accepting it).
|
|
141
159
|
const noOverride = options.url === undefined && options.expectedSha256 === undefined;
|
|
142
|
-
const vendored =
|
|
160
|
+
const vendored =
|
|
161
|
+
noOverride &&
|
|
162
|
+
existsSync(vendoredPorfforArchive) &&
|
|
163
|
+
(await digest(vendoredPorfforArchive)) === expected;
|
|
143
164
|
if (vendored) await writeFile(archive, await readFile(vendoredPorfforArchive));
|
|
144
|
-
else
|
|
165
|
+
else
|
|
166
|
+
await download(
|
|
167
|
+
options.url ?? PORFFOR_ARCHIVE_URL,
|
|
168
|
+
archive,
|
|
169
|
+
options.fetcher ?? fetch,
|
|
170
|
+
options.timeoutMs ?? 30_000,
|
|
171
|
+
);
|
|
145
172
|
const actual = await digest(archive);
|
|
146
173
|
if (actual !== expected)
|
|
147
174
|
throw new PorfforToolchainError(
|
|
@@ -152,7 +179,9 @@ export async function ensurePorffor(options: AcquireOptions = {}): Promise<strin
|
|
|
152
179
|
await rm(archive, { force: true });
|
|
153
180
|
await ensurePorfforPatched(stage);
|
|
154
181
|
const files = Object.fromEntries(
|
|
155
|
-
await Promise.all(
|
|
182
|
+
await Promise.all(
|
|
183
|
+
required.map(async (file) => [file, await digest(resolve(stage, file))] as const),
|
|
184
|
+
),
|
|
156
185
|
);
|
|
157
186
|
await writeFile(
|
|
158
187
|
resolve(stage, ".sproutboat-complete"),
|
package/src/patch.test.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { expect, test } from "bun:test";
|
|
|
2
2
|
import { mkdtemp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
|
-
import {
|
|
5
|
+
import { patchRenderJs, patchUwebsockets } from "./patch";
|
|
6
6
|
|
|
7
7
|
// The parts of Porffor's compiler/render.js the patch anchors to.
|
|
8
8
|
const RENDER = `void porf_native_fetch_runtime_init(void) {
|
|
@@ -162,7 +162,9 @@ test("#156: status-line fallback synthesizes a line for unlisted codes, idempote
|
|
|
162
162
|
|
|
163
163
|
// #163: collect_headers takes res, drops a client-sent x-sb-remote-addr, and
|
|
164
164
|
// appends the real peer; the call site passes res through.
|
|
165
|
-
expect(once).toContain(
|
|
165
|
+
expect(once).toContain(
|
|
166
|
+
"static i32 collect_headers(uWS::HttpRequest* req, uWS::HttpResponse<false>* res) {",
|
|
167
|
+
);
|
|
166
168
|
expect(once).toContain("const i32 headers_ptr = collect_headers(req, res);");
|
|
167
169
|
expect(once).toContain('if (key == "x-sb-remote-addr") continue;');
|
|
168
170
|
expect(once).toContain("res->getRemoteAddressAsText()");
|
|
@@ -179,12 +181,22 @@ test("#156: status-line fallback synthesizes a line for unlisted codes, idempote
|
|
|
179
181
|
);
|
|
180
182
|
expect(once).toContain('key == "x-sb-raw-body"');
|
|
181
183
|
expect(once).toContain("bool raw_body = false;");
|
|
182
|
-
expect(once).toContain(
|
|
183
|
-
|
|
184
|
-
|
|
184
|
+
expect(once).toContain(
|
|
185
|
+
'if (std::string_view(scan_buf, scan_bytes) == "x-sb-raw-body") raw_body = true;',
|
|
186
|
+
);
|
|
187
|
+
expect(once).toContain(
|
|
188
|
+
"if (raw_body) porf_native_fetch_read_raw_bytes(body_value, &body_buf, &body_len);",
|
|
189
|
+
);
|
|
190
|
+
expect(once).toContain(
|
|
191
|
+
"else porf_native_fetch_read_value(body_value, &body_buf, &body_len, &body_owned);",
|
|
192
|
+
);
|
|
185
193
|
// Header reads are the original 4-arg call, unchanged.
|
|
186
|
-
expect(once).toContain(
|
|
187
|
-
|
|
194
|
+
expect(once).toContain(
|
|
195
|
+
"porf_native_fetch_read_value(name_value, &name_buf, &name_len, &name_owned);",
|
|
196
|
+
);
|
|
197
|
+
expect(once).toContain(
|
|
198
|
+
"porf_native_fetch_read_value(value_value, &value_buf, &value_len, &value_owned);",
|
|
199
|
+
);
|
|
188
200
|
|
|
189
201
|
await patchUwebsockets(root);
|
|
190
202
|
expect(await readFile(join(root, "compiler/uwebsockets.js"), "utf8")).toBe(once);
|
|
@@ -240,60 +252,3 @@ test("#165: render.js routes console output to stderr, unbuffered, idempotently"
|
|
|
240
252
|
await rm(root, { recursive: true, force: true });
|
|
241
253
|
}
|
|
242
254
|
});
|
|
243
|
-
|
|
244
|
-
// The part of Porffor's compiler/builtins/promise.ts the #168 patch anchors to.
|
|
245
|
-
const PROMISE_TS = `export const __Porffor_promise_resolve = (value: any, promise: any): void => {
|
|
246
|
-
if (Porffor.type(value) == Porffor.TYPES.object) {
|
|
247
|
-
// cheap prototype-chain probe for 'then' before the expensive Get below, does not invoke getters
|
|
248
|
-
const thenHash: i32 = __Porffor_object_hash('then');
|
|
249
|
-
let probe: any = value;
|
|
250
|
-
while (Porffor.type(probe) == Porffor.TYPES.object) {
|
|
251
|
-
if (Porffor.object.lookup(probe, 'then', thenHash) != 0) break;
|
|
252
|
-
probe = __Porffor_object_getPrototype(probe);
|
|
253
|
-
}
|
|
254
|
-
if (Porffor.type(probe) != Porffor.TYPES.object) {
|
|
255
|
-
__ecma262_FulfillPromise(promise, value);
|
|
256
|
-
return;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
};
|
|
260
|
-
`;
|
|
261
|
-
|
|
262
|
-
test("#168: promise-resolve's then-probe gets a fixed-point guard, idempotently", async () => {
|
|
263
|
-
const root = await mkdtemp(join(tmpdir(), "sb-patch-promise-"));
|
|
264
|
-
try {
|
|
265
|
-
await mkdir(join(root, "compiler/builtins"), { recursive: true });
|
|
266
|
-
await writeFile(join(root, "compiler/builtins/promise.ts"), PROMISE_TS);
|
|
267
|
-
await patchPromiseTs(root);
|
|
268
|
-
const once = await readFile(join(root, "compiler/builtins/promise.ts"), "utf8");
|
|
269
|
-
|
|
270
|
-
expect(once).toContain("sproutboat #168");
|
|
271
|
-
expect(once).toContain("let probeFound: boolean = false;");
|
|
272
|
-
expect(once).toContain("if (Porffor.object.lookup(probe, 'then', thenHash) != 0) { probeFound = true; break; }");
|
|
273
|
-
// The fixed-point guard mirrors _internal_object.ts's lastProto idiom.
|
|
274
|
-
expect(once).toContain("Porffor.fastOr(probe == null, Porffor.IR.ptr(probe) == Porffor.IR.ptr(lastProto))");
|
|
275
|
-
expect(once).toContain("if (!probeFound) {");
|
|
276
|
-
// Belt-and-suspenders: a hard iteration cap terminates the loop even if
|
|
277
|
-
// some other corruption shape (a drifting pointer, a longer cycle) defeats
|
|
278
|
-
// the fixed-point check above.
|
|
279
|
-
expect(once).toContain("if (probeSteps > 64) break;");
|
|
280
|
-
// The old type-check-only exit condition is gone.
|
|
281
|
-
expect(once).not.toContain("if (Porffor.type(probe) != Porffor.TYPES.object) {");
|
|
282
|
-
|
|
283
|
-
await patchPromiseTs(root);
|
|
284
|
-
expect(await readFile(join(root, "compiler/builtins/promise.ts"), "utf8")).toBe(once);
|
|
285
|
-
} finally {
|
|
286
|
-
await rm(root, { recursive: true, force: true });
|
|
287
|
-
}
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
test("#168: a drifted promise builtin fails loudly instead of silently no-op'ing", async () => {
|
|
291
|
-
const root = await mkdtemp(join(tmpdir(), "sb-patch-promise-drift-"));
|
|
292
|
-
try {
|
|
293
|
-
await mkdir(join(root, "compiler/builtins"), { recursive: true });
|
|
294
|
-
await writeFile(join(root, "compiler/builtins/promise.ts"), "// nothing the patch recognizes\n");
|
|
295
|
-
await expect(patchPromiseTs(root)).rejects.toThrow(/anchor not found/);
|
|
296
|
-
} finally {
|
|
297
|
-
await rm(root, { recursive: true, force: true });
|
|
298
|
-
}
|
|
299
|
-
});
|
package/src/patch.ts
CHANGED
|
@@ -108,7 +108,8 @@ const BYTESTRING_MARKER = "sproutboat #172";
|
|
|
108
108
|
* below) calls it, gated on the reserved `x-sb-raw-body` response header the
|
|
109
109
|
* assets binding sets. Every existing call site is untouched.
|
|
110
110
|
*/
|
|
111
|
-
const READ_RAW_ANCHOR =
|
|
111
|
+
const READ_RAW_ANCHOR =
|
|
112
|
+
"int porf_native_fetch_read_value(jsval value, const char** out_buf, size_t* out_len, char** out_owned) {";
|
|
112
113
|
const READ_RAW_INJECT =
|
|
113
114
|
"// sproutboat #176: zero-copy passthrough for a bytestring that is already-\n" +
|
|
114
115
|
"// finished bytes (an asset read off disk), never a string to UTF-8 encode.\n" +
|
|
@@ -208,7 +209,8 @@ const STATUS_SIG_MARKER = "static std::string lookup_status_line(i32 status) {";
|
|
|
208
209
|
// 303 is the one this was reported for (POST-redirect-GET); give it the real
|
|
209
210
|
// reason phrase. Everything else unlisted rides the synthesized fallback below.
|
|
210
211
|
const STATUS_303_ANCHOR = ' case 302: return "302 Found";\n';
|
|
211
|
-
const STATUS_303_INJECT =
|
|
212
|
+
const STATUS_303_INJECT =
|
|
213
|
+
' case 302: return "302 Found";\n case 303: return "303 See Other";\n';
|
|
212
214
|
const STATUS_303_MARKER = 'case 303: return "303 See Other";';
|
|
213
215
|
const STATUS_DEFAULT_ANCHOR = " default: return {};";
|
|
214
216
|
const STATUS_DEFAULT_INJECT = ' default: return std::to_string(status) + " Status";';
|
|
@@ -225,7 +227,8 @@ const STATUS_DEFAULT_MARKER = 'std::to_string(status) + " Status"';
|
|
|
225
227
|
* `request.cf.clientIp` and resolves it against `SB_TRUSTED_PROXIES` if set.
|
|
226
228
|
*/
|
|
227
229
|
const HDR_SIG_ANCHOR = "static i32 collect_headers(uWS::HttpRequest* req) {\n";
|
|
228
|
-
const HDR_SIG_INJECT =
|
|
230
|
+
const HDR_SIG_INJECT =
|
|
231
|
+
"static i32 collect_headers(uWS::HttpRequest* req, uWS::HttpResponse<false>* res) {\n";
|
|
229
232
|
const HDR_SIG_MARKER = "collect_headers(uWS::HttpRequest* req, uWS::HttpResponse";
|
|
230
233
|
|
|
231
234
|
const HDR_CALL_ANCHOR = "const i32 headers_ptr = collect_headers(req);";
|
|
@@ -361,7 +364,7 @@ const WRITE_RESPONSE_INJECT =
|
|
|
361
364
|
" size_t scan_bytes = 0;\n" +
|
|
362
365
|
" char* scan_owned = nullptr;\n" +
|
|
363
366
|
" porf_native_fetch_read_value(scan_name, &scan_buf, &scan_bytes, &scan_owned);\n" +
|
|
364
|
-
|
|
367
|
+
' if (std::string_view(scan_buf, scan_bytes) == "x-sb-raw-body") raw_body = true;\n' +
|
|
365
368
|
" if (scan_owned) free(scan_owned);\n" +
|
|
366
369
|
" }\n" +
|
|
367
370
|
" }\n" +
|
|
@@ -410,75 +413,6 @@ const WRITE_RESPONSE_INJECT =
|
|
|
410
413
|
"}";
|
|
411
414
|
const WRITE_RESPONSE_MARKER = "porf_native_fetch_read_raw_bytes(body_value";
|
|
412
415
|
|
|
413
|
-
/**
|
|
414
|
-
* baronunread/sproutboat#168 — `__Porffor_promise_resolve`'s duck-typing probe
|
|
415
|
-
* for `.then` walks a value's prototype chain with no termination guard. Under
|
|
416
|
-
* certain allocator conditions `__Porffor_object_getPrototype` returns a stale
|
|
417
|
-
* "object" jsval instead of the `null`/`undefined` that should end the chain,
|
|
418
|
-
* so the walk never bottoms out — a true infinite spin (100% CPU, no error, no
|
|
419
|
-
* log line) that wedges the whole process, since native-fetch serves one
|
|
420
|
-
* request at a time on a single event loop. Hits any handler whose `fetch`
|
|
421
|
-
* resolves a promise with a plain object — the common shape for a JSON
|
|
422
|
-
* response — so this is not a rare pattern; onset is nondeterministic
|
|
423
|
-
* (allocator/pool reuse), typically after a handful of requests.
|
|
424
|
-
*
|
|
425
|
-
* `_internal_object.ts`'s own prototype-chain walks already guard against
|
|
426
|
-
* exactly this failure mode: track the previous prototype and stop once the
|
|
427
|
-
* "next" pointer stops advancing (a fixed point reads the same as reaching the
|
|
428
|
-
* end). This probe has no such guard. Mirror the same idiom here: an explicit
|
|
429
|
-
* `probeFound` flag (so a fixed-point break reads as "no `.then` found",
|
|
430
|
-
* matching how a legitimate null-terminated chain is read) plus the
|
|
431
|
-
* `lastProto` pointer comparison used everywhere else in the runtime.
|
|
432
|
-
*
|
|
433
|
-
* A hard iteration cap rides alongside the fixed-point check, not instead of
|
|
434
|
-
* it: the lldb trace showed the *same* stale pointer on every sample, which
|
|
435
|
-
* the fixed-point check alone catches on its very next iteration, but that's
|
|
436
|
-
* one observed corruption shape, not a guarantee about every allocator state
|
|
437
|
-
* that can produce this bug. A cap makes termination unconditional regardless
|
|
438
|
-
* of whether some other corrupted state instead drifts (a different bad
|
|
439
|
-
* pointer each time) or cycles across more than one node — real prototype
|
|
440
|
-
* chains are a handful of links deep, so 64 iterations is generous headroom
|
|
441
|
-
* with no risk of cutting off a legitimate lookup.
|
|
442
|
-
*/
|
|
443
|
-
const THEN_PROBE_ANCHOR =
|
|
444
|
-
" const thenHash: i32 = __Porffor_object_hash('then');\n" +
|
|
445
|
-
" let probe: any = value;\n" +
|
|
446
|
-
" while (Porffor.type(probe) == Porffor.TYPES.object) {\n" +
|
|
447
|
-
" if (Porffor.object.lookup(probe, 'then', thenHash) != 0) break;\n" +
|
|
448
|
-
" probe = __Porffor_object_getPrototype(probe);\n" +
|
|
449
|
-
" }\n" +
|
|
450
|
-
" if (Porffor.type(probe) != Porffor.TYPES.object) {\n";
|
|
451
|
-
const THEN_PROBE_INJECT =
|
|
452
|
-
" const thenHash: i32 = __Porffor_object_hash('then');\n" +
|
|
453
|
-
" let probe: any = value;\n" +
|
|
454
|
-
" let lastProto: any = probe;\n" +
|
|
455
|
-
" let probeFound: boolean = false; // sproutboat #168: fixed-point chain reads as \"not found\", not a spin\n" +
|
|
456
|
-
" let probeSteps: i32 = 0; // sproutboat #168: hard cap, belt-and-suspenders alongside the fixed-point check\n" +
|
|
457
|
-
" while (Porffor.type(probe) == Porffor.TYPES.object) {\n" +
|
|
458
|
-
" if (Porffor.object.lookup(probe, 'then', thenHash) != 0) { probeFound = true; break; }\n" +
|
|
459
|
-
" probe = __Porffor_object_getPrototype(probe);\n" +
|
|
460
|
-
" if (Porffor.fastOr(probe == null, Porffor.IR.ptr(probe) == Porffor.IR.ptr(lastProto))) break;\n" +
|
|
461
|
-
" lastProto = probe;\n" +
|
|
462
|
-
" probeSteps++;\n" +
|
|
463
|
-
" if (probeSteps > 64) break;\n" +
|
|
464
|
-
" }\n" +
|
|
465
|
-
" if (!probeFound) {\n";
|
|
466
|
-
const THEN_PROBE_MARKER = "sproutboat #168";
|
|
467
|
-
|
|
468
|
-
/** The promise builtin: the #168 `.then`-probe livelock fix. Exported for tests. */
|
|
469
|
-
export async function patchPromiseTs(root: string): Promise<void> {
|
|
470
|
-
const file = resolve(root, "compiler/builtins/promise.ts");
|
|
471
|
-
let src = await readFile(file, "utf8");
|
|
472
|
-
if (src.includes(THEN_PROBE_MARKER)) return;
|
|
473
|
-
if (!src.includes(THEN_PROBE_ANCHOR)) {
|
|
474
|
-
throw new Error(
|
|
475
|
-
"could not patch Porffor's promise-resolve then-probe (#168): anchor not found in " +
|
|
476
|
-
`${file}. Porffor's promise builtin changed — check patches/UPSTREAM.md.`,
|
|
477
|
-
);
|
|
478
|
-
}
|
|
479
|
-
await writeFile(file, src.replace(THEN_PROBE_ANCHOR, THEN_PROBE_INJECT));
|
|
480
|
-
}
|
|
481
|
-
|
|
482
416
|
const done = new Set<string>();
|
|
483
417
|
|
|
484
418
|
/** Edits to Porffor's uWebSockets shim: `[marker, anchor, inject, what]`. */
|
|
@@ -486,15 +420,30 @@ const UWS_EDITS = [
|
|
|
486
420
|
[BODY_MARKER, BODY_ANCHOR, BODY_INJECT, "request body limit"],
|
|
487
421
|
[STATUS_SIG_MARKER, STATUS_SIG_ANCHOR, STATUS_SIG_INJECT, "status-line return type (#156)"],
|
|
488
422
|
[STATUS_303_MARKER, STATUS_303_ANCHOR, STATUS_303_INJECT, "status-line 303 case (#156)"],
|
|
489
|
-
[
|
|
423
|
+
[
|
|
424
|
+
STATUS_DEFAULT_MARKER,
|
|
425
|
+
STATUS_DEFAULT_ANCHOR,
|
|
426
|
+
STATUS_DEFAULT_INJECT,
|
|
427
|
+
"status-line fallback (#156)",
|
|
428
|
+
],
|
|
490
429
|
[HDR_SIG_MARKER, HDR_SIG_ANCHOR, HDR_SIG_INJECT, "collect_headers res arg (#163)"],
|
|
491
430
|
[HDR_CALL_MARKER, HDR_CALL_ANCHOR, HDR_CALL_INJECT, "collect_headers call site (#163)"],
|
|
492
431
|
[HDR_CAP_MARKER, HDR_CAP_ANCHOR, HDR_CAP_INJECT, "remote-addr header capacity (#163)"],
|
|
493
432
|
[HDR_SKIP_MARKER, HDR_SKIP_ANCHOR, HDR_SKIP_INJECT, "drop client-sent x-sb-remote-addr (#163)"],
|
|
494
433
|
[HDR_APPEND_MARKER, HDR_APPEND_ANCHOR, HDR_APPEND_INJECT, "append x-sb-remote-addr (#163)"],
|
|
495
434
|
[READ_RAW_DECL_MARKER, READ_RAW_DECL_ANCHOR, READ_RAW_DECL_INJECT, "read_raw_bytes decl (#176)"],
|
|
496
|
-
[
|
|
497
|
-
|
|
435
|
+
[
|
|
436
|
+
FORBIDDEN_HDR_MARKER,
|
|
437
|
+
FORBIDDEN_HDR_ANCHOR,
|
|
438
|
+
FORBIDDEN_HDR_INJECT,
|
|
439
|
+
"drop x-sb-raw-body from the wire (#176)",
|
|
440
|
+
],
|
|
441
|
+
[
|
|
442
|
+
WRITE_RESPONSE_MARKER,
|
|
443
|
+
WRITE_RESPONSE_ANCHOR,
|
|
444
|
+
WRITE_RESPONSE_INJECT,
|
|
445
|
+
"detect x-sb-raw-body, steer the body read (#176)",
|
|
446
|
+
],
|
|
498
447
|
] as const;
|
|
499
448
|
|
|
500
449
|
/** The uWebSockets shim source: body limit + the #156 status-line fix. Exported for tests. */
|
|
@@ -589,6 +538,5 @@ export async function ensurePorfforPatched(root: string): Promise<void> {
|
|
|
589
538
|
await patchCompilerArgs(root);
|
|
590
539
|
await patchUwebsockets(root);
|
|
591
540
|
await patchRenderJs(root);
|
|
592
|
-
await patchPromiseTs(root);
|
|
593
541
|
done.add(root);
|
|
594
542
|
}
|
package/src/pin.ts
CHANGED
|
@@ -10,13 +10,14 @@
|
|
|
10
10
|
* uWebSockets archive in `sproutboat-cli/vendor/` — then run both repos'
|
|
11
11
|
* test + conformance suites. See sproutboat-cli/MIGRATION.md.
|
|
12
12
|
*/
|
|
13
|
-
export const PORFFOR_CHANNEL = "alpha-
|
|
14
|
-
export const PORFFOR_COMMIT_FULL = "
|
|
13
|
+
export const PORFFOR_CHANNEL = "alpha-6";
|
|
14
|
+
export const PORFFOR_COMMIT_FULL = "038f415e08efc5f87a6bfcb05a18824caa3a14f6";
|
|
15
15
|
export const PORFFOR_COMMIT = PORFFOR_COMMIT_FULL.slice(0, 7);
|
|
16
|
-
export const PORFFOR_ARCHIVE_SHA256 =
|
|
16
|
+
export const PORFFOR_ARCHIVE_SHA256 =
|
|
17
|
+
"61f65d8fac5f94a7910f0a3f046e8929a852addb0033a032b9f7e08d0b07df5c";
|
|
17
18
|
export const PORFFOR_ARCHIVE_URL = `https://codeload.github.com/CanadaHonk/porffor/tar.gz/${PORFFOR_COMMIT_FULL}`;
|
|
18
19
|
|
|
19
|
-
/** A compact identity string for a manifest / report (`alpha-
|
|
20
|
+
/** A compact identity string for a manifest / report (`alpha-6 (038f415)`). */
|
|
20
21
|
export function porfforVersion(): string {
|
|
21
22
|
return process.env.PORFFOR_VERSION || `${PORFFOR_CHANNEL} (${PORFFOR_COMMIT})`;
|
|
22
23
|
}
|
|
Binary file
|
|
Binary file
|