From 71798d658f46074cf2d63cafe347526b88d7b31e Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Sat, 21 Jan 2023 18:18:22 -0800 Subject: [PATCH] chore: remove separate network tethering client connection (#20267) --- .../bin/container_run_server.sh | 2 +- .../playwright-core/src/androidServerImpl.ts | 2 +- .../playwright-core/src/browserServerImpl.ts | 2 +- packages/playwright-core/src/cli/cli.ts | 3 -- packages/playwright-core/src/cli/driver.ts | 4 +- .../playwright-core/src/containers/docker.ts | 1 - .../src/remote/playwrightConnection.ts | 46 ++++--------------- .../src/remote/playwrightServer.ts | 39 ++-------------- 8 files changed, 18 insertions(+), 81 deletions(-) diff --git a/packages/playwright-core/bin/container_run_server.sh b/packages/playwright-core/bin/container_run_server.sh index f6f4a2afe5..bfdf3666ab 100755 --- a/packages/playwright-core/bin/container_run_server.sh +++ b/packages/playwright-core/bin/container_run_server.sh @@ -38,7 +38,7 @@ PW_UUID=$(cat /proc/sys/kernel/random/uuid) # Make sure to re-start playwright server if something goes wrong. # The approach taken from: https://stackoverflow.com/a/697064/314883 -until npx playwright run-server --port=5200 --path=/$PW_UUID --proxy-mode=tether; do +until npx playwright run-server --port=5200 --path=/$PW_UUID; do echo "Server crashed with exit code $?. Respawning.." >&2 sleep 1 done diff --git a/packages/playwright-core/src/androidServerImpl.ts b/packages/playwright-core/src/androidServerImpl.ts index a5c581d044..9e89d7c83a 100644 --- a/packages/playwright-core/src/androidServerImpl.ts +++ b/packages/playwright-core/src/androidServerImpl.ts @@ -49,7 +49,7 @@ export class AndroidServerLauncherImpl { const path = options.wsPath ? (options.wsPath.startsWith('/') ? options.wsPath : `/${options.wsPath}`) : `/${createGuid()}`; // 2. Start the server - const server = new PlaywrightServer({ path, maxConnections: 1, preLaunchedAndroidDevice: device, browserProxyMode: 'client' }); + const server = new PlaywrightServer({ path, maxConnections: 1, preLaunchedAndroidDevice: device }); const wsEndpoint = await server.listen(options.port); // 3. Return the BrowserServer interface diff --git a/packages/playwright-core/src/browserServerImpl.ts b/packages/playwright-core/src/browserServerImpl.ts index 5f2d9a2bb7..0d6ae54702 100644 --- a/packages/playwright-core/src/browserServerImpl.ts +++ b/packages/playwright-core/src/browserServerImpl.ts @@ -57,7 +57,7 @@ export class BrowserServerLauncherImpl implements BrowserServerLauncher { const path = options.wsPath ? (options.wsPath.startsWith('/') ? options.wsPath : `/${options.wsPath}`) : `/${createGuid()}`; // 2. Start the server - const server = new PlaywrightServer({ path, maxConnections: Infinity, browserProxyMode: 'client', preLaunchedBrowser: browser, preLaunchedSocksProxy: socksProxy }); + const server = new PlaywrightServer({ path, maxConnections: Infinity, preLaunchedBrowser: browser, preLaunchedSocksProxy: socksProxy }); const wsEndpoint = await server.listen(options.port); // 3. Return the BrowserServer interface diff --git a/packages/playwright-core/src/cli/cli.ts b/packages/playwright-core/src/cli/cli.ts index 19d692220d..bf59bfa569 100755 --- a/packages/playwright-core/src/cli/cli.ts +++ b/packages/playwright-core/src/cli/cli.ts @@ -270,14 +270,11 @@ program .option('--port ', 'Server port') .option('--path ', 'Endpoint Path', '/') .option('--max-clients ', 'Maximum clients') - .option('--proxy-mode ', 'Either `client` or `tether`. Defaults to `client`.', 'client') .action(function(options) { runServer({ port: options.port ? +options.port : undefined, path: options.path, maxConnections: options.maxClients ? +options.maxClients : Infinity, - browserProxyMode: options.proxyMode, - ownedByTetherClient: !!process.env.PW_OWNED_BY_TETHER_CLIENT, }).catch(logErrorAndExit); }); diff --git a/packages/playwright-core/src/cli/driver.ts b/packages/playwright-core/src/cli/driver.ts index d5b976c625..7e9d9e4f86 100644 --- a/packages/playwright-core/src/cli/driver.ts +++ b/packages/playwright-core/src/cli/driver.ts @@ -59,10 +59,8 @@ export async function runServer(options: RunServerOptions) { port, path = '/', maxConnections = Infinity, - browserProxyMode = 'client', - ownedByTetherClient = false, } = options; - const server = new PlaywrightServer({ path, maxConnections, browserProxyMode, ownedByTetherClient }); + const server = new PlaywrightServer({ path, maxConnections }); const wsEndpoint = await server.listen(port); process.on('exit', () => server.close().catch(console.error)); console.log('Listening on ' + wsEndpoint); // eslint-disable-line no-console diff --git a/packages/playwright-core/src/containers/docker.ts b/packages/playwright-core/src/containers/docker.ts index 920909d62a..1e0d9a4c24 100644 --- a/packages/playwright-core/src/containers/docker.ts +++ b/packages/playwright-core/src/containers/docker.ts @@ -223,7 +223,6 @@ export async function ensurePlaywrightContainerOrDie(port: number): Promise = { - PW_OWNED_BY_TETHER_CLIENT: '1', DEBUG: process.env.DEBUG, }; for (const [key, value] of Object.entries(process.env)) { diff --git a/packages/playwright-core/src/remote/playwrightConnection.ts b/packages/playwright-core/src/remote/playwrightConnection.ts index d3b8f1762a..c575d4006a 100644 --- a/packages/playwright-core/src/remote/playwrightConnection.ts +++ b/packages/playwright-core/src/remote/playwrightConnection.ts @@ -25,7 +25,7 @@ import type { LaunchOptions } from '../server/types'; import { AndroidDevice } from '../server/android/android'; import { DebugControllerDispatcher } from '../server/dispatchers/debugControllerDispatcher'; -export type ClientType = 'controller' | 'playwright' | 'launch-browser' | 'reuse-browser' | 'pre-launched-browser-or-android' | 'network-tethering'; +export type ClientType = 'controller' | 'playwright' | 'launch-browser' | 'reuse-browser' | 'pre-launched-browser-or-android'; type Options = { socksProxyPattern: string | undefined, @@ -37,8 +37,7 @@ type PreLaunched = { playwright?: Playwright | undefined; browser?: Browser | undefined; androidDevice?: AndroidDevice | undefined; - ownedSocksProxy?: SocksProxy | undefined; - sharedSocksProxy?: SocksProxy | undefined; + socksProxy?: SocksProxy | undefined; }; export class PlaywrightConnection { @@ -91,20 +90,10 @@ export class PlaywrightConnection { return await this._initLaunchBrowserMode(scope); if (clientType === 'playwright') return await this._initPlaywrightConnectMode(scope); - if (clientType === 'network-tethering') - return await this._initPlaywrightTetheringMode(scope); throw new Error('Unsupported client type: ' + clientType); }); } - private async _initPlaywrightTetheringMode(scope: RootDispatcher) { - this._debugLog(`engaged playwright.tethering mode`); - const playwright = createPlaywright('javascript'); - this._preLaunched.sharedSocksProxy?.setPattern(this._options.socksProxyPattern); - // Tethering client owns the shared socks proxy. - return new PlaywrightDispatcher(scope, playwright, this._preLaunched.sharedSocksProxy); - } - private async _initPlaywrightConnectMode(scope: RootDispatcher) { this._debugLog(`engaged playwright.connect mode`); const playwright = createPlaywright('javascript'); @@ -113,14 +102,7 @@ export class PlaywrightConnection { await Promise.all(playwright.allBrowsers().map(browser => browser.close())); }); - let ownedSocksProxy: SocksProxy | undefined; - if (this._preLaunched.sharedSocksProxy) { - // Note: tethering client configures the pattern, and connected client's pattern is ignored. - playwright.options.socksProxyPort = this._preLaunched.sharedSocksProxy.port(); - this._debugLog(`using shared socks proxy on port ${playwright.options.socksProxyPort}`); - } else { - ownedSocksProxy = await this._createOwnedSocksProxy(playwright); - } + const ownedSocksProxy = await this._createOwnedSocksProxy(playwright); return new PlaywrightDispatcher(scope, playwright, ownedSocksProxy); } @@ -128,15 +110,7 @@ export class PlaywrightConnection { this._debugLog(`engaged launch mode for "${this._options.browserName}"`); const playwright = createPlaywright('javascript'); - let ownedSocksProxy: SocksProxy | undefined; - if (this._preLaunched.sharedSocksProxy) { - // Note: tethering client configures the pattern, and connected client's pattern is ignored. - playwright.options.socksProxyPort = this._preLaunched.sharedSocksProxy.port(); - this._debugLog(`using shared socks proxy on port ${playwright.options.socksProxyPort}`); - } else { - ownedSocksProxy = await this._createOwnedSocksProxy(playwright); - } - + const ownedSocksProxy = await this._createOwnedSocksProxy(playwright); const browser = await playwright[this._options.browserName as 'chromium'].launch(serverSideCallMetadata(), this._options.launchOptions); this._cleanups.push(async () => { @@ -156,8 +130,7 @@ export class PlaywrightConnection { const playwright = this._preLaunched.playwright!; // Note: connected client owns the socks proxy and configures the pattern. - playwright.options.socksProxyPort = this._preLaunched.ownedSocksProxy?.port(); - this._preLaunched.ownedSocksProxy?.setPattern(this._options.socksProxyPattern); + this._preLaunched.socksProxy?.setPattern(this._options.socksProxyPattern); const browser = this._preLaunched.browser!; browser.on(Browser.Events.Disconnected, () => { @@ -165,7 +138,7 @@ export class PlaywrightConnection { this.close({ code: 1001, reason: 'Browser closed' }); }); - const playwrightDispatcher = new PlaywrightDispatcher(scope, playwright, this._preLaunched.ownedSocksProxy, browser); + const playwrightDispatcher = new PlaywrightDispatcher(scope, playwright, this._preLaunched.socksProxy, browser); // In pre-launched mode, keep only the pre-launched browser. for (const b of playwright.allBrowsers()) { if (b !== browser) @@ -196,13 +169,12 @@ export class PlaywrightConnection { } private async _initReuseBrowsersMode(scope: RootDispatcher) { + // Note: reuse browser mode does not support socks proxy, because + // clients come and go, while the browser stays the same. + this._debugLog(`engaged reuse browsers mode for ${this._options.browserName}`); const playwright = this._preLaunched.playwright!; - // Note: connected client owns the socks proxy and configures the pattern. - playwright.options.socksProxyPort = this._preLaunched.sharedSocksProxy?.port(); - this._debugLog(`using shared socks proxy on port ${playwright.options.socksProxyPort}`); - const requestedOptions = launchOptionsHash(this._options.launchOptions); let browser = playwright.allBrowsers().find(b => { if (b.options.name !== this._options.browserName) diff --git a/packages/playwright-core/src/remote/playwrightServer.ts b/packages/playwright-core/src/remote/playwrightServer.ts index 3af284a4e6..dd8f07e92c 100644 --- a/packages/playwright-core/src/remote/playwrightServer.ts +++ b/packages/playwright-core/src/remote/playwrightServer.ts @@ -25,7 +25,7 @@ import type { ClientType } from './playwrightConnection'; import type { LaunchOptions } from '../server/types'; import { ManualPromise } from '../utils/manualPromise'; import type { AndroidDevice } from '../server/android/android'; -import { SocksProxy } from '../common/socksProxy'; +import { type SocksProxy } from '../common/socksProxy'; const debugLog = debug('pw:server'); @@ -43,16 +43,12 @@ type ServerOptions = { preLaunchedBrowser?: Browser; preLaunchedAndroidDevice?: AndroidDevice; preLaunchedSocksProxy?: SocksProxy; - browserProxyMode: 'client' | 'tether'; - ownedByTetherClient?: boolean; }; export class PlaywrightServer { private _preLaunchedPlaywright: Playwright | undefined; private _wsServer: WebSocketServer | undefined; - private _networkTetheringSocksProxy: SocksProxy | undefined; private _options: ServerOptions; - private _networkTetheringClientTimeout: NodeJS.Timeout | undefined; constructor(options: ServerOptions) { this._options = options; @@ -86,24 +82,12 @@ export class PlaywrightServer { resolve(wsEndpoint); }).on('error', reject); }); - if (this._options.browserProxyMode === 'tether') { - this._networkTetheringSocksProxy = new SocksProxy(); - await this._networkTetheringSocksProxy.listen(0); - debugLog('Launched tethering proxy at ' + this._networkTetheringSocksProxy.port()); - } debugLog('Listening at ' + wsEndpoint); - if (this._options.ownedByTetherClient) { - this._networkTetheringClientTimeout = setTimeout(() => { - this.close(); - }, 30_000); - } - this._wsServer = new wsServer({ server, path: this._options.path }); const browserSemaphore = new Semaphore(this._options.maxConnections); const controllerSemaphore = new Semaphore(1); const reuseBrowserSemaphore = new Semaphore(1); - const networkTetheringSemaphore = new Semaphore(1); this._wsServer.on('connection', (ws, request) => { const url = new URL('http://localhost' + (request.url || '')); const browserHeader = request.headers['x-playwright-browser']; @@ -121,11 +105,10 @@ export class PlaywrightServer { const log = newLogger(); log(`serving connection: ${request.url}`); const isDebugControllerClient = !!request.headers['x-playwright-debug-controller']; - const isNetworkTetheringClient = !!request.headers['x-playwright-network-tethering']; const shouldReuseBrowser = !!request.headers['x-playwright-reuse-context']; // If we started in the legacy reuse-browser mode, create this._preLaunchedPlaywright. - // If we get a reuse-controller request, create this._preLaunchedPlaywright. + // If we get a debug-controller request, create this._preLaunchedPlaywright. if (isDebugControllerClient || shouldReuseBrowser) { if (!this._preLaunchedPlaywright) this._preLaunchedPlaywright = createPlaywright('javascript'); @@ -133,10 +116,7 @@ export class PlaywrightServer { let clientType: ClientType = 'playwright'; let semaphore: Semaphore = browserSemaphore; - if (isNetworkTetheringClient) { - clientType = 'network-tethering'; - semaphore = networkTetheringSemaphore; - } else if (isDebugControllerClient) { + if (isDebugControllerClient) { clientType = 'controller'; semaphore = controllerSemaphore; } else if (shouldReuseBrowser) { @@ -150,9 +130,6 @@ export class PlaywrightServer { semaphore = browserSemaphore; } - if (clientType === 'network-tethering' && this._options.ownedByTetherClient) - clearTimeout(this._networkTetheringClientTimeout); - const connection = new PlaywrightConnection( semaphore.aquire(), clientType, ws, @@ -161,14 +138,9 @@ export class PlaywrightServer { playwright: this._preLaunchedPlaywright, browser: this._options.preLaunchedBrowser, androidDevice: this._options.preLaunchedAndroidDevice, - ownedSocksProxy: this._options.preLaunchedSocksProxy, - sharedSocksProxy: this._networkTetheringSocksProxy, + socksProxy: this._options.preLaunchedSocksProxy, }, - log, () => { - semaphore.release(); - if (this._options.ownedByTetherClient && clientType === 'network-tethering') - this.close(); - }); + log, () => semaphore.release()); (ws as any)[kConnectionSymbol] = connection; }); @@ -179,7 +151,6 @@ export class PlaywrightServer { const server = this._wsServer; if (!server) return; - await this._networkTetheringSocksProxy?.close(); debugLog('closing websocket server'); const waitForClose = new Promise(f => server.close(f)); // First disconnect all remaining clients.