diff --git a/docs/src/api/class-android.md b/docs/src/api/class-android.md index c889ee5d0b..c976c9bba8 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 21f318a70a..0de5c1228b 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 6a776f1cee..176f696e1d 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 4c3685076e..a0d7bb5496 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 41f9c2c2e4..dfe960c5ea 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 2fc2cea0d1..e649a21303 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 fa24e066b6..54d79f9ca1 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 c90a25b0a0..80c9760f2e 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 dcb69d614b..f56d9d500e 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 });