From 5e74b650931f827208fe1a29c184b16221ba1c41 Mon Sep 17 00:00:00 2001 From: delvedor Date: Tue, 9 Apr 2019 12:50:54 +0200 Subject: [PATCH 1/6] Added custom http agent support --- index.d.ts | 4 +++- lib/Connection.d.ts | 3 ++- lib/Connection.js | 26 ++++++++++++++------------ 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/index.d.ts b/index.d.ts index 0fd8d458d..3411c13b0 100644 --- a/index.d.ts +++ b/index.d.ts @@ -21,6 +21,8 @@ import { EventEmitter } from 'events'; import { SecureContextOptions } from 'tls'; +import * as http from 'http'; +import * as https from 'https'; import Transport, { ApiResponse, RequestEvent, @@ -82,7 +84,7 @@ interface ClientOptions { suggestCompression?: boolean; compression?: 'gzip'; ssl?: SecureContextOptions; - agent?: AgentOptions; + agent?: AgentOptions | http.Agent | https.Agent; nodeFilter?: nodeFilterFn; nodeSelector?: nodeSelectorFn | string; headers?: anyObject; diff --git a/lib/Connection.d.ts b/lib/Connection.d.ts index 99d9a7ffd..ca6d1cf80 100644 --- a/lib/Connection.d.ts +++ b/lib/Connection.d.ts @@ -22,6 +22,7 @@ import { URL } from 'url'; import { inspect, InspectOptions } from 'util'; import * as http from 'http'; +import * as https from 'http'; import { SecureContextOptions } from 'tls'; interface ConnectionOptions { @@ -29,7 +30,7 @@ interface ConnectionOptions { ssl?: SecureContextOptions; id?: string; headers?: any; - agent?: AgentOptions; + agent?: AgentOptions | http.Agent | https.Agent; status?: string; roles?: any; } diff --git a/lib/Connection.js b/lib/Connection.js index 4429e8696..57a9b2897 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 (opts.agent instanceof http.Agent || opts.agent instanceof https.Agent) { + 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 From 8ea3c0a9b7ce56a99ce0c5cc63a170530d694edc Mon Sep 17 00:00:00 2001 From: delvedor Date: Tue, 9 Apr 2019 12:51:01 +0200 Subject: [PATCH 2/6] Updated docs --- docs/configuration.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.asciidoc b/docs/configuration.asciidoc index 3df5caafc..77a64a0d3 100644 --- a/docs/configuration.asciidoc +++ b/docs/configuration.asciidoc @@ -90,7 +90,7 @@ _Default:_ `false` _Default:_ `null` |`agent` -|`http.AgentOptions` - http agent https://nodejs.org/api/http.html#http_new_agent_options[options]. + +|`http.AgentOptions` - http agent https://nodejs.org/api/http.html#http_new_agent_options[options], or an actual http agent instance. + _Default:_ `null` |`nodeFilter` From 8d7228b7986001116d6ad2c92f6bd1e11b739501 Mon Sep 17 00:00:00 2001 From: delvedor Date: Tue, 9 Apr 2019 12:51:09 +0200 Subject: [PATCH 3/6] Updated test --- test/unit/connection.test.js | 50 ++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/test/unit/connection.test.js b/test/unit/connection.test.js index 229e00d04..3135a5255 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 + }) + 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) From c4feec0912fe58be0765ea256d1becfdc9c03499 Mon Sep 17 00:00:00 2001 From: delvedor Date: Tue, 9 Apr 2019 15:31:13 +0200 Subject: [PATCH 4/6] Use a function to retrieve the custom http agent --- index.d.ts | 6 ++---- lib/Connection.d.ts | 5 +++-- lib/Connection.js | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/index.d.ts b/index.d.ts index 3411c13b0..7b8bcc49d 100644 --- a/index.d.ts +++ b/index.d.ts @@ -21,8 +21,6 @@ import { EventEmitter } from 'events'; import { SecureContextOptions } from 'tls'; -import * as http from 'http'; -import * as https from 'https'; import Transport, { ApiResponse, RequestEvent, @@ -31,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'; @@ -84,7 +82,7 @@ interface ClientOptions { suggestCompression?: boolean; compression?: 'gzip'; ssl?: SecureContextOptions; - agent?: AgentOptions | http.Agent | https.Agent; + agent?: AgentOptions | agentFn; nodeFilter?: nodeFilterFn; nodeSelector?: nodeSelectorFn | string; headers?: anyObject; diff --git a/lib/Connection.d.ts b/lib/Connection.d.ts index ca6d1cf80..a02b6f72a 100644 --- a/lib/Connection.d.ts +++ b/lib/Connection.d.ts @@ -22,15 +22,16 @@ import { URL } from 'url'; import { inspect, InspectOptions } from 'util'; import * as http from 'http'; -import * as https from 'http'; import { SecureContextOptions } from 'tls'; +export declare type agentFn = () => any; + interface ConnectionOptions { url: URL; ssl?: SecureContextOptions; id?: string; headers?: any; - agent?: AgentOptions | http.Agent | https.Agent; + agent?: AgentOptions | agentFn; status?: string; roles?: any; } diff --git a/lib/Connection.js b/lib/Connection.js index 57a9b2897..e90182453 100644 --- a/lib/Connection.js +++ b/lib/Connection.js @@ -46,8 +46,8 @@ class Connection { throw new ConfigurationError(`Invalid protocol: '${this.url.protocol}'`) } - if (opts.agent instanceof http.Agent || opts.agent instanceof https.Agent) { - this.agent = opts.agent + if (typeof opts.agent === 'function') { + this.agent = opts.agent() } else { const keepAliveFalse = opts.agent && opts.agent.keepAlive === false const agentOptions = Object.assign({}, { From 3c5599240356b688b4a7843f708f60dfece7817e Mon Sep 17 00:00:00 2001 From: delvedor Date: Tue, 9 Apr 2019 15:31:21 +0200 Subject: [PATCH 5/6] Updated docs --- docs/configuration.asciidoc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/configuration.asciidoc b/docs/configuration.asciidoc index 77a64a0d3..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], or an actual http agent instance. + +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. + From 3705fedc0fa6fed118e524f5fc395afcf2c8bb51 Mon Sep 17 00:00:00 2001 From: delvedor Date: Tue, 9 Apr 2019 15:31:24 +0200 Subject: [PATCH 6/6] Updated test --- test/unit/connection.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/connection.test.js b/test/unit/connection.test.js index 3135a5255..84068cad5 100644 --- a/test/unit/connection.test.js +++ b/test/unit/connection.test.js @@ -171,7 +171,7 @@ test('Custom http agent', t => { agent.custom = true const connection = new Connection({ url: new URL(`http://localhost:${port}`), - agent + agent: () => agent }) t.true(connection.agent.custom) connection.request({