From f21ab8a105826b64bf5c2df81e1f341537d273c0 Mon Sep 17 00:00:00 2001 From: tuwrraphael Date: Tue, 9 Mar 2021 16:21:46 +0100 Subject: [PATCH] Fix constructor on NO_PROXY with wildcard domain (#216) * fix contrstructor on NO_PROXY with wildcard domain * escape * in NO_PROXY regex only if needed keep the original behavior for back-compat purposes * patch for no proxy with wildcards --- lib/HttpClient.ts | 2 +- lib/Util.ts | 22 ++++++++++++++++++++ package-lock.json | 2 +- package.json | 2 +- test/units/httptests.ts | 40 +++++++++++++++++++++++++++++++++++ test/units/utiltests.ts | 46 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 test/units/utiltests.ts diff --git a/lib/HttpClient.ts b/lib/HttpClient.ts index 0732e2a..2e0f519 100644 --- a/lib/HttpClient.ts +++ b/lib/HttpClient.ts @@ -128,7 +128,7 @@ export class HttpClient implements ifm.IHttpClient { if (no_proxy) { this._httpProxyBypassHosts = []; no_proxy.split(',').forEach(bypass => { - this._httpProxyBypassHosts.push(new RegExp(bypass, 'i')); + this._httpProxyBypassHosts.push(util.buildProxyBypassRegexFromEnv(bypass)); }); } diff --git a/lib/Util.ts b/lib/Util.ts index 3a377e8..0bd5992 100644 --- a/lib/Util.ts +++ b/lib/Util.ts @@ -98,6 +98,28 @@ export async function decompressGzippedContent(buffer: Buffer, charset?: string) }) } +/** + * Builds a RegExp to test urls against for deciding + * wether to bypass proxy from an entry of the + * environment variable setting NO_PROXY + * + * @param {string} bypass + * @return {RegExp} + */ +export function buildProxyBypassRegexFromEnv(bypass : string) : RegExp { + try { + // We need to keep this around for back-compat purposes + return new RegExp(bypass, 'i') + } + catch(err) { + if (err instanceof SyntaxError && (bypass || "").startsWith("*")) { + let wildcardEscaped = bypass.replace('*', '(.*)'); + return new RegExp(wildcardEscaped, 'i'); + } + throw err; + } +} + /** * Obtain Response's Content Charset. * Through inspecting `content-type` response header. diff --git a/package-lock.json b/package-lock.json index 6482198..55bf209 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "typed-rest-client", - "version": "1.8.2", + "version": "1.8.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 8e00631..ff2afd9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "typed-rest-client", - "version": "1.8.2", + "version": "1.8.3", "description": "Node Rest and Http Clients for use with TypeScript", "main": "./RestClient.js", "scripts": { diff --git a/test/units/httptests.ts b/test/units/httptests.ts index ad33268..bd85c05 100644 --- a/test/units/httptests.ts +++ b/test/units/httptests.ts @@ -462,3 +462,43 @@ describe('Http Tests with keepAlive', function () { assert(res.message.statusCode == 501, "status code should be 501"); }); }); + +describe('Http Tests with NO_PROXY environment variable', function () { + let noProxyBeforeTest = undefined; + before(() => { + + }); + + after(() => { + + }); + + beforeEach(() => { + noProxyBeforeTest = process.env["NO_PROXY"]; + }); + + afterEach(() => { + if (undefined !== noProxyBeforeTest) { + process.env["NO_PROXY"] = noProxyBeforeTest; + } else { + delete process.env["NO_PROXY"]; + } + }) + + it('constructs with NO_PROXY', () => { + this.timeout(1000); + process.env["NO_PROXY"] = "microsoft.com"; + let http: httpm.HttpClient = new httpm.HttpClient('typed-test-client-tests'); + assert(http, 'http client should not be null'); + assert(http.userAgent, 'user-agent should not be null') + }); + + it('constructs with wildcard in NO_PROXY', () => { + this.timeout(1000); + process.env["NO_PROXY"] = "*.microsoft.com"; + let http: httpm.HttpClient = new httpm.HttpClient('typed-test-client-tests'); + assert(http, 'http client should not be null'); + assert(http.userAgent, 'user-agent should not be null') + }); + +}); \ No newline at end of file diff --git a/test/units/utiltests.ts b/test/units/utiltests.ts new file mode 100644 index 0000000..e5acff4 --- /dev/null +++ b/test/units/utiltests.ts @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +import assert = require('assert'); +import url = require("url"); +import * as util from '../../lib/Util'; + +describe('Util Tests', function () { + + before(() => { + + }); + + after(() => { + }); + + describe('buildProxyBypassRegexFromEnv', () => { + it('constructs RegExp for domain', () => { + let regExp = util.buildProxyBypassRegexFromEnv('microsoft.com'); + assert(regExp, 'regExp should not be null'); + }); + + it('constructs RegExp for wildcard domain', () => { + let regExp = util.buildProxyBypassRegexFromEnv('*.microsoft.com'); + assert(regExp, 'regExp should not be null'); + }); + + it('bypasses same domain', () => { + let regExp = util.buildProxyBypassRegexFromEnv('microsoft.com'); + assert(regExp, 'regExp should not be null'); + let parsedUrl = url.parse("https://microsoft.com/api/resource"); + let bypassed = regExp.test(parsedUrl.href); + assert.equal(bypassed, true); + }); + + it('bypasses subdomain using wildcard', () => { + let regExp = util.buildProxyBypassRegexFromEnv('*.microsoft.com'); + assert(regExp, 'regExp should not be null'); + let parsedUrl = url.parse("https://subdomain.microsoft.com/api/resource"); + let bypassed = regExp.test(parsedUrl.href); + assert.equal(bypassed, true); + }); + + }); + +}); \ No newline at end of file