Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
81145 views
1
module.exports = ForeverAgent
2
ForeverAgent.SSL = ForeverAgentSSL
3
4
var util = require('util')
5
, Agent = require('http').Agent
6
, net = require('net')
7
, tls = require('tls')
8
, AgentSSL = require('https').Agent
9
10
function getConnectionName(host, port) {
11
var name = ''
12
if (typeof host === 'string') {
13
name = host + ':' + port
14
} else {
15
// For node.js v012.0 and iojs-v1.5.1, host is an object. And any existing localAddress is part of the connection name.
16
name = host.host + ':' + host.port + ':' + (host.localAddress ? (host.localAddress + ':') : ':')
17
}
18
return name
19
}
20
21
function ForeverAgent(options) {
22
var self = this
23
self.options = options || {}
24
self.requests = {}
25
self.sockets = {}
26
self.freeSockets = {}
27
self.maxSockets = self.options.maxSockets || Agent.defaultMaxSockets
28
self.minSockets = self.options.minSockets || ForeverAgent.defaultMinSockets
29
self.on('free', function(socket, host, port) {
30
var name = getConnectionName(host, port)
31
32
if (self.requests[name] && self.requests[name].length) {
33
self.requests[name].shift().onSocket(socket)
34
} else if (self.sockets[name].length < self.minSockets) {
35
if (!self.freeSockets[name]) self.freeSockets[name] = []
36
self.freeSockets[name].push(socket)
37
38
// if an error happens while we don't use the socket anyway, meh, throw the socket away
39
var onIdleError = function() {
40
socket.destroy()
41
}
42
socket._onIdleError = onIdleError
43
socket.on('error', onIdleError)
44
} else {
45
// If there are no pending requests just destroy the
46
// socket and it will get removed from the pool. This
47
// gets us out of timeout issues and allows us to
48
// default to Connection:keep-alive.
49
socket.destroy()
50
}
51
})
52
53
}
54
util.inherits(ForeverAgent, Agent)
55
56
ForeverAgent.defaultMinSockets = 5
57
58
59
ForeverAgent.prototype.createConnection = net.createConnection
60
ForeverAgent.prototype.addRequestNoreuse = Agent.prototype.addRequest
61
ForeverAgent.prototype.addRequest = function(req, host, port) {
62
var name = getConnectionName(host, port)
63
64
if (typeof host !== 'string') {
65
var options = host
66
port = options.port
67
host = options.host
68
}
69
70
if (this.freeSockets[name] && this.freeSockets[name].length > 0 && !req.useChunkedEncodingByDefault) {
71
var idleSocket = this.freeSockets[name].pop()
72
idleSocket.removeListener('error', idleSocket._onIdleError)
73
delete idleSocket._onIdleError
74
req._reusedSocket = true
75
req.onSocket(idleSocket)
76
} else {
77
this.addRequestNoreuse(req, host, port)
78
}
79
}
80
81
ForeverAgent.prototype.removeSocket = function(s, name, host, port) {
82
if (this.sockets[name]) {
83
var index = this.sockets[name].indexOf(s)
84
if (index !== -1) {
85
this.sockets[name].splice(index, 1)
86
}
87
} else if (this.sockets[name] && this.sockets[name].length === 0) {
88
// don't leak
89
delete this.sockets[name]
90
delete this.requests[name]
91
}
92
93
if (this.freeSockets[name]) {
94
var index = this.freeSockets[name].indexOf(s)
95
if (index !== -1) {
96
this.freeSockets[name].splice(index, 1)
97
if (this.freeSockets[name].length === 0) {
98
delete this.freeSockets[name]
99
}
100
}
101
}
102
103
if (this.requests[name] && this.requests[name].length) {
104
// If we have pending requests and a socket gets closed a new one
105
// needs to be created to take over in the pool for the one that closed.
106
this.createSocket(name, host, port).emit('free')
107
}
108
}
109
110
function ForeverAgentSSL (options) {
111
ForeverAgent.call(this, options)
112
}
113
util.inherits(ForeverAgentSSL, ForeverAgent)
114
115
ForeverAgentSSL.prototype.createConnection = createConnectionSSL
116
ForeverAgentSSL.prototype.addRequestNoreuse = AgentSSL.prototype.addRequest
117
118
function createConnectionSSL (port, host, options) {
119
if (typeof port === 'object') {
120
options = port;
121
} else if (typeof host === 'object') {
122
options = host;
123
} else if (typeof options === 'object') {
124
options = options;
125
} else {
126
options = {};
127
}
128
129
if (typeof port === 'number') {
130
options.port = port;
131
}
132
133
if (typeof host === 'string') {
134
options.host = host;
135
}
136
137
return tls.connect(options);
138
}
139
140