Read zlib options held in typed objects (#1316)

This commit is contained in:
Chris Tate
2026-10-18 14:24:54 -05:00
committed by GitHub
5 changed files with 88 additions and 0 deletions
@@ -0,0 +1,6 @@
{
"order": [
"<repo>/tests/corpus/5633-zlib-typed-options.ts"
],
"diags": []
}
+15
View File
@@ -420,7 +420,22 @@ void scr_zlib_options_drop(ScrZlibOptions *o) {
o->dict = NULL;
}
static bool scr_zlib_options_parse_object(int mode, const ScrDyn *opts, ScrZlibOptions *out);
/* A typed options object (a record that crossed into a checked-dynamic
* slot by reference) is read through its materialized view, as a plain
* object is. */
bool scr_zlib_options_parse(int mode, const ScrDyn *opts, ScrZlibOptions *out) {
if (opts == NULL || opts->kind != SCR_DYN_TYPED_REF) return scr_zlib_options_parse_object(mode, opts, out);
ScrDyn *view = scr_dyn_typed_ref_materialize(opts);
bool ok = false;
if (scr_exc_pending()) memset(out, 0, sizeof *out);
else ok = scr_zlib_options_parse_object(mode, view, out);
scr_dyn_release(view);
return ok;
}
static bool scr_zlib_options_parse_object(int mode, const ScrDyn *opts, ScrZlibOptions *out) {
memset(out, 0, sizeof *out);
out->window_bits = 15;
out->level = Z_DEFAULT_COMPRESSION;
+7
View File
@@ -431,6 +431,13 @@ static const char *scr_zs_class_name(int mode) {
}
ScrStream *scr_zlib_stream_new(double mode_d, ScrDyn *opts) {
/* A typed options object is read through its materialized view. */
if (opts != NULL && opts->kind == SCR_DYN_TYPED_REF) {
ScrDyn *view = scr_dyn_typed_ref_materialize(opts);
ScrStream *stream = scr_exc_pending() ? NULL : scr_zlib_stream_new(mode_d, view);
scr_dyn_release(view);
return stream;
}
int mode = (int)mode_d;
const ScrDyn *o = opts != NULL && scr_dyn_truthy(opts) ? opts : NULL;
ScrZlibOptions zo;
+58
View File
@@ -0,0 +1,58 @@
// zlib options held in a typed object (a cast object literal that crosses
// into the options slot by reference) are read like a plain options
// object: levels, windowBits and strategies apply, and out-of-range values
// throw Node's ERR_OUT_OF_RANGE from the sync, callback, promisified and
// stream forms.
import * as zlib from "node:zlib";
import { promisify } from "node:util";
const data = Buffer.from("hello hello hello hello hello");
const stored = { level: 0 } as zlib.ZlibOptions;
const fast = { level: 1 } as zlib.ZlibOptions;
const huffman = { strategy: zlib.constants.Z_HUFFMAN_ONLY } as zlib.ZlibOptions;
const smallWindow = { windowBits: 9, memLevel: 1 } as zlib.ZlibOptions;
const badLevel = { level: 99 } as zlib.ZlibOptions;
const badWindow = { windowBits: 3 } as zlib.ZlibOptions;
function attempt(label: string, run: () => void): void {
try {
run();
console.log(label, "ok");
} catch (e) {
const err = e as NodeJS.ErrnoException;
console.log(label, err.name, err.code, err.message);
}
}
console.log("sync stored", zlib.deflateSync(data, stored).toString("hex"));
console.log("sync fast", zlib.deflateSync(data, fast).toString("hex"));
console.log("sync huffman", zlib.deflateSync(data, huffman).toString("hex"));
console.log("raw small window", zlib.deflateRawSync(data, smallWindow).toString("hex"));
console.log("gzip stored", zlib.gzipSync(data, stored).subarray(10).toString("hex"));
attempt("sync bad level", () => zlib.deflateSync(data, badLevel));
attempt("sync bad window", () => zlib.inflateSync(zlib.deflateSync(data), badWindow));
attempt("callback bad level", () => zlib.gzip(data, badLevel, () => console.log("not called")));
attempt("stream bad level", () => zlib.createDeflate(badLevel));
const deflateAsync = promisify(zlib.deflate);
async function main(): Promise<void> {
const viaCallback = await new Promise<Buffer>((resolve, reject) =>
zlib.deflate(data, stored, (err, out) => (err ? reject(err) : resolve(out))),
);
console.log("callback stored", viaCallback.toString("hex"));
console.log("promise stored", (await deflateAsync(data, stored)).toString("hex"));
try {
await deflateAsync(data, badLevel);
console.log("promise bad level fulfilled");
} catch (e) {
console.log("promise bad level", (e as NodeJS.ErrnoException).code);
}
const stream = zlib.createDeflate(fast);
const parts: Buffer[] = [];
stream.on("data", (chunk: Buffer) => parts.push(chunk));
stream.on("end", () => console.log("stream fast", Buffer.concat(parts).toString("hex")));
stream.end(data);
}
main().catch((e) => console.log("unexpected", String(e)));
+2
View File
@@ -1976,6 +1976,7 @@
"5630-promisify-zlib.ts": 2503,
"5631-promisify-crypto.ts": 2200,
"5632-promisify-dns.ts": 1700,
"5633-zlib-typed-options.ts": 1800,
"5644-net-socket-addresses.ts": 2220,
"5645-net-socket-callbacks.ts": 2442,
"5646-net-server-connections.ts": 2389,
@@ -5012,6 +5013,7 @@
"5630-promisify-zlib.ts": 3392,
"5631-promisify-crypto.ts": 2600,
"5632-promisify-dns.ts": 2000,
"5633-zlib-typed-options.ts": 2200,
"5644-net-socket-addresses.ts": 2393,
"5645-net-socket-callbacks.ts": 2060,
"5646-net-server-connections.ts": 2755,