feat(proxy): bind proxy to open port (#8331)

This commit is contained in:
Pavel Feldman 2021-08-19 18:08:55 -07:00 committed by GitHub
parent 70eca0401d
commit 80dded6ccf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 35 additions and 25 deletions

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import net from 'net';
import net, { AddressInfo } from 'net';
import * as channels from '../protocol/channels';
import { Playwright } from '../server/playwright';
import { AndroidDispatcher } from './androidDispatcher';
@ -25,6 +25,7 @@ import { SelectorsDispatcher } from './selectorsDispatcher';
import * as types from '../server/types';
import { SocksConnection, SocksConnectionClient } from '../utils/socksProxy';
import { createGuid } from '../utils/utils';
import { debugLogger } from '../utils/debugLogger';
export class PlaywrightDispatcher extends Dispatcher<Playwright, channels.PlaywrightInitializer> implements channels.PlaywrightChannel {
private _socksProxy: SocksProxy | undefined;
@ -45,9 +46,10 @@ export class PlaywrightDispatcher extends Dispatcher<Playwright, channels.Playwr
}, false);
}
enableSocksProxy(port: number) {
async enableSocksProxy() {
this._socksProxy = new SocksProxy(this);
this._socksProxy.listen(port);
this._object.options.socksProxyPort = await this._socksProxy.listen(0);
debugLogger.log('proxy', `Starting socks proxy server on port ${this._object.options.socksProxyPort}`);
}
async socksConnected(params: channels.PlaywrightSocksConnectedParams, metadata?: channels.Metadata): Promise<void> {
@ -85,8 +87,12 @@ class SocksProxy implements SocksConnectionClient {
});
}
listen(port: number) {
this._server.listen(port);
async listen(port: number): Promise<number> {
return new Promise(f => {
this._server.listen(port, () => {
f((this._server.address() as AddressInfo).port);
});
});
}
onSocketRequested(uid: string, host: string, port: number): void {

View File

@ -50,7 +50,7 @@ export class PlaywrightServer {
playwright = createPlaywright();
const dispatcher = new PlaywrightDispatcher(rootScope, playwright);
if (process.env.PW_SOCKS_PROXY_PORT)
dispatcher.enableSocksProxy(+process.env.PW_SOCKS_PROXY_PORT);
await dispatcher.enableSocksProxy();
return dispatcher;
});
return () => {

View File

@ -33,8 +33,9 @@ export interface BrowserProcess {
}
export type PlaywrightOptions = {
rootSdkObject: SdkObject,
selectors: Selectors,
rootSdkObject: SdkObject;
selectors: Selectors;
socksProxyPort?: number;
};
export type BrowserOptions = PlaywrightOptions & {

View File

@ -53,7 +53,7 @@ export abstract class BrowserType extends SdkObject {
}
async launch(metadata: CallMetadata, options: types.LaunchOptions, protocolLogger?: types.ProtocolLogger): Promise<Browser> {
options = validateLaunchOptions(options);
options = this._validateLaunchOptions(options);
const controller = new ProgressController(metadata, this);
controller.setLogName('browser');
const browser = await controller.run(progress => {
@ -63,7 +63,7 @@ export abstract class BrowserType extends SdkObject {
}
async launchPersistentContext(metadata: CallMetadata, userDataDir: string, options: types.LaunchPersistentOptions): Promise<BrowserContext> {
options = validateLaunchOptions(options);
options = this._validateLaunchOptions(options);
const controller = new ProgressController(metadata, this);
const persistent: types.BrowserContextOptions = options;
controller.setLogName('browser');
@ -243,6 +243,18 @@ export abstract class BrowserType extends SdkObject {
throw new Error('CDP connections are only supported by Chromium');
}
private _validateLaunchOptions<Options extends types.LaunchOptions>(options: Options): Options {
const { devtools = false } = options;
let { headless = !devtools, downloadsPath, proxy } = options;
if (debugMode())
headless = false;
if (downloadsPath && !path.isAbsolute(downloadsPath))
downloadsPath = path.join(process.cwd(), downloadsPath);
if (this._playwrightOptions.socksProxyPort)
proxy = { server: `socks5://127.0.0.1:${this._playwrightOptions.socksProxyPort}` };
return { ...options, devtools, headless, downloadsPath, proxy };
}
abstract _defaultArgs(options: types.LaunchOptions, isPersistent: boolean, userDataDir: string): string[];
abstract _connectToTransport(transport: ConnectionTransport, options: BrowserOptions): Promise<Browser>;
abstract _amendEnvironment(env: Env, userDataDir: string, executable: string, browserArguments: string[]): Env;
@ -256,15 +268,3 @@ function copyTestHooks(from: object, to: object) {
(to as any)[key] = value;
}
}
function validateLaunchOptions<Options extends types.LaunchOptions>(options: Options): Options {
const { devtools = false } = options;
let { headless = !devtools, downloadsPath, proxy } = options;
if (debugMode())
headless = false;
if (downloadsPath && !path.isAbsolute(downloadsPath))
downloadsPath = path.join(process.cwd(), downloadsPath);
if (process.env.PW_SOCKS_PROXY_PORT)
proxy = { server: `socks5://127.0.0.1:${process.env.PW_SOCKS_PROXY_PORT}` };
return { ...options, devtools, headless, downloadsPath, proxy };
}

View File

@ -163,14 +163,14 @@ export class Chromium extends BrowserType {
const proxyURL = new URL(proxy.server);
const isSocks = proxyURL.protocol === 'socks5:';
// https://www.chromium.org/developers/design-documents/network-settings
if (isSocks && !process.env.PW_SOCKS_PROXY_PORT) {
if (isSocks && !this._playwrightOptions.socksProxyPort) {
// https://www.chromium.org/developers/design-documents/network-stack/socks-proxy
chromeArguments.push(`--host-resolver-rules="MAP * ~NOTFOUND , EXCLUDE ${proxyURL.hostname}"`);
}
chromeArguments.push(`--proxy-server=${proxy.server}`);
const proxyBypassRules = [];
// https://source.chromium.org/chromium/chromium/src/+/master:net/docs/proxy.md;l=548;drc=71698e610121078e0d1a811054dcf9fd89b49578
if (process.env.PW_SOCKS_PROXY_PORT)
if (this._playwrightOptions.socksProxyPort)
proxyBypassRules.push('<-loopback>');
if (proxy.bypass)
proxyBypassRules.push(...proxy.bypass.split(',').map(t => t.trim()).map(t => t.startsWith('.') ? '*' + t : t));

View File

@ -33,7 +33,7 @@ class OutOfProcessPlaywrightServer {
detached: true,
env: {
...process.env,
PW_SOCKS_PROXY_PORT: String(proxyPort)
PW_SOCKS_PROXY_PORT: '1'
}
});
this._driverProcess.unref();
@ -44,6 +44,9 @@ class OutOfProcessPlaywrightServer {
if (line.startsWith(prefix))
resolve(line.substr(prefix.length));
});
this._driverProcess.stderr.on('data', (data: Buffer) => {
console.log(data.toString());
});
this._driverProcess.on('exit', () => reject());
});
}