Blame view

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