diff options
author | isaacs <i@izs.me> | 2013-05-22 18:44:24 -0700 |
---|---|---|
committer | isaacs <i@izs.me> | 2013-07-09 22:31:11 -0700 |
commit | 49519f121787d51394f00c871f854794e409bdda (patch) | |
tree | a0e40fb168563401ec401ce7e08098c24d212abc /lib/_http_agent.js | |
parent | 40e92650bb97b736b8e29c5de35c1c29ebd625ef (diff) | |
download | node-new-49519f121787d51394f00c871f854794e409bdda.tar.gz |
http: Reuse more http/https Agent code
Diffstat (limited to 'lib/_http_agent.js')
-rw-r--r-- | lib/_http_agent.js | 100 |
1 files changed, 71 insertions, 29 deletions
diff --git a/lib/_http_agent.js b/lib/_http_agent.js index 20fa1b6a2a..07e8f4c557 100644 --- a/lib/_http_agent.js +++ b/lib/_http_agent.js @@ -24,6 +24,7 @@ var url = require('url'); var util = require('util'); var EventEmitter = require('events').EventEmitter; var ClientRequest = require('_http_client').ClientRequest; +var debug = util.debuglog('http'); // New Agent code. @@ -44,7 +45,12 @@ function 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 = {}; @@ -54,11 +60,9 @@ function Agent(options) { self.keepAlive = self.options.keepAlive || false; self.maxSockets = self.options.maxSockets || Agent.defaultMaxSockets; - self.on('free', function(socket, host, port, localAddress) { - var name = host + ':' + port; - if (localAddress) { - name += ':' + localAddress; - } + 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) { @@ -103,18 +107,38 @@ exports.Agent = Agent; Agent.defaultMaxSockets = Infinity; Agent.prototype.createConnection = net.createConnection; -Agent.prototype.defaultPort = 80; -Agent.prototype.protocol = 'http:'; -Agent.prototype.addRequest = function(req, host, port, localAddress) { - var name = host + ':' + port; - if (localAddress) { - name += ':' + localAddress; - } + +// 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) { + var host = options.host; + var port = options.port; + var localAddress = options.localAddress; + + var name = this.getName(options); if (!this.sockets[name]) { this.sockets[name] = []; } if (this.freeSockets[name] && this.freeSockets[name].length) { + debug('have free socket'); // we have a free socket, so use that. var socket = this.freeSockets[name].shift(); @@ -125,9 +149,11 @@ Agent.prototype.addRequest = function(req, host, port, localAddress) { socket.ref(); req.onSocket(socket); } else if (this.sockets[name].length < this.maxSockets) { + debug('call onSocket'); // If we are under maxSockets create a new one. - req.onSocket(this.createSocket(name, host, port, localAddress, req)); + 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] = []; @@ -136,14 +162,12 @@ Agent.prototype.addRequest = function(req, host, port, localAddress) { } }; -Agent.prototype.createSocket = function(name, host, port, localAddress, req) { +Agent.prototype.createSocket = function(req, options) { var self = this; - var options = util._extend({}, self.options); - options.port = port; - options.host = host; - options.localAddress = localAddress; + options = util._extend({}, options); + options = util._extend(options, self.options); - options.servername = host; + options.servername = options.host; if (req) { var hostHeader = req.getHeader('host'); if (hostHeader) { @@ -151,30 +175,36 @@ Agent.prototype.createSocket = function(name, host, port, localAddress, req) { } } + var name = self.getName(options); + + debug('createConnection', name, options); 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, host, port, localAddress); + self.emit('free', s, options); } s.on('free', onFree); function onClose(err) { + debug('CLIENT socket onClose'); // 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, name, host, port, localAddress); + self.removeSocket(s, options); } s.on('close', onClose); 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 - self.removeSocket(s, name, host, port, localAddress); + // (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); @@ -183,7 +213,9 @@ Agent.prototype.createSocket = function(name, host, port, localAddress, req) { return s; }; -Agent.prototype.removeSocket = function(s, name, host, port, localAddress) { +Agent.prototype.removeSocket = function(s, options) { + var name = this.getName(options); + debug('removeSocket', name); if (this.sockets[name]) { var index = this.sockets[name].indexOf(s); if (index !== -1) { @@ -195,9 +227,10 @@ Agent.prototype.removeSocket = function(s, name, host, port, localAddress) { } } if (this.requests[name] && this.requests[name].length) { + debug('removeSocket, have a request, make a socket'); var req = this.requests[name][0]; - // If we have pending requests and a socket gets closed a new one - this.createSocket(name, host, port, localAddress, req).emit('free'); + // If we have pending requests and a socket gets closed make a new one + this.createSocket(req, options).emit('free'); } }; @@ -216,6 +249,10 @@ Agent.prototype.request = function(options, cb) { if (typeof options === 'string') { options = url.parse(options); } + // don't try to do dns lookups of foo.com:8080, just foo.com + if (options.hostname) { + options.host = options.hostname; + } if (options && options.path && / /.test(options.path)) { // The actual regex is more like /[^A-Za-z0-9\-._~!$&'()*+,;=/:@]/ @@ -229,11 +266,16 @@ Agent.prototype.request = function(options, cb) { throw new Error('Protocol:' + options.protocol + ' not supported.'); } - options = util._extend({ agent: this, keepAlive: false }, options); + options = util._extend({ + agent: this, + keepAlive: this.keepAlive + }, options); + // if it's false, then make a new one, just like this one. if (options.agent === false) - options.agent = new Agent(options); + options.agent = new this.constructor(options); + debug('agent.request', options); return new ClientRequest(options, cb); }; |