agentkeepalive
Advanced tools
Comparing version 0.1.5 to 0.2.0
var https = require('https'); | ||
var HttpsAgent = require('../').HttpsAgent; | ||
var keepaliveAgent = new HttpsAgent(); | ||
var keepaliveAgent = new HttpsAgent({ | ||
keepAlive: true | ||
}); | ||
// https://www.google.com/search?q=nodejs&sugexp=chrome,mod=12&sourceid=chrome&ie=UTF-8 | ||
var options = { | ||
host: 'www.google.com', | ||
host: 'github.com', | ||
port: 443, | ||
path: '/search?q=nodejs&sugexp=chrome,mod=12&sourceid=chrome&ie=UTF-8', | ||
path: '/', | ||
method: 'GET', | ||
@@ -14,9 +16,23 @@ agent: keepaliveAgent | ||
var start = Date.now(); | ||
var req = https.request(options, function (res) { | ||
console.log('STATUS: ' + res.statusCode); | ||
console.log('HEADERS: ' + JSON.stringify(res.headers)); | ||
console.log('STATUS1: %d, %d ms', res.statusCode, Date.now() - start); | ||
console.log('HEADERS1: %j', res.headers); | ||
res.setEncoding('utf8'); | ||
res.on('data', function (chunk) { | ||
console.log('BODY: ' + chunk); | ||
console.log('BODY1: %d', chunk.length); | ||
}); | ||
res.on('end', function () { | ||
process.nextTick(function () { | ||
start = Date.now(); | ||
https.get(options, function (res) { | ||
console.log('STATUS2: %d, %d ms', res.statusCode, Date.now() - start); | ||
console.log('HEADERS2: %j', res.headers); | ||
res.setEncoding('utf8'); | ||
res.on('data', function (chunk) { | ||
console.log('BODY2: %d', chunk.length); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
@@ -30,5 +46,4 @@ | ||
setTimeout(function () { | ||
console.log('keep alive sockets:'); | ||
console.log(keepaliveAgent.unusedSockets); | ||
console.log('keep alive sockets:', keepaliveAgent); | ||
process.exit(); | ||
}, 2000); | ||
}, 5000); |
@@ -1,1 +0,1 @@ | ||
module.exports = process.env.AGENT_KEEPALIVE_COV ? require('./lib-cov/agent') : require('./lib/agent'); | ||
module.exports = require('./lib/agent'); |
158
lib/agent.js
@@ -7,4 +7,5 @@ /*! | ||
* * https://github.com/joyent/node/blob/master/lib/http.js | ||
* * https://github.com/joyent/node/blob/master/lib/_http_agent.js | ||
* | ||
* Copyright(c) 2012 fengmk2 <fengmk2@gmail.com> | ||
* Copyright(c) 2012 - 2013 fengmk2 <fengmk2@gmail.com> | ||
* MIT Licensed | ||
@@ -23,130 +24,51 @@ */ | ||
var debug; | ||
if (process.env.NODE_DEBUG && /agentkeepalive/.test(process.env.NODE_DEBUG)) { | ||
debug = function (x) { | ||
console.error('agentkeepalive:', x); | ||
}; | ||
} else { | ||
debug = function () { }; | ||
if (typeof http.Agent.request === 'function') { | ||
// node >= 0.11, default Agent is keepavlie | ||
module.exports = http.Agent; | ||
module.exports.HttpsAgent = https.Agent; | ||
return; | ||
} | ||
function Agent(options) { | ||
options = options || {}; | ||
http.Agent.call(this, options); | ||
var self = this; | ||
// max requests per keepalive socket, default is 0, no limit. | ||
self.maxKeepAliveRequests = parseInt(options.maxKeepAliveRequests, 10) || 0; | ||
// max keep alive time, default 60 seconds. | ||
// if set `maxKeepAliveTime = 0`, will disable keepalive feature. | ||
self.maxKeepAliveTime = parseInt(options.maxKeepAliveTime, 10); | ||
if (isNaN(self.maxKeepAliveTime)) { | ||
self.maxKeepAliveTime = 60000; | ||
} | ||
self.unusedSockets = {}; | ||
self.createSocketCount = 0; | ||
self.timeoutSocketCount = 0; | ||
self.requestFinishedCount = 0; | ||
var Agent = require('./_http_agent').Agent; | ||
module.exports = Agent; | ||
// override the `free` event listener | ||
self.removeAllListeners('free'); | ||
self.on('free', function (socket, host, port, localAddress) { | ||
self.requestFinishedCount++; | ||
socket._requestCount++; | ||
var name = host + ':' + port; | ||
if (localAddress) { | ||
name += ':' + localAddress; | ||
} | ||
if (self.requests[name] && self.requests[name].length > 0) { | ||
self.requests[name].shift().onSocket(socket); | ||
if (self.requests[name].length === 0) { | ||
// don't leak | ||
delete self.requests[name]; | ||
} | ||
} else { | ||
// If there are no pending requests just destroy the | ||
// socket and it will get removed from the pool. This | ||
// gets us out of timeout issues and allows us to | ||
// default to Connection:keep-alive. | ||
// socket.destroy(); | ||
if (self.maxKeepAliveTime === 0 || | ||
(self.maxKeepAliveRequests && socket._requestCount >= self.maxKeepAliveRequests)) { | ||
socket.destroy(); | ||
return; | ||
} | ||
// Avoid duplicitive timeout events by removing timeout listeners set on | ||
// socket by previous requests. node does not do this normally because it | ||
// assumes sockets are too short-lived for it to matter. It becomes a | ||
// problem when sockets are being reused. Steps are being taken to fix | ||
// this issue upstream in node v0.10.0. | ||
// | ||
// See https://github.com/joyent/node/commit/451ff1540ab536237e8d751d241d7fc3391a4087 | ||
if (self.maxKeepAliveTime && socket._events && Array.isArray(socket._events.timeout)) { | ||
socket.removeAllListeners('timeout'); | ||
// Restore the socket's setTimeout() that was remove as collateral | ||
// damage. | ||
socket.setTimeout(self.maxKeepAliveTime, socket._maxKeepAliveTimeout); | ||
} | ||
// keepalive | ||
if (!self.unusedSockets[name]) { | ||
self.unusedSockets[name] = []; | ||
} | ||
self.unusedSockets[name].push(socket); | ||
} | ||
}); | ||
function HttpsAgent(options) { | ||
Agent.call(this, options); | ||
this.defaultPort = 443; | ||
this.protocol = 'https:'; | ||
} | ||
util.inherits(HttpsAgent, Agent); | ||
HttpsAgent.prototype.createConnection = https.globalAgent.createConnection; | ||
util.inherits(Agent, http.Agent); | ||
module.exports = Agent; | ||
HttpsAgent.prototype.getName = function(options) { | ||
var name = Agent.prototype.getName.call(this, options); | ||
Agent.prototype.addRequest = function (req, host, port, localAddress) { | ||
var name = host + ':' + port; | ||
if (localAddress) { | ||
name += ':' + localAddress; | ||
} | ||
if (this.unusedSockets[name] && this.unusedSockets[name].length > 0) { | ||
return req.onSocket(this.unusedSockets[name].shift()); | ||
} | ||
return http.Agent.prototype.addRequest.call(this, req, host, port, localAddress); | ||
}; | ||
name += ':'; | ||
if (options.ca) | ||
name += options.ca; | ||
Agent.prototype.createSocket = function (name, host, port, localAddress, req) { | ||
var self = this; | ||
var socket = http.Agent.prototype.createSocket.call(this, name, host, port, localAddress, req); | ||
socket._requestCount = 0; | ||
if (self.maxKeepAliveTime) { | ||
socket._maxKeepAliveTimeout = function () { | ||
socket.destroy(); | ||
self.timeoutSocketCount++; | ||
}; | ||
socket.setTimeout(self.maxKeepAliveTime, socket._maxKeepAliveTimeout); | ||
// Disable Nagle's algorithm: http://blog.caustik.com/2012/04/08/scaling-node-js-to-100k-concurrent-connections/ | ||
socket.setNoDelay(true); | ||
} | ||
this.createSocketCount++; | ||
return socket; | ||
}; | ||
name += ':'; | ||
if (options.cert) | ||
name += options.cert; | ||
Agent.prototype.removeSocket = function (socket, name, host, port, localAddress) { | ||
if (this.unusedSockets[name]) { | ||
var unusedIndex = this.unusedSockets[name].indexOf(socket); | ||
if (unusedIndex !== -1) { | ||
this.unusedSockets[name].splice(unusedIndex, 1); | ||
if (this.unusedSockets[name].length === 0) { | ||
// don't leak | ||
delete this.unusedSockets[name]; | ||
} | ||
} | ||
} | ||
return http.Agent.prototype.removeSocket.call(this, socket, name, host, port, localAddress); | ||
name += ':'; | ||
if (options.ciphers) | ||
name += options.ciphers; | ||
name += ':'; | ||
if (options.key) | ||
name += options.key; | ||
name += ':'; | ||
if (options.pfx) | ||
name += options.pfx; | ||
name += ':'; | ||
if (options.rejectUnauthorized !== undefined) | ||
name += options.rejectUnauthorized; | ||
return name; | ||
}; | ||
function HttpsAgent(options) { | ||
Agent.call(this, options); | ||
this.createConnection = https.globalAgent.createConnection; | ||
} | ||
util.inherits(HttpsAgent, Agent); | ||
HttpsAgent.prototype.defaultPort = 443; | ||
Agent.HttpsAgent = HttpsAgent; |
{ | ||
"name": "agentkeepalive", | ||
"version": "0.1.5", | ||
"version": "0.2.0", | ||
"description": "Missing keepalive http.Agent", | ||
@@ -10,3 +10,5 @@ "main": "index.js", | ||
"scripts": { | ||
"test": "make test" | ||
"test": "make test-all", | ||
"blanket": { "pattern": "agentkeepalive/lib" }, | ||
"travis-cov": { "threshold": 92 } | ||
}, | ||
@@ -29,6 +31,10 @@ "repository": { | ||
"pedding": "*", | ||
"visionmedia-jscoverage": "*" | ||
"blanket": "*", | ||
"travis-cov": "*", | ||
"coveralls": "*", | ||
"mocha-lcov-reporter": "*" | ||
}, | ||
"engines": { "node": ">= 0.10.0" }, | ||
"author": "fengmk2 <fengmk2@gmail.com> (http://fengmk2.github.com)", | ||
"license": "MIT" | ||
} |
@@ -1,10 +0,7 @@ | ||
agentkeepalive | ||
============== | ||
# agentkeepalive [![Build Status](https://secure.travis-ci.org/TBEDP/agentkeepalive.png?branch=master)](http://travis-ci.org/TBEDP/agentkeepalive) [![Coverage Status](https://coveralls.io/repos/TBEDP/agentkeepalive/badge.png)](https://coveralls.io/r/TBEDP/agentkeepalive) | ||
[![Build Status](https://secure.travis-ci.org/TBEDP/agentkeepalive.png?branch=master)](http://travis-ci.org/TBEDP/agentkeepalive) | ||
![logo](https://raw.github.com/TBEDP/agentkeepalive/master/logo.png) | ||
The nodejs's missing `keep alive` `http.Agent`. Support `http` and `https`. | ||
jscoverage: [**93%**](http://fengmk2.github.com/coverage/agentkeepalive.html) | ||
## Install | ||
@@ -176,3 +173,3 @@ | ||
Copyright (c) 2012 fengmk2 <fengmk2@gmail.com>; | ||
Copyright (c) 2012 - 2013 fengmk2 <fengmk2@gmail.com>; | ||
@@ -196,2 +193,2 @@ Permission is hereby granted, free of charge, to any person obtaining | ||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
2
57057
7
14
603
193
9