210 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			210 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
| /*!
 | |
|  * 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()
 | |
|   }
 | |
| }
 |