summaryrefslogtreecommitdiff
path: root/lib/_http_agent.js
diff options
context:
space:
mode:
authorisaacs <i@izs.me>2013-05-22 18:44:24 -0700
committerisaacs <i@izs.me>2013-07-09 22:31:11 -0700
commit49519f121787d51394f00c871f854794e409bdda (patch)
treea0e40fb168563401ec401ce7e08098c24d212abc /lib/_http_agent.js
parent40e92650bb97b736b8e29c5de35c1c29ebd625ef (diff)
downloadnode-new-49519f121787d51394f00c871f854794e409bdda.tar.gz
http: Reuse more http/https Agent code
Diffstat (limited to 'lib/_http_agent.js')
-rw-r--r--lib/_http_agent.js100
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);
};