This repository has been archived by the owner. It is now read-only.
Permalink
Browse files

http: Add agent.get/request methods

  • Loading branch information...
isaacs committed May 21, 2013
1 parent 9fc9b87 commit 40e92650bb97b736b8e29c5de35c1c29ebd625ef
Showing with 136 additions and 29 deletions.
  1. +37 −4 lib/_http_agent.js
  2. +4 −24 lib/http.js
  3. +2 −1 lib/https.js
  4. +2 −0 lib/net.js
  5. +91 −0 test/simple/test-http-keepalive-request.js
View
@@ -20,8 +20,10 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var net = require('net');
+var url = require('url');
var util = require('util');
var EventEmitter = require('events').EventEmitter;
+var ClientRequest = require('_http_client').ClientRequest;
// New Agent code.
@@ -42,7 +44,9 @@ function Agent(options) {
EventEmitter.call(this);
var self = this;
- self.options = options || {};
+ 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 = {};
self.sockets = {};
self.freeSockets = {};
@@ -91,15 +95,16 @@ function Agent(options) {
}
}
});
- self.createConnection = net.createConnection;
}
util.inherits(Agent, EventEmitter);
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) {
@@ -207,5 +212,33 @@ Agent.prototype.destroy = function() {
});
};
-var globalAgent = new Agent();
-exports.globalAgent = globalAgent;
+Agent.prototype.request = function(options, cb) {
+ if (typeof options === 'string') {
+ options = url.parse(options);
+ }
+
+ if (options && options.path && / /.test(options.path)) {
+ // The actual regex is more like /[^A-Za-z0-9\-._~!$&'()*+,;=/:@]/
+ // with an additional rule for ignoring percentage-escaped characters
+ // but that's a) hard to capture in a regular expression that performs
+ // well, and b) possibly too restrictive for real-world usage. That's
+ // why it only scans for spaces because those are guaranteed to create
+ // an invalid request.
+ throw new TypeError('Request path contains unescaped characters.');
+ } else if (options.protocol && options.protocol !== this.protocol) {
+ throw new Error('Protocol:' + options.protocol + ' not supported.');
+ }
+
+ options = util._extend({ agent: this, keepAlive: false }, options);
+
+ if (options.agent === false)
+ options.agent = new Agent(options);
+
+ return new ClientRequest(options, cb);
+};
+
+Agent.prototype.get = function(options, cb) {
+ var req = this.request(options, cb);
+ req.end();
+ return req;
+};
View
@@ -20,7 +20,6 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var util = require('util');
-var url = require('url');
var EventEmitter = require('events').EventEmitter;
@@ -42,40 +41,21 @@ exports.STATUS_CODES = server.STATUS_CODES;
var agent = require('_http_agent');
-
var Agent = exports.Agent = agent.Agent;
-var globalAgent = exports.globalAgent = agent.globalAgent;
+var globalAgent = new Agent();
+exports.globalAgent = globalAgent;
var client = require('_http_client');
var ClientRequest = exports.ClientRequest = client.ClientRequest;
exports.request = function(options, cb) {
- if (typeof options === 'string') {
- options = url.parse(options);
- } else if (options && options.path && / /.test(options.path)) {
- // The actual regex is more like /[^A-Za-z0-9\-._~!$&'()*+,;=/:@]/
- // with an additional rule for ignoring percentage-escaped characters
- // but that's a) hard to capture in a regular expression that performs
- // well, and b) possibly too restrictive for real-world usage. That's
- // why it only scans for spaces because those are guaranteed to create
- // an invalid request.
- throw new TypeError('Request path contains unescaped characters.');
- }
-
- if (options.protocol && options.protocol !== 'http:') {
- throw new Error('Protocol:' + options.protocol + ' not supported.');
- }
-
- return new ClientRequest(options, cb);
+ return globalAgent.request(options, cb);
};
exports.get = function(options, cb) {
- var req = exports.request(options, cb);
- req.end();
- return req;
+ return globalAgent.get(options, cb);
};
-
var httpSocketSetup = common.httpSocketSetup;
exports._connectionListener = server._connectionListener;
View
@@ -83,10 +83,11 @@ function createConnection(port, host, options) {
function Agent(options) {
http.Agent.call(this, options);
- this.createConnection = createConnection;
}
inherits(Agent, http.Agent);
Agent.prototype.defaultPort = 443;
+Agent.prototype.protocol = 'https:';
+Agent.prototype.createConnection = createConnection;
var globalAgent = new Agent();
View
@@ -77,6 +77,7 @@ exports.createServer = function() {
//
exports.connect = exports.createConnection = function() {
var args = normalizeConnectArgs(arguments);
+ debug('createConnection', args);
var s = new Socket(args[0]);
return Socket.prototype.connect.apply(s, args);
};
@@ -832,6 +833,7 @@ Socket.prototype.connect = function(options, cb) {
var self = this;
var pipe = !!options.path;
+ debug('pipe', pipe, options.path);
if (!this._handle) {
this._handle = pipe ? createPipe() : createTCP();
@@ -0,0 +1,91 @@
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+var common = require('../common');
+var assert = require('assert');
+
+var http = require('http');
+
+
+var serverSocket = null;
+var server = http.createServer(function(req, res) {
+ // They should all come in on the same server socket.
+ if (serverSocket) {
+ assert.equal(req.socket, serverSocket);
+ } else {
+ serverSocket = req.socket;
+ }
+
+ res.end(req.url);
+});
+server.listen(common.PORT);
+
+var agent = http.Agent({ keepAlive: true });
+
+
+var clientSocket = null;
+var expectRequests = 10;
+var actualRequests = 0;
+
+
+makeRequest(expectRequests);
+function makeRequest(n) {
+ if (n === 0) {
+ server.close();
+ agent.destroy();
+ return;
+ }
+
+ var req = agent.request({
+ port: common.PORT,
+ path: '/' + n
+ });
+
+ req.end();
+
+ req.on('socket', function(sock) {
+ if (clientSocket) {
+ assert.equal(sock, clientSocket);
+ } else {
+ clientSocket = sock;
+ }
+ });
+
+ req.on('response', function(res) {
+ var data = '';
+ res.setEncoding('utf8');
+ res.on('data', function(c) {
+ data += c;
+ });
+ res.on('end', function() {
+ assert.equal(data, '/' + n);
+ setTimeout(function() {
+ actualRequests++;
+ makeRequest(n - 1);
+ }, 1);
+ });
+ });
+}
+
+process.on('exit', function() {
+ assert.equal(actualRequests, expectRequests)
+ console.log('ok');
+});

0 comments on commit 40e9265

Please sign in to comment.