agent-base
Advanced tools
Comparing version 0.0.1 to 1.0.0
57
agent.js
@@ -6,3 +6,2 @@ | ||
var net = require('net'); | ||
var inherits = require('util').inherits; | ||
@@ -18,17 +17,11 @@ var EventEmitter = require('events').EventEmitter; | ||
/** | ||
* Barebones HTTP "Agent" implementation. Emulates the node-core `http.Agent` | ||
* class, but implemented in a way that can be easily extended for additional | ||
* functionality. | ||
* | ||
* This base implementation does no socket pooling, and opens | ||
* a new connection for every HTTP request. | ||
* | ||
* It behaves more-or-less like `agent: false`. | ||
* | ||
* @api public | ||
*/ | ||
function Agent () { | ||
if (!(this instanceof Agent)) return new Agent(); | ||
function Agent (callback) { | ||
if (!(this instanceof Agent)) return new Agent(callback); | ||
if ('function' != typeof callback) throw new Error('Must pass a "callback function"'); | ||
EventEmitter.call(this); | ||
this.callback = callback; | ||
} | ||
@@ -38,8 +31,2 @@ inherits(Agent, EventEmitter); | ||
/** | ||
* Default port to connect to. | ||
*/ | ||
Agent.prototype.defaultPort = 80; | ||
/** | ||
* Called by node-core's "_http_client.js" module when creating | ||
@@ -56,21 +43,23 @@ * a new HTTP request with this Agent instance. | ||
opts = host; | ||
if (opts.host && opts.path) { | ||
// if both a `host` and `path` are specified then it's most likely the | ||
// result of a `url.parse()` call... we need to remove the `path` portion so | ||
// that `net.connect()` doesn't attempt to open that as a unix socket file. | ||
delete opts.path; | ||
} | ||
} else { | ||
// <= v0.10.x API | ||
opts = { | ||
host: host, | ||
port: port, | ||
localAddress: localAddress | ||
}; | ||
opts = { host: host, port: port }; | ||
if (null != localAddress) { | ||
opts.localAddress = localAddress; | ||
} | ||
} | ||
// hint to use "Connection: close" | ||
// XXX: non-documented `http` module API :( | ||
req._last = true; | ||
req.shouldKeepAlive = false; | ||
// create the `net.Socket` instance | ||
var info = { | ||
host: opts.hostname || opts.host, | ||
port: +opts.port || this.defaultPort, | ||
localAddress: opts.localAddress | ||
}; | ||
this.createConnection(info, function (err, socket) { | ||
this.callback(req, opts, function (err, socket) { | ||
if (err) { | ||
@@ -83,13 +72,1 @@ req.emit('error', err); | ||
}; | ||
/** | ||
* Creates and returns a `net.Socket` instance to use for an HTTP request. | ||
* | ||
* @api protected | ||
*/ | ||
Agent.prototype.createConnection = function (opts, fn) { | ||
var socket = net.connect(opts); | ||
fn(null, socket); | ||
return socket; | ||
}; |
@@ -0,1 +1,6 @@ | ||
1.0.0 / 2013-09-09 | ||
================== | ||
- New API: now you pass a callback function directly | ||
0.0.1 / 2013-07-09 | ||
@@ -2,0 +7,0 @@ ================== |
{ | ||
"name": "agent-base", | ||
"version": "0.0.1", | ||
"description": "Barebone `http.Agent` implementation", | ||
"version": "1.0.0", | ||
"description": "Turn a function into an `http.Agent` instance", | ||
"main": "agent.js", | ||
@@ -6,0 +6,0 @@ "scripts": { |
@@ -1,26 +0,18 @@ | ||
node-agent-base | ||
=============== | ||
### Barebone `http.Agent` implementation | ||
agent-base | ||
========== | ||
### Turn a function into an `http.Agent` instance | ||
[![Build Status](https://travis-ci.org/TooTallNate/node-agent-base.png?branch=master)](https://travis-ci.org/TooTallNate/node-agent-base) | ||
This module provides a very basic, barebones implementation of a Node.js | ||
`http.Agent`. This can be used with the built-in `http` module. | ||
This module provides an `http.Agent` generator. That is, you pass it an async | ||
callback function, and it returns a new `http.Agent` instance that will invoke the | ||
given callback function when sending outbound HTTP requests. | ||
It provides _no_ Keep-Alive support and _no_ socket pooling. It's _very_ minimal. | ||
#### Why? | ||
It's minimal in order to be easily extended, and to feel like I have a sense of | ||
"control" over the underlying sockets being used by the `http` module. | ||
This also allows for cooler things to be done in subclasses, like preprocessing | ||
the socket somehow, or perhaps connecting the socket to a different server | ||
entirely (think proxy servers). | ||
#### Some subclasses: | ||
Here's some more interesting subclasses of `agent-base`. Send a pull request to | ||
add yours! | ||
Here's some more interesting uses of `agent-base`. Send a pull request to | ||
list yours! | ||
* [`http-proxy-agent`][http-proxy-agent]: An HTTP(s) proxy `http.Agent` implementation for HTTP endpoints | ||
* [`https-proxy-agent`][https-proxy-agent]: An HTTP(s) proxy `http.Agent` implementation for HTTPS endpoints | ||
* [`socks-proxy-agent`][socks-proxy-agent]: A SOCKS (v4a) proxy `http.Agent` implementation for HTTP and HTTPS | ||
@@ -41,6 +33,10 @@ | ||
Here's a minimal example that creates a new `net.Socket` connection to the server | ||
for every HTTP request (i.e. the equivalent of `agent: false` option): | ||
``` js | ||
var url = require('url'); | ||
var net = require('net'); | ||
var http = require('http'); | ||
var Agent = require('agent-base'); | ||
var agent = require('agent-base'); | ||
@@ -51,3 +47,7 @@ var endpoint = 'http://nodejs.org/api/'; | ||
// This is the important part! | ||
opts.agent = new Agent(); | ||
opts.agent = agent(function (req, opts, fn) { | ||
if (!opts.port) opts.port = 80; | ||
var socket = net.connect(opts); | ||
fn(null, socket); | ||
}); | ||
@@ -90,1 +90,2 @@ // Everything else works just like normal... | ||
[https-proxy-agent]: https://github.com/TooTallNate/node-https-proxy-agent | ||
[socks-proxy-agent]: https://github.com/TooTallNate/node-socks-proxy-agent |
133
test/test.js
@@ -6,27 +6,134 @@ | ||
var fs = require('fs'); | ||
var url = require('url'); | ||
var net = require('net'); | ||
var tls = require('tls'); | ||
var http = require('http'); | ||
var https = require('https'); | ||
var assert = require('assert'); | ||
var Agent = require('../'); | ||
describe('Agent', function () { | ||
describe('"http" module', function () { | ||
var server; | ||
var port; | ||
it('should work in simple http requests', function (done) { | ||
// set up a local HTTP server | ||
var server = http.createServer(function (req, res) { | ||
res.setHeader('X-It-Works', 'yesss'); | ||
// setup test HTTP server | ||
before(function (done) { | ||
server = http.createServer(); | ||
server.listen(0, function () { | ||
port = server.address().port; | ||
done(); | ||
}); | ||
}); | ||
// shut down test HTTP server | ||
after(function (done) { | ||
server.once('close', function () { | ||
done(); | ||
}); | ||
server.close(); | ||
}); | ||
// test subject `http.Agent` instance | ||
var agent = new Agent(function (req, opts, fn) { | ||
if (!opts.port) opts.port = 80; | ||
var socket = net.connect(opts); | ||
fn(null, socket); | ||
}); | ||
it('should work for basic HTTP requests', function (done) { | ||
// add HTTP server "request" listener | ||
var gotReq = false; | ||
server.once('request', function (req, res) { | ||
gotReq = true; | ||
res.setHeader('X-Foo', 'bar'); | ||
res.setHeader('X-Url', req.url); | ||
res.end(); | ||
}); | ||
var info = url.parse('http://127.0.0.1:' + port + '/foo'); | ||
info.agent = agent; | ||
http.get(info, function (res) { | ||
assert.equal('bar', res.headers['x-foo']); | ||
assert.equal('/foo', res.headers['x-url']); | ||
assert(gotReq); | ||
done(); | ||
}); | ||
}); | ||
it('should set the `Connection: close` response header', function (done) { | ||
// add HTTP server "request" listener | ||
var gotReq = false; | ||
server.once('request', function (req, res) { | ||
gotReq = true; | ||
res.setHeader('X-Url', req.url); | ||
assert.equal('close', req.headers.connection); | ||
res.end(); | ||
}); | ||
var info = url.parse('http://127.0.0.1:' + port + '/bar'); | ||
info.agent = agent; | ||
http.get(info, function (res) { | ||
assert.equal('/bar', res.headers['x-url']); | ||
assert.equal('close', res.headers.connection); | ||
assert(gotReq); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
describe('"https" module', function () { | ||
var server; | ||
var port; | ||
// setup test HTTPS server | ||
before(function (done) { | ||
var options = { | ||
key: fs.readFileSync(__dirname + '/server.key'), | ||
cert: fs.readFileSync(__dirname + '/server.crt') | ||
}; | ||
server = https.createServer(options); | ||
server.listen(0, function () { | ||
var port = server.address().port; | ||
var info = url.parse('http://127.0.0.1:' + port + '/foo'); | ||
info.agent = new Agent(); | ||
http.get(info, function (res) { | ||
assert.equal('yesss', res.headers['x-it-works']); | ||
server.on('close', done); | ||
server.close(); | ||
}); | ||
port = server.address().port; | ||
done(); | ||
}); | ||
}); | ||
// shut down test HTTP server | ||
after(function (done) { | ||
server.once('close', function () { | ||
done(); | ||
}); | ||
server.close(); | ||
}); | ||
// test subject `http.Agent` instance | ||
var agent = new Agent(function (req, opts, fn) { | ||
if (!opts.port) opts.port = 443; | ||
opts.rejectUnauthorized = false; | ||
var socket = tls.connect(opts); | ||
fn(null, socket); | ||
}); | ||
it('should work for basic HTTPS requests', function (done) { | ||
// add HTTPS server "request" listener | ||
var gotReq = false; | ||
server.once('request', function (req, res) { | ||
gotReq = true; | ||
res.setHeader('X-Foo', 'bar'); | ||
res.setHeader('X-Url', req.url); | ||
res.end(); | ||
}); | ||
var info = url.parse('https://127.0.0.1:' + port + '/foo'); | ||
info.agent = agent; | ||
info.rejectUnauthorized = false; | ||
https.get(info, function (res) { | ||
assert.equal('bar', res.headers['x-foo']); | ||
assert.equal('/foo', res.headers['x-url']); | ||
assert(gotReq); | ||
done(); | ||
}); | ||
}); | ||
}); |
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
10485
9
178
1
89
1
4