3 * Copyright(c) 2013 Jonathan Ong
4 * Copyright(c) 2014 Douglas Christopher Wilson
12 module.exports = onFinished;
13 module.exports.isFinished = isFinished;
16 * Module dependencies.
19 var first = require('ee-first')
25 /* istanbul ignore next */
26 var defer = typeof setImmediate === 'function'
28 : function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) }
31 * Invoke callback when the response has finished, useful for
32 * cleaning up resources afterwards.
35 * @param {function} listener
40 function onFinished(msg, listener) {
41 if (isFinished(msg) !== false) {
42 defer(listener, null, msg)
46 // attach the listener to the message
47 attachListener(msg, listener)
53 * Determine if message is already finished.
60 function isFinished(msg) {
61 var socket = msg.socket
63 if (typeof msg.finished === 'boolean') {
65 return Boolean(msg.finished || (socket && !socket.writable))
68 if (typeof msg.complete === 'boolean') {
70 return Boolean(!socket || msg.complete || !socket.readable)
78 * Attach a finished listener to the message.
81 * @param {function} callback
85 function attachFinishedListener(msg, callback) {
90 function onFinish(error) {
98 // finished on first message event
99 eeMsg = eeSocket = first([[msg, 'end', 'finish']], onFinish)
101 function onSocket(socket) {
103 msg.removeListener('socket', onSocket)
106 if (eeMsg !== eeSocket) return
108 // finished on first socket event
109 eeSocket = first([[socket, 'error', 'close']], onFinish)
113 // socket already assigned
118 // wait for socket to be assigned
119 msg.on('socket', onSocket)
121 if (msg.socket === undefined) {
123 patchAssignSocket(msg, onSocket)
128 * Attach the listener to the message.
130 * @param {object} msg
135 function attachListener(msg, listener) {
136 var attached = msg.__onFinished
138 // create a private single listener with queue
139 if (!attached || !attached.queue) {
140 attached = msg.__onFinished = createListener(msg)
141 attachFinishedListener(msg, attached)
144 attached.queue.push(listener)
148 * Create listener on message.
150 * @param {object} msg
155 function createListener(msg) {
156 function listener(err) {
157 if (msg.__onFinished === listener) msg.__onFinished = null
158 if (!listener.queue) return
160 var queue = listener.queue
161 listener.queue = null
163 for (var i = 0; i < queue.length; i++) {
174 * Patch ServerResponse.prototype.assignSocket for node.js 0.8.
176 * @param {ServerResponse} res
177 * @param {function} callback
181 function patchAssignSocket(res, callback) {
182 var assignSocket = res.assignSocket
184 if (typeof assignSocket !== 'function') return
186 // res.on('socket', callback) is broken in 0.8
187 res.assignSocket = function _assignSocket(socket) {
188 assignSocket.call(this, socket)