69f88f2c06d07ccb97f9002209055c0f2f6c2e406159b2221f10f4091319a9675a3ad7d2b931679b3cf8cda2b64f23183e14db97a99b3b7e79c6a1eff5a3e7 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. 'use strict';
  2. const Buffer = require('buffer').Buffer;
  3. const Transform = require('stream').Transform;
  4. const binding = require('./binding');
  5. const util = require('util');
  6. const assert = require('assert').ok;
  7. const kMaxLength = require('buffer').kMaxLength;
  8. const kRangeErrorMessage = 'Cannot create final Buffer. It would be larger ' +
  9. 'than 0x' + kMaxLength.toString(16) + ' bytes';
  10. // zlib doesn't provide these, so kludge them in following the same
  11. // const naming scheme zlib uses.
  12. binding.Z_MIN_WINDOWBITS = 8;
  13. binding.Z_MAX_WINDOWBITS = 15;
  14. binding.Z_DEFAULT_WINDOWBITS = 15;
  15. // fewer than 64 bytes per chunk is stupid.
  16. // technically it could work with as few as 8, but even 64 bytes
  17. // is absurdly low. Usually a MB or more is best.
  18. binding.Z_MIN_CHUNK = 64;
  19. binding.Z_MAX_CHUNK = Infinity;
  20. binding.Z_DEFAULT_CHUNK = (16 * 1024);
  21. binding.Z_MIN_MEMLEVEL = 1;
  22. binding.Z_MAX_MEMLEVEL = 9;
  23. binding.Z_DEFAULT_MEMLEVEL = 8;
  24. binding.Z_MIN_LEVEL = -1;
  25. binding.Z_MAX_LEVEL = 9;
  26. binding.Z_DEFAULT_LEVEL = binding.Z_DEFAULT_COMPRESSION;
  27. // expose all the zlib constants
  28. const bkeys = Object.keys(binding);
  29. for (var bk = 0; bk < bkeys.length; bk++) {
  30. var bkey = bkeys[bk];
  31. if (bkey.match(/^Z/)) {
  32. Object.defineProperty(exports, bkey, {
  33. enumerable: true, value: binding[bkey], writable: false
  34. });
  35. }
  36. }
  37. // translation table for return codes.
  38. const codes = {
  39. Z_OK: binding.Z_OK,
  40. Z_STREAM_END: binding.Z_STREAM_END,
  41. Z_NEED_DICT: binding.Z_NEED_DICT,
  42. Z_ERRNO: binding.Z_ERRNO,
  43. Z_STREAM_ERROR: binding.Z_STREAM_ERROR,
  44. Z_DATA_ERROR: binding.Z_DATA_ERROR,
  45. Z_MEM_ERROR: binding.Z_MEM_ERROR,
  46. Z_BUF_ERROR: binding.Z_BUF_ERROR,
  47. Z_VERSION_ERROR: binding.Z_VERSION_ERROR
  48. };
  49. const ckeys = Object.keys(codes);
  50. for (var ck = 0; ck < ckeys.length; ck++) {
  51. var ckey = ckeys[ck];
  52. codes[codes[ckey]] = ckey;
  53. }
  54. Object.defineProperty(exports, 'codes', {
  55. enumerable: true, value: Object.freeze(codes), writable: false
  56. });
  57. exports.Deflate = Deflate;
  58. exports.Inflate = Inflate;
  59. exports.Gzip = Gzip;
  60. exports.Gunzip = Gunzip;
  61. exports.DeflateRaw = DeflateRaw;
  62. exports.InflateRaw = InflateRaw;
  63. exports.Unzip = Unzip;
  64. exports.createDeflate = function(o) {
  65. return new Deflate(o);
  66. };
  67. exports.createInflate = function(o) {
  68. return new Inflate(o);
  69. };
  70. exports.createDeflateRaw = function(o) {
  71. return new DeflateRaw(o);
  72. };
  73. exports.createInflateRaw = function(o) {
  74. return new InflateRaw(o);
  75. };
  76. exports.createGzip = function(o) {
  77. return new Gzip(o);
  78. };
  79. exports.createGunzip = function(o) {
  80. return new Gunzip(o);
  81. };
  82. exports.createUnzip = function(o) {
  83. return new Unzip(o);
  84. };
  85. // Convenience methods.
  86. // compress/decompress a string or buffer in one step.
  87. exports.deflate = function(buffer, opts, callback) {
  88. if (typeof opts === 'function') {
  89. callback = opts;
  90. opts = {};
  91. }
  92. return zlibBuffer(new Deflate(opts), buffer, callback);
  93. };
  94. exports.deflateSync = function(buffer, opts) {
  95. return zlibBufferSync(new Deflate(opts), buffer);
  96. };
  97. exports.gzip = function(buffer, opts, callback) {
  98. if (typeof opts === 'function') {
  99. callback = opts;
  100. opts = {};
  101. }
  102. return zlibBuffer(new Gzip(opts), buffer, callback);
  103. };
  104. exports.gzipSync = function(buffer, opts) {
  105. return zlibBufferSync(new Gzip(opts), buffer);
  106. };
  107. exports.deflateRaw = function(buffer, opts, callback) {
  108. if (typeof opts === 'function') {
  109. callback = opts;
  110. opts = {};
  111. }
  112. return zlibBuffer(new DeflateRaw(opts), buffer, callback);
  113. };
  114. exports.deflateRawSync = function(buffer, opts) {
  115. return zlibBufferSync(new DeflateRaw(opts), buffer);
  116. };
  117. exports.unzip = function(buffer, opts, callback) {
  118. if (typeof opts === 'function') {
  119. callback = opts;
  120. opts = {};
  121. }
  122. return zlibBuffer(new Unzip(opts), buffer, callback);
  123. };
  124. exports.unzipSync = function(buffer, opts) {
  125. return zlibBufferSync(new Unzip(opts), buffer);
  126. };
  127. exports.inflate = function(buffer, opts, callback) {
  128. if (typeof opts === 'function') {
  129. callback = opts;
  130. opts = {};
  131. }
  132. return zlibBuffer(new Inflate(opts), buffer, callback);
  133. };
  134. exports.inflateSync = function(buffer, opts) {
  135. return zlibBufferSync(new Inflate(opts), buffer);
  136. };
  137. exports.gunzip = function(buffer, opts, callback) {
  138. if (typeof opts === 'function') {
  139. callback = opts;
  140. opts = {};
  141. }
  142. return zlibBuffer(new Gunzip(opts), buffer, callback);
  143. };
  144. exports.gunzipSync = function(buffer, opts) {
  145. return zlibBufferSync(new Gunzip(opts), buffer);
  146. };
  147. exports.inflateRaw = function(buffer, opts, callback) {
  148. if (typeof opts === 'function') {
  149. callback = opts;
  150. opts = {};
  151. }
  152. return zlibBuffer(new InflateRaw(opts), buffer, callback);
  153. };
  154. exports.inflateRawSync = function(buffer, opts) {
  155. return zlibBufferSync(new InflateRaw(opts), buffer);
  156. };
  157. function zlibBuffer(engine, buffer, callback) {
  158. var buffers = [];
  159. var nread = 0;
  160. engine.on('error', onError);
  161. engine.on('end', onEnd);
  162. engine.end(buffer);
  163. flow();
  164. function flow() {
  165. var chunk;
  166. while (null !== (chunk = engine.read())) {
  167. buffers.push(chunk);
  168. nread += chunk.length;
  169. }
  170. engine.once('readable', flow);
  171. }
  172. function onError(err) {
  173. engine.removeListener('end', onEnd);
  174. engine.removeListener('readable', flow);
  175. callback(err);
  176. }
  177. function onEnd() {
  178. var buf;
  179. var err = null;
  180. if (nread >= kMaxLength) {
  181. err = new RangeError(kRangeErrorMessage);
  182. } else {
  183. buf = Buffer.concat(buffers, nread);
  184. }
  185. buffers = [];
  186. engine.close();
  187. callback(err, buf);
  188. }
  189. }
  190. function zlibBufferSync(engine, buffer) {
  191. if (typeof buffer === 'string')
  192. buffer = Buffer.from(buffer);
  193. if (!Buffer.isBuffer(buffer))
  194. throw new TypeError('Not a string or buffer');
  195. var flushFlag = engine._finishFlushFlag;
  196. return engine._processChunk(buffer, flushFlag);
  197. }
  198. // generic zlib
  199. // minimal 2-byte header
  200. function Deflate(opts) {
  201. if (!(this instanceof Deflate)) return new Deflate(opts);
  202. Zlib.call(this, opts, binding.DEFLATE);
  203. }
  204. function Inflate(opts) {
  205. if (!(this instanceof Inflate)) return new Inflate(opts);
  206. Zlib.call(this, opts, binding.INFLATE);
  207. }
  208. // gzip - bigger header, same deflate compression
  209. function Gzip(opts) {
  210. if (!(this instanceof Gzip)) return new Gzip(opts);
  211. Zlib.call(this, opts, binding.GZIP);
  212. }
  213. function Gunzip(opts) {
  214. if (!(this instanceof Gunzip)) return new Gunzip(opts);
  215. Zlib.call(this, opts, binding.GUNZIP);
  216. }
  217. // raw - no header
  218. function DeflateRaw(opts) {
  219. if (!(this instanceof DeflateRaw)) return new DeflateRaw(opts);
  220. Zlib.call(this, opts, binding.DEFLATERAW);
  221. }
  222. function InflateRaw(opts) {
  223. if (!(this instanceof InflateRaw)) return new InflateRaw(opts);
  224. Zlib.call(this, opts, binding.INFLATERAW);
  225. }
  226. // auto-detect header.
  227. function Unzip(opts) {
  228. if (!(this instanceof Unzip)) return new Unzip(opts);
  229. Zlib.call(this, opts, binding.UNZIP);
  230. }
  231. function isValidFlushFlag(flag) {
  232. return flag === binding.Z_NO_FLUSH ||
  233. flag === binding.Z_PARTIAL_FLUSH ||
  234. flag === binding.Z_SYNC_FLUSH ||
  235. flag === binding.Z_FULL_FLUSH ||
  236. flag === binding.Z_FINISH ||
  237. flag === binding.Z_BLOCK;
  238. }
  239. // the Zlib class they all inherit from
  240. // This thing manages the queue of requests, and returns
  241. // true or false if there is anything in the queue when
  242. // you call the .write() method.
  243. function Zlib(opts, mode) {
  244. this._opts = opts = opts || {};
  245. this._chunkSize = opts.chunkSize || exports.Z_DEFAULT_CHUNK;
  246. Transform.call(this, opts);
  247. if (opts.flush && !isValidFlushFlag(opts.flush)) {
  248. throw new Error('Invalid flush flag: ' + opts.flush);
  249. }
  250. if (opts.finishFlush && !isValidFlushFlag(opts.finishFlush)) {
  251. throw new Error('Invalid flush flag: ' + opts.finishFlush);
  252. }
  253. this._flushFlag = opts.flush || binding.Z_NO_FLUSH;
  254. this._finishFlushFlag = typeof opts.finishFlush !== 'undefined' ?
  255. opts.finishFlush : binding.Z_FINISH;
  256. if (opts.chunkSize) {
  257. if (opts.chunkSize < exports.Z_MIN_CHUNK ||
  258. opts.chunkSize > exports.Z_MAX_CHUNK) {
  259. throw new Error('Invalid chunk size: ' + opts.chunkSize);
  260. }
  261. }
  262. if (opts.windowBits) {
  263. if (opts.windowBits < exports.Z_MIN_WINDOWBITS ||
  264. opts.windowBits > exports.Z_MAX_WINDOWBITS) {
  265. throw new Error('Invalid windowBits: ' + opts.windowBits);
  266. }
  267. }
  268. if (opts.level) {
  269. if (opts.level < exports.Z_MIN_LEVEL ||
  270. opts.level > exports.Z_MAX_LEVEL) {
  271. throw new Error('Invalid compression level: ' + opts.level);
  272. }
  273. }
  274. if (opts.memLevel) {
  275. if (opts.memLevel < exports.Z_MIN_MEMLEVEL ||
  276. opts.memLevel > exports.Z_MAX_MEMLEVEL) {
  277. throw new Error('Invalid memLevel: ' + opts.memLevel);
  278. }
  279. }
  280. if (opts.strategy) {
  281. if (opts.strategy != exports.Z_FILTERED &&
  282. opts.strategy != exports.Z_HUFFMAN_ONLY &&
  283. opts.strategy != exports.Z_RLE &&
  284. opts.strategy != exports.Z_FIXED &&
  285. opts.strategy != exports.Z_DEFAULT_STRATEGY) {
  286. throw new Error('Invalid strategy: ' + opts.strategy);
  287. }
  288. }
  289. if (opts.dictionary) {
  290. if (!Buffer.isBuffer(opts.dictionary)) {
  291. throw new Error('Invalid dictionary: it should be a Buffer instance');
  292. }
  293. }
  294. this._handle = new binding.Zlib(mode);
  295. var self = this;
  296. this._hadError = false;
  297. this._handle.onerror = function(message, errno) {
  298. // there is no way to cleanly recover.
  299. // continuing only obscures problems.
  300. _close(self);
  301. self._hadError = true;
  302. var error = new Error(message);
  303. error.errno = errno;
  304. error.code = exports.codes[errno];
  305. self.emit('error', error);
  306. };
  307. var level = exports.Z_DEFAULT_COMPRESSION;
  308. if (typeof opts.level === 'number') level = opts.level;
  309. var strategy = exports.Z_DEFAULT_STRATEGY;
  310. if (typeof opts.strategy === 'number') strategy = opts.strategy;
  311. this._handle.init(opts.windowBits || exports.Z_DEFAULT_WINDOWBITS,
  312. level,
  313. opts.memLevel || exports.Z_DEFAULT_MEMLEVEL,
  314. strategy,
  315. opts.dictionary);
  316. this._buffer = Buffer.allocUnsafe(this._chunkSize);
  317. this._offset = 0;
  318. this._level = level;
  319. this._strategy = strategy;
  320. this.once('end', this.close);
  321. Object.defineProperty(this, '_closed', {
  322. get: () => { return !this._handle; },
  323. configurable: true,
  324. enumerable: true
  325. });
  326. }
  327. util.inherits(Zlib, Transform);
  328. Zlib.prototype.params = function(level, strategy, callback) {
  329. if (level < exports.Z_MIN_LEVEL ||
  330. level > exports.Z_MAX_LEVEL) {
  331. throw new RangeError('Invalid compression level: ' + level);
  332. }
  333. if (strategy != exports.Z_FILTERED &&
  334. strategy != exports.Z_HUFFMAN_ONLY &&
  335. strategy != exports.Z_RLE &&
  336. strategy != exports.Z_FIXED &&
  337. strategy != exports.Z_DEFAULT_STRATEGY) {
  338. throw new TypeError('Invalid strategy: ' + strategy);
  339. }
  340. if (this._level !== level || this._strategy !== strategy) {
  341. var self = this;
  342. this.flush(binding.Z_SYNC_FLUSH, function() {
  343. assert(self._handle, 'zlib binding closed');
  344. self._handle.params(level, strategy);
  345. if (!self._hadError) {
  346. self._level = level;
  347. self._strategy = strategy;
  348. if (callback) callback();
  349. }
  350. });
  351. } else {
  352. process.nextTick(callback);
  353. }
  354. };
  355. Zlib.prototype.reset = function() {
  356. assert(this._handle, 'zlib binding closed');
  357. return this._handle.reset();
  358. };
  359. // This is the _flush function called by the transform class,
  360. // internally, when the last chunk has been written.
  361. Zlib.prototype._flush = function(callback) {
  362. this._transform(Buffer.alloc(0), '', callback);
  363. };
  364. Zlib.prototype.flush = function(kind, callback) {
  365. var ws = this._writableState;
  366. if (typeof kind === 'function' || (kind === undefined && !callback)) {
  367. callback = kind;
  368. kind = binding.Z_FULL_FLUSH;
  369. }
  370. if (ws.ended) {
  371. if (callback)
  372. process.nextTick(callback);
  373. } else if (ws.ending) {
  374. if (callback)
  375. this.once('end', callback);
  376. } else if (ws.needDrain) {
  377. if (callback) {
  378. this.once('drain', () => this.flush(kind, callback));
  379. }
  380. } else {
  381. this._flushFlag = kind;
  382. this.write(Buffer.alloc(0), '', callback);
  383. }
  384. };
  385. Zlib.prototype.close = function(callback) {
  386. _close(this, callback);
  387. process.nextTick(emitCloseNT, this);
  388. };
  389. function _close(engine, callback) {
  390. if (callback)
  391. process.nextTick(callback);
  392. // Caller may invoke .close after a zlib error (which will null _handle).
  393. if (!engine._handle)
  394. return;
  395. engine._handle.close();
  396. engine._handle = null;
  397. }
  398. function emitCloseNT(self) {
  399. self.emit('close');
  400. }
  401. Zlib.prototype._transform = function(chunk, encoding, cb) {
  402. var flushFlag;
  403. var ws = this._writableState;
  404. var ending = ws.ending || ws.ended;
  405. var last = ending && (!chunk || ws.length === chunk.length);
  406. if (chunk !== null && !Buffer.isBuffer(chunk))
  407. return cb(new Error('invalid input'));
  408. if (!this._handle)
  409. return cb(new Error('zlib binding closed'));
  410. // If it's the last chunk, or a final flush, we use the Z_FINISH flush flag
  411. // (or whatever flag was provided using opts.finishFlush).
  412. // If it's explicitly flushing at some other time, then we use
  413. // Z_FULL_FLUSH. Otherwise, use Z_NO_FLUSH for maximum compression
  414. // goodness.
  415. if (last)
  416. flushFlag = this._finishFlushFlag;
  417. else {
  418. flushFlag = this._flushFlag;
  419. // once we've flushed the last of the queue, stop flushing and
  420. // go back to the normal behavior.
  421. if (chunk.length >= ws.length) {
  422. this._flushFlag = this._opts.flush || binding.Z_NO_FLUSH;
  423. }
  424. }
  425. this._processChunk(chunk, flushFlag, cb);
  426. };
  427. Zlib.prototype._processChunk = function(chunk, flushFlag, cb) {
  428. var availInBefore = chunk && chunk.length;
  429. var availOutBefore = this._chunkSize - this._offset;
  430. var inOff = 0;
  431. var self = this;
  432. var async = typeof cb === 'function';
  433. if (!async) {
  434. var buffers = [];
  435. var nread = 0;
  436. var error;
  437. this.on('error', function(er) {
  438. error = er;
  439. });
  440. assert(this._handle, 'zlib binding closed');
  441. do {
  442. var res = this._handle.writeSync(flushFlag,
  443. chunk, // in
  444. inOff, // in_off
  445. availInBefore, // in_len
  446. this._buffer, // out
  447. this._offset, //out_off
  448. availOutBefore); // out_len
  449. } while (!this._hadError && callback(res[0], res[1]));
  450. if (this._hadError) {
  451. throw error;
  452. }
  453. if (nread >= kMaxLength) {
  454. _close(this);
  455. throw new RangeError(kRangeErrorMessage);
  456. }
  457. var buf = Buffer.concat(buffers, nread);
  458. _close(this);
  459. return buf;
  460. }
  461. assert(this._handle, 'zlib binding closed');
  462. var req = this._handle.write(flushFlag,
  463. chunk, // in
  464. inOff, // in_off
  465. availInBefore, // in_len
  466. this._buffer, // out
  467. this._offset, //out_off
  468. availOutBefore); // out_len
  469. req.buffer = chunk;
  470. req.callback = callback;
  471. function callback(availInAfter, availOutAfter) {
  472. // When the callback is used in an async write, the callback's
  473. // context is the `req` object that was created. The req object
  474. // is === this._handle, and that's why it's important to null
  475. // out the values after they are done being used. `this._handle`
  476. // can stay in memory longer than the callback and buffer are needed.
  477. if (this) {
  478. this.buffer = null;
  479. this.callback = null;
  480. }
  481. if (self._hadError)
  482. return;
  483. var have = availOutBefore - availOutAfter;
  484. assert(have >= 0, 'have should not go down');
  485. if (have > 0) {
  486. var out = self._buffer.slice(self._offset, self._offset + have);
  487. self._offset += have;
  488. // serve some output to the consumer.
  489. if (async) {
  490. self.push(out);
  491. } else {
  492. buffers.push(out);
  493. nread += out.length;
  494. }
  495. }
  496. // exhausted the output buffer, or used all the input create a new one.
  497. if (availOutAfter === 0 || self._offset >= self._chunkSize) {
  498. availOutBefore = self._chunkSize;
  499. self._offset = 0;
  500. self._buffer = Buffer.allocUnsafe(self._chunkSize);
  501. }
  502. if (availOutAfter === 0) {
  503. // Not actually done. Need to reprocess.
  504. // Also, update the availInBefore to the availInAfter value,
  505. // so that if we have to hit it a third (fourth, etc.) time,
  506. // it'll have the correct byte counts.
  507. inOff += (availInBefore - availInAfter);
  508. availInBefore = availInAfter;
  509. if (!async)
  510. return true;
  511. var newReq = self._handle.write(flushFlag,
  512. chunk,
  513. inOff,
  514. availInBefore,
  515. self._buffer,
  516. self._offset,
  517. self._chunkSize);
  518. newReq.callback = callback; // this same function
  519. newReq.buffer = chunk;
  520. return;
  521. }
  522. if (!async)
  523. return false;
  524. // finished with the chunk.
  525. cb();
  526. }
  527. };
  528. util.inherits(Deflate, Zlib);
  529. util.inherits(Inflate, Zlib);
  530. util.inherits(Gzip, Zlib);
  531. util.inherits(Gunzip, Zlib);
  532. util.inherits(DeflateRaw, Zlib);
  533. util.inherits(InflateRaw, Zlib);
  534. util.inherits(Unzip, Zlib);