Skip to content

Commit

Permalink
Merge pull request #1671 from simov/agent-docs
Browse files Browse the repository at this point in the history
Add tests and docs for using the agent, agentClass, agentOptions and forever options.
Forever option defaults to using http(s).Agent in node 0.12+
  • Loading branch information
simov committed Jul 20, 2015
2 parents 50ee190 + 391b80b commit a2aea33
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 21 deletions.
13 changes: 8 additions & 5 deletions README.md
Expand Up @@ -772,7 +772,11 @@ The first argument can be either a `url` or an `options` object. The only requir

---

- `pool` - An object describing which agents to use for the request. If this option is omitted the request will use the global agent (as long as [your options allow for it](request.js#L747)). Otherwise, request will search the pool for your custom agent. If no custom agent is found, a new agent will be created and added to the pool.
- `agent` - `http(s).Agent` instance to use
- `agentClass` - alternatively specify your agent's class name
- `agentOptions` - and pass its options. **Note:** for HTTPS see [tls API doc for TLS/SSL options](http://nodejs.org/api/tls.html#tls_tls_connect_options_callback) and the [documentation above](#using-optionsagentoptions).
- `forever` - set to `true` to use the [forever-agent](https://github.com/request/forever-agent) **Note:** Defaults to `http(s).Agent({keepAlive:true})` in node 0.12+
- `pool` - An object describing which agents to use for the request. If this option is omitted the request will use the global agent (as long as your options allow for it). Otherwise, request will search the pool for your custom agent. If no custom agent is found, a new agent will be created and added to the pool. **Note:** `pool` is used only when the `agent` option is not specified.
- A `maxSockets` property can also be provided on the `pool` object to set the max number of sockets for all agents created (ex: `pool: {maxSockets: Infinity}`).
- Note that if you are sending multiple requests in a loop and creating
multiple new `pool` objects, `maxSockets` will not work as intended. To
Expand All @@ -783,10 +787,12 @@ The first argument can be either a `url` or an `options` object. The only requir
request to respond before aborting the request. Note that if the underlying
TCP connection cannot be established, the OS-wide TCP connection timeout will
overrule the `timeout` option ([the default in Linux is around 20 seconds](http://www.sekuda.com/overriding_the_default_linux_kernel_20_second_tcp_socket_connect_timeout)).

---

- `localAddress` - Local interface to bind for network connections.
- `proxy` - An HTTP proxy to be used. Supports proxy Auth with Basic Auth, identical to support for the `url` parameter (by embedding the auth info in the `uri`)
- `strictSSL` - If `true`, requires SSL certificates be valid. **Note:** to use your own certificate authority, you need to specify an agent that was created with that CA as an option.
- `agentOptions` - Object containing user agent options. See documentation above. **Note:** [see tls API doc for TLS/SSL options](http://nodejs.org/api/tls.html#tls_tls_connect_options_callback).
- `tunnel` - controls the behavior of
[HTTP `CONNECT` tunneling](https://en.wikipedia.org/wiki/HTTP_tunnel#HTTP_CONNECT_tunneling)
as follows:
Expand All @@ -803,9 +809,6 @@ The first argument can be either a `url` or an `options` object. The only requir
---

- `time` - If `true`, the request-response cycle (including all redirects) is timed at millisecond resolution, and the result provided on the response's `elapsedTime` property.

---

- `har` - A [HAR 1.2 Request Object](http://www.softwareishard.com/blog/har-12-spec/#request), will be processed from HAR format into options overwriting matching values *(see the [HAR 1.2 section](#support-for-har-1.2) for details)*

The callback argument gets 3 arguments:
Expand Down
10 changes: 10 additions & 0 deletions lib/helpers.js
Expand Up @@ -54,11 +54,21 @@ function copy (obj) {
return o
}

function version () {
var numbers = process.version.replace('v', '').split('.')
return {
major: parseInt(numbers[0], 10),
minor: parseInt(numbers[1], 10),
patch: parseInt(numbers[2], 10)
}
}

exports.isFunction = isFunction
exports.paramsHaveRequestBody = paramsHaveRequestBody
exports.safeStringify = safeStringify
exports.md5 = md5
exports.isReadStream = isReadStream
exports.toBase64 = toBase64
exports.copy = copy
exports.version = version
exports.defer = deferMethod()
12 changes: 11 additions & 1 deletion request.js
Expand Up @@ -31,6 +31,7 @@ var safeStringify = helpers.safeStringify
, toBase64 = helpers.toBase64
, defer = helpers.defer
, copy = helpers.copy
, version = helpers.version
, globalCookieJar = cookies.jar()


Expand Down Expand Up @@ -477,7 +478,16 @@ Request.prototype.init = function (options) {
if (options.agentClass) {
self.agentClass = options.agentClass
} else if (options.forever) {
self.agentClass = protocol === 'http:' ? ForeverAgent : ForeverAgent.SSL
var v = version()
// use ForeverAgent in node 0.10- only
if (v.major === 0 && v.minor <= 10) {
self.agentClass = protocol === 'http:' ? ForeverAgent : ForeverAgent.SSL
} else {
self.agent = new self.httpModule.Agent({
keepAlive: true,
maxSockets: (options.pool && options.pool.maxSockets) || Infinity
})
}
} else {
self.agentClass = self.httpModule.Agent
}
Expand Down
99 changes: 84 additions & 15 deletions tests/test-agent.js
@@ -1,34 +1,103 @@
'use strict'

var request = require('../index')
, http = require('http')
, tape = require('tape')
, version = require('../lib/helpers').version
, http = require('http')
, ForeverAgent = require('forever-agent')
, tape = require('tape')

var s = http.createServer(function(req, res) {
var s = http.createServer(function (req, res) {
res.statusCode = 200
res.end('ok')
res.end()
})

tape('setup', function(t) {
tape('setup', function (t) {
s.listen(6767, function() {
t.end()
})
})

tape('should work with forever agent', function(t) {
var r = request.forever({maxSockets: 1})
function httpAgent (t, options, req) {
var r = (req || request)(options, function (_err, res, body) {

r({
url: 'http://localhost:6767',
headers: { 'Connection':'Close' }
}, function(err, resp, body) {
t.equal(err, null)
t.equal(body, 'ok')
t.end()
t.ok(r.agent instanceof http.Agent, 'is http.Agent')
t.equal(r.agent.options.keepAlive, true, 'is keepAlive')
t.equal(Object.keys(r.agent.sockets).length, 1, '1 socket name')

var name = (typeof r.agent.getName === 'function')
? r.agent.getName({port:6767})
: 'localhost:6767' // node 0.10-
t.equal(r.agent.sockets[name].length, 1, '1 open socket')

var socket = r.agent.sockets[name][0]
socket.on('close', function () {
t.equal(Object.keys(r.agent.sockets).length, 0, '0 open sockets')
t.end()
})
socket.end()
})
}

function foreverAgent (t, options, req) {
var r = (req || request)(options, function (_err, res, body) {

t.ok(r.agent instanceof ForeverAgent, 'is ForeverAgent')
t.equal(Object.keys(r.agent.sockets).length, 1, '1 socket name')

var name = 'localhost:6767' // node 0.10-
t.equal(r.agent.sockets[name].length, 1, '1 open socket')

var socket = r.agent.sockets[name][0]
socket.on('close', function () {
t.equal(Object.keys(r.agent.sockets[name]).length, 0, '0 open sockets')
t.end()
})
socket.end()
})
}

// http.Agent

tape('options.agent', function (t) {
httpAgent(t, {
uri: 'http://localhost:6767',
agent: new http.Agent({keepAlive: true})
})
})

tape('cleanup', function(t) {
tape('options.agentClass + options.agentOptions', function (t) {
httpAgent(t, {
uri: 'http://localhost:6767',
agentClass: http.Agent,
agentOptions: {keepAlive: true}
})
})

// forever-agent

tape('options.forever = true', function (t) {
var v = version()
var options = {
uri: 'http://localhost:6767',
forever: true
}

if (v.major === 0 && v.minor <= 10) {foreverAgent(t, options)}
else {httpAgent(t, options)}
})

tape('forever() method', function (t) {
var v = version()
var options = {
uri: 'http://localhost:6767'
}
var r = request.forever({maxSockets: 1})

if (v.major === 0 && v.minor <= 10) {foreverAgent(t, options, r)}
else {httpAgent(t, options, r)}
})

tape('cleanup', function (t) {
s.close(function() {
t.end()
})
Expand Down

0 comments on commit a2aea33

Please sign in to comment.