diff --git a/docs/configuration.asciidoc b/docs/configuration.asciidoc index 3df5caafc..45f186fd4 100644 --- a/docs/configuration.asciidoc +++ b/docs/configuration.asciidoc @@ -90,8 +90,20 @@ _Default:_ `false` _Default:_ `null` |`agent` -|`http.AgentOptions` - http agent https://nodejs.org/api/http.html#http_new_agent_options[options]. + +a|`http.AgentOptions, function` - http agent https://nodejs.org/api/http.html#http_new_agent_options[options], or a function that returns an actual http agent instance. + _Default:_ `null` +[source,js] +---- +const client = new Client({ + node: 'http://localhost:9200', + agent: { agent: 'options' } +}) + +const client = new Client({ + node: 'http://localhost:9200', + agent: () => new CustomAgent() +}) +---- |`nodeFilter` a|`function` - Filters which node not to use for a request. + diff --git a/index.d.ts b/index.d.ts index 0fd8d458d..7b8bcc49d 100644 --- a/index.d.ts +++ b/index.d.ts @@ -29,7 +29,7 @@ import Transport, { nodeFilterFn, nodeSelectorFn } from './lib/Transport'; -import Connection, { AgentOptions } from './lib/Connection'; +import Connection, { AgentOptions, agentFn } from './lib/Connection'; import ConnectionPool, { ResurrectEvent } from './lib/ConnectionPool'; import Serializer from './lib/Serializer'; import * as RequestParams from './api/requestParams'; @@ -82,7 +82,7 @@ interface ClientOptions { suggestCompression?: boolean; compression?: 'gzip'; ssl?: SecureContextOptions; - agent?: AgentOptions; + agent?: AgentOptions | agentFn; nodeFilter?: nodeFilterFn; nodeSelector?: nodeSelectorFn | string; headers?: anyObject; diff --git a/lib/Connection.d.ts b/lib/Connection.d.ts index 99d9a7ffd..a02b6f72a 100644 --- a/lib/Connection.d.ts +++ b/lib/Connection.d.ts @@ -24,12 +24,14 @@ import { inspect, InspectOptions } from 'util'; import * as http from 'http'; import { SecureContextOptions } from 'tls'; +export declare type agentFn = () => any; + interface ConnectionOptions { url: URL; ssl?: SecureContextOptions; id?: string; headers?: any; - agent?: AgentOptions; + agent?: AgentOptions | agentFn; status?: string; roles?: any; } diff --git a/lib/Connection.js b/lib/Connection.js index 4429e8696..e90182453 100644 --- a/lib/Connection.js +++ b/lib/Connection.js @@ -46,18 +46,20 @@ class Connection { throw new ConfigurationError(`Invalid protocol: '${this.url.protocol}'`) } - // Probably there is a bug in Node Core - // see https://github.com/nodejs/node/issues/26357 - const keepAliveFalse = opts.agent && opts.agent.keepAlive === false - const agentOptions = Object.assign({}, { - keepAlive: true, - keepAliveMsecs: 1000, - maxSockets: keepAliveFalse ? Infinity : 256, - maxFreeSockets: 256 - }, opts.agent) - this.agent = this.url.protocol === 'http:' - ? new http.Agent(agentOptions) - : new https.Agent(Object.assign({}, agentOptions, this.ssl)) + if (typeof opts.agent === 'function') { + this.agent = opts.agent() + } else { + const keepAliveFalse = opts.agent && opts.agent.keepAlive === false + const agentOptions = Object.assign({}, { + keepAlive: true, + keepAliveMsecs: 1000, + maxSockets: keepAliveFalse ? Infinity : 256, + maxFreeSockets: 256 + }, opts.agent) + this.agent = this.url.protocol === 'http:' + ? new http.Agent(agentOptions) + : new https.Agent(Object.assign({}, agentOptions, this.ssl)) + } this.makeRequest = this.url.protocol === 'http:' ? http.request diff --git a/test/unit/connection.test.js b/test/unit/connection.test.js index 229e00d04..84068cad5 100644 --- a/test/unit/connection.test.js +++ b/test/unit/connection.test.js @@ -23,6 +23,7 @@ const { test } = require('tap') const { inspect } = require('util') const { createGzip, createDeflate } = require('zlib') const { URL } = require('url') +const { Agent } = require('http') const intoStream = require('into-stream') const { buildServer } = require('../utils') const Connection = require('../../lib/Connection') @@ -149,6 +150,55 @@ test('Basic (https with ssl agent)', t => { }) }) +test('Custom http agent', t => { + t.plan(5) + + function handler (req, res) { + t.match(req.headers, { + 'x-custom-test': 'true', + connection: 'keep-alive' + }) + res.end('ok') + } + + buildServer(handler, ({ port }, server) => { + const agent = new Agent({ + keepAlive: true, + keepAliveMsecs: 1000, + maxSockets: 256, + maxFreeSockets: 256 + }) + agent.custom = true + const connection = new Connection({ + url: new URL(`http://localhost:${port}`), + agent: () => agent + }) + t.true(connection.agent.custom) + connection.request({ + path: '/hello', + method: 'GET', + headers: { + 'X-Custom-Test': true + } + }, (err, res) => { + t.error(err) + + t.match(res.headers, { + connection: 'keep-alive' + }) + + var payload = '' + res.setEncoding('utf8') + res.on('data', chunk => { payload += chunk }) + res.on('error', err => t.fail(err)) + res.on('end', () => { + t.strictEqual(payload, 'ok') + server.stop() + }) + }) + }) +}) + test('Disable keep alive', t => { t.plan(3)