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() | ||
|  |   } | ||
|  | } |