feat: add webContents.setWindowOpenHandler API (#24517)

Co-authored-by: Jeremy Rose <jeremya@chromium.org>
This commit is contained in:
loc 2020-11-10 09:06:03 -08:00 коммит произвёл GitHub
Родитель 6b222a2d8a
Коммит 0b85fdf26c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
56 изменённых файлов: 2087 добавлений и 885 удалений

Просмотреть файл

@ -14,7 +14,7 @@
"@typescript-eslint/no-unused-vars": ["error", {
"vars": "all",
"args": "after-used",
"ignoreRestSiblings": false
"ignoreRestSiblings": true
}],
"prefer-const": ["error", {
"destructuring": "all"

Просмотреть файл

@ -134,7 +134,7 @@ Returns:
Emitted when page receives favicon urls.
#### Event: 'new-window'
#### Event: 'new-window' _Deprecated_
Returns:
@ -155,6 +155,8 @@ Returns:
be set. If no post data is to be sent, the value will be `null`. Only defined
when the window is being created by a form that set `target=_blank`.
Deprecated in favor of [`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandler-handler).
Emitted when the page requests to open a new window for a `url`. It could be
requested by `window.open` or an external link like `<a target='_blank'>`.
@ -189,6 +191,39 @@ myBrowserWindow.webContents.on('new-window', (event, url, frameName, disposition
})
```
#### Event: 'did-create-window'
Returns:
* `window` BrowserWindow
* `details` Object
* `url` String - URL for the created window.
* `frameName` String - Name given to the created window in the
`window.open()` call.
* `options` BrowserWindowConstructorOptions - The options used to create the
BrowserWindow. They are merged in increasing precedence: options inherited
from the parent, parsed options from the `features` string from
`window.open()`, and options given by
[`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandler-handler).
Unrecognized options are not filtered out.
* `additionalFeatures` String[] - The non-standard features (features not
handled Chromium or Electron) _Deprecated_
* `referrer` [Referrer](structures/referrer.md) - The referrer that will be
passed to the new window. May or may not result in the `Referer` header
being sent, depending on the referrer policy.
* `postBody` [PostBody](structures/post-body.md) (optional) - The post data
that will be sent to the new window, along with the appropriate headers
that will be set. If no post data is to be sent, the value will be `null`.
Only defined when the window is being created by a form that set
`target=_blank`.
* `disposition` String - Can be `default`, `foreground-tab`,
`background-tab`, `new-window`, `save-to-disk` and `other`.
Emitted _after_ successful creation of a window via `window.open` in the renderer.
Not emitted if the creation of the window is canceled from
[`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandler-handler).
See [`window.open()`](window-open.md) for more details and how to use this in conjunction with `webContents.setWindowOpenHandler`.
#### Event: 'will-navigate'
Returns:
@ -1123,6 +1158,22 @@ Works like `executeJavaScript` but evaluates `scripts` in an isolated context.
Ignore application menu shortcuts while this web contents is focused.
#### `contents.setWindowOpenHandler(handler)`
* `handler` Function<{action: 'deny'} | {action: 'allow', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions}>
* `details` Object
* `url` String - The _resolved_ version of the URL passed to `window.open()`. e.g. opening a window with `window.open('foo')` will yield something like `https://the-origin/the/current/path/foo`.
* `frameName` String - Name of the window provided in `window.open()`
* `features` String - Comma separated list of window features provided to `window.open()`.
Returns `{action: 'deny'} | {action: 'allow', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions}` - `deny` cancels the creation of the new
window. `allow` will allow the new window to be created. Specifying `overrideBrowserWindowOptions` allows customization of the created window.
Returning an unrecognized value such as a null, undefined, or an object
without a recognized 'action' value will result in a console error and have
the same effect as returning `{action: 'deny'}`.
Called before creating a window when `window.open()` is called from the
renderer. See [`window.open()`](window-open.md) for more details and how to use this in conjunction with `did-create-window`.
#### `contents.setAudioMuted(muted)`
* `muted` Boolean

Просмотреть файл

@ -1,18 +1,34 @@
# `window.open` Function
# Opening windows from the renderer
> Open a new window and load a URL.
There are several ways to control how windows are created from trusted or
untrusted content within a renderer. Windows can be created from the renderer in two ways:
When `window.open` is called to create a new window in a web page, a new instance
of [`BrowserWindow`](browser-window.md) will be created for the `url` and a proxy will be returned
to `window.open` to let the page have limited control over it.
- clicking on links or submitting forms adorned with `target=_blank`
- JavaScript calling `window.open()`
The proxy has limited standard functionality implemented to be
compatible with traditional web pages. For full control of the new window
you should create a `BrowserWindow` directly.
In non-sandboxed renderers, or when `nativeWindowOpen` is false (the default), this results in the creation of a
[`BrowserWindowProxy`](browser-window-proxy.md), a light wrapper around
`BrowserWindow`.
The newly created `BrowserWindow` will inherit the parent window's options by
default. To override inherited options you can set them in the `features`
string.
However, when the `sandbox` (or directly, `nativeWindowOpen`) option is set, a
`Window` instance is created, as you'd expect in the browser. For same-origin
content, the new window is created within the same process, enabling the parent
to access the child window directly. This can be very useful for app sub-windows that act
as preference panels, or similar, as the parent can render to the sub-window
directly, as if it were a `div` in the parent.
Electron pairs this native Chrome `Window` with a BrowserWindow under the hood.
You can take advantage of all the customization available when creating a
BrowserWindow in the main process by using `webContents.setWindowOpenHandler()`
for renderer-created windows.
BrowserWindow constructor options are set by, in increasing precedence
order: options inherited from the parent, parsed options
from the `features` string from `window.open()`, security-related webPreferences
inherited from the parent, and options given by
[`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandler-handler).
Note that `webContents.setWindowOpenHandler` has final say and full privilege
because it is invoked in the main process.
### `window.open(url[, frameName][, features])`
@ -20,16 +36,22 @@ string.
* `frameName` String (optional)
* `features` String (optional)
Returns [`BrowserWindowProxy`](browser-window-proxy.md) - Creates a new window
and returns an instance of `BrowserWindowProxy` class.
Returns [`BrowserWindowProxy`](browser-window-proxy.md) | [`Window`](https://developer.mozilla.org/en-US/docs/Web/API/Window)
The `features` string follows the format of standard browser, but each feature
has to be a field of `BrowserWindow`'s options. These are the features you can set via `features` string: `zoomFactor`, `nodeIntegration`, `preload`, `javascript`, `contextIsolation`, `webviewTag`.
`features` is a comma-separated key-value list, following the standard format of
the browser. Electron will parse `BrowserWindowConstructorOptions` out of this
list where possible, for convenience. For full control and better ergonomics,
consider using `webContents.setWindowOpenHandler` to customize the
BrowserWindow creation.
A subset of `WebPreferences` can be set directly,
unnested, from the features string: `zoomFactor`, `nodeIntegration`, `preload`,
`javascript`, `contextIsolation`, and `webviewTag`.
For example:
```js
window.open('https://github.com', '_blank', 'nodeIntegration=no')
window.open('https://github.com', '_blank', 'top=500,left=200,frame=false,nodeIntegration=no')
```
**Notes:**
@ -41,60 +63,74 @@ window.open('https://github.com', '_blank', 'nodeIntegration=no')
* JavaScript will always be disabled in the opened `window` if it is disabled on
the parent window.
* Non-standard features (that are not handled by Chromium or Electron) given in
`features` will be passed to any registered `webContent`'s `new-window` event
handler in the `additionalFeatures` argument.
`features` will be passed to any registered `webContents`'s
`did-create-window` event handler in the `additionalFeatures` argument.
### `window.opener.postMessage(message, targetOrigin)`
To customize or cancel the creation of the window, you can optionally set an
override handler with `webContents.setWindowOpenHandler()` from the main
process. Returning `false` cancels the window, while returning an object sets
the `BrowserWindowConstructorOptions` used when creating the window. Note that
this is more powerful than passing options through the feature string, as the
renderer has more limited privileges in deciding security preferences than the
main process.
* `message` String
* `targetOrigin` String
Sends a message to the parent window with the specified origin or `*` for no
origin preference.
### Using Chrome's `window.open()` implementation
If you want to use Chrome's built-in `window.open()` implementation, set
`nativeWindowOpen` to `true` in the `webPreferences` options object.
Native `window.open()` allows synchronous access to opened windows so it is
convenient choice if you need to open a dialog or a preferences window.
This option can also be set on `<webview>` tags as well:
```html
<webview webpreferences="nativeWindowOpen=yes"></webview>
```
The creation of the `BrowserWindow` is customizable via `WebContents`'s
`new-window` event.
### `BrowserWindowProxy` example
```javascript
// main process
// main.js
const mainWindow = new BrowserWindow()
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
if (url.startsWith('https://github.com/')) {
return true
}
return false
})
mainWindow.webContents.on('did-create-window', (childWindow) => {
// For example...
childWindow.webContents('will-navigate', (e) => {
e.preventDefault()
})
})
```
```javascript
// renderer.js
const windowProxy = window.open('https://github.com/', null, 'minimizable=false')
windowProxy.postMessage('hi', '*')
```
### Native `Window` example
```javascript
// main.js
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nativeWindowOpen: true
}
})
mainWindow.webContents.on('new-window', (event, url, frameName, disposition, options, additionalFeatures) => {
if (frameName === 'modal') {
// open window as modal
event.preventDefault()
Object.assign(options, {
modal: true,
parent: mainWindow,
width: 100,
height: 100
})
event.newGuest = new BrowserWindow(options)
// In this example, only windows with the `about:blank` url will be created.
// All other urls will be blocked.
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
if (url === 'about:blank') {
return {
frame: false,
fullscreenable: false,
backgroundColor: 'black',
webPreferences: {
preload: 'my-child-window-preload-script.js'
}
}
}
return false
})
```
```javascript
// renderer process (mainWindow)
const modal = window.open('', 'modal')
modal.document.write('<h1>Hello</h1>')
const childWindow = window.open('', 'modal')
childWindow.document.write('<h1>Hello</h1>')
```

Просмотреть файл

@ -611,22 +611,29 @@ windows at runtime.
### How?
[`webContents`][web-contents] will emit the [`new-window`][new-window] event
before creating new windows. That event will be passed, amongst other
parameters, the `url` the window was requested to open and the options used to
create it. We recommend that you use the event to scrutinize the creation of
windows, limiting it to only what you need.
[`webContents`][web-contents] will delegate to its [window open
handler][window-open-handler] before creating new windows. The handler will
receive, amongst other parameters, the `url` the window was requested to open
and the options used to create it. We recommend that you register a handler to
monitor the creation of windows, and deny any unexpected window creation.
```js
const { shell } = require('electron')
app.on('web-contents-created', (event, contents) => {
contents.on('new-window', async (event, navigationUrl) => {
contents.setWindowOpenHandler(({ url }) => {
// In this example, we'll ask the operating system
// to open this event's url in the default browser.
event.preventDefault()
//
// See the following item for considerations regarding what
// URLs should be allowed through to shell.openExternal.
if (isSafeForExternalOpen(url)) {
setImmediate(() => {
shell.openExternal(url)
})
}
await shell.openExternal(navigationUrl)
return { action: 'deny' }
})
})
```
@ -811,7 +818,7 @@ which potential security issues are not as widely known.
[browser-view]: ../api/browser-view.md
[webview-tag]: ../api/webview-tag.md
[web-contents]: ../api/web-contents.md
[new-window]: ../api/web-contents.md#event-new-window
[window-open-handler]: ../api/web-contents.md#contentssetwindowopenhandler-handler
[will-navigate]: ../api/web-contents.md#event-will-navigate
[open-external]: ../api/shell.md#shellopenexternalurl-options
[sandbox]: ../api/sandbox-option.md

Просмотреть файл

@ -237,6 +237,7 @@ auto_filenames = {
"lib/browser/devtools.ts",
"lib/browser/guest-view-manager.ts",
"lib/browser/guest-window-manager.ts",
"lib/browser/guest-window-proxy.ts",
"lib/browser/init.ts",
"lib/browser/ipc-main-impl.ts",
"lib/browser/ipc-main-internal-utils.ts",

Просмотреть файл

@ -1,13 +1,12 @@
import { app, ipcMain, session, deprecate } from 'electron/main';
import type { MenuItem, MenuItemConstructorOptions } from 'electron/main';
import { app, ipcMain, session, deprecate, BrowserWindowConstructorOptions } from 'electron/main';
import type { MenuItem, MenuItemConstructorOptions, LoadURLOptions } from 'electron/main';
import * as url from 'url';
import * as path from 'path';
import { internalWindowOpen } from '@electron/internal/browser/guest-window-manager';
import { openGuestWindow, makeWebPreferences } from '@electron/internal/browser/guest-window-manager';
import { NavigationController } from '@electron/internal/browser/navigation-controller';
import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal';
import * as ipcMainUtils from '@electron/internal/browser/ipc-main-internal-utils';
import { parseFeatures } from '@electron/internal/common/parse-features-string';
import { MessagePortMain } from '@electron/internal/browser/message-port-main';
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
@ -21,6 +20,8 @@ const getNextId = function () {
return ++nextId;
};
type PostData = LoadURLOptions['postData']
/* eslint-disable camelcase */
type MediaSize = {
name: string,
@ -439,6 +440,40 @@ WebContents.prototype.loadFile = function (filePath, options = {}) {
}));
};
WebContents.prototype.setWindowOpenHandler = function (handler: (details: Electron.HandlerDetails) => ({action: 'allow'} | {action: 'deny', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions})) {
this._windowOpenHandler = handler;
};
WebContents.prototype._callWindowOpenHandler = function (event: any, url: string, frameName: string, rawFeatures: string): BrowserWindowConstructorOptions | null {
if (!this._windowOpenHandler) {
return null;
}
const response = this._windowOpenHandler({ url, frameName, features: rawFeatures });
if (typeof response !== 'object') {
event.preventDefault();
console.error(`The window open handler response must be an object, but was instead of type '${typeof response}'.`);
return null;
}
if (response === null) {
event.preventDefault();
console.error('The window open handler response must be an object, but was instead null.');
return null;
}
if (response.action === 'deny') {
event.preventDefault();
return null;
} else if (response.action === 'allow') {
if (typeof response.overrideBrowserWindowOptions === 'object' && response.overrideBrowserWindowOptions !== null) { return response.overrideBrowserWindowOptions; } else { return {}; }
} else {
event.preventDefault();
console.error('The window open handler response must be an object with an \'action\' property of \'allow\' or \'deny\'.');
return null;
}
};
const addReplyToEvent = (event: any) => {
event.reply = (...args: any[]) => {
event.sender.sendToFrame(event.frameId, ...args);
@ -490,6 +525,8 @@ WebContents.prototype._init = function () {
this.getActiveIndex = navigationController.getActiveIndex.bind(navigationController);
this.length = navigationController.length.bind(navigationController);
this._windowOpenHandler = null;
// Every remote callback from renderer process would add a listener to the
// render-view-deleted event, so ignore the listeners warning.
this.setMaxListeners(0);
@ -570,43 +607,67 @@ WebContents.prototype._init = function () {
if (this.getType() !== 'remote') {
// Make new windows requested by links behave like "window.open".
this.on('-new-window' as any, (event: any, url: string, frameName: string, disposition: string,
rawFeatures: string, referrer: string, postData: Electron.UploadRawData[]) => {
const { options, webPreferences, additionalFeatures } = parseFeatures(rawFeatures);
const mergedOptions = {
show: true,
width: 800,
height: 600,
title: frameName,
webPreferences,
...options
};
rawFeatures: string, referrer: any, postData: PostData) => {
openGuestWindow({
event,
embedder: event.sender,
disposition,
referrer,
postData,
overrideBrowserWindowOptions: {},
windowOpenArgs: {
url,
frameName,
features: rawFeatures
}
});
});
internalWindowOpen(event, url, referrer, frameName, disposition, mergedOptions, additionalFeatures, postData);
let windowOpenOverriddenOptions: BrowserWindowConstructorOptions | null = null;
this.on('-will-add-new-contents' as any, (event: any, url: string, frameName: string, rawFeatures: string) => {
windowOpenOverriddenOptions = this._callWindowOpenHandler(event, url, frameName, rawFeatures);
if (!event.defaultPrevented) {
const secureOverrideWebPreferences = windowOpenOverriddenOptions ? {
// Allow setting of backgroundColor as a webPreference even though
// it's technically a BrowserWindowConstructorOptions option because
// we need to access it in the renderer at init time.
backgroundColor: windowOpenOverriddenOptions.backgroundColor,
...windowOpenOverriddenOptions.webPreferences
} : undefined;
this._setNextChildWebPreferences(
makeWebPreferences({ embedder: event.sender, secureOverrideWebPreferences })
);
}
});
// Create a new browser window for the native implementation of
// "window.open", used in sandbox and nativeWindowOpen mode.
this.on('-add-new-contents' as any, (event: any, webContents: Electron.WebContents, disposition: string,
userGesture: boolean, left: number, top: number, width: number, height: number, url: string, frameName: string,
referrer: string, rawFeatures: string, postData: Electron.UploadRawData[]) => {
_userGesture: boolean, _left: number, _top: number, _width: number, _height: number, url: string, frameName: string,
referrer: Electron.Referrer, rawFeatures: string, postData: PostData) => {
const overriddenOptions = windowOpenOverriddenOptions || undefined;
windowOpenOverriddenOptions = null;
if ((disposition !== 'foreground-tab' && disposition !== 'new-window' &&
disposition !== 'background-tab')) {
event.preventDefault();
return;
}
const { options, webPreferences, additionalFeatures } = parseFeatures(rawFeatures);
const mergedOptions = {
show: true,
width: 800,
height: 600,
webContents,
title: frameName,
webPreferences,
...options
};
internalWindowOpen(event, url, referrer, frameName, disposition, mergedOptions, additionalFeatures, postData);
openGuestWindow({
event,
embedder: event.sender,
guest: webContents,
overrideBrowserWindowOptions: overriddenOptions,
disposition,
referrer,
postData,
windowOpenArgs: {
url,
frameName,
features: rawFeatures
}
});
});
const prefs = this.getWebPreferences() || {};

Просмотреть файл

@ -1,360 +1,300 @@
import * as electron from 'electron/main';
import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal';
import * as ipcMainUtils from '@electron/internal/browser/ipc-main-internal-utils';
/**
* Create and minimally track guest windows at the direction of the renderer
* (via window.open). Here, "guest" roughly means "child" it's not necessarily
* emblematic of its process status; both in-process (same-origin
* nativeWindowOpen) and out-of-process (cross-origin nativeWindowOpen and
* BrowserWindowProxy) are created here. "Embedder" roughly means "parent."
*/
import { BrowserWindow } from 'electron/main';
import type { BrowserWindowConstructorOptions, Referrer, WebContents, LoadURLOptions } from 'electron/main';
import { parseFeatures } from '@electron/internal/common/parse-features-string';
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
const { isSameOrigin } = process._linkedBinding('electron_common_v8_util');
const { BrowserWindow } = electron;
const hasProp = {}.hasOwnProperty;
const frameToGuest = new Map<string, Electron.BrowserWindow>();
// Security options that child windows will always inherit from parent windows
const inheritedWebPreferences = new Map([
['contextIsolation', true],
['javascript', false],
['nativeWindowOpen', true],
['nodeIntegration', false],
['enableRemoteModule', false],
['sandbox', true],
['webviewTag', false],
['nodeIntegrationInSubFrames', false],
['enableWebSQL', false]
]);
// Copy attribute of |parent| to |child| if it is not defined in |child|.
const mergeOptions = function (child: Record<string, any>, parent: Record<string, any>, visited?: Set<Record<string, any>>) {
// Check for circular reference.
if (visited == null) visited = new Set();
if (visited.has(parent)) return;
visited.add(parent);
for (const key in parent) {
if (key === 'type') continue;
if (!hasProp.call(parent, key)) continue;
if (key in child && key !== 'webPreferences') continue;
const value = parent[key];
if (typeof value === 'object' && !Array.isArray(value)) {
child[key] = mergeOptions(child[key] || {}, value, visited);
} else {
child[key] = value;
}
}
visited.delete(parent);
return child;
};
// Merge |options| with the |embedder|'s window's options.
const mergeBrowserWindowOptions = function (embedder: Electron.WebContents, options: Record<string, any>) {
if (options.webPreferences == null) {
options.webPreferences = {};
}
if (embedder.browserWindowOptions != null) {
let parentOptions = embedder.browserWindowOptions;
// if parent's visibility is available, that overrides 'show' flag (#12125)
const win = BrowserWindow.fromWebContents(embedder);
if (win != null) {
parentOptions = {
...win.getBounds(),
...embedder.browserWindowOptions,
show: win.isVisible()
};
}
// Inherit the original options if it is a BrowserWindow.
mergeOptions(options, parentOptions);
} else {
// Or only inherit webPreferences if it is a webview.
mergeOptions(options.webPreferences, embedder.getLastWebPreferences());
}
// Inherit certain option values from parent window
const webPreferences = embedder.getLastWebPreferences();
for (const [name, value] of inheritedWebPreferences) {
if ((webPreferences as any)[name] === value) {
options.webPreferences[name] = value;
}
}
if (!webPreferences.nativeWindowOpen) {
// Sets correct openerId here to give correct options to 'new-window' event handler
options.webPreferences.openerId = embedder.id;
}
return options;
};
const MULTIPART_CONTENT_TYPE = 'multipart/form-data';
const URL_ENCODED_CONTENT_TYPE = 'application/x-www-form-urlencoded';
function makeContentTypeHeader ({ contentType, boundary }: { contentType: string, boundary?: string }) {
const header = `content-type: ${contentType};`;
if (contentType === MULTIPART_CONTENT_TYPE) {
return `${header} boundary=${boundary}`;
}
return header;
type PostData = LoadURLOptions['postData']
export type WindowOpenArgs = {
url: string,
frameName: string,
features: string,
}
// Figure out appropriate headers for post data.
const parseContentTypeFormat = function (postData: Electron.UploadRawData[]) {
if (postData.length) {
// For multipart forms, the first element will start with the boundary
// notice, which looks something like `------WebKitFormBoundary12345678`
// Note, this regex would fail when submitting a urlencoded form with an
// input attribute of name="--theKey", but, uhh, don't do that?
const postDataFront = postData[0].bytes.toString();
const boundary = /^--.*[^-\r\n]/.exec(postDataFront);
if (boundary) {
return {
boundary: boundary[0].substr(2),
contentType: MULTIPART_CONTENT_TYPE
};
}
}
// Either the form submission didn't contain any inputs (the postData array
// was empty), or we couldn't find the boundary and thus we can assume this is
// a key=value style form.
return {
contentType: URL_ENCODED_CONTENT_TYPE
};
};
const frameNamesToWindow = new Map<string, BrowserWindow>();
const registerFrameNameToGuestWindow = (name: string, win: BrowserWindow) => frameNamesToWindow.set(name, win);
const unregisterFrameName = (name: string) => frameNamesToWindow.delete(name);
const getGuestWindowByFrameName = (name: string) => frameNamesToWindow.get(name);
// Setup a new guest with |embedder|
const setupGuest = function (embedder: Electron.WebContents, frameName: string, guest: Electron.BrowserWindow) {
// When |embedder| is destroyed we should also destroy attached guest, and if
// guest is closed by user then we should prevent |embedder| from double
// closing guest.
const guestId = guest.webContents.id;
/**
* `openGuestWindow` is called for both implementations of window.open
* (BrowserWindowProxy and nativeWindowOpen) to create and setup event handling
* for the new window.
*
* Until its removal in 12.0.0, the `new-window` event is fired, allowing the
* user to preventDefault() on the passed event (which ends up calling
* DestroyWebContents in the nativeWindowOpen code path).
*/
export function openGuestWindow ({ event, embedder, guest, referrer, disposition, postData, overrideBrowserWindowOptions, windowOpenArgs }: {
event: { sender: WebContents, defaultPrevented: boolean },
embedder: WebContents,
guest?: WebContents,
referrer: Referrer,
disposition: string,
postData?: PostData,
overrideBrowserWindowOptions?: BrowserWindowConstructorOptions,
windowOpenArgs: WindowOpenArgs,
}): BrowserWindow | undefined {
const { url, frameName, features } = windowOpenArgs;
const isNativeWindowOpen = !!guest;
const { options: browserWindowOptions, additionalFeatures } = makeBrowserWindowOptions({
embedder,
features,
frameName,
overrideOptions: overrideBrowserWindowOptions
});
const didCancelEvent = emitDeprecatedNewWindowEvent({
event,
embedder,
guest,
browserWindowOptions,
windowOpenArgs,
additionalFeatures,
disposition,
referrer
});
if (didCancelEvent) return;
// To spec, subsequent window.open calls with the same frame name (`target` in
// spec parlance) will reuse the previous window.
// https://html.spec.whatwg.org/multipage/window-object.html#apis-for-creating-and-navigating-browsing-contexts-by-name
const existingWindow = getGuestWindowByFrameName(frameName);
if (existingWindow) {
existingWindow.loadURL(url);
return existingWindow;
}
const window = new BrowserWindow({
webContents: guest,
...browserWindowOptions
});
if (!isNativeWindowOpen) {
// We should only call `loadURL` if the webContents was constructed by us in
// the case of BrowserWindowProxy (non-sandboxed, nativeWindowOpen: false),
// as navigating to the url when creating the window from an existing
// webContents is not necessary (it will navigate there anyway).
window.loadURL(url, {
httpReferrer: referrer,
...(postData && {
postData,
extraHeaders: formatPostDataHeaders(postData)
})
});
}
handleWindowLifecycleEvents({ embedder, frameName, guest: window });
embedder.emit('did-create-window', window, { url, frameName, options: browserWindowOptions, disposition, additionalFeatures, referrer, postData });
return window;
}
/**
* Manage the relationship between embedder window and guest window. When the
* guest is destroyed, notify the embedder. When the embedder is destroyed, so
* too is the guest destroyed; this is Electron convention and isn't based in
* browser behavior.
*/
const handleWindowLifecycleEvents = function ({ embedder, guest, frameName }: {
embedder: WebContents,
guest: BrowserWindow,
frameName: string
}) {
const closedByEmbedder = function () {
guest.removeListener('closed', closedByUser);
guest.destroy();
};
const cachedGuestId = guest.webContents.id;
const closedByUser = function () {
embedder._sendInternal(`${IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_CLOSED}_${guestId}`);
embedder._sendInternal(`${IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_CLOSED}_${cachedGuestId}`);
embedder.removeListener('current-render-view-deleted' as any, closedByEmbedder);
};
embedder.once('current-render-view-deleted' as any, closedByEmbedder);
guest.once('closed', closedByUser);
if (frameName) {
frameToGuest.set(frameName, guest);
guest.frameName = frameName;
registerFrameNameToGuestWindow(frameName, guest);
guest.once('closed', function () {
frameToGuest.delete(frameName);
unregisterFrameName(frameName);
});
}
return guestId;
};
// Create a new guest created by |embedder| with |options|.
const createGuest = function (embedder: Electron.webContents, url: string, referrer: string | Electron.Referrer,
frameName: string, options: Record<string, any>, postData?: Electron.UploadRawData[]) {
let guest = frameToGuest.get(frameName);
if (frameName && (guest != null)) {
guest.loadURL(url);
return guest.webContents.id;
}
// Remember the embedder window's id.
if (options.webPreferences == null) {
options.webPreferences = {};
}
guest = new BrowserWindow(options);
if (!options.webContents) {
// We should not call `loadURL` if the window was constructed from an
// existing webContents (window.open in a sandboxed renderer).
//
// Navigating to the url when creating the window from an existing
// webContents is not necessary (it will navigate there anyway).
const loadOptions: Electron.LoadURLOptions = {
httpReferrer: referrer
};
if (postData != null) {
loadOptions.postData = postData;
loadOptions.extraHeaders = makeContentTypeHeader(parseContentTypeFormat(postData));
}
guest.loadURL(url, loadOptions);
}
return setupGuest(embedder, frameName, guest);
};
const getGuestWindow = function (guestContents: Electron.WebContents) {
let guestWindow = BrowserWindow.fromWebContents(guestContents);
if (guestWindow == null) {
const hostContents = guestContents.hostWebContents;
if (hostContents != null) {
guestWindow = BrowserWindow.fromWebContents(hostContents);
}
}
if (!guestWindow) {
throw new Error('getGuestWindow failed');
}
return guestWindow;
};
const isChildWindow = function (sender: Electron.WebContents, target: Electron.WebContents) {
return target.getLastWebPreferences().openerId === sender.id;
};
const isRelatedWindow = function (sender: Electron.WebContents, target: Electron.WebContents) {
return isChildWindow(sender, target) || isChildWindow(target, sender);
};
const isScriptableWindow = function (sender: Electron.WebContents, target: Electron.WebContents) {
return isRelatedWindow(sender, target) && isSameOrigin(sender.getURL(), target.getURL());
};
const isNodeIntegrationEnabled = function (sender: Electron.WebContents) {
return sender.getLastWebPreferences().nodeIntegration === true;
};
// Checks whether |sender| can access the |target|:
const canAccessWindow = function (sender: Electron.WebContents, target: Electron.WebContents) {
return isChildWindow(sender, target) ||
isScriptableWindow(sender, target) ||
isNodeIntegrationEnabled(sender);
};
// Routed window.open messages with raw options
ipcMainInternal.on(IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_OPEN, (event, url: string, frameName: string, features: string) => {
// This should only be allowed for senders that have nativeWindowOpen: false
const lastWebPreferences = event.sender.getLastWebPreferences();
if (lastWebPreferences.nativeWindowOpen || lastWebPreferences.sandbox) {
event.returnValue = null;
throw new Error(`${IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_OPEN} denied: expected native window.open`);
}
if (url == null || url === '') url = 'about:blank';
if (frameName == null) frameName = '';
if (features == null) features = '';
const disposition = 'new-window';
const { options, webPreferences, additionalFeatures } = parseFeatures(features);
if (!options.title) options.title = frameName;
(options as Electron.BrowserWindowConstructorOptions).webPreferences = webPreferences;
const referrer: Electron.Referrer = { url: '', policy: 'default' };
internalWindowOpen(event, url, referrer, frameName, disposition, options, additionalFeatures);
});
// Routed window.open messages with fully parsed options
export function internalWindowOpen (event: ElectronInternal.IpcMainInternalEvent, url: string, referrer: string | Electron.Referrer,
frameName: string, disposition: string, options: Record<string, any>, additionalFeatures: string[], postData?: Electron.UploadRawData[]) {
options = mergeBrowserWindowOptions(event.sender, options);
/**
* Deprecated in favor of `webContents.setWindowOpenHandler` and
* `did-create-window` in 11.0.0. Will be removed in 12.0.0.
*/
function emitDeprecatedNewWindowEvent ({ event, embedder, guest, windowOpenArgs, browserWindowOptions, additionalFeatures, disposition, referrer, postData }: {
event: { sender: WebContents, defaultPrevented: boolean },
embedder: WebContents,
guest?: WebContents,
windowOpenArgs: WindowOpenArgs,
browserWindowOptions: BrowserWindowConstructorOptions,
additionalFeatures: string[]
disposition: string,
referrer: Referrer,
postData?: PostData,
}): boolean {
const { url, frameName } = windowOpenArgs;
const isWebViewWithPopupsDisabled = embedder.getType() === 'webview' && (embedder as any).getLastWebPreferences().disablePopups;
const postBody = postData ? {
data: postData,
...parseContentTypeFormat(postData)
headers: formatPostDataHeaders(postData)
} : null;
event.sender.emit('new-window', event, url, frameName, disposition, options, additionalFeatures, referrer, postBody);
const { newGuest } = event as unknown as { newGuest: Electron.BrowserWindow };
if ((event.sender.getType() === 'webview' && event.sender.getLastWebPreferences().disablePopups) || event.defaultPrevented) {
if (newGuest != null) {
if (options.webContents === newGuest.webContents) {
// the webContents is not changed, so set defaultPrevented to false to
embedder.emit(
'new-window',
event,
url,
frameName,
disposition,
{
...browserWindowOptions,
webContents: guest
},
additionalFeatures,
referrer,
postBody
);
const { newGuest } = event as any;
if (isWebViewWithPopupsDisabled) return true;
if (event.defaultPrevented) {
if (newGuest) {
if (guest === newGuest.webContents) {
// The webContents is not changed, so set defaultPrevented to false to
// stop the callers of this event from destroying the webContents.
(event as any).defaultPrevented = false;
}
event.returnValue = setupGuest(event.sender, frameName, newGuest);
} else {
event.returnValue = null;
handleWindowLifecycleEvents({
embedder: event.sender,
guest: newGuest,
frameName
});
}
} else {
event.returnValue = createGuest(event.sender, url, referrer, frameName, options, postData);
return true;
}
return false;
}
const makeSafeHandler = function<Event> (handler: (event: Event, guestContents: Electron.webContents, ...args: any[]) => any) {
return (event: Event, guestId: number, ...args: any[]) => {
// Access webContents via electron to prevent circular require.
const guestContents = electron.webContents.fromId(guestId);
if (!guestContents) {
throw new Error(`Invalid guestId: ${guestId}`);
// Security options that child windows will always inherit from parent windows
const securityWebPreferences: { [key: string]: boolean } = {
contextIsolation: true,
javascript: false,
nativeWindowOpen: true,
nodeIntegration: false,
enableRemoteModule: false,
sandbox: true,
webviewTag: false,
nodeIntegrationInSubFrames: false,
enableWebSQL: false
};
function makeBrowserWindowOptions ({ embedder, features, frameName, overrideOptions, useDeprecatedBehaviorForBareValues = true, useDeprecatedBehaviorForOptionInheritance = true }: {
embedder: WebContents,
features: string,
frameName: string,
overrideOptions?: BrowserWindowConstructorOptions,
useDeprecatedBehaviorForBareValues?: boolean
useDeprecatedBehaviorForOptionInheritance?: boolean
}) {
const { options: parsedOptions, webPreferences: parsedWebPreferences, additionalFeatures } = parseFeatures(features, useDeprecatedBehaviorForBareValues);
const deprecatedInheritedOptions = getDeprecatedInheritedOptions(embedder);
return {
additionalFeatures,
options: {
...(useDeprecatedBehaviorForOptionInheritance && deprecatedInheritedOptions),
show: true,
title: frameName,
width: 800,
height: 600,
...parsedOptions,
...overrideOptions,
webPreferences: makeWebPreferences({ embedder, insecureParsedWebPreferences: parsedWebPreferences, secureOverrideWebPreferences: overrideOptions && overrideOptions.webPreferences, useDeprecatedBehaviorForOptionInheritance: true })
}
return handler(event, guestContents, ...args);
};
};
}
const handleMessage = function (channel: string, handler: (event: Electron.IpcMainInvokeEvent, guestContents: Electron.webContents, ...args: any[]) => any) {
ipcMainInternal.handle(channel, makeSafeHandler(handler));
};
export function makeWebPreferences ({ embedder, secureOverrideWebPreferences = {}, insecureParsedWebPreferences: parsedWebPreferences = {}, useDeprecatedBehaviorForOptionInheritance = true }: {
embedder: WebContents,
insecureParsedWebPreferences?: ReturnType<typeof parseFeatures>['webPreferences'],
// Note that override preferences are considered elevated, and should only be
// sourced from the main process, as they override security defaults. If you
// have unvetted prefs, use parsedWebPreferences.
secureOverrideWebPreferences?: BrowserWindowConstructorOptions['webPreferences'],
useDeprecatedBehaviorForBareValues?: boolean
useDeprecatedBehaviorForOptionInheritance?: boolean
}) {
const deprecatedInheritedOptions = getDeprecatedInheritedOptions(embedder);
const parentWebPreferences = (embedder as any).getLastWebPreferences();
const securityWebPreferencesFromParent = Object.keys(securityWebPreferences).reduce((map, key) => {
if (securityWebPreferences[key] === parentWebPreferences[key]) {
map[key] = parentWebPreferences[key];
}
return map;
}, {} as any);
const openerId = parentWebPreferences.nativeWindowOpen ? null : embedder.id;
const handleMessageSync = function (channel: string, handler: (event: ElectronInternal.IpcMainInternalEvent, guestContents: Electron.webContents, ...args: any[]) => any) {
ipcMainUtils.handleSync(channel, makeSafeHandler(handler));
};
return {
...(useDeprecatedBehaviorForOptionInheritance && deprecatedInheritedOptions ? deprecatedInheritedOptions.webPreferences : null),
...parsedWebPreferences,
// Note that order is key here, we want to disallow the renderer's
// ability to change important security options but allow main (via
// setWindowOpenHandler) to change them.
...securityWebPreferencesFromParent,
...secureOverrideWebPreferences,
// Sets correct openerId here to give correct options to 'new-window' event handler
// TODO: Figure out another way to pass this?
openerId
};
}
const securityCheck = function (contents: Electron.WebContents, guestContents: Electron.WebContents, check: (sender: Electron.WebContents, target: Electron.WebContents) => boolean) {
if (!check(contents, guestContents)) {
console.error(`Blocked ${contents.getURL()} from accessing guestId: ${guestContents.id}`);
throw new Error(`Access denied to guestId: ${guestContents.id}`);
}
};
const windowMethods = new Set([
'destroy',
'focus',
'blur'
]);
handleMessage(IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_METHOD, (event, guestContents, method: string, ...args: any[]) => {
securityCheck(event.sender, guestContents, canAccessWindow);
if (!windowMethods.has(method)) {
console.error(`Blocked ${event.sender.getURL()} from calling method: ${method}`);
throw new Error(`Invalid method: ${method}`);
/**
* Current Electron behavior is to inherit all options from the parent window.
* In practical use, this is kind of annoying because consumers have to know
* about the parent window's preferences in order to unset them and makes child
* windows even more of an anomaly. In 11.0.0 we will remove this behavior and
* only critical security preferences will be inherited by default.
*/
function getDeprecatedInheritedOptions (embedder: WebContents) {
if (!(embedder as any).browserWindowOptions) {
// If it's a webview, return just the webPreferences.
return {
webPreferences: (embedder as any).getLastWebPreferences()
};
}
return (getGuestWindow(guestContents) as any)[method](...args);
});
const { type, show, ...inheritableOptions } = (embedder as any).browserWindowOptions;
return inheritableOptions;
}
handleMessage(IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE, (event, guestContents, message, targetOrigin, sourceOrigin) => {
if (targetOrigin == null) {
targetOrigin = '*';
function formatPostDataHeaders (postData: any) {
if (!postData) return;
let extraHeaders = 'content-type: application/x-www-form-urlencoded';
if (postData.length > 0) {
const postDataFront = postData[0].bytes.toString();
const boundary = /^--.*[^-\r\n]/.exec(
postDataFront
);
if (boundary != null) {
extraHeaders = `content-type: multipart/form-data; boundary=${boundary[0].substr(
2
)}`;
}
}
// The W3C does not seem to have word on how postMessage should work when the
// origins do not match, so we do not do |canAccessWindow| check here since
// postMessage across origins is useful and not harmful.
securityCheck(event.sender, guestContents, isRelatedWindow);
if (targetOrigin === '*' || isSameOrigin(guestContents.getURL(), targetOrigin)) {
const sourceId = event.sender.id;
guestContents._sendInternal(IPC_MESSAGES.GUEST_WINDOW_POSTMESSAGE, sourceId, message, sourceOrigin);
}
});
const webContentsMethodsAsync = new Set([
'loadURL',
'executeJavaScript',
'print'
]);
handleMessage(IPC_MESSAGES.GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD, (event, guestContents, method: string, ...args: any[]) => {
securityCheck(event.sender, guestContents, canAccessWindow);
if (!webContentsMethodsAsync.has(method)) {
console.error(`Blocked ${event.sender.getURL()} from calling method: ${method}`);
throw new Error(`Invalid method: ${method}`);
}
return (guestContents as any)[method](...args);
});
const webContentsMethodsSync = new Set([
'getURL'
]);
handleMessageSync(IPC_MESSAGES.GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD, (event, guestContents, method: string, ...args: any[]) => {
securityCheck(event.sender, guestContents, canAccessWindow);
if (!webContentsMethodsSync.has(method)) {
console.error(`Blocked ${event.sender.getURL()} from calling method: ${method}`);
throw new Error(`Invalid method: ${method}`);
}
return (guestContents as any)[method](...args);
});
return extraHeaders;
}

Просмотреть файл

@ -0,0 +1,211 @@
/**
* Manage guest windows when using the default BrowserWindowProxy version of the
* renderer's window.open (i.e. nativeWindowOpen off). This module mostly
* consists of marshaling IPC requests from the BrowserWindowProxy to the
* WebContents.
*/
import { webContents, BrowserWindow } from 'electron/main';
import type { WebContents } from 'electron/main';
import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal';
import * as ipcMainUtils from '@electron/internal/browser/ipc-main-internal-utils';
import { openGuestWindow } from '@electron/internal/browser/guest-window-manager';
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
const { isSameOrigin } = process._linkedBinding('electron_common_v8_util');
const getGuestWindow = function (guestContents: WebContents) {
let guestWindow = BrowserWindow.fromWebContents(guestContents);
if (guestWindow == null) {
const hostContents = guestContents.hostWebContents;
if (hostContents != null) {
guestWindow = BrowserWindow.fromWebContents(hostContents);
}
}
if (!guestWindow) {
throw new Error('getGuestWindow failed');
}
return guestWindow;
};
const isChildWindow = function (sender: WebContents, target: WebContents) {
return (target as any).getLastWebPreferences().openerId === sender.id;
};
const isRelatedWindow = function (sender: WebContents, target: WebContents) {
return isChildWindow(sender, target) || isChildWindow(target, sender);
};
const isScriptableWindow = function (sender: WebContents, target: WebContents) {
return (
isRelatedWindow(sender, target) &&
isSameOrigin(sender.getURL(), target.getURL())
);
};
const isNodeIntegrationEnabled = function (sender: WebContents) {
return (sender as any).getLastWebPreferences().nodeIntegration === true;
};
// Checks whether |sender| can access the |target|:
const canAccessWindow = function (sender: WebContents, target: WebContents) {
return (
isChildWindow(sender, target) ||
isScriptableWindow(sender, target) ||
isNodeIntegrationEnabled(sender)
);
};
// Routed window.open messages with raw options
ipcMainInternal.on(
IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_OPEN,
(
event,
url: string,
frameName: string,
features: string
) => {
// This should only be allowed for senders that have nativeWindowOpen: false
const lastWebPreferences = (event.sender as any).getLastWebPreferences();
if (lastWebPreferences.nativeWindowOpen || lastWebPreferences.sandbox) {
(event as any).returnValue = null;
throw new Error(
'GUEST_WINDOW_MANAGER_WINDOW_OPEN denied: expected native window.open'
);
}
const browserWindowOptions = (event.sender as any)._callWindowOpenHandler(event, url, frameName, features);
if (event.defaultPrevented) {
return;
}
const guest = openGuestWindow({
event,
embedder: event.sender,
referrer: { url: '', policy: 'default' },
disposition: 'new-window',
overrideBrowserWindowOptions: browserWindowOptions,
windowOpenArgs: {
url: url || 'about:blank',
frameName: frameName || '',
features: features || ''
}
});
(event as any).returnValue = guest ? guest.webContents.id : null;
}
);
type IpcHandler<T, Event> = (event: Event, guestContents: Electron.WebContents, ...args: any[]) => T;
const makeSafeHandler = function<T, Event> (handler: IpcHandler<T, Event>) {
return (event: Event, guestId: number, ...args: any[]) => {
// Access webContents via electron to prevent circular require.
const guestContents = webContents.fromId(guestId);
if (!guestContents) {
throw new Error(`Invalid guestId: ${guestId}`);
}
return handler(event, guestContents as Electron.WebContents, ...args);
};
};
const handleMessage = function (channel: string, handler: IpcHandler<any, Electron.IpcMainInvokeEvent>) {
ipcMainInternal.handle(channel, makeSafeHandler(handler));
};
const handleMessageSync = function (channel: string, handler: IpcHandler<any, ElectronInternal.IpcMainInternalEvent>) {
ipcMainUtils.handleSync(channel, makeSafeHandler(handler));
};
type ContentsCheck = (contents: WebContents, guestContents: WebContents) => boolean;
const securityCheck = function (contents: WebContents, guestContents: WebContents, check: ContentsCheck) {
if (!check(contents, guestContents)) {
console.error(
`Blocked ${contents.getURL()} from accessing guestId: ${guestContents.id}`
);
throw new Error(`Access denied to guestId: ${guestContents.id}`);
}
};
const windowMethods = new Set(['destroy', 'focus', 'blur']);
handleMessage(
IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_METHOD,
(event, guestContents, method, ...args) => {
securityCheck(event.sender, guestContents, canAccessWindow);
if (!windowMethods.has(method)) {
console.error(
`Blocked ${event.sender.getURL()} from calling method: ${method}`
);
throw new Error(`Invalid method: ${method}`);
}
return (getGuestWindow(guestContents) as any)[method](...args);
}
);
handleMessage(
IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE,
(event, guestContents, message, targetOrigin, sourceOrigin) => {
if (targetOrigin == null) {
targetOrigin = '*';
}
// The W3C does not seem to have word on how postMessage should work when the
// origins do not match, so we do not do |canAccessWindow| check here since
// postMessage across origins is useful and not harmful.
securityCheck(event.sender, guestContents, isRelatedWindow);
if (
targetOrigin === '*' ||
isSameOrigin(guestContents.getURL(), targetOrigin)
) {
const sourceId = event.sender.id;
guestContents._sendInternal(
IPC_MESSAGES.GUEST_WINDOW_POSTMESSAGE,
sourceId,
message,
sourceOrigin
);
}
}
);
const webContentsMethodsAsync = new Set([
'loadURL',
'executeJavaScript',
'print'
]);
handleMessage(
IPC_MESSAGES.GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD,
(event, guestContents, method, ...args) => {
securityCheck(event.sender, guestContents, canAccessWindow);
if (!webContentsMethodsAsync.has(method)) {
console.error(
`Blocked ${event.sender.getURL()} from calling method: ${method}`
);
throw new Error(`Invalid method: ${method}`);
}
return (guestContents as any)[method](...args);
}
);
const webContentsMethodsSync = new Set(['getURL']);
handleMessageSync(
IPC_MESSAGES.GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD,
(event, guestContents, method, ...args) => {
securityCheck(event.sender, guestContents, canAccessWindow);
if (!webContentsMethodsSync.has(method)) {
console.error(
`Blocked ${event.sender.getURL()} from calling method: ${method}`
);
throw new Error(`Invalid method: ${method}`);
}
return (guestContents as any)[method](...args);
}
);

Просмотреть файл

@ -76,7 +76,7 @@ require('@electron/internal/browser/rpc-server');
// Load the guest view manager.
require('@electron/internal/browser/guest-view-manager');
require('@electron/internal/browser/guest-window-manager');
require('@electron/internal/browser/guest-window-proxy');
// Now we try to load app's package.json.
let packagePath = null;

Просмотреть файл

@ -123,11 +123,13 @@ export class NavigationController extends EventEmitter {
this.webContents.removeListener('did-fail-load', failListener);
this.webContents.removeListener('did-start-navigation', navigationListener);
this.webContents.removeListener('did-stop-loading', stopLoadingListener);
this.webContents.removeListener('destroyed', stopLoadingListener);
};
this.webContents.on('did-finish-load', finishListener);
this.webContents.on('did-fail-load', failListener);
this.webContents.on('did-start-navigation', navigationListener);
this.webContents.on('did-stop-loading', stopLoadingListener);
this.webContents.on('destroyed', stopLoadingListener);
});
// Add a no-op rejection handler to silence the unhandled rejection error.
p.catch(() => {});

Просмотреть файл

@ -81,7 +81,7 @@ type AllowedWebPreference = (typeof allowedWebPreferences)[number];
/**
* Parses a feature string that has the format used in window.open().
*
* `useSoonToBeDeprecatedBehaviorForBareKeys` In the html spec, windowFeatures keys
* `useSoonToBeDeprecatedBehaviorForBareKeys` - In the html spec, windowFeatures keys
* without values are interpreted as `true`. Previous versions of Electron did
* not respect this. In order to not break any applications, this will be
* flipped in the next major version.
@ -103,7 +103,7 @@ export function parseFeatures (
if (parsed.top !== undefined) parsed.y = parsed.top;
return {
options: parsed as Omit<BrowserWindowConstructorOptions, 'webPreferences'> & { [key: string]: CoercedValue },
options: parsed as Omit<BrowserWindowConstructorOptions, 'webPreferences'>,
webPreferences,
additionalFeatures: bareKeys
};

Просмотреть файл

@ -1,7 +1,7 @@
const { hasSwitch } = process._linkedBinding('electron_common_command_line');
const { getWebPreference } = process._linkedBinding('electron_renderer_web_frame');
const binding = process._linkedBinding('electron_renderer_context_bridge');
const contextIsolationEnabled = hasSwitch('context-isolation');
const contextIsolationEnabled = getWebPreference(window, 'contextIsolation');
const checkContextIsolationEnabled = () => {
if (!contextIsolationEnabled) throw new Error('contextBridge API can only be used when contextIsolation is enabled');

Просмотреть файл

@ -55,31 +55,33 @@ webFrameInit();
// Process command line arguments.
const { hasSwitch, getSwitchValue } = process._linkedBinding('electron_common_command_line');
const { getWebPreference } = process._linkedBinding('electron_renderer_web_frame');
const parseOption = function<T> (
name: string, defaultValue: T, converter?: (value: string) => T
const parseOption = function<TDefault> (
name: string, defaultValue: TDefault, converter?: (value: string) => any
) {
return hasSwitch(name)
const value = getWebPreference(window, name);
return value
? (
converter
? converter(getSwitchValue(name))
: getSwitchValue(name)
? converter(value)
: value
)
: defaultValue;
};
const contextIsolation = hasSwitch('context-isolation');
const nodeIntegration = hasSwitch('node-integration');
const webviewTag = hasSwitch('webview-tag');
const isHiddenPage = hasSwitch('hidden-page');
const usesNativeWindowOpen = hasSwitch('native-window-open');
const rendererProcessReuseEnabled = hasSwitch('disable-electron-site-instance-overrides');
const contextIsolation = getWebPreference(window, 'contextIsolation');
const nodeIntegration = getWebPreference(window, 'nodeIntegration');
const webviewTag = getWebPreference(window, 'webviewTag');
const isHiddenPage = getWebPreference(window, 'hiddenPage');
const usesNativeWindowOpen = getWebPreference(window, 'nativeWindowOpen');
const rendererProcessReuseEnabled = getWebPreference(window, 'disableElectronSiteInstanceOverrides');
const preloadScript = parseOption('preload', null);
const preloadScripts = parseOption('preload-scripts', [], value => value.split(path.delimiter)) as string[];
const appPath = parseOption('app-path', null);
const guestInstanceId = parseOption('guest-instance-id', null, value => parseInt(value));
const openerId = parseOption('opener-id', null, value => parseInt(value));
const preloadScripts = parseOption('preloadScripts', []);
const guestInstanceId = parseOption('guestInstanceId', null, value => parseInt(value));
const openerId = parseOption('openerId', null, value => parseInt(value));
const appPath = hasSwitch('app-path') ? getSwitchValue('app-path') : null;
// The webContents preload script is loaded after the session preload scripts.
if (preloadScript) {

Просмотреть файл

@ -114,6 +114,7 @@ function preloadRequire (module: string) {
// Process command line arguments.
const { hasSwitch } = process._linkedBinding('electron_common_command_line');
const { getWebPreference } = process._linkedBinding('electron_renderer_web_frame');
// Similar to nodes --expose-internals flag, this exposes _linkedBinding so
// that tests can call it to get access to some test only bindings
@ -121,9 +122,9 @@ if (hasSwitch('unsafely-expose-electron-internals-for-testing')) {
preloadProcess._linkedBinding = process._linkedBinding;
}
const contextIsolation = hasSwitch('context-isolation');
const isHiddenPage = hasSwitch('hidden-page');
const rendererProcessReuseEnabled = hasSwitch('disable-electron-site-instance-overrides');
const contextIsolation = getWebPreference(window, 'contextIsolation');
const isHiddenPage = getWebPreference(window, 'hiddenPage');
const rendererProcessReuseEnabled = getWebPreference(window, 'disableElectronSiteInstanceOverrides');
const usesNativeWindowOpen = true;
switch (window.location.protocol) {

Просмотреть файл

@ -4,7 +4,7 @@
"repository": "https://github.com/electron/electron",
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
"devDependencies": {
"@electron/docs-parser": "^0.10.0",
"@electron/docs-parser": "^0.10.1",
"@electron/typescript-definitions": "^8.8.0",
"@octokit/auth-app": "^2.10.0",
"@octokit/rest": "^18.0.3",
@ -148,4 +148,4 @@
"@types/temp": "^0.8.34",
"aws-sdk": "^2.727.1"
}
}
}

Просмотреть файл

@ -83,6 +83,7 @@ feat_allow_embedders_to_add_observers_on_created_hunspell.patch
feat_add_onclose_to_messageport.patch
web_contents.patch
ui_gtk_public_header.patch
allow_in_process_windows_to_have_different_web_prefs.patch
refactor_expose_cursor_changes_to_the_webcontentsobserver.patch
crash_allow_setting_more_options.patch
breakpad_treat_node_processes_as_browser_processes.patch
@ -97,6 +98,7 @@ remove_some_deps_that_do_not_work_on_arm64.patch
fix_check_issecureeventinputenabled_in_constructor_before_setting.patch
skip_atk_toolchain_check.patch
worker_feat_add_hook_to_notify_script_ready.patch
chore_provide_iswebcontentscreationoverridden_with_full_params.patch
fix_properly_honor_printing_page_ranges.patch
fix_use_electron_generated_resources.patch
chore_expose_v8_initialization_isolate_callbacks.patch

Просмотреть файл

@ -0,0 +1,279 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Andy Locascio <andy@slack-corp.com>
Date: Wed, 6 May 2020 16:37:54 -0700
Subject: allow in-process windows to have different web prefs
Allow earlier access to newly created WebContents so that we can change
WebPreferences of in-process child windows, rather than relying on
process-level command line switches, as before.
diff --git a/third_party/blink/common/web_preferences/web_preferences.cc b/third_party/blink/common/web_preferences/web_preferences.cc
index 1e51bb68df930c44e165b32c8c03b99986792209..9535330e3e7a3c4621e96eadbf90f4da2bf2daf0 100644
--- a/third_party/blink/common/web_preferences/web_preferences.cc
+++ b/third_party/blink/common/web_preferences/web_preferences.cc
@@ -143,6 +143,29 @@ WebPreferences::WebPreferences()
navigate_on_drag_drop(true),
v8_cache_options(blink::mojom::V8CacheOptions::kDefault),
record_whole_document(false),
+
+ // Begin Electron-specific WebPreferences.
+ disable_electron_site_instance_overrides(),
+ background_color(base::EmptyString()),
+ opener_id(0),
+ context_isolation(false),
+ enable_remote_module(false),
+ world_safe_execute_javascript(false),
+ guest_instance_id(0),
+ hidden_page(false),
+ offscreen(false),
+ preload(base::FilePath::StringType()),
+ native_window_open(false),
+ node_integration(false),
+ node_integration_in_worker(false),
+ node_leakage_in_renderers(false),
+ node_integration_in_sub_frames(false),
+ enable_spellcheck(false),
+ enable_plugins(false),
+ enable_websql(false),
+ webview_tag(false),
+ // End Electron-specific WebPreferences.
+
cookie_enabled(true),
accelerated_video_decode_enabled(false),
animation_policy(
diff --git a/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc b/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc
index 912c1bf5919bc657a4903d3fbca60c1013aa9d98..b3759ab22c071ad94062f6c3f7c24920ba3cde47 100644
--- a/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc
+++ b/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc
@@ -144,6 +144,11 @@ bool StructTraits<blink::mojom::WebPreferencesDataView,
!data.ReadCursiveFontFamilyMap(&out->cursive_font_family_map) ||
!data.ReadFantasyFontFamilyMap(&out->fantasy_font_family_map) ||
!data.ReadPictographFontFamilyMap(&out->pictograph_font_family_map) ||
+ // Begin Electron-specific WebPreferences.
+ !data.ReadPreloads(&out->preloads) ||
+ !data.ReadBackgroundColor(&out->background_color) ||
+ !data.ReadPreload(&out->preload) ||
+ // End Electron-specific WebPreferences.
!data.ReadLazyFrameLoadingDistanceThresholdsPx(
&out->lazy_frame_loading_distance_thresholds_px) ||
!data.ReadLazyImageLoadingDistanceThresholdsPx(
@@ -267,6 +272,27 @@ bool StructTraits<blink::mojom::WebPreferencesDataView,
out->navigate_on_drag_drop = data.navigate_on_drag_drop();
out->v8_cache_options = data.v8_cache_options();
out->record_whole_document = data.record_whole_document();
+
+ // Begin Electron-specific WebPreferences.
+ out->disable_electron_site_instance_overrides = data.disable_electron_site_instance_overrides();
+ out->opener_id = data.opener_id();
+ out->context_isolation = data.context_isolation();
+ out->enable_remote_module = data.enable_remote_module();
+ out->world_safe_execute_javascript = data.world_safe_execute_javascript();
+ out->guest_instance_id = data.guest_instance_id();
+ out->hidden_page = data.hidden_page();
+ out->offscreen = data.offscreen();
+ out->native_window_open = data.native_window_open();
+ out->node_integration = data.node_integration();
+ out->node_integration_in_worker = data.node_integration_in_worker();
+ out->node_leakage_in_renderers = data.node_leakage_in_renderers();
+ out->node_integration_in_sub_frames = data.node_integration_in_sub_frames();
+ out->enable_spellcheck = data.enable_spellcheck();
+ out->enable_plugins = data.enable_plugins();
+ out->enable_websql = data.enable_websql();
+ out->webview_tag = data.webview_tag();
+ // End Electron-specific WebPreferences.
+
out->cookie_enabled = data.cookie_enabled();
out->accelerated_video_decode_enabled =
data.accelerated_video_decode_enabled();
diff --git a/third_party/blink/public/common/web_preferences/web_preferences.h b/third_party/blink/public/common/web_preferences/web_preferences.h
index 81e4729f540ff272a43c77045187fe3d4bde3ea0..3a2c60f7616f724d3a0399f7fe8becae60d6ae88 100644
--- a/third_party/blink/public/common/web_preferences/web_preferences.h
+++ b/third_party/blink/public/common/web_preferences/web_preferences.h
@@ -9,6 +9,7 @@
#include <string>
#include <vector>
+#include "base/files/file_path.h"
#include "base/strings/string16.h"
#include "base/time/time.h"
#include "build/build_config.h"
@@ -154,6 +155,29 @@ struct BLINK_COMMON_EXPORT WebPreferences {
blink::mojom::V8CacheOptions v8_cache_options;
bool record_whole_document;
+ // Begin Electron-specific WebPreferences.
+ std::vector<base::FilePath> preloads;
+ bool disable_electron_site_instance_overrides;
+ std::string background_color;
+ int opener_id;
+ bool context_isolation;
+ bool enable_remote_module;
+ bool world_safe_execute_javascript;
+ int guest_instance_id;
+ bool hidden_page;
+ bool offscreen;
+ base::FilePath preload;
+ bool native_window_open;
+ bool node_integration;
+ bool node_integration_in_worker;
+ bool node_leakage_in_renderers;
+ bool node_integration_in_sub_frames;
+ bool enable_spellcheck;
+ bool enable_plugins;
+ bool enable_websql;
+ bool webview_tag;
+ // End Electron-specific WebPreferences.
+
// This flags corresponds to a Page's Settings' setCookieEnabled state. It
// only controls whether or not the "document.cookie" field is properly
// connected to the backing store, for instance if you wanted to be able to
diff --git a/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h b/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h
index 74b22fbaad5c8ae911dca4b26bbfffd8e9079856..decef06a6d0cda2da8aa3c88d589dbff75ff369e 100644
--- a/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h
+++ b/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h
@@ -6,6 +6,7 @@
#define THIRD_PARTY_BLINK_PUBLIC_COMMON_WEB_PREFERENCES_WEB_PREFERENCES_MOJOM_TRAITS_H_
#include "build/build_config.h"
+#include "mojo/public/cpp/base/file_path_mojom_traits.h"
#include "mojo/public/cpp/bindings/struct_traits.h"
#include "net/nqe/effective_connection_type.h"
#include "third_party/blink/public/common/common_export.h"
@@ -452,6 +453,88 @@ struct BLINK_COMMON_EXPORT StructTraits<blink::mojom::WebPreferencesDataView,
return r.record_whole_document;
}
+ // Begin Electron-specific WebPreferences.
+ static const std::vector<base::FilePath>& preloads(const blink::web_pref::WebPreferences& r) {
+ return r.preloads;
+ }
+
+ static bool disable_electron_site_instance_overrides(const blink::web_pref::WebPreferences& r) {
+ return r.disable_electron_site_instance_overrides;
+ }
+
+ static const std::string& background_color(const blink::web_pref::WebPreferences& r) {
+ return r.background_color;
+ }
+
+ static int opener_id(const blink::web_pref::WebPreferences& r) {
+ return r.opener_id;
+ }
+
+ static bool context_isolation(const blink::web_pref::WebPreferences& r) {
+ return r.context_isolation;
+ }
+
+ static bool enable_remote_module(const blink::web_pref::WebPreferences& r) {
+ return r.enable_remote_module;
+ }
+
+ static bool world_safe_execute_javascript(const blink::web_pref::WebPreferences& r) {
+ return r.world_safe_execute_javascript;
+ }
+
+ static int guest_instance_id(const blink::web_pref::WebPreferences& r) {
+ return r.guest_instance_id;
+ }
+
+ static bool hidden_page(const blink::web_pref::WebPreferences& r) {
+ return r.hidden_page;
+ }
+
+ static bool offscreen(const blink::web_pref::WebPreferences& r) {
+ return r.offscreen;
+ }
+
+ static const base::FilePath& preload(const blink::web_pref::WebPreferences& r) {
+ return r.preload;
+ }
+
+ static bool native_window_open(const blink::web_pref::WebPreferences& r) {
+ return r.native_window_open;
+ }
+
+ static bool node_integration(const blink::web_pref::WebPreferences& r) {
+ return r.node_integration;
+ }
+
+ static bool node_integration_in_worker(const blink::web_pref::WebPreferences& r) {
+ return r.node_integration_in_worker;
+ }
+
+ static bool node_leakage_in_renderers(const blink::web_pref::WebPreferences& r) {
+ return r.node_leakage_in_renderers;
+ }
+
+ static bool node_integration_in_sub_frames(const blink::web_pref::WebPreferences& r) {
+ return r.node_integration_in_sub_frames;
+ }
+
+ static bool enable_spellcheck(const blink::web_pref::WebPreferences& r) {
+ return r.enable_spellcheck;
+ }
+
+ static bool enable_plugins(const blink::web_pref::WebPreferences& r) {
+ return r.enable_plugins;
+ }
+
+ static bool enable_websql(const blink::web_pref::WebPreferences& r) {
+ return r.enable_websql;
+ }
+
+ static bool webview_tag(const blink::web_pref::WebPreferences& r) {
+ return r.webview_tag;
+ }
+ // End Electron-specific WebPreferences.
+
static bool cookie_enabled(const blink::web_pref::WebPreferences& r) {
return r.cookie_enabled;
}
diff --git a/third_party/blink/public/mojom/webpreferences/web_preferences.mojom b/third_party/blink/public/mojom/webpreferences/web_preferences.mojom
index ac1099c8fb923184a014bf9cbaa35c496cf85cd9..688ea93b1d067555b7b48165ba7a33625f9d597f 100644
--- a/third_party/blink/public/mojom/webpreferences/web_preferences.mojom
+++ b/third_party/blink/public/mojom/webpreferences/web_preferences.mojom
@@ -8,6 +8,7 @@ import "third_party/blink/public/mojom/css/preferred_color_scheme.mojom";
import "third_party/blink/public/mojom/v8_cache_options.mojom";
import "url/mojom/url.mojom";
import "mojo/public/mojom/base/string16.mojom";
+import "mojo/public/mojom/base/file_path.mojom";
enum PointerType {
kPointerFirstType = 1, // 1 << 0
@@ -202,6 +203,29 @@ struct WebPreferences {
V8CacheOptions v8_cache_options;
bool record_whole_document;
+ // Begin Electron-specific WebPreferences.
+ array<mojo_base.mojom.FilePath> preloads;
+ bool disable_electron_site_instance_overrides;
+ string background_color;
+ int32 opener_id;
+ bool context_isolation;
+ bool enable_remote_module;
+ bool world_safe_execute_javascript;
+ int32 guest_instance_id;
+ bool hidden_page;
+ bool offscreen;
+ mojo_base.mojom.FilePath preload;
+ bool native_window_open;
+ bool node_integration;
+ bool node_integration_in_worker;
+ bool node_leakage_in_renderers;
+ bool node_integration_in_sub_frames;
+ bool enable_spellcheck;
+ bool enable_plugins;
+ bool enable_websql;
+ bool webview_tag;
+ // End Electron-specific WebPreferences.
+
// This flags corresponds to a Page's Settings' setCookieEnabled state. It
// only controls whether or not the "document.cookie" field is properly
// connected to the backing store, for instance if you wanted to be able to
@@ -428,4 +452,4 @@ struct WebPreferences {
// Whether touch input can trigger HTML drag-and-drop operations. The
// default value depends on the platform.
bool touch_drag_drop_enabled;
-};
\ No newline at end of file
+};

Просмотреть файл

@ -21,22 +21,37 @@ index 365d0d8cf45c664160048a7a9606907cb5414292..dd52048e922904826c5b31d13f17dfc9
&no_javascript_access);
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 962cd0fb5a428530cd9e2f8e689f2d09bc95ce1b..e099a6cc44e73da8b24603fd86b72139f0735fb2 100644
index 962cd0fb5a428530cd9e2f8e689f2d09bc95ce1b..ea458219bd182bd9ff21b203c282e7d0738049dd 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -3624,9 +3624,9 @@ RenderFrameHostDelegate* WebContentsImpl::CreateNewWindow(
@@ -3582,6 +3582,14 @@ RenderFrameHostDelegate* WebContentsImpl::CreateNewWindow(
}
auto* new_contents_impl = new_contents.get();
if (delegate_) {
- delegate_->WebContentsCreated(this, render_process_id,
- opener->GetRoutingID(), params.frame_name,
- params.target_url, new_contents_impl);
+ // Call this earlier than Chrome to associate the web preferences with the
+ // WebContents before the view gets created.
+ if (delegate_) {
+ delegate_->WebContentsCreatedWithFullParams(this, render_process_id,
+ opener->GetRoutingID(),
+ params, new_contents_impl);
+ }
+
new_contents_impl->GetController().SetSessionStorageNamespace(
partition_id, session_storage_namespace);
@@ -3623,12 +3631,6 @@ RenderFrameHostDelegate* WebContentsImpl::CreateNewWindow(
AddDestructionObserver(new_contents_impl);
}
- if (delegate_) {
- delegate_->WebContentsCreated(this, render_process_id,
- opener->GetRoutingID(), params.frame_name,
- params.target_url, new_contents_impl);
- }
-
observers_.ForEachObserver([&](WebContentsObserver* observer) {
observer->DidOpenRequestedURL(new_contents_impl, opener, params.target_url,
params.referrer.To<Referrer>(),
diff --git a/content/common/frame.mojom b/content/common/frame.mojom
index 703c4611691b72380423576eebdadcd23e6ae913..2be0f93b7ea3791bb776158795a44aa7422e19ac 100644
--- a/content/common/frame.mojom

Просмотреть файл

@ -0,0 +1,433 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Andy Locascio <andy@slack-corp.com>
Date: Wed, 9 Sep 2020 16:56:06 -0700
Subject: chore: provide IsWebContentsCreationOverridden with full params
Pending upstream patch, this gives us fuller access to the window.open params
so that we will be able to decide whether to cancel it or not.
diff --git a/chrome/browser/android/document/document_web_contents_delegate.cc b/chrome/browser/android/document/document_web_contents_delegate.cc
index 0e90487923c57c0570e73ef0f0e8c5acc2576932..fcdc88233b2277f3b37a2a2b0bdee7d71b721bf8 100644
--- a/chrome/browser/android/document/document_web_contents_delegate.cc
+++ b/chrome/browser/android/document/document_web_contents_delegate.cc
@@ -46,8 +46,7 @@ bool DocumentWebContentsDelegate::IsWebContentsCreationOverridden(
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) {
+ const mojom::CreateNewWindowParams& params) {
NOTREACHED();
return true;
}
diff --git a/chrome/browser/android/document/document_web_contents_delegate.h b/chrome/browser/android/document/document_web_contents_delegate.h
index 5b4d70991e19edcdfee731c56251932bf43e535f..fe1977c5e6ce0f5b30e8be529b9efa51785db57f 100644
--- a/chrome/browser/android/document/document_web_contents_delegate.h
+++ b/chrome/browser/android/document/document_web_contents_delegate.h
@@ -41,8 +41,7 @@ class DocumentWebContentsDelegate
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) override;
+ const mojom::CreateNewWindowParams& params) override;
};
#endif // CHROME_BROWSER_ANDROID_DOCUMENT_DOCUMENT_WEB_CONTENTS_DELEGATE_H_
diff --git a/chrome/browser/chromeos/first_run/drive_first_run_controller.cc b/chrome/browser/chromeos/first_run/drive_first_run_controller.cc
index a52c550f1aeadcdb36948078ed5fec24838c3da8..4aaddf84c0b3574218df5bdea77a72967271d5a8 100644
--- a/chrome/browser/chromeos/first_run/drive_first_run_controller.cc
+++ b/chrome/browser/chromeos/first_run/drive_first_run_controller.cc
@@ -123,8 +123,7 @@ class DriveWebContentsManager : public content::WebContentsObserver,
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) override;
+ const mojom::CreateNewWindowParams& params) override;
content::WebContents* CreateCustomWebContents(
content::RenderFrameHost* opener,
content::SiteInstance* source_site_instance,
@@ -234,15 +233,14 @@ bool DriveWebContentsManager::IsWebContentsCreationOverridden(
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) {
+ const mojom::CreateNewWindowParams& params) {
if (window_container_type == content::mojom::WindowContainerType::NORMAL)
return false;
// Check that the target URL is for the Drive app.
const extensions::Extension* extension =
extensions::ExtensionRegistry::Get(profile_)
- ->enabled_extensions().GetAppByURL(target_url);
+ ->enabled_extensions().GetAppByURL(params.target_url);
return extension && extension->id() == app_id_;
}
diff --git a/chrome/browser/media/offscreen_tab.cc b/chrome/browser/media/offscreen_tab.cc
index aba8e2273c98d2dc9a01a698f8de187056b3ce01..5141b4d1a711416f4dfc030838b9cf22e7613f8b 100644
--- a/chrome/browser/media/offscreen_tab.cc
+++ b/chrome/browser/media/offscreen_tab.cc
@@ -282,8 +282,7 @@ bool OffscreenTab::IsWebContentsCreationOverridden(
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) {
+ const mojom::CreateNewWindowParams& params) {
// Disallow creating separate WebContentses. The WebContents implementation
// uses this to spawn new windows/tabs, which is also not allowed for
// offscreen tabs.
diff --git a/chrome/browser/media/offscreen_tab.h b/chrome/browser/media/offscreen_tab.h
index fb09bf2c5d22e3838575403b53867d0021e13b67..36e7982bbcc7c8b50bb2942ada39862bad4bbc22 100644
--- a/chrome/browser/media/offscreen_tab.h
+++ b/chrome/browser/media/offscreen_tab.h
@@ -106,8 +106,7 @@ class OffscreenTab final : public ProfileObserver,
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) final;
+ const mojom::CreateNewWindowParams& params) override;
void EnterFullscreenModeForTab(
content::RenderFrameHost* requesting_frame,
const blink::mojom::FullscreenOptions& options) final;
diff --git a/chrome/browser/ui/ash/assistant/assistant_web_view_impl.cc b/chrome/browser/ui/ash/assistant/assistant_web_view_impl.cc
index 672d5d41e33178ed6c6f62156e69b1adaf099fe8..4c0f8db8a9c40c34df8abfa89d88b0ceaef76392 100644
--- a/chrome/browser/ui/ash/assistant/assistant_web_view_impl.cc
+++ b/chrome/browser/ui/ash/assistant/assistant_web_view_impl.cc
@@ -77,10 +77,9 @@ bool AssistantWebViewImpl::IsWebContentsCreationOverridden(
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) {
+ const mojom::CreateNewWindowParams& params) {
if (params_.suppress_navigation) {
- NotifyDidSuppressNavigation(target_url,
+ NotifyDidSuppressNavigation(params.target_url,
WindowOpenDisposition::NEW_FOREGROUND_TAB,
/*from_user_gesture=*/true);
return true;
diff --git a/chrome/browser/ui/ash/assistant/assistant_web_view_impl.h b/chrome/browser/ui/ash/assistant/assistant_web_view_impl.h
index 07014765f33bdddebcc5bc32a2713d6523faf394..f866f69f9c810d89f1a0e9e4952293f66804602a 100644
--- a/chrome/browser/ui/ash/assistant/assistant_web_view_impl.h
+++ b/chrome/browser/ui/ash/assistant/assistant_web_view_impl.h
@@ -48,8 +48,7 @@ class AssistantWebViewImpl : public ash::AssistantWebView,
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) override;
+ const mojom::CreateNewWindowParams& params) override;
content::WebContents* OpenURLFromTab(
content::WebContents* source,
const content::OpenURLParams& params) override;
diff --git a/chrome/browser/ui/ash/keyboard/chrome_keyboard_web_contents.cc b/chrome/browser/ui/ash/keyboard/chrome_keyboard_web_contents.cc
index 3d9b343765bdca5723a94e00db1426308a641a50..57afd89cb06ff255f126c7f7784f10e7689cefe3 100644
--- a/chrome/browser/ui/ash/keyboard/chrome_keyboard_web_contents.cc
+++ b/chrome/browser/ui/ash/keyboard/chrome_keyboard_web_contents.cc
@@ -64,8 +64,7 @@ class ChromeKeyboardContentsDelegate : public content::WebContentsDelegate,
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) override {
+ const mojom::CreateNewWindowParams& params) override {
return true;
}
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 30a8f5eeaedb9bc186faabca645917bc53e7f041..8e7316a1255f9de8f3374b7ed99a8c8f42701b43 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -1818,12 +1818,11 @@ bool Browser::IsWebContentsCreationOverridden(
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) {
+ const mojom::CreateNewWindowParams& params) {
return window_container_type ==
content::mojom::WindowContainerType::BACKGROUND &&
ShouldCreateBackgroundContents(source_site_instance, opener_url,
- frame_name);
+ params->frame_name);
}
WebContents* Browser::CreateCustomWebContents(
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index 79cde7e1b913e91a15405a0ae1cd7e97fa11971e..b5f00b336b0e15e675f8ce03997343f24b5b0e51 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -769,8 +769,7 @@ class Browser : public TabStripModelObserver,
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) override;
+ const mojom::CreateNewWindowParams& params) override;
content::WebContents* CreateCustomWebContents(
content::RenderFrameHost* opener,
content::SiteInstance* source_site_instance,
diff --git a/chrome/browser/ui/media_router/presentation_receiver_window_controller.cc b/chrome/browser/ui/media_router/presentation_receiver_window_controller.cc
index 41177655d0608837ff7af7b944f22b1e657c68f6..6068228781eb1dabe1890f9121a3f86df4f6ac52 100644
--- a/chrome/browser/ui/media_router/presentation_receiver_window_controller.cc
+++ b/chrome/browser/ui/media_router/presentation_receiver_window_controller.cc
@@ -201,8 +201,7 @@ bool PresentationReceiverWindowController::IsWebContentsCreationOverridden(
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) {
+ const mojom::CreateNewWindowParams& params) {
// Disallow creating separate WebContentses. The WebContents implementation
// uses this to spawn new windows/tabs, which is also not allowed for
// local presentations.
diff --git a/chrome/browser/ui/media_router/presentation_receiver_window_controller.h b/chrome/browser/ui/media_router/presentation_receiver_window_controller.h
index 058ec72442d59989c4d6df4a7c791ecfeff0ef99..f7c8c2139382cb2e290c561624291afe647383cf 100644
--- a/chrome/browser/ui/media_router/presentation_receiver_window_controller.h
+++ b/chrome/browser/ui/media_router/presentation_receiver_window_controller.h
@@ -99,8 +99,7 @@ class PresentationReceiverWindowController final
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) override;
+ const mojom::CreateNewWindowParams& params) override;
// The profile used for the presentation.
Profile* otr_profile_;
diff --git a/components/embedder_support/android/delegate/web_contents_delegate_android.cc b/components/embedder_support/android/delegate/web_contents_delegate_android.cc
index 420803e98b1dde758dc72ba5a481f0b7cbde836b..633353c180aa748c2d80eb07412bfd0ffcf07ae3 100644
--- a/components/embedder_support/android/delegate/web_contents_delegate_android.cc
+++ b/components/embedder_support/android/delegate/web_contents_delegate_android.cc
@@ -167,14 +167,13 @@ bool WebContentsDelegateAndroid::IsWebContentsCreationOverridden(
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) {
+ const mojom::CreateNewWindowParams& params) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
if (obj.is_null())
return false;
ScopedJavaLocalRef<jstring> java_url =
- ConvertUTF8ToJavaString(env, target_url.spec());
+ ConvertUTF8ToJavaString(env, params.target_url.spec());
return !Java_WebContentsDelegateAndroid_shouldCreateWebContents(env, obj,
java_url);
}
diff --git a/components/embedder_support/android/delegate/web_contents_delegate_android.h b/components/embedder_support/android/delegate/web_contents_delegate_android.h
index fdd6866f595974f5a38e288a48b1e386a33c54d1..653981ffa4f58e727b2d7a2631f6213e3790c39f 100644
--- a/components/embedder_support/android/delegate/web_contents_delegate_android.h
+++ b/components/embedder_support/android/delegate/web_contents_delegate_android.h
@@ -78,8 +78,7 @@ class WebContentsDelegateAndroid : public content::WebContentsDelegate {
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) override;
+ const mojom::CreateNewWindowParams& params) override;
void CloseContents(content::WebContents* source) override;
void SetContentsBounds(content::WebContents* source,
const gfx::Rect& bounds) override;
diff --git a/components/offline_pages/content/background_loader/background_loader_contents.cc b/components/offline_pages/content/background_loader/background_loader_contents.cc
index 53fad64f87a952fd0d7398958288ecde259b57bf..0b8359b6179bf16e58978e5f3e51a911ad3d0a3f 100644
--- a/components/offline_pages/content/background_loader/background_loader_contents.cc
+++ b/components/offline_pages/content/background_loader/background_loader_contents.cc
@@ -80,8 +80,7 @@ bool BackgroundLoaderContents::IsWebContentsCreationOverridden(
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) {
+ const mojom::CreateNewWindowParams& params) {
// Background pages should not create other webcontents/tabs.
return true;
}
diff --git a/components/offline_pages/content/background_loader/background_loader_contents.h b/components/offline_pages/content/background_loader/background_loader_contents.h
index c5c5a7b63b5b3b62a9517cbef3ae23ce57a3c89c..4f1b7e88d6d2ae89a60311c8aeb1fceea87f2b02 100644
--- a/components/offline_pages/content/background_loader/background_loader_contents.h
+++ b/components/offline_pages/content/background_loader/background_loader_contents.h
@@ -60,8 +60,7 @@ class BackgroundLoaderContents : public content::WebContentsDelegate {
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) override;
+ const mojom::CreateNewWindowParams& params) override;
void AddNewContents(content::WebContents* source,
std::unique_ptr<content::WebContents> new_contents,
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 2a80aaa5d4421bf2b3a46cc1674256944b33a1fa..409c300c3831bb3fd3f0a019fb6e85bd866a705a 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -3543,8 +3543,7 @@ RenderFrameHostDelegate* WebContentsImpl::CreateNewWindow(
if (delegate_ && delegate_->IsWebContentsCreationOverridden(
source_site_instance, params.window_container_type,
- opener->GetLastCommittedURL(), params.frame_name,
- params.target_url)) {
+ opener->GetLastCommittedURL(), params)) {
return static_cast<WebContentsImpl*>(delegate_->CreateCustomWebContents(
opener, source_site_instance, is_new_browsing_instance,
opener->GetLastCommittedURL(), params.frame_name, params.target_url,
diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc
index b0513d20bd48fe8ffe8398b5387e13545749c508..7ce75c95771cc0053db01ec5318a68624bae9f4d 100644
--- a/content/public/browser/web_contents_delegate.cc
+++ b/content/public/browser/web_contents_delegate.cc
@@ -134,8 +134,7 @@ bool WebContentsDelegate::IsWebContentsCreationOverridden(
SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) {
+ const mojom::CreateNewWindowParams& params) {
return false;
}
diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h
index 94f576a6d52731f92c65adb958be5ca0a3391d4c..33359363fa18364d254aab5360f4c952f358bd17 100644
--- a/content/public/browser/web_contents_delegate.h
+++ b/content/public/browser/web_contents_delegate.h
@@ -317,8 +317,7 @@ class CONTENT_EXPORT WebContentsDelegate {
SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url);
+ const mojom::CreateNewWindowParams& params);
// Allow delegate to creates a custom WebContents when
// WebContents::CreateNewWindow() is called. This function is only called
diff --git a/extensions/browser/guest_view/extension_options/extension_options_guest.cc b/extensions/browser/guest_view/extension_options/extension_options_guest.cc
index bda659c7a464a58413e7eb33a897065268ab3fc6..29950878aca7f1518265561dea79b78d82230982 100644
--- a/extensions/browser/guest_view/extension_options/extension_options_guest.cc
+++ b/extensions/browser/guest_view/extension_options/extension_options_guest.cc
@@ -212,8 +212,7 @@ bool ExtensionOptionsGuest::IsWebContentsCreationOverridden(
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) {
+ const content::mojom::CreateNewWindowParams& params) {
// This method handles opening links from within the guest. Since this guest
// view is used for displaying embedded extension options, we want any
// external links to be opened in a new tab, not in a new guest view so we
diff --git a/extensions/browser/guest_view/extension_options/extension_options_guest.h b/extensions/browser/guest_view/extension_options/extension_options_guest.h
index 97273c32a05acf325fd0de22c4f79c1746aa23bc..4b357acd069387963347d35d82371b955147893f 100644
--- a/extensions/browser/guest_view/extension_options/extension_options_guest.h
+++ b/extensions/browser/guest_view/extension_options/extension_options_guest.h
@@ -55,8 +55,7 @@ class ExtensionOptionsGuest
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) final;
+ const content::mojom::CreateNewWindowParams& params) final;
content::WebContents* CreateCustomWebContents(
content::RenderFrameHost* opener,
content::SiteInstance* source_site_instance,
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
index 998d6d0c481fd49ff3a8a852e05347179f80b276..6ce9f2e9e8031d9abf03da7e656f221ce0912790 100644
--- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
+++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
@@ -380,8 +380,7 @@ bool MimeHandlerViewGuest::IsWebContentsCreationOverridden(
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) {
+ const content::mojom::CreateNewWindowParams& params) {
return true;
}
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h
index a7f0b19a8ab9bac6f1315ebd715d8e1b134edfe1..cbe2912d4ab2d9015396bbddf7836e106d0bff8b 100644
--- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h
+++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h
@@ -155,8 +155,7 @@ class MimeHandlerViewGuest
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) override;
+ const content::mojom::CreateNewWindowParams& params) override;
content::WebContents* CreateCustomWebContents(
content::RenderFrameHost* opener,
content::SiteInstance* source_site_instance,
diff --git a/fuchsia/engine/browser/frame_impl.cc b/fuchsia/engine/browser/frame_impl.cc
index 32a8e39b23bdf962b88eba3a40346febfbac298a..bc120621e1df1921651f3323650a8644ff688933 100644
--- a/fuchsia/engine/browser/frame_impl.cc
+++ b/fuchsia/engine/browser/frame_impl.cc
@@ -346,8 +346,7 @@ bool FrameImpl::IsWebContentsCreationOverridden(
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) {
+ const mojom::CreateNewWindowParams& params) {
// Specify a generous upper bound for unacknowledged popup windows, so that we
// can catch bad client behavior while not interfering with normal operation.
constexpr size_t kMaxPendingWebContentsCount = 10;
diff --git a/fuchsia/engine/browser/frame_impl.h b/fuchsia/engine/browser/frame_impl.h
index 7027e5ee119d52ce9a43a1901beb18a81161512c..f20f7b169b10f68b8e0a3115a058378c6058e229 100644
--- a/fuchsia/engine/browser/frame_impl.h
+++ b/fuchsia/engine/browser/frame_impl.h
@@ -198,8 +198,7 @@ class FrameImpl : public fuchsia::web::Frame,
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) override;
+ const mojom::CreateNewWindowParams& params) override;
void WebContentsCreated(content::WebContents* source_contents,
int opener_render_process_id,
int opener_render_frame_id,
diff --git a/headless/lib/browser/headless_web_contents_impl.cc b/headless/lib/browser/headless_web_contents_impl.cc
index ebe323930ac3298b182c08e6b78c635e785ea4fa..5c1846d948cd6394252a8c94790aa3094f8c9c33 100644
--- a/headless/lib/browser/headless_web_contents_impl.cc
+++ b/headless/lib/browser/headless_web_contents_impl.cc
@@ -164,8 +164,7 @@ class HeadlessWebContentsImpl::Delegate : public content::WebContentsDelegate {
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) override {
+ const mojom::CreateNewWindowParams& params) override {
return headless_web_contents_->browser_context()
->options()
->block_new_web_contents();
diff --git a/ui/views/controls/webview/web_dialog_view.cc b/ui/views/controls/webview/web_dialog_view.cc
index 39a58363e717a0b9d71b7e3ca26578f81f8fb453..4372cf1e383ef3884048fb2a06c72888abcac9e3 100644
--- a/ui/views/controls/webview/web_dialog_view.cc
+++ b/ui/views/controls/webview/web_dialog_view.cc
@@ -427,8 +427,7 @@ bool WebDialogView::IsWebContentsCreationOverridden(
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) {
+ const content::mojom::CreateNewWindowParams& params) {
if (delegate_)
return delegate_->HandleShouldOverrideWebContentsCreation();
return false;
diff --git a/ui/views/controls/webview/web_dialog_view.h b/ui/views/controls/webview/web_dialog_view.h
index 97142bc886e1bbf05871fb6603342ed0cd15dcf8..94206bb4674e696093a5cfc027281254c3bf37ff 100644
--- a/ui/views/controls/webview/web_dialog_view.h
+++ b/ui/views/controls/webview/web_dialog_view.h
@@ -153,8 +153,7 @@ class WEBVIEW_EXPORT WebDialogView : public ClientView,
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
- const std::string& frame_name,
- const GURL& target_url) override;
+ const content::mojom::CreateNewWindowParams& params) override;
void RequestMediaAccessPermission(
content::WebContents* web_contents,
const content::MediaStreamRequest& request,

Просмотреть файл

@ -13,7 +13,7 @@ This patch can be removed once app.allowRendererProcessReuse is forced
to true as then Chromiums assumptions around processes become correct.
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index e099a6cc44e73da8b24603fd86b72139f0735fb2..2f207fda8afb44901d2027cb2ec1da1de826521f 100644
index ea458219bd182bd9ff21b203c282e7d0738049dd..1455dfcae9e1ded39d351f6569919f0c313e3de5 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -3012,11 +3012,13 @@ bool WebContentsImpl::HandleMouseEvent(const blink::WebMouseEvent& event) {

Просмотреть файл

@ -43,10 +43,10 @@ index ffe62ea1114943d1535a806fa515122c47072372..f5f851e4852b045555d5832b7ec72be9
void RenderWidgetHostImpl::OnCursorVisibilityStateChanged(bool is_visible) {
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 22cba415650311acd16750e7ad0956ca71aa75e8..eff997916d5dd833d66d3fa9738dee1fe55075f8 100644
index 37d02e3c950bdb0a1e0f9ef20be71c24fdbde10d..2a80aaa5d4421bf2b3a46cc1674256944b33a1fa 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -4123,6 +4123,12 @@ bool WebContentsImpl::OnUpdateDragCursor() {
@@ -4125,6 +4125,12 @@ bool WebContentsImpl::OnUpdateDragCursor() {
browser_plugin_embedder_->OnUpdateDragCursor();
}

Просмотреть файл

@ -9,7 +9,7 @@ is needed for OSR.
Originally landed in https://github.com/electron/libchromiumcontent/pull/226.
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 2f207fda8afb44901d2027cb2ec1da1de826521f..22cba415650311acd16750e7ad0956ca71aa75e8 100644
index 1455dfcae9e1ded39d351f6569919f0c313e3de5..37d02e3c950bdb0a1e0f9ef20be71c24fdbde10d 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -2744,6 +2744,12 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params) {

Просмотреть файл

@ -784,14 +784,13 @@ void Session::CreateInterruptedDownload(const gin_helper::Dictionary& options) {
length, last_modified, etag, base::Time::FromDoubleT(start_time)));
}
void Session::SetPreloads(
const std::vector<base::FilePath::StringType>& preloads) {
void Session::SetPreloads(const std::vector<base::FilePath>& preloads) {
auto* prefs = SessionPreferences::FromBrowserContext(browser_context());
DCHECK(prefs);
prefs->set_preloads(preloads);
}
std::vector<base::FilePath::StringType> Session::GetPreloads() const {
std::vector<base::FilePath> Session::GetPreloads() const {
auto* prefs = SessionPreferences::FromBrowserContext(browser_context());
DCHECK(prefs);
return prefs->preloads();

Просмотреть файл

@ -115,8 +115,8 @@ class Session : public gin::Wrappable<Session>,
const std::string& uuid);
void DownloadURL(const GURL& url);
void CreateInterruptedDownload(const gin_helper::Dictionary& options);
void SetPreloads(const std::vector<base::FilePath::StringType>& preloads);
std::vector<base::FilePath::StringType> GetPreloads() const;
void SetPreloads(const std::vector<base::FilePath>& preloads);
std::vector<base::FilePath> GetPreloads() const;
v8::Local<v8::Value> Cookies(v8::Isolate* isolate);
v8::Local<v8::Value> Protocol(v8::Isolate* isolate);
v8::Local<v8::Value> ServiceWorkerContext(v8::Isolate* isolate);

Просмотреть файл

@ -639,7 +639,11 @@ void WebContents::InitWithSessionAndOptions(
prefs->caret_blink_interval = *interval;
// Save the preferences in C++.
new WebContentsPreferences(web_contents(), options);
// If there's already a WebContentsPreferences object, we created it as part
// of the webContents.setWindowOpenHandler path, so don't overwrite it.
if (!WebContentsPreferences::From(web_contents())) {
new WebContentsPreferences(web_contents(), options);
}
// Trigger re-calculation of webkit prefs.
web_contents()->NotifyPreferencesChanged();
@ -778,18 +782,44 @@ void WebContents::WebContentsCreatedWithFullParams(
tracker->referrer = params.referrer.To<content::Referrer>();
tracker->raw_features = params.raw_features;
tracker->body = params.body;
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
gin_helper::Dictionary dict;
gin::ConvertFromV8(isolate, pending_child_web_preferences_.Get(isolate),
&dict);
pending_child_web_preferences_.Reset();
// Associate the preferences passed in via `setWindowOpenHandler` with the
// content::WebContents that was just created for the child window. These
// preferences will be picked up by the RenderWidgetHost via its call to the
// delegate's OverrideWebkitPrefs.
new WebContentsPreferences(new_contents, dict);
}
bool WebContents::IsWebContentsCreationOverridden(
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
const std::string& frame_name,
const GURL& target_url) {
if (Emit("-will-add-new-contents", target_url, frame_name)) {
return true;
}
return false;
const content::mojom::CreateNewWindowParams& params) {
bool default_prevented = Emit("-will-add-new-contents", params.target_url,
params.frame_name, params.raw_features);
// If the app prevented the default, redirect to CreateCustomWebContents,
// which always returns nullptr, which will result in the window open being
// prevented (window.open() will return null in the renderer).
return default_prevented;
}
void WebContents::SetNextChildWebPreferences(
const gin_helper::Dictionary preferences) {
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
// Store these prefs for when Chrome calls WebContentsCreatedWithFullParams
// with the new child contents.
pending_child_web_preferences_.Reset(isolate, preferences.GetHandle());
}
content::WebContents* WebContents::CreateCustomWebContents(
@ -1076,7 +1106,7 @@ void WebContents::RenderViewDeleted(content::RenderViewHost* render_view_host) {
if (web_contents()->GetRenderViewHost() == render_view_host) {
// When the RVH that has been deleted is the current RVH it means that the
// the web contents are being closed. This is communicated by this event.
// Currently tracked by guest-window-manager.js to destroy the
// Currently tracked by guest-window-manager.ts to destroy the
// BrowserWindow.
Emit("current-render-view-deleted",
render_view_host->GetProcess()->GetID());
@ -2738,11 +2768,11 @@ void WebContents::DoGetZoomLevel(DoGetZoomLevelCallback callback) {
std::move(callback).Run(GetZoomLevel());
}
std::vector<base::FilePath::StringType> WebContents::GetPreloadPaths() const {
std::vector<base::FilePath> WebContents::GetPreloadPaths() const {
auto result = SessionPreferences::GetValidPreloads(GetBrowserContext());
if (auto* web_preferences = WebContentsPreferences::From(web_contents())) {
base::FilePath::StringType preload;
base::FilePath preload;
if (web_preferences->GetPreloadPath(&preload)) {
result.emplace_back(preload);
}
@ -3017,6 +3047,8 @@ v8::Local<v8::ObjectTemplate> WebContents::FillObjectTemplate(
.SetMethod("_getPrinters", &WebContents::GetPrinterList)
.SetMethod("_printToPDF", &WebContents::PrintToPDF)
#endif
.SetMethod("_setNextChildWebPreferences",
&WebContents::SetNextChildWebPreferences)
.SetMethod("addWorkSpace", &WebContents::AddWorkSpace)
.SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace)
.SetMethod("showDefinitionForSelection",

Просмотреть файл

@ -252,6 +252,8 @@ class WebContents : public gin::Wrappable<WebContents>,
v8::Local<v8::Promise> PrintToPDF(base::DictionaryValue settings);
#endif
void SetNextChildWebPreferences(const gin_helper::Dictionary);
// DevTools workspace api.
void AddWorkSpace(gin::Arguments* args, const base::FilePath& path);
void RemoveWorkSpace(gin::Arguments* args, const base::FilePath& path);
@ -354,7 +356,7 @@ class WebContents : public gin::Wrappable<WebContents>,
const scoped_refptr<network::ResourceRequestBody>& body);
// Returns the preload script path of current WebContents.
std::vector<base::FilePath::StringType> GetPreloadPaths() const;
std::vector<base::FilePath> GetPreloadPaths() const;
// Returns the web preferences of current WebContents.
v8::Local<v8::Value> GetWebPreferences(v8::Isolate* isolate) const;
@ -456,8 +458,7 @@ class WebContents : public gin::Wrappable<WebContents>,
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
const std::string& frame_name,
const GURL& target_url) override;
const content::mojom::CreateNewWindowParams& params) override;
content::WebContents* CreateCustomWebContents(
content::RenderFrameHost* opener,
content::SiteInstance* source_site_instance,
@ -679,6 +680,8 @@ class WebContents : public gin::Wrappable<WebContents>,
// Observers of this WebContents.
base::ObserverList<ExtendedWebContentsObserver> observers_;
v8::Global<v8::Value> pending_child_web_preferences_;
bool initially_shown_ = true;
service_manager::BinderRegistryWithArgs<content::RenderFrameHost*> registry_;

Просмотреть файл

@ -225,12 +225,6 @@ void BindNetworkHintsHandler(
NetworkHintsHandlerImpl::Create(frame_host, std::move(receiver));
}
#if defined(OS_WIN)
const base::FilePath::StringPieceType kPathDelimiter = FILE_PATH_LITERAL(";");
#else
const base::FilePath::StringPieceType kPathDelimiter = FILE_PATH_LITERAL(":");
#endif
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
// Used by the GetPrivilegeRequiredByUrl() and GetProcessPrivilege() functions
// below. Extension, and isolated apps require different privileges to be
@ -610,13 +604,21 @@ void ElectronBrowserClient::OverrideWebkitPrefs(
? blink::mojom::PreferredColorScheme::kDark
: blink::mojom::PreferredColorScheme::kLight;
auto* web_contents = content::WebContents::FromRenderViewHost(host);
auto preloads =
SessionPreferences::GetValidPreloads(web_contents->GetBrowserContext());
if (!preloads.empty())
prefs->preloads = preloads;
if (CanUseCustomSiteInstance())
prefs->disable_electron_site_instance_overrides = true;
SetFontDefaults(prefs);
// Custom preferences of guest page.
auto* web_contents = content::WebContents::FromRenderViewHost(host);
auto* web_preferences = WebContentsPreferences::From(web_contents);
if (web_preferences)
if (web_preferences) {
web_preferences->OverrideWebkitPrefs(prefs);
}
}
void ElectronBrowserClient::SetCanUseCustomSiteInstance(bool should_disable) {
@ -803,16 +805,6 @@ void ElectronBrowserClient::AppendExtraCommandLineSwitches(
if (web_preferences)
web_preferences->AppendCommandLineSwitches(
command_line, IsRendererSubFrame(process_id));
auto preloads = SessionPreferences::GetValidPreloads(
web_contents->GetBrowserContext());
if (!preloads.empty())
command_line->AppendSwitchNative(
switches::kPreloadScripts,
base::JoinString(preloads, kPathDelimiter));
if (CanUseCustomSiteInstance()) {
command_line->AppendSwitch(
switches::kDisableElectronSiteInstanceOverrides);
}
}
}
}

Просмотреть файл

@ -21,6 +21,7 @@ template <typename T>
class EventEmitterMixin {
public:
// this.emit(name, new Event(), args...);
// Returns true if event.preventDefault() was called during processing.
template <typename... Args>
bool Emit(base::StringPiece name, Args&&... args) {
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();

Просмотреть файл

@ -25,13 +25,13 @@ SessionPreferences* SessionPreferences::FromBrowserContext(
}
// static
std::vector<base::FilePath::StringType> SessionPreferences::GetValidPreloads(
std::vector<base::FilePath> SessionPreferences::GetValidPreloads(
content::BrowserContext* context) {
std::vector<base::FilePath::StringType> result;
std::vector<base::FilePath> result;
if (auto* self = FromBrowserContext(context)) {
for (const auto& preload : self->preloads()) {
if (base::FilePath(preload).IsAbsolute()) {
if (preload.IsAbsolute()) {
result.emplace_back(preload);
} else {
LOG(ERROR) << "preload script must have absolute path: " << preload;

Просмотреть файл

@ -17,24 +17,22 @@ class SessionPreferences : public base::SupportsUserData::Data {
public:
static SessionPreferences* FromBrowserContext(
content::BrowserContext* context);
static std::vector<base::FilePath::StringType> GetValidPreloads(
static std::vector<base::FilePath> GetValidPreloads(
content::BrowserContext* context);
explicit SessionPreferences(content::BrowserContext* context);
~SessionPreferences() override;
void set_preloads(const std::vector<base::FilePath::StringType>& preloads) {
void set_preloads(const std::vector<base::FilePath>& preloads) {
preloads_ = preloads;
}
const std::vector<base::FilePath::StringType>& preloads() const {
return preloads_;
}
const std::vector<base::FilePath>& preloads() const { return preloads_; }
private:
// The user data key.
static int kLocatorKey;
std::vector<base::FilePath::StringType> preloads_;
std::vector<base::FilePath> preloads_;
};
} // namespace electron

Просмотреть файл

@ -241,22 +241,22 @@ bool WebContentsPreferences::GetPreference(base::StringPiece name,
return GetAsString(&preference_, name, value);
}
bool WebContentsPreferences::GetPreloadPath(
base::FilePath::StringType* path) const {
bool WebContentsPreferences::GetPreloadPath(base::FilePath* path) const {
DCHECK(path);
base::FilePath::StringType preload;
if (GetAsString(&preference_, options::kPreloadScript, &preload)) {
if (base::FilePath(preload).IsAbsolute()) {
base::FilePath::StringType preload_path;
if (GetAsString(&preference_, options::kPreloadScript, &preload_path)) {
base::FilePath preload(preload_path);
if (preload.IsAbsolute()) {
*path = std::move(preload);
return true;
} else {
LOG(ERROR) << "preload script must have absolute path.";
}
} else if (GetAsString(&preference_, options::kPreloadURL, &preload)) {
} else if (GetAsString(&preference_, options::kPreloadURL, &preload_path)) {
// Translate to file path if there is "preload-url" option.
base::FilePath preload_path;
if (net::FileURLToFilePath(GURL(preload), &preload_path)) {
*path = std::move(preload_path.value());
base::FilePath preload;
if (net::FileURLToFilePath(GURL(preload_path), &preload)) {
*path = std::move(preload);
return true;
} else {
LOG(ERROR) << "preload url must be file:// protocol.";
@ -287,36 +287,16 @@ WebContentsPreferences* WebContentsPreferences::From(
void WebContentsPreferences::AppendCommandLineSwitches(
base::CommandLine* command_line,
bool is_subframe) {
// Check if plugins are enabled.
if (IsEnabled(options::kPlugins))
command_line->AppendSwitch(switches::kEnablePlugins);
// Experimental flags.
if (IsEnabled(options::kExperimentalFeatures))
command_line->AppendSwitch(
::switches::kEnableExperimentalWebPlatformFeatures);
// Check if we have node integration specified.
if (IsEnabled(options::kNodeIntegration))
command_line->AppendSwitch(switches::kNodeIntegration);
// Whether to enable node integration in Worker.
if (IsEnabled(options::kNodeIntegrationInWorker))
command_line->AppendSwitch(switches::kNodeIntegrationInWorker);
// Check if webview tag creation is enabled, default to nodeIntegration value.
if (IsEnabled(options::kWebviewTag))
command_line->AppendSwitch(switches::kWebviewTag);
// Sandbox can be enabled for renderer processes hosting cross-origin frames
// unless nodeIntegrationInSubFrames is enabled
bool can_sandbox_frame =
is_subframe && !IsEnabled(options::kNodeIntegrationInSubFrames);
// If the `sandbox` option was passed to the BrowserWindow's webPreferences,
// pass `--enable-sandbox` to the renderer so it won't have any node.js
// integration. Otherwise disable Chromium sandbox, unless app.enableSandbox()
// was called.
if (IsEnabled(options::kSandbox) || can_sandbox_frame) {
command_line->AppendSwitch(switches::kEnableSandbox);
} else if (!command_line->HasSwitch(switches::kEnableSandbox)) {
@ -324,15 +304,6 @@ void WebContentsPreferences::AppendCommandLineSwitches(
command_line->AppendSwitch(::switches::kNoZygote);
}
// Check if nativeWindowOpen is enabled.
if (IsEnabled(options::kNativeWindowOpen))
command_line->AppendSwitch(switches::kNativeWindowOpen);
// The preload script.
base::FilePath::StringType preload;
if (GetPreloadPath(&preload))
command_line->AppendSwitchNative(switches::kPreloadScript, preload);
// Custom args for renderer process
auto* customArgs =
preference_.FindKeyOfType(options::kCustomArgs, base::Value::Type::LIST);
@ -343,46 +314,13 @@ void WebContentsPreferences::AppendCommandLineSwitches(
}
}
#if BUILDFLAG(ENABLE_REMOTE_MODULE)
// Whether to enable the remote module
if (IsEnabled(options::kEnableRemoteModule, false))
command_line->AppendSwitch(switches::kEnableRemoteModule);
#endif
// Run Electron APIs and preload script in isolated world
if (IsEnabled(options::kContextIsolation))
command_line->AppendSwitch(switches::kContextIsolation);
if (IsEnabled(options::kWorldSafeExecuteJavaScript))
command_line->AppendSwitch(switches::kWorldSafeExecuteJavaScript);
// --background-color.
std::string s;
if (GetAsString(&preference_, options::kBackgroundColor, &s)) {
command_line->AppendSwitchASCII(switches::kBackgroundColor, s);
} else if (!IsEnabled(options::kOffscreen)) {
// For non-OSR WebContents, we expect to have white background, see
// https://github.com/electron/electron/issues/13764 for more.
command_line->AppendSwitchASCII(switches::kBackgroundColor, "#fff");
}
// --offscreen
// TODO(loc): Offscreen is duplicated in WebPreferences because it's needed
// earlier than we can get WebPreferences at the moment.
if (IsEnabled(options::kOffscreen)) {
command_line->AppendSwitch(options::kOffscreen);
}
// --guest-instance-id, which is used to identify guest WebContents.
int guest_instance_id = 0;
if (GetAsInteger(&preference_, options::kGuestInstanceID, &guest_instance_id))
command_line->AppendSwitchASCII(switches::kGuestInstanceID,
base::NumberToString(guest_instance_id));
// Pass the opener's window id.
int opener_id;
if (GetAsInteger(&preference_, options::kOpenerID, &opener_id))
command_line->AppendSwitchASCII(switches::kOpenerID,
base::NumberToString(opener_id));
#if defined(OS_MAC)
// Enable scroll bounce.
if (IsEnabled(options::kScrollBounce))
@ -402,6 +340,7 @@ void WebContentsPreferences::AppendCommandLineSwitches(
}
}
std::string s;
// Enable blink features.
if (GetAsString(&preference_, options::kEnableBlinkFeatures, &s))
command_line->AppendSwitchASCII(::switches::kEnableBlinkFeatures, s);
@ -410,39 +349,8 @@ void WebContentsPreferences::AppendCommandLineSwitches(
if (GetAsString(&preference_, options::kDisableBlinkFeatures, &s))
command_line->AppendSwitchASCII(::switches::kDisableBlinkFeatures, s);
if (guest_instance_id) {
// Webview `document.visibilityState` tracks window visibility so we need
// to let it know if the window happens to be hidden right now.
auto* manager = WebViewManager::GetWebViewManager(web_contents_);
if (manager) {
auto* embedder = manager->GetEmbedder(guest_instance_id);
if (embedder) {
auto* relay = NativeWindowRelay::FromWebContents(embedder);
if (relay) {
auto* window = relay->GetNativeWindow();
if (window) {
const bool visible = window->IsVisible() && !window->IsMinimized();
if (!visible) {
command_line->AppendSwitch(switches::kHiddenPage);
}
}
}
}
}
}
if (IsEnabled(options::kNodeIntegrationInSubFrames))
command_line->AppendSwitch(switches::kNodeIntegrationInSubFrames);
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
if (IsEnabled(options::kSpellcheck)) {
command_line->AppendSwitch(switches::kEnableSpellcheck);
}
#endif
// Whether to allow the WebSQL api
if (IsEnabled(options::kEnableWebSQL))
command_line->AppendSwitch(switches::kEnableWebSQL);
if (IsEnabled(options::kNodeIntegrationInWorker))
command_line->AppendSwitch(switches::kNodeIntegrationInWorker);
// We are appending args to a webContents so let's save the current state
// of our preferences object so that during the lifetime of the WebContents
@ -507,6 +415,87 @@ void WebContentsPreferences::OverrideWebkitPrefs(
if (GetAsString(&preference_, "defaultEncoding", &encoding))
prefs->default_encoding = encoding;
// --background-color.
std::string color;
if (GetAsString(&preference_, options::kBackgroundColor, &color)) {
prefs->background_color = color;
} else if (!IsEnabled(options::kOffscreen)) {
prefs->background_color = "#fff";
}
// Pass the opener's window id.
int opener_id;
if (GetAsInteger(&preference_, options::kOpenerID, &opener_id))
prefs->opener_id = opener_id;
// Run Electron APIs and preload script in isolated world
prefs->context_isolation = IsEnabled(options::kContextIsolation);
#if BUILDFLAG(ENABLE_REMOTE_MODULE)
// Whether to enable the remote module
prefs->enable_remote_module = IsEnabled(options::kEnableRemoteModule, false);
#endif
prefs->world_safe_execute_javascript =
IsEnabled(options::kWorldSafeExecuteJavaScript);
int guest_instance_id = 0;
if (GetAsInteger(&preference_, options::kGuestInstanceID, &guest_instance_id))
prefs->guest_instance_id = guest_instance_id;
prefs->hidden_page = false;
if (guest_instance_id) {
// Webview `document.visibilityState` tracks window visibility so we need
// to let it know if the window happens to be hidden right now.
auto* manager = WebViewManager::GetWebViewManager(web_contents_);
if (manager) {
auto* embedder = manager->GetEmbedder(guest_instance_id);
if (embedder) {
auto* relay = NativeWindowRelay::FromWebContents(embedder);
if (relay) {
auto* window = relay->GetNativeWindow();
if (window) {
const bool visible = window->IsVisible() && !window->IsMinimized();
if (!visible) {
prefs->hidden_page = true;
}
}
}
}
}
}
prefs->offscreen = IsEnabled(options::kOffscreen);
// The preload script.
GetPreloadPath(&prefs->preload);
// Check if nativeWindowOpen is enabled.
prefs->native_window_open = IsEnabled(options::kNativeWindowOpen);
// Check if we have node integration specified.
prefs->node_integration = IsEnabled(options::kNodeIntegration);
// Whether to enable node integration in Worker.
prefs->node_integration_in_worker =
IsEnabled(options::kNodeIntegrationInWorker);
prefs->node_integration_in_sub_frames =
IsEnabled(options::kNodeIntegrationInSubFrames);
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
prefs->enable_spellcheck = IsEnabled(options::kSpellcheck);
#endif
// Check if plugins are enabled.
prefs->enable_plugins = IsEnabled(options::kPlugins);
// Check if webview tag creation is enabled, default to nodeIntegration value.
prefs->webview_tag = IsEnabled(options::kWebviewTag);
// Whether to allow the WebSQL api
prefs->enable_websql = IsEnabled(options::kEnableWebSQL);
std::string v8_cache_options;
if (GetAsString(&preference_, "v8CacheOptions", &v8_cache_options)) {
if (v8_cache_options == "none") {

Просмотреть файл

@ -59,7 +59,7 @@ class WebContentsPreferences
bool GetPreference(base::StringPiece name, std::string* value) const;
// Returns the preload script path.
bool GetPreloadPath(base::FilePath::StringType* path) const;
bool GetPreloadPath(base::FilePath* path) const;
// Returns the web preferences.
base::Value* preference() { return &preference_; }

Просмотреть файл

@ -40,6 +40,10 @@ void WebViewGuestDelegate::AttachToIframe(
content::WebContents* guest_web_contents = api_web_contents_->web_contents();
// Force a refresh of the webPreferences so that OverrideWebkitPrefs runs on
// the new web contents before the renderer process initializes.
// guest_web_contents->NotifyPreferencesChanged();
// Attach this inner WebContents |guest_web_contents| to the outer
// WebContents |embedder_web_contents|. The outer WebContents's
// frame |embedder_frame| hosts the inner WebContents.

Просмотреть файл

@ -109,6 +109,8 @@ const char kZoomFactor[] = "zoomFactor";
// Script that will be loaded by guest WebContents before other scripts.
const char kPreloadScript[] = "preload";
const char kPreloadScripts[] = "preloadScripts";
// Like --preload, but the passed argument is an URL.
const char kPreloadURL[] = "preloadURL";
@ -181,6 +183,11 @@ const char kWebGL[] = "webgl";
// navigation.
const char kNavigateOnDragDrop[] = "navigateOnDragDrop";
const char kDisableElectronSiteInstanceOverrides[] =
"disableElectronSiteInstanceOverrides";
const char kEnableNodeLeakageInRenderers[] = "enableNodeLeakageInRenderers";
const char kHiddenPage[] = "hiddenPage";
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
const char kSpellcheck[] = "spellcheck";
#endif
@ -200,9 +207,6 @@ namespace switches {
// Enable chromium sandbox.
const char kEnableSandbox[] = "enable-sandbox";
// Enable plugins.
const char kEnablePlugins[] = "enable-plugins";
// Ppapi Flash path.
const char kPpapiFlashPath[] = "ppapi-flash-path";
@ -242,33 +246,11 @@ const char kAppPath[] = "app-path";
const char kEnableApiFilteringLogging[] = "enable-api-filtering-logging";
// The command line switch versions of the options.
const char kBackgroundColor[] = "background-color";
const char kPreloadScript[] = "preload";
const char kPreloadScripts[] = "preload-scripts";
const char kNodeIntegration[] = "node-integration";
const char kContextIsolation[] = "context-isolation";
const char kWorldSafeExecuteJavaScript[] = "world-safe-execute-javascript";
const char kGuestInstanceID[] = "guest-instance-id";
const char kOpenerID[] = "opener-id";
const char kScrollBounce[] = "scroll-bounce";
const char kHiddenPage[] = "hidden-page";
const char kNativeWindowOpen[] = "native-window-open";
const char kWebviewTag[] = "webview-tag";
const char kDisableElectronSiteInstanceOverrides[] =
"disable-electron-site-instance-overrides";
const char kEnableNodeLeakageInRenderers[] = "enable-node-leakage-in-renderers";
// Command switch passed to renderer process to control nodeIntegration.
const char kNodeIntegrationInWorker[] = "node-integration-in-worker";
// Command switch passed to renderer process to control whether node
// environments will be created in sub-frames.
const char kNodeIntegrationInSubFrames[] = "node-integration-in-subframes";
// Command switch passed to render process to control whether WebSQL api
// is allowed.
const char kEnableWebSQL[] = "enable-websql";
// Widevine options
// Path to Widevine CDM binaries.
const char kWidevineCdmPath[] = "widevine-cdm-path";
@ -294,16 +276,10 @@ const char kEnableAuthNegotiatePort[] = "enable-auth-negotiate-port";
// If set, NTLM v2 is disabled for POSIX platforms.
const char kDisableNTLMv2[] = "disable-ntlm-v2";
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
const char kEnableSpellcheck[] = "enable-spellcheck";
#endif
#if BUILDFLAG(ENABLE_REMOTE_MODULE)
const char kEnableRemoteModule[] = "enable-remote-module";
#endif
const char kGlobalCrashKeys[] = "global-crash-keys";
const char kEnableWebSQL[] = "enable-websql";
} // namespace switches
} // namespace electron

Просмотреть файл

@ -60,6 +60,7 @@ extern const char kTrafficLightPosition[];
// WebPreferences.
extern const char kZoomFactor[];
extern const char kPreloadScript[];
extern const char kPreloadScripts[];
extern const char kPreloadURL[];
extern const char kNodeIntegration[];
extern const char kContextIsolation[];
@ -89,6 +90,10 @@ extern const char kNavigateOnDragDrop[];
extern const char kEnableWebSQL[];
extern const char kEnablePreferredSizeMode[];
extern const char kDisableElectronSiteInstanceOverrides[];
extern const char kEnableNodeLeakageInRenderers[];
extern const char kHiddenPage[];
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
extern const char kSpellcheck[];
#endif
@ -104,7 +109,6 @@ extern const char kEnableRemoteModule[];
namespace switches {
extern const char kEnableSandbox[];
extern const char kEnablePlugins[];
extern const char kPpapiFlashPath[];
extern const char kPpapiFlashVersion[];
extern const char kDisableHttpCache[];
@ -119,23 +123,8 @@ extern const char kAppUserModelId[];
extern const char kAppPath[];
extern const char kEnableApiFilteringLogging[];
extern const char kBackgroundColor[];
extern const char kPreloadScript[];
extern const char kPreloadScripts[];
extern const char kNodeIntegration[];
extern const char kContextIsolation[];
extern const char kWorldSafeExecuteJavaScript[];
extern const char kGuestInstanceID[];
extern const char kOpenerID[];
extern const char kScrollBounce[];
extern const char kHiddenPage[];
extern const char kNativeWindowOpen[];
extern const char kNodeIntegrationInWorker[];
extern const char kWebviewTag[];
extern const char kNodeIntegrationInSubFrames[];
extern const char kDisableElectronSiteInstanceOverrides[];
extern const char kEnableNodeLeakageInRenderers[];
extern const char kEnableWebSQL[];
extern const char kWidevineCdmPath[];
extern const char kWidevineCdmVersion[];
@ -147,16 +136,9 @@ extern const char kAuthNegotiateDelegateWhitelist[];
extern const char kEnableAuthNegotiatePort[];
extern const char kDisableNTLMv2[];
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
extern const char kEnableSpellcheck[];
#endif
#if BUILDFLAG(ENABLE_REMOTE_MODULE)
extern const char kEnableRemoteModule[];
#endif
extern const char kGlobalCrashKeys[];
extern const char kEnableWebSQL[];
} // namespace switches
} // namespace electron

Просмотреть файл

@ -20,6 +20,7 @@
#include "shell/common/api/api.mojom.h"
#include "shell/common/gin_converters/blink_converter.h"
#include "shell/common/gin_converters/callback_converter.h"
#include "shell/common/gin_converters/file_path_converter.h"
#include "shell/common/gin_helper/dictionary.h"
#include "shell/common/gin_helper/error_thrower.h"
#include "shell/common/gin_helper/promise.h"
@ -29,6 +30,7 @@
#include "shell/renderer/electron_renderer_client.h"
#include "third_party/blink/public/common/page/page_zoom.h"
#include "third_party/blink/public/common/web_cache/web_cache_resource_type_stats.h"
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
#include "third_party/blink/public/platform/web_cache.h"
#include "third_party/blink/public/platform/web_isolated_world_info.h"
#include "third_party/blink/public/web/web_custom_element.h"
@ -395,6 +397,65 @@ double GetZoomFactor(gin_helper::ErrorThrower thrower,
return blink::PageZoomLevelToZoomFactor(zoom_level);
}
v8::Local<v8::Value> GetWebPreference(v8::Isolate* isolate,
v8::Local<v8::Value> window,
std::string pref_name) {
content::RenderFrame* render_frame = GetRenderFrame(window);
const auto& prefs = render_frame->GetBlinkPreferences();
if (pref_name == options::kPreloadScripts) {
return gin::ConvertToV8(isolate, prefs.preloads);
} else if (pref_name == options::kDisableElectronSiteInstanceOverrides) {
return gin::ConvertToV8(isolate,
prefs.disable_electron_site_instance_overrides);
} else if (pref_name == options::kBackgroundColor) {
return gin::ConvertToV8(isolate, prefs.background_color);
} else if (pref_name == options::kOpenerID) {
// NOTE: openerId is internal-only.
return gin::ConvertToV8(isolate, prefs.opener_id);
} else if (pref_name == options::kContextIsolation) {
return gin::ConvertToV8(isolate, prefs.context_isolation);
#if BUILDFLAG(ENABLE_REMOTE_MODULE)
} else if (pref_name == options::kEnableRemoteModule) {
return gin::ConvertToV8(isolate, prefs.enable_remote_module);
#endif
} else if (pref_name == options::kWorldSafeExecuteJavaScript) {
return gin::ConvertToV8(isolate, prefs.world_safe_execute_javascript);
} else if (pref_name == options::kGuestInstanceID) {
// NOTE: guestInstanceId is internal-only.
return gin::ConvertToV8(isolate, prefs.guest_instance_id);
} else if (pref_name == options::kHiddenPage) {
// NOTE: hiddenPage is internal-only.
return gin::ConvertToV8(isolate, prefs.hidden_page);
} else if (pref_name == options::kOffscreen) {
return gin::ConvertToV8(isolate, prefs.offscreen);
} else if (pref_name == options::kPreloadScript) {
return gin::ConvertToV8(isolate, prefs.preload.value());
} else if (pref_name == options::kNativeWindowOpen) {
return gin::ConvertToV8(isolate, prefs.native_window_open);
} else if (pref_name == options::kNodeIntegration) {
return gin::ConvertToV8(isolate, prefs.node_integration);
} else if (pref_name == options::kNodeIntegrationInWorker) {
return gin::ConvertToV8(isolate, prefs.node_integration_in_worker);
} else if (pref_name == options::kEnableNodeLeakageInRenderers) {
// NOTE: enableNodeLeakageInRenderers is internal-only.
return gin::ConvertToV8(isolate, prefs.node_leakage_in_renderers);
} else if (pref_name == options::kNodeIntegrationInSubFrames) {
return gin::ConvertToV8(isolate, true);
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
} else if (pref_name == options::kSpellcheck) {
return gin::ConvertToV8(isolate, prefs.enable_spellcheck);
#endif
} else if (pref_name == options::kPlugins) {
return gin::ConvertToV8(isolate, prefs.enable_plugins);
} else if (pref_name == options::kEnableWebSQL) {
return gin::ConvertToV8(isolate, prefs.enable_websql);
} else if (pref_name == options::kWebviewTag) {
return gin::ConvertToV8(isolate, prefs.webview_tag);
}
return v8::Null(isolate);
}
void SetVisualZoomLevelLimits(gin_helper::ErrorThrower thrower,
v8::Local<v8::Value> window,
double min_level,
@ -574,13 +635,13 @@ v8::Local<v8::Promise> ExecuteJavaScript(gin_helper::Arguments* args,
ScriptExecutionCallback::CompletionCallback completion_callback;
args->GetNext(&completion_callback);
bool world_safe_exec_js = base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kWorldSafeExecuteJavaScript);
auto& prefs = render_frame->GetBlinkPreferences();
render_frame->GetWebFrame()->RequestExecuteScriptAndReturnValue(
blink::WebScriptSource(blink::WebString::FromUTF16(code)),
has_user_gesture,
new ScriptExecutionCallback(std::move(promise), world_safe_exec_js,
new ScriptExecutionCallback(std::move(promise),
prefs.world_safe_execute_javascript,
std::move(completion_callback)));
return handle;
@ -640,8 +701,7 @@ v8::Local<v8::Promise> ExecuteJavaScriptInIsolatedWorld(
blink::WebURL(GURL(url)), start_line));
}
bool world_safe_exec_js = base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kWorldSafeExecuteJavaScript);
auto& prefs = render_frame->GetBlinkPreferences();
// Debugging tip: if you see a crash stack trace beginning from this call,
// then it is very likely that some exception happened when executing the
@ -649,7 +709,8 @@ v8::Local<v8::Promise> ExecuteJavaScriptInIsolatedWorld(
render_frame->GetWebFrame()->RequestExecuteScriptInIsolatedWorld(
world_id, &sources.front(), sources.size(), has_user_gesture,
scriptExecutionType,
new ScriptExecutionCallback(std::move(promise), world_safe_exec_js,
new ScriptExecutionCallback(std::move(promise),
prefs.world_safe_execute_javascript,
std::move(completion_callback)));
return handle;
@ -852,6 +913,7 @@ void Initialize(v8::Local<v8::Object> exports,
dict.SetMethod("allowGuestViewElementDefinition",
&AllowGuestViewElementDefinition);
dict.SetMethod("getWebFrameId", &GetWebFrameId);
dict.SetMethod("getWebPreference", &GetWebPreference);
dict.SetMethod("setSpellCheckProvider", &SetSpellCheckProvider);
dict.SetMethod("insertText", &InsertText);
dict.SetMethod("insertCSS", &InsertCSS);

Просмотреть файл

@ -7,6 +7,7 @@
#include "base/command_line.h"
#include "content/public/renderer/render_frame.h"
#include "shell/common/options_switches.h"
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
#include "third_party/blink/public/platform/url_conversion.h"
#include "third_party/blink/public/platform/web_security_origin.h"
#include "third_party/blink/public/web/web_local_frame.h"
@ -23,8 +24,10 @@ ContentSettingsObserver::~ContentSettingsObserver() = default;
bool ContentSettingsObserver::AllowStorageAccessSync(StorageType storage_type) {
if (storage_type == StorageType::kDatabase &&
!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableWebSQL)) {
// Command line support is still relevant for extensions.
!(base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableWebSQL) ||
render_frame()->GetBlinkPreferences().enable_websql)) {
return false;
}

Просмотреть файл

@ -21,6 +21,7 @@
#include "services/service_manager/public/cpp/interface_provider.h"
#include "shell/common/options_switches.h"
#include "shell/common/world_ids.h"
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
#include "third_party/blink/public/platform/web_isolated_world_info.h"
#include "third_party/blink/public/web/blink.h"
#include "third_party/blink/public/web/web_document.h"
@ -64,21 +65,18 @@ void ElectronRenderFrameObserver::DidInstallConditionalFeatures(
if (ShouldNotifyClient(world_id))
renderer_client_->DidCreateScriptContext(context, render_frame_);
auto* command_line = base::CommandLine::ForCurrentProcess();
bool use_context_isolation = renderer_client_->isolated_world();
auto prefs = render_frame_->GetBlinkPreferences();
bool use_context_isolation = prefs.context_isolation;
// This logic matches the EXPLAINED logic in electron_renderer_client.cc
// to avoid explaining it twice go check that implementation in
// DidCreateScriptContext();
bool is_main_world = IsMainWorld(world_id);
bool is_main_frame = render_frame_->IsMainFrame();
bool reuse_renderer_processes_enabled =
command_line->HasSwitch(switches::kDisableElectronSiteInstanceOverrides);
bool is_not_opened =
!render_frame_->GetWebFrame()->Opener() ||
command_line->HasSwitch(switches::kEnableNodeLeakageInRenderers);
bool allow_node_in_sub_frames =
command_line->HasSwitch(switches::kNodeIntegrationInSubFrames);
prefs.disable_electron_site_instance_overrides;
bool is_not_opened = !render_frame_->GetWebFrame()->Opener() ||
prefs.node_leakage_in_renderers;
bool allow_node_in_sub_frames = prefs.node_integration_in_sub_frames;
bool should_create_isolated_context =
use_context_isolation && is_main_world &&
(is_main_frame || allow_node_in_sub_frames) &&
@ -163,10 +161,9 @@ bool ElectronRenderFrameObserver::IsIsolatedWorld(int world_id) {
}
bool ElectronRenderFrameObserver::ShouldNotifyClient(int world_id) {
bool allow_node_in_sub_frames =
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kNodeIntegrationInSubFrames);
if (renderer_client_->isolated_world() &&
auto prefs = render_frame_->GetBlinkPreferences();
bool allow_node_in_sub_frames = prefs.node_integration_in_sub_frames;
if (prefs.context_isolation &&
(render_frame_->IsMainFrame() || allow_node_in_sub_frames))
return IsIsolatedWorld(world_id);
else

Просмотреть файл

@ -20,6 +20,7 @@
#include "shell/common/options_switches.h"
#include "shell/renderer/electron_render_frame_observer.h"
#include "shell/renderer/web_worker_observer.h"
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_local_frame.h"
@ -91,17 +92,15 @@ void ElectronRendererClient::DidCreateScriptContext(
// TODO(zcbenz): Do not create Node environment if node integration is not
// enabled.
auto* command_line = base::CommandLine::ForCurrentProcess();
// Only load node if we are a main frame or a devtools extension
// unless node support has been explicitly enabled for sub frames
auto prefs = render_frame->GetBlinkPreferences();
bool reuse_renderer_processes_enabled =
command_line->HasSwitch(switches::kDisableElectronSiteInstanceOverrides);
prefs.disable_electron_site_instance_overrides;
// Consider the window not "opened" if it does not have an Opener, or if a
// user has manually opted in to leaking node in the renderer
bool is_not_opened =
!render_frame->GetWebFrame()->Opener() ||
command_line->HasSwitch(switches::kEnableNodeLeakageInRenderers);
!render_frame->GetWebFrame()->Opener() || prefs.node_leakage_in_renderers;
// Consider this the main frame if it is both a Main Frame and it wasn't
// opened. We allow an opened main frame to have node if renderer process
// reuse is enabled as that will correctly free node environments prevent a
@ -109,8 +108,7 @@ void ElectronRendererClient::DidCreateScriptContext(
bool is_main_frame = render_frame->IsMainFrame() &&
(is_not_opened || reuse_renderer_processes_enabled);
bool is_devtools = IsDevToolsExtension(render_frame);
bool allow_node_in_subframes =
command_line->HasSwitch(switches::kNodeIntegrationInSubFrames);
bool allow_node_in_subframes = prefs.node_integration_in_sub_frames;
bool should_load_node =
(is_main_frame || is_devtools || allow_node_in_subframes) &&
!IsWebViewFrame(renderer_context, render_frame);
@ -186,10 +184,9 @@ void ElectronRendererClient::WillReleaseScriptContext(
// for existing users.
// We also do this if we have disable electron site instance overrides to
// avoid memory leaks
auto* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kNodeIntegrationInSubFrames) ||
command_line->HasSwitch(
switches::kDisableElectronSiteInstanceOverrides)) {
auto prefs = render_frame->GetBlinkPreferences();
if (prefs.node_integration_in_sub_frames ||
prefs.disable_electron_site_instance_overrides) {
node::FreeEnvironment(env);
if (env == node_bindings_->uv_env())
node::FreeIsolateData(node_bindings_->isolate_data());
@ -213,6 +210,8 @@ bool ElectronRendererClient::ShouldFork(blink::WebLocalFrame* frame,
void ElectronRendererClient::WorkerScriptReadyForEvaluationOnWorkerThread(
v8::Local<v8::Context> context) {
// TODO(loc): Note that this will not be correct for in-process child windows
// with webPreferences that have a different value for nodeIntegrationInWorker
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kNodeIntegrationInWorker)) {
WebWorkerObserver::GetCurrent()->WorkerScriptReadyForEvaluation(context);
@ -221,6 +220,8 @@ void ElectronRendererClient::WorkerScriptReadyForEvaluationOnWorkerThread(
void ElectronRendererClient::WillDestroyWorkerContextOnWorkerThread(
v8::Local<v8::Context> context) {
// TODO(loc): Note that this will not be correct for in-process child windows
// with webPreferences that have a different value for nodeIntegrationInWorker
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kNodeIntegrationInWorker)) {
WebWorkerObserver::GetCurrent()->ContextWillDestroy(context);
@ -230,8 +231,9 @@ void ElectronRendererClient::WillDestroyWorkerContextOnWorkerThread(
void ElectronRendererClient::SetupMainWorldOverrides(
v8::Handle<v8::Context> context,
content::RenderFrame* render_frame) {
auto prefs = render_frame->GetBlinkPreferences();
// We only need to run the isolated bundle if webview is enabled
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kWebviewTag))
if (!prefs.webview_tag)
return;
// Setup window overrides in the main world context
// Wrap the bundle into a function that receives the isolatedWorld as

Просмотреть файл

@ -19,6 +19,7 @@
#include "shell/common/node_util.h"
#include "shell/common/options_switches.h"
#include "shell/renderer/electron_render_frame_observer.h"
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
#include "third_party/blink/public/web/blink.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/electron_node/src/node_binding.h"
@ -198,8 +199,7 @@ void ElectronSandboxedRendererClient::DidCreateScriptContext(
bool is_devtools =
IsDevTools(render_frame) || IsDevToolsExtension(render_frame);
bool allow_node_in_sub_frames =
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kNodeIntegrationInSubFrames);
render_frame->GetBlinkPreferences().node_integration_in_sub_frames;
bool should_load_preload =
(is_main_frame || is_devtools || allow_node_in_sub_frames) &&
!IsWebViewFrame(context, render_frame);
@ -232,8 +232,9 @@ void ElectronSandboxedRendererClient::DidCreateScriptContext(
void ElectronSandboxedRendererClient::SetupMainWorldOverrides(
v8::Handle<v8::Context> context,
content::RenderFrame* render_frame) {
auto prefs = render_frame->GetBlinkPreferences();
// We only need to run the isolated bundle if webview is enabled
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kWebviewTag))
if (!prefs.webview_tag)
return;
// Setup window overrides in the main world context

Просмотреть файл

@ -31,6 +31,7 @@
#include "shell/renderer/electron_api_service_impl.h"
#include "shell/renderer/electron_autofill_agent.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
#include "third_party/blink/public/web/blink.h"
#include "third_party/blink/public/web/web_custom_element.h" // NOLINT(build/include_alpha)
#include "third_party/blink/public/web/web_frame_widget.h"
@ -112,8 +113,6 @@ RendererClientBase::RendererClientBase() {
ParseSchemesCLISwitch(command_line, switches::kStreamingSchemes);
for (const std::string& scheme : streaming_schemes_list)
media::AddStreamingScheme(scheme.c_str());
isolated_world_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kContextIsolation);
// We rely on the unique process host id which is notified to the
// renderer process via command line switch from the content layer,
// if this switch is removed from the content layer for some reason,
@ -135,9 +134,8 @@ void RendererClientBase::DidCreateScriptContext(
global.SetHidden("contextId", context_id);
#if BUILDFLAG(ENABLE_REMOTE_MODULE)
auto* command_line = base::CommandLine::ForCurrentProcess();
bool enableRemoteModule =
command_line->HasSwitch(switches::kEnableRemoteModule);
render_frame->GetBlinkPreferences().enable_remote_module;
global.SetHidden("enableRemoteModule", enableRemoteModule);
#endif
}
@ -153,6 +151,8 @@ void RendererClientBase::RenderThreadStarted() {
// On macOS, popup menus are rendered by the main process by default.
// This causes problems in OSR, since when the popup is rendered separately,
// it won't be captured in the rendered image.
// TODO(loc): This will be wrong for in-process child windows, as this
// function won't run again for them.
if (command_line->HasSwitch(options::kOffscreen)) {
blink::WebView::SetUseExternalPopupMenus(false);
}
@ -177,8 +177,7 @@ void RendererClientBase::RenderThreadStarted() {
#endif
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
if (command_line->HasSwitch(switches::kEnableSpellcheck))
spellcheck_ = std::make_unique<SpellCheck>(this);
spellcheck_ = std::make_unique<SpellCheck>(this);
#endif
blink::WebCustomElement::AddEmbedderCustomElementName("webview");
@ -274,11 +273,11 @@ void RendererClientBase::RenderFrameCreated(
if (render_frame->IsMainFrame() && render_view) {
blink::WebView* webview = render_view->GetWebView();
if (webview) {
base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
if (cmd->HasSwitch(switches::kGuestInstanceID)) { // webview.
auto prefs = render_frame->GetBlinkPreferences();
if (prefs.guest_instance_id) { // webview.
webview->SetBaseBackgroundColor(SK_ColorTRANSPARENT);
} else { // normal window.
std::string name = cmd->GetSwitchValueASCII(switches::kBackgroundColor);
std::string name = prefs.background_color;
SkColor color =
name.empty() ? SK_ColorTRANSPARENT : ParseHexColor(name);
webview->SetBaseBackgroundColor(color);
@ -300,8 +299,7 @@ void RendererClientBase::RenderFrameCreated(
#endif
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
auto* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kEnableSpellcheck))
if (render_frame->GetBlinkPreferences().enable_spellcheck)
new SpellCheckProvider(render_frame, spellcheck_.get(), this);
#endif
}
@ -330,12 +328,11 @@ bool RendererClientBase::OverrideCreatePlugin(
content::RenderFrame* render_frame,
const blink::WebPluginParams& params,
blink::WebPlugin** plugin) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (params.mime_type.Utf8() == content::kBrowserPluginMimeType ||
#if BUILDFLAG(ENABLE_PDF_VIEWER)
params.mime_type.Utf8() == kPdfPluginMimeType ||
#endif // BUILDFLAG(ENABLE_PDF_VIEWER)
command_line->HasSwitch(switches::kEnablePlugins))
render_frame->GetBlinkPreferences().enable_plugins)
return false;
*plugin = nullptr;
@ -444,7 +441,9 @@ void RendererClientBase::RunScriptsAtDocumentEnd(
v8::Local<v8::Context> RendererClientBase::GetContext(
blink::WebLocalFrame* frame,
v8::Isolate* isolate) const {
if (isolated_world())
auto* render_frame = content::RenderFrame::FromWebFrame(frame);
DCHECK(render_frame);
if (render_frame && render_frame->GetBlinkPreferences().context_isolation)
return frame->WorldScriptContext(isolate, WorldIDs::ISOLATED_WORLD_ID);
else
return frame->MainWorldScriptContext();

Просмотреть файл

@ -79,7 +79,6 @@ class RendererClientBase : public content::ContentRendererClient
std::unique_ptr<blink::WebPrescientNetworking> CreatePrescientNetworking(
content::RenderFrame* render_frame) override;
bool isolated_world() const { return isolated_world_; }
// Get the context that the Electron API is running in.
v8::Local<v8::Context> GetContext(blink::WebLocalFrame* frame,
@ -143,7 +142,6 @@ class RendererClientBase : public content::ContentRendererClient
#if defined(WIDEVINE_CDM_AVAILABLE)
ChromeKeySystemsProvider key_systems_provider_;
#endif
bool isolated_world_;
std::string renderer_client_id_;
// An increasing ID used for identifying an V8 context in this process.
int64_t next_context_id_ = 0;

Просмотреть файл

@ -225,16 +225,16 @@ describe('BrowserView module', () => {
});
describe('window.open()', () => {
it('works in BrowserView', async () => {
it('works in BrowserView', (done) => {
view = new BrowserView();
w.setBrowserView(view);
const newWindow = emittedOnce(view.webContents, 'new-window');
view.webContents.once('new-window', event => event.preventDefault());
view.webContents.setWindowOpenHandler(({ url, frameName }) => {
expect(url).to.equal('http://host/');
expect(frameName).to.equal('host');
done();
return { action: 'deny' };
});
view.webContents.loadFile(path.join(fixtures, 'pages', 'window-open.html'));
const [, url, frameName,,, additionalFeatures] = await newWindow;
expect(url).to.equal('http://host/');
expect(frameName).to.equal('host');
expect(additionalFeatures[0]).to.equal('this-is-not-a-standard-feature');
});
});
});

Просмотреть файл

@ -114,7 +114,7 @@ describe('BrowserWindow with affinity module', () => {
]);
await closeWindow(w, { assertNotWindows: false });
});
it('disables node integration when first window is false', async () => {
it('allows nodeIntegration to enable in second window with the same affinity', async () => {
const [, w1] = await Promise.all([
testNodeIntegration(false),
createWindowWithWebPrefs({
@ -124,7 +124,7 @@ describe('BrowserWindow with affinity module', () => {
})
]);
const [, w2] = await Promise.all([
testNodeIntegration(false),
testNodeIntegration(true),
createWindowWithWebPrefs({
affinity: affinityWithNodeTrue,
preload,
@ -149,7 +149,7 @@ describe('BrowserWindow with affinity module', () => {
await closeWindow(w, { assertNotWindows: false });
});
it('enables node integration when first window is true', async () => {
it('allows nodeIntegration to disable in second window with the same affinity', async () => {
const [, w1] = await Promise.all([
testNodeIntegration(true),
createWindowWithWebPrefs({
@ -159,7 +159,7 @@ describe('BrowserWindow with affinity module', () => {
})
]);
const [, w2] = await Promise.all([
testNodeIntegration(true),
testNodeIntegration(false),
createWindowWithWebPrefs({
affinity: affinityWithNodeFalse,
preload,

Просмотреть файл

@ -2175,20 +2175,27 @@ describe('BrowserWindow module', () => {
it('should open windows in same domain with cross-scripting enabled', async () => {
const w = new BrowserWindow({
show: false,
show: true,
webPreferences: {
sandbox: true,
preload
}
});
w.webContents.once('new-window', (event, url, frameName, disposition, options) => {
options.webPreferences!.preload = preload;
});
w.webContents.setWindowOpenHandler(() => ({
action: 'allow',
overrideBrowserWindowOptions: {
webPreferences: {
preload
}
}
}));
const htmlPath = path.join(__dirname, 'fixtures', 'api', 'sandbox.html?window-open');
const pageUrl = 'file://' + htmlPath;
const answer = emittedOnce(ipcMain, 'answer');
w.loadURL(pageUrl);
const [, url, frameName, , options] = await emittedOnce(w.webContents, 'new-window');
const [, { url, frameName, options }] = await emittedOnce(w.webContents, 'did-create-window');
const expectedUrl = process.platform === 'win32'
? 'file:///' + htmlPath.replace(/\\/g, '/')
: pageUrl;
@ -2202,16 +2209,22 @@ describe('BrowserWindow module', () => {
it('should open windows in another domain with cross-scripting disabled', async () => {
const w = new BrowserWindow({
show: false,
show: true,
webPreferences: {
sandbox: true,
preload
}
});
w.webContents.once('new-window', (event, url, frameName, disposition, options) => {
options.webPreferences!.preload = preload;
});
w.webContents.setWindowOpenHandler(() => ({
action: 'allow',
overrideBrowserWindowOptions: {
webPreferences: {
preload
}
}
}));
w.loadFile(
path.join(__dirname, 'fixtures', 'api', 'sandbox.html'),
{ search: 'window-open-external' }
@ -2267,12 +2280,10 @@ describe('BrowserWindow module', () => {
});
const preloadPath = path.join(fixtures, 'api', 'new-window-preload.js');
w.webContents.once('new-window', (event, url, frameName, disposition, options) => {
options.webPreferences!.preload = preloadPath;
});
w.webContents.setWindowOpenHandler(() => ({ action: 'allow', overrideBrowserWindowOptions: { webPreferences: { preload: preloadPath } } }));
w.loadFile(path.join(fixtures, 'api', 'new-window.html'));
const [, args] = await emittedOnce(ipcMain, 'answer');
expect(args).to.include('--enable-sandbox');
const [, { argv }] = await emittedOnce(ipcMain, 'answer');
expect(argv).to.include('--enable-sandbox');
});
it('should open windows with the options configured via new-window event listeners', async () => {
@ -2284,11 +2295,7 @@ describe('BrowserWindow module', () => {
});
const preloadPath = path.join(fixtures, 'api', 'new-window-preload.js');
w.webContents.once('new-window', (event, url, frameName, disposition, options) => {
options.webPreferences!.preload = preloadPath;
const prefs = options.webPreferences as any;
prefs.foo = 'bar';
});
w.webContents.setWindowOpenHandler(() => ({ action: 'allow', overrideBrowserWindowOptions: { webPreferences: { preload: preloadPath, foo: 'bar' } } }));
w.loadFile(path.join(fixtures, 'api', 'new-window.html'));
const [[, childWebContents]] = await Promise.all([
emittedOnce(app, 'web-contents-created'),
@ -2307,11 +2314,13 @@ describe('BrowserWindow module', () => {
}
});
let childWc: WebContents | null = null;
w.webContents.on('new-window', (event, url, frameName, disposition, options) => {
options.webPreferences!.preload = preload;
childWc = (options as any).webContents;
w.webContents.setWindowOpenHandler(() => ({ action: 'allow', overrideBrowserWindowOptions: { webPreferences: { preload } } }));
w.webContents.on('did-create-window', (win) => {
childWc = win.webContents;
expect(w.webContents).to.not.equal(childWc);
});
ipcMain.once('parent-ready', function (event) {
expect(event.sender).to.equal(w.webContents, 'sender should be the parent');
event.sender.send('verified');
@ -2438,9 +2447,7 @@ describe('BrowserWindow module', () => {
enableRemoteModule: true
}
});
w.webContents.once('new-window', (event, url, frameName, disposition, options) => {
options.webPreferences!.preload = preload;
});
w.webContents.setWindowOpenHandler(() => ({ action: 'allow', overrideBrowserWindowOptions: { webPreferences: { preload } } }));
w.loadFile(path.join(__dirname, 'fixtures', 'api', 'sandbox.html'), { search: 'reload-remote-child' });
@ -2602,20 +2609,30 @@ describe('BrowserWindow module', () => {
});
it('should inherit the nativeWindowOpen setting in opened windows', async () => {
const preloadPath = path.join(fixtures, 'api', 'new-window-preload.js');
w.webContents.once('new-window', (event, url, frameName, disposition, options) => {
options.webPreferences!.preload = preloadPath;
});
w.webContents.setWindowOpenHandler(() => ({
action: 'allow',
overrideBrowserWindowOptions: {
webPreferences: {
preload: preloadPath
}
}
}));
w.loadFile(path.join(fixtures, 'api', 'new-window.html'));
const [, args] = await emittedOnce(ipcMain, 'answer');
expect(args).to.include('--native-window-open');
const [, { nativeWindowOpen }] = await emittedOnce(ipcMain, 'answer');
expect(nativeWindowOpen).to.be.true();
});
it('should open windows with the options configured via new-window event listeners', async () => {
const preloadPath = path.join(fixtures, 'api', 'new-window-preload.js');
w.webContents.once('new-window', (event, url, frameName, disposition, options) => {
options.webPreferences!.preload = preloadPath;
const prefs = options.webPreferences! as any;
prefs.foo = 'bar';
});
w.webContents.setWindowOpenHandler(() => ({
action: 'allow',
overrideBrowserWindowOptions: {
webPreferences: {
preload: preloadPath,
foo: 'bar'
}
}
}));
w.loadFile(path.join(fixtures, 'api', 'new-window.html'));
const [[, childWebContents]] = await Promise.all([
emittedOnce(app, 'web-contents-created'),
@ -2655,13 +2672,19 @@ describe('BrowserWindow module', () => {
}
});
w.webContents.once('new-window', (event, url, frameName, disposition, options) => {
options.webPreferences!.preload = path.join(fixtures, 'api', 'window-open-preload.js');
});
w.webContents.setWindowOpenHandler(() => ({
action: 'allow',
overrideBrowserWindowOptions: {
webPreferences: {
preload: path.join(fixtures, 'api', 'window-open-preload.js')
}
}
}));
w.loadFile(path.join(fixtures, 'api', 'window-open-location-open.html'));
const [, args, typeofProcess] = await emittedOnce(ipcMain, 'answer');
expect(args).not.to.include('--node-integration');
expect(args).to.include('--native-window-open');
const [, { nodeIntegration, nativeWindowOpen, typeofProcess }] = await emittedOnce(ipcMain, 'answer');
expect(nodeIntegration).to.be.false();
expect(nativeWindowOpen).to.be.true();
expect(typeofProcess).to.eql('undefined');
});
@ -2675,11 +2698,16 @@ describe('BrowserWindow module', () => {
}
});
w.webContents.once('new-window', (event, url, frameName, disposition, options) => {
options.webPreferences!.preload = path.join(fixtures, 'api', 'window-open-preload.js');
});
w.webContents.setWindowOpenHandler(() => ({
action: 'allow',
overrideBrowserWindowOptions: {
webPreferences: {
preload: path.join(fixtures, 'api', 'window-open-preload.js')
}
}
}));
w.loadFile(path.join(fixtures, 'api', 'window-open-location-open.html'));
const [, , , windowOpenerIsNull] = await emittedOnce(ipcMain, 'answer');
const [, { windowOpenerIsNull }] = await emittedOnce(ipcMain, 'answer');
expect(windowOpenerIsNull).to.be.false('window.opener is null');
});
});

Просмотреть файл

@ -82,15 +82,19 @@ describe('window.postMessage', () => {
await closeAllWindows();
});
it('sets the source and origin correctly', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true } });
w.loadURL(`file://${fixturesPath}/pages/window-open-postMessage-driver.html`);
const [, message] = await emittedOnce(ipcMain, 'complete');
expect(message.data).to.equal('testing');
expect(message.origin).to.equal('file://');
expect(message.sourceEqualsOpener).to.equal(true);
expect(message.eventOrigin).to.equal('file://');
});
for (const nativeWindowOpen of [true, false]) {
describe(`when nativeWindowOpen: ${nativeWindowOpen}`, () => {
it('sets the source and origin correctly', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, nativeWindowOpen } });
w.loadURL(`file://${fixturesPath}/pages/window-open-postMessage-driver.html`);
const [, message] = await emittedOnce(ipcMain, 'complete');
expect(message.data).to.equal('testing');
expect(message.origin).to.equal('file://');
expect(message.sourceEqualsOpener).to.equal(true);
expect(message.eventOrigin).to.equal('file://');
});
});
}
});
describe('focus handling', () => {
@ -620,7 +624,7 @@ describe('chromium features', () => {
describe('window.open', () => {
for (const show of [true, false]) {
it(`inherits parent visibility over parent {show=${show}} option`, async () => {
it(`shows the child regardless of parent visibility when parent {show=${show}}`, async () => {
const w = new BrowserWindow({ show });
// toggle visibility
@ -635,7 +639,7 @@ describe('chromium features', () => {
const newWindow = emittedOnce(w.webContents, 'new-window');
w.loadFile(path.join(fixturesPath, 'pages', 'window-open.html'));
const [,,,, options] = await newWindow;
expect(options.show).to.equal(w.isVisible());
expect(options.show).to.equal(true);
});
}
@ -671,35 +675,6 @@ describe('chromium features', () => {
expect(preferences.javascript).to.be.false();
});
it('handles cycles when merging the parent options into the child options', async () => {
const foo = {} as any;
foo.bar = foo;
foo.baz = {
hello: {
world: true
}
};
foo.baz2 = foo.baz;
const w = new BrowserWindow({ show: false, foo: foo } as any);
w.loadFile(path.join(fixturesPath, 'pages', 'window-open.html'));
const [,,,, options] = await emittedOnce(w.webContents, 'new-window');
expect(options.show).to.be.false();
expect((options as any).foo).to.deep.equal({
bar: undefined,
baz: {
hello: {
world: true
}
},
baz2: {
hello: {
world: true
}
}
});
});
it('defines a window.location getter', async () => {
let targetURL: string;
if (process.platform === 'win32') {
@ -925,10 +900,15 @@ describe('chromium features', () => {
for (const sandboxPopup of [false, true]) {
const description = `when parent=${s(parent)} opens child=${s(child)} with nodeIntegration=${nodeIntegration} nativeWindowOpen=${nativeWindowOpen} sandboxPopup=${sandboxPopup}, child should ${openerAccessible ? '' : 'not '}be able to access opener`;
it(description, async () => {
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, nativeWindowOpen } });
w.webContents.once('new-window', (e, url, frameName, disposition, options) => {
options!.webPreferences!.sandbox = sandboxPopup;
});
const w = new BrowserWindow({ show: true, webPreferences: { nodeIntegration: true, nativeWindowOpen } });
w.webContents.setWindowOpenHandler(() => ({
action: 'allow',
overrideBrowserWindowOptions: {
webPreferences: {
sandbox: sandboxPopup
}
}
}));
await w.loadURL(parent);
const childOpenerLocation = await w.webContents.executeJavaScript(`new Promise(resolve => {
window.addEventListener('message', function f(e) {

Просмотреть файл

@ -2,33 +2,33 @@
[
"top=5,left=10,resizable=no",
{
"sender": "[WebContents]",
"returnValue": "placeholder-guest-contents-id"
"sender": "[WebContents]"
},
"about:blank",
"frame name",
"new-window",
{
"show": true,
"width": 800,
"height": 600,
"webContents": "[WebContents]",
"title": "frame name",
"backgroundColor": "blue",
"focusable": false,
"webPreferences": {
"nativeWindowOpen": true,
"sandbox": true,
"backgroundColor": "blue",
"nodeIntegration": false,
"webviewTag": false,
"nodeIntegrationInSubFrames": false
"nodeIntegrationInSubFrames": false,
"openerId": null
},
"show": true,
"height": 600,
"top": 5,
"left": 10,
"resizable": false,
"x": 10,
"y": 5,
"backgroundColor": "blue",
"focusable": false
"webContents": "[WebContents]"
},
[],
{
@ -40,32 +40,32 @@
[
"zoomFactor=2,resizable=0,x=0,y=10",
{
"sender": "[WebContents]",
"returnValue": "placeholder-guest-contents-id"
"sender": "[WebContents]"
},
"about:blank",
"frame name",
"new-window",
{
"show": true,
"width": 800,
"height": 600,
"webContents": "[WebContents]",
"title": "frame name",
"backgroundColor": "blue",
"focusable": false,
"webPreferences": {
"zoomFactor": "2",
"nativeWindowOpen": true,
"sandbox": true,
"backgroundColor": "blue",
"zoomFactor": "2",
"nodeIntegration": false,
"webviewTag": false,
"nodeIntegrationInSubFrames": false
"nodeIntegrationInSubFrames": false,
"openerId": null
},
"show": true,
"height": 600,
"resizable": false,
"x": 0,
"y": 10,
"backgroundColor": "blue",
"focusable": false
"webContents": "[WebContents]"
},
[],
{
@ -77,30 +77,30 @@
[
"backgroundColor=gray,webPreferences=0,x=100,y=100",
{
"sender": "[WebContents]",
"returnValue": "placeholder-guest-contents-id"
"sender": "[WebContents]"
},
"about:blank",
"frame name",
"new-window",
{
"show": true,
"width": 800,
"height": 600,
"webContents": "[WebContents]",
"title": "frame name",
"backgroundColor": "gray",
"focusable": false,
"webPreferences": {
"nativeWindowOpen": true,
"sandbox": true,
"backgroundColor": "gray",
"nodeIntegration": false,
"webviewTag": false,
"nodeIntegrationInSubFrames": false
"nodeIntegrationInSubFrames": false,
"openerId": null
},
"backgroundColor": "gray",
"show": true,
"height": 600,
"x": 100,
"y": 100,
"focusable": false
"webContents": "[WebContents]"
},
[],
{
@ -112,30 +112,30 @@
[
"x=50,y=20,title=sup",
{
"sender": "[WebContents]",
"returnValue": "placeholder-guest-contents-id"
"sender": "[WebContents]"
},
"about:blank",
"frame name",
"new-window",
{
"show": true,
"width": 800,
"height": 600,
"webContents": "[WebContents]",
"title": "sup",
"backgroundColor": "blue",
"focusable": false,
"webPreferences": {
"nativeWindowOpen": true,
"sandbox": true,
"backgroundColor": "blue",
"nodeIntegration": false,
"webviewTag": false,
"nodeIntegrationInSubFrames": false
"nodeIntegrationInSubFrames": false,
"openerId": null
},
"show": true,
"height": 600,
"x": 50,
"y": 20,
"backgroundColor": "blue",
"focusable": false
"webContents": "[WebContents]"
},
[],
{
@ -147,32 +147,32 @@
[
"show=false,top=1,left=1",
{
"sender": "[WebContents]",
"returnValue": "placeholder-guest-contents-id"
"sender": "[WebContents]"
},
"about:blank",
"frame name",
"new-window",
{
"show": false,
"width": 800,
"height": 600,
"webContents": "[WebContents]",
"title": "frame name",
"backgroundColor": "blue",
"focusable": false,
"webPreferences": {
"nativeWindowOpen": true,
"sandbox": true,
"backgroundColor": "blue",
"nodeIntegration": false,
"webviewTag": false,
"nodeIntegrationInSubFrames": false
"nodeIntegrationInSubFrames": false,
"openerId": null
},
"show": false,
"height": 600,
"top": 1,
"left": 1,
"x": 1,
"y": 1,
"backgroundColor": "blue",
"focusable": false
"webContents": "[WebContents]"
},
[],
{

Просмотреть файл

@ -9,21 +9,22 @@
"frame name",
"new-window",
{
"show": true,
"title": "frame name",
"width": 800,
"height": 600,
"top": 5,
"left": 10,
"resizable": false,
"x": 10,
"y": 5,
"title": "frame name",
"webPreferences": {
"nodeIntegration": false,
"webviewTag": false,
"nodeIntegrationInSubFrames": false,
"openerId": "placeholder-opener-id"
},
"width": 800,
"height": 600,
"show": false
"webContents": "[WebContents]"
},
[],
{
@ -42,10 +43,13 @@
"frame name",
"new-window",
{
"show": true,
"title": "frame name",
"width": 800,
"height": 600,
"resizable": false,
"x": 0,
"y": 10,
"title": "frame name",
"webPreferences": {
"zoomFactor": "2",
"nodeIntegration": false,
@ -53,9 +57,7 @@
"nodeIntegrationInSubFrames": false,
"openerId": "placeholder-opener-id"
},
"width": 800,
"height": 600,
"show": false
"webContents": "[WebContents]"
},
[],
{
@ -74,6 +76,10 @@
"frame name",
"new-window",
{
"show": true,
"title": "frame name",
"width": 800,
"height": 600,
"backgroundColor": "gray",
"webPreferences": {
"nodeIntegration": false,
@ -84,10 +90,7 @@
},
"x": 100,
"y": 100,
"title": "frame name",
"width": 800,
"height": 600,
"show": false
"webContents": "[WebContents]"
},
[],
{
@ -106,18 +109,19 @@
"frame name",
"new-window",
{
"show": true,
"title": "sup",
"width": 800,
"height": 600,
"x": 50,
"y": 20,
"title": "sup",
"webPreferences": {
"nodeIntegration": false,
"webviewTag": false,
"nodeIntegrationInSubFrames": false,
"openerId": "placeholder-opener-id"
},
"width": 800,
"height": 600,
"show": false
"webContents": "[WebContents]"
},
[],
{
@ -137,19 +141,20 @@
"new-window",
{
"show": false,
"title": "frame name",
"width": 800,
"height": 600,
"top": 1,
"left": 1,
"x": 1,
"y": 1,
"title": "frame name",
"webPreferences": {
"nodeIntegration": false,
"webviewTag": false,
"nodeIntegrationInSubFrames": false,
"openerId": "placeholder-opener-id"
},
"width": 800,
"height": 600
"webContents": "[WebContents]"
},
[],
{

Просмотреть файл

@ -1,15 +1,16 @@
import { BrowserWindow } from 'electron';
import { writeFileSync, readFileSync } from 'fs';
import { resolve } from 'path';
import { expect } from 'chai';
import { expect, assert } from 'chai';
import { closeAllWindows } from './window-helpers';
const { emittedOnce } = require('./events-helpers');
function genSnapshot (browserWindow: BrowserWindow, features: string) {
return new Promise((resolve) => {
browserWindow.webContents.on('new-window', (...args: any[]) => {
resolve([features, ...args]);
});
browserWindow.webContents.executeJavaScript(`window.open('about:blank', 'frame name', '${features}')`);
browserWindow.webContents.executeJavaScript(`window.open('about:blank', 'frame name', '${features}') && true`);
});
}
@ -52,7 +53,7 @@ describe('new-window event', () => {
beforeEach((done) => {
browserWindow = new BrowserWindow(browserWindowOptions);
browserWindow.loadURL('about:blank');
browserWindow.on('ready-to-show', () => done());
browserWindow.on('ready-to-show', () => { done(); });
});
afterEach(closeAllWindows);
@ -86,6 +87,100 @@ describe('new-window event', () => {
}
});
describe('webContents.setWindowOpenHandler', () => {
const testConfig = {
native: {
browserWindowOptions: {
show: false,
webPreferences: {
nativeWindowOpen: true
}
}
},
proxy: {
browserWindowOptions: {
show: false,
webPreferences: {
nativeWindowOpen: false
}
}
}
};
for (const testName of Object.keys(testConfig) as (keyof typeof testConfig)[]) {
let browserWindow: BrowserWindow;
const { browserWindowOptions } = testConfig[testName];
describe(testName, () => {
beforeEach((done) => {
browserWindow = new BrowserWindow(browserWindowOptions);
browserWindow.loadURL('about:blank');
browserWindow.on('ready-to-show', () => { browserWindow.show(); done(); });
});
afterEach(closeAllWindows);
it('does not fire window creation events if an override returns action: deny', (done) => {
browserWindow.webContents.setWindowOpenHandler(() => ({ action: 'deny' }));
browserWindow.webContents.on('new-window', () => {
assert.fail('new-window should not to be called with an overridden window.open');
});
browserWindow.webContents.on('did-create-window', () => {
assert.fail('did-create-window should not to be called with an overridden window.open');
});
browserWindow.webContents.executeJavaScript("window.open('about:blank') && true");
setTimeout(() => {
done();
}, 500);
});
it('fires handler with correct params', (done) => {
const testFrameName = 'test-frame-name';
const testFeatures = 'top=10&left=10&something-unknown';
const testUrl = 'app://does-not-exist/';
browserWindow.webContents.setWindowOpenHandler(({ url, frameName, features }) => {
expect(url).to.equal(testUrl);
expect(frameName).to.equal(testFrameName);
expect(features).to.equal(testFeatures);
done();
return { action: 'deny' };
});
browserWindow.webContents.executeJavaScript(`window.open('${testUrl}', '${testFrameName}', '${testFeatures}') && true`);
});
it('does fire window creation events if an override returns action: allow', async () => {
browserWindow.webContents.setWindowOpenHandler(() => ({ action: 'allow' }));
setImmediate(() => {
browserWindow.webContents.executeJavaScript("window.open('about:blank') && true");
});
await Promise.all([
emittedOnce(browserWindow.webContents, 'did-create-window'),
emittedOnce(browserWindow.webContents, 'new-window')
]);
});
it('can change webPreferences of child windows', (done) => {
browserWindow.webContents.setWindowOpenHandler(() => ({ action: 'allow', overrideBrowserWindowOptions: { webPreferences: { defaultFontSize: 30 } } }));
browserWindow.webContents.on('did-create-window', async (childWindow) => {
await childWindow.webContents.executeJavaScript("document.write('hello')");
const size = await childWindow.webContents.executeJavaScript("getComputedStyle(document.querySelector('body')).fontSize");
expect(size).to.equal('30px');
done();
});
browserWindow.webContents.executeJavaScript("window.open('about:blank') && true");
});
});
}
});
function stringifySnapshots (snapshots: any, pretty = false) {
return JSON.stringify(snapshots, (key, value) => {
if (['sender', 'webContents'].includes(key)) {

7
spec/fixtures/api/new-window-preload.js поставляемый
Просмотреть файл

@ -1,4 +1,7 @@
const { ipcRenderer } = require('electron');
const { ipcRenderer, webFrame } = require('electron');
ipcRenderer.send('answer', process.argv);
ipcRenderer.send('answer', {
nativeWindowOpen: webFrame.getWebPreference('nativeWindowOpen'),
argv: process.argv
});
window.close();

10
spec/fixtures/api/window-open-preload.js поставляемый
Просмотреть файл

@ -1,9 +1,15 @@
const { ipcRenderer } = require('electron');
const { ipcRenderer, webFrame } = require('electron');
setImmediate(function () {
if (window.location.toString() === 'bar://page/') {
const windowOpenerIsNull = window.opener == null;
ipcRenderer.send('answer', process.argv, typeof global.process, windowOpenerIsNull);
ipcRenderer.send('answer', {
nativeWindowOpen: webFrame.getWebPreference('nativeWindowOpen'),
nodeIntegration: webFrame.getWebPreference('nodeIntegration'),
sandbox: webFrame.getWebPreference('sandbox'),
typeofProcess: typeof global.process,
windowOpenerIsNull
});
window.close();
}
});

4
spec/fixtures/pages/visibilitychange.html поставляемый
Просмотреть файл

@ -4,7 +4,9 @@
const {ipcRenderer} = require('electron')
ipcRenderer.send('pong', document.visibilityState, document.hidden)
document.addEventListener('visibilitychange', function () {
ipcRenderer.send('pong', document.visibilityState, document.hidden)
setTimeout(() => {
ipcRenderer.send('pong', document.visibilityState, document.hidden)
}, 500);
})
</script>
</body>

Двоичные данные
spec/fixtures/test.asar/deleteme/a.asar поставляемый

Двоичный файл не отображается.

5
typings/internal-ambient.d.ts поставляемый
Просмотреть файл

@ -1,3 +1,4 @@
/* eslint-disable no-var */
declare var internalBinding: any;
declare var nodeProcess: any;
declare var isolatedWorld: any;
@ -45,8 +46,8 @@ declare namespace NodeJS {
clearWeaklyTrackedValues(): void;
getWeaklyTrackedValues(): any[];
addRemoteObjectRef(contextId: string, id: number): void;
isSameOrigin(a: string, b: string): boolean;
triggerFatalErrorForTesting(): void;
isSameOrigin(left: string, right: string): boolean;
}
interface EnvironmentBinding {
@ -118,7 +119,7 @@ declare namespace NodeJS {
session?: Electron.Session;
partition?: string;
referrer?: string;
}
};
type ResponseHead = {
statusCode: number;
statusMessage: string;

3
typings/internal-electron.d.ts поставляемый
Просмотреть файл

@ -64,6 +64,9 @@ declare namespace Electron {
equal(other: WebContents): boolean;
_initiallyShown: boolean;
browserWindowOptions: BrowserWindowConstructorOptions;
_windowOpenHandler: ((opts: {url: string, frameName: string, features: string}) => any) | null;
_callWindowOpenHandler(event: any, url: string, frameName: string, rawFeatures: string): Electron.BrowserWindowConstructorOptions | null;
_setNextChildWebPreferences(prefs: Partial<Electron.BrowserWindowConstructorOptions['webPreferences']> & Pick<Electron.BrowserWindowConstructorOptions, 'backgroundColor'>): void;
_send(internal: boolean, sendToAll: boolean, channel: string, args: any): boolean;
_sendToFrame(internal: boolean, sendToAll: boolean, frameId: number, channel: string, args: any): boolean;
_sendToFrameInternal(frameId: number, channel: string, ...args: any[]): boolean;

Просмотреть файл

@ -18,10 +18,10 @@
esutils "^2.0.2"
js-tokens "^4.0.0"
"@electron/docs-parser@^0.10.0":
version "0.10.0"
resolved "https://registry.yarnpkg.com/@electron/docs-parser/-/docs-parser-0.10.0.tgz#cc399f3847c37a38af8c13c711dc57eb07e21994"
integrity sha512-dNUNsW3tC5VWyWDD6awxDsA0Wc91PVaG4KmSBnqQmXE7bNjnEFE1hf5TaH0KOmJq1KMyQ2rbp7rrrvqRoLKP1Q==
"@electron/docs-parser@^0.10.1":
version "0.10.1"
resolved "https://registry.yarnpkg.com/@electron/docs-parser/-/docs-parser-0.10.1.tgz#aa5911c4ef2ec237d7a126111019ec45058088db"
integrity sha512-gDKGfc4ilPsKGCCyCCU20iJnHRV3QPYthOocgfAnzm5lOANssxLjl4KeN/DO8nTmKX/BmFsf+XGNa4Penq0L8A==
dependencies:
"@types/markdown-it" "^0.0.9"
chai "^4.2.0"