1var once = require('once'); 2 3var noop = function() {}; 4 5var isRequest = function(stream) { 6 return stream.setHeader && typeof stream.abort === 'function'; 7}; 8 9var isChildProcess = function(stream) { 10 return stream.stdio && Array.isArray(stream.stdio) && stream.stdio.length === 3 11}; 12 13var eos = function(stream, opts, callback) { 14 if (typeof opts === 'function') return eos(stream, null, opts); 15 if (!opts) opts = {}; 16 17 callback = once(callback || noop); 18 19 var ws = stream._writableState; 20 var rs = stream._readableState; 21 var readable = opts.readable || (opts.readable !== false && stream.readable); 22 var writable = opts.writable || (opts.writable !== false && stream.writable); 23 24 var onlegacyfinish = function() { 25 if (!stream.writable) onfinish(); 26 }; 27 28 var onfinish = function() { 29 writable = false; 30 if (!readable) callback.call(stream); 31 }; 32 33 var onend = function() { 34 readable = false; 35 if (!writable) callback.call(stream); 36 }; 37 38 var onexit = function(exitCode) { 39 callback.call(stream, exitCode ? new Error('exited with error code: ' + exitCode) : null); 40 }; 41 42 var onerror = function(err) { 43 callback.call(stream, err); 44 }; 45 46 var onclose = function() { 47 if (readable && !(rs && rs.ended)) return callback.call(stream, new Error('premature close')); 48 if (writable && !(ws && ws.ended)) return callback.call(stream, new Error('premature close')); 49 }; 50 51 var onrequest = function() { 52 stream.req.on('finish', onfinish); 53 }; 54 55 if (isRequest(stream)) { 56 stream.on('complete', onfinish); 57 stream.on('abort', onclose); 58 if (stream.req) onrequest(); 59 else stream.on('request', onrequest); 60 } else if (writable && !ws) { // legacy streams 61 stream.on('end', onlegacyfinish); 62 stream.on('close', onlegacyfinish); 63 } 64 65 if (isChildProcess(stream)) stream.on('exit', onexit); 66 67 stream.on('end', onend); 68 stream.on('finish', onfinish); 69 if (opts.error !== false) stream.on('error', onerror); 70 stream.on('close', onclose); 71 72 return function() { 73 stream.removeListener('complete', onfinish); 74 stream.removeListener('abort', onclose); 75 stream.removeListener('request', onrequest); 76 if (stream.req) stream.req.removeListener('finish', onfinish); 77 stream.removeListener('end', onlegacyfinish); 78 stream.removeListener('close', onlegacyfinish); 79 stream.removeListener('finish', onfinish); 80 stream.removeListener('exit', onexit); 81 stream.removeListener('end', onend); 82 stream.removeListener('error', onerror); 83 stream.removeListener('close', onclose); 84 }; 85}; 86 87module.exports = eos; 88