3 * Copyright(c) 2013 Jonathan Ong
4 * Copyright(c) 2014 Douglas Christopher Wilson
15 module.exports = onFinished
16 module.exports.isFinished = isFinished
19 * Module dependencies.
23 var first = require('ee-first')
30 /* istanbul ignore next */
31 var defer = typeof setImmediate === 'function'
33 : function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) }
36 * Invoke callback when the response has finished, useful for
37 * cleaning up resources afterwards.
40 * @param {function} listener
45 function onFinished(msg, listener) {
46 if (isFinished(msg) !== false) {
47 defer(listener, null, msg)
51 // attach the listener to the message
52 attachListener(msg, listener)
58 * Determine if message is already finished.
65 function isFinished(msg) {
66 var socket = msg.socket
68 if (typeof msg.finished === 'boolean') {
70 return Boolean(msg.finished || (socket && !socket.writable))
73 if (typeof msg.complete === 'boolean') {
75 return Boolean(msg.upgrade || !socket || !socket.readable || (msg.complete && !msg.readable))
83 * Attach a finished listener to the message.
86 * @param {function} callback
90 function attachFinishedListener(msg, callback) {
95 function onFinish(error) {
103 // finished on first message event
104 eeMsg = eeSocket = first([[msg, 'end', 'finish']], onFinish)
106 function onSocket(socket) {
108 msg.removeListener('socket', onSocket)
111 if (eeMsg !== eeSocket) return
113 // finished on first socket event
114 eeSocket = first([[socket, 'error', 'close']], onFinish)
118 // socket already assigned
123 // wait for socket to be assigned
124 msg.on('socket', onSocket)
126 if (msg.socket === undefined) {
128 patchAssignSocket(msg, onSocket)
133 * Attach the listener to the message.
135 * @param {object} msg
140 function attachListener(msg, listener) {
141 var attached = msg.__onFinished
143 // create a private single listener with queue
144 if (!attached || !attached.queue) {
145 attached = msg.__onFinished = createListener(msg)
146 attachFinishedListener(msg, attached)
149 attached.queue.push(listener)
153 * Create listener on message.
155 * @param {object} msg
160 function createListener(msg) {
161 function listener(err) {
162 if (msg.__onFinished === listener) msg.__onFinished = null
163 if (!listener.queue) return
165 var queue = listener.queue
166 listener.queue = null
168 for (var i = 0; i < queue.length; i++) {
179 * Patch ServerResponse.prototype.assignSocket for node.js 0.8.
181 * @param {ServerResponse} res
182 * @param {function} callback
186 function patchAssignSocket(res, callback) {
187 var assignSocket = res.assignSocket
189 if (typeof assignSocket !== 'function') return
191 // res.on('socket', callback) is broken in 0.8
192 res.assignSocket = function _assignSocket(socket) {
193 assignSocket.call(this, socket)