browser(firefox): make interception, locale and geolocation work on browser context level (#1469)

This commit is contained in:
Dmitry Gozman 2020-03-21 21:35:13 -07:00 committed by GitHub
parent 3f90c09e6d
commit fb7b919bd4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 138 additions and 107 deletions

View file

@ -1 +1 @@
1047 1048

View file

@ -669,10 +669,10 @@ index 5de630a1db847a09651b310928bb7bc4d4f66f29..0268bc2bdfb3bfda2ef6e01a5dd24209
nsCOMPtr<nsIPrincipal> principal = nsCOMPtr<nsIPrincipal> principal =
diff --git a/juggler/BrowserContextManager.js b/juggler/BrowserContextManager.js diff --git a/juggler/BrowserContextManager.js b/juggler/BrowserContextManager.js
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..6c3d918022f0e8ff84083cb20266c97902cd04d4 index 0000000000000000000000000000000000000000..d30b333e03e9a4121e0a5e1bbf694d88bab5defa
--- /dev/null --- /dev/null
+++ b/juggler/BrowserContextManager.js +++ b/juggler/BrowserContextManager.js
@@ -0,0 +1,214 @@ @@ -0,0 +1,224 @@
+"use strict"; +"use strict";
+ +
+const {ContextualIdentityService} = ChromeUtils.import("resource://gre/modules/ContextualIdentityService.jsm"); +const {ContextualIdentityService} = ChromeUtils.import("resource://gre/modules/ContextualIdentityService.jsm");
@ -758,6 +758,7 @@ index 0000000000000000000000000000000000000000..6c3d918022f0e8ff84083cb20266c979
+ this._manager._userContextIdToBrowserContext.set(this.userContextId, this); + this._manager._userContextIdToBrowserContext.set(this.userContextId, this);
+ this.options = options || {}; + this.options = options || {};
+ this.options.scriptsToEvaluateOnNewDocument = []; + this.options.scriptsToEvaluateOnNewDocument = [];
+ this.pages = new Set();
+ } + }
+ +
+ destroy() { + destroy() {
@ -769,13 +770,26 @@ index 0000000000000000000000000000000000000000..6c3d918022f0e8ff84083cb20266c979
+ this._manager._userContextIdToBrowserContext.delete(this.userContextId); + this._manager._userContextIdToBrowserContext.delete(this.userContextId);
+ } + }
+ +
+ addScriptToEvaluateOnNewDocument(script) { + async addScriptToEvaluateOnNewDocument(script) {
+ this.options.scriptsToEvaluateOnNewDocument.push(script); + this.options.scriptsToEvaluateOnNewDocument.push(script);
+ this.emit(BrowserContext.Events.ScriptToEvaluateOnNewDocumentAdded, script); + await Promise.all(Array.from(this.pages).map(page => page.addScriptToEvaluateOnNewDocument(script)));
+ } + }
+ +
+ grantPermissions(origin, permissions) { + async setGeolocationOverride(geolocation) {
+ this.options.geolocation = geolocation;
+ await Promise.all(Array.from(this.pages).map(page => page.setGeolocationOverride(geolocation)));
+ }
+
+ async grantPermissions(origin, permissions) {
+ this._permissions.set(origin, permissions); + this._permissions.set(origin, permissions);
+ const promises = [];
+ for (const page of this.pages) {
+ if (origin === '*' || page._url.startsWith(origin)) {
+ this.grantPermissionsToOrigin(page._url);
+ promises.push(page.ensurePermissions(permissions));
+ }
+ }
+ await Promise.all(promises);
+ } + }
+ +
+ resetPermissions() { + resetPermissions() {
@ -875,10 +889,6 @@ index 0000000000000000000000000000000000000000..6c3d918022f0e8ff84083cb20266c979
+ } + }
+} +}
+ +
+BrowserContext.Events = {
+ ScriptToEvaluateOnNewDocumentAdded: Symbol('BrowserContext.Events.ScriptToEvaluateOnNewDocumentAdded'),
+};
+
+function dirPath(path) { +function dirPath(path) {
+ return path.substring(0, path.lastIndexOf('/') + 1); + return path.substring(0, path.lastIndexOf('/') + 1);
+} +}
@ -997,10 +1007,10 @@ index 0000000000000000000000000000000000000000..862c680198bbb503a5f04c19bdb8fdf2
+ +
diff --git a/juggler/NetworkObserver.js b/juggler/NetworkObserver.js diff --git a/juggler/NetworkObserver.js b/juggler/NetworkObserver.js
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..59855077f4b9af267c805b15ec073f69f806c1e8 index 0000000000000000000000000000000000000000..268926d1cff9c3a073a1910708a813ed5481a690
--- /dev/null --- /dev/null
+++ b/juggler/NetworkObserver.js +++ b/juggler/NetworkObserver.js
@@ -0,0 +1,699 @@ @@ -0,0 +1,717 @@
+"use strict"; +"use strict";
+ +
+const {EventEmitter} = ChromeUtils.import('resource://gre/modules/EventEmitter.jsm'); +const {EventEmitter} = ChromeUtils.import('resource://gre/modules/EventEmitter.jsm');
@ -1072,6 +1082,7 @@ index 0000000000000000000000000000000000000000..59855077f4b9af267c805b15ec073f69
+ registrar.registerFactory(SINK_CLASS_ID, SINK_CLASS_DESCRIPTION, SINK_CONTRACT_ID, this._channelSinkFactory); + registrar.registerFactory(SINK_CLASS_ID, SINK_CLASS_DESCRIPTION, SINK_CONTRACT_ID, this._channelSinkFactory);
+ Services.catMan.addCategoryEntry(SINK_CATEGORY_NAME, SINK_CONTRACT_ID, SINK_CONTRACT_ID, false, true); + Services.catMan.addCategoryEntry(SINK_CATEGORY_NAME, SINK_CONTRACT_ID, SINK_CONTRACT_ID, false, true);
+ +
+ this._browsersWithEnabledInterception = new Set();
+ this._browserInterceptors = new Map(); // Browser => (requestId => interceptor). + this._browserInterceptors = new Map(); // Browser => (requestId => interceptor).
+ this._extraHTTPHeaders = new Map(); + this._extraHTTPHeaders = new Map();
+ this._browserResponseStorages = new Map(); + this._browserResponseStorages = new Map();
@ -1092,11 +1103,11 @@ index 0000000000000000000000000000000000000000..59855077f4b9af267c805b15ec073f69
+ } + }
+ +
+ enableRequestInterception(browser) { + enableRequestInterception(browser) {
+ if (!this._browserInterceptors.has(browser)) + this._browsersWithEnabledInterception.add(browser);
+ this._browserInterceptors.set(browser, new Map());
+ } + }
+ +
+ disableRequestInterception(browser) { + disableRequestInterception(browser) {
+ this._browsersWithEnabledInterception.delete(browser);
+ const interceptors = this._browserInterceptors.get(browser); + const interceptors = this._browserInterceptors.get(browser);
+ if (!interceptors) + if (!interceptors)
+ return; + return;
@ -1229,8 +1240,8 @@ index 0000000000000000000000000000000000000000..59855077f4b9af267c805b15ec073f69
+ this._appendExtraHTTPHeaders(httpChannel, this._extraHTTPHeaders.get(browser)); + this._appendExtraHTTPHeaders(httpChannel, this._extraHTTPHeaders.get(browser));
+ const requestId = this._requestId(httpChannel); + const requestId = this._requestId(httpChannel);
+ const isRedirect = this._redirectMap.has(requestId); + const isRedirect = this._redirectMap.has(requestId);
+ const interceptors = this._browserInterceptors.get(browser); + const interceptionEnabled = this._isInterceptionEnabledForBrowser(browser);
+ if (!interceptors) { + if (!interceptionEnabled) {
+ new NotificationCallbacks(this, browser, httpChannel, false); + new NotificationCallbacks(this, browser, httpChannel, false);
+ this._sendOnRequest(httpChannel, false); + this._sendOnRequest(httpChannel, false);
+ new ResponseBodyListener(this, browser, httpChannel); + new ResponseBodyListener(this, browser, httpChannel);
@ -1238,6 +1249,7 @@ index 0000000000000000000000000000000000000000..59855077f4b9af267c805b15ec073f69
+ // We pretend that redirect is interceptable in the protocol, although it's actually not + // We pretend that redirect is interceptable in the protocol, although it's actually not
+ // and therefore we do not instantiate the interceptor. + // and therefore we do not instantiate the interceptor.
+ // TODO: look into REDIRECT_MODE_MANUAL. + // TODO: look into REDIRECT_MODE_MANUAL.
+ const interceptors = this._ensureInterceptors(browser);
+ interceptors.set(requestId, { + interceptors.set(requestId, {
+ _resume: () => {}, + _resume: () => {},
+ _abort: () => {}, + _abort: () => {},
@ -1248,7 +1260,6 @@ index 0000000000000000000000000000000000000000..59855077f4b9af267c805b15ec073f69
+ new ResponseBodyListener(this, browser, httpChannel); + new ResponseBodyListener(this, browser, httpChannel);
+ } else { + } else {
+ const previousCallbacks = httpChannel.notificationCallbacks; + const previousCallbacks = httpChannel.notificationCallbacks;
+ let shouldIntercept = true;
+ if (previousCallbacks instanceof Ci.nsIInterfaceRequestor) { + if (previousCallbacks instanceof Ci.nsIInterfaceRequestor) {
+ const interceptor = previousCallbacks.getInterface(Ci.nsINetworkInterceptController); + const interceptor = previousCallbacks.getInterface(Ci.nsINetworkInterceptController);
+ // We assume that interceptor is a service worker if there is one. + // We assume that interceptor is a service worker if there is one.
@ -1267,6 +1278,24 @@ index 0000000000000000000000000000000000000000..59855077f4b9af267c805b15ec073f69
+ } + }
+ } + }
+ +
+ _isInterceptionEnabledForBrowser(browser) {
+ if (this._browsersWithEnabledInterception.has(browser))
+ return true;
+ const browserContext = TargetRegistry.instance().browserContextForBrowser(browser);
+ if (browserContext && browserContext.options.requestInterceptionEnabled)
+ return true;
+ return false;
+ }
+
+ _ensureInterceptors(browser) {
+ let interceptors = this._browserInterceptors.get(browser);
+ if (!interceptors) {
+ interceptors = new Map();
+ this._browserInterceptors.set(browser, interceptors);
+ }
+ return interceptors;
+ }
+
+ _appendExtraHTTPHeaders(httpChannel, headers) { + _appendExtraHTTPHeaders(httpChannel, headers) {
+ if (!headers) + if (!headers)
+ return; + return;
@ -1280,10 +1309,10 @@ index 0000000000000000000000000000000000000000..59855077f4b9af267c805b15ec073f69
+ interceptor._resume(); + interceptor._resume();
+ return; + return;
+ } + }
+ const interceptors = this._browserInterceptors.get(browser); + const interceptionEnabled = this._isInterceptionEnabledForBrowser(browser);
+ this._sendOnRequest(httpChannel, !!interceptors); + this._sendOnRequest(httpChannel, !!interceptionEnabled);
+ if (interceptors) + if (interceptionEnabled)
+ interceptors.set(this._requestId(httpChannel), interceptor); + this._ensureInterceptors(browser).set(this._requestId(httpChannel), interceptor);
+ else + else
+ interceptor._resume(); + interceptor._resume();
+ } + }
@ -1377,6 +1406,7 @@ index 0000000000000000000000000000000000000000..59855077f4b9af267c805b15ec073f69
+ } else { + } else {
+ this._browserSessionCount.delete(browser); + this._browserSessionCount.delete(browser);
+ this._browserResponseStorages.delete(browser); + this._browserResponseStorages.delete(browser);
+ this._browsersWithEnabledInterception.delete(browser);
+ this._browserInterceptors.delete(browser); + this._browserInterceptors.delete(browser);
+ } + }
+ } + }
@ -1657,10 +1687,8 @@ index 0000000000000000000000000000000000000000..59855077f4b9af267c805b15ec073f69
+ for (const header of headers) + for (const header of headers)
+ this._intercepted.synthesizeHeader(header.name, header.value); + this._intercepted.synthesizeHeader(header.name, header.value);
+ const synthesized = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream); + const synthesized = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
+ if (base64body) + const body = base64body ? atob(base64body) : '';
+ synthesized.data = atob(base64body); + synthesized.data = body;
+ else
+ synthesized.data = '';
+ this._intercepted.startSynthesizedResponse(synthesized, null, null, '', false); + this._intercepted.startSynthesizedResponse(synthesized, null, null, '', false);
+ this._intercepted.finishSynthesizedResponse(); + this._intercepted.finishSynthesizedResponse();
+ this._networkObserver.emit('response', this._httpChannel, { + this._networkObserver.emit('response', this._httpChannel, {
@ -1671,7 +1699,7 @@ index 0000000000000000000000000000000000000000..59855077f4b9af267c805b15ec073f69
+ status, + status,
+ statusText, + statusText,
+ }); + });
+ this._networkObserver._sendOnRequestFinished(this._httpChannel); + this._networkObserver._onResponseFinished(this._browser, this._httpChannel, body);
+ } + }
+ +
+ _abort(errorCode) { + _abort(errorCode) {
@ -1838,15 +1866,14 @@ index 0000000000000000000000000000000000000000..ba34976ad05e7f5f1a99777f76ac08b1
+this.SimpleChannel = SimpleChannel; +this.SimpleChannel = SimpleChannel;
diff --git a/juggler/TargetRegistry.js b/juggler/TargetRegistry.js diff --git a/juggler/TargetRegistry.js b/juggler/TargetRegistry.js
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..e438996fbc04d2eec36436b7e3007649ed088286 index 0000000000000000000000000000000000000000..e601450c163db148baa1966b1585abdd6852261d
--- /dev/null --- /dev/null
+++ b/juggler/TargetRegistry.js +++ b/juggler/TargetRegistry.js
@@ -0,0 +1,264 @@ @@ -0,0 +1,269 @@
+const {EventEmitter} = ChromeUtils.import('resource://gre/modules/EventEmitter.jsm'); +const {EventEmitter} = ChromeUtils.import('resource://gre/modules/EventEmitter.jsm');
+const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); +const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js');
+const {SimpleChannel} = ChromeUtils.import('chrome://juggler/content/SimpleChannel.js'); +const {SimpleChannel} = ChromeUtils.import('chrome://juggler/content/SimpleChannel.js');
+const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
+const {BrowserContext} = ChromeUtils.import("chrome://juggler/content/BrowserContextManager.js");
+ +
+const Cc = Components.classes; +const Cc = Components.classes;
+const Ci = Components.interfaces; +const Ci = Components.interfaces;
@ -2018,12 +2045,8 @@ index 0000000000000000000000000000000000000000..e438996fbc04d2eec36436b7e3007649
+ this._contentReadyPromise = new Promise(f => this._contentReadyCallback = f); + this._contentReadyPromise = new Promise(f => this._contentReadyCallback = f);
+ this._waitForInitialNavigation = false; + this._waitForInitialNavigation = false;
+ +
+ if (browserContext) { + if (browserContext)
+ this._eventListeners.push(helper.on(browserContext, BrowserContext.Events.ScriptToEvaluateOnNewDocumentAdded, script => { + browserContext.pages.add(this);
+ this._channel.connect('').emit('addScriptToEvaluateOnNewDocument', {script});
+ }));
+ }
+
+ if (browserContext && browserContext.options.viewport) + if (browserContext && browserContext.options.viewport)
+ this.setViewportSize(browserContext.options.viewport.viewportSize); + this.setViewportSize(browserContext.options.viewport.viewportSize);
+ } + }
@ -2079,7 +2102,17 @@ index 0000000000000000000000000000000000000000..e438996fbc04d2eec36436b7e3007649
+ await this._channel.connect('').send('ensurePermissions', permissions).catch(e => void e); + await this._channel.connect('').send('ensurePermissions', permissions).catch(e => void e);
+ } + }
+ +
+ async addScriptToEvaluateOnNewDocument(script) {
+ await this._channel.connect('').send('addScriptToEvaluateOnNewDocument', script).catch(e => void e);
+ }
+
+ async setGeolocationOverride(geolocation) {
+ await this._channel.connect('').send('setGeolocationOverride', geolocation).catch(e => void e);
+ }
+
+ dispose() { + dispose() {
+ if (this._browserContext)
+ this._browserContext.pages.delete(this);
+ helper.removeListeners(this._eventListeners); + helper.removeListeners(this._eventListeners);
+ } + }
+} +}
@ -2704,10 +2737,10 @@ index 0000000000000000000000000000000000000000..be70ea364f9534bb3b344f64970366c3
+ +
diff --git a/juggler/content/PageAgent.js b/juggler/content/PageAgent.js diff --git a/juggler/content/PageAgent.js b/juggler/content/PageAgent.js
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..ccf881cfee36a1f47fbab880202cc72e7e98e387 index 0000000000000000000000000000000000000000..3dd06f27d071a1ca70609d63a12b1ff690d99371
--- /dev/null --- /dev/null
+++ b/juggler/content/PageAgent.js +++ b/juggler/content/PageAgent.js
@@ -0,0 +1,964 @@ @@ -0,0 +1,938 @@
+"use strict"; +"use strict";
+const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
+const Ci = Components.interfaces; +const Ci = Components.interfaces;
@ -2883,8 +2916,6 @@ index 0000000000000000000000000000000000000000..ccf881cfee36a1f47fbab880202cc72e
+ setEmulatedMedia: this._setEmulatedMedia.bind(this), + setEmulatedMedia: this._setEmulatedMedia.bind(this),
+ setFileInputFiles: this._setFileInputFiles.bind(this), + setFileInputFiles: this._setFileInputFiles.bind(this),
+ setInterceptFileChooserDialog: this._setInterceptFileChooserDialog.bind(this), + setInterceptFileChooserDialog: this._setInterceptFileChooserDialog.bind(this),
+ setGeolocationOverride: this._setGeolocationOverride.bind(this),
+ setLanguageOverride: this._setLanguageOverride.bind(this),
+ }), + }),
+ ]; + ];
+ this._enabled = false; + this._enabled = false;
@ -3046,30 +3077,6 @@ index 0000000000000000000000000000000000000000..ccf881cfee36a1f47fbab880202cc72e
+ this._docShell.fileInputInterceptionEnabled = !!enabled; + this._docShell.fileInputInterceptionEnabled = !!enabled;
+ } + }
+ +
+ _setGeolocationOverride({ latitude, longitude, accuracy }) {
+ if (latitude !== undefined && longitude !== undefined) {
+ this._docShell.setGeolocationOverride({
+ coords: {
+ latitude,
+ longitude,
+ accuracy,
+ altitude: NaN,
+ altitudeAccuracy: NaN,
+ heading: NaN,
+ speed: NaN,
+ },
+ address: null,
+ timestamp: Date.now()
+ });
+ } else {
+ this._docShell.setGeolocationOverride(null);
+ }
+ }
+
+ _setLanguageOverride({ language }) {
+ this._docShell.languageOverride = language;
+ }
+
+ _linkClicked(sync, anchorElement) { + _linkClicked(sync, anchorElement) {
+ if (anchorElement.ownerGlobal.docShell !== this._docShell) + if (anchorElement.ownerGlobal.docShell !== this._docShell)
+ return; + return;
@ -4437,10 +4444,10 @@ index 0000000000000000000000000000000000000000..3a386425d3796d0a6786dea193b3402d
+ +
diff --git a/juggler/content/main.js b/juggler/content/main.js diff --git a/juggler/content/main.js b/juggler/content/main.js
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..6ce6eff8dc8852d7fbbac907421de6de39d8ed0e index 0000000000000000000000000000000000000000..c7708c6904454fb25f08aa5c19f7aeca27db5e21
--- /dev/null --- /dev/null
+++ b/juggler/content/main.js +++ b/juggler/content/main.js
@@ -0,0 +1,129 @@ @@ -0,0 +1,157 @@
+const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
+const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); +const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js');
+const {FrameTree} = ChromeUtils.import('chrome://juggler/content/content/FrameTree.js'); +const {FrameTree} = ChromeUtils.import('chrome://juggler/content/content/FrameTree.js');
@ -4481,13 +4488,33 @@ index 0000000000000000000000000000000000000000..6ce6eff8dc8852d7fbbac907421de6de
+ handler.dispose(); + handler.dispose();
+} +}
+ +
+function setGeolocationOverrideInDocShell(geolocation) {
+ if (geolocation) {
+ docShell.setGeolocationOverride({
+ coords: {
+ latitude: geolocation.latitude,
+ longitude: geolocation.longitude,
+ accuracy: geolocation.accuracy,
+ altitude: NaN,
+ altitudeAccuracy: NaN,
+ heading: NaN,
+ speed: NaN,
+ },
+ address: null,
+ timestamp: Date.now()
+ });
+ } else {
+ docShell.setGeolocationOverride(null);
+ }
+}
+
+function initialize() { +function initialize() {
+ let response = sendSyncMessage('juggler:content-ready', {})[0]; + let response = sendSyncMessage('juggler:content-ready', {})[0];
+ if (!response) + if (!response)
+ response = { sessionIds: [], browserContextOptions: {}, waitForInitialNavigation: false }; + response = { sessionIds: [], browserContextOptions: {}, waitForInitialNavigation: false };
+ +
+ const { sessionIds, browserContextOptions, waitForInitialNavigation } = response; + const { sessionIds, browserContextOptions, waitForInitialNavigation } = response;
+ const { userAgent, bypassCSP, javaScriptDisabled, viewport, scriptsToEvaluateOnNewDocument } = browserContextOptions; + const { userAgent, bypassCSP, javaScriptDisabled, viewport, scriptsToEvaluateOnNewDocument, locale, geolocation } = browserContextOptions;
+ +
+ if (userAgent !== undefined) + if (userAgent !== undefined)
+ docShell.customUserAgent = userAgent; + docShell.customUserAgent = userAgent;
@ -4495,6 +4522,10 @@ index 0000000000000000000000000000000000000000..6ce6eff8dc8852d7fbbac907421de6de
+ docShell.bypassCSPEnabled = bypassCSP; + docShell.bypassCSPEnabled = bypassCSP;
+ if (javaScriptDisabled !== undefined) + if (javaScriptDisabled !== undefined)
+ docShell.allowJavascript = !javaScriptDisabled; + docShell.allowJavascript = !javaScriptDisabled;
+ if (locale !== undefined)
+ docShell.languageOverride = locale;
+ if (geolocation !== undefined)
+ setGeolocationOverrideInDocShell(geolocation);
+ if (viewport !== undefined) { + if (viewport !== undefined) {
+ docShell.contentViewer.overrideDPPX = viewport.deviceScaleFactor || this._initialDPPX; + docShell.contentViewer.overrideDPPX = viewport.deviceScaleFactor || this._initialDPPX;
+ docShell.deviceSizeIsPageSize = viewport.isMobile; + docShell.deviceSizeIsPageSize = viewport.isMobile;
@ -4521,10 +4552,14 @@ index 0000000000000000000000000000000000000000..6ce6eff8dc8852d7fbbac907421de6de
+ disposeContentSession(sessionId); + disposeContentSession(sessionId);
+ }, + },
+ +
+ addScriptToEvaluateOnNewDocument({script}) { + addScriptToEvaluateOnNewDocument(script) {
+ frameTree.addScriptToEvaluateOnNewDocument(script); + frameTree.addScriptToEvaluateOnNewDocument(script);
+ }, + },
+ +
+ setGeolocationOverride(geolocation) {
+ setGeolocationOverrideInDocShell(geolocation);
+ },
+
+ async ensurePermissions(permissions) { + async ensurePermissions(permissions) {
+ const checkPermissions = () => { + const checkPermissions = () => {
+ for (const permission of ALL_PERMISSIONS) { + for (const permission of ALL_PERMISSIONS) {
@ -4651,10 +4686,10 @@ index 0000000000000000000000000000000000000000..2f2b7ca247f6b6dff396fb4b644654de
+this.AccessibilityHandler = AccessibilityHandler; +this.AccessibilityHandler = AccessibilityHandler;
diff --git a/juggler/protocol/BrowserHandler.js b/juggler/protocol/BrowserHandler.js diff --git a/juggler/protocol/BrowserHandler.js b/juggler/protocol/BrowserHandler.js
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..a5f050cd024dfdd3d7b1366600273744f82c5cbb index 0000000000000000000000000000000000000000..5983ce421c19def00f3da36d8d4e5c4f7722006c
--- /dev/null --- /dev/null
+++ b/juggler/protocol/BrowserHandler.js +++ b/juggler/protocol/BrowserHandler.js
@@ -0,0 +1,172 @@ @@ -0,0 +1,170 @@
+"use strict"; +"use strict";
+ +
+const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
@ -4772,17 +4807,7 @@ index 0000000000000000000000000000000000000000..a5f050cd024dfdd3d7b1366600273744
+ } + }
+ +
+ async grantPermissions({browserContextId, origin, permissions}) { + async grantPermissions({browserContextId, origin, permissions}) {
+ const browserContext = this._contextManager.browserContextForId(browserContextId); + await this._contextManager.browserContextForId(browserContextId).grantPermissions(origin, permissions);
+ browserContext.grantPermissions(origin, permissions);
+ const contextPages = this._targetRegistry.pageTargets(browserContextId);
+ const promises = [];
+ for (const page of contextPages) {
+ if (origin === '*' || page._url.startsWith(origin)) {
+ browserContext.grantPermissionsToOrigin(page._url);
+ promises.push(page.ensurePermissions(permissions));
+ }
+ }
+ await Promise.all(promises);
+ } + }
+ +
+ resetPermissions({browserContextId}) { + resetPermissions({browserContextId}) {
@ -4797,8 +4822,16 @@ index 0000000000000000000000000000000000000000..a5f050cd024dfdd3d7b1366600273744
+ this._contextManager.browserContextForId(browserContextId).options.httpCredentials = credentials; + this._contextManager.browserContextForId(browserContextId).options.httpCredentials = credentials;
+ } + }
+ +
+ addScriptToEvaluateOnNewDocument({browserContextId, script}) { + setRequestInterception({browserContextId, enabled}) {
+ this._contextManager.browserContextForId(browserContextId).addScriptToEvaluateOnNewDocument(script); + this._contextManager.browserContextForId(browserContextId).options.requestInterceptionEnabled = enabled;
+ }
+
+ async setGeolocationOverride({browserContextId, geolocation}) {
+ await this._contextManager.browserContextForId(browserContextId).setGeolocationOverride(geolocation);
+ }
+
+ async addScriptToEvaluateOnNewDocument({browserContextId, script}) {
+ await this._contextManager.browserContextForId(browserContextId).addScriptToEvaluateOnNewDocument(script);
+ } + }
+ +
+ setCookies({browserContextId, cookies}) { + setCookies({browserContextId, cookies}) {
@ -5195,10 +5228,10 @@ index 0000000000000000000000000000000000000000..e1f1e21a20768d707a92ffffc8a7c114
+this.NetworkHandler = NetworkHandler; +this.NetworkHandler = NetworkHandler;
diff --git a/juggler/protocol/PageHandler.js b/juggler/protocol/PageHandler.js diff --git a/juggler/protocol/PageHandler.js b/juggler/protocol/PageHandler.js
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..c2e7ba3ee96c9d6f3da56a274c760b36816631a0 index 0000000000000000000000000000000000000000..11f9567d816304906df6b6192b3fb71e6c9d53dc
--- /dev/null --- /dev/null
+++ b/juggler/protocol/PageHandler.js +++ b/juggler/protocol/PageHandler.js
@@ -0,0 +1,357 @@ @@ -0,0 +1,348 @@
+"use strict"; +"use strict";
+ +
+const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); +const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js');
@ -5488,15 +5521,6 @@ index 0000000000000000000000000000000000000000..c2e7ba3ee96c9d6f3da56a274c760b36
+ throw new Error('ERROR: cannot find worker with id ' + workerId); + throw new Error('ERROR: cannot find worker with id ' + workerId);
+ return await worker.sendMessage(JSON.parse(message)); + return await worker.sendMessage(JSON.parse(message));
+ } + }
+
+ async setGeolocationOverride(options) {
+ return await this._contentPage.send('setGeolocationOverride', options);
+ }
+
+ async setLanguageOverride(options) {
+ return await this._contentPage.send('setLanguageOverride', options);
+ }
+
+} +}
+ +
+class Dialog { +class Dialog {
@ -5707,10 +5731,10 @@ index 0000000000000000000000000000000000000000..78b6601b91d0b7fcda61114e6846aa07
+this.EXPORTED_SYMBOLS = ['t', 'checkScheme']; +this.EXPORTED_SYMBOLS = ['t', 'checkScheme'];
diff --git a/juggler/protocol/Protocol.js b/juggler/protocol/Protocol.js diff --git a/juggler/protocol/Protocol.js b/juggler/protocol/Protocol.js
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..cb775900073f83e5e6892b84f8ff782dc8f5bc04 index 0000000000000000000000000000000000000000..a2608ebe6c45766c2fe34228f9d85ee222aa46c6
--- /dev/null --- /dev/null
+++ b/juggler/protocol/Protocol.js +++ b/juggler/protocol/Protocol.js
@@ -0,0 +1,757 @@ @@ -0,0 +1,764 @@
+const {t, checkScheme} = ChromeUtils.import('chrome://juggler/content/protocol/PrimitiveTypes.js'); +const {t, checkScheme} = ChromeUtils.import('chrome://juggler/content/protocol/PrimitiveTypes.js');
+ +
+// Protocol-specific types. +// Protocol-specific types.
@ -5749,6 +5773,12 @@ index 0000000000000000000000000000000000000000..cb775900073f83e5e6892b84f8ff782d
+ sameSite: t.Enum(['Strict', 'Lax', 'None']), + sameSite: t.Enum(['Strict', 'Lax', 'None']),
+}; +};
+ +
+browserTypes.Geolocation = {
+ latitude: t.Number,
+ longitude: t.Number,
+ accuracy: t.Optional(t.Number),
+};
+
+const pageTypes = {}; +const pageTypes = {};
+pageTypes.DOMPoint = { +pageTypes.DOMPoint = {
+ x: t.Number, + x: t.Number,
@ -5919,6 +5949,7 @@ index 0000000000000000000000000000000000000000..cb775900073f83e5e6892b84f8ff782d
+ bypassCSP: t.Optional(t.Boolean), + bypassCSP: t.Optional(t.Boolean),
+ javaScriptDisabled: t.Optional(t.Boolean), + javaScriptDisabled: t.Optional(t.Boolean),
+ viewport: t.Optional(pageTypes.Viewport), + viewport: t.Optional(pageTypes.Viewport),
+ locale: t.Optional(t.String),
+ }, + },
+ returns: { + returns: {
+ browserContextId: t.String, + browserContextId: t.String,
@ -5961,6 +5992,18 @@ index 0000000000000000000000000000000000000000..cb775900073f83e5e6892b84f8ff782d
+ credentials: t.Nullable(networkTypes.HTTPCredentials), + credentials: t.Nullable(networkTypes.HTTPCredentials),
+ }, + },
+ }, + },
+ 'setRequestInterception': {
+ params: {
+ browserContextId: t.Optional(t.String),
+ enabled: t.Boolean,
+ },
+ },
+ 'setGeolocationOverride': {
+ params: {
+ browserContextId: t.Optional(t.String),
+ geolocation: t.Nullable(browserTypes.Geolocation),
+ }
+ },
+ 'addScriptToEvaluateOnNewDocument': { + 'addScriptToEvaluateOnNewDocument': {
+ params: { + params: {
+ browserContextId: t.Optional(t.String), + browserContextId: t.Optional(t.String),
@ -6431,18 +6474,6 @@ index 0000000000000000000000000000000000000000..cb775900073f83e5e6892b84f8ff782d
+ message: t.String, + message: t.String,
+ }, + },
+ }, + },
+ 'setGeolocationOverride': {
+ params: {
+ latitude: t.Optional(t.Number),
+ longitude: t.Optional(t.Number),
+ accuracy: t.Optional(t.Number)
+ }
+ },
+ 'setLanguageOverride': {
+ params: {
+ language: t.String,
+ }
+ }
+ }, + },
+}; +};
+ +