You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					210 lines
				
				4.2 KiB
			
		
		
			
		
	
	
					210 lines
				
				4.2 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								/*!
							 | 
						||
| 
								 | 
							
								 * 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()
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 |