diff --git a/README.md b/README.md index 617c49f..c13f9bc 100644 --- a/README.md +++ b/README.md @@ -550,6 +550,7 @@ If you have a suggestion for a feature currently not supported, feel free to ope xforward: true // enables X-Forwarded-For }, changeOrigin: false, // changes the origin of the host header to the target URL + timeout: 120000 // override the default 2 minute http socket timeout value in milliseconds } ``` diff --git a/lib/node-http-proxy/http-proxy.js b/lib/node-http-proxy/http-proxy.js index cc4f9f1..da3ac1d 100644 --- a/lib/node-http-proxy/http-proxy.js +++ b/lib/node-http-proxy/http-proxy.js @@ -66,6 +66,7 @@ var HttpProxy = exports.HttpProxy = function (options) { // this.forward = options.forward; this.target = options.target; + this.timeout = options.timeout; // // Setup the necessary instances instance variables for @@ -163,6 +164,9 @@ HttpProxy.prototype.proxyRequest = function (req, res, buffer) { req.headers['x-forwarded-proto'] = getProto(req); } } + if(this.timeout) { + req.socket.setTimeout(this.timeout); + } // // Emit the `start` event indicating that we have begun the proxy operation. @@ -350,10 +354,17 @@ HttpProxy.prototype.proxyRequest = function (req, res, buffer) { }); // - // Handle 'error' events from the `reverseProxy`. + // Handle 'error' events from the `reverseProxy`. Setup timeout override if needed // reverseProxy.once('error', proxyError); + // Set a timeout on the socket if `this.timeout` is specified. + reverseProxy.once('socket', function (socket) { + if (self.timeout) { + socket.setTimeout(self.timeout); + } + }); + // // Handle 'error' events from the `req` (e.g. `Parse Error`). // @@ -899,4 +910,4 @@ HttpProxy.prototype._forwardRequest = function (req) { function getProto(req) { return req.isSpdy ? 'https' : (req.connection.pair ? 'https' : 'http'); -} \ No newline at end of file +} diff --git a/test/helpers/http.js b/test/helpers/http.js index 24749be..aaf7a80 100644 --- a/test/helpers/http.js +++ b/test/helpers/http.js @@ -67,9 +67,11 @@ exports.createServer = function (options, callback) { }); } - res.writeHead(200, { 'Content-Type': 'text/plain' }); - res.write(options.output || 'hello proxy'); - res.end(); + setTimeout(function() { + res.writeHead(200, { 'Content-Type': 'text/plain' }); + res.write(options.output || 'hello proxy'); + res.end(); + }, options.latency || 1); } var server = protocols.target === 'https' diff --git a/test/http/http-test.js b/test/http/http-test.js index 363e8c9..b25aa85 100644 --- a/test/http/http-test.js +++ b/test/http/http-test.js @@ -76,7 +76,12 @@ vows.describe(helpers.describe()).addBatch({ outputHeaders: { "x-testheader": "target" }, latency: 1000 }) - } + }, + "and timeout set": macros.http.assertProxied({ + shouldFail: true, + timeout: 2000, + requestLatency: 4000 + }) }, "With a no valid target server": { "and no latency": macros.http.assertInvalidProxy(), diff --git a/test/macros/http.js b/test/macros/http.js index b8cf57b..61c9cd1 100644 --- a/test/macros/http.js +++ b/test/macros/http.js @@ -49,6 +49,30 @@ exports.assertRequest = function (options) { }; }; +// +// ### function assertFailedRequest (options) +// #### @options {Object} Options for this failed request assertion. +// #### @request {Object} Options to use for `request`. +// #### @assert {Object} Test assertions against the response. +// +// Makes a request using `options.request` and then asserts the response +// and body against anything in `options.assert`. +// +exports.assertFailedRequest = function (options) { + return { + topic: function () { + // + // Now make the HTTP request and assert. + // + options.request.rejectUnauthorized = false; + request(options.request, this.callback); + }, + "should not succeed": function (err, res, body) { + assert.notStrictEqual(err,null); + } + }; +}; + // // ### function assertProxied (options) // #### @options {Object} Options for this test @@ -63,14 +87,17 @@ exports.assertRequest = function (options) { exports.assertProxied = function (options) { options = options || {}; - var ports = options.ports || helpers.nextPortPair, + var ports = options.ports || helpers.nextPortPair, output = options.output || 'hello world from ' + ports.target, outputHeaders = options.outputHeaders, targetHeaders = options.targetHeaders, proxyHeaders = options.proxyHeaders, protocol = helpers.protocols.proxy, - req = options.request || {}; - + req = options.request || {}, + timeout = options.timeout || null, + assertFn = options.shouldFail + ? exports.assertFailedRequest + : exports.assertRequest; req.uri = req.uri || protocol + '://127.0.0.1:' + ports.proxy; @@ -85,7 +112,8 @@ exports.assertProxied = function (options) { output: output, outputHeaders: targetHeaders, port: ports.target, - headers: req.headers + headers: req.headers, + latency: options.requestLatency }, proxy: { latency: options.latency, @@ -97,12 +125,13 @@ exports.assertProxied = function (options) { https: helpers.protocols.target === 'https', host: '127.0.0.1', port: ports.target - } + }, + timeout: timeout } } }, this.callback); }, - "the proxy request": exports.assertRequest({ + "the proxy request": assertFn({ request: req, assert: { headers: outputHeaders,