| /*! |
| * destroy |
| * Copyright(c) 2014 Jonathan Ong |
| * Copyright(c) 2015-2022 Douglas Christopher Wilson |
| * MIT Licensed |
| */ |
| |
| 'use strict' |
| |
| /** |
| * Module dependencies. |
| * @private |
| */ |
| |
| var EventEmitter = require('events').EventEmitter |
| var ReadStream = require('fs').ReadStream |
| var Stream = require('stream') |
| var Zlib = require('zlib') |
| |
| /** |
| * Module exports. |
| * @public |
| */ |
| |
| module.exports = destroy |
| |
| /** |
| * Destroy the given stream, and optionally suppress any future `error` events. |
| * |
| * @param {object} stream |
| * @param {boolean} suppress |
| * @public |
| */ |
| |
| function destroy (stream, suppress) { |
| if (isFsReadStream(stream)) { |
| destroyReadStream(stream) |
| } else if (isZlibStream(stream)) { |
| destroyZlibStream(stream) |
| } else if (hasDestroy(stream)) { |
| stream.destroy() |
| } |
| |
| if (isEventEmitter(stream) && suppress) { |
| stream.removeAllListeners('error') |
| stream.addListener('error', noop) |
| } |
| |
| return stream |
| } |
| |
| /** |
| * Destroy a ReadStream. |
| * |
| * @param {object} stream |
| * @private |
| */ |
| |
| function destroyReadStream (stream) { |
| stream.destroy() |
| |
| if (typeof stream.close === 'function') { |
| // node.js core bug work-around |
| stream.on('open', onOpenClose) |
| } |
| } |
| |
| /** |
| * Close a Zlib stream. |
| * |
| * Zlib streams below Node.js 4.5.5 have a buggy implementation |
| * of .close() when zlib encountered an error. |
| * |
| * @param {object} stream |
| * @private |
| */ |
| |
| function closeZlibStream (stream) { |
| if (stream._hadError === true) { |
| var prop = stream._binding === null |
| ? '_binding' |
| : '_handle' |
| |
| stream[prop] = { |
| close: function () { this[prop] = null } |
| } |
| } |
| |
| stream.close() |
| } |
| |
| /** |
| * Destroy a Zlib stream. |
| * |
| * Zlib streams don't have a destroy function in Node.js 6. On top of that |
| * simply calling destroy on a zlib stream in Node.js 8+ will result in a |
| * memory leak. So until that is fixed, we need to call both close AND destroy. |
| * |
| * PR to fix memory leak: https://github.com/nodejs/node/pull/23734 |
| * |
| * In Node.js 6+8, it's important that destroy is called before close as the |
| * stream would otherwise emit the error 'zlib binding closed'. |
| * |
| * @param {object} stream |
| * @private |
| */ |
| |
| function destroyZlibStream (stream) { |
| if (typeof stream.destroy === 'function') { |
| // node.js core bug work-around |
| // istanbul ignore if: node.js 0.8 |
| if (stream._binding) { |
| // node.js < 0.10.0 |
| stream.destroy() |
| if (stream._processing) { |
| stream._needDrain = true |
| stream.once('drain', onDrainClearBinding) |
| } else { |
| stream._binding.clear() |
| } |
| } else if (stream._destroy && stream._destroy !== Stream.Transform.prototype._destroy) { |
| // node.js >= 12, ^11.1.0, ^10.15.1 |
| stream.destroy() |
| } else if (stream._destroy && typeof stream.close === 'function') { |
| // node.js 7, 8 |
| stream.destroyed = true |
| stream.close() |
| } else { |
| // fallback |
| // istanbul ignore next |
| stream.destroy() |
| } |
| } else if (typeof stream.close === 'function') { |
| // node.js < 8 fallback |
| closeZlibStream(stream) |
| } |
| } |
| |
| /** |
| * Determine if stream has destroy. |
| * @private |
| */ |
| |
| function hasDestroy (stream) { |
| return stream instanceof Stream && |
| typeof stream.destroy === 'function' |
| } |
| |
| /** |
| * Determine if val is EventEmitter. |
| * @private |
| */ |
| |
| function isEventEmitter (val) { |
| return val instanceof EventEmitter |
| } |
| |
| /** |
| * Determine if stream is fs.ReadStream stream. |
| * @private |
| */ |
| |
| function isFsReadStream (stream) { |
| return stream instanceof ReadStream |
| } |
| |
| /** |
| * Determine if stream is Zlib stream. |
| * @private |
| */ |
| |
| function isZlibStream (stream) { |
| return stream instanceof Zlib.Gzip || |
| stream instanceof Zlib.Gunzip || |
| stream instanceof Zlib.Deflate || |
| stream instanceof Zlib.DeflateRaw || |
| stream instanceof Zlib.Inflate || |
| stream instanceof Zlib.InflateRaw || |
| stream instanceof Zlib.Unzip |
| } |
| |
| /** |
| * No-op function. |
| * @private |
| */ |
| |
| function noop () {} |
| |
| /** |
| * On drain handler to clear binding. |
| * @private |
| */ |
| |
| // istanbul ignore next: node.js 0.8 |
| function onDrainClearBinding () { |
| this._binding.clear() |
| } |
| |
| /** |
| * On open handler to close stream. |
| * @private |
| */ |
| |
| function onOpenClose () { |
| if (typeof this.fd === 'number') { |
| // actually close down the fd |
| this.close() |
| } |
| } |