feat: add support for configuring system network context proxies (#41335)
* feat: add support for configuring system network context proxies * chore: add specs * chore: fix lint * fix: address review feedback
This commit is contained in:
parent
136762b45f
commit
26131b23b8
13 changed files with 391 additions and 113 deletions
|
@ -6,9 +6,10 @@ import * as net from 'node:net';
|
|||
import * as fs from 'fs-extra';
|
||||
import * as path from 'node:path';
|
||||
import { promisify } from 'node:util';
|
||||
import { app, BrowserWindow, Menu, session, net as electronNet, WebContents } from 'electron/main';
|
||||
import { app, BrowserWindow, Menu, session, net as electronNet, WebContents, utilityProcess } from 'electron/main';
|
||||
import { closeWindow, closeAllWindows } from './lib/window-helpers';
|
||||
import { ifdescribe, ifit, listen, waitUntil } from './lib/spec-helpers';
|
||||
import { collectStreamBody, getResponse } from './lib/net-helpers';
|
||||
import { once } from 'node:events';
|
||||
import split = require('split')
|
||||
import * as semver from 'semver';
|
||||
|
@ -1895,6 +1896,154 @@ describe('app module', () => {
|
|||
app.showAboutPanel();
|
||||
});
|
||||
});
|
||||
|
||||
describe('app.setProxy(options)', () => {
|
||||
let server: http.Server;
|
||||
|
||||
afterEach(async () => {
|
||||
if (server) {
|
||||
server.close();
|
||||
}
|
||||
await app.setProxy({ mode: 'direct' as const });
|
||||
});
|
||||
|
||||
it('allows configuring proxy settings', async () => {
|
||||
const config = { proxyRules: 'http=myproxy:80' };
|
||||
await app.setProxy(config);
|
||||
const proxy = await app.resolveProxy('http://example.com/');
|
||||
expect(proxy).to.equal('PROXY myproxy:80');
|
||||
});
|
||||
|
||||
it('allows removing the implicit bypass rules for localhost', async () => {
|
||||
const config = {
|
||||
proxyRules: 'http=myproxy:80',
|
||||
proxyBypassRules: '<-loopback>'
|
||||
};
|
||||
|
||||
await app.setProxy(config);
|
||||
const proxy = await app.resolveProxy('http://localhost');
|
||||
expect(proxy).to.equal('PROXY myproxy:80');
|
||||
});
|
||||
|
||||
it('allows configuring proxy settings with pacScript', async () => {
|
||||
server = http.createServer((req, res) => {
|
||||
const pac = `
|
||||
function FindProxyForURL(url, host) {
|
||||
return "PROXY myproxy:8132";
|
||||
}
|
||||
`;
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'application/x-ns-proxy-autoconfig'
|
||||
});
|
||||
res.end(pac);
|
||||
});
|
||||
const { url } = await listen(server);
|
||||
{
|
||||
const config = { pacScript: url };
|
||||
await app.setProxy(config);
|
||||
const proxy = await app.resolveProxy('https://google.com');
|
||||
expect(proxy).to.equal('PROXY myproxy:8132');
|
||||
}
|
||||
{
|
||||
const config = { mode: 'pac_script' as any, pacScript: url };
|
||||
await app.setProxy(config);
|
||||
const proxy = await app.resolveProxy('https://google.com');
|
||||
expect(proxy).to.equal('PROXY myproxy:8132');
|
||||
}
|
||||
});
|
||||
|
||||
it('allows bypassing proxy settings', async () => {
|
||||
const config = {
|
||||
proxyRules: 'http=myproxy:80',
|
||||
proxyBypassRules: '<local>'
|
||||
};
|
||||
await app.setProxy(config);
|
||||
const proxy = await app.resolveProxy('http://example/');
|
||||
expect(proxy).to.equal('DIRECT');
|
||||
});
|
||||
|
||||
it('allows configuring proxy settings with mode `direct`', async () => {
|
||||
const config = { mode: 'direct' as const, proxyRules: 'http=myproxy:80' };
|
||||
await app.setProxy(config);
|
||||
const proxy = await app.resolveProxy('http://example.com/');
|
||||
expect(proxy).to.equal('DIRECT');
|
||||
});
|
||||
|
||||
it('allows configuring proxy settings with mode `auto_detect`', async () => {
|
||||
const config = { mode: 'auto_detect' as const };
|
||||
await app.setProxy(config);
|
||||
});
|
||||
|
||||
it('allows configuring proxy settings with mode `pac_script`', async () => {
|
||||
const config = { mode: 'pac_script' as const };
|
||||
await app.setProxy(config);
|
||||
const proxy = await app.resolveProxy('http://example.com/');
|
||||
expect(proxy).to.equal('DIRECT');
|
||||
});
|
||||
|
||||
it('allows configuring proxy settings with mode `fixed_servers`', async () => {
|
||||
const config = { mode: 'fixed_servers' as const, proxyRules: 'http=myproxy:80' };
|
||||
await app.setProxy(config);
|
||||
const proxy = await app.resolveProxy('http://example.com/');
|
||||
expect(proxy).to.equal('PROXY myproxy:80');
|
||||
});
|
||||
|
||||
it('allows configuring proxy settings with mode `system`', async () => {
|
||||
const config = { mode: 'system' as const };
|
||||
await app.setProxy(config);
|
||||
});
|
||||
|
||||
it('disallows configuring proxy settings with mode `invalid`', async () => {
|
||||
const config = { mode: 'invalid' as any };
|
||||
await expect(app.setProxy(config)).to.eventually.be.rejectedWith(/Invalid mode/);
|
||||
});
|
||||
|
||||
it('impacts proxy for requests made from utility process', async () => {
|
||||
const utilityFixturePath = path.resolve(__dirname, 'fixtures', 'api', 'utility-process', 'api-net-spec.js');
|
||||
const fn = async () => {
|
||||
const urlRequest = electronNet.request('http://example.com/');
|
||||
const response = await getResponse(urlRequest);
|
||||
expect(response.statusCode).to.equal(200);
|
||||
const message = await collectStreamBody(response);
|
||||
expect(message).to.equal('ok from proxy\n');
|
||||
};
|
||||
server = http.createServer((req, res) => {
|
||||
res.writeHead(200);
|
||||
res.end('ok from proxy\n');
|
||||
});
|
||||
const { port, hostname } = await listen(server);
|
||||
const config = { mode: 'fixed_servers' as const, proxyRules: `http=${hostname}:${port}` };
|
||||
await app.setProxy(config);
|
||||
const proxy = await app.resolveProxy('http://example.com/');
|
||||
expect(proxy).to.equal(`PROXY ${hostname}:${port}`);
|
||||
const child = utilityProcess.fork(utilityFixturePath, [], {
|
||||
execArgv: ['--expose-gc']
|
||||
});
|
||||
child.postMessage({ fn: `(${fn})()` });
|
||||
const [data] = await once(child, 'message');
|
||||
expect(data.ok).to.be.true(data.message);
|
||||
// Cleanup.
|
||||
const [code] = await once(child, 'exit');
|
||||
expect(code).to.equal(0);
|
||||
});
|
||||
|
||||
it('does not impact proxy for requests made from main process', async () => {
|
||||
server = http.createServer((req, res) => {
|
||||
res.writeHead(200);
|
||||
res.end('ok from server\n');
|
||||
});
|
||||
const { url } = await listen(server);
|
||||
const config = { mode: 'fixed_servers' as const, proxyRules: 'http=myproxy:80' };
|
||||
await app.setProxy(config);
|
||||
const proxy = await app.resolveProxy('http://example.com/');
|
||||
expect(proxy).to.equal('PROXY myproxy:80');
|
||||
const urlRequest = electronNet.request(url);
|
||||
const response = await getResponse(urlRequest);
|
||||
expect(response.statusCode).to.equal(200);
|
||||
const message = await collectStreamBody(response);
|
||||
expect(message).to.equal('ok from server\n');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('default behavior', () => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue