From cb740b63768b334b7a605b151a542ffa11d5af56 Mon Sep 17 00:00:00 2001 From: Paul Winkler Date: Wed, 9 Mar 2022 15:17:40 +0000 Subject: [PATCH] Use http-proxy-agent and https-proxy-agent instead of hpagent --- lib/remote-model.js | 42 ++++++++++++++++++++-------------- package-lock.json | 43 +++++++++++++++++++++++++++++------ package.json | 3 ++- test/helper.js | 2 ++ test/lib/spec.remote-model.js | 36 ++++++++++++++++++++++++----- 5 files changed, 95 insertions(+), 31 deletions(-) diff --git a/lib/remote-model.js b/lib/remote-model.js index a4fd524..e7c4abc 100644 --- a/lib/remote-model.js +++ b/lib/remote-model.js @@ -122,28 +122,36 @@ class RemoteModel extends LocalModel { proxy(proxy = this.options.proxy, url) { if (!proxy || !url) return; - if (typeof proxy === 'string') proxy = { proxy }; + if (typeof proxy === 'string') proxy = { uri: proxy }; + + const proxyUrl = new URL(proxy.uri); + + const getAuth = u => + u.username && u.password ? decodeURIComponent(`${u.username}:${u.password}`) : + u.username ? decodeURIComponent(u.username) : null; + + const getPath = u => u.pathname + u.search + u.hash; + + const options = Object.assign({ + host: proxyUrl.hostname, + port: proxyUrl.port, + protocol: proxyUrl.protocol, + path: getPath(proxyUrl), + auth: getAuth(proxyUrl), + maxSockets: 1, + keepAlive: false + }, proxy); const isHttps = (new URL(url).protocol === 'https:'); if (isHttps) { - const { HttpsProxyAgent } = require('hpagent'); - return { - https: new HttpsProxyAgent(Object.assign({ - keepAlive: false, - maxSockets: 1, - maxFreeSockets: 1, - }, proxy)) - }; + const HttpsProxyAgent = require('https-proxy-agent'); + const agent = new HttpsProxyAgent(options); + return { https: agent }; } else { - const { HttpProxyAgent } = require('hpagent'); - return { - http: new HttpProxyAgent(Object.assign({ - keepAlive: false, - maxSockets: 1, - maxFreeSockets: 1, - }, proxy)) - }; + const HttpProxyAgent = require('http-proxy-agent'); + const agent = new HttpProxyAgent(options); + return { http: agent }; } } diff --git a/package-lock.json b/package-lock.json index 50c8ae0..2dbef0b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -469,6 +469,11 @@ "defer-to-connect": "^2.0.0" } }, + "@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==" + }, "@types/cacheable-request": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.2.tgz", @@ -524,6 +529,14 @@ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + } + }, "aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -554,7 +567,8 @@ }, "ansi-regex": { "version": "5.0.0", - "resolved": "", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", "dev": true }, "ansi-styles": { @@ -1480,11 +1494,6 @@ } } }, - "hpagent": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-0.1.2.tgz", - "integrity": "sha512-ePqFXHtSQWAFXYmj+JtOTHr84iNrII4/QRlAAPPE+zqnKy4xJo7Ie1Y4kC7AdB+LxLxSTTzBMASsEcy0q8YyvQ==" - }, "html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -1496,6 +1505,16 @@ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" }, + "http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "requires": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + } + }, "http2-wrapper": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", @@ -1505,6 +1524,15 @@ "resolve-alpn": "^1.0.0" } }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "requires": { + "agent-base": "6", + "debug": "4" + } + }, "ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -2440,7 +2468,8 @@ }, "path-parse": { "version": "1.0.6", - "resolved": "", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, "path-to-regexp": { diff --git a/package.json b/package.json index 7c96ed3..8037cc5 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,8 @@ "dependencies": { "debug": "^4.3.3", "got": "^11.8.3", - "hpagent": "^0.1.2", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", "lodash.kebabcase": "^4.1.1" }, "devDependencies": { diff --git a/test/helper.js b/test/helper.js index 853c1eb..36af334 100644 --- a/test/helper.js +++ b/test/helper.js @@ -4,3 +4,5 @@ global.should = chai.should(); global.expect = chai.expect; global.sinon = require('sinon'); chai.use(require('sinon-chai')); + +require('hmpo-logger').config(); diff --git a/test/lib/spec.remote-model.js b/test/lib/spec.remote-model.js index 4e3df2b..9e23788 100644 --- a/test/lib/spec.remote-model.js +++ b/test/lib/spec.remote-model.js @@ -5,7 +5,8 @@ const ModelError = require('../../lib/model-error'); const BaseModel = require('../../lib/local-model'); const logger = require('hmpo-logger'); -const { HttpProxyAgent, HttpsProxyAgent } = require('hpagent'); +const HttpsProxyAgent = require('https-proxy-agent'); +const HttpProxyAgent = require('http-proxy-agent'); describe('Remote Model', () => { let model, cb, mocks; @@ -71,7 +72,7 @@ describe('Remote Model', () => { }); it('should use console log and a trimHtml pass-through if hmpo-logger is not available', () => { - logger.get.throws(new Error()); + logger.get.throws({ message: 'test error' }); model = new Model(); @@ -431,19 +432,43 @@ describe('Remote Model', () => { 'method': 'VERB', 'url': 'http://example.net', 'proxy': { - proxy: 'http://proxy.example.com:8000', - keepAlive: true + uri: 'http://proxy.example.com:8000', + keepAlive: true, + maxSockets: 200 } }); sinon.assert.match(returnedConfig, { agent: { http: { - keepAlive: true + proxy: { + keepAlive: true, + maxSockets: 200 + } } } }); }); + + it('should process auth for the proxy', () => { + let agent; + + agent = model.proxy('http://username:password@host:123/path', 'https://example.com'); + sinon.assert.match(agent.https.proxy, { + auth: 'username:password', + host: 'host', + port: 123, + protocol: 'http:' + }); + + agent = model.proxy('http://username@host:123/path', 'https://example.com'); + sinon.assert.match(agent.https.proxy, { + auth: 'username', + host: 'host', + port: 123, + protocol: 'http:' + }); + }); }); describe('with headers supplied into the constructor', () => { @@ -742,7 +767,6 @@ describe('Remote Model', () => { }; model.request(settings, cb); - console.log(model.logError.args[0][0]); model.logError.should.have.been.calledWithExactly({ settings: settings, statusCode: 404,