index.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. "use strict";
  2. var __importDefault = (this && this.__importDefault) || function (mod) {
  3. return (mod && mod.__esModule) ? mod : { "default": mod };
  4. };
  5. Object.defineProperty(exports, "__esModule", { value: true });
  6. exports.BrotliDecompress = exports.BrotliCompress = exports.Brotli = exports.Unzip = exports.InflateRaw = exports.DeflateRaw = exports.Gunzip = exports.Gzip = exports.Inflate = exports.Deflate = exports.Zlib = exports.ZlibError = exports.constants = void 0;
  7. const assert_1 = __importDefault(require("assert"));
  8. const buffer_1 = require("buffer");
  9. const minipass_1 = require("minipass");
  10. const zlib_1 = __importDefault(require("zlib"));
  11. const constants_js_1 = require("./constants.js");
  12. var constants_js_2 = require("./constants.js");
  13. Object.defineProperty(exports, "constants", { enumerable: true, get: function () { return constants_js_2.constants; } });
  14. const OriginalBufferConcat = buffer_1.Buffer.concat;
  15. const _superWrite = Symbol('_superWrite');
  16. class ZlibError extends Error {
  17. code;
  18. errno;
  19. constructor(err) {
  20. super('zlib: ' + err.message);
  21. this.code = err.code;
  22. this.errno = err.errno;
  23. /* c8 ignore next */
  24. if (!this.code)
  25. this.code = 'ZLIB_ERROR';
  26. this.message = 'zlib: ' + err.message;
  27. Error.captureStackTrace(this, this.constructor);
  28. }
  29. get name() {
  30. return 'ZlibError';
  31. }
  32. }
  33. exports.ZlibError = ZlibError;
  34. // the Zlib class they all inherit from
  35. // This thing manages the queue of requests, and returns
  36. // true or false if there is anything in the queue when
  37. // you call the .write() method.
  38. const _flushFlag = Symbol('flushFlag');
  39. class ZlibBase extends minipass_1.Minipass {
  40. #sawError = false;
  41. #ended = false;
  42. #flushFlag;
  43. #finishFlushFlag;
  44. #fullFlushFlag;
  45. #handle;
  46. #onError;
  47. get sawError() {
  48. return this.#sawError;
  49. }
  50. get handle() {
  51. return this.#handle;
  52. }
  53. /* c8 ignore start */
  54. get flushFlag() {
  55. return this.#flushFlag;
  56. }
  57. /* c8 ignore stop */
  58. constructor(opts, mode) {
  59. if (!opts || typeof opts !== 'object')
  60. throw new TypeError('invalid options for ZlibBase constructor');
  61. //@ts-ignore
  62. super(opts);
  63. /* c8 ignore start */
  64. this.#flushFlag = opts.flush ?? 0;
  65. this.#finishFlushFlag = opts.finishFlush ?? 0;
  66. this.#fullFlushFlag = opts.fullFlushFlag ?? 0;
  67. /* c8 ignore stop */
  68. // this will throw if any options are invalid for the class selected
  69. try {
  70. // @types/node doesn't know that it exports the classes, but they're there
  71. //@ts-ignore
  72. this.#handle = new zlib_1.default[mode](opts);
  73. }
  74. catch (er) {
  75. // make sure that all errors get decorated properly
  76. throw new ZlibError(er);
  77. }
  78. this.#onError = err => {
  79. // no sense raising multiple errors, since we abort on the first one.
  80. if (this.#sawError)
  81. return;
  82. this.#sawError = true;
  83. // there is no way to cleanly recover.
  84. // continuing only obscures problems.
  85. this.close();
  86. this.emit('error', err);
  87. };
  88. this.#handle?.on('error', er => this.#onError(new ZlibError(er)));
  89. this.once('end', () => this.close);
  90. }
  91. close() {
  92. if (this.#handle) {
  93. this.#handle.close();
  94. this.#handle = undefined;
  95. this.emit('close');
  96. }
  97. }
  98. reset() {
  99. if (!this.#sawError) {
  100. (0, assert_1.default)(this.#handle, 'zlib binding closed');
  101. //@ts-ignore
  102. return this.#handle.reset?.();
  103. }
  104. }
  105. flush(flushFlag) {
  106. if (this.ended)
  107. return;
  108. if (typeof flushFlag !== 'number')
  109. flushFlag = this.#fullFlushFlag;
  110. this.write(Object.assign(buffer_1.Buffer.alloc(0), { [_flushFlag]: flushFlag }));
  111. }
  112. end(chunk, encoding, cb) {
  113. /* c8 ignore start */
  114. if (typeof chunk === 'function') {
  115. cb = chunk;
  116. encoding = undefined;
  117. chunk = undefined;
  118. }
  119. if (typeof encoding === 'function') {
  120. cb = encoding;
  121. encoding = undefined;
  122. }
  123. /* c8 ignore stop */
  124. if (chunk) {
  125. if (encoding)
  126. this.write(chunk, encoding);
  127. else
  128. this.write(chunk);
  129. }
  130. this.flush(this.#finishFlushFlag);
  131. this.#ended = true;
  132. return super.end(cb);
  133. }
  134. get ended() {
  135. return this.#ended;
  136. }
  137. // overridden in the gzip classes to do portable writes
  138. [_superWrite](data) {
  139. return super.write(data);
  140. }
  141. write(chunk, encoding, cb) {
  142. // process the chunk using the sync process
  143. // then super.write() all the outputted chunks
  144. if (typeof encoding === 'function')
  145. (cb = encoding), (encoding = 'utf8');
  146. if (typeof chunk === 'string')
  147. chunk = buffer_1.Buffer.from(chunk, encoding);
  148. if (this.#sawError)
  149. return;
  150. (0, assert_1.default)(this.#handle, 'zlib binding closed');
  151. // _processChunk tries to .close() the native handle after it's done, so we
  152. // intercept that by temporarily making it a no-op.
  153. // diving into the node:zlib internals a bit here
  154. const nativeHandle = this.#handle
  155. ._handle;
  156. const originalNativeClose = nativeHandle.close;
  157. nativeHandle.close = () => { };
  158. const originalClose = this.#handle.close;
  159. this.#handle.close = () => { };
  160. // It also calls `Buffer.concat()` at the end, which may be convenient
  161. // for some, but which we are not interested in as it slows us down.
  162. buffer_1.Buffer.concat = args => args;
  163. let result = undefined;
  164. try {
  165. const flushFlag = typeof chunk[_flushFlag] === 'number'
  166. ? chunk[_flushFlag]
  167. : this.#flushFlag;
  168. result = this.#handle._processChunk(chunk, flushFlag);
  169. // if we don't throw, reset it back how it was
  170. buffer_1.Buffer.concat = OriginalBufferConcat;
  171. }
  172. catch (err) {
  173. // or if we do, put Buffer.concat() back before we emit error
  174. // Error events call into user code, which may call Buffer.concat()
  175. buffer_1.Buffer.concat = OriginalBufferConcat;
  176. this.#onError(new ZlibError(err));
  177. }
  178. finally {
  179. if (this.#handle) {
  180. // Core zlib resets `_handle` to null after attempting to close the
  181. // native handle. Our no-op handler prevented actual closure, but we
  182. // need to restore the `._handle` property.
  183. ;
  184. this.#handle._handle =
  185. nativeHandle;
  186. nativeHandle.close = originalNativeClose;
  187. this.#handle.close = originalClose;
  188. // `_processChunk()` adds an 'error' listener. If we don't remove it
  189. // after each call, these handlers start piling up.
  190. this.#handle.removeAllListeners('error');
  191. // make sure OUR error listener is still attached tho
  192. }
  193. }
  194. if (this.#handle)
  195. this.#handle.on('error', er => this.#onError(new ZlibError(er)));
  196. let writeReturn;
  197. if (result) {
  198. if (Array.isArray(result) && result.length > 0) {
  199. const r = result[0];
  200. // The first buffer is always `handle._outBuffer`, which would be
  201. // re-used for later invocations; so, we always have to copy that one.
  202. writeReturn = this[_superWrite](buffer_1.Buffer.from(r));
  203. for (let i = 1; i < result.length; i++) {
  204. writeReturn = this[_superWrite](result[i]);
  205. }
  206. }
  207. else {
  208. // either a single Buffer or an empty array
  209. writeReturn = this[_superWrite](buffer_1.Buffer.from(result));
  210. }
  211. }
  212. if (cb)
  213. cb();
  214. return writeReturn;
  215. }
  216. }
  217. class Zlib extends ZlibBase {
  218. #level;
  219. #strategy;
  220. constructor(opts, mode) {
  221. opts = opts || {};
  222. opts.flush = opts.flush || constants_js_1.constants.Z_NO_FLUSH;
  223. opts.finishFlush = opts.finishFlush || constants_js_1.constants.Z_FINISH;
  224. opts.fullFlushFlag = constants_js_1.constants.Z_FULL_FLUSH;
  225. super(opts, mode);
  226. this.#level = opts.level;
  227. this.#strategy = opts.strategy;
  228. }
  229. params(level, strategy) {
  230. if (this.sawError)
  231. return;
  232. if (!this.handle)
  233. throw new Error('cannot switch params when binding is closed');
  234. // no way to test this without also not supporting params at all
  235. /* c8 ignore start */
  236. if (!this.handle.params)
  237. throw new Error('not supported in this implementation');
  238. /* c8 ignore stop */
  239. if (this.#level !== level || this.#strategy !== strategy) {
  240. this.flush(constants_js_1.constants.Z_SYNC_FLUSH);
  241. (0, assert_1.default)(this.handle, 'zlib binding closed');
  242. // .params() calls .flush(), but the latter is always async in the
  243. // core zlib. We override .flush() temporarily to intercept that and
  244. // flush synchronously.
  245. const origFlush = this.handle.flush;
  246. this.handle.flush = (flushFlag, cb) => {
  247. /* c8 ignore start */
  248. if (typeof flushFlag === 'function') {
  249. cb = flushFlag;
  250. flushFlag = this.flushFlag;
  251. }
  252. /* c8 ignore stop */
  253. this.flush(flushFlag);
  254. cb?.();
  255. };
  256. try {
  257. ;
  258. this.handle.params(level, strategy);
  259. }
  260. finally {
  261. this.handle.flush = origFlush;
  262. }
  263. /* c8 ignore start */
  264. if (this.handle) {
  265. this.#level = level;
  266. this.#strategy = strategy;
  267. }
  268. /* c8 ignore stop */
  269. }
  270. }
  271. }
  272. exports.Zlib = Zlib;
  273. // minimal 2-byte header
  274. class Deflate extends Zlib {
  275. constructor(opts) {
  276. super(opts, 'Deflate');
  277. }
  278. }
  279. exports.Deflate = Deflate;
  280. class Inflate extends Zlib {
  281. constructor(opts) {
  282. super(opts, 'Inflate');
  283. }
  284. }
  285. exports.Inflate = Inflate;
  286. class Gzip extends Zlib {
  287. #portable;
  288. constructor(opts) {
  289. super(opts, 'Gzip');
  290. this.#portable = opts && !!opts.portable;
  291. }
  292. [_superWrite](data) {
  293. if (!this.#portable)
  294. return super[_superWrite](data);
  295. // we'll always get the header emitted in one first chunk
  296. // overwrite the OS indicator byte with 0xFF
  297. this.#portable = false;
  298. data[9] = 255;
  299. return super[_superWrite](data);
  300. }
  301. }
  302. exports.Gzip = Gzip;
  303. class Gunzip extends Zlib {
  304. constructor(opts) {
  305. super(opts, 'Gunzip');
  306. }
  307. }
  308. exports.Gunzip = Gunzip;
  309. // raw - no header
  310. class DeflateRaw extends Zlib {
  311. constructor(opts) {
  312. super(opts, 'DeflateRaw');
  313. }
  314. }
  315. exports.DeflateRaw = DeflateRaw;
  316. class InflateRaw extends Zlib {
  317. constructor(opts) {
  318. super(opts, 'InflateRaw');
  319. }
  320. }
  321. exports.InflateRaw = InflateRaw;
  322. // auto-detect header.
  323. class Unzip extends Zlib {
  324. constructor(opts) {
  325. super(opts, 'Unzip');
  326. }
  327. }
  328. exports.Unzip = Unzip;
  329. class Brotli extends ZlibBase {
  330. constructor(opts, mode) {
  331. opts = opts || {};
  332. opts.flush = opts.flush || constants_js_1.constants.BROTLI_OPERATION_PROCESS;
  333. opts.finishFlush =
  334. opts.finishFlush || constants_js_1.constants.BROTLI_OPERATION_FINISH;
  335. opts.fullFlushFlag = constants_js_1.constants.BROTLI_OPERATION_FLUSH;
  336. super(opts, mode);
  337. }
  338. }
  339. exports.Brotli = Brotli;
  340. class BrotliCompress extends Brotli {
  341. constructor(opts) {
  342. super(opts, 'BrotliCompress');
  343. }
  344. }
  345. exports.BrotliCompress = BrotliCompress;
  346. class BrotliDecompress extends Brotli {
  347. constructor(opts) {
  348. super(opts, 'BrotliDecompress');
  349. }
  350. }
  351. exports.BrotliDecompress = BrotliDecompress;
  352. //# sourceMappingURL=index.js.map