diff options
Diffstat (limited to 'node_modules/agentkeepalive')
| -rw-r--r-- | node_modules/agentkeepalive/History.md | 104 | ||||
| -rw-r--r-- | node_modules/agentkeepalive/README.md | 234 | ||||
| -rw-r--r-- | node_modules/agentkeepalive/browser.js | 5 | ||||
| -rw-r--r-- | node_modules/agentkeepalive/index.js | 2 | ||||
| -rw-r--r-- | node_modules/agentkeepalive/lib/_http_agent.js | 334 | ||||
| -rw-r--r-- | node_modules/agentkeepalive/lib/agent.js | 97 | ||||
| -rw-r--r-- | node_modules/agentkeepalive/lib/https_agent.js | 95 | ||||
| -rw-r--r-- | node_modules/agentkeepalive/lib/utils.js | 31 | ||||
| -rw-r--r-- | node_modules/agentkeepalive/package.json | 47 |
9 files changed, 949 insertions, 0 deletions
diff --git a/node_modules/agentkeepalive/History.md b/node_modules/agentkeepalive/History.md new file mode 100644 index 00000000..b36e0669 --- /dev/null +++ b/node_modules/agentkeepalive/History.md @@ -0,0 +1,104 @@ + +2.2.0 / 2016-06-26 +================== + + * feat: Add browser shim (noop) for isomorphic use. (#39) + * chore: add security check badge + +2.1.1 / 2016-04-06 +================== + + * https: fix ssl socket leak when keepalive is used + * chore: remove circle ci image + +2.1.0 / 2016-04-02 +================== + + * fix: opened sockets number overflow maxSockets + +2.0.5 / 2016-03-16 +================== + + * fix: pick _evictSession to httpsAgent + +2.0.4 / 2016-03-13 +================== + + * test: add Circle ci + * test: add appveyor ci build + * refactor: make sure only one error listener + * chore: use codecov + * fix: handle idle socket error + * test: run on more node versions + +2.0.3 / 2015-08-03 +================== + + * fix: add default error handler to avoid Unhandled error event throw + +2.0.2 / 2015-04-25 +================== + + * fix: remove socket from freeSockets on 'timeout' (@pmalouin) + +2.0.1 / 2015-04-19 +================== + + * fix: add timeoutSocketCount to getCurrentStatus() + * feat(getCurrentStatus): add getCurrentStatus + +2.0.0 / 2015-04-01 +================== + + * fix: socket.destroyed always be undefined on 0.10.x + * Make it compatible with node v0.10.x (@lattmann) + +1.2.1 / 2015-03-23 +================== + + * patch from iojs: don't overwrite servername option + * patch commits from joyent/node + * add max sockets test case + * add nagle algorithm delayed link + +1.2.0 / 2014-09-02 +================== + + * allow set keepAliveTimeout = 0 + * support timeout on working socket. fixed #6 + +1.1.0 / 2014-08-28 +================== + + * add some socket counter for deep monitor + +1.0.0 / 2014-08-13 +================== + + * update _http_agent, only support 0.11+, only support node 0.11.0+ + +0.2.2 / 2013-11-19 +================== + + * support node 0.8 and node 0.10 + +0.2.1 / 2013-11-08 +================== + + * fix socket does not timeout bug, it will hang on life, must use 0.2.x on node 0.11 + +0.2.0 / 2013-11-06 +================== + + * use keepalive agent on node 0.11+ impl + +0.1.5 / 2013-06-24 +================== + + * support coveralls + * add node 0.10 test + * add 0.8.22 original https.js + * add original http.js module to diff + * update jscover + * mv pem to fixtures + * add https agent usage diff --git a/node_modules/agentkeepalive/README.md b/node_modules/agentkeepalive/README.md new file mode 100644 index 00000000..59a47a46 --- /dev/null +++ b/node_modules/agentkeepalive/README.md @@ -0,0 +1,234 @@ +# agentkeepalive + +[![NPM version][npm-image]][npm-url] +[![build status][travis-image]][travis-url] +[![Appveyor status][appveyor-image]][appveyor-url] +[![Test coverage][codecov-image]][codecov-url] +[![David deps][david-image]][david-url] +[![Known Vulnerabilities][snyk-image]][snyk-url] +[![npm download][download-image]][download-url] + +[npm-image]: https://img.shields.io/npm/v/agentkeepalive.svg?style=flat +[npm-url]: https://npmjs.org/package/agentkeepalive +[travis-image]: https://img.shields.io/travis/node-modules/agentkeepalive.svg?style=flat +[travis-url]: https://travis-ci.org/node-modules/agentkeepalive +[appveyor-image]: https://ci.appveyor.com/api/projects/status/k7ct4s47di6m5uy2?svg=true +[appveyor-url]: https://ci.appveyor.com/project/fengmk2/agentkeepalive +[codecov-image]: https://codecov.io/gh/node-modules/agentkeepalive/branch/master/graph/badge.svg +[codecov-url]: https://codecov.io/gh/node-modules/agentkeepalive +[david-image]: https://img.shields.io/david/node-modules/agentkeepalive.svg?style=flat +[david-url]: https://david-dm.org/node-modules/agentkeepalive +[snyk-image]: https://snyk.io/test/npm/agentkeepalive/badge.svg?style=flat-square +[snyk-url]: https://snyk.io/test/npm/agentkeepalive +[download-image]: https://img.shields.io/npm/dm/agentkeepalive.svg?style=flat-square +[download-url]: https://npmjs.org/package/agentkeepalive + +The Node.js's missing `keep alive` `http.Agent`. Support `http` and `https`. + +## Install + +```bash +$ npm install agentkeepalive --save +``` + +## new Agent([options]) + +* `options` {Object} Set of configurable options to set on the agent. + Can have the following fields: + * `keepAlive` {Boolean} Keep sockets around in a pool to be used by + other requests in the future. Default = `true` + * `keepAliveMsecs` {Number} When using HTTP KeepAlive, how often + to send TCP KeepAlive packets over sockets being kept alive. + Default = `1000`. Only relevant if `keepAlive` is set to `true`. + * `keepAliveTimeout`: {Number} Sets the free socket to timeout + after `keepAliveTimeout` milliseconds of inactivity on the free socket. + Default is `15000`. + Only relevant if `keepAlive` is set to `true`. + * `timeout`: {Number} Sets the working socket to timeout + after `timeout` milliseconds of inactivity on the working socket. + Default is `keepAliveTimeout * 2`. + * `maxSockets` {Number} Maximum number of sockets to allow per + host. Default = `Infinity`. + * `maxFreeSockets` {Number} Maximum number of sockets to leave open + in a free state. Only relevant if `keepAlive` is set to `true`. + Default = `256`. + +## Usage + +```js +var http = require('http'); +var Agent = require('agentkeepalive'); + +var keepaliveAgent = new Agent({ + maxSockets: 100, + maxFreeSockets: 10, + timeout: 60000, + keepAliveTimeout: 30000 // free socket keepalive for 30 seconds +}); + +var options = { + host: 'cnodejs.org', + port: 80, + path: '/', + method: 'GET', + agent: keepaliveAgent +}; + +var req = http.request(options, function (res) { + console.log('STATUS: ' + res.statusCode); + console.log('HEADERS: ' + JSON.stringify(res.headers)); + res.setEncoding('utf8'); + res.on('data', function (chunk) { + console.log('BODY: ' + chunk); + }); +}); + +req.on('error', function (e) { + console.log('problem with request: ' + e.message); +}); +req.end(); + +setTimeout(function () { + console.log('keep alive sockets:'); + console.log(keepaliveAgent.unusedSockets); +}, 2000); + +``` + +### `agent.getCurrentStatus()` + +`agent.getCurrentStatus()` will return a object to show the status of this agent: + +```js +{ + createSocketCount: 10, + closeSocketCount: 5, + timeoutSocketCount: 0, + requestCount: 5, + freeSockets: { 'localhost:57479::': 3 }, + sockets: { 'localhost:57479::': 5 }, + requests: {} +} +``` + +### Support `https` + +```js +var https = require('https'); +var HttpsAgent = require('agentkeepalive').HttpsAgent; + +var keepaliveAgent = new HttpsAgent(); +// https://www.google.com/search?q=nodejs&sugexp=chrome,mod=12&sourceid=chrome&ie=UTF-8 +var options = { + host: 'www.google.com', + port: 443, + path: '/search?q=nodejs&sugexp=chrome,mod=12&sourceid=chrome&ie=UTF-8', + method: 'GET', + agent: keepaliveAgent +}; + +var req = https.request(options, function (res) { + console.log('STATUS: ' + res.statusCode); + console.log('HEADERS: ' + JSON.stringify(res.headers)); + res.setEncoding('utf8'); + res.on('data', function (chunk) { + console.log('BODY: ' + chunk); + }); +}); + +req.on('error', function (e) { + console.log('problem with request: ' + e.message); +}); +req.end(); + +setTimeout(function () { + console.log('keep alive sockets:'); + console.log(keepaliveAgent.unusedSockets); + process.exit(); +}, 2000); +``` + +## [Benchmark](https://github.com/node-modules/agentkeepalive/tree/master/benchmark) + +run the benchmark: + +```bash +cd benchmark +sh start.sh +``` + +Intel(R) Core(TM)2 Duo CPU P8600 @ 2.40GHz + +node@v0.8.9 + +50 maxSockets, 60 concurrent, 1000 requests per concurrent, 5ms delay + +Keep alive agent (30 seconds): + +```js +Transactions: 60000 hits +Availability: 100.00 % +Elapsed time: 29.70 secs +Data transferred: 14.88 MB +Response time: 0.03 secs +Transaction rate: 2020.20 trans/sec +Throughput: 0.50 MB/sec +Concurrency: 59.84 +Successful transactions: 60000 +Failed transactions: 0 +Longest transaction: 0.15 +Shortest transaction: 0.01 +``` + +Normal agent: + +```js +Transactions: 60000 hits +Availability: 100.00 % +Elapsed time: 46.53 secs +Data transferred: 14.88 MB +Response time: 0.05 secs +Transaction rate: 1289.49 trans/sec +Throughput: 0.32 MB/sec +Concurrency: 59.81 +Successful transactions: 60000 +Failed transactions: 0 +Longest transaction: 0.45 +Shortest transaction: 0.00 +``` + +Socket created: + +``` +[proxy.js:120000] keepalive, 50 created, 60000 requestFinished, 1200 req/socket, 0 requests, 0 sockets, 0 unusedSockets, 50 timeout +{" <10ms":662," <15ms":17825," <20ms":20552," <30ms":17646," <40ms":2315," <50ms":567," <100ms":377," <150ms":56," <200ms":0," >=200ms+":0} +---------------------------------------------------------------- +[proxy.js:120000] normal , 53866 created, 84260 requestFinished, 1.56 req/socket, 0 requests, 0 sockets +{" <10ms":75," <15ms":1112," <20ms":10947," <30ms":32130," <40ms":8228," <50ms":3002," <100ms":4274," <150ms":181," <200ms":18," >=200ms+":33} +``` + +## License + +(The MIT License) + +Copyright(c) 2012 - 2015 fengmk2 <fengmk2@gmail.com> +Copyright(c) node-modules and other contributors. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/agentkeepalive/browser.js b/node_modules/agentkeepalive/browser.js new file mode 100644 index 00000000..29c9398a --- /dev/null +++ b/node_modules/agentkeepalive/browser.js @@ -0,0 +1,5 @@ +module.exports = noop; +module.exports.HttpsAgent = noop; + +// Noop function for browser since native api's don't use agents. +function noop () {} diff --git a/node_modules/agentkeepalive/index.js b/node_modules/agentkeepalive/index.js new file mode 100644 index 00000000..bdc76692 --- /dev/null +++ b/node_modules/agentkeepalive/index.js @@ -0,0 +1,2 @@ +module.exports = require('./lib/agent'); +module.exports.HttpsAgent = require('./lib/https_agent'); diff --git a/node_modules/agentkeepalive/lib/_http_agent.js b/node_modules/agentkeepalive/lib/_http_agent.js new file mode 100644 index 00000000..3c20b028 --- /dev/null +++ b/node_modules/agentkeepalive/lib/_http_agent.js @@ -0,0 +1,334 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +// copy from https://github.com/nodejs/node/blob/v4.x/lib/_http_agent.js + +'use strict'; + +var net = require('net'); +var util = require('util'); +var EventEmitter = require('events').EventEmitter; +var debug = require('./utils').debug; + +// New Agent code. + +// The largest departure from the previous implementation is that +// an Agent instance holds connections for a variable number of host:ports. +// Surprisingly, this is still API compatible as far as third parties are +// concerned. The only code that really notices the difference is the +// request object. + +// Another departure is that all code related to HTTP parsing is in +// ClientRequest.onSocket(). The Agent is now *strictly* +// concerned with managing a connection pool. + +function Agent(options) { + if (!(this instanceof Agent)) + return new Agent(options); + + EventEmitter.call(this); + + var self = this; + + self.defaultPort = 80; + self.protocol = 'http:'; + + self.options = util._extend({}, options); + + // don't confuse net and make it think that we're connecting to a pipe + self.options.path = null; + self.requests = {}; + self.sockets = {}; + self.freeSockets = {}; + self.keepAliveMsecs = self.options.keepAliveMsecs || 1000; + self.keepAlive = self.options.keepAlive || false; + // free keep-alive socket timeout. By default free socket do not have a timeout. + // keepAliveTimeout should be rename to `freeSocketKeepAliveTimeout` + self.keepAliveTimeout = self.options.keepAliveTimeout || 0; + // working socket timeout. By default working socket do not have a timeout. + self.timeout = self.options.timeout || 0; + self.maxSockets = self.options.maxSockets || Agent.defaultMaxSockets; + self.maxFreeSockets = self.options.maxFreeSockets || 256; + + self.on('free', function(socket, options) { + var name = self.getName(options); + debug('agent.on(free)', name); + + if (!socket.destroyed && + self.requests[name] && self.requests[name].length) { + self.requests[name].shift().onSocket(socket); + if (self.requests[name].length === 0) { + // don't leak + delete self.requests[name]; + } + debug('continue handle next request'); + } else { + // If there are no pending requests, then put it in + // the freeSockets pool, but only if we're allowed to do so. + var req = socket._httpMessage; + if (req && + req.shouldKeepAlive && + !socket.destroyed && + self.options.keepAlive) { + var freeSockets = self.freeSockets[name]; + var freeLen = freeSockets ? freeSockets.length : 0; + var count = freeLen; + if (self.sockets[name]) + count += self.sockets[name].length; + // console.log(count, freeLen, self.maxSockets, self.maxFreeSockets) + if (count > self.maxSockets || freeLen >= self.maxFreeSockets) { + // console.log('hit max sockets', count, freeLen, self.maxSockets, self.maxFreeSockets); + self.removeSocket(socket, options); + socket.destroy(); + } else { + freeSockets = freeSockets || []; + self.freeSockets[name] = freeSockets; + socket.setKeepAlive(true, self.keepAliveMsecs); + socket.unref && socket.unref(); + socket._httpMessage = null; + self.removeSocket(socket, options); + freeSockets.push(socket); + + // Add a default error handler to avoid Unhandled 'error' event throw on idle socket + // https://github.com/node-modules/agentkeepalive/issues/25 + // https://github.com/nodejs/node/pull/4482 (fixed in >= 4.4.0 and >= 5.4.0) + if (socket.listeners('error').length === 0) { + socket.once('error', freeSocketErrorListener); + } + + // set free keepalive timer + socket.setTimeout(self.keepAliveTimeout); + } + } else { + self.removeSocket(socket, options); + socket.destroy(); + } + } + }); +} + +util.inherits(Agent, EventEmitter); +exports.Agent = Agent; + +function freeSocketErrorListener(err) { + var socket = this; + debug('SOCKET ERROR on FREE socket:', err.message, err.stack); + socket.destroy(); + socket.emit('agentRemove'); +} + +Agent.defaultMaxSockets = Infinity; + +Agent.prototype.createConnection = net.createConnection; + +// Get the key for a given set of request options +Agent.prototype.getName = function(options) { + var name = ''; + + if (options.host) + name += options.host; + else + name += 'localhost'; + + name += ':'; + if (options.port) + name += options.port; + name += ':'; + if (options.localAddress) + name += options.localAddress; + name += ':'; + return name; +}; + +Agent.prototype.addRequest = function(req, options) { + // Legacy API: addRequest(req, host, port, path) + if (typeof options === 'string') { + options = { + host: options, + port: arguments[2], + path: arguments[3] + }; + } + + options = util._extend({}, options); + options = util._extend(options, this.options); + + var name = this.getName(options); + if (!this.sockets[name]) { + this.sockets[name] = []; + } + + var freeLen = this.freeSockets[name] ? this.freeSockets[name].length : 0; + var sockLen = freeLen + this.sockets[name].length; + + if (freeLen) { + // we have a free socket, so use that. + var socket = this.freeSockets[name].shift(); + debug('have free socket'); + + socket.removeListener('error', freeSocketErrorListener); + + // restart the default timer + socket.setTimeout(this.timeout); + + // don't leak + if (!this.freeSockets[name].length) + delete this.freeSockets[name]; + + socket.ref && socket.ref(); + req.onSocket(socket); + this.sockets[name].push(socket); + } else if (sockLen < this.maxSockets) { + debug('call onSocket', sockLen, freeLen); + // If we are under maxSockets create a new one. + req.onSocket(this.createSocket(req, options)); + } else { + debug('wait for socket'); + // We are over limit so we'll add it to the queue. + if (!this.requests[name]) { + this.requests[name] = []; + } + this.requests[name].push(req); + } +}; + +Agent.prototype.createSocket = function(req, options) { + var self = this; + options = util._extend({}, options); + options = util._extend(options, self.options); + + if (!options.servername) { + options.servername = options.host; + if (req) { + var hostHeader = req.getHeader('host'); + if (hostHeader) { + options.servername = hostHeader.replace(/:.*$/, ''); + } + } + } + + var name = self.getName(options); + + debug('createConnection', name, options); + options.encoding = null; + var s = self.createConnection(options); + if (!self.sockets[name]) { + self.sockets[name] = []; + } + this.sockets[name].push(s); + debug('sockets', name, this.sockets[name].length); + + function onFree() { + self.emit('free', s, options); + } + s.on('free', onFree); + + function onClose(err) { + debug('CLIENT socket onClose'); + // fix: socket.destroyed always be undefined on 0.10.x + if (typeof s.destroyed !== 'boolean') { + s.destroyed = true; + } + + // This is the only place where sockets get removed from the Agent. + // If you want to remove a socket from the pool, just close it. + // All socket errors end in a close event anyway. + self.removeSocket(s, options); + self.emit('close'); + } + s.on('close', onClose); + + function onTimeout() { + debug('CLIENT socket onTimeout'); + s.destroy(); + // Remove it from freeSockets immediately to prevent new requests from being sent through this socket. + self.removeSocket(s, options); + self.emit('timeout'); + } + s.on('timeout', onTimeout); + // set the default timer + s.setTimeout(self.timeout); + + function onRemove() { + // We need this function for cases like HTTP 'upgrade' + // (defined by WebSockets) where we need to remove a socket from the + // pool because it'll be locked up indefinitely + debug('CLIENT socket onRemove'); + self.removeSocket(s, options); + s.removeListener('close', onClose); + s.removeListener('free', onFree); + s.removeListener('agentRemove', onRemove); + // remove timer + s.setTimeout(0, onTimeout); + } + s.on('agentRemove', onRemove); + return s; +}; + +Agent.prototype.removeSocket = function(s, options) { + var freeLen, sockLen; + var name = this.getName(options); + debug('removeSocket', name, 'destroyed:', s.destroyed); + var sets = [this.sockets]; + + // If the socket was destroyed, remove it from the free buffers too. + if (s.destroyed) + sets.push(this.freeSockets); + + for (var sk = 0; sk < sets.length; sk++) { + var sockets = sets[sk]; + if (sockets[name]) { + var index = sockets[name].indexOf(s); + if (index !== -1) { + sockets[name].splice(index, 1); + // Don't leak + if (sockets[name].length === 0) + delete sockets[name]; + } + } + } + + freeLen = this.freeSockets[name] ? this.freeSockets[name].length : 0; + sockLen = freeLen + this.sockets[name] ? this.sockets[name].length : 0; + + if (this.requests[name] && this.requests[name].length && sockLen < this.maxSockets) { + debug('removeSocket, have a request, make a socket'); + var req = this.requests[name][0]; + // If we have pending requests and a socket gets closed make a new one + this.createSocket(req, options).emit('free'); + } +}; + +Agent.prototype.destroy = function() { + var sets = [this.freeSockets, this.sockets]; + for (var s = 0; s < sets.length; s++) { + var set = sets[s]; + var keys = Object.keys(set); + for (var v = 0; v < keys.length; v++) { + var setName = set[keys[v]]; + for (var n = 0; n < setName.length; n++) { + setName[n].destroy(); + } + } + } +}; + +exports.globalAgent = new Agent(); diff --git a/node_modules/agentkeepalive/lib/agent.js b/node_modules/agentkeepalive/lib/agent.js new file mode 100644 index 00000000..ad4917f0 --- /dev/null +++ b/node_modules/agentkeepalive/lib/agent.js @@ -0,0 +1,97 @@ +/** + * refer: + * * @atimb "Real keep-alive HTTP agent": https://gist.github.com/2963672 + * * https://github.com/joyent/node/blob/master/lib/http.js + * * https://github.com/joyent/node/blob/master/lib/https.js + * * https://github.com/joyent/node/blob/master/lib/_http_agent.js + * + * Copyright(c) 2012 - 2014 fengmk2 <fengmk2@gmail.com> + * Copyright(c) node-modules + * MIT Licensed + */ + +'use strict'; + +/** + * Module dependencies. + */ + +var https = require('https'); +var utils = require('./utils'); +var OriginalAgent = require('./_http_agent').Agent; +var OriginalHttpsAgent = https.Agent; + +module.exports = Agent; + +function Agent(options) { + if (!(this instanceof Agent)) { + return new Agent(options); + } + + options = options || {}; + options.keepAlive = options.keepAlive !== false; + // default is keep-alive and 15s free socket timeout + if (options.keepAliveTimeout === undefined) { + options.keepAliveTimeout = 15000; + } + // default timeout is double keepalive timeout + if (options.timeout === undefined) { + options.timeout = options.keepAliveTimeout * 2; + } + + OriginalAgent.call(this, options); + + var self = this; + self.createSocketCount = 0; + self.closeSocketCount = 0; + // socket error event count + self.errorSocketCount = 0; + self.requestCount = 0; + self.timeoutSocketCount = 0; + self.on('free', function () { + self.requestCount++; + }); + self.on('timeout', function () { + self.timeoutSocketCount++; + }); + self.on('close', function () { + self.closeSocketCount++; + }); + self.on('error', function () { + self.errorSocketCount++; + }); +} + +utils.inherits(Agent, OriginalAgent); + +Agent.prototype.createSocket = function (req, options) { + var socket = OriginalAgent.prototype.createSocket.call(this, req, options); + if (this.keepAlive) { + // Disable Nagle's algorithm: http://blog.caustik.com/2012/04/08/scaling-node-js-to-100k-concurrent-connections/ + // http://fengmk2.com/benchmark/nagle-algorithm-delayed-ack-mock.html + socket.setNoDelay(true); + } + this.createSocketCount++; + return socket; +}; + +Agent.prototype.getCurrentStatus = function () { + return { + createSocketCount: this.createSocketCount, + closeSocketCount: this.closeSocketCount, + errorSocketCount: this.errorSocketCount, + timeoutSocketCount: this.timeoutSocketCount, + requestCount: this.requestCount, + freeSockets: inspect(this.freeSockets), + sockets: inspect(this.sockets), + requests: inspect(this.requests) + }; +}; + +function inspect(obj) { + var res = {}; + for (var key in obj) { + res[key] = obj[key].length; + } + return res; +} diff --git a/node_modules/agentkeepalive/lib/https_agent.js b/node_modules/agentkeepalive/lib/https_agent.js new file mode 100644 index 00000000..36b32d66 --- /dev/null +++ b/node_modules/agentkeepalive/lib/https_agent.js @@ -0,0 +1,95 @@ +/** + * Https Agent base on custom http agent + * + * Copyright(c) node-modules and other contributors. + * MIT Licensed + * + * Authors: + * fengmk2 <m@fengmk2.com> (http://fengmk2.com) + */ + +'use strict'; + +/** + * Module dependencies. + */ + +var https = require('https'); +var utils = require('./utils'); +var HttpAgent = require('./agent'); +var OriginalHttpsAgent = https.Agent; + +var HttpsAgent; + +if (utils.isNode10) { + // node v0.10 + HttpsAgent = function HttpsAgent(options) { + HttpAgent.call(this, options); + this.defaultPort = 443; + this.protocol = 'https:'; + }; + + utils.inherits(HttpsAgent, HttpAgent); + + HttpsAgent.prototype.createConnection = https.globalAgent.createConnection; + HttpsAgent.prototype.getName = function(options) { + var name = HttpAgent.prototype.getName.call(this, options); + + name += ':'; + if (options.ca) + name += options.ca; + + name += ':'; + if (options.cert) + name += options.cert; + + 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; + }; +} else { + HttpsAgent = function HttpsAgent(options) { + HttpAgent.call(this, options); + this.defaultPort = 443; + this.protocol = 'https:'; + this.maxCachedSessions = this.options.maxCachedSessions; + if (this.maxCachedSessions === undefined) + this.maxCachedSessions = 100; + + this._sessionCache = { + map: {}, + list: [] + }; + }; + + utils.inherits(HttpsAgent, HttpAgent); + + [ + 'createConnection', + 'getName', + '_getSession', + '_cacheSession', + // https://github.com/nodejs/node/pull/4982 + '_evictSession', + ].forEach(function(method) { + if (typeof OriginalHttpsAgent.prototype[method] === 'function') { + HttpsAgent.prototype[method] = OriginalHttpsAgent.prototype[method]; + } + }); +} + +module.exports = HttpsAgent; diff --git a/node_modules/agentkeepalive/lib/utils.js b/node_modules/agentkeepalive/lib/utils.js new file mode 100644 index 00000000..7f79f9c1 --- /dev/null +++ b/node_modules/agentkeepalive/lib/utils.js @@ -0,0 +1,31 @@ +/** + * Copyright(c) node-modules and other contributors. + * MIT Licensed + * + * Authors: + * fengmk2 <m@fengmk2.com> (http://fengmk2.com) + */ + +'use strict'; + +/** + * Module dependencies. + */ + +var util = require('util'); +var debug; +var node10 = process.version.indexOf('v0.10.') === 0; + +if (node10) { + debug = function () { + if (process.env.NODE_DEBUG && /agentkeepalive/.test(process.env.NODE_DEBUG)) { + console.log.apply(console.log, arguments); + } + }; +} else { + debug = util.debuglog('agentkeepalive'); +} + +exports.debug = debug; +exports.isNode10 = node10; +exports.inherits = util.inherits; diff --git a/node_modules/agentkeepalive/package.json b/node_modules/agentkeepalive/package.json new file mode 100644 index 00000000..810590ee --- /dev/null +++ b/node_modules/agentkeepalive/package.json @@ -0,0 +1,47 @@ +{ + "name": "agentkeepalive", + "version": "2.2.0", + "description": "Missing keepalive http.Agent", + "main": "index.js", + "browser": "browser.js", + "files": [ + "index.js", + "browser.js", + "lib" + ], + "scripts": { + "test": "mocha -R spec -t 5000 -r should-http test/*.test.js", + "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- -t 5000 -r should-http test/*.test.js", + "ci": "npm run lint && npm run test-cov", + "lint": "jshint .", + "codecov": "npm i codecov && codecov" + }, + "repository": { + "type": "git", + "url": "git://github.com/node-modules/agentkeepalive.git" + }, + "bugs": { + "url": "https://github.com/node-modules/agentkeepalive/issues" + }, + "keywords": [ + "http", + "https", + "agent", + "keepalive", + "agentkeepalive" + ], + "dependencies": {}, + "devDependencies": { + "istanbul": "*", + "mocha": "*", + "pedding": "1", + "should": "4", + "should-http": "~0.0.2", + "jshint": "^2.9.1" + }, + "engines": { + "node": ">= 0.10.0" + }, + "author": "fengmk2 <fengmk2@gmail.com> (http://fengmk2.com)", + "license": "MIT" +} |
