11cb0ef41Sopenharmony_ci// Copyright Joyent, Inc. and other Node contributors. 21cb0ef41Sopenharmony_ci// 31cb0ef41Sopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a 41cb0ef41Sopenharmony_ci// copy of this software and associated documentation files (the 51cb0ef41Sopenharmony_ci// "Software"), to deal in the Software without restriction, including 61cb0ef41Sopenharmony_ci// without limitation the rights to use, copy, modify, merge, publish, 71cb0ef41Sopenharmony_ci// distribute, sublicense, and/or sell copies of the Software, and to permit 81cb0ef41Sopenharmony_ci// persons to whom the Software is furnished to do so, subject to the 91cb0ef41Sopenharmony_ci// following conditions: 101cb0ef41Sopenharmony_ci// 111cb0ef41Sopenharmony_ci// The above copyright notice and this permission notice shall be included 121cb0ef41Sopenharmony_ci// in all copies or substantial portions of the Software. 131cb0ef41Sopenharmony_ci// 141cb0ef41Sopenharmony_ci// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 151cb0ef41Sopenharmony_ci// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 161cb0ef41Sopenharmony_ci// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 171cb0ef41Sopenharmony_ci// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 181cb0ef41Sopenharmony_ci// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 191cb0ef41Sopenharmony_ci// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 201cb0ef41Sopenharmony_ci// USE OR OTHER DEALINGS IN THE SOFTWARE. 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ci'use strict'; 231cb0ef41Sopenharmony_ciconst common = require('../common'); 241cb0ef41Sopenharmony_ciif (!common.hasCrypto) 251cb0ef41Sopenharmony_ci common.skip('missing crypto'); 261cb0ef41Sopenharmony_ci 271cb0ef41Sopenharmony_ciconst assert = require('assert'); 281cb0ef41Sopenharmony_ciconst crypto = require('crypto'); 291cb0ef41Sopenharmony_ciconst stream = require('stream'); 301cb0ef41Sopenharmony_ciconst zlib = require('zlib'); 311cb0ef41Sopenharmony_ci 321cb0ef41Sopenharmony_ciconst Stream = stream.Stream; 331cb0ef41Sopenharmony_ci 341cb0ef41Sopenharmony_ci// Emit random bytes, and keep a shasum 351cb0ef41Sopenharmony_ciclass RandomReadStream extends Stream { 361cb0ef41Sopenharmony_ci constructor(opt) { 371cb0ef41Sopenharmony_ci super(); 381cb0ef41Sopenharmony_ci 391cb0ef41Sopenharmony_ci this.readable = true; 401cb0ef41Sopenharmony_ci this._paused = false; 411cb0ef41Sopenharmony_ci this._processing = false; 421cb0ef41Sopenharmony_ci 431cb0ef41Sopenharmony_ci this._hasher = crypto.createHash('sha1'); 441cb0ef41Sopenharmony_ci opt = opt || {}; 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ci // base block size. 471cb0ef41Sopenharmony_ci opt.block = opt.block || 256 * 1024; 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_ci // Total number of bytes to emit 501cb0ef41Sopenharmony_ci opt.total = opt.total || 256 * 1024 * 1024; 511cb0ef41Sopenharmony_ci this._remaining = opt.total; 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_ci // How variable to make the block sizes 541cb0ef41Sopenharmony_ci opt.jitter = opt.jitter || 1024; 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_ci this._opt = opt; 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ci this._process = this._process.bind(this); 591cb0ef41Sopenharmony_ci 601cb0ef41Sopenharmony_ci process.nextTick(this._process); 611cb0ef41Sopenharmony_ci } 621cb0ef41Sopenharmony_ci 631cb0ef41Sopenharmony_ci pause() { 641cb0ef41Sopenharmony_ci this._paused = true; 651cb0ef41Sopenharmony_ci this.emit('pause'); 661cb0ef41Sopenharmony_ci } 671cb0ef41Sopenharmony_ci 681cb0ef41Sopenharmony_ci resume() { 691cb0ef41Sopenharmony_ci // console.error("rrs resume"); 701cb0ef41Sopenharmony_ci this._paused = false; 711cb0ef41Sopenharmony_ci this.emit('resume'); 721cb0ef41Sopenharmony_ci this._process(); 731cb0ef41Sopenharmony_ci } 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ci _process() { 761cb0ef41Sopenharmony_ci if (this._processing) return; 771cb0ef41Sopenharmony_ci if (this._paused) return; 781cb0ef41Sopenharmony_ci 791cb0ef41Sopenharmony_ci this._processing = true; 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_ci if (!this._remaining) { 821cb0ef41Sopenharmony_ci this._hash = this._hasher.digest('hex').toLowerCase().trim(); 831cb0ef41Sopenharmony_ci this._processing = false; 841cb0ef41Sopenharmony_ci 851cb0ef41Sopenharmony_ci this.emit('end'); 861cb0ef41Sopenharmony_ci return; 871cb0ef41Sopenharmony_ci } 881cb0ef41Sopenharmony_ci 891cb0ef41Sopenharmony_ci // Figure out how many bytes to output 901cb0ef41Sopenharmony_ci // if finished, then just emit end. 911cb0ef41Sopenharmony_ci let block = this._opt.block; 921cb0ef41Sopenharmony_ci const jitter = this._opt.jitter; 931cb0ef41Sopenharmony_ci if (jitter) { 941cb0ef41Sopenharmony_ci block += Math.ceil(Math.random() * jitter - (jitter / 2)); 951cb0ef41Sopenharmony_ci } 961cb0ef41Sopenharmony_ci block = Math.min(block, this._remaining); 971cb0ef41Sopenharmony_ci const buf = Buffer.allocUnsafe(block); 981cb0ef41Sopenharmony_ci for (let i = 0; i < block; i++) { 991cb0ef41Sopenharmony_ci buf[i] = Math.random() * 256; 1001cb0ef41Sopenharmony_ci } 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ci this._hasher.update(buf); 1031cb0ef41Sopenharmony_ci 1041cb0ef41Sopenharmony_ci this._remaining -= block; 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_ci this._processing = false; 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci this.emit('data', buf); 1091cb0ef41Sopenharmony_ci process.nextTick(this._process); 1101cb0ef41Sopenharmony_ci } 1111cb0ef41Sopenharmony_ci} 1121cb0ef41Sopenharmony_ci 1131cb0ef41Sopenharmony_ci// A filter that just verifies a shasum 1141cb0ef41Sopenharmony_ciclass HashStream extends Stream { 1151cb0ef41Sopenharmony_ci constructor() { 1161cb0ef41Sopenharmony_ci super(); 1171cb0ef41Sopenharmony_ci this.readable = this.writable = true; 1181cb0ef41Sopenharmony_ci this._hasher = crypto.createHash('sha1'); 1191cb0ef41Sopenharmony_ci } 1201cb0ef41Sopenharmony_ci 1211cb0ef41Sopenharmony_ci write(c) { 1221cb0ef41Sopenharmony_ci // Simulate the way that an fs.ReadStream returns false 1231cb0ef41Sopenharmony_ci // on *every* write, only to resume a moment later. 1241cb0ef41Sopenharmony_ci this._hasher.update(c); 1251cb0ef41Sopenharmony_ci process.nextTick(() => this.resume()); 1261cb0ef41Sopenharmony_ci return false; 1271cb0ef41Sopenharmony_ci } 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_ci resume() { 1301cb0ef41Sopenharmony_ci this.emit('resume'); 1311cb0ef41Sopenharmony_ci process.nextTick(() => this.emit('drain')); 1321cb0ef41Sopenharmony_ci } 1331cb0ef41Sopenharmony_ci 1341cb0ef41Sopenharmony_ci end(c) { 1351cb0ef41Sopenharmony_ci if (c) { 1361cb0ef41Sopenharmony_ci this.write(c); 1371cb0ef41Sopenharmony_ci } 1381cb0ef41Sopenharmony_ci this._hash = this._hasher.digest('hex').toLowerCase().trim(); 1391cb0ef41Sopenharmony_ci this.emit('data', this._hash); 1401cb0ef41Sopenharmony_ci this.emit('end'); 1411cb0ef41Sopenharmony_ci } 1421cb0ef41Sopenharmony_ci} 1431cb0ef41Sopenharmony_ci 1441cb0ef41Sopenharmony_cifor (const [ createCompress, createDecompress ] of [ 1451cb0ef41Sopenharmony_ci [ zlib.createGzip, zlib.createGunzip ], 1461cb0ef41Sopenharmony_ci [ zlib.createBrotliCompress, zlib.createBrotliDecompress ], 1471cb0ef41Sopenharmony_ci]) { 1481cb0ef41Sopenharmony_ci const inp = new RandomReadStream({ total: 1024, block: 256, jitter: 16 }); 1491cb0ef41Sopenharmony_ci const out = new HashStream(); 1501cb0ef41Sopenharmony_ci const gzip = createCompress(); 1511cb0ef41Sopenharmony_ci const gunz = createDecompress(); 1521cb0ef41Sopenharmony_ci 1531cb0ef41Sopenharmony_ci inp.pipe(gzip).pipe(gunz).pipe(out); 1541cb0ef41Sopenharmony_ci 1551cb0ef41Sopenharmony_ci out.on('data', common.mustCall((c) => { 1561cb0ef41Sopenharmony_ci assert.strictEqual(c, inp._hash, `Hash '${c}' equals '${inp._hash}'.`); 1571cb0ef41Sopenharmony_ci })); 1581cb0ef41Sopenharmony_ci} 159