index.js 16 KB

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