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
|
||||
Changed: pavel.feldman@gmail.com Mon 10 May 2021 09:56:40 PM PDT
|
||||
1259
|
||||
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);
|
||||
}
|
||||
|
||||
async addBinding(name, script) {
|
||||
await this._channel.connect('').send('addBinding', { name, script }).catch(e => void e);
|
||||
async addBinding(worldName, name, script) {
|
||||
await this._channel.connect('').send('addBinding', { worldName, name, script }).catch(e => void e);
|
||||
}
|
||||
|
||||
async applyContextSetting(name, value) {
|
||||
@ -717,9 +717,9 @@ class BrowserContext {
|
||||
await Promise.all(Array.from(this.pages).map(page => page.addScriptToEvaluateOnNewDocument(script)));
|
||||
}
|
||||
|
||||
async addBinding(name, script) {
|
||||
this.bindings.push({ name, script });
|
||||
await Promise.all(Array.from(this.pages).map(page => page.addBinding(name, script)));
|
||||
async addBinding(worldName, name, script) {
|
||||
this.bindings.push({ worldName, name, script });
|
||||
await Promise.all(Array.from(this.pages).map(page => page.addBinding(worldName, name, script)));
|
||||
}
|
||||
|
||||
async applySetting(name, value) {
|
||||
|
||||
@ -148,10 +148,10 @@ class FrameTree {
|
||||
return true;
|
||||
}
|
||||
|
||||
addBinding(name, script) {
|
||||
this._bindings.set(name, script);
|
||||
addBinding(worldName, name, script) {
|
||||
this._bindings.set(worldName + ':' + name, {worldName, name, script});
|
||||
for (const frame of this.frames())
|
||||
frame._addBinding(name, script);
|
||||
frame._addBinding(worldName, name, script);
|
||||
}
|
||||
|
||||
frameForDocShell(docShell) {
|
||||
@ -297,7 +297,6 @@ class FrameTree {
|
||||
}
|
||||
|
||||
FrameTree.Events = {
|
||||
BindingCalled: 'bindingcalled',
|
||||
FrameAttached: 'frameattached',
|
||||
FrameDetached: 'framedetached',
|
||||
WorkerCreated: 'workercreated',
|
||||
@ -461,18 +460,18 @@ class Frame {
|
||||
this._executionContext = null;
|
||||
}
|
||||
|
||||
_addBinding(name, script) {
|
||||
Cu.exportFunction((...args) => {
|
||||
this._frameTree.emit(FrameTree.Events.BindingCalled, {
|
||||
frame: this,
|
||||
name,
|
||||
payload: args[0]
|
||||
});
|
||||
}, this.domWindow(), {
|
||||
defineAs: name,
|
||||
});
|
||||
if (this._executionContext)
|
||||
this._evaluateScriptSafely(this._executionContext, script);
|
||||
_getOrCreateIsolatedContext(worldName) {
|
||||
for (let context of this._isolatedWorlds.values()) {
|
||||
if (context.auxData().name === worldName)
|
||||
return context;
|
||||
}
|
||||
return this.createIsolatedWorld(worldName);
|
||||
}
|
||||
|
||||
_addBinding(worldName, name, script) {
|
||||
const executionContext = worldName ? this._getOrCreateIsolatedContext(worldName) : this._executionContext;
|
||||
if (executionContext)
|
||||
executionContext.addBinding(name, script);
|
||||
}
|
||||
|
||||
_evaluateScriptSafely(executionContext, script) {
|
||||
@ -494,20 +493,25 @@ class Frame {
|
||||
|
||||
if (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(), {
|
||||
frameId: this._frameId,
|
||||
name: '',
|
||||
});
|
||||
for (const [name, script] of this._frameTree._bindings)
|
||||
this._addBinding(name, script);
|
||||
for (const {script, worldName} of this._frameTree._isolatedWorlds.values())
|
||||
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())
|
||||
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()) {
|
||||
const context = worldName ? this.createIsolatedWorld(worldName) : this.executionContext();
|
||||
const context = worldName ? this._getOrCreateIsolatedContext(worldName) : this.executionContext();
|
||||
this._evaluateScriptSafely(context, script);
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,7 +104,6 @@ class PageAgent {
|
||||
helper.addObserver(this._onDocumentOpenLoad.bind(this), 'juggler-document-open-loaded'),
|
||||
helper.addEventListener(this._messageManager, 'error', this._onError.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, 'framedetached', this._onFrameDetached.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.onExecutionContextCreated(this._onExecutionContextCreated.bind(this)),
|
||||
this._runtime.events.onExecutionContextDestroyed(this._onExecutionContextDestroyed.bind(this)),
|
||||
this._runtime.events.onBindingCalled(this._onBindingCalled.bind(this)),
|
||||
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),
|
||||
adoptNode: this._adoptNode.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', {
|
||||
executionContextId: frame.executionContext().id(),
|
||||
executionContextId,
|
||||
name,
|
||||
payload
|
||||
});
|
||||
|
||||
@ -74,6 +74,7 @@ class Runtime {
|
||||
onErrorFromWorker: createEvent(),
|
||||
onExecutionContextCreated: createEvent(),
|
||||
onExecutionContextDestroyed: createEvent(),
|
||||
onBindingCalled: createEvent(),
|
||||
};
|
||||
}
|
||||
|
||||
@ -166,6 +167,10 @@ class Runtime {
|
||||
_registerConsoleObserver(Services) {
|
||||
const consoleObserver = ({wrappedJSObject}, topic, data) => {
|
||||
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;
|
||||
return domWindow && domWindow.windowGlobalChild.innerWindowId === wrappedJSObject.innerID;
|
||||
});
|
||||
@ -311,6 +316,10 @@ class ExecutionContext {
|
||||
return this._auxData;
|
||||
}
|
||||
|
||||
_isIsolatedWorldContext() {
|
||||
return !!this._auxData.name;
|
||||
}
|
||||
|
||||
async evaluateScript(script, exceptionDetails = {}) {
|
||||
const userInputHelper = this._domWindow ? this._domWindow.windowUtils.setHandlingUserInput(true) : null;
|
||||
if (this._domWindow && this._domWindow.document)
|
||||
@ -365,6 +374,23 @@ class ExecutionContext {
|
||||
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) {
|
||||
if (!this._remoteObjects.has(objectId))
|
||||
return;
|
||||
|
||||
@ -91,8 +91,8 @@ function initialize() {
|
||||
}
|
||||
for (const script of scriptsToEvaluateOnNewDocument)
|
||||
frameTree.addScriptToEvaluateOnNewDocument(script);
|
||||
for (const { name, script } of bindings)
|
||||
frameTree.addBinding(name, script);
|
||||
for (const { worldName, name, script } of bindings)
|
||||
frameTree.addBinding(worldName, name, script);
|
||||
|
||||
pageAgent = new PageAgent(messageManager, channel, frameTree);
|
||||
|
||||
@ -101,8 +101,8 @@ function initialize() {
|
||||
frameTree.addScriptToEvaluateOnNewDocument(script);
|
||||
},
|
||||
|
||||
addBinding({name, script}) {
|
||||
frameTree.addBinding(name, script);
|
||||
addBinding({worldName, name, script}) {
|
||||
frameTree.addBinding(worldName, name, script);
|
||||
},
|
||||
|
||||
applyContextSetting({name, value}) {
|
||||
|
||||
@ -237,8 +237,8 @@ class BrowserHandler {
|
||||
await this._targetRegistry.browserContextForId(browserContextId).addScriptToEvaluateOnNewDocument(script);
|
||||
}
|
||||
|
||||
async ['Browser.addBinding']({browserContextId, name, script}) {
|
||||
await this._targetRegistry.browserContextForId(browserContextId).addBinding(name, script);
|
||||
async ['Browser.addBinding']({browserContextId, worldName, name, script}) {
|
||||
await this._targetRegistry.browserContextForId(browserContextId).addBinding(worldName, name, script);
|
||||
}
|
||||
|
||||
['Browser.setCookies']({browserContextId, cookies}) {
|
||||
|
||||
@ -373,6 +373,7 @@ const Browser = {
|
||||
'addBinding': {
|
||||
params: {
|
||||
browserContextId: t.Optional(t.String),
|
||||
worldName: t.Optional(t.String),
|
||||
name: t.String,
|
||||
script: t.String,
|
||||
},
|
||||
@ -523,7 +524,10 @@ const Runtime = {
|
||||
events: {
|
||||
'executionContextCreated': {
|
||||
executionContextId: t.String,
|
||||
auxData: t.Any,
|
||||
auxData: {
|
||||
frameId: t.Optional(t.String),
|
||||
name: t.Optional(t.String),
|
||||
},
|
||||
},
|
||||
'executionContextDestroyed': {
|
||||
executionContextId: t.String,
|
||||
@ -718,6 +722,7 @@ const Page = {
|
||||
},
|
||||
'addBinding': {
|
||||
params: {
|
||||
worldName: t.Optional(t.String),
|
||||
name: t.String,
|
||||
script: t.String,
|
||||
},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user