aboutsummaryrefslogtreecommitdiff
path: root/node_modules/agentkeepalive
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/agentkeepalive')
-rw-r--r--node_modules/agentkeepalive/History.md104
-rw-r--r--node_modules/agentkeepalive/README.md234
-rw-r--r--node_modules/agentkeepalive/browser.js5
-rw-r--r--node_modules/agentkeepalive/index.js2
-rw-r--r--node_modules/agentkeepalive/lib/_http_agent.js334
-rw-r--r--node_modules/agentkeepalive/lib/agent.js97
-rw-r--r--node_modules/agentkeepalive/lib/https_agent.js95
-rw-r--r--node_modules/agentkeepalive/lib/utils.js31
-rw-r--r--node_modules/agentkeepalive/package.json47
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"
+}