mirror of
https://github.com/nodejs/node.git
synced 2026-11-09 15:11:11 -05:00
Pass rejectGarbageAfterEnd: true to createInflateRaw() and createBrotliDecompress(), matching the behavior already in place for deflate and gzip. The Compression Streams spec treats any data following a valid compressed payload as an error. When the underlying Node.js stream throws synchronously from write() (e.g. zlib rejects an invalid chunk type), destroy the stream so that the readable side is also errored. Without this, the readable side hangs forever waiting for data that will never arrive. Introduce a kValidateChunk callback option in the webstreams adapter layer. Compression streams use this to validate that chunks are BufferSource instances not backed by SharedArrayBuffer, replacing the previous monkey-patching of the underlying handle's write method. Unskip WPT compression bad-chunks tests which now run instead of hang and mark the remaining expected failures. PR-URL: https://github.com/nodejs/node/pull/62107 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Mattias Buelens <mattias@buelens.com> Reviewed-By: René <contact.9a5d6388@renegade334.me.uk>
87 lines
2.9 KiB
JavaScript
87 lines
2.9 KiB
JavaScript
'use strict';
|
|
require('../common');
|
|
const assert = require('assert');
|
|
const test = require('node:test');
|
|
const { CompressionStream, DecompressionStream } = require('stream/web');
|
|
|
|
// Verify that DecompressionStream rejects trailing data after a valid
|
|
// compressed payload for all four supported formats (deflate, deflate-raw, gzip, brotli).
|
|
|
|
const input = Buffer.from('hello');
|
|
const trailingJunk = Buffer.from([0xDE, 0xAD]);
|
|
|
|
async function compress(format, data) {
|
|
const cs = new CompressionStream(format);
|
|
const writer = cs.writable.getWriter();
|
|
writer.write(data);
|
|
writer.close();
|
|
const chunks = await Array.fromAsync(cs.readable);
|
|
return Buffer.concat(chunks.map((c) => Buffer.from(c)));
|
|
}
|
|
|
|
for (const format of ['deflate', 'deflate-raw', 'gzip', 'brotli']) {
|
|
test(`DecompressionStream rejects trailing junk for ${format}`, async () => {
|
|
const compressed = await compress(format, input);
|
|
const withJunk = Buffer.concat([compressed, trailingJunk]);
|
|
|
|
const ds = new DecompressionStream(format);
|
|
const writer = ds.writable.getWriter();
|
|
const reader = ds.readable.getReader();
|
|
|
|
writer.write(withJunk).catch(() => {});
|
|
writer.close().catch(() => {});
|
|
|
|
await assert.rejects(async () => {
|
|
const chunks = [];
|
|
while (true) {
|
|
const { done, value } = await reader.read();
|
|
if (done) break;
|
|
chunks.push(value);
|
|
}
|
|
}, (err) => {
|
|
assert(err instanceof Error, `Expected Error, got ${err?.constructor?.name}`);
|
|
return true;
|
|
});
|
|
});
|
|
|
|
test(`DecompressionStream accepts valid ${format} data without trailing junk`, async () => {
|
|
const compressed = await compress(format, input);
|
|
|
|
const ds = new DecompressionStream(format);
|
|
const writer = ds.writable.getWriter();
|
|
|
|
writer.write(compressed);
|
|
writer.close();
|
|
|
|
const chunks = await Array.fromAsync(ds.readable);
|
|
const result = Buffer.concat(chunks.map((c) => Buffer.from(c)));
|
|
assert.strictEqual(result.toString(), 'hello');
|
|
});
|
|
}
|
|
|
|
// Extra: Verify that trailing data is also rejected when passed as a separate
|
|
// chunk after the valid compressed data has been fully written.
|
|
for (const format of ['deflate', 'deflate-raw', 'gzip', 'brotli']) {
|
|
test(`DecompressionStream rejects trailing junk as separate chunk for ${format}`, async () => {
|
|
const compressed = await compress(format, input);
|
|
|
|
const ds = new DecompressionStream(format);
|
|
const writer = ds.writable.getWriter();
|
|
const reader = ds.readable.getReader();
|
|
|
|
writer.write(compressed).catch(() => {});
|
|
writer.write(trailingJunk).catch(() => {});
|
|
writer.close().catch(() => {});
|
|
|
|
await assert.rejects(async () => {
|
|
while (true) {
|
|
const { done } = await reader.read();
|
|
if (done) break;
|
|
}
|
|
}, (err) => {
|
|
assert(err instanceof Error, `Expected Error, got ${err?.constructor?.name}`);
|
|
return true;
|
|
});
|
|
});
|
|
}
|