Skip to content

Commit dfbcf7d

Browse files
Adds NO_PROXY support for proxy configuration. Closes #7165 (#7179)
1 parent bd906c5 commit dfbcf7d

3 files changed

Lines changed: 16 additions & 78 deletions

File tree

docs/docs/user-guide/using-proxy-url.mdx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,13 @@ When using a proxy, it's important to understand the different parts of a proxy
1515
- **username and password**: if the proxy server requires authentication, you will need to provide a username and password
1616
- **host**: the hostname or IP address of the proxy server
1717
- **port number**: the port number on which the proxy server is listening. Defaults to 443 for the `HTTPS` protocol, otherwise it defaults to 80 when not provided
18+
19+
## Bypassing the proxy for specific hosts
20+
21+
If you need certain requests to bypass the proxy, you can use the `NO_PROXY` (or `no_proxy`) environment variable. This is a comma-separated list of hostnames or domain patterns that should not be routed through the proxy.
22+
23+
For example, to bypass the proxy for Microsoft authentication endpoints:
24+
25+
```sh
26+
export NO_PROXY="login.microsoftonline.com,*.microsoft.com,*.azure.net"
27+
```

src/request.spec.ts

Lines changed: 5 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -292,16 +292,11 @@ describe('Request', () => {
292292
});
293293
});
294294

295-
it('returns response of a successful GET request, with a proxy url', async () => {
296-
let proxyConfigured = false;
295+
it('does not set explicit proxy config on requests, letting Axios handle proxy natively', async () => {
297296
sinon.stub(process, 'env').value({ 'HTTPS_PROXY': 'http://proxy.contoso.com:8080' });
298297

299298
sinon.stub(_request as any, 'req').callsFake((options) => {
300299
_options = options as CliRequestOptions;
301-
proxyConfigured = !!_options.proxy &&
302-
_options.proxy.host === 'proxy.contoso.com' &&
303-
_options.proxy.port === 8080 &&
304-
_options.proxy.protocol === 'http';
305300
return { data: {} };
306301
});
307302

@@ -310,19 +305,14 @@ describe('Request', () => {
310305
url: 'https://contoso.sharepoint.com/'
311306
});
312307

313-
assert(proxyConfigured);
308+
assert.strictEqual(_options.proxy, undefined);
314309
});
315310

316-
it('returns response of a successful GET request, with a proxy url and defaults port to 80', async () => {
317-
let proxyConfigured = false;
318-
sinon.stub(process, 'env').value({ 'HTTPS_PROXY': 'http://proxy.contoso.com' });
311+
it('does not set explicit proxy config when NO_PROXY is set', async () => {
312+
sinon.stub(process, 'env').value({ 'HTTPS_PROXY': 'http://proxy.contoso.com:8080', 'NO_PROXY': 'contoso.sharepoint.com' });
319313

320314
sinon.stub(_request as any, 'req').callsFake((options) => {
321315
_options = options as CliRequestOptions;
322-
proxyConfigured = !!_options.proxy &&
323-
_options.proxy.host === 'proxy.contoso.com' &&
324-
_options.proxy.port === 80 &&
325-
_options.proxy.protocol === 'http';
326316
return { data: {} };
327317
});
328318

@@ -331,50 +321,7 @@ describe('Request', () => {
331321
url: 'https://contoso.sharepoint.com/'
332322
});
333323

334-
assert(proxyConfigured);
335-
});
336-
337-
it('returns response of a successful GET request, with a proxy url and defaults port to 443', async () => {
338-
let proxyConfigured = false;
339-
sinon.stub(process, 'env').value({ 'HTTPS_PROXY': 'https://proxy.contoso.com' });
340-
341-
sinon.stub(_request as any, 'req').callsFake((options) => {
342-
_options = options as CliRequestOptions;
343-
proxyConfigured = !!_options.proxy &&
344-
_options.proxy.host === 'proxy.contoso.com' &&
345-
_options.proxy.port === 443 &&
346-
_options.proxy.protocol === 'http';
347-
return { data: {} };
348-
});
349-
350-
await _request
351-
.get({
352-
url: 'https://contoso.sharepoint.com/'
353-
});
354-
assert(proxyConfigured);
355-
});
356-
357-
it('returns response of a successful GET request, with a proxy url with username and password', async () => {
358-
let proxyConfigured = false;
359-
sinon.stub(process, 'env').value({ 'HTTPS_PROXY': 'http://username:password@proxy.contoso.com:8080' });
360-
361-
sinon.stub(_request as any, 'req').callsFake((options) => {
362-
_options = options as CliRequestOptions;
363-
proxyConfigured = !!_options.proxy &&
364-
_options.proxy.host === 'proxy.contoso.com' &&
365-
_options.proxy.port === 8080 &&
366-
_options.proxy.protocol === 'http' &&
367-
_options.proxy.auth?.username === 'username' &&
368-
_options.proxy.auth?.password === 'password';
369-
return { data: {} };
370-
});
371-
372-
await _request
373-
.get({
374-
url: 'https://contoso.sharepoint.com/'
375-
});
376-
377-
assert(proxyConfigured);
324+
assert.strictEqual(_options.proxy, undefined);
378325
});
379326

380327
it('correctly handles failed GET request', async () => {

src/request.ts

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import Axios, { AxiosError, AxiosInstance, AxiosProxyConfig, AxiosRequestConfig, AxiosResponse } from 'axios';
1+
import Axios, { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
22
import { Stream } from 'stream';
33
import auth, { Auth, CloudType } from './Auth.js';
44
import { Logger } from './cli/Logger.js';
@@ -186,12 +186,6 @@ class Request {
186186
}
187187
}
188188

189-
const proxyUrl = process.env.HTTP_PROXY || process.env.HTTPS_PROXY;
190-
191-
if (proxyUrl) {
192-
options.proxy = this.createProxyConfigFromUrl(proxyUrl);
193-
}
194-
195189
const res = await this.req(options);
196190

197191
const end = process.hrtime.bigint();
@@ -235,19 +229,6 @@ class Request {
235229
options.url = options.url!.substring(0, 8) +
236230
options.url!.substring(8).replace('//', '/');
237231
}
238-
239-
private createProxyConfigFromUrl(url: string): AxiosProxyConfig {
240-
const parsedUrl = new URL(url);
241-
const port = parsedUrl.port || (url.toLowerCase().startsWith('https') ? 443 : 80);
242-
let authObject = null;
243-
if (parsedUrl.username && parsedUrl.password) {
244-
authObject = {
245-
username: parsedUrl.username,
246-
password: parsedUrl.password
247-
};
248-
}
249-
return { host: parsedUrl.hostname, port: Number(port), protocol: 'http', ...(authObject && { auth: authObject }) };
250-
}
251232
}
252233

253234
export default new Request();

0 commit comments

Comments
 (0)