arnaucube
arnaucube/thoughtsPublic Self-hosted repository
thoughts/node_modules/body-parser/node_modules/on-finished/index.js
node_modules/body-parser/node_modules/on-finished/index.jsRaw
  1/*!
  2 * on-finished
  3 * Copyright(c) 2013 Jonathan Ong
  4 * Copyright(c) 2014 Douglas Christopher Wilson
  5 * MIT Licensed
  6 */
  7
  8'use strict'
  9
 10/**
 11 * Module exports.
 12 * @public
 13 */
 14
 15module.exports = onFinished
 16module.exports.isFinished = isFinished
 17
 18/**
 19 * Module dependencies.
 20 * @private
 21 */
 22
 23var first = require('ee-first')
 24
 25/**
 26 * Variables.
 27 * @private
 28 */
 29
 30/* istanbul ignore next */
 31var defer = typeof setImmediate === 'function'
 32  ? setImmediate
 33  : function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) }
 34
 35/**
 36 * Invoke callback when the response has finished, useful for
 37 * cleaning up resources afterwards.
 38 *
 39 * @param {object} msg
 40 * @param {function} listener
 41 * @return {object}
 42 * @public
 43 */
 44
 45function onFinished(msg, listener) {
 46  if (isFinished(msg) !== false) {
 47    defer(listener, null, msg)
 48    return msg
 49  }
 50
 51  // attach the listener to the message
 52  attachListener(msg, listener)
 53
 54  return msg
 55}
 56
 57/**
 58 * Determine if message is already finished.
 59 *
 60 * @param {object} msg
 61 * @return {boolean}
 62 * @public
 63 */
 64
 65function isFinished(msg) {
 66  var socket = msg.socket
 67
 68  if (typeof msg.finished === 'boolean') {
 69    // OutgoingMessage
 70    return Boolean(msg.finished || (socket && !socket.writable))
 71  }
 72
 73  if (typeof msg.complete === 'boolean') {
 74    // IncomingMessage
 75    return Boolean(msg.upgrade || !socket || !socket.readable || (msg.complete && !msg.readable))
 76  }
 77
 78  // don't know
 79  return undefined
 80}
 81
 82/**
 83 * Attach a finished listener to the message.
 84 *
 85 * @param {object} msg
 86 * @param {function} callback
 87 * @private
 88 */
 89
 90function attachFinishedListener(msg, callback) {
 91  var eeMsg
 92  var eeSocket
 93  var finished = false
 94
 95  function onFinish(error) {
 96    eeMsg.cancel()
 97    eeSocket.cancel()
 98
 99    finished = true
100    callback(error)
101  }
102
103  // finished on first message event
104  eeMsg = eeSocket = first([[msg, 'end', 'finish']], onFinish)
105
106  function onSocket(socket) {
107    // remove listener
108    msg.removeListener('socket', onSocket)
109
110    if (finished) return
111    if (eeMsg !== eeSocket) return
112
113    // finished on first socket event
114    eeSocket = first([[socket, 'error', 'close']], onFinish)
115  }
116
117  if (msg.socket) {
118    // socket already assigned
119    onSocket(msg.socket)
120    return
121  }
122
123  // wait for socket to be assigned
124  msg.on('socket', onSocket)
125
126  if (msg.socket === undefined) {
127    // node.js 0.8 patch
128    patchAssignSocket(msg, onSocket)
129  }
130}
131
132/**
133 * Attach the listener to the message.
134 *
135 * @param {object} msg
136 * @return {function}
137 * @private
138 */
139
140function attachListener(msg, listener) {
141  var attached = msg.__onFinished
142
143  // create a private single listener with queue
144  if (!attached || !attached.queue) {
145    attached = msg.__onFinished = createListener(msg)
146    attachFinishedListener(msg, attached)
147  }
148
149  attached.queue.push(listener)
150}
151
152/**
153 * Create listener on message.
154 *
155 * @param {object} msg
156 * @return {function}
157 * @private
158 */
159
160function createListener(msg) {
161  function listener(err) {
162    if (msg.__onFinished === listener) msg.__onFinished = null
163    if (!listener.queue) return
164
165    var queue = listener.queue
166    listener.queue = null
167
168    for (var i = 0; i < queue.length; i++) {
169      queue[i](err, msg)
170    }
171  }
172
173  listener.queue = []
174
175  return listener
176}
177
178/**
179 * Patch ServerResponse.prototype.assignSocket for node.js 0.8.
180 *
181 * @param {ServerResponse} res
182 * @param {function} callback
183 * @private
184 */
185
186function patchAssignSocket(res, callback) {
187  var assignSocket = res.assignSocket
188
189  if (typeof assignSocket !== 'function') return
190
191  // res.on('socket', callback) is broken in 0.8
192  res.assignSocket = function _assignSocket(socket) {
193    assignSocket.call(this, socket)
194    callback(socket)
195  }
196}