Initial commit
[yaffs-website] / node_modules / forever-agent / index.js
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 }