From fdaaaa8d35485148a2e52a10b5860aeee00c1418 Mon Sep 17 00:00:00 2001 From: Michael Hirn Date: Thu, 15 Aug 2019 12:22:33 +0100 Subject: [PATCH 1/2] feat: add proxy support --- README.md | 1 + package-lock.json | 45 +++++++++++++++++++++++++++++++++++++++++++++ package.json | 3 +++ src/Api.js | 21 +++++++++++++++++---- src/ApiError.js | 1 + src/cli.js | 4 +++- 6 files changed, 70 insertions(+), 5 deletions(-) mode change 100644 => 100755 src/cli.js diff --git a/README.md b/README.md index 79eec8b..74e5916 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ let speedtest = new FastSpeedtest({ urlCount: 5, // default: 5 bufferSize: 8, // default: 8 unit: FastSpeedtest.UNITS.Mbps // default: Bps + proxy: 'http://optional:auth@my-proxy:123' // default: undefined }); speedtest.getSpeed().then(s => { diff --git a/package-lock.json b/package-lock.json index 940be66..115e91c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -124,6 +124,14 @@ "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", "dev": true }, + "agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "requires": { + "es6-promisify": "^5.0.0" + } + }, "ajv": { "version": "6.7.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.7.0.tgz", @@ -2093,6 +2101,19 @@ "is-symbol": "^1.0.2" } }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "requires": { + "es6-promise": "^4.0.3" + } + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -3121,6 +3142,30 @@ "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", "dev": true }, + "https-proxy-agent": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz", + "integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==", + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", diff --git a/package.json b/package.json index 7279989..c68bd4e 100644 --- a/package.json +++ b/package.json @@ -44,5 +44,8 @@ "eslint-plugin-import": "^2.14.0", "mocha": "^5.2.0", "release-it": "^9.8.1" + }, + "dependencies": { + "https-proxy-agent": "^2.2.2" } } diff --git a/src/Api.js b/src/Api.js index a2b459a..e74f0ec 100644 --- a/src/Api.js +++ b/src/Api.js @@ -1,5 +1,7 @@ const https = require('https'); const http = require('http'); +const HttpsProxyAgent = require('https-proxy-agent'); +const url = require('url'); const Timer = require('./Timer'); const ApiError = require('./ApiError'); @@ -28,6 +30,10 @@ class Api { throw new Error('Invalid unit'); } + if (options.proxy) { + this.proxy = new HttpsProxyAgent(options.proxy); + } + this.token = options.token; this.verbose = options.verbose || false; this.timeout = options.timeout || DEFAULT_SPEEDTEST_TIMEOUT; @@ -59,12 +65,12 @@ class Api { * Get data from the specified URL * * @async - * @param {string} url The URL to download from + * @param {string} options The http/s get options to download from * @return {Promise} The request and response from the URL */ - async get(url) { + async get(options) { return new Promise((resolve, reject) => { - const request = (this.https ? https : http).get(url, (response) => { + const request = (this.https ? https : http).get(options, (response) => { if (response.headers['content-type'].includes('json')) { response.setEncoding('utf8'); let rawData = ''; @@ -102,13 +108,20 @@ class Api { try { const targets = []; while (targets.length < this.urlCount) { + const target = `http${this.https ? 's' : ''}://api.fast.com/netflix/speedtest?https=${this.https ? 'true' : 'false'}&token=${this.token}&urlCount=${this.urlCount - targets.length}`; + const options = url.parse(target); + if (this.proxy) options.agent = this.proxy; /* eslint-disable no-await-in-loop */ - const { response } = await this.get(`http${this.https ? 's' : ''}://api.fast.com/netflix/speedtest?https=${this.https ? 'true' : 'false'}&token=${this.token}&urlCount=${this.urlCount - targets.length}`); + const { response } = await this.get(options); /* eslint-enable no-await-in-loop */ if (response.statusCode !== 200) { if (response.statusCode === 403) { throw new ApiError({ code: ApiError.CODES.BAD_TOKEN }); } + if (response.statusCode === 407) { + throw new ApiError({ code: ApiError.CODES.PROXY_NOT_AUTHENTICATED }); + } + console.log(response.statusCode); throw new ApiError({ code: ApiError.CODES.UNKNOWN }); } targets.push(...response.data); diff --git a/src/ApiError.js b/src/ApiError.js index f95000d..f874d07 100644 --- a/src/ApiError.js +++ b/src/ApiError.js @@ -22,6 +22,7 @@ ApiError.CODES = { BAD_TOKEN: 'Unknown app token', UNREACHABLE_HTTPS_API: 'Fast api is unreachable with https, try with http', UNREACHABLE_HTTP_API: 'Fast api is unreachable, check your network connection', + PROXY_NOT_AUTHENTICATED: 'Failed to authenticate with provided proxy credentials', UNKNOWN: 'Unknown error', }; diff --git a/src/cli.js b/src/cli.js old mode 100644 new mode 100755 index 3d8d99d..097b7d3 --- a/src/cli.js +++ b/src/cli.js @@ -8,7 +8,7 @@ const args = process.argv.slice(2); if (args.includes('-h') || args.includes('--help')) { console.log([ 'fast-speedtest - speed test powered by fast.com', - 'usage: fast-speedtest token [-v, --verbose] [-r, --raw] [-n, --no-https] [-t, --timeout timeout] [-c, --count url-count] [-b, --buffer buffer-size] [-u, --unit output-unit]', + 'usage: fast-speedtest token [-v, --verbose] [-r, --raw] [-n, --no-https] [-t, --timeout timeout] [-c, --count url-count] [-b, --buffer buffer-size] [-u, --unit output-unit] [-p, --proxy proxy]', ].join('\n')); process.exit(0); } @@ -42,6 +42,7 @@ const timeout = getArgParam('-t', '--timeout'); const urlCount = getArgParam('-c', '--count'); const bufferSize = getArgParam('-b', '--buffer'); const unitName = getArgParam('-u', '--unit'); +const proxy = getArgParam('-p', '--proxy'); if (unitName && !(unitName in Api.UNITS)) { throw new Error(`Unit not valide, must be one of ${Object.keys(Api.UNITS)}`); } @@ -55,6 +56,7 @@ const api = new Api({ bufferSize, https, unit, + proxy, }); api.getSpeed().then((s) => { From 158fe523b29bbd81b21dd5ef43ebd9fcaef6f60e Mon Sep 17 00:00:00 2001 From: Siopy <37114131+Siopyy@users.noreply.github.com> Date: Wed, 9 Oct 2019 07:41:44 +0200 Subject: [PATCH 2/2] Configuration lost "," --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 74e5916..90a7ba7 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ let speedtest = new FastSpeedtest({ https: true, // default: true urlCount: 5, // default: 5 bufferSize: 8, // default: 8 - unit: FastSpeedtest.UNITS.Mbps // default: Bps + unit: FastSpeedtest.UNITS.Mbps, // default: Bps proxy: 'http://optional:auth@my-proxy:123' // default: undefined });