123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- /*!
- * 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()
- }
- }
|