diff --git a/.travis.yml b/.travis.yml index d4f8a9d..4a1bf61 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,8 +4,8 @@ node_js: - '4.3.2' - '4' - '6' - - '7' - '8' + - '9' install: - npm i npminstall && npminstall script: diff --git a/appveyor.yml b/appveyor.yml index ccda1b5..181ac89 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,8 +3,8 @@ environment: - nodejs_version: '4.3.2' - nodejs_version: '4' - nodejs_version: '6' - - nodejs_version: '7' - nodejs_version: '8' + - nodejs_version: '9' install: - ps: Install-Product node $env:nodejs_version @@ -13,6 +13,6 @@ install: test_script: - node --version - npm --version - - npm run ci + - npm run test build: off diff --git a/lib/_http_agent.js b/lib/_http_agent.js index 57723d9..604a884 100644 --- a/lib/_http_agent.js +++ b/lib/_http_agent.js @@ -119,7 +119,10 @@ function Agent(options) { socket.once('error', freeSocketErrorListener); } // set free keepalive timer - socket.setTimeout(self.freeSocketKeepAliveTimeout); + // try to use socket custom freeSocketKeepAliveTimeout first + const freeSocketKeepAliveTimeout = socket.freeSocketKeepAliveTimeout || self.freeSocketKeepAliveTimeout; + socket.setTimeout(freeSocketKeepAliveTimeout); + debug(`push to free socket queue and wait for ${freeSocketKeepAliveTimeout}ms`); // [patch end] } } else { @@ -179,13 +182,14 @@ function handleSocketCreation(req) { } // [patch end] -Agent.prototype.addRequest = function addRequest(req, options) { +Agent.prototype.addRequest = function addRequest(req, options, port/*legacy*/, + localAddress/*legacy*/) { // Legacy API: addRequest(req, host, port, localAddress) if (typeof options === 'string') { options = { host: options, - port: arguments[2], - localAddress: arguments[3] + port, + localAddress }; } diff --git a/package.json b/package.json index 4a722a7..fc2a01c 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "node": ">= 4.0.0" }, "ci": { - "version": "4.3.2, 4, 6, 7, 8" + "version": "4.3.2, 4, 6, 8, 9" }, "author": "fengmk2 (https://fengmk2.com)", "license": "MIT" diff --git a/test/server_timeout.test.js b/test/server_timeout.test.js new file mode 100644 index 0000000..e97fec1 --- /dev/null +++ b/test/server_timeout.test.js @@ -0,0 +1,73 @@ +'use strict'; + +const assert = require('assert'); +const http = require('http'); +const Agent = require('..'); + +describe('test/server_timeout.test.js', () => { + let port; + let server; + before(done => { + server = http.createServer((req, res) => { + if (server.keepAliveTimeout) { + res.setHeader('Keep-Alive', `timeout=${parseInt(server.keepAliveTimeout / 1000)}`); + } + res.end('Hello World, ' + req.connection.remotePort); + }); + server.on('clientError', (err, socket) => { + socket.end('HTTP/1.1 400 Bad Request\r\n\r\n'); + }); + server.keepAliveTimeout = 1000; + server.listen(0, err => { + port = server.address().port; + done(err); + }); + }); + + it('should handle Keep-Alive header and not throw reset error', done => { + const keepaliveAgent = new Agent({ + keepAlive: true, + }); + + let count = 0; + function request() { + count++; + const req = http.request({ + method: 'GET', + port, + path: '/', + agent: keepaliveAgent, + }, res => { + assert(res.statusCode === 200); + const chunks = []; + res.on('data', data => { + chunks.push(data); + }); + res.on('end', () => { + const text = Buffer.concat(chunks).toString(); + console.log('[%s] status: %s, text: %s, headers: %j', count, text, res.statusCode, res.headers); + assert(res.headers.connection === 'keep-alive'); + assert(res.headers['keep-alive'] === 'timeout=1'); + const m = /^timeout=(\d+?)/.exec(res.headers['keep-alive']); + if (m) { + const keepAliveTimeout = parseInt(m[1]) * 1000 - 500; + if (keepAliveTimeout > 0) { + res.socket.freeSocketKeepAliveTimeout = keepAliveTimeout; + } + } + if (count > 5) { + done(); + } + }); + }); + req.on('error', err => { + console.error('[%s] error: %s', count, err); + done(err); + }); + req.end(); + } + + setInterval(request, server.keepAliveTimeout); + request(); + }); +});