Skip to content

Commit 049fdf7

Browse files
authored
browser(firefox): implement Browser.addBinding (#1477)
1 parent c68cee9 commit 049fdf7

File tree

2 files changed

+92
-46
lines changed

2 files changed

+92
-46
lines changed

browser_patches/firefox/BUILD_NUMBER

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1049
1+
1050

browser_patches/firefox/patches/bootstrap.diff

+91-45
Original file line numberDiff line numberDiff line change
@@ -718,10 +718,10 @@ index 5de630a1db847a09651b310928bb7bc4d4f66f29..0268bc2bdfb3bfda2ef6e01a5dd24209
718718
nsCOMPtr<nsIPrincipal> principal =
719719
diff --git a/juggler/BrowserContextManager.js b/juggler/BrowserContextManager.js
720720
new file mode 100644
721-
index 0000000000000000000000000000000000000000..3365aa618718308ffdf05d9f196d792fc7b58677
721+
index 0000000000000000000000000000000000000000..bd57d338c279f5ab31102e6644f43e133b7f4e25
722722
--- /dev/null
723723
+++ b/juggler/BrowserContextManager.js
724-
@@ -0,0 +1,229 @@
724+
@@ -0,0 +1,235 @@
725725
+"use strict";
726726
+
727727
+const {ContextualIdentityService} = ChromeUtils.import("resource://gre/modules/ContextualIdentityService.jsm");
@@ -807,6 +807,7 @@ index 0000000000000000000000000000000000000000..3365aa618718308ffdf05d9f196d792f
807807
+ this._manager._userContextIdToBrowserContext.set(this.userContextId, this);
808808
+ this.options = options || {};
809809
+ this.options.scriptsToEvaluateOnNewDocument = [];
810+
+ this.options.bindings = [];
810811
+ this.pages = new Set();
811812
+ }
812813
+
@@ -824,6 +825,11 @@ index 0000000000000000000000000000000000000000..3365aa618718308ffdf05d9f196d792f
824825
+ await Promise.all(Array.from(this.pages).map(page => page.addScriptToEvaluateOnNewDocument(script)));
825826
+ }
826827
+
828+
+ async addBinding(name, script) {
829+
+ this.options.bindings.push({ name, script });
830+
+ await Promise.all(Array.from(this.pages).map(page => page.addBinding(name, script)));
831+
+ }
832+
+
827833
+ async setGeolocationOverride(geolocation) {
828834
+ this.options.geolocation = geolocation;
829835
+ await Promise.all(Array.from(this.pages).map(page => page.setGeolocationOverride(geolocation)));
@@ -1929,10 +1935,10 @@ index 0000000000000000000000000000000000000000..ba34976ad05e7f5f1a99777f76ac08b1
19291935
+this.SimpleChannel = SimpleChannel;
19301936
diff --git a/juggler/TargetRegistry.js b/juggler/TargetRegistry.js
19311937
new file mode 100644
1932-
index 0000000000000000000000000000000000000000..75ea79a8fa493f0d8f2f88244aaf397af17833d4
1938+
index 0000000000000000000000000000000000000000..e624e3c21a20dd324e0d135598e2a2402c8b62bf
19331939
--- /dev/null
19341940
+++ b/juggler/TargetRegistry.js
1935-
@@ -0,0 +1,273 @@
1941+
@@ -0,0 +1,277 @@
19361942
+const {EventEmitter} = ChromeUtils.import('resource://gre/modules/EventEmitter.jsm');
19371943
+const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js');
19381944
+const {SimpleChannel} = ChromeUtils.import('chrome://juggler/content/SimpleChannel.js');
@@ -2169,6 +2175,10 @@ index 0000000000000000000000000000000000000000..75ea79a8fa493f0d8f2f88244aaf397a
21692175
+ await this._channel.connect('').send('addScriptToEvaluateOnNewDocument', script).catch(e => void e);
21702176
+ }
21712177
+
2178+
+ async addBinding(name, script) {
2179+
+ await this._channel.connect('').send('addBinding', { name, script }).catch(e => void e);
2180+
+ }
2181+
+
21722182
+ async setGeolocationOverride(geolocation) {
21732183
+ await this._channel.connect('').send('setGeolocationOverride', geolocation).catch(e => void e);
21742184
+ }
@@ -2354,10 +2364,10 @@ index 0000000000000000000000000000000000000000..268fbc361d8053182bb6c27f626e853d
23542364
+
23552365
diff --git a/juggler/content/FrameTree.js b/juggler/content/FrameTree.js
23562366
new file mode 100644
2357-
index 0000000000000000000000000000000000000000..13c3cd817b369ed012326b97d03ba6e123b84740
2367+
index 0000000000000000000000000000000000000000..679b5851c427064c636bd1f7793358cc45b0de67
23582368
--- /dev/null
23592369
+++ b/juggler/content/FrameTree.js
2360-
@@ -0,0 +1,376 @@
2370+
@@ -0,0 +1,411 @@
23612371
+"use strict";
23622372
+const Ci = Components.interfaces;
23632373
+const Cr = Components.results;
@@ -2378,6 +2388,7 @@ index 0000000000000000000000000000000000000000..13c3cd817b369ed012326b97d03ba6e1
23782388
+ this._browsingContextGroup.__jugglerFrameTrees = new Set();
23792389
+ this._browsingContextGroup.__jugglerFrameTrees.add(this);
23802390
+
2391+
+ this._bindings = new Map();
23812392
+ this._workers = new Map();
23822393
+ this._docShellToFrame = new Map();
23832394
+ this._frameIdToFrame = new Map();
@@ -2408,6 +2419,7 @@ index 0000000000000000000000000000000000000000..13c3cd817b369ed012326b97d03ba6e1
24082419
+ this._eventListeners = [
24092420
+ helper.addObserver(subject => this._onDocShellCreated(subject.QueryInterface(Ci.nsIDocShell)), 'webnavigation-create'),
24102421
+ helper.addObserver(subject => this._onDocShellDestroyed(subject.QueryInterface(Ci.nsIDocShell)), 'webnavigation-destroy'),
2422+
+ helper.addObserver(window => this._onDOMWindowCreated(window), 'content-document-global-created'),
24112423
+ helper.addProgressListener(webProgress, this, flags),
24122424
+ ];
24132425
+ }
@@ -2471,6 +2483,25 @@ index 0000000000000000000000000000000000000000..13c3cd817b369ed012326b97d03ba6e1
24712483
+ return this._scriptsToEvaluateOnNewDocument;
24722484
+ }
24732485
+
2486+
+ addBinding(name, script) {
2487+
+ this._bindings.set(name, script);
2488+
+ for (const frame of this.frames())
2489+
+ this._addBindingToFrame(frame, name, script);
2490+
+ }
2491+
+
2492+
+ _addBindingToFrame(frame, name, script) {
2493+
+ Cu.exportFunction((...args) => {
2494+
+ this.emit(FrameTree.Events.BindingCalled, {
2495+
+ frame,
2496+
+ name,
2497+
+ payload: args[0]
2498+
+ });
2499+
+ }, frame.domWindow(), {
2500+
+ defineAs: name,
2501+
+ });
2502+
+ frame.domWindow().eval(script);
2503+
+ }
2504+
+
24742505
+ frameForDocShell(docShell) {
24752506
+ return this._docShellToFrame.get(docShell) || null;
24762507
+ }
@@ -2578,6 +2609,8 @@ index 0000000000000000000000000000000000000000..13c3cd817b369ed012326b97d03ba6e1
25782609
+ const frame = new Frame(this, docShell, parentFrame);
25792610
+ this._docShellToFrame.set(docShell, frame);
25802611
+ this._frameIdToFrame.set(frame.id(), frame);
2612+
+ for (const [name, script] of this._bindings)
2613+
+ this._addBindingToFrame(frame, name, script);
25812614
+ this.emit(FrameTree.Events.FrameAttached, frame);
25822615
+ return frame;
25832616
+ }
@@ -2588,6 +2621,16 @@ index 0000000000000000000000000000000000000000..13c3cd817b369ed012326b97d03ba6e1
25882621
+ this._detachFrame(frame);
25892622
+ }
25902623
+
2624+
+ _onDOMWindowCreated(window) {
2625+
+ const docShell = window.docShell;
2626+
+ const frame = this.frameForDocShell(docShell);
2627+
+ if (!frame)
2628+
+ return;
2629+
+ for (const [name, script] of this._bindings)
2630+
+ this._addBindingToFrame(frame, name, script);
2631+
+ this.emit(FrameTree.Events.GlobalObjectCreated, { frame, window });
2632+
+ }
2633+
+
25912634
+ _detachFrame(frame) {
25922635
+ // Detach all children first
25932636
+ for (const subframe of frame._children)
@@ -2602,8 +2645,10 @@ index 0000000000000000000000000000000000000000..13c3cd817b369ed012326b97d03ba6e1
26022645
+}
26032646
+
26042647
+FrameTree.Events = {
2648+
+ BindingCalled: 'bindingcalled',
26052649
+ FrameAttached: 'frameattached',
26062650
+ FrameDetached: 'framedetached',
2651+
+ GlobalObjectCreated: 'globalobjectcreated',
26072652
+ WorkerCreated: 'workercreated',
26082653
+ WorkerDestroyed: 'workerdestroyed',
26092654
+ NavigationStarted: 'navigationstarted',
@@ -2804,10 +2849,10 @@ index 0000000000000000000000000000000000000000..be70ea364f9534bb3b344f64970366c3
28042849
+
28052850
diff --git a/juggler/content/PageAgent.js b/juggler/content/PageAgent.js
28062851
new file mode 100644
2807-
index 0000000000000000000000000000000000000000..3dd06f27d071a1ca70609d63a12b1ff690d99371
2852+
index 0000000000000000000000000000000000000000..6a001d9f51c819edd3981e090172ac87d6f85840
28082853
--- /dev/null
28092854
+++ b/juggler/content/PageAgent.js
2810-
@@ -0,0 +1,938 @@
2855+
@@ -0,0 +1,921 @@
28112856
+"use strict";
28122857
+const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
28132858
+const Ci = Components.interfaces;
@@ -2873,8 +2918,6 @@ index 0000000000000000000000000000000000000000..3dd06f27d071a1ca70609d63a12b1ff6
28732918
+ name: '',
28742919
+ });
28752920
+
2876-
+ for (const bindingName of this._agent._bindingsToAdd.values())
2877-
+ this.exposeFunction(bindingName);
28782921
+ for (const script of this._agent._frameTree.scriptsToEvaluateOnNewDocument()) {
28792922
+ // TODO: this should actually be handled in FrameTree, but first we have to move
28802923
+ // execution contexts there.
@@ -2896,18 +2939,6 @@ index 0000000000000000000000000000000000000000..3dd06f27d071a1ca70609d63a12b1ff6
28962939
+ }
28972940
+ }
28982941
+
2899-
+ exposeFunction(name) {
2900-
+ Cu.exportFunction((...args) => {
2901-
+ this._agent._browserPage.emit('pageBindingCalled', {
2902-
+ executionContextId: this.mainContext.id(),
2903-
+ name,
2904-
+ payload: args[0]
2905-
+ });
2906-
+ }, this._frame.domWindow(), {
2907-
+ defineAs: name,
2908-
+ });
2909-
+ }
2910-
+
29112942
+ createIsolatedWorld(name) {
29122943
+ const principal = [this._frame.domWindow()]; // extended principal
29132944
+ const sandbox = Cu.Sandbox(principal, {
@@ -2954,11 +2985,10 @@ index 0000000000000000000000000000000000000000..3dd06f27d071a1ca70609d63a12b1ff6
29542985
+ this._frameData = new Map();
29552986
+ this._workerData = new Map();
29562987
+ this._scriptsToEvaluateOnNewDocument = new Map();
2957-
+ this._bindingsToAdd = new Set();
29582988
+
29592989
+ this._eventListeners = [
29602990
+ browserChannel.register(sessionId + 'page', {
2961-
+ addBinding: this._addBinding.bind(this),
2991+
+ addBinding: ({ name, script }) => this._frameTree.addBinding(name, script),
29622992
+ addScriptToEvaluateOnNewDocument: this._addScriptToEvaluateOnNewDocument.bind(this),
29632993
+ adoptNode: this._adoptNode.bind(this),
29642994
+ awaitViewportDimensions: this._awaitViewportDimensions.bind(this),
@@ -3080,13 +3110,14 @@ index 0000000000000000000000000000000000000000..3dd06f27d071a1ca70609d63a12b1ff6
30803110
+ helper.addObserver(this._linkClicked.bind(this, false), 'juggler-link-click'),
30813111
+ helper.addObserver(this._linkClicked.bind(this, true), 'juggler-link-click-sync'),
30823112
+ helper.addObserver(this._filePickerShown.bind(this), 'juggler-file-picker-shown'),
3083-
+ helper.addObserver(this._onDOMWindowCreated.bind(this), 'content-document-global-created'),
30843113
+ helper.addEventListener(this._messageManager, 'DOMContentLoaded', this._onDOMContentLoaded.bind(this)),
30853114
+ helper.addEventListener(this._messageManager, 'pageshow', this._onLoad.bind(this)),
30863115
+ helper.addObserver(this._onDocumentOpenLoad.bind(this), 'juggler-document-open-loaded'),
30873116
+ helper.addEventListener(this._messageManager, 'error', this._onError.bind(this)),
3117+
+ helper.on(this._frameTree, 'bindingcalled', this._onBindingCalled.bind(this)),
30883118
+ helper.on(this._frameTree, 'frameattached', this._onFrameAttached.bind(this)),
30893119
+ helper.on(this._frameTree, 'framedetached', this._onFrameDetached.bind(this)),
3120+
+ helper.on(this._frameTree, 'globalobjectcreated', this._onGlobalObjectCreated.bind(this)),
30903121
+ helper.on(this._frameTree, 'navigationstarted', this._onNavigationStarted.bind(this)),
30913122
+ helper.on(this._frameTree, 'navigationcommitted', this._onNavigationCommitted.bind(this)),
30923123
+ helper.on(this._frameTree, 'navigationaborted', this._onNavigationAborted.bind(this)),
@@ -3244,11 +3275,7 @@ index 0000000000000000000000000000000000000000..3dd06f27d071a1ca70609d63a12b1ff6
32443275
+ });
32453276
+ }
32463277
+
3247-
+ _onDOMWindowCreated(window) {
3248-
+ const docShell = window.docShell;
3249-
+ const frame = this._frameTree.frameForDocShell(docShell);
3250-
+ if (!frame)
3251-
+ return;
3278+
+ _onGlobalObjectCreated({ frame }) {
32523279
+ this._frameData.get(frame).reset();
32533280
+ }
32543281
+
@@ -3267,6 +3294,15 @@ index 0000000000000000000000000000000000000000..3dd06f27d071a1ca70609d63a12b1ff6
32673294
+ });
32683295
+ }
32693296
+
3297+
+ _onBindingCalled({frame, name, payload}) {
3298+
+ const frameData = this._frameData.get(frame);
3299+
+ this._browserPage.emit('pageBindingCalled', {
3300+
+ executionContextId: frameData.mainContext.id(),
3301+
+ name,
3302+
+ payload
3303+
+ });
3304+
+ }
3305+
+
32703306
+ dispose() {
32713307
+ for (const workerData of this._workerData.values())
32723308
+ workerData.dispose();
@@ -3334,14 +3370,6 @@ index 0000000000000000000000000000000000000000..3dd06f27d071a1ca70609d63a12b1ff6
33343370
+ return {navigationId: frame.pendingNavigationId(), navigationURL: frame.pendingNavigationURL()};
33353371
+ }
33363372
+
3337-
+ _addBinding({name}) {
3338-
+ if (this._bindingsToAdd.has(name))
3339-
+ throw new Error(`Binding with name ${name} already exists`);
3340-
+ this._bindingsToAdd.add(name);
3341-
+ for (const frameData of this._frameData.values())
3342-
+ frameData.exposeFunction(name);
3343-
+ }
3344-
+
33453373
+ async _adoptNode({frameId, objectId, executionContextId}) {
33463374
+ const frame = this._frameTree.frame(frameId);
33473375
+ if (!frame)
@@ -4511,10 +4539,10 @@ index 0000000000000000000000000000000000000000..3a386425d3796d0a6786dea193b3402d
45114539
+
45124540
diff --git a/juggler/content/main.js b/juggler/content/main.js
45134541
new file mode 100644
4514-
index 0000000000000000000000000000000000000000..56472e8515cb84d66bd0ec89e5ca1984bb360f5a
4542+
index 0000000000000000000000000000000000000000..9bb5c2bff8eb3e350203b56a3445e9b200747f8b
45154543
--- /dev/null
45164544
+++ b/juggler/content/main.js
4517-
@@ -0,0 +1,172 @@
4545+
@@ -0,0 +1,178 @@
45184546
+const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
45194547
+const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js');
45204548
+const {FrameTree} = ChromeUtils.import('chrome://juggler/content/content/FrameTree.js');
@@ -4590,7 +4618,7 @@ index 0000000000000000000000000000000000000000..56472e8515cb84d66bd0ec89e5ca1984
45904618
+ response = { sessionIds: [], browserContextOptions: {}, waitForInitialNavigation: false };
45914619
+
45924620
+ const { sessionIds, browserContextOptions, waitForInitialNavigation } = response;
4593-
+ const { userAgent, bypassCSP, javaScriptDisabled, viewport, scriptsToEvaluateOnNewDocument, locale, geolocation, onlineOverride } = browserContextOptions;
4621+
+ const { userAgent, bypassCSP, javaScriptDisabled, viewport, scriptsToEvaluateOnNewDocument, bindings, locale, geolocation, onlineOverride } = browserContextOptions;
45944622
+
45954623
+ if (userAgent !== undefined)
45964624
+ docShell.customUserAgent = userAgent;
@@ -4614,6 +4642,8 @@ index 0000000000000000000000000000000000000000..56472e8515cb84d66bd0ec89e5ca1984
46144642
+ frameTree = new FrameTree(docShell, waitForInitialNavigation);
46154643
+ for (const script of scriptsToEvaluateOnNewDocument || [])
46164644
+ frameTree.addScriptToEvaluateOnNewDocument(script);
4645+
+ for (const { name, script } of bindings || [])
4646+
+ frameTree.addBinding(name, script);
46174647
+ networkMonitor = new NetworkMonitor(docShell, frameTree);
46184648
+
46194649
+ const channel = SimpleChannel.createForMessageManager('content::page', messageManager);
@@ -4634,6 +4664,10 @@ index 0000000000000000000000000000000000000000..56472e8515cb84d66bd0ec89e5ca1984
46344664
+ frameTree.addScriptToEvaluateOnNewDocument(script);
46354665
+ },
46364666
+
4667+
+ addBinding(name, script) {
4668+
+ frameTree.addBinding(name, script);
4669+
+ },
4670+
+
46374671
+ setGeolocationOverride(geolocation) {
46384672
+ setGeolocationOverrideInDocShell(geolocation);
46394673
+ },
@@ -4768,10 +4802,10 @@ index 0000000000000000000000000000000000000000..2f2b7ca247f6b6dff396fb4b644654de
47684802
+this.AccessibilityHandler = AccessibilityHandler;
47694803
diff --git a/juggler/protocol/BrowserHandler.js b/juggler/protocol/BrowserHandler.js
47704804
new file mode 100644
4771-
index 0000000000000000000000000000000000000000..b3a7b47765d69f9ba48c74e23aaae4e2a40498e5
4805+
index 0000000000000000000000000000000000000000..e225fc81c62bbfac4d071ab1a9d83a754dda46bb
47724806
--- /dev/null
47734807
+++ b/juggler/protocol/BrowserHandler.js
4774-
@@ -0,0 +1,174 @@
4808+
@@ -0,0 +1,178 @@
47754809
+"use strict";
47764810
+
47774811
+const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
@@ -4920,6 +4954,10 @@ index 0000000000000000000000000000000000000000..b3a7b47765d69f9ba48c74e23aaae4e2
49204954
+ await this._contextManager.browserContextForId(browserContextId).addScriptToEvaluateOnNewDocument(script);
49214955
+ }
49224956
+
4957+
+ async addBinding({browserContextId, name, script}) {
4958+
+ await this._contextManager.browserContextForId(browserContextId).addBinding(name, script);
4959+
+ }
4960+
+
49234961
+ setCookies({browserContextId, cookies}) {
49244962
+ this._contextManager.browserContextForId(browserContextId).setCookies(cookies);
49254963
+ }
@@ -5817,10 +5855,10 @@ index 0000000000000000000000000000000000000000..78b6601b91d0b7fcda61114e6846aa07
58175855
+this.EXPORTED_SYMBOLS = ['t', 'checkScheme'];
58185856
diff --git a/juggler/protocol/Protocol.js b/juggler/protocol/Protocol.js
58195857
new file mode 100644
5820-
index 0000000000000000000000000000000000000000..390e68d71c0034748ae90132d9d1defaa67de772
5858+
index 0000000000000000000000000000000000000000..67df4d5592d66e0db3c7c120ad12f9b360b9c45d
58215859
--- /dev/null
58225860
+++ b/juggler/protocol/Protocol.js
5823-
@@ -0,0 +1,770 @@
5861+
@@ -0,0 +1,778 @@
58245862
+const {t, checkScheme} = ChromeUtils.import('chrome://juggler/content/protocol/PrimitiveTypes.js');
58255863
+
58265864
+// Protocol-specific types.
@@ -6096,6 +6134,13 @@ index 0000000000000000000000000000000000000000..390e68d71c0034748ae90132d9d1defa
60966134
+ script: t.String,
60976135
+ }
60986136
+ },
6137+
+ 'addBinding': {
6138+
+ params: {
6139+
+ browserContextId: t.Optional(t.String),
6140+
+ name: t.String,
6141+
+ script: t.String,
6142+
+ },
6143+
+ },
60996144
+ 'grantPermissions': {
61006145
+ params: {
61016146
+ origin: t.String,
@@ -6382,6 +6427,7 @@ index 0000000000000000000000000000000000000000..390e68d71c0034748ae90132d9d1defa
63826427
+ 'addBinding': {
63836428
+ params: {
63846429
+ name: t.String,
6430+
+ script: t.String,
63856431
+ },
63866432
+ },
63876433
+ 'setViewportSize': {

0 commit comments

Comments
 (0)