mirror of
https://github.com/microsoft/playwright.git
synced 2025-01-07 11:46:42 +03:00
feat(remote): let client enable/disable sock proxy (#12086)
This commit is contained in:
parent
e9ca11d91b
commit
5a0445b8da
@ -53,7 +53,7 @@ export class BrowserServerLauncherImpl implements BrowserServerLauncher {
|
|||||||
path = options.wsPath.startsWith('/') ? options.wsPath : `/${options.wsPath}`;
|
path = options.wsPath.startsWith('/') ? options.wsPath : `/${options.wsPath}`;
|
||||||
|
|
||||||
// 2. Start the server
|
// 2. Start the server
|
||||||
const server = new PlaywrightServer(path, Infinity, browser);
|
const server = new PlaywrightServer(path, Infinity, false, browser);
|
||||||
const wsEndpoint = await server.listen(options.port);
|
const wsEndpoint = await server.listen(options.port);
|
||||||
|
|
||||||
// 3. Return the BrowserServer interface
|
// 3. Return the BrowserServer interface
|
||||||
|
@ -129,10 +129,8 @@ export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel> imple
|
|||||||
const deadline = params.timeout ? monotonicTime() + params.timeout : 0;
|
const deadline = params.timeout ? monotonicTime() + params.timeout : 0;
|
||||||
let browser: Browser;
|
let browser: Browser;
|
||||||
const connectParams: channels.BrowserTypeConnectParams = { wsEndpoint, headers: params.headers, slowMo: params.slowMo, timeout: params.timeout };
|
const connectParams: channels.BrowserTypeConnectParams = { wsEndpoint, headers: params.headers, slowMo: params.slowMo, timeout: params.timeout };
|
||||||
if ((params as any).__testHookPortForwarding) {
|
if ((params as any).__testHookRedirectPortForwarding)
|
||||||
connectParams.enableSocksProxy = true;
|
connectParams.socksProxyRedirectPortForTest = (params as any).__testHookRedirectPortForwarding;
|
||||||
connectParams.socksProxyRedirectPortForTest = (params as any).__testHookPortForwarding.redirectPortForTest;
|
|
||||||
}
|
|
||||||
const { pipe } = await this._channel.connect(connectParams);
|
const { pipe } = await this._channel.connect(connectParams);
|
||||||
const closePipe = () => pipe.close().catch(() => {});
|
const closePipe = () => pipe.close().catch(() => {});
|
||||||
const connection = new Connection();
|
const connection = new Connection();
|
||||||
|
@ -93,7 +93,7 @@ export class BrowserTypeDispatcher extends Dispatcher<BrowserType, channels.Brow
|
|||||||
waitForNextTask(() => {
|
waitForNextTask(() => {
|
||||||
try {
|
try {
|
||||||
const json = JSON.parse(event.data as string);
|
const json = JSON.parse(event.data as string);
|
||||||
if (params.enableSocksProxy && json.method === '__create__' && json.params.type === 'SocksSupport')
|
if (json.method === '__create__' && json.params.type === 'SocksSupport')
|
||||||
socksInterceptor = new SocksInterceptor(ws, params.socksProxyRedirectPortForTest, json.params.guid);
|
socksInterceptor = new SocksInterceptor(ws, params.socksProxyRedirectPortForTest, json.params.guid);
|
||||||
if (!socksInterceptor?.interceptMessage(json))
|
if (!socksInterceptor?.interceptMessage(json))
|
||||||
pipe.dispatch(json);
|
pipe.dispatch(json);
|
||||||
|
@ -603,14 +603,12 @@ export type BrowserTypeConnectParams = {
|
|||||||
headers?: any,
|
headers?: any,
|
||||||
slowMo?: number,
|
slowMo?: number,
|
||||||
timeout?: number,
|
timeout?: number,
|
||||||
enableSocksProxy?: boolean,
|
|
||||||
socksProxyRedirectPortForTest?: number,
|
socksProxyRedirectPortForTest?: number,
|
||||||
};
|
};
|
||||||
export type BrowserTypeConnectOptions = {
|
export type BrowserTypeConnectOptions = {
|
||||||
headers?: any,
|
headers?: any,
|
||||||
slowMo?: number,
|
slowMo?: number,
|
||||||
timeout?: number,
|
timeout?: number,
|
||||||
enableSocksProxy?: boolean,
|
|
||||||
socksProxyRedirectPortForTest?: number,
|
socksProxyRedirectPortForTest?: number,
|
||||||
};
|
};
|
||||||
export type BrowserTypeConnectResult = {
|
export type BrowserTypeConnectResult = {
|
||||||
|
@ -596,7 +596,6 @@ BrowserType:
|
|||||||
headers: json?
|
headers: json?
|
||||||
slowMo: number?
|
slowMo: number?
|
||||||
timeout: number?
|
timeout: number?
|
||||||
enableSocksProxy: boolean?
|
|
||||||
socksProxyRedirectPortForTest: number?
|
socksProxyRedirectPortForTest: number?
|
||||||
returns:
|
returns:
|
||||||
pipe: JsonPipe
|
pipe: JsonPipe
|
||||||
|
@ -249,7 +249,6 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
|
|||||||
headers: tOptional(tAny),
|
headers: tOptional(tAny),
|
||||||
slowMo: tOptional(tNumber),
|
slowMo: tOptional(tNumber),
|
||||||
timeout: tOptional(tNumber),
|
timeout: tOptional(tNumber),
|
||||||
enableSocksProxy: tOptional(tBoolean),
|
|
||||||
socksProxyRedirectPortForTest: tOptional(tNumber),
|
socksProxyRedirectPortForTest: tOptional(tNumber),
|
||||||
});
|
});
|
||||||
scheme.BrowserTypeLaunchParams = tObject({
|
scheme.BrowserTypeLaunchParams = tObject({
|
||||||
|
@ -31,18 +31,20 @@ const debugLog = debug('pw:server');
|
|||||||
export class PlaywrightServer {
|
export class PlaywrightServer {
|
||||||
private _path: string;
|
private _path: string;
|
||||||
private _maxClients: number;
|
private _maxClients: number;
|
||||||
|
private _enableSocksProxy: boolean;
|
||||||
private _browser: Browser | undefined;
|
private _browser: Browser | undefined;
|
||||||
private _wsServer: WebSocket.Server | undefined;
|
private _wsServer: WebSocket.Server | undefined;
|
||||||
private _clientsCount = 0;
|
private _clientsCount = 0;
|
||||||
|
|
||||||
static async startDefault(options: { path?: string, maxClients?: number } = {}): Promise<PlaywrightServer> {
|
static async startDefault(options: { path?: string, maxClients?: number, enableSocksProxy?: boolean } = {}): Promise<PlaywrightServer> {
|
||||||
const { path = '/ws', maxClients = 1 } = options;
|
const { path = '/ws', maxClients = 1, enableSocksProxy = true } = options;
|
||||||
return new PlaywrightServer(path, maxClients);
|
return new PlaywrightServer(path, maxClients, enableSocksProxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(path: string, maxClients: number, browser?: Browser) {
|
constructor(path: string, maxClients: number, enableSocksProxy: boolean, browser?: Browser) {
|
||||||
this._path = path;
|
this._path = path;
|
||||||
this._maxClients = maxClients;
|
this._maxClients = maxClients;
|
||||||
|
this._enableSocksProxy = enableSocksProxy;
|
||||||
this._browser = browser;
|
this._browser = browser;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +77,7 @@ export class PlaywrightServer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._clientsCount++;
|
this._clientsCount++;
|
||||||
const connection = new Connection(ws, request, this._browser, () => this._clientsCount--);
|
const connection = new Connection(ws, request, this._enableSocksProxy, this._browser, () => this._clientsCount--);
|
||||||
(ws as any)[kConnectionSymbol] = connection;
|
(ws as any)[kConnectionSymbol] = connection;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -117,7 +119,7 @@ class Connection {
|
|||||||
private _id: number;
|
private _id: number;
|
||||||
private _disconnected = false;
|
private _disconnected = false;
|
||||||
|
|
||||||
constructor(ws: WebSocket, request: http.IncomingMessage, browser: Browser | undefined, onClose: () => void) {
|
constructor(ws: WebSocket, request: http.IncomingMessage, enableSocksProxy: boolean, browser: Browser | undefined, onClose: () => void) {
|
||||||
this._ws = ws;
|
this._ws = ws;
|
||||||
this._onClose = onClose;
|
this._onClose = onClose;
|
||||||
this._id = ++lastConnectionId;
|
this._id = ++lastConnectionId;
|
||||||
@ -139,32 +141,34 @@ class Connection {
|
|||||||
if (browser)
|
if (browser)
|
||||||
return await this._initPreLaunchedBrowserMode(scope, browser);
|
return await this._initPreLaunchedBrowserMode(scope, browser);
|
||||||
const url = new URL('http://localhost' + (request.url || ''));
|
const url = new URL('http://localhost' + (request.url || ''));
|
||||||
const header = request.headers['X-Playwright-Browser'];
|
const browserHeader = request.headers['X-Playwright-Browser'];
|
||||||
const browserAlias = url.searchParams.get('browser') || (Array.isArray(header) ? header[0] : header);
|
const browserAlias = url.searchParams.get('browser') || (Array.isArray(browserHeader) ? browserHeader[0] : browserHeader);
|
||||||
|
const proxyHeader = request.headers['X-Playwright-Proxy'];
|
||||||
|
const proxyValue = url.searchParams.get('proxy') || (Array.isArray(proxyHeader) ? proxyHeader[0] : proxyHeader);
|
||||||
if (!browserAlias)
|
if (!browserAlias)
|
||||||
return await this._initPlaywrightConnectMode(scope);
|
return await this._initPlaywrightConnectMode(scope, enableSocksProxy && proxyValue === '*');
|
||||||
return await this._initLaunchBrowserMode(scope, browserAlias);
|
return await this._initLaunchBrowserMode(scope, enableSocksProxy && proxyValue === '*', browserAlias);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _initPlaywrightConnectMode(scope: DispatcherScope) {
|
private async _initPlaywrightConnectMode(scope: DispatcherScope, enableSocksProxy: boolean) {
|
||||||
debugLog(`[id=${this._id}] engaged playwright.connect mode`);
|
debugLog(`[id=${this._id}] engaged playwright.connect mode`);
|
||||||
const playwright = createPlaywright('javascript');
|
const playwright = createPlaywright('javascript');
|
||||||
// Close all launched browsers on disconnect.
|
// Close all launched browsers on disconnect.
|
||||||
this._cleanups.push(() => gracefullyCloseAll());
|
this._cleanups.push(() => gracefullyCloseAll());
|
||||||
|
|
||||||
const socksProxy = await this._enableSocksProxyIfNeeded(playwright);
|
const socksProxy = enableSocksProxy ? await this._enableSocksProxy(playwright) : undefined;
|
||||||
return new PlaywrightDispatcher(scope, playwright, socksProxy);
|
return new PlaywrightDispatcher(scope, playwright, socksProxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _initLaunchBrowserMode(scope: DispatcherScope, browserAlias: string) {
|
private async _initLaunchBrowserMode(scope: DispatcherScope, enableSocksProxy: boolean, browserAlias: string) {
|
||||||
debugLog(`[id=${this._id}] engaged launch mode for "${browserAlias}"`);
|
debugLog(`[id=${this._id}] engaged launch mode for "${browserAlias}"`);
|
||||||
const executable = registry.findExecutable(browserAlias);
|
const executable = registry.findExecutable(browserAlias);
|
||||||
if (!executable || !executable.browserName)
|
if (!executable || !executable.browserName)
|
||||||
throw new Error(`Unsupported browser "${browserAlias}`);
|
throw new Error(`Unsupported browser "${browserAlias}`);
|
||||||
|
|
||||||
const playwright = createPlaywright('javascript');
|
const playwright = createPlaywright('javascript');
|
||||||
const socksProxy = await this._enableSocksProxyIfNeeded(playwright);
|
const socksProxy = enableSocksProxy ? await this._enableSocksProxy(playwright) : undefined;
|
||||||
const browser = await playwright[executable.browserName].launch(internalCallMetadata(), {
|
const browser = await playwright[executable.browserName].launch(internalCallMetadata(), {
|
||||||
channel: executable.type === 'browser' ? undefined : executable.name,
|
channel: executable.type === 'browser' ? undefined : executable.name,
|
||||||
});
|
});
|
||||||
@ -194,9 +198,7 @@ class Connection {
|
|||||||
return playwrightDispatcher;
|
return playwrightDispatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _enableSocksProxyIfNeeded(playwright: Playwright) {
|
private async _enableSocksProxy(playwright: Playwright) {
|
||||||
if (!process.env.PW_SOCKS_PROXY_PORT)
|
|
||||||
return;
|
|
||||||
const socksProxy = new SocksProxy();
|
const socksProxy = new SocksProxy();
|
||||||
playwright.options.socksProxyPort = await socksProxy.listen(0);
|
playwright.options.socksProxyPort = await socksProxy.listen(0);
|
||||||
debugLog(`[id=${this._id}] started socks proxy on port ${playwright.options.socksProxyPort}`);
|
debugLog(`[id=${this._id}] started socks proxy on port ${playwright.options.socksProxyPort}`);
|
||||||
|
@ -67,8 +67,8 @@ const it = contextTest.extend<{ pageFactory: (redirectPortForTest?: number) => P
|
|||||||
const server = new OutOfProcessPlaywrightServer(0, 3200 + testInfo.workerIndex);
|
const server = new OutOfProcessPlaywrightServer(0, 3200 + testInfo.workerIndex);
|
||||||
playwrightServers.push(server);
|
playwrightServers.push(server);
|
||||||
const browser = await browserType.connect({
|
const browser = await browserType.connect({
|
||||||
wsEndpoint: await server.wsEndpoint() + '?browser=' + (channel || browserName),
|
wsEndpoint: await server.wsEndpoint() + '?proxy=*&browser=' + (channel || browserName),
|
||||||
__testHookPortForwarding: { redirectPortForTest },
|
__testHookRedirectPortForwarding: redirectPortForTest,
|
||||||
} as any);
|
} as any);
|
||||||
browsers.push(browser);
|
browsers.push(browser);
|
||||||
return await browser.newPage();
|
return await browser.newPage();
|
||||||
|
Loading…
Reference in New Issue
Block a user