feat(rpc): support firefox user prefs (#3093)

Also ignore firefoxUserPrefs in launchPersistentContext according to our api.
This commit is contained in:
Dmitry Gozman 2020-07-22 17:20:00 -07:00 committed by GitHub
parent 80c0711d98
commit 65002a0ac2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 32 additions and 15 deletions

View file

@ -170,6 +170,7 @@ export type BrowserTypeLaunchParams = {
password?: string, password?: string,
}, },
downloadsPath?: string, downloadsPath?: string,
firefoxUserPrefs?: SerializedValue,
slowMo?: number, slowMo?: number,
}; };
export type BrowserTypeLaunchResult = { export type BrowserTypeLaunchResult = {
@ -197,6 +198,7 @@ export type BrowserTypeLaunchServerParams = {
password?: string, password?: string,
}, },
downloadsPath?: string, downloadsPath?: string,
firefoxUserPrefs?: SerializedValue,
port?: number, port?: number,
}; };
export type BrowserTypeLaunchServerResult = { export type BrowserTypeLaunchServerResult = {

View file

@ -22,6 +22,9 @@ import { ChannelOwner } from './channelOwner';
import { BrowserServer } from './browserServer'; import { BrowserServer } from './browserServer';
import { LoggerSink } from '../../loggerSink'; import { LoggerSink } from '../../loggerSink';
import { headersObjectToArray, envObjectToArray } from '../serializers'; import { headersObjectToArray, envObjectToArray } from '../serializers';
import { serializeArgument } from './jsHandle';
type FirefoxPrefsOptions = { firefoxUserPrefs?: { [key: string]: string | number | boolean } };
export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeInitializer> { export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeInitializer> {
@ -41,7 +44,7 @@ export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeIni
return this._initializer.name; return this._initializer.name;
} }
async launch(options: types.LaunchOptions & { logger?: LoggerSink } = {}): Promise<Browser> { async launch(options: types.LaunchOptions & FirefoxPrefsOptions & { logger?: LoggerSink } = {}): Promise<Browser> {
const logger = options.logger; const logger = options.logger;
options = { ...options, logger: undefined }; options = { ...options, logger: undefined };
return this._wrapApiCall('browserType.launch', async () => { return this._wrapApiCall('browserType.launch', async () => {
@ -50,6 +53,7 @@ export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeIni
ignoreDefaultArgs: Array.isArray(options.ignoreDefaultArgs) ? options.ignoreDefaultArgs : undefined, ignoreDefaultArgs: Array.isArray(options.ignoreDefaultArgs) ? options.ignoreDefaultArgs : undefined,
ignoreAllDefaultArgs: !!options.ignoreDefaultArgs && !Array.isArray(options.ignoreDefaultArgs), ignoreAllDefaultArgs: !!options.ignoreDefaultArgs && !Array.isArray(options.ignoreDefaultArgs),
env: options.env ? envObjectToArray(options.env) : undefined, env: options.env ? envObjectToArray(options.env) : undefined,
firefoxUserPrefs: options.firefoxUserPrefs ? serializeArgument(options.firefoxUserPrefs).value : undefined,
}; };
const browser = Browser.from((await this._channel.launch(launchOptions)).browser); const browser = Browser.from((await this._channel.launch(launchOptions)).browser);
browser._logger = logger; browser._logger = logger;
@ -57,7 +61,7 @@ export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeIni
}, logger); }, logger);
} }
async launchServer(options: types.LaunchServerOptions & { logger?: LoggerSink } = {}): Promise<BrowserServer> { async launchServer(options: types.LaunchServerOptions & FirefoxPrefsOptions & { logger?: LoggerSink } = {}): Promise<BrowserServer> {
const logger = options.logger; const logger = options.logger;
options = { ...options, logger: undefined }; options = { ...options, logger: undefined };
return this._wrapApiCall('browserType.launchServer', async () => { return this._wrapApiCall('browserType.launchServer', async () => {
@ -66,6 +70,7 @@ export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeIni
ignoreDefaultArgs: Array.isArray(options.ignoreDefaultArgs) ? options.ignoreDefaultArgs : undefined, ignoreDefaultArgs: Array.isArray(options.ignoreDefaultArgs) ? options.ignoreDefaultArgs : undefined,
ignoreAllDefaultArgs: !!options.ignoreDefaultArgs && !Array.isArray(options.ignoreDefaultArgs), ignoreAllDefaultArgs: !!options.ignoreDefaultArgs && !Array.isArray(options.ignoreDefaultArgs),
env: options.env ? envObjectToArray(options.env) : undefined, env: options.env ? envObjectToArray(options.env) : undefined,
firefoxUserPrefs: options.firefoxUserPrefs ? serializeArgument(options.firefoxUserPrefs).value : undefined,
}; };
return BrowserServer.from((await this._channel.launchServer(launchServerOptions)).server); return BrowserServer.from((await this._channel.launchServer(launchServerOptions)).server);
}, logger); }, logger);

View file

@ -151,6 +151,7 @@ interface BrowserType
username?: string username?: string
password?: string password?: string
downloadsPath?: string downloadsPath?: string
firefoxUserPrefs?: SerializedValue
slowMo?: number slowMo?: number
returns returns
browser: Browser browser: Browser
@ -176,6 +177,7 @@ interface BrowserType
username?: string username?: string
password?: string password?: string
downloadsPath?: string downloadsPath?: string
firefoxUserPrefs?: SerializedValue
port?: number port?: number
returns returns
server: BrowserServer server: BrowserServer

View file

@ -24,6 +24,7 @@ import { BrowserContextBase } from '../../browserContext';
import { BrowserContextDispatcher } from './browserContextDispatcher'; import { BrowserContextDispatcher } from './browserContextDispatcher';
import { BrowserServerDispatcher } from './browserServerDispatcher'; import { BrowserServerDispatcher } from './browserServerDispatcher';
import { headersArrayToObject, envArrayToObject } from '../serializers'; import { headersArrayToObject, envArrayToObject } from '../serializers';
import { parseValue } from './jsHandleDispatcher';
export class BrowserTypeDispatcher extends Dispatcher<BrowserType, BrowserTypeInitializer> implements BrowserTypeChannel { export class BrowserTypeDispatcher extends Dispatcher<BrowserType, BrowserTypeInitializer> implements BrowserTypeChannel {
constructor(scope: DispatcherScope, browserType: BrowserTypeBase) { constructor(scope: DispatcherScope, browserType: BrowserTypeBase) {
@ -38,6 +39,7 @@ export class BrowserTypeDispatcher extends Dispatcher<BrowserType, BrowserTypeIn
...params, ...params,
ignoreDefaultArgs: params.ignoreAllDefaultArgs ? true : params.ignoreDefaultArgs, ignoreDefaultArgs: params.ignoreAllDefaultArgs ? true : params.ignoreDefaultArgs,
env: params.env ? envArrayToObject(params.env) : undefined, env: params.env ? envArrayToObject(params.env) : undefined,
firefoxUserPrefs: params.firefoxUserPrefs ? parseValue(params.firefoxUserPrefs) : undefined,
}; };
const browser = await this._object.launch(options); const browser = await this._object.launch(options);
return { browser: new BrowserDispatcher(this._scope, browser as BrowserBase) }; return { browser: new BrowserDispatcher(this._scope, browser as BrowserBase) };
@ -59,6 +61,7 @@ export class BrowserTypeDispatcher extends Dispatcher<BrowserType, BrowserTypeIn
const options = { const options = {
...params, ...params,
ignoreDefaultArgs: params.ignoreAllDefaultArgs ? true : params.ignoreDefaultArgs, ignoreDefaultArgs: params.ignoreAllDefaultArgs ? true : params.ignoreDefaultArgs,
firefoxUserPrefs: params.firefoxUserPrefs ? parseValue(params.firefoxUserPrefs) : undefined,
env: params.env ? envArrayToObject(params.env) : undefined, env: params.env ? envArrayToObject(params.env) : undefined,
}; };
return { server: new BrowserServerDispatcher(this._scope, await this._object.launchServer(options)) }; return { server: new BrowserServerDispatcher(this._scope, await this._object.launchServer(options)) };

View file

@ -17,7 +17,7 @@
import { CRSession, CRSessionEvents } from '../../chromium/crConnection'; import { CRSession, CRSessionEvents } from '../../chromium/crConnection';
import { CDPSessionChannel, CDPSessionInitializer, SerializedValue } from '../channels'; import { CDPSessionChannel, CDPSessionInitializer, SerializedValue } from '../channels';
import { Dispatcher, DispatcherScope } from './dispatcher'; import { Dispatcher, DispatcherScope } from './dispatcher';
import { serializeResult, parseArgument } from './jsHandleDispatcher'; import { serializeResult, parseValue } from './jsHandleDispatcher';
export class CDPSessionDispatcher extends Dispatcher<CRSession, CDPSessionInitializer> implements CDPSessionChannel { export class CDPSessionDispatcher extends Dispatcher<CRSession, CDPSessionInitializer> implements CDPSessionChannel {
constructor(scope: DispatcherScope, crSession: CRSession) { constructor(scope: DispatcherScope, crSession: CRSession) {
@ -33,7 +33,7 @@ export class CDPSessionDispatcher extends Dispatcher<CRSession, CDPSessionInitia
} }
async send(params: { method: string, params?: SerializedValue }): Promise<{ result: SerializedValue }> { async send(params: { method: string, params?: SerializedValue }): Promise<{ result: SerializedValue }> {
const cdpParams = params.params ? parseArgument({ value: params.params, handles: [] }) : undefined; const cdpParams = params.params ? parseValue(params.params) : undefined;
return { result: serializeResult(await this._object.send(params.method as any, cdpParams)) }; return { result: serializeResult(await this._object.send(params.method as any, cdpParams)) };
} }

View file

@ -65,6 +65,9 @@ export class JSHandleDispatcher extends Dispatcher<js.JSHandle, JSHandleInitiali
export function parseArgument(arg: SerializedArgument): any { export function parseArgument(arg: SerializedArgument): any {
return parseSerializedValue(arg.value, arg.handles.map(a => (a as JSHandleDispatcher)._object)); return parseSerializedValue(arg.value, arg.handles.map(a => (a as JSHandleDispatcher)._object));
} }
export function parseValue(v: SerializedValue): any {
return parseSerializedValue(v, []);
}
export function serializeResult(arg: any): SerializedValue { export function serializeResult(arg: any): SerializedValue {
return serializeValue(arg, value => ({ fallThrough: value }), new Set()); return serializeValue(arg, value => ({ fallThrough: value }), new Set());

View file

@ -73,26 +73,28 @@ export class Firefox extends BrowserTypeBase {
throw new Error('Pass userDataDir parameter instead of specifying -profile argument'); throw new Error('Pass userDataDir parameter instead of specifying -profile argument');
if (args.find(arg => arg.startsWith('-juggler'))) if (args.find(arg => arg.startsWith('-juggler')))
throw new Error('Use the port parameter instead of -juggler argument'); throw new Error('Use the port parameter instead of -juggler argument');
let firefoxUserPrefs = isPersistent ? undefined : options.firefoxUserPrefs;
if (proxy) { if (proxy) {
options.firefoxUserPrefs = options.firefoxUserPrefs || {}; // TODO: we should support proxy in persistent context without overriding user prefs.
options.firefoxUserPrefs['network.proxy.type'] = 1; firefoxUserPrefs = firefoxUserPrefs || {};
firefoxUserPrefs['network.proxy.type'] = 1;
const proxyServer = new URL(proxy.server); const proxyServer = new URL(proxy.server);
const isSocks = proxyServer.protocol === 'socks5:'; const isSocks = proxyServer.protocol === 'socks5:';
if (isSocks) { if (isSocks) {
options.firefoxUserPrefs['network.proxy.socks'] = proxyServer.hostname; firefoxUserPrefs['network.proxy.socks'] = proxyServer.hostname;
options.firefoxUserPrefs['network.proxy.socks_port'] = parseInt(proxyServer.port, 10); firefoxUserPrefs['network.proxy.socks_port'] = parseInt(proxyServer.port, 10);
} else { } else {
options.firefoxUserPrefs['network.proxy.http'] = proxyServer.hostname; firefoxUserPrefs['network.proxy.http'] = proxyServer.hostname;
options.firefoxUserPrefs['network.proxy.http_port'] = parseInt(proxyServer.port, 10); firefoxUserPrefs['network.proxy.http_port'] = parseInt(proxyServer.port, 10);
options.firefoxUserPrefs['network.proxy.ssl'] = proxyServer.hostname; firefoxUserPrefs['network.proxy.ssl'] = proxyServer.hostname;
options.firefoxUserPrefs['network.proxy.ssl_port'] = parseInt(proxyServer.port, 10); firefoxUserPrefs['network.proxy.ssl_port'] = parseInt(proxyServer.port, 10);
} }
if (proxy.bypass) if (proxy.bypass)
options.firefoxUserPrefs['network.proxy.no_proxies_on'] = proxy.bypass; firefoxUserPrefs['network.proxy.no_proxies_on'] = proxy.bypass;
} }
if (options.firefoxUserPrefs) { if (firefoxUserPrefs) {
const lines: string[] = []; const lines: string[] = [];
for (const [name, value] of Object.entries(options.firefoxUserPrefs)) for (const [name, value] of Object.entries(firefoxUserPrefs))
lines.push(`user_pref(${JSON.stringify(name)}, ${JSON.stringify(value)});`); lines.push(`user_pref(${JSON.stringify(name)}, ${JSON.stringify(value)});`);
fs.writeFileSync(path.join(userDataDir, 'user.js'), lines.join('\n')); fs.writeFileSync(path.join(userDataDir, 'user.js'), lines.join('\n'));
} }