Skip to content

Commit

Permalink
Added timeout option to abort the request before the response starts …
Browse files Browse the repository at this point in the history
…responding
  • Loading branch information
mbrevoort committed Jul 1, 2011
1 parent 44e4e56 commit b0cff72
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -43,6 +43,7 @@ The first argument is an options object. The only required option is uri, all ot
* `encoding` - Encoding to be used on response.setEncoding when buffering the response data.
* `pool` - A hash object containing the agents for these requests. If omitted this request will use the global pool which is set to node's default maxSockets.
* `pool.maxSockets` - Integer containing the maximum amount of sockets in the pool.
* `timeout` - Integer containing the number of milliseconds to wait for a request to response before aborting the request

The callback argument gets 3 arguments. The first is an error when applicable (usually from the http.Client option not the http.ClientRequest object). The second in an http.ClientResponse object. The third is the response body buffer.

Expand Down
8 changes: 8 additions & 0 deletions main.js
Expand Up @@ -211,6 +211,7 @@ Request.prototype.request = function () {
options.req = options.httpModule.request(options, function (response) {
options.response = response;
if (setHost) delete options.headers.host;
if (options.timeout && options.timeoutTimer) clearTimeout(options.timeoutTimer);

if (response.statusCode >= 300 &&
response.statusCode < 400 &&
Expand Down Expand Up @@ -277,6 +278,13 @@ Request.prototype.request = function () {
}
})

if (options.timeout) {
options.timeoutTimer = setTimeout(function() {
options.req.abort();
options.emit("error", "ETIMEDOUT");
}, options.timeout);
}

options.req.on('error', clientErrorHandler);
}

Expand Down
84 changes: 84 additions & 0 deletions tests/test-timeout.js
@@ -0,0 +1,84 @@
var server = require('./server')
, events = require('events')
, stream = require('stream')
, assert = require('assert')
, request = require('../main.js')
;

var s = server.createServer();
var expectedBody = "waited";
var remainingTests = 5;

// Request that waits for 200ms
s.on('/timeout', function (req, resp) {
setTimeout(function(){
resp.writeHead(200, {'content-type':'text/plain'})
resp.write(expectedBody)
resp.end()
}, 200);
});

// Scenario that should timeout
var shouldTimeout = {
url: s.url + "/timeout",
timeout:100
}

request(shouldTimeout, function (err, resp, body) {
assert.ok(err == "ETIMEDOUT");
checkDone();
})


// Scenario that shouldn't timeout
var shouldntTimeout = {
url: s.url + "/timeout",
timeout:300
}

request(shouldntTimeout, function (err, resp, body) {
assert.ok(!err);
assert.ok(expectedBody === body)
checkDone();
})

// Scenario with no timeout set, so shouldn't timeout
var noTimeout = {
url: s.url + "/timeout"
}

request(noTimeout, function (err, resp, body) {
assert.ok(!err);
assert.ok(expectedBody === body)
checkDone();
})

// Scenario with a negative timeout value, should be treated a zero or the minimum delay
var negativeTimeout = {
url: s.url + "/timeout",
timeout:-1000
}

request(negativeTimeout, function (err, resp, body) {
assert.ok(err == "ETIMEDOUT");
checkDone();
})

// Scenario with a float timeout value, should be rounded by setTimeout anyway
var floatTimeout = {
url: s.url + "/timeout",
timeout: 100.76
}

request(floatTimeout, function (err, resp, body) {
assert.ok(err == "ETIMEDOUT");
checkDone();
})

function checkDone() {
if(--remainingTests == 0) {
s.close();
console.log("All tests passed.");
}
}

0 comments on commit b0cff72

Please sign in to comment.