mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
browser(firefox): bindings in isolated worlds (#6493)
This commit is contained in:
parent
d243ae7ede
commit
f8039bed10
@ -1,2 +1,2 @@
|
|||||||
1258
|
1259
|
||||||
Changed: pavel.feldman@gmail.com Mon 10 May 2021 09:56:40 PM PDT
|
Changed: yurys@chromium.org Tue 11 May 2021 09:09:59 AM PDT
|
||||||
|
|||||||
@ -479,8 +479,8 @@ class PageTarget {
|
|||||||
await this._channel.connect('').send('addScriptToEvaluateOnNewDocument', script).catch(e => void e);
|
await this._channel.connect('').send('addScriptToEvaluateOnNewDocument', script).catch(e => void e);
|
||||||
}
|
}
|
||||||
|
|
||||||
async addBinding(name, script) {
|
async addBinding(worldName, name, script) {
|
||||||
await this._channel.connect('').send('addBinding', { name, script }).catch(e => void e);
|
await this._channel.connect('').send('addBinding', { worldName, name, script }).catch(e => void e);
|
||||||
}
|
}
|
||||||
|
|
||||||
async applyContextSetting(name, value) {
|
async applyContextSetting(name, value) {
|
||||||
@ -717,9 +717,9 @@ class BrowserContext {
|
|||||||
await Promise.all(Array.from(this.pages).map(page => page.addScriptToEvaluateOnNewDocument(script)));
|
await Promise.all(Array.from(this.pages).map(page => page.addScriptToEvaluateOnNewDocument(script)));
|
||||||
}
|
}
|
||||||
|
|
||||||
async addBinding(name, script) {
|
async addBinding(worldName, name, script) {
|
||||||
this.bindings.push({ name, script });
|
this.bindings.push({ worldName, name, script });
|
||||||
await Promise.all(Array.from(this.pages).map(page => page.addBinding(name, script)));
|
await Promise.all(Array.from(this.pages).map(page => page.addBinding(worldName, name, script)));
|
||||||
}
|
}
|
||||||
|
|
||||||
async applySetting(name, value) {
|
async applySetting(name, value) {
|
||||||
|
|||||||
@ -148,10 +148,10 @@ class FrameTree {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
addBinding(name, script) {
|
addBinding(worldName, name, script) {
|
||||||
this._bindings.set(name, script);
|
this._bindings.set(worldName + ':' + name, {worldName, name, script});
|
||||||
for (const frame of this.frames())
|
for (const frame of this.frames())
|
||||||
frame._addBinding(name, script);
|
frame._addBinding(worldName, name, script);
|
||||||
}
|
}
|
||||||
|
|
||||||
frameForDocShell(docShell) {
|
frameForDocShell(docShell) {
|
||||||
@ -297,7 +297,6 @@ class FrameTree {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FrameTree.Events = {
|
FrameTree.Events = {
|
||||||
BindingCalled: 'bindingcalled',
|
|
||||||
FrameAttached: 'frameattached',
|
FrameAttached: 'frameattached',
|
||||||
FrameDetached: 'framedetached',
|
FrameDetached: 'framedetached',
|
||||||
WorkerCreated: 'workercreated',
|
WorkerCreated: 'workercreated',
|
||||||
@ -461,18 +460,18 @@ class Frame {
|
|||||||
this._executionContext = null;
|
this._executionContext = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
_addBinding(name, script) {
|
_getOrCreateIsolatedContext(worldName) {
|
||||||
Cu.exportFunction((...args) => {
|
for (let context of this._isolatedWorlds.values()) {
|
||||||
this._frameTree.emit(FrameTree.Events.BindingCalled, {
|
if (context.auxData().name === worldName)
|
||||||
frame: this,
|
return context;
|
||||||
name,
|
}
|
||||||
payload: args[0]
|
return this.createIsolatedWorld(worldName);
|
||||||
});
|
}
|
||||||
}, this.domWindow(), {
|
|
||||||
defineAs: name,
|
_addBinding(worldName, name, script) {
|
||||||
});
|
const executionContext = worldName ? this._getOrCreateIsolatedContext(worldName) : this._executionContext;
|
||||||
if (this._executionContext)
|
if (executionContext)
|
||||||
this._evaluateScriptSafely(this._executionContext, script);
|
executionContext.addBinding(name, script);
|
||||||
}
|
}
|
||||||
|
|
||||||
_evaluateScriptSafely(executionContext, script) {
|
_evaluateScriptSafely(executionContext, script) {
|
||||||
@ -494,20 +493,25 @@ class Frame {
|
|||||||
|
|
||||||
if (this._executionContext)
|
if (this._executionContext)
|
||||||
this._runtime.destroyExecutionContext(this._executionContext);
|
this._runtime.destroyExecutionContext(this._executionContext);
|
||||||
|
for (const world of this._isolatedWorlds.values())
|
||||||
|
this._runtime.destroyExecutionContext(world);
|
||||||
|
this._isolatedWorlds.clear();
|
||||||
|
|
||||||
this._executionContext = this._runtime.createExecutionContext(this.domWindow(), this.domWindow(), {
|
this._executionContext = this._runtime.createExecutionContext(this.domWindow(), this.domWindow(), {
|
||||||
frameId: this._frameId,
|
frameId: this._frameId,
|
||||||
name: '',
|
name: '',
|
||||||
});
|
});
|
||||||
for (const [name, script] of this._frameTree._bindings)
|
for (const {script, worldName} of this._frameTree._isolatedWorlds.values())
|
||||||
this._addBinding(name, script);
|
this.createIsolatedWorld(worldName);
|
||||||
|
|
||||||
|
// Add bindings before evaluating scripts.
|
||||||
|
for (const [id, {worldName, name, script}] of this._frameTree._bindings)
|
||||||
|
this._addBinding(worldName, name, script);
|
||||||
|
|
||||||
for (const script of this._frameTree._scriptsToEvaluateOnNewDocument.values())
|
for (const script of this._frameTree._scriptsToEvaluateOnNewDocument.values())
|
||||||
this._evaluateScriptSafely(this._executionContext, script);
|
this._evaluateScriptSafely(this._executionContext, script);
|
||||||
|
|
||||||
for (const world of this._isolatedWorlds.values())
|
|
||||||
this._runtime.destroyExecutionContext(world);
|
|
||||||
this._isolatedWorlds.clear();
|
|
||||||
for (const {script, worldName} of this._frameTree._isolatedWorlds.values()) {
|
for (const {script, worldName} of this._frameTree._isolatedWorlds.values()) {
|
||||||
const context = worldName ? this.createIsolatedWorld(worldName) : this.executionContext();
|
const context = worldName ? this._getOrCreateIsolatedContext(worldName) : this.executionContext();
|
||||||
this._evaluateScriptSafely(context, script);
|
this._evaluateScriptSafely(context, script);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -104,7 +104,6 @@ class PageAgent {
|
|||||||
helper.addObserver(this._onDocumentOpenLoad.bind(this), 'juggler-document-open-loaded'),
|
helper.addObserver(this._onDocumentOpenLoad.bind(this), 'juggler-document-open-loaded'),
|
||||||
helper.addEventListener(this._messageManager, 'error', this._onError.bind(this)),
|
helper.addEventListener(this._messageManager, 'error', this._onError.bind(this)),
|
||||||
helper.on(this._frameTree, 'load', this._onLoad.bind(this)),
|
helper.on(this._frameTree, 'load', this._onLoad.bind(this)),
|
||||||
helper.on(this._frameTree, 'bindingcalled', this._onBindingCalled.bind(this)),
|
|
||||||
helper.on(this._frameTree, 'frameattached', this._onFrameAttached.bind(this)),
|
helper.on(this._frameTree, 'frameattached', this._onFrameAttached.bind(this)),
|
||||||
helper.on(this._frameTree, 'framedetached', this._onFrameDetached.bind(this)),
|
helper.on(this._frameTree, 'framedetached', this._onFrameDetached.bind(this)),
|
||||||
helper.on(this._frameTree, 'navigationstarted', this._onNavigationStarted.bind(this)),
|
helper.on(this._frameTree, 'navigationstarted', this._onNavigationStarted.bind(this)),
|
||||||
@ -133,8 +132,9 @@ class PageAgent {
|
|||||||
this._runtime.events.onConsoleMessage(msg => this._browserPage.emit('runtimeConsole', msg)),
|
this._runtime.events.onConsoleMessage(msg => this._browserPage.emit('runtimeConsole', msg)),
|
||||||
this._runtime.events.onExecutionContextCreated(this._onExecutionContextCreated.bind(this)),
|
this._runtime.events.onExecutionContextCreated(this._onExecutionContextCreated.bind(this)),
|
||||||
this._runtime.events.onExecutionContextDestroyed(this._onExecutionContextDestroyed.bind(this)),
|
this._runtime.events.onExecutionContextDestroyed(this._onExecutionContextDestroyed.bind(this)),
|
||||||
|
this._runtime.events.onBindingCalled(this._onBindingCalled.bind(this)),
|
||||||
browserChannel.register('page', {
|
browserChannel.register('page', {
|
||||||
addBinding: ({ name, script }) => this._frameTree.addBinding(name, script),
|
addBinding: ({ worldName, name, script }) => this._frameTree.addBinding(worldName, name, script),
|
||||||
addScriptToEvaluateOnNewDocument: ({script, worldName}) => this._frameTree.addScriptToEvaluateOnNewDocument(script, worldName),
|
addScriptToEvaluateOnNewDocument: ({script, worldName}) => this._frameTree.addScriptToEvaluateOnNewDocument(script, worldName),
|
||||||
adoptNode: this._adoptNode.bind(this),
|
adoptNode: this._adoptNode.bind(this),
|
||||||
crash: this._crash.bind(this),
|
crash: this._crash.bind(this),
|
||||||
@ -355,9 +355,9 @@ class PageAgent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_onBindingCalled({frame, name, payload}) {
|
_onBindingCalled({executionContextId, name, payload}) {
|
||||||
this._browserPage.emit('pageBindingCalled', {
|
this._browserPage.emit('pageBindingCalled', {
|
||||||
executionContextId: frame.executionContext().id(),
|
executionContextId,
|
||||||
name,
|
name,
|
||||||
payload
|
payload
|
||||||
});
|
});
|
||||||
|
|||||||
@ -74,6 +74,7 @@ class Runtime {
|
|||||||
onErrorFromWorker: createEvent(),
|
onErrorFromWorker: createEvent(),
|
||||||
onExecutionContextCreated: createEvent(),
|
onExecutionContextCreated: createEvent(),
|
||||||
onExecutionContextDestroyed: createEvent(),
|
onExecutionContextDestroyed: createEvent(),
|
||||||
|
onBindingCalled: createEvent(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,6 +167,10 @@ class Runtime {
|
|||||||
_registerConsoleObserver(Services) {
|
_registerConsoleObserver(Services) {
|
||||||
const consoleObserver = ({wrappedJSObject}, topic, data) => {
|
const consoleObserver = ({wrappedJSObject}, topic, data) => {
|
||||||
const executionContext = Array.from(this._executionContexts.values()).find(context => {
|
const executionContext = Array.from(this._executionContexts.values()).find(context => {
|
||||||
|
// There is no easy way to determine isolated world context and we normally don't write
|
||||||
|
// objects to console from utility worlds so we always return main world context here.
|
||||||
|
if (context._isIsolatedWorldContext())
|
||||||
|
return false;
|
||||||
const domWindow = context._domWindow;
|
const domWindow = context._domWindow;
|
||||||
return domWindow && domWindow.windowGlobalChild.innerWindowId === wrappedJSObject.innerID;
|
return domWindow && domWindow.windowGlobalChild.innerWindowId === wrappedJSObject.innerID;
|
||||||
});
|
});
|
||||||
@ -311,6 +316,10 @@ class ExecutionContext {
|
|||||||
return this._auxData;
|
return this._auxData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_isIsolatedWorldContext() {
|
||||||
|
return !!this._auxData.name;
|
||||||
|
}
|
||||||
|
|
||||||
async evaluateScript(script, exceptionDetails = {}) {
|
async evaluateScript(script, exceptionDetails = {}) {
|
||||||
const userInputHelper = this._domWindow ? this._domWindow.windowUtils.setHandlingUserInput(true) : null;
|
const userInputHelper = this._domWindow ? this._domWindow.windowUtils.setHandlingUserInput(true) : null;
|
||||||
if (this._domWindow && this._domWindow.document)
|
if (this._domWindow && this._domWindow.document)
|
||||||
@ -365,6 +374,23 @@ class ExecutionContext {
|
|||||||
return this._createRemoteObject(obj);
|
return this._createRemoteObject(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addBinding(name, script) {
|
||||||
|
Cu.exportFunction((...args) => {
|
||||||
|
emitEvent(this._runtime.events.onBindingCalled, {
|
||||||
|
executionContextId: this._id,
|
||||||
|
name,
|
||||||
|
payload: args[0],
|
||||||
|
});
|
||||||
|
}, this._contextGlobal, {
|
||||||
|
defineAs: name,
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
this._global.executeInGlobal(script);
|
||||||
|
} catch (e) {
|
||||||
|
dump(`ERROR: ${e.message}\n${e.stack}\n`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsafeObject(objectId) {
|
unsafeObject(objectId) {
|
||||||
if (!this._remoteObjects.has(objectId))
|
if (!this._remoteObjects.has(objectId))
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -91,8 +91,8 @@ function initialize() {
|
|||||||
}
|
}
|
||||||
for (const script of scriptsToEvaluateOnNewDocument)
|
for (const script of scriptsToEvaluateOnNewDocument)
|
||||||
frameTree.addScriptToEvaluateOnNewDocument(script);
|
frameTree.addScriptToEvaluateOnNewDocument(script);
|
||||||
for (const { name, script } of bindings)
|
for (const { worldName, name, script } of bindings)
|
||||||
frameTree.addBinding(name, script);
|
frameTree.addBinding(worldName, name, script);
|
||||||
|
|
||||||
pageAgent = new PageAgent(messageManager, channel, frameTree);
|
pageAgent = new PageAgent(messageManager, channel, frameTree);
|
||||||
|
|
||||||
@ -101,8 +101,8 @@ function initialize() {
|
|||||||
frameTree.addScriptToEvaluateOnNewDocument(script);
|
frameTree.addScriptToEvaluateOnNewDocument(script);
|
||||||
},
|
},
|
||||||
|
|
||||||
addBinding({name, script}) {
|
addBinding({worldName, name, script}) {
|
||||||
frameTree.addBinding(name, script);
|
frameTree.addBinding(worldName, name, script);
|
||||||
},
|
},
|
||||||
|
|
||||||
applyContextSetting({name, value}) {
|
applyContextSetting({name, value}) {
|
||||||
|
|||||||
@ -237,8 +237,8 @@ class BrowserHandler {
|
|||||||
await this._targetRegistry.browserContextForId(browserContextId).addScriptToEvaluateOnNewDocument(script);
|
await this._targetRegistry.browserContextForId(browserContextId).addScriptToEvaluateOnNewDocument(script);
|
||||||
}
|
}
|
||||||
|
|
||||||
async ['Browser.addBinding']({browserContextId, name, script}) {
|
async ['Browser.addBinding']({browserContextId, worldName, name, script}) {
|
||||||
await this._targetRegistry.browserContextForId(browserContextId).addBinding(name, script);
|
await this._targetRegistry.browserContextForId(browserContextId).addBinding(worldName, name, script);
|
||||||
}
|
}
|
||||||
|
|
||||||
['Browser.setCookies']({browserContextId, cookies}) {
|
['Browser.setCookies']({browserContextId, cookies}) {
|
||||||
|
|||||||
@ -373,6 +373,7 @@ const Browser = {
|
|||||||
'addBinding': {
|
'addBinding': {
|
||||||
params: {
|
params: {
|
||||||
browserContextId: t.Optional(t.String),
|
browserContextId: t.Optional(t.String),
|
||||||
|
worldName: t.Optional(t.String),
|
||||||
name: t.String,
|
name: t.String,
|
||||||
script: t.String,
|
script: t.String,
|
||||||
},
|
},
|
||||||
@ -523,7 +524,10 @@ const Runtime = {
|
|||||||
events: {
|
events: {
|
||||||
'executionContextCreated': {
|
'executionContextCreated': {
|
||||||
executionContextId: t.String,
|
executionContextId: t.String,
|
||||||
auxData: t.Any,
|
auxData: {
|
||||||
|
frameId: t.Optional(t.String),
|
||||||
|
name: t.Optional(t.String),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'executionContextDestroyed': {
|
'executionContextDestroyed': {
|
||||||
executionContextId: t.String,
|
executionContextId: t.String,
|
||||||
@ -718,6 +722,7 @@ const Page = {
|
|||||||
},
|
},
|
||||||
'addBinding': {
|
'addBinding': {
|
||||||
params: {
|
params: {
|
||||||
|
worldName: t.Optional(t.String),
|
||||||
name: t.String,
|
name: t.String,
|
||||||
script: t.String,
|
script: t.String,
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user