From 7a16f72895754fda7e80635d5c160357f4a7aaed Mon Sep 17 00:00:00 2001 From: Matt Zabriskie Date: Fri, 22 Jan 2016 16:27:54 -0700 Subject: [PATCH] Improving logic for handling timeout in node closes #124 --- lib/adapters/http.js | 22 +++++++++++++++++++--- test/unit/adapters/http.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/lib/adapters/http.js b/lib/adapters/http.js index 9867752..395dd1c 100644 --- a/lib/adapters/http.js +++ b/lib/adapters/http.js @@ -13,6 +13,8 @@ var Buffer = require('buffer').Buffer; module.exports = function httpAdapter(resolve, reject, config) { var data = config.data; var headers = config.headers; + var timer; + var aborted = false; // Set User-Agent (required by some servers) // Only set header if it hasn't been set in config @@ -57,6 +59,12 @@ module.exports = function httpAdapter(resolve, reject, config) { // Create the request var transport = parsed.protocol === 'https:' ? https : http; var req = transport.request(options, function handleResponse(res) { + if (aborted) return; + + // Response has been received so kill timer that handles request timeout + clearTimeout(timer); + timer = null; + // uncompress the response body transparently if required var stream = res; switch (res.headers['content-encoding']) { @@ -103,13 +111,21 @@ module.exports = function httpAdapter(resolve, reject, config) { // Handle errors req.on('error', function handleRequestError(err) { + if (aborted) return; reject(err); }); // Handle request timeout - req.setTimeout(config.timeout, function handleRequestTimeout() { - req.abort(); - }); + if (config.timeout && !timer) { + timer = setTimeout(function handleRequestTimeout() { + var err = new Error('timeout of ' + config.timeout + 'ms exceeded'); + err.timeout = config.timeout; + err.code = 'ECONNABORTED'; + req.abort(); + reject(err); + aborted = true; + }, config.timeout); + } // Send the request req.end(data); diff --git a/test/unit/adapters/http.js b/test/unit/adapters/http.js index 98b5e5e..27e0080 100644 --- a/test/unit/adapters/http.js +++ b/test/unit/adapters/http.js @@ -11,6 +11,34 @@ module.exports = { callback(); }, + testTimeout: function (test) { + server = http.createServer(function (req, res) { + setTimeout(function () { + res.end(); + }, 1000); + }).listen(4444, function () { + var success = false, failure = false; + var error; + + axios.get('http://localhost:4444/', { + timeout: 250 + }).then(function (res) { + success = true; + }).catch(function (res) { + error = res; + failure = true; + }); + + setTimeout(function () { + test.equal(success, false, 'request should not succeed'); + test.equal(failure, true, 'request should fail'); + test.equal(error.code, 'ECONNABORTED'); + test.equal(error.message, 'timeout of 250ms exceeded'); + test.done(); + }, 300); + }); + }, + testJSON: function (test) { var data = { firstName: 'Fred',