Skip to content

Commit

Permalink
add isFinished function
Browse files Browse the repository at this point in the history
  • Loading branch information
dougwilson committed Aug 16, 2014
1 parent 1d3872e commit cafe7cb
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 36 deletions.
1 change: 1 addition & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
unreleased
==========

* add `isFinished` function
* remove support for non-`res` argument
* support both `req` and `res` as arguments
* deps: ee-first@1.0.5
Expand Down
21 changes: 16 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ $ npm install finished

## API

### finished(res, listener)
```js
var onFinished = require('finished')
```

### onFinished(res, listener)

Attach a listener to listen for the response to finish. The listener will
be invoked only once when the response finished. If the response finished
Expand All @@ -25,14 +29,12 @@ Listening to the end of a response would be used to close things associated
with the response, like open files.

```js
var onFinished = require('finished')

onFinished(res, function (err) {
// do something maybe
})
```

### finished(req, listener)
### onFinished(req, listener)

Attach a listener to listen for the request to finish. The listener will
be invoked only once when the request finished. If the request finished
Expand All @@ -43,7 +45,6 @@ after reading the data.

```js
var data = ''
var onFinished = require('finished')

req.setEncoding('utf8')
res.on('data', function (str) {
Expand All @@ -55,6 +56,16 @@ onFinished(req, function (err) {
})
```

### onFinished.isFinished(res)

Determine if `res` is already finished. This would be useful to check and
not even start certain operations if the response has already finished.

### onFinished.isFinished(req)

Determine if `req` is already finished. This would be useful to check and
not even start certain operations if the request has already finished.

### Example

The following code ensures that file descriptors are always closed
Expand Down
29 changes: 26 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@
* MIT Licensed
*/

/**
* Module exports.
*/

module.exports = finished;
module.exports.isFinished = isFinished;


/**
* Module dependencies.
*/
Expand All @@ -23,16 +31,16 @@ var defer = typeof setImmediate === 'function'
* Invoke callback when the response has finished, useful for
* cleaning up resources afterwards.
*
* @param {object} thingie
* @param {object} msg
* @param {function} callback
* @return {object}
* @api public
*/

module.exports = function finished(msg, callback) {
function finished(msg, callback) {
var socket = msg.socket

if (msg.finished || !socket.writable) {
if (isFinished(msg)) {
defer(callback)
return msg
}
Expand All @@ -59,3 +67,18 @@ module.exports = function finished(msg, callback) {

return msg
}

/**
* Determine is message is already finished.
*
* @param {object} msg
* @return {boolean}
* @api public
*/

function isFinished(msg) {
// finished for OutgoingMessage, complete for IncomingMessage
return msg.finished === true
|| msg.complete === true
|| msg.socket.writable === false
}
182 changes: 154 additions & 28 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,8 @@ describe('finished(res, listener)', function () {
onFinished(res, done)
setTimeout(res.end.bind(res), 0)
})
server.listen(function () {
var port = this.address().port
http.get('http://127.0.0.1:' + port, function (res) {
res.resume()
res.on('close', server.close.bind(server))
})
})

sendget(server)
})

it('should fire when called after finish', function (done) {
Expand All @@ -27,13 +22,8 @@ describe('finished(res, listener)', function () {
})
setTimeout(res.end.bind(res), 0)
})
server.listen(function () {
var port = this.address().port
http.get('http://127.0.0.1:' + port, function (res) {
res.resume()
res.on('close', server.close.bind(server))
})
})

sendget(server)
})
})

Expand Down Expand Up @@ -127,6 +117,73 @@ describe('finished(res, listener)', function () {
})
})

describe('isFinished(res)', function () {
it('should be false before response finishes', function (done) {
var server = http.createServer(function (req, res) {
assert.ok(!onFinished.isFinished(res))
res.end()
done()
})

sendget(server)
})

it('should be true after response finishes', function (done) {
var server = http.createServer(function (req, res) {
onFinished(res, function (err) {
assert.ifError(err)
assert.ok(onFinished.isFinished(res))
done()
})

res.end()
})

sendget(server)
})

describe('when response errors', function () {
it('should return true', function (done) {
var server = http.createServer(function (req, res) {
onFinished(res, function (err) {
assert.ok(err)
assert.ok(onFinished.isFinished(res))
done()
})

socket.on('error', noop)
socket.write('W')
})
var socket

server.listen(function () {
socket = net.connect(this.address().port, function () {
writerequest(this, true)
})
})
})
})

describe('when the response aborts', function () {
it('should return true', function (done) {
var client
var server = http.createServer(function (req, res) {
onFinished(res, function (err) {
assert.ifError(err)
assert.ok(onFinished.isFinished(res))
done()
})
setTimeout(client.abort.bind(client), 0)
})
server.listen(function () {
var port = this.address().port
client = http.get('http://127.0.0.1:' + port)
client.on('error', noop)
})
})
})
})

describe('finished(req, listener)', function () {
describe('when the request finishes', function () {
it('should fire the callback', function (done) {
Expand All @@ -135,13 +192,8 @@ describe('finished(req, listener)', function () {
req.resume()
setTimeout(res.end.bind(res), 0)
})
server.listen(function () {
var port = this.address().port
http.get('http://127.0.0.1:' + port, function (res) {
res.resume()
res.on('close', server.close.bind(server))
})
})

sendget(server)
})

it('should fire when called after finish', function (done) {
Expand All @@ -152,13 +204,8 @@ describe('finished(req, listener)', function () {
req.resume()
setTimeout(res.end.bind(res), 0)
})
server.listen(function () {
var port = this.address().port
http.get('http://127.0.0.1:' + port, function (res) {
res.resume()
res.on('close', server.close.bind(server))
})
})

sendget(server)
})
})

Expand Down Expand Up @@ -264,6 +311,75 @@ describe('finished(req, listener)', function () {
})
})

describe('isFinished(req)', function () {
it('should be false before request finishes', function (done) {
var server = http.createServer(function (req, res) {
assert.ok(!onFinished.isFinished(req))
req.resume()
res.end()
done()
})

sendget(server)
})

it('should be true after request finishes', function (done) {
var server = http.createServer(function (req, res) {
onFinished(req, function (err) {
assert.ifError(err)
assert.ok(onFinished.isFinished(req))
done()
})

req.resume()
res.end()
})

sendget(server)
})

describe('when request errors', function () {
it('should return true', function (done) {
var server = http.createServer(function (req, res) {
onFinished(req, function (err) {
assert.ok(err)
assert.ok(onFinished.isFinished(req))
done()
})

socket.on('error', noop)
socket.write('W')
})
var socket

server.listen(function () {
socket = net.connect(this.address().port, function () {
writerequest(this, true)
})
})
})
})

describe('when the request aborts', function () {
it('should return true', function (done) {
var client
var server = http.createServer(function (req, res) {
onFinished(res, function (err) {
assert.ifError(err)
assert.ok(onFinished.isFinished(req))
done()
})
setTimeout(client.abort.bind(client), 0)
})
server.listen(function () {
var port = this.address().port
client = http.get('http://127.0.0.1:' + port)
client.on('error', noop)
})
})
})
})

function captureStderr(fn) {
var chunks = []
var write = process.stderr.write
Expand All @@ -283,6 +399,16 @@ function captureStderr(fn) {

function noop() {}

function sendget(server) {
server.listen(function onListening() {
var port = this.address().port
http.get('http://127.0.0.1:' + port, function onResponse(res) {
res.resume()
res.on('close', server.close.bind(server))
})
})
}

function writerequest(socket, chunked) {
socket.write('GET / HTTP/1.1\r\n')
socket.write('Host: localhost\r\n')
Expand Down

0 comments on commit cafe7cb

Please sign in to comment.