2024-11-29 15:55:03 -05:00
|
|
|
|
// Flags: --no-warnings
|
2017-01-03 13:16:48 -08:00
|
|
|
|
// Copyright Joyent, Inc. and other Node contributors.
|
|
|
|
|
//
|
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
// copy of this software and associated documentation files (the
|
|
|
|
|
// "Software"), to deal in the Software without restriction, including
|
|
|
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
|
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
|
|
|
|
// persons to whom the Software is furnished to do so, subject to the
|
|
|
|
|
// following conditions:
|
|
|
|
|
//
|
|
|
|
|
// The above copyright notice and this permission notice shall be included
|
|
|
|
|
// in all copies or substantial portions of the Software.
|
|
|
|
|
//
|
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
|
|
|
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
|
|
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
|
|
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
|
|
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
2015-05-19 13:00:06 +02:00
|
|
|
|
'use strict';
|
2016-09-17 14:39:36 +02:00
|
|
|
|
const common = require('../common');
|
|
|
|
|
const assert = require('assert');
|
|
|
|
|
const zlib = require('zlib');
|
2016-11-10 11:26:20 -08:00
|
|
|
|
const stream = require('stream');
|
2017-10-13 01:10:44 -04:00
|
|
|
|
const fs = require('fs');
|
2017-07-17 15:33:46 -07:00
|
|
|
|
const fixtures = require('../common/fixtures');
|
2016-11-10 11:26:20 -08:00
|
|
|
|
|
2020-04-24 21:12:32 +02:00
|
|
|
|
// Should not segfault.
|
|
|
|
|
assert.throws(() => zlib.gzipSync(Buffer.alloc(0), { windowBits: 8 }), {
|
2020-04-24 21:12:32 +02:00
|
|
|
|
code: 'ERR_OUT_OF_RANGE',
|
|
|
|
|
name: 'RangeError',
|
|
|
|
|
message: 'The value of "options.windowBits" is out of range. ' +
|
|
|
|
|
'It must be >= 9 and <= 15. Received 8',
|
2020-04-24 21:12:32 +02:00
|
|
|
|
});
|
|
|
|
|
|
2017-01-08 13:19:00 +00:00
|
|
|
|
let zlibPairs = [
|
2016-11-10 11:26:20 -08:00
|
|
|
|
[zlib.Deflate, zlib.Inflate],
|
|
|
|
|
[zlib.Gzip, zlib.Gunzip],
|
|
|
|
|
[zlib.Deflate, zlib.Unzip],
|
|
|
|
|
[zlib.Gzip, zlib.Unzip],
|
2018-12-10 15:48:50 +01:00
|
|
|
|
[zlib.DeflateRaw, zlib.InflateRaw],
|
|
|
|
|
[zlib.BrotliCompress, zlib.BrotliDecompress],
|
2024-03-15 14:54:30 -07:00
|
|
|
|
[zlib.ZstdCompress, zlib.ZstdDecompress],
|
2016-11-10 11:26:20 -08:00
|
|
|
|
];
|
2011-09-06 16:13:05 -07:00
|
|
|
|
|
2019-01-21 01:22:27 +01:00
|
|
|
|
// How fast to trickle through the slowstream
|
2017-01-08 13:19:00 +00:00
|
|
|
|
let trickle = [128, 1024, 1024 * 1024];
|
2011-09-06 16:13:05 -07:00
|
|
|
|
|
2019-03-07 01:03:53 +01:00
|
|
|
|
// Tunable options for zlib classes.
|
2011-09-06 16:13:05 -07:00
|
|
|
|
|
|
|
|
|
// several different chunk sizes
|
2017-01-08 13:19:00 +00:00
|
|
|
|
let chunkSize = [128, 1024, 1024 * 16, 1024 * 1024];
|
2011-09-06 16:13:05 -07:00
|
|
|
|
|
2019-03-22 03:44:26 +01:00
|
|
|
|
// This is every possible value.
|
2017-01-08 13:19:00 +00:00
|
|
|
|
let level = [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
|
|
|
let windowBits = [8, 9, 10, 11, 12, 13, 14, 15];
|
|
|
|
|
let memLevel = [1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
|
|
|
let strategy = [0, 1, 2, 3, 4];
|
2011-09-06 16:13:05 -07:00
|
|
|
|
|
2018-12-10 13:27:32 +01:00
|
|
|
|
// It's nice in theory to test every combination, but it
|
2011-09-06 16:13:05 -07:00
|
|
|
|
// takes WAY too long. Maybe a pummel test could do this?
|
|
|
|
|
if (!process.env.PUMMEL) {
|
|
|
|
|
trickle = [1024];
|
|
|
|
|
chunkSize = [1024 * 16];
|
|
|
|
|
level = [6];
|
|
|
|
|
memLevel = [8];
|
|
|
|
|
windowBits = [15];
|
|
|
|
|
strategy = [0];
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-08 13:19:00 +00:00
|
|
|
|
let testFiles = ['person.jpg', 'elipses.txt', 'empty.txt'];
|
2011-09-17 23:03:23 -07:00
|
|
|
|
|
|
|
|
|
if (process.env.FAST) {
|
2011-10-04 18:08:18 -04:00
|
|
|
|
zlibPairs = [[zlib.Gzip, zlib.Unzip]];
|
2016-01-30 21:46:45 -08:00
|
|
|
|
testFiles = ['person.jpg'];
|
2011-09-17 23:03:23 -07:00
|
|
|
|
}
|
|
|
|
|
|
2016-11-10 11:26:20 -08:00
|
|
|
|
const tests = {};
|
2017-07-24 11:21:48 -07:00
|
|
|
|
testFiles.forEach(common.mustCall((file) => {
|
2017-07-17 15:33:46 -07:00
|
|
|
|
tests[file] = fixtures.readSync(file);
|
2017-07-24 11:21:48 -07:00
|
|
|
|
}, testFiles.length));
|
2011-09-06 16:13:05 -07:00
|
|
|
|
|
|
|
|
|
|
2019-03-22 03:44:26 +01:00
|
|
|
|
// Stream that saves everything
|
2017-07-24 11:21:48 -07:00
|
|
|
|
class BufferStream extends stream.Stream {
|
|
|
|
|
constructor() {
|
|
|
|
|
super();
|
|
|
|
|
this.chunks = [];
|
|
|
|
|
this.length = 0;
|
|
|
|
|
this.writable = true;
|
|
|
|
|
this.readable = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
write(c) {
|
|
|
|
|
this.chunks.push(c);
|
|
|
|
|
this.length += c.length;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
end(c) {
|
|
|
|
|
if (c) this.write(c);
|
|
|
|
|
// flatten
|
|
|
|
|
const buf = Buffer.allocUnsafe(this.length);
|
|
|
|
|
let i = 0;
|
|
|
|
|
this.chunks.forEach((c) => {
|
|
|
|
|
c.copy(buf, i);
|
|
|
|
|
i += c.length;
|
|
|
|
|
});
|
|
|
|
|
this.emit('data', buf);
|
|
|
|
|
this.emit('end');
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2011-09-06 16:13:05 -07:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-24 11:21:48 -07:00
|
|
|
|
class SlowStream extends stream.Stream {
|
|
|
|
|
constructor(trickle) {
|
|
|
|
|
super();
|
|
|
|
|
this.trickle = trickle;
|
|
|
|
|
this.offset = 0;
|
|
|
|
|
this.readable = this.writable = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
write() {
|
|
|
|
|
throw new Error('not implemented, just call ss.end(chunk)');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pause() {
|
|
|
|
|
this.paused = true;
|
|
|
|
|
this.emit('pause');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resume() {
|
|
|
|
|
const emit = () => {
|
|
|
|
|
if (this.paused) return;
|
|
|
|
|
if (this.offset >= this.length) {
|
|
|
|
|
this.ended = true;
|
|
|
|
|
return this.emit('end');
|
|
|
|
|
}
|
|
|
|
|
const end = Math.min(this.offset + this.trickle, this.length);
|
|
|
|
|
const c = this.chunk.slice(this.offset, end);
|
|
|
|
|
this.offset += c.length;
|
|
|
|
|
this.emit('data', c);
|
|
|
|
|
process.nextTick(emit);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (this.ended) return;
|
|
|
|
|
this.emit('resume');
|
|
|
|
|
if (!this.chunk) return;
|
|
|
|
|
this.paused = false;
|
|
|
|
|
emit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
end(chunk) {
|
2019-03-07 01:03:53 +01:00
|
|
|
|
// Walk over the chunk in blocks.
|
2017-07-24 11:21:48 -07:00
|
|
|
|
this.chunk = chunk;
|
|
|
|
|
this.length = chunk.length;
|
|
|
|
|
this.resume();
|
|
|
|
|
return this.ended;
|
|
|
|
|
}
|
2011-09-06 16:13:05 -07:00
|
|
|
|
}
|
|
|
|
|
|
2017-10-13 01:10:44 -04:00
|
|
|
|
// windowBits: 8 shouldn't throw
|
2018-02-09 02:32:04 +01:00
|
|
|
|
zlib.createDeflateRaw({ windowBits: 8 });
|
2017-10-13 01:10:44 -04:00
|
|
|
|
|
|
|
|
|
{
|
2018-01-04 17:03:44 -08:00
|
|
|
|
const node = fs.createReadStream(fixtures.path('person.jpg'));
|
2017-10-13 01:10:44 -04:00
|
|
|
|
const raw = [];
|
|
|
|
|
const reinflated = [];
|
|
|
|
|
node.on('data', (chunk) => raw.push(chunk));
|
|
|
|
|
|
|
|
|
|
// Usually, the inflate windowBits parameter needs to be at least the
|
|
|
|
|
// value of the matching deflate’s windowBits. However, inflate raw with
|
|
|
|
|
// windowBits = 8 should be able to handle compressed data from a source
|
|
|
|
|
// that does not know about the silent 8-to-9 upgrade of windowBits
|
2017-10-26 12:32:23 +02:00
|
|
|
|
// that most versions of zlib/Node perform, and which *still* results in
|
|
|
|
|
// a valid 8-bit-window zlib stream.
|
2017-10-13 01:10:44 -04:00
|
|
|
|
node.pipe(zlib.createDeflateRaw({ windowBits: 9 }))
|
|
|
|
|
.pipe(zlib.createInflateRaw({ windowBits: 8 }))
|
|
|
|
|
.on('data', (chunk) => reinflated.push(chunk))
|
|
|
|
|
.on('end', common.mustCall(
|
2020-03-02 17:02:08 +01:00
|
|
|
|
() => assert(Buffer.concat(raw).equals(Buffer.concat(reinflated)))))
|
|
|
|
|
.on('close', common.mustCall(1));
|
2017-10-13 01:10:44 -04:00
|
|
|
|
}
|
2011-09-06 16:13:05 -07:00
|
|
|
|
|
2018-12-10 13:27:32 +01:00
|
|
|
|
// For each of the files, make sure that compressing and
|
2011-09-06 16:13:05 -07:00
|
|
|
|
// decompressing results in the same data, for every combination
|
|
|
|
|
// of the options set above.
|
|
|
|
|
|
2017-07-24 11:21:48 -07:00
|
|
|
|
const testKeys = Object.keys(tests);
|
|
|
|
|
testKeys.forEach(common.mustCall((file) => {
|
2017-01-08 13:19:00 +00:00
|
|
|
|
const test = tests[file];
|
2017-07-24 11:21:48 -07:00
|
|
|
|
chunkSize.forEach(common.mustCall((chunkSize) => {
|
|
|
|
|
trickle.forEach(common.mustCall((trickle) => {
|
|
|
|
|
windowBits.forEach(common.mustCall((windowBits) => {
|
|
|
|
|
level.forEach(common.mustCall((level) => {
|
|
|
|
|
memLevel.forEach(common.mustCall((memLevel) => {
|
|
|
|
|
strategy.forEach(common.mustCall((strategy) => {
|
|
|
|
|
zlibPairs.forEach(common.mustCall((pair) => {
|
2017-01-08 13:19:00 +00:00
|
|
|
|
const Def = pair[0];
|
|
|
|
|
const Inf = pair[1];
|
2018-01-11 19:03:58 +01:00
|
|
|
|
const opts = { level, windowBits, memLevel, strategy };
|
2011-10-04 18:08:18 -04:00
|
|
|
|
|
2017-01-08 13:19:00 +00:00
|
|
|
|
const def = new Def(opts);
|
|
|
|
|
const inf = new Inf(opts);
|
|
|
|
|
const ss = new SlowStream(trickle);
|
|
|
|
|
const buf = new BufferStream();
|
2011-10-04 18:08:18 -04:00
|
|
|
|
|
2018-12-10 13:27:32 +01:00
|
|
|
|
// Verify that the same exact buffer comes out the other end.
|
2017-07-24 11:21:48 -07:00
|
|
|
|
buf.on('data', common.mustCall((c) => {
|
2017-04-28 04:06:42 +03:00
|
|
|
|
const msg = `${file} ${chunkSize} ${
|
2017-07-25 10:37:08 -07:00
|
|
|
|
JSON.stringify(opts)} ${Def.name} -> ${Inf.name}`;
|
2017-01-08 13:19:00 +00:00
|
|
|
|
let i;
|
|
|
|
|
for (i = 0; i < Math.max(c.length, test.length); i++) {
|
2011-10-04 18:08:18 -04:00
|
|
|
|
if (c[i] !== test[i]) {
|
2017-07-24 11:21:48 -07:00
|
|
|
|
assert.fail(msg);
|
2011-10-04 18:08:18 -04:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-07-24 11:21:48 -07:00
|
|
|
|
}));
|
2011-10-04 18:08:18 -04:00
|
|
|
|
|
2019-03-22 03:44:26 +01:00
|
|
|
|
// The magic happens here.
|
2011-10-04 18:08:18 -04:00
|
|
|
|
ss.pipe(def).pipe(inf).pipe(buf);
|
|
|
|
|
ss.end(test);
|
2017-07-24 11:21:48 -07:00
|
|
|
|
}, zlibPairs.length));
|
|
|
|
|
}, strategy.length));
|
|
|
|
|
}, memLevel.length));
|
|
|
|
|
}, level.length));
|
|
|
|
|
}, windowBits.length));
|
|
|
|
|
}, trickle.length));
|
|
|
|
|
}, chunkSize.length));
|
|
|
|
|
}, testKeys.length));
|
2024-11-29 15:55:03 -05:00
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
// Test instantiation without 'new'
|
|
|
|
|
common.expectWarning('DeprecationWarning', `Instantiating Gzip without the 'new' keyword has been deprecated.`, 'DEP0184');
|
|
|
|
|
const gzip = zlib.Gzip();
|
|
|
|
|
assert.ok(gzip instanceof zlib.Gzip);
|
|
|
|
|
}
|