| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 | /*! * on-finished * Copyright(c) 2013 Jonathan Ong * Copyright(c) 2014 Douglas Christopher Wilson * MIT Licensed */'use strict'/** * Module exports. * @public */module.exports = onFinishedmodule.exports.isFinished = isFinished/** * Module dependencies. * @private */var asyncHooks = tryRequireAsyncHooks()var first = require('ee-first')/** * Variables. * @private *//* istanbul ignore next */var defer = typeof setImmediate === 'function'  ? setImmediate  : function (fn) { process.nextTick(fn.bind.apply(fn, arguments)) }/** * Invoke callback when the response has finished, useful for * cleaning up resources afterwards. * * @param {object} msg * @param {function} listener * @return {object} * @public */function onFinished (msg, listener) {  if (isFinished(msg) !== false) {    defer(listener, null, msg)    return msg  }  // attach the listener to the message  attachListener(msg, wrap(listener))  return msg}/** * Determine if message is already finished. * * @param {object} msg * @return {boolean} * @public */function isFinished (msg) {  var socket = msg.socket  if (typeof msg.finished === 'boolean') {    // OutgoingMessage    return Boolean(msg.finished || (socket && !socket.writable))  }  if (typeof msg.complete === 'boolean') {    // IncomingMessage    return Boolean(msg.upgrade || !socket || !socket.readable || (msg.complete && !msg.readable))  }  // don't know  return undefined}/** * Attach a finished listener to the message. * * @param {object} msg * @param {function} callback * @private */function attachFinishedListener (msg, callback) {  var eeMsg  var eeSocket  var finished = false  function onFinish (error) {    eeMsg.cancel()    eeSocket.cancel()    finished = true    callback(error)  }  // finished on first message event  eeMsg = eeSocket = first([[msg, 'end', 'finish']], onFinish)  function onSocket (socket) {    // remove listener    msg.removeListener('socket', onSocket)    if (finished) return    if (eeMsg !== eeSocket) return    // finished on first socket event    eeSocket = first([[socket, 'error', 'close']], onFinish)  }  if (msg.socket) {    // socket already assigned    onSocket(msg.socket)    return  }  // wait for socket to be assigned  msg.on('socket', onSocket)  if (msg.socket === undefined) {    // istanbul ignore next: node.js 0.8 patch    patchAssignSocket(msg, onSocket)  }}/** * Attach the listener to the message. * * @param {object} msg * @return {function} * @private */function attachListener (msg, listener) {  var attached = msg.__onFinished  // create a private single listener with queue  if (!attached || !attached.queue) {    attached = msg.__onFinished = createListener(msg)    attachFinishedListener(msg, attached)  }  attached.queue.push(listener)}/** * Create listener on message. * * @param {object} msg * @return {function} * @private */function createListener (msg) {  function listener (err) {    if (msg.__onFinished === listener) msg.__onFinished = null    if (!listener.queue) return    var queue = listener.queue    listener.queue = null    for (var i = 0; i < queue.length; i++) {      queue[i](err, msg)    }  }  listener.queue = []  return listener}/** * Patch ServerResponse.prototype.assignSocket for node.js 0.8. * * @param {ServerResponse} res * @param {function} callback * @private */// istanbul ignore next: node.js 0.8 patchfunction patchAssignSocket (res, callback) {  var assignSocket = res.assignSocket  if (typeof assignSocket !== 'function') return  // res.on('socket', callback) is broken in 0.8  res.assignSocket = function _assignSocket (socket) {    assignSocket.call(this, socket)    callback(socket)  }}/** * Try to require async_hooks * @private */function tryRequireAsyncHooks () {  try {    return require('async_hooks')  } catch (e) {    return {}  }}/** * Wrap function with async resource, if possible. * AsyncResource.bind static method backported. * @private */function wrap (fn) {  var res  // create anonymous resource  if (asyncHooks.AsyncResource) {    res = new asyncHooks.AsyncResource(fn.name || 'bound-anonymous-fn')  }  // incompatible node.js  if (!res || !res.runInAsyncScope) {    return fn  }  // return bound function  return res.runInAsyncScope.bind(res, fn, null)}
 |