summaryrefslogtreecommitdiffstats
path: root/remote
diff options
context:
space:
mode:
Diffstat (limited to 'remote')
-rw-r--r--remote/cdp/test/browser/network/browser_navigationEvents.js10
-rw-r--r--remote/marionette/actors/MarionetteCommandsChild.sys.mjs2
-rw-r--r--remote/marionette/browser.sys.mjs19
-rw-r--r--remote/marionette/driver.sys.mjs17
-rw-r--r--remote/shared/Prompt.sys.mjs43
-rw-r--r--remote/shared/listeners/PromptListener.sys.mjs11
-rw-r--r--remote/shared/messagehandler/test/browser/browser_handle_command_retry.js4
-rw-r--r--remote/shared/messagehandler/test/browser/browser_session_data_browser_element.js2
-rw-r--r--remote/shared/messagehandler/test/xpcshell/test_Errors.js2
-rw-r--r--remote/shared/webdriver/Capabilities.sys.mjs5
-rw-r--r--remote/webdriver-bidi/modules/root/browsingContext.sys.mjs24
-rw-r--r--remote/webdriver-bidi/modules/root/network.sys.mjs81
-rw-r--r--remote/webdriver-bidi/modules/root/session.sys.mjs37
-rw-r--r--remote/webdriver-bidi/modules/root/storage.sys.mjs129
-rw-r--r--remote/webdriver-bidi/modules/windowglobal/browsingContext.sys.mjs14
15 files changed, 229 insertions, 171 deletions
diff --git a/remote/cdp/test/browser/network/browser_navigationEvents.js b/remote/cdp/test/browser/network/browser_navigationEvents.js
index 57680c2a57..f120731158 100644
--- a/remote/cdp/test/browser/network/browser_navigationEvents.js
+++ b/remote/cdp/test/browser/network/browser_navigationEvents.js
@@ -76,6 +76,12 @@ add_task(async function eventsForTopFrameNavigation({ client }) {
"The same loaderId is used for dependent responses (Bug 1637838)"
);
is(scriptResponse.response.url, FRAMESET_JS_URL, "Got the Script response");
+
+ // The priority header only appears when the urgency and incremental values
+ // are not both default values (u=3 and i=false). In this case the scriptRequest.request.headers
+ // has no priority header and scriptResponse.response.requestHeaders does, hence we delete.
+ delete scriptResponse.response.requestHeaders.priority;
+
Assert.deepEqual(
scriptResponse.response.requestHeaders,
scriptRequest.request.headers,
@@ -125,6 +131,10 @@ add_task(async function eventsForTopFrameNavigation({ client }) {
subscriptResponse.loaderId === subdocRequest.loaderId,
"The same loaderId is used for dependent responses (Bug 1637838)"
);
+
+ // see comment above
+ delete subscriptResponse.response.requestHeaders.priority;
+
Assert.deepEqual(
subscriptResponse.response.requestHeaders,
subscriptRequest.request.headers,
diff --git a/remote/marionette/actors/MarionetteCommandsChild.sys.mjs b/remote/marionette/actors/MarionetteCommandsChild.sys.mjs
index 078612da56..d454e03fb0 100644
--- a/remote/marionette/actors/MarionetteCommandsChild.sys.mjs
+++ b/remote/marionette/actors/MarionetteCommandsChild.sys.mjs
@@ -284,7 +284,7 @@ export class MarionetteCommandsChild extends JSWindowActorChild {
const accessible = await lazy.accessibility.getAccessible(elem);
if (!accessible) {
- return null;
+ return "";
}
// If name is null (absent), expose the empty string.
diff --git a/remote/marionette/browser.sys.mjs b/remote/marionette/browser.sys.mjs
index d9a867fac5..397bb75a1e 100644
--- a/remote/marionette/browser.sys.mjs
+++ b/remote/marionette/browser.sys.mjs
@@ -145,23 +145,6 @@ browser.Context = class {
}
/**
- * Retrieves the current tabmodal UI object. According to the browser
- * associated with the currently selected tab.
- */
- getTabModal() {
- let br = this.contentBrowser;
- if (!br.hasAttribute("tabmodalPromptShowing")) {
- return null;
- }
-
- // The modal is a direct sibling of the browser element.
- // See tabbrowser.xml's getTabModalPromptBox.
- let modalElements = br.parentNode.getElementsByTagName("tabmodalprompt");
-
- return br.tabModalPromptBox.getPrompt(modalElements[0]);
- }
-
- /**
* Close the current window.
*
* @returns {Promise}
@@ -254,7 +237,7 @@ browser.Context = class {
tab = await lazy.TabManager.addTab({ focus, window: this.window });
} else if (lazy.AppInfo.isFirefox) {
const opened = new lazy.EventPromise(this.window, "TabOpen");
- this.window.BrowserOpenTab({ url: "about:blank" });
+ this.window.BrowserCommands.openTab({ url: "about:blank" });
await opened;
tab = this.tabBrowser.selectedTab;
diff --git a/remote/marionette/driver.sys.mjs b/remote/marionette/driver.sys.mjs
index f4642e756e..6b5b1cf082 100644
--- a/remote/marionette/driver.sys.mjs
+++ b/remote/marionette/driver.sys.mjs
@@ -3346,23 +3346,6 @@ GeckoDriver.prototype.setPermission = async function (cmd) {
const { descriptor, state, oneRealm = false } = cmd.parameters;
const browsingContext = lazy.assert.open(this.getBrowsingContext());
- // XXX: WPT should not have these but currently they do and we pass testing pref to
- // pass them, see bug 1875837.
- if (
- ["clipboard-read", "clipboard-write"].includes(descriptor.name) &&
- state === "granted"
- ) {
- if (
- Services.prefs.getBoolPref("dom.events.testing.asyncClipboard", false)
- ) {
- // Okay, do nothing. The clipboard module will work without permission.
- return;
- }
- throw new lazy.error.UnsupportedOperationError(
- "setPermission: expected dom.events.testing.asyncClipboard to be set"
- );
- }
-
// XXX: We currently depend on camera/microphone tests throwing UnsupportedOperationError,
// the fix is ongoing in bug 1609427.
if (["camera", "microphone"].includes(descriptor.name)) {
diff --git a/remote/shared/Prompt.sys.mjs b/remote/shared/Prompt.sys.mjs
index bacf24c5d1..39292d4bfd 100644
--- a/remote/shared/Prompt.sys.mjs
+++ b/remote/shared/Prompt.sys.mjs
@@ -42,7 +42,7 @@ modal.findPrompt = function (context) {
win.opener === context.window
) {
lazy.logger.trace("Found open window modal prompt");
- return new modal.Dialog(() => context, win);
+ return new modal.Dialog(win);
}
}
@@ -51,7 +51,7 @@ modal.findPrompt = function (context) {
if (geckoViewPrompts.length) {
lazy.logger.trace("Found open GeckoView prompt");
const prompt = geckoViewPrompts[0];
- return new modal.Dialog(() => context, prompt);
+ return new modal.Dialog(prompt);
}
}
@@ -65,7 +65,7 @@ modal.findPrompt = function (context) {
let dialogs = contentBrowser.tabDialogBox.getTabDialogManager().dialogs;
if (dialogs.length) {
lazy.logger.trace("Found open tab modal prompt");
- return new modal.Dialog(() => context, dialogs[0].frameContentWindow);
+ return new modal.Dialog(dialogs[0].frameContentWindow);
}
dialogs = contentBrowser.tabDialogBox.getContentDialogManager().dialogs;
@@ -74,36 +74,23 @@ modal.findPrompt = function (context) {
// gets lazily added. If it's not set yet, ignore the dialog for now.
if (dialogs.length && dialogs[0].frameContentWindow.Dialog) {
lazy.logger.trace("Found open content prompt");
- return new modal.Dialog(() => context, dialogs[0].frameContentWindow);
+ return new modal.Dialog(dialogs[0].frameContentWindow);
}
}
-
- // If no modal dialog has been found yet, check for old non SubDialog based
- // content modal dialogs. Even with those deprecated in Firefox 89 we should
- // keep supporting applications that don't have them implemented yet.
- if (contentBrowser?.tabModalPromptBox) {
- const prompts = contentBrowser.tabModalPromptBox.listPrompts();
- if (prompts.length) {
- lazy.logger.trace("Found open old-style content prompt");
- return new modal.Dialog(() => context, null);
- }
- }
-
return null;
};
/**
* Represents a modal dialog.
*
- * @param {function(): browser.Context} curBrowserFn
- * Function that returns the current |browser.Context|.
* @param {DOMWindow} dialog
* DOMWindow of the dialog.
*/
modal.Dialog = class {
- constructor(curBrowserFn, dialog) {
- this.curBrowserFn_ = curBrowserFn;
- this.win_ = Cu.getWeakReference(dialog);
+ #win;
+
+ constructor(dialog) {
+ this.#win = Cu.getWeakReference(dialog);
}
get args() {
@@ -114,10 +101,6 @@ modal.Dialog = class {
return tm ? tm.args : null;
}
- get curBrowser_() {
- return this.curBrowserFn_();
- }
-
get isOpen() {
if (lazy.AppInfo.isAndroid) {
return this.window !== null;
@@ -136,11 +119,7 @@ modal.Dialog = class {
}
get tabModal() {
- let win = this.window;
- if (win) {
- return win.Dialog;
- }
- return this.curBrowser_.getTabModal();
+ return this.window?.Dialog;
}
get promptType() {
@@ -164,8 +143,8 @@ modal.Dialog = class {
* it is currently attached to the DOM.
*/
get window() {
- if (this.win_) {
- let win = this.win_.get();
+ if (this.#win) {
+ let win = this.#win.get();
if (win && (lazy.AppInfo.isAndroid || win.parent)) {
return win;
}
diff --git a/remote/shared/listeners/PromptListener.sys.mjs b/remote/shared/listeners/PromptListener.sys.mjs
index e04c766970..0e14409051 100644
--- a/remote/shared/listeners/PromptListener.sys.mjs
+++ b/remote/shared/listeners/PromptListener.sys.mjs
@@ -172,7 +172,7 @@ export class PromptListener {
}
this.emit("opened", {
contentBrowser: curBrowser.contentBrowser,
- prompt: new lazy.modal.Dialog(() => curBrowser, subject),
+ prompt: new lazy.modal.Dialog(subject),
});
break;
@@ -190,7 +190,6 @@ export class PromptListener {
// the selected tab.
const tab = tabBrowser.selectedTab;
const contentBrowser = lazy.TabManager.getBrowserForTab(tab);
- const window = lazy.TabManager.getWindowForTab(tab);
// Do not send the event if the curBrowser is specified,
// and it's different from prompt browser.
@@ -200,13 +199,7 @@ export class PromptListener {
this.emit("opened", {
contentBrowser,
- prompt: new lazy.modal.Dialog(
- () => ({
- contentBrowser,
- window,
- }),
- prompt
- ),
+ prompt: new lazy.modal.Dialog(prompt),
});
return;
}
diff --git a/remote/shared/messagehandler/test/browser/browser_handle_command_retry.js b/remote/shared/messagehandler/test/browser/browser_handle_command_retry.js
index 1d020397e1..815990079b 100644
--- a/remote/shared/messagehandler/test/browser/browser_handle_command_retry.js
+++ b/remote/shared/messagehandler/test/browser/browser_handle_command_retry.js
@@ -12,8 +12,8 @@ PromiseTestUtils.allowMatchingRejectionsGlobally(
);
// The tests in this file assert the retry behavior for MessageHandler commands.
-// We call "blocked" commands from resources/modules/windowglobal/retry.jsm and
-// then trigger reload and navigations to simulate AbortErrors and force the
+// We call "blocked" commands from resources/modules/windowglobal/retry.sys.mjs
+// and then trigger reload and navigations to simulate AbortErrors and force the
// MessageHandler to retry the commands, when possible.
// Test that without retry behavior, a pending command rejects when the
diff --git a/remote/shared/messagehandler/test/browser/browser_session_data_browser_element.js b/remote/shared/messagehandler/test/browser/browser_session_data_browser_element.js
index 9c15974ae6..f435ad2a91 100644
--- a/remote/shared/messagehandler/test/browser/browser_session_data_browser_element.js
+++ b/remote/shared/messagehandler/test/browser/browser_session_data_browser_element.js
@@ -27,7 +27,7 @@ add_task(async function test_session_data_broadcast() {
const root = createRootMessageHandler("session-id-event");
- // When the windowglobal command.jsm module applies the session data
+ // When the windowglobal command.sys.mjs module applies the session data
// browser_session_data_browser_element, it will emit an event.
// Collect the events to detect which MessageHandlers have been started.
info("Watch events emitted when session data is applied");
diff --git a/remote/shared/messagehandler/test/xpcshell/test_Errors.js b/remote/shared/messagehandler/test/xpcshell/test_Errors.js
index 26187dac11..1a1d50e97e 100644
--- a/remote/shared/messagehandler/test/xpcshell/test_Errors.js
+++ b/remote/shared/messagehandler/test/xpcshell/test_Errors.js
@@ -7,7 +7,7 @@ const { error } = ChromeUtils.importESModule(
);
// Note: this test file is similar to remote/shared/webdriver/test/xpcshell/test_Errors.js
-// because shared/webdriver/Errors.jsm and shared/messagehandler/Errors.jsm share
+// because shared/webdriver/Errors.sys.mjs and shared/messagehandler/Errors.sys.mjs share
// similar helpers.
add_task(function test_toJSON() {
diff --git a/remote/shared/webdriver/Capabilities.sys.mjs b/remote/shared/webdriver/Capabilities.sys.mjs
index 3c30ea0789..8ed9836306 100644
--- a/remote/shared/webdriver/Capabilities.sys.mjs
+++ b/remote/shared/webdriver/Capabilities.sys.mjs
@@ -1031,7 +1031,10 @@ export function validateCapabilities(capabilities) {
*/
export function processCapabilities(params) {
const { capabilities } = params;
- lazy.assert.object(capabilities);
+ lazy.assert.object(
+ capabilities,
+ lazy.pprint`Expected "capabilities" to be an object, got ${capabilities}`
+ );
let {
alwaysMatch: requiredCapabilities = {},
diff --git a/remote/webdriver-bidi/modules/root/browsingContext.sys.mjs b/remote/webdriver-bidi/modules/root/browsingContext.sys.mjs
index f2a5d5e645..8424bebf4a 100644
--- a/remote/webdriver-bidi/modules/root/browsingContext.sys.mjs
+++ b/remote/webdriver-bidi/modules/root/browsingContext.sys.mjs
@@ -22,7 +22,6 @@ ChromeUtils.defineESModuleGetters(lazy, {
"chrome://remote/content/shared/NavigationManager.sys.mjs",
NavigationListener:
"chrome://remote/content/shared/listeners/NavigationListener.sys.mjs",
- OwnershipModel: "chrome://remote/content/webdriver-bidi/RemoteValue.sys.mjs",
PollPromise: "chrome://remote/content/shared/Sync.sys.mjs",
pprint: "chrome://remote/content/shared/Format.sys.mjs",
print: "chrome://remote/content/shared/PDF.sys.mjs",
@@ -857,12 +856,6 @@ class BrowsingContextModule extends Module {
* @param {number=} options.maxNodeCount
* The maximum amount of nodes which is going to be returned.
* Defaults to return all the found nodes.
- * @param {OwnershipModel=} options.ownership
- * The ownership model to use for the serialization
- * of the DOM nodes. Defaults to `OwnershipModel.None`.
- * @property {string=} sandbox
- * The name of the sandbox. If the value is null or empty
- * string, the default realm will be used.
* @property {SerializationOptions=} serializationOptions
* An object which holds the information of how the DOM nodes
* should be serialized.
@@ -884,8 +877,6 @@ class BrowsingContextModule extends Module {
context: contextId,
locator,
maxNodeCount = null,
- ownership = lazy.OwnershipModel.None,
- sandbox = null,
serializationOptions,
startNodes = null,
} = options;
@@ -923,19 +914,6 @@ class BrowsingContextModule extends Module {
}, maxNodeCountErrorMsg)(maxNodeCount);
}
- const ownershipTypes = Object.values(lazy.OwnershipModel);
- lazy.assert.that(
- ownership => ownershipTypes.includes(ownership),
- `Expected "ownership" to be one of ${ownershipTypes}, got ${ownership}`
- )(ownership);
-
- if (sandbox != null) {
- lazy.assert.string(
- sandbox,
- `Expected "sandbox" to be a string, got ${sandbox}`
- );
- }
-
const serializationOptionsWithDefaults =
lazy.setDefaultAndAssertSerializationOptions(serializationOptions);
@@ -961,8 +939,6 @@ class BrowsingContextModule extends Module {
params: {
locator,
maxNodeCount,
- resultOwnership: ownership,
- sandbox,
serializationOptions: serializationOptionsWithDefaults,
startNodes,
},
diff --git a/remote/webdriver-bidi/modules/root/network.sys.mjs b/remote/webdriver-bidi/modules/root/network.sys.mjs
index 238b9f3640..6850e3f372 100644
--- a/remote/webdriver-bidi/modules/root/network.sys.mjs
+++ b/remote/webdriver-bidi/modules/root/network.sys.mjs
@@ -340,6 +340,9 @@ class NetworkModule extends Module {
* of any intercept, the request will be suspended.
*
* @param {object=} options
+ * @param {Array<string>=} options.contexts
+ * The list of browsing context ids where this intercept should be used.
+ * Optional, defaults to null.
* @param {Array<InterceptPhase>} options.phases
* The phases where this intercept should be checked.
* @param {Array<URLPattern>=} options.urlPatterns
@@ -353,7 +356,34 @@ class NetworkModule extends Module {
* Raised if an argument is of an invalid type or value.
*/
addIntercept(options = {}) {
- const { phases, urlPatterns = [] } = options;
+ const { contexts = null, phases, urlPatterns = [] } = options;
+
+ if (contexts !== null) {
+ lazy.assert.array(
+ contexts,
+ `Expected "contexts" to be an array, got ${contexts}`
+ );
+
+ if (!options.contexts.length) {
+ throw new lazy.error.InvalidArgumentError(
+ `Expected "contexts" to contain at least one item, got an empty array`
+ );
+ }
+
+ for (const contextId of contexts) {
+ lazy.assert.string(
+ contextId,
+ `Expected elements of "contexts" to be a string, got ${contextId}`
+ );
+ const context = this.#getBrowsingContext(contextId);
+
+ if (context.parent) {
+ throw new lazy.error.InvalidArgumentError(
+ `Context with id ${contextId} is not a top-level browsing context`
+ );
+ }
+ }
+ }
lazy.assert.array(
phases,
@@ -386,6 +416,7 @@ class NetworkModule extends Module {
const interceptId = lazy.generateUUID();
this.#interceptMap.set(interceptId, {
+ contexts,
phases,
urlPatterns: parsedPatterns,
});
@@ -1122,6 +1153,23 @@ class NetworkModule extends Module {
return challenges;
}
+ #getBrowsingContext(contextId) {
+ const context = lazy.TabManager.getBrowsingContextById(contextId);
+ if (context === null) {
+ throw new lazy.error.NoSuchFrameError(
+ `Browsing Context with id ${contextId} not found`
+ );
+ }
+
+ if (!context.currentWindowGlobal) {
+ throw new lazy.error.NoSuchFrameError(
+ `No window found for BrowsingContext with id ${contextId}`
+ );
+ }
+
+ return context;
+ }
+
#getContextInfo(browsingContext) {
return {
contextId: browsingContext.id,
@@ -1129,11 +1177,7 @@ class NetworkModule extends Module {
};
}
- #getSuspendMarkerText(requestData, phase) {
- return `Request (id: ${requestData.request}) suspended by WebDriver BiDi in ${phase} phase`;
- }
-
- #getNetworkIntercepts(event, requestData) {
+ #getNetworkIntercepts(event, requestData, contextId) {
const intercepts = [];
let phase;
@@ -1153,8 +1197,23 @@ class NetworkModule extends Module {
return intercepts;
}
+ // Retrieve the top browsing context id for this network event.
+ const browsingContext = lazy.TabManager.getBrowsingContextById(contextId);
+ const topLevelContextId = lazy.TabManager.getIdForBrowsingContext(
+ browsingContext.top
+ );
+
const url = requestData.url;
for (const [interceptId, intercept] of this.#interceptMap) {
+ if (
+ intercept.contexts !== null &&
+ !intercept.contexts.includes(topLevelContextId)
+ ) {
+ // Skip this intercept if the event's context does not match the list
+ // of contexts for this intercept.
+ continue;
+ }
+
if (intercept.phases.includes(phase)) {
const urlPatterns = intercept.urlPatterns;
if (
@@ -1196,6 +1255,10 @@ class NetworkModule extends Module {
return navigation ? navigation.navigationId : null;
}
+ #getSuspendMarkerText(requestData, phase) {
+ return `Request (id: ${requestData.request}) suspended by WebDriver BiDi in ${phase} phase`;
+ }
+
#onAuthRequired = (name, data) => {
const {
authCallbacks,
@@ -1580,7 +1643,11 @@ class NetworkModule extends Module {
#processNetworkEvent(eventName, data) {
const { contextId, navigation, redirectCount, requestData, timestamp } =
data;
- const intercepts = this.#getNetworkIntercepts(eventName, requestData);
+ const intercepts = this.#getNetworkIntercepts(
+ eventName,
+ requestData,
+ contextId
+ );
const isBlocked = !!intercepts.length;
const baseParameters = {
diff --git a/remote/webdriver-bidi/modules/root/session.sys.mjs b/remote/webdriver-bidi/modules/root/session.sys.mjs
index a34ca514e3..8ecf7d7724 100644
--- a/remote/webdriver-bidi/modules/root/session.sys.mjs
+++ b/remote/webdriver-bidi/modules/root/session.sys.mjs
@@ -76,16 +76,10 @@ class SessionModule extends Module {
const { events, contexts: contextIds = null } = params;
// Check input types until we run schema validation.
- lazy.assert.array(events, "events: array value expected");
- events.forEach(name => {
- lazy.assert.string(name, `${name}: string value expected`);
- });
+ this.#assertNonEmptyArrayWithStrings(events, "events");
if (contextIds !== null) {
- lazy.assert.array(contextIds, "contexts: array value expected");
- contextIds.forEach(contextId => {
- lazy.assert.string(contextId, `${contextId}: string value expected`);
- });
+ this.#assertNonEmptyArrayWithStrings(contextIds, "contexts");
}
const listeners = this.#updateEventMap(events, contextIds, true);
@@ -113,15 +107,9 @@ class SessionModule extends Module {
const { events, contexts: contextIds = null } = params;
// Check input types until we run schema validation.
- lazy.assert.array(events, "events: array value expected");
- events.forEach(name => {
- lazy.assert.string(name, `${name}: string value expected`);
- });
+ this.#assertNonEmptyArrayWithStrings(events, "events");
if (contextIds !== null) {
- lazy.assert.array(contextIds, "contexts: array value expected");
- contextIds.forEach(contextId => {
- lazy.assert.string(contextId, `${contextId}: string value expected`);
- });
+ this.#assertNonEmptyArrayWithStrings(contextIds, "contexts");
}
const listeners = this.#updateEventMap(events, contextIds, false);
@@ -139,6 +127,23 @@ class SessionModule extends Module {
}
}
+ #assertNonEmptyArrayWithStrings(array, variableName) {
+ lazy.assert.array(
+ array,
+ `Expected "${variableName}" to be an array, got ${array}`
+ );
+ lazy.assert.that(
+ array => !!array.length,
+ `Expected "${variableName}" array to have at least one item`
+ )(array);
+ array.forEach(item => {
+ lazy.assert.string(
+ item,
+ `Expected elements of "${variableName}" to be a string, got ${item}`
+ );
+ });
+ }
+
#getBrowserIdForContextId(contextId) {
const context = lazy.TabManager.getBrowsingContextById(contextId);
if (!context) {
diff --git a/remote/webdriver-bidi/modules/root/storage.sys.mjs b/remote/webdriver-bidi/modules/root/storage.sys.mjs
index 3eced2da4c..34f909aa28 100644
--- a/remote/webdriver-bidi/modules/root/storage.sys.mjs
+++ b/remote/webdriver-bidi/modules/root/storage.sys.mjs
@@ -16,6 +16,15 @@ ChromeUtils.defineESModuleGetters(lazy, {
"chrome://remote/content/shared/UserContextManager.sys.mjs",
});
+const PREF_COOKIE_BEHAVIOR = "network.cookie.cookieBehavior";
+const PREF_COOKIE_OPTIN_PARTITIONING =
+ "network.cookie.cookieBehavior.optInPartitioning";
+
+// This is a static preference, so it cannot be modified during runtime and we can cache its value.
+ChromeUtils.defineLazyGetter(lazy, "cookieBehaviorOptInPartitioning", () =>
+ Services.prefs.getBoolPref(PREF_COOKIE_OPTIN_PARTITIONING)
+);
+
const CookieFieldsMapping = {
domain: "host",
expiry: "expiry",
@@ -603,10 +612,22 @@ class StorageModule extends Module {
if (partitionSpec.type === PartitionType.Context) {
const { context: contextId } = partitionSpec;
const browsingContext = this.#getBrowsingContext(contextId);
+ const principal = Services.scriptSecurityManager.createContentPrincipal(
+ browsingContext.currentURI,
+ {}
+ );
// Define browsing context’s associated storage partition as combination of user context id
- // and the origin of the document in this browsing context.
+ // and the origin of the document in this browsing context. We also add here `isThirdPartyURI`
+ // which is required to filter out third-party cookies in case they are not allowed.
return {
+ // In case we have the browsing context of an iframe here, we perform a check
+ // if the URI of the top context is considered third-party to the URI of the iframe principal.
+ // It's considered a third-party if base domains or hosts (in case one or both base domains
+ // can not be determined) do not match.
+ isThirdPartyURI: browsingContext.parent
+ ? principal.isThirdPartyURI(browsingContext.top.currentURI)
+ : false,
sourceOrigin: browsingContext.currentURI.prePath,
userContext: browsingContext.originAttributes.userContextId,
};
@@ -640,6 +661,9 @@ class StorageModule extends Module {
);
}
+ // This key is not used for partitioning and was required to only filter out third-party cookies.
+ delete partitionKey.isThirdPartyURI;
+
return partitionKey;
}
@@ -742,44 +766,61 @@ class StorageModule extends Module {
// Prepare the data in the format required for the platform API.
const originAttributes = this.#getOriginAttributes(storagePartitionKey);
- // In case we want to get the cookies for a certain `sourceOrigin`,
- // we have to separately retrieve cookies for a hostname built from `sourceOrigin`,
- // and with `partitionKey` equal an empty string to retrieve the cookies that which were set
- // by this hostname but without `partitionKey`, e.g. with `document.cookie`.
- if (storagePartitionKey.sourceOrigin) {
- const url = new URL(storagePartitionKey.sourceOrigin);
- const hostname = url.hostname;
-
- const principal = Services.scriptSecurityManager.createContentPrincipal(
- Services.io.newURI(url),
- {}
+ // Retrieve the cookies which exactly match a built partition attributes.
+ const cookiesWithOriginAttributes =
+ Services.cookies.getCookiesWithOriginAttributes(
+ JSON.stringify(originAttributes)
);
- const isSecureProtocol = principal.isOriginPotentiallyTrustworthy;
-
- // We want to keep `userContext` id here, if it's present,
- // but set the `partitionKey` to an empty string.
- const cookiesMatchingHostname =
- Services.cookies.getCookiesWithOriginAttributes(
- JSON.stringify({ ...originAttributes, partitionKey: "" }),
- hostname
+
+ const isFirstPartyOrCrossSiteAllowed =
+ !storagePartitionKey.isThirdPartyURI ||
+ this.#shouldIncludeCrossSiteCookie();
+
+ // Check if we accessing the first party storage or cross-site cookies are allowed.
+ if (isFirstPartyOrCrossSiteAllowed) {
+ // In case we want to get the cookies for a certain `sourceOrigin`,
+ // we have to separately retrieve cookies for a hostname built from `sourceOrigin`,
+ // and with `partitionKey` equal an empty string to retrieve the cookies that which were set
+ // by this hostname but without `partitionKey`, e.g. with `document.cookie`.
+ if (storagePartitionKey.sourceOrigin) {
+ const url = new URL(storagePartitionKey.sourceOrigin);
+ const hostname = url.hostname;
+
+ const principal = Services.scriptSecurityManager.createContentPrincipal(
+ Services.io.newURI(url),
+ {}
);
+ const isSecureProtocol = principal.isOriginPotentiallyTrustworthy;
+
+ // We want to keep `userContext` id here, if it's present,
+ // but set the `partitionKey` to an empty string.
+ const cookiesMatchingHostname =
+ Services.cookies.getCookiesWithOriginAttributes(
+ JSON.stringify({ ...originAttributes, partitionKey: "" }),
+ hostname
+ );
+ for (const cookie of cookiesMatchingHostname) {
+ // Ignore secure cookies for non-secure protocols.
+ if (cookie.isSecure && !isSecureProtocol) {
+ continue;
+ }
+ store.push(cookie);
+ }
+ }
- for (const cookie of cookiesMatchingHostname) {
- // Ignore secure cookies for non-secure protocols.
- if (cookie.isSecure && !isSecureProtocol) {
- continue;
+ store = store.concat(cookiesWithOriginAttributes);
+ }
+ // If we're trying to access the store in the third party context and
+ // the preferences imply that we shouldn't include cross site cookies,
+ // but we should include partitioned cookies, add only partitioned cookies.
+ else if (this.#shouldIncludePartitionedCookies()) {
+ for (const cookie of cookiesWithOriginAttributes) {
+ if (cookie.isPartitioned) {
+ store.push(cookie);
}
- store.push(cookie);
}
}
- // Add the cookies which exactly match a built partition attributes.
- store = store.concat(
- Services.cookies.getCookiesWithOriginAttributes(
- JSON.stringify(originAttributes)
- )
- );
-
return store;
}
@@ -856,6 +897,30 @@ class StorageModule extends Module {
return cookie;
}
+
+ #shouldIncludeCrossSiteCookie() {
+ const cookieBehavior = Services.prefs.getIntPref(PREF_COOKIE_BEHAVIOR);
+
+ if (
+ cookieBehavior === Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN ||
+ cookieBehavior ===
+ Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN
+ ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ #shouldIncludePartitionedCookies() {
+ const cookieBehavior = Services.prefs.getIntPref(PREF_COOKIE_BEHAVIOR);
+
+ return (
+ cookieBehavior ===
+ Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN &&
+ lazy.cookieBehaviorOptInPartitioning
+ );
+ }
}
export const storage = StorageModule;
diff --git a/remote/webdriver-bidi/modules/windowglobal/browsingContext.sys.mjs b/remote/webdriver-bidi/modules/windowglobal/browsingContext.sys.mjs
index adf821601d..ef61954284 100644
--- a/remote/webdriver-bidi/modules/windowglobal/browsingContext.sys.mjs
+++ b/remote/webdriver-bidi/modules/windowglobal/browsingContext.sys.mjs
@@ -17,6 +17,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
"chrome://remote/content/webdriver-bidi/modules/root/browsingContext.sys.mjs",
OriginType:
"chrome://remote/content/webdriver-bidi/modules/root/browsingContext.sys.mjs",
+ OwnershipModel: "chrome://remote/content/webdriver-bidi/RemoteValue.sys.mjs",
PollPromise: "chrome://remote/content/shared/Sync.sys.mjs",
});
@@ -425,16 +426,9 @@ class BrowsingContextModule extends WindowGlobalBiDiModule {
}
_locateNodes(params = {}) {
- const {
- locator,
- maxNodeCount,
- resultOwnership,
- sandbox,
- serializationOptions,
- startNodes,
- } = params;
+ const { locator, maxNodeCount, serializationOptions, startNodes } = params;
- const realm = this.messageHandler.getRealm({ sandboxName: sandbox });
+ const realm = this.messageHandler.getRealm();
const contextNodes = [];
if (startNodes === null) {
@@ -482,7 +476,7 @@ class BrowsingContextModule extends WindowGlobalBiDiModule {
this.serialize(
returnedNode,
serializationOptions,
- resultOwnership,
+ lazy.OwnershipModel.None,
realm,
{ seenNodeIds }
)