Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests and docs for using the agent, agentClass and agentOptions. Forever option defaults to using http(s).Agent in node 0.12+ #1671

Merged
merged 2 commits into from Jul 20, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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