From a7599ad509ab1f66b14239727f3156d9cfcebca4 Mon Sep 17 00:00:00 2001 From: cavivie Date: Mon, 27 May 2024 17:24:23 +0800 Subject: [PATCH] feat(api): add host option in launchServer options (#30999) --- docs/src/api/class-android.md | 6 ++++++ docs/src/api/class-browserserver.md | 2 ++ docs/src/api/class-browsertype.md | 6 ++++++ .../playwright-core/src/androidServerImpl.ts | 2 +- .../playwright-core/src/browserServerImpl.ts | 2 +- packages/playwright-core/src/client/types.ts | 2 ++ packages/playwright-core/types/types.d.ts | 17 +++++++++++++++++ tests/android/launch-server.spec.ts | 11 +++++++++++ tests/library/browsertype-launch-server.spec.ts | 7 +++++++ 9 files changed, 53 insertions(+), 2 deletions(-) diff --git a/docs/src/api/class-android.md b/docs/src/api/class-android.md index c889ee5d0b785..c976c9bba80ca 100644 --- a/docs/src/api/class-android.md +++ b/docs/src/api/class-android.md @@ -202,6 +202,12 @@ Prevents automatic playwright driver installation on attach. Assumes that the dr Optional device serial number to launch the browser on. If not specified, it will throw if multiple devices are connected. +### option: Android.launchServer.host +* since: v1.45 +- `host` <[string]> + +Host to use for the web socket. It is optional and if it is omitted, the server will accept connections on the unspecified IPv6 address (::) when IPv6 is available, or the unspecified IPv4 address (0.0.0.0) otherwise. Consider hardening it with picking a specific interface. + ### option: Android.launchServer.port * since: v1.28 - `port` <[int]> diff --git a/docs/src/api/class-browserserver.md b/docs/src/api/class-browserserver.md index 21f318a70abcb..0de5c1228bd11 100644 --- a/docs/src/api/class-browserserver.md +++ b/docs/src/api/class-browserserver.md @@ -31,3 +31,5 @@ Browser websocket url. Browser websocket endpoint which can be used as an argument to [`method: BrowserType.connect`] to establish connection to the browser. + +Note that if the listen `host` option in `launchServer` options is not specified, localhost will be output anyway, even if the actual listening address is an unspecified address. diff --git a/docs/src/api/class-browsertype.md b/docs/src/api/class-browsertype.md index 6a776f1cee997..176f696e1d5c8 100644 --- a/docs/src/api/class-browsertype.md +++ b/docs/src/api/class-browsertype.md @@ -380,6 +380,12 @@ const { chromium } = require('playwright'); // Or 'webkit' or 'firefox'. ### option: BrowserType.launchServer.logger = %%-browser-option-logger-%% * since: v1.8 +### option: BrowserType.launchServer.host +* since: v1.45 +- `host` <[string]> + +Host to use for the web socket. It is optional and if it is omitted, the server will accept connections on the unspecified IPv6 address (::) when IPv6 is available, or the unspecified IPv4 address (0.0.0.0) otherwise. Consider hardening it with picking a specific interface. + ### option: BrowserType.launchServer.port * since: v1.8 - `port` <[int]> diff --git a/packages/playwright-core/src/androidServerImpl.ts b/packages/playwright-core/src/androidServerImpl.ts index 4c3685076e8aa..a0d7bb5496b01 100644 --- a/packages/playwright-core/src/androidServerImpl.ts +++ b/packages/playwright-core/src/androidServerImpl.ts @@ -50,7 +50,7 @@ export class AndroidServerLauncherImpl { // 2. Start the server const server = new PlaywrightServer({ mode: 'launchServer', path, maxConnections: 1, preLaunchedAndroidDevice: device }); - const wsEndpoint = await server.listen(options.port); + const wsEndpoint = await server.listen(options.port, options.host); // 3. Return the BrowserServer interface const browserServer = new ws.EventEmitter() as (BrowserServer & WebSocketEventEmitter); diff --git a/packages/playwright-core/src/browserServerImpl.ts b/packages/playwright-core/src/browserServerImpl.ts index 41f9c2c2e47e3..dfe960c5eaad7 100644 --- a/packages/playwright-core/src/browserServerImpl.ts +++ b/packages/playwright-core/src/browserServerImpl.ts @@ -58,7 +58,7 @@ export class BrowserServerLauncherImpl implements BrowserServerLauncher { // 2. Start the server const server = new PlaywrightServer({ mode: 'launchServer', path, maxConnections: Infinity, preLaunchedBrowser: browser, preLaunchedSocksProxy: socksProxy }); - const wsEndpoint = await server.listen(options.port); + const wsEndpoint = await server.listen(options.port, options.host); // 3. Return the BrowserServer interface const browserServer = new ws.EventEmitter() as (BrowserServer & WebSocketEventEmitter); diff --git a/packages/playwright-core/src/client/types.ts b/packages/playwright-core/src/client/types.ts index 2fc2cea0d1873..e649a21303b2a 100644 --- a/packages/playwright-core/src/client/types.ts +++ b/packages/playwright-core/src/client/types.ts @@ -111,6 +111,7 @@ export type LaunchServerOptions = { }, downloadsPath?: string, chromiumSandbox?: boolean, + host?: string, port?: number, wsPath?: string, logger?: Logger, @@ -122,6 +123,7 @@ export type LaunchAndroidServerOptions = { adbHost?: string, adbPort?: number, omitDriverInstall?: boolean, + host?: string, port?: number, wsPath?: string, }; diff --git a/packages/playwright-core/types/types.d.ts b/packages/playwright-core/types/types.d.ts index fa24e066b67c0..54d79f9ca1d44 100644 --- a/packages/playwright-core/types/types.d.ts +++ b/packages/playwright-core/types/types.d.ts @@ -13745,6 +13745,13 @@ export interface BrowserType { */ headless?: boolean; + /** + * Host to use for the web socket. It is optional and if it is omitted, the server will accept connections on the + * unspecified IPv6 address (::) when IPv6 is available, or the unspecified IPv4 address (0.0.0.0) otherwise. Consider + * hardening it with picking a specific interface. + */ + host?: string; + /** * If `true`, Playwright does not pass its own configurations args and only uses the ones from `args`. If an array is * given, then filters out the given default arguments. Dangerous option; use with care. Defaults to `false`. @@ -14621,6 +14628,13 @@ export interface Android { */ deviceSerialNumber?: string; + /** + * Host to use for the web socket. It is optional and if it is omitted, the server will accept connections on the + * unspecified IPv6 address (::) when IPv6 is available, or the unspecified IPv4 address (0.0.0.0) otherwise. Consider + * hardening it with picking a specific interface. + */ + host?: string; + /** * Prevents automatic playwright driver installation on attach. Assumes that the drivers have been installed already. */ @@ -17201,6 +17215,9 @@ export interface BrowserServer { * Browser websocket endpoint which can be used as an argument to * [browserType.connect(wsEndpoint[, options])](https://playwright.dev/docs/api/class-browsertype#browser-type-connect) * to establish connection to the browser. + * + * Note that if the listen `host` option in `launchServer` options is not specified, localhost will be output anyway, + * even if the actual listening address is an unspecified address. */ wsEndpoint(): string; diff --git a/tests/android/launch-server.spec.ts b/tests/android/launch-server.spec.ts index c90a25b0a0364..80c9760f2ea00 100644 --- a/tests/android/launch-server.spec.ts +++ b/tests/android/launch-server.spec.ts @@ -30,6 +30,17 @@ test('android.launchServer should connect to a device', async ({ playwright }) = await browserServer.close(); }); +test('android.launchServer should work with host', async ({ playwright }) => { + const host = '0.0.0.0'; + const browserServer = await playwright._android.launchServer({ host }); + expect(browserServer.wsEndpoint()).toContain(String(host)); + const device = await playwright._android.connect(browserServer.wsEndpoint()); + const output = await device.shell('echo 123'); + expect(output.toString()).toBe('123\n'); + await device.close(); + await browserServer.close(); +}); + test('android.launchServer should handle close event correctly', async ({ playwright }) => { const receivedEvents: string[] = []; const browserServer = await playwright._android.launchServer(); diff --git a/tests/library/browsertype-launch-server.spec.ts b/tests/library/browsertype-launch-server.spec.ts index dcb69d614b0b0..f56d9d500e4d1 100644 --- a/tests/library/browsertype-launch-server.spec.ts +++ b/tests/library/browsertype-launch-server.spec.ts @@ -26,6 +26,13 @@ it.describe('launch server', () => { await browserServer.close(); }); + it('should work with host', async ({ browserType }) => { + const host = '0.0.0.0'; + const browserServer = await browserType.launchServer({ host }); + expect(browserServer.wsEndpoint()).toContain(String(host)); + await browserServer.close(); + }); + it('should work with port', async ({ browserType }, testInfo) => { const port = 8800 + testInfo.workerIndex; const browserServer = await browserType.launchServer({ port });