feat(connect): exposeNetwork option (#24436)

This commit is contained in:
Dmitry Gozman 2023-07-26 17:29:31 -07:00 committed by GitHub
parent ececb6d19e
commit ea6d127f28
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 78 additions and 12 deletions

View file

@ -124,6 +124,22 @@ Logger sink for Playwright logging. Optional.
Maximum time in milliseconds to wait for the connection to be established. Defaults to Maximum time in milliseconds to wait for the connection to be established. Defaults to
`0` (no timeout). `0` (no timeout).
### option: BrowserType.connect.exposeNetwork
* since: v1.37
- `exposeNetwork` <[string]>
This option exposes network available on the connecting client to the browser being connected to. Consists of a list of rules separated by comma.
Available rules:
1. Hostname pattern, for example: `example.com`, `*.org:99`, `x.*.y.com`, `*foo.org`.
1. IP literal, for example: `127.0.0.1`, `0.0.0.0:99`, `[::1]`, `[0:0::1]:99`.
1. `<loopback>` that matches local loopback interfaces: `localhost`, `*.localhost`, `127.0.0.1`, `[::1]`.
Some common examples:
1. `"*"` to expose all network.
1. `"<loopback>"` to expose localhost network.
1. `"*.test.internal-domain,*.staging.internal-domain,<loopback>"` to expose test/staging deployments and localhost.
## async method: BrowserType.connectOverCDP ## async method: BrowserType.connectOverCDP
* since: v1.9 * since: v1.9
- returns: <[Browser]> - returns: <[Browser]>

View file

@ -97,7 +97,7 @@ export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel> imple
'x-playwright-launch-options': jsonStringifyForceASCII({ ...this._defaultLaunchOptions, ...launchOptions }), 'x-playwright-launch-options': jsonStringifyForceASCII({ ...this._defaultLaunchOptions, ...launchOptions }),
...connectOptions.headers, ...connectOptions.headers,
}, },
_exposeNetwork: connectOptions._exposeNetwork, exposeNetwork: connectOptions.exposeNetwork ?? connectOptions._exposeNetwork,
slowMo: connectOptions.slowMo, slowMo: connectOptions.slowMo,
timeout: connectOptions.timeout ?? 3 * 60 * 1000, // 3 minutes timeout: connectOptions.timeout ?? 3 * 60 * 1000, // 3 minutes
}); });
@ -149,7 +149,7 @@ export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel> imple
const connectParams: channels.LocalUtilsConnectParams = { const connectParams: channels.LocalUtilsConnectParams = {
wsEndpoint: params.wsEndpoint, wsEndpoint: params.wsEndpoint,
headers, headers,
exposeNetwork: params._exposeNetwork, exposeNetwork: params.exposeNetwork ?? params._exposeNetwork,
slowMo: params.slowMo, slowMo: params.slowMo,
timeout: params.timeout, timeout: params.timeout,
}; };

View file

@ -87,6 +87,7 @@ export type LaunchPersistentContextOptions = Omit<LaunchOptionsBase & BrowserCon
export type ConnectOptions = { export type ConnectOptions = {
wsEndpoint: string, wsEndpoint: string,
headers?: { [key: string]: string; }; headers?: { [key: string]: string; };
exposeNetwork?: string,
_exposeNetwork?: string, _exposeNetwork?: string,
slowMo?: number, slowMo?: number,
timeout?: number, timeout?: number,

View file

@ -19640,6 +19640,23 @@ export interface ConnectOverCDPOptions {
} }
export interface ConnectOptions { export interface ConnectOptions {
/**
* This option exposes network available on the connecting client to the browser being connected to. Consists of a
* list of rules separated by comma.
*
* Available rules:
* 1. Hostname pattern, for example: `example.com`, `*.org:99`, `x.*.y.com`, `*foo.org`.
* 1. IP literal, for example: `127.0.0.1`, `0.0.0.0:99`, `[::1]`, `[0:0::1]:99`.
* 1. `<loopback>` that matches local loopback interfaces: `localhost`, `*.localhost`, `127.0.0.1`, `[::1]`.
*
* Some common examples:
* 1. `"*"` to expose all network.
* 1. `"<loopback>"` to expose localhost network.
* 1. `"*.test.internal-domain,*.staging.internal-domain,<loopback>"` to expose test/staging deployments and
* localhost.
*/
exposeNetwork?: string;
/** /**
* Additional HTTP headers to be sent with web socket connect request. Optional. * Additional HTTP headers to be sent with web socket connect request. Optional.
*/ */

View file

@ -514,7 +514,7 @@ function connectOptionsFromEnv() {
return { return {
wsEndpoint, wsEndpoint,
headers, headers,
_exposeNetwork: process.env.PW_TEST_CONNECT_EXPOSE_NETWORK, exposeNetwork: process.env.PW_TEST_CONNECT_EXPOSE_NETWORK,
}; };
} }

View file

@ -3392,6 +3392,22 @@ type ConnectOptions = {
*/ */
headers?: { [key: string]: string; }; headers?: { [key: string]: string; };
/**
* This option exposes network available on the connecting client to the browser being connected to.
* Consists of a list of rules separated by comma.
*
* Available rules:
* - Hostname pattern, for example: `example.com`, `*.org:99`, `x.*.y.com`, `*foo.org`.
* - IP literal, for example: `127.0.0.1`, `0.0.0.0:99`, `[::1]`, `[0:0::1]:99`.
* - `<loopback>` that matches local loopback interfaces: `localhost`, `*.localhost`, `127.0.0.1`, `[::1]`.
* Some common examples:
* - `"*"` to expose all network.
* - `"<loopback>"` to expose localhost network.
* - `"*.test.internal-domain,*.staging.internal-domain,<loopback>"` to expose test/staging deployments and localhost.
*/
exposeNetwork?: string;
/** /**
* Timeout in milliseconds for the connection to be established. Optional, defaults to no timeout. * Timeout in milliseconds for the connection to be established. Optional, defaults to no timeout.
*/ */

View file

@ -736,7 +736,7 @@ for (const kind of ['launchServer', 'run-server'] as const) {
res.end('<html><body>original-target</body></html>'); res.end('<html><body>original-target</body></html>');
}); });
const remoteServer = await startRemoteServer(kind); const remoteServer = await startRemoteServer(kind);
const browser = await connect(remoteServer.wsEndpoint(), { _exposeNetwork: '*' } as any); const browser = await connect(remoteServer.wsEndpoint(), { exposeNetwork: '*' });
const page = await browser.newPage(); const page = await browser.newPage();
await page.goto(server.PREFIX + '/foo.html'); await page.goto(server.PREFIX + '/foo.html');
expect(await page.content()).toContain('original-target'); expect(await page.content()).toContain('original-target');
@ -770,7 +770,7 @@ for (const kind of ['launchServer', 'run-server'] as const) {
}); });
const examplePort = 20_000 + testInfo.workerIndex * 3; const examplePort = 20_000 + testInfo.workerIndex * 3;
const remoteServer = await startRemoteServer(kind); const remoteServer = await startRemoteServer(kind);
const browser = await connect(remoteServer.wsEndpoint(), { _exposeNetwork: '*' } as any, ipV6ServerPort); const browser = await connect(remoteServer.wsEndpoint(), { exposeNetwork: '*' }, ipV6ServerPort);
const page = await browser.newPage(); const page = await browser.newPage();
await page.goto(`http://[::1]:${examplePort}/foo.html`); await page.goto(`http://[::1]:${examplePort}/foo.html`);
expect(await page.content()).toContain('from-ipv6-server'); expect(await page.content()).toContain('from-ipv6-server');
@ -790,7 +790,7 @@ for (const kind of ['launchServer', 'run-server'] as const) {
}); });
const examplePort = 20_000 + workerInfo.workerIndex * 3; const examplePort = 20_000 + workerInfo.workerIndex * 3;
const remoteServer = await startRemoteServer(kind); const remoteServer = await startRemoteServer(kind);
const browser = await connect(remoteServer.wsEndpoint(), { _exposeNetwork: '*' } as any, dummyServerPort); const browser = await connect(remoteServer.wsEndpoint(), { exposeNetwork: '*' }, dummyServerPort);
const page = await browser.newPage(); const page = await browser.newPage();
const response = await page.request.get(`http://127.0.0.1:${examplePort}/foo.html`); const response = await page.request.get(`http://127.0.0.1:${examplePort}/foo.html`);
expect(response.status()).toBe(200); expect(response.status()).toBe(200);
@ -806,7 +806,7 @@ for (const kind of ['launchServer', 'run-server'] as const) {
}); });
const examplePort = 20_000 + workerInfo.workerIndex * 3; const examplePort = 20_000 + workerInfo.workerIndex * 3;
const remoteServer = await startRemoteServer(kind); const remoteServer = await startRemoteServer(kind);
const browser = await connect(remoteServer.wsEndpoint(), { _exposeNetwork: '*' } as any, dummyServerPort); const browser = await connect(remoteServer.wsEndpoint(), { exposeNetwork: '*' }, dummyServerPort);
const page = await browser.newPage(); const page = await browser.newPage();
await page.goto(`http://local.playwright:${examplePort}/foo.html`); await page.goto(`http://local.playwright:${examplePort}/foo.html`);
expect(await page.content()).toContain('from-dummy-server'); expect(await page.content()).toContain('from-dummy-server');
@ -816,7 +816,7 @@ for (const kind of ['launchServer', 'run-server'] as const) {
test('should lead to the error page for forwarded requests when the connection is refused', async ({ connect, startRemoteServer, browserName }, workerInfo) => { test('should lead to the error page for forwarded requests when the connection is refused', async ({ connect, startRemoteServer, browserName }, workerInfo) => {
const examplePort = 20_000 + workerInfo.workerIndex * 3; const examplePort = 20_000 + workerInfo.workerIndex * 3;
const remoteServer = await startRemoteServer(kind); const remoteServer = await startRemoteServer(kind);
const browser = await connect(remoteServer.wsEndpoint(), { _exposeNetwork: '*' } as any); const browser = await connect(remoteServer.wsEndpoint(), { exposeNetwork: '*' });
const page = await browser.newPage(); const page = await browser.newPage();
const error = await page.goto(`http://127.0.0.1:${examplePort}`).catch(e => e); const error = await page.goto(`http://127.0.0.1:${examplePort}`).catch(e => e);
if (browserName === 'chromium') if (browserName === 'chromium')
@ -837,7 +837,7 @@ for (const kind of ['launchServer', 'run-server'] as const) {
}); });
const examplePort = 20_000 + workerInfo.workerIndex * 3; const examplePort = 20_000 + workerInfo.workerIndex * 3;
const remoteServer = await startRemoteServer(kind); const remoteServer = await startRemoteServer(kind);
const browser = await connect(remoteServer.wsEndpoint(), { _exposeNetwork: 'localhost' } as any, dummyServerPort); const browser = await connect(remoteServer.wsEndpoint(), { exposeNetwork: 'localhost' }, dummyServerPort);
const page = await browser.newPage(); const page = await browser.newPage();
// localhost should be proxied. // localhost should be proxied.
@ -866,11 +866,11 @@ for (const kind of ['launchServer', 'run-server'] as const) {
}); });
const remoteServer = await startRemoteServer(kind); const remoteServer = await startRemoteServer(kind);
const browser = await connect(remoteServer.wsEndpoint(), { const browser = await connect(remoteServer.wsEndpoint(), {
_exposeNetwork: '127.0.0.1', exposeNetwork: '127.0.0.1',
headers: { headers: {
'x-playwright-proxy': '*', 'x-playwright-proxy': '*',
}, },
} as any, dummyServerPort); }, dummyServerPort);
const page = await browser.newPage(); const page = await browser.newPage();
// local.playwright should fail on the client side. // local.playwright should fail on the client side.

View file

@ -64,7 +64,7 @@ if (mode === 'service2') {
connectOptions = { connectOptions = {
wsEndpoint: `${process.env.PLAYWRIGHT_SERVICE_URL}?accessKey=${process.env.PLAYWRIGHT_SERVICE_ACCESS_KEY}&cap=${JSON.stringify({ os, runId })}`, wsEndpoint: `${process.env.PLAYWRIGHT_SERVICE_URL}?accessKey=${process.env.PLAYWRIGHT_SERVICE_ACCESS_KEY}&cap=${JSON.stringify({ os, runId })}`,
timeout: 3 * 60 * 1000, timeout: 3 * 60 * 1000,
_exposeNetwork: '<loopback>', exposeNetwork: '<loopback>',
}; };
} }

View file

@ -192,6 +192,22 @@ type ConnectOptions = {
*/ */
headers?: { [key: string]: string; }; headers?: { [key: string]: string; };
/**
* This option exposes network available on the connecting client to the browser being connected to.
* Consists of a list of rules separated by comma.
*
* Available rules:
* - Hostname pattern, for example: `example.com`, `*.org:99`, `x.*.y.com`, `*foo.org`.
* - IP literal, for example: `127.0.0.1`, `0.0.0.0:99`, `[::1]`, `[0:0::1]:99`.
* - `<loopback>` that matches local loopback interfaces: `localhost`, `*.localhost`, `127.0.0.1`, `[::1]`.
* Some common examples:
* - `"*"` to expose all network.
* - `"<loopback>"` to expose localhost network.
* - `"*.test.internal-domain,*.staging.internal-domain,<loopback>"` to expose test/staging deployments and localhost.
*/
exposeNetwork?: string;
/** /**
* Timeout in milliseconds for the connection to be established. Optional, defaults to no timeout. * Timeout in milliseconds for the connection to be established. Optional, defaults to no timeout.
*/ */