summaryrefslogtreecommitdiffstats
path: root/dom/security/test/general
diff options
context:
space:
mode:
Diffstat (limited to 'dom/security/test/general')
-rw-r--r--dom/security/test/general/browser.ini55
-rw-r--r--dom/security/test/general/browser_file_nonscript.js38
-rw-r--r--dom/security/test/general/browser_restrict_privileged_about_script.js70
-rw-r--r--dom/security/test/general/browser_same_site_cookies_bug1748693.js51
-rw-r--r--dom/security/test/general/browser_test_assert_systemprincipal_documents.js41
-rw-r--r--dom/security/test/general/browser_test_data_download.js113
-rw-r--r--dom/security/test/general/browser_test_data_text_csv.js108
-rw-r--r--dom/security/test/general/browser_test_framing_error_pages.js53
-rw-r--r--dom/security/test/general/browser_test_referrer_loadInOtherProcess.js156
-rw-r--r--dom/security/test/general/browser_test_report_blocking.js218
-rw-r--r--dom/security/test/general/browser_test_toplevel_data_navigations.js70
-rw-r--r--dom/security/test/general/browser_test_view_image_data_navigation.js71
-rw-r--r--dom/security/test/general/browser_test_xfo_embed_object.js41
-rw-r--r--dom/security/test/general/bug1277803.html11
-rw-r--r--dom/security/test/general/chrome.ini11
-rw-r--r--dom/security/test/general/closeWindow.sjs24
-rw-r--r--dom/security/test/general/favicon_bug1277803.icobin0 -> 1406 bytes
-rw-r--r--dom/security/test/general/file_1767581.js1
-rw-r--r--dom/security/test/general/file_about_child.html11
-rw-r--r--dom/security/test/general/file_assert_systemprincipal_documents.html11
-rw-r--r--dom/security/test/general/file_assert_systemprincipal_documents_iframe.html9
-rw-r--r--dom/security/test/general/file_block_script_wrong_mime_server.sjs38
-rw-r--r--dom/security/test/general/file_block_subresource_redir_to_data.sjs33
-rw-r--r--dom/security/test/general/file_block_toplevel_data_navigation.html16
-rw-r--r--dom/security/test/general/file_block_toplevel_data_navigation2.html17
-rw-r--r--dom/security/test/general/file_block_toplevel_data_navigation3.html16
-rw-r--r--dom/security/test/general/file_block_toplevel_data_redirect.sjs13
-rw-r--r--dom/security/test/general/file_cache_splitting_isloaded.sjs35
-rw-r--r--dom/security/test/general/file_cache_splitting_server.sjs27
-rw-r--r--dom/security/test/general/file_cache_splitting_window.html17
-rw-r--r--dom/security/test/general/file_contentpolicytype_targeted_link_iframe.sjs45
-rw-r--r--dom/security/test/general/file_data_download.html14
-rw-r--r--dom/security/test/general/file_data_text_csv.html14
-rw-r--r--dom/security/test/general/file_framing_error_pages.sjs27
-rw-r--r--dom/security/test/general/file_framing_error_pages_csp.html7
-rw-r--r--dom/security/test/general/file_framing_error_pages_xfo.html7
-rw-r--r--dom/security/test/general/file_framing_xfo_embed.html7
-rw-r--r--dom/security/test/general/file_framing_xfo_embed_object.sjs7
-rw-r--r--dom/security/test/general/file_framing_xfo_object.html7
-rw-r--r--dom/security/test/general/file_gpc_server.sjs14
-rw-r--r--dom/security/test/general/file_loads_nonscript.html49
-rw-r--r--dom/security/test/general/file_meta_referrer_in_head.html13
-rw-r--r--dom/security/test/general/file_meta_referrer_notin_head.html14
-rw-r--r--dom/security/test/general/file_nonscript1
-rw-r--r--dom/security/test/general/file_nonscript.html1
-rw-r--r--dom/security/test/general/file_nonscript.json1
-rw-r--r--dom/security/test/general/file_nonscript.txt1
-rw-r--r--dom/security/test/general/file_nonscript.xyz1
-rw-r--r--dom/security/test/general/file_nosniff_navigation.sjs40
-rw-r--r--dom/security/test/general/file_nosniff_testserver.sjs61
-rw-r--r--dom/security/test/general/file_same_site_cookies_about.sjs99
-rw-r--r--dom/security/test/general/file_same_site_cookies_blob_iframe_inclusion.html34
-rw-r--r--dom/security/test/general/file_same_site_cookies_blob_iframe_navigation.html30
-rw-r--r--dom/security/test/general/file_same_site_cookies_bug1748693.sjs31
-rw-r--r--dom/security/test/general/file_same_site_cookies_cross_origin_context.sjs54
-rw-r--r--dom/security/test/general/file_same_site_cookies_from_script.sjs48
-rw-r--r--dom/security/test/general/file_same_site_cookies_iframe.sjs99
-rw-r--r--dom/security/test/general/file_same_site_cookies_redirect.sjs103
-rw-r--r--dom/security/test/general/file_same_site_cookies_subrequest.sjs82
-rw-r--r--dom/security/test/general/file_same_site_cookies_toplevel_nav.sjs96
-rw-r--r--dom/security/test/general/file_same_site_cookies_toplevel_set_cookie.sjs68
-rw-r--r--dom/security/test/general/file_script.js1
-rw-r--r--dom/security/test/general/file_toplevel_data_meta_redirect.html10
-rw-r--r--dom/security/test/general/file_toplevel_data_navigations.sjs13
-rw-r--r--dom/security/test/general/file_view_bg_image_data_navigation.html16
-rw-r--r--dom/security/test/general/file_view_image_data_navigation.html12
-rw-r--r--dom/security/test/general/file_xfo_error_page.sjs8
-rw-r--r--dom/security/test/general/mochitest.ini95
-rw-r--r--dom/security/test/general/test_allow_opening_data_json.html39
-rw-r--r--dom/security/test/general/test_assert_about_page_no_csp.html30
-rw-r--r--dom/security/test/general/test_block_script_wrong_mime.html92
-rw-r--r--dom/security/test/general/test_block_subresource_redir_to_data.html68
-rw-r--r--dom/security/test/general/test_block_toplevel_data_img_navigation.html53
-rw-r--r--dom/security/test/general/test_block_toplevel_data_navigation.html134
-rw-r--r--dom/security/test/general/test_bug1277803.xhtml65
-rw-r--r--dom/security/test/general/test_bug1450853.html91
-rw-r--r--dom/security/test/general/test_bug1660452_http.html39
-rw-r--r--dom/security/test/general/test_bug1660452_https.html39
-rw-r--r--dom/security/test/general/test_cache_split.html153
-rw-r--r--dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html103
-rw-r--r--dom/security/test/general/test_gpc.html51
-rw-r--r--dom/security/test/general/test_innerhtml_sanitizer.html74
-rw-r--r--dom/security/test/general/test_innerhtml_sanitizer.xhtml73
-rw-r--r--dom/security/test/general/test_meta_referrer.html55
-rw-r--r--dom/security/test/general/test_nosniff.html88
-rw-r--r--dom/security/test/general/test_nosniff_navigation.html35
-rw-r--r--dom/security/test/general/test_same_site_cookies_about.html116
-rw-r--r--dom/security/test/general/test_same_site_cookies_cross_origin_context.html93
-rw-r--r--dom/security/test/general/test_same_site_cookies_from_script.html86
-rw-r--r--dom/security/test/general/test_same_site_cookies_iframe.html168
-rw-r--r--dom/security/test/general/test_same_site_cookies_laxByDefault.html85
-rw-r--r--dom/security/test/general/test_same_site_cookies_redirect.html101
-rw-r--r--dom/security/test/general/test_same_site_cookies_subrequest.html113
-rw-r--r--dom/security/test/general/test_same_site_cookies_toplevel_nav.html117
-rw-r--r--dom/security/test/general/test_same_site_cookies_toplevel_set_cookie.html57
-rw-r--r--dom/security/test/general/test_xfo_error_page.html35
-rw-r--r--dom/security/test/general/window_nosniff_navigation.html96
97 files changed, 4954 insertions, 0 deletions
diff --git a/dom/security/test/general/browser.ini b/dom/security/test/general/browser.ini
new file mode 100644
index 0000000000..bdbaf86b03
--- /dev/null
+++ b/dom/security/test/general/browser.ini
@@ -0,0 +1,55 @@
+[DEFAULT]
+[browser_test_toplevel_data_navigations.js]
+skip-if = (verify && debug && (os == 'mac')) || (debug && (os == 'mac' || os == 'linux')) # Bug 1403815
+support-files =
+ file_toplevel_data_navigations.sjs
+ file_toplevel_data_meta_redirect.html
+[browser_test_data_download.js]
+support-files =
+ file_data_download.html
+[browser_test_data_text_csv.js]
+support-files =
+ file_data_text_csv.html
+[browser_test_view_image_data_navigation.js]
+support-files =
+ file_view_image_data_navigation.html
+ file_view_bg_image_data_navigation.html
+[browser_test_assert_systemprincipal_documents.js]
+skip-if = !nightly_build
+support-files =
+ file_assert_systemprincipal_documents.html
+ file_assert_systemprincipal_documents_iframe.html
+[browser_test_referrer_loadInOtherProcess.js]
+[browser_test_framing_error_pages.js]
+support-files =
+ file_framing_error_pages_csp.html
+ file_framing_error_pages_xfo.html
+ file_framing_error_pages.sjs
+[browser_test_xfo_embed_object.js]
+support-files =
+ file_framing_xfo_embed.html
+ file_framing_xfo_object.html
+ file_framing_xfo_embed_object.sjs
+[browser_test_report_blocking.js]
+support-files =
+ file_framing_error_pages_xfo.html
+ file_framing_error_pages_csp.html
+ file_framing_error_pages.sjs
+[browser_same_site_cookies_bug1748693.js]
+support-files =
+ file_same_site_cookies_bug1748693.sjs
+[browser_file_nonscript.js]
+support-files =
+ file_loads_nonscript.html
+ file_nonscript
+ file_nonscript.xyz
+ file_nonscript.html
+ file_nonscript.txt
+ file_nonscript.json
+ file_script.js
+[browser_restrict_privileged_about_script.js]
+# This test intentionally asserts when in debug builds. Let's rely on opt builds when in CI.
+skip-if = debug
+support-files =
+ file_about_child.html
+ file_1767581.js
diff --git a/dom/security/test/general/browser_file_nonscript.js b/dom/security/test/general/browser_file_nonscript.js
new file mode 100644
index 0000000000..95243c32a7
--- /dev/null
+++ b/dom/security/test/general/browser_file_nonscript.js
@@ -0,0 +1,38 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function test_fileurl_nonscript_load() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["security.block_fileuri_script_with_wrong_mime", true]],
+ });
+
+ let file = getChromeDir(getResolvedURI(gTestPath));
+ file.append("file_loads_nonscript.html");
+ let uriString = Services.io.newFileURI(file).spec;
+
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, uriString);
+ registerCleanupFunction(async function () {
+ BrowserTestUtils.removeTab(tab);
+ });
+
+ let counter = await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
+ Cu.exportFunction(Assert.equal.bind(Assert), content.window, {
+ defineAs: "equal",
+ });
+ content.window.postMessage("run", "*");
+
+ await new Promise(resolve => {
+ content.window.addEventListener("message", event => {
+ if (event.data === "done") {
+ resolve();
+ }
+ });
+ });
+
+ return content.window.wrappedJSObject.counter;
+ });
+
+ is(counter, 1, "Only one script should have run");
+});
diff --git a/dom/security/test/general/browser_restrict_privileged_about_script.js b/dom/security/test/general/browser_restrict_privileged_about_script.js
new file mode 100644
index 0000000000..0baa6e3d4d
--- /dev/null
+++ b/dom/security/test/general/browser_restrict_privileged_about_script.js
@@ -0,0 +1,70 @@
+"use strict";
+
+const kChildPage = getRootDirectory(gTestPath) + "file_about_child.html";
+
+const kAboutPagesRegistered = BrowserTestUtils.registerAboutPage(
+ registerCleanupFunction,
+ "test-about-privileged-with-scripts",
+ kChildPage,
+ Ci.nsIAboutModule.ALLOW_SCRIPT |
+ Ci.nsIAboutModule.URI_MUST_LOAD_IN_CHILD |
+ Ci.nsIAboutModule.URI_CAN_LOAD_IN_PRIVILEGEDABOUT_PROCESS |
+ Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT |
+ Ci.nsIAboutModule.IS_SECURE_CHROME_UI
+);
+
+add_task(async function test_principal_click() {
+ await kAboutPagesRegistered;
+ await SpecialPowers.pushPrefEnv({
+ set: [["dom.security.skip_about_page_has_csp_assert", true]],
+ });
+ await BrowserTestUtils.withNewTab(
+ "about:test-about-privileged-with-scripts",
+ async function (browser) {
+ // Wait for page to fully load
+ info("Waiting for tab to be loaded..");
+ // let's look into the fully loaded about page
+ await SpecialPowers.spawn(
+ gBrowser.selectedBrowser,
+ [],
+ async function () {
+ let channel = content.docShell.currentDocumentChannel;
+ is(
+ channel.originalURI.asciiSpec,
+ "about:test-about-privileged-with-scripts",
+ "sanity check - make sure we test the principal for the correct URI"
+ );
+
+ let triggeringPrincipal = channel.loadInfo.triggeringPrincipal;
+ ok(
+ triggeringPrincipal.isSystemPrincipal,
+ "loading about: from privileged page must have a triggering of System"
+ );
+
+ let contentPolicyType = channel.loadInfo.externalContentPolicyType;
+ is(
+ contentPolicyType,
+ Ci.nsIContentPolicy.TYPE_DOCUMENT,
+ "sanity check - loading a top level document"
+ );
+
+ let loadingPrincipal = channel.loadInfo.loadingPrincipal;
+ is(
+ loadingPrincipal,
+ null,
+ "sanity check - load of TYPE_DOCUMENT must have a null loadingPrincipal"
+ );
+ ok(
+ !content.document.nodePrincipal.isSystemPrincipal,
+ "sanity check - loaded about page does not have the system principal"
+ );
+ isnot(
+ content.testResult,
+ "fail-script-was-loaded",
+ "The script from https://example.com shouldn't work in an about: page."
+ );
+ }
+ );
+ }
+ );
+});
diff --git a/dom/security/test/general/browser_same_site_cookies_bug1748693.js b/dom/security/test/general/browser_same_site_cookies_bug1748693.js
new file mode 100644
index 0000000000..da3c3d7762
--- /dev/null
+++ b/dom/security/test/general/browser_same_site_cookies_bug1748693.js
@@ -0,0 +1,51 @@
+"use strict";
+
+const HTTPS_PATH = getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "https://example.com"
+);
+const HTTP_PATH = getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "http://example.com"
+);
+
+function checkCookies(expectedCookies = {}) {
+ info(JSON.stringify(expectedCookies));
+ return SpecialPowers.spawn(
+ gBrowser.selectedBrowser,
+ [expectedCookies],
+ async function (expectedCookies) {
+ let cookies = content.document.getElementById("msg").innerHTML;
+ info(cookies);
+ for (const [cookie, expected] of Object.entries(expectedCookies)) {
+ if (expected) {
+ ok(cookies.includes(cookie), `${cookie} should be sent`);
+ } else {
+ ok(!cookies.includes(cookie), `${cookie} should not be sent`);
+ }
+ }
+ }
+ );
+}
+
+add_task(async function bug1748693() {
+ waitForExplicitFinish();
+
+ let loaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+ BrowserTestUtils.loadURIString(
+ gBrowser,
+ `${HTTPS_PATH}file_same_site_cookies_bug1748693.sjs?setcookies`
+ );
+ await loaded;
+
+ loaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+ BrowserTestUtils.loadURIString(
+ gBrowser,
+ `${HTTP_PATH}file_same_site_cookies_bug1748693.sjs`
+ );
+ await loaded;
+
+ await checkCookies({ auth: true, auth_secure: false });
+
+ finish();
+});
diff --git a/dom/security/test/general/browser_test_assert_systemprincipal_documents.js b/dom/security/test/general/browser_test_assert_systemprincipal_documents.js
new file mode 100644
index 0000000000..8804e85b2c
--- /dev/null
+++ b/dom/security/test/general/browser_test_assert_systemprincipal_documents.js
@@ -0,0 +1,41 @@
+//"use strict"
+
+const kTestPath = getRootDirectory(gTestPath);
+const kTestURI = kTestPath + "file_assert_systemprincipal_documents.html";
+
+add_setup(async function () {
+ // We expect the assertion in function
+ // CheckSystemPrincipalLoads as defined in
+ // file dom/security/nsContentSecurityManager.cpp
+ SimpleTest.expectAssertions(1);
+
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["security.disallow_non_local_systemprincipal_in_tests", true],
+ ["security.allow_unsafe_parent_loads", true],
+ ],
+ });
+});
+
+add_task(async function open_test_iframe_in_tab() {
+ // This looks at the iframe (load type SUBDOCUMENT)
+ await BrowserTestUtils.withNewTab(
+ { gBrowser, url: kTestURI },
+ async browser => {
+ await SpecialPowers.spawn(browser, [], async function () {
+ let outerPrincipal = content.document.nodePrincipal;
+ ok(
+ outerPrincipal.isSystemPrincipal,
+ "Sanity: Using SystemPrincipal for test file on chrome://"
+ );
+ const iframeDoc =
+ content.document.getElementById("testframe").contentDocument;
+ is(
+ iframeDoc.body.innerHTML,
+ "",
+ "iframe with systemprincipal should be empty document"
+ );
+ });
+ }
+ );
+});
diff --git a/dom/security/test/general/browser_test_data_download.js b/dom/security/test/general/browser_test_data_download.js
new file mode 100644
index 0000000000..a74126971f
--- /dev/null
+++ b/dom/security/test/general/browser_test_data_download.js
@@ -0,0 +1,113 @@
+"use strict";
+
+const kTestPath = getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "http://example.com"
+);
+const kTestURI = kTestPath + "file_data_download.html";
+
+function addWindowListener(aURL) {
+ return new Promise(resolve => {
+ Services.wm.addListener({
+ onOpenWindow(aXULWindow) {
+ info("window opened, waiting for focus");
+ Services.wm.removeListener(this);
+ var domwindow = aXULWindow.docShell.domWindow;
+ waitForFocus(function () {
+ is(
+ domwindow.document.location.href,
+ aURL,
+ "should have seen the right window open"
+ );
+ resolve(domwindow);
+ }, domwindow);
+ },
+ onCloseWindow(aXULWindow) {},
+ });
+ });
+}
+
+function waitDelay(delay) {
+ return new Promise((resolve, reject) => {
+ /* eslint-disable mozilla/no-arbitrary-setTimeout */
+ window.setTimeout(resolve, delay);
+ });
+}
+
+function promisePanelOpened() {
+ if (DownloadsPanel.panel && DownloadsPanel.panel.state == "open") {
+ return Promise.resolve();
+ }
+ return BrowserTestUtils.waitForEvent(DownloadsPanel.panel, "popupshown");
+}
+
+add_task(async function test_with_downloads_pref_disabled() {
+ waitForExplicitFinish();
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["security.data_uri.block_toplevel_data_uri_navigations", true],
+ ["browser.download.always_ask_before_handling_new_types", true],
+ ],
+ });
+ let windowPromise = addWindowListener(
+ "chrome://mozapps/content/downloads/unknownContentType.xhtml"
+ );
+ BrowserTestUtils.loadURIString(gBrowser, kTestURI);
+ let win = await windowPromise;
+
+ is(
+ win.document.getElementById("location").value,
+ "data-foo.html",
+ "file name of download should match"
+ );
+
+ let mainWindowActivated = BrowserTestUtils.waitForEvent(window, "activate");
+ await BrowserTestUtils.closeWindow(win);
+ await mainWindowActivated;
+});
+
+add_task(async function test_with_always_ask_pref_disabled() {
+ waitForExplicitFinish();
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["security.data_uri.block_toplevel_data_uri_navigations", true],
+ ["browser.download.always_ask_before_handling_new_types", false],
+ ],
+ });
+ let downloadsPanelPromise = promisePanelOpened();
+ let downloadsPromise = Downloads.getList(Downloads.PUBLIC);
+
+ BrowserTestUtils.loadURIString(gBrowser, kTestURI);
+ // wait until downloadsPanel opens before continuing with test
+ await downloadsPanelPromise;
+ let downloadList = await downloadsPromise;
+
+ is(DownloadsPanel.isPanelShowing, true, "DownloadsPanel should be open.");
+ is(
+ downloadList._downloads.length,
+ 1,
+ "File should be successfully downloaded."
+ );
+
+ let [download] = downloadList._downloads;
+ is(download.contentType, "text/html", "File contentType should be correct.");
+ is(
+ download.source.url,
+ "data:text/html,<body>data download</body>",
+ "File name should be correct."
+ );
+
+ info("cleaning up downloads");
+ try {
+ if (Services.appinfo.OS === "WINNT") {
+ // We need to make the file writable to delete it on Windows.
+ await IOUtils.setPermissions(download.target.path, 0o600);
+ }
+ await IOUtils.remove(download.target.path);
+ } catch (error) {
+ info("The file " + download.target.path + " is not removed, " + error);
+ }
+
+ await downloadList.remove(download);
+ await download.finalize();
+});
diff --git a/dom/security/test/general/browser_test_data_text_csv.js b/dom/security/test/general/browser_test_data_text_csv.js
new file mode 100644
index 0000000000..2c013a0d61
--- /dev/null
+++ b/dom/security/test/general/browser_test_data_text_csv.js
@@ -0,0 +1,108 @@
+"use strict";
+
+const kTestPath = getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "http://example.com"
+);
+const kTestURI = kTestPath + "file_data_text_csv.html";
+
+function addWindowListener(aURL, aCallback) {
+ return new Promise(resolve => {
+ Services.wm.addListener({
+ onOpenWindow(aXULWindow) {
+ info("window opened, waiting for focus");
+ Services.wm.removeListener(this);
+ var domwindow = aXULWindow.docShell.domWindow;
+ waitForFocus(function () {
+ is(
+ domwindow.document.location.href,
+ aURL,
+ "should have seen the right window open"
+ );
+ resolve(domwindow);
+ }, domwindow);
+ },
+ onCloseWindow(aXULWindow) {},
+ });
+ });
+}
+
+function promisePanelOpened() {
+ if (DownloadsPanel.panel && DownloadsPanel.panel.state == "open") {
+ return Promise.resolve();
+ }
+ return BrowserTestUtils.waitForEvent(DownloadsPanel.panel, "popupshown");
+}
+
+add_task(async function test_with_pref_enabled() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["security.data_uri.block_toplevel_data_uri_navigations", true],
+ ["browser.download.always_ask_before_handling_new_types", true],
+ ],
+ });
+
+ let windowPromise = addWindowListener(
+ "chrome://mozapps/content/downloads/unknownContentType.xhtml"
+ );
+ BrowserTestUtils.loadURIString(gBrowser, kTestURI);
+ let win = await windowPromise;
+
+ let expectedValue = "Untitled.csv";
+ is(
+ win.document.getElementById("location").value,
+ expectedValue,
+ "file name of download should match"
+ );
+ let mainWindowActivated = BrowserTestUtils.waitForEvent(window, "activate");
+ await BrowserTestUtils.closeWindow(win);
+ await mainWindowActivated;
+});
+
+add_task(async function test_with_pref_disabled() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["security.data_uri.block_toplevel_data_uri_navigations", true],
+ ["browser.download.always_ask_before_handling_new_types", false],
+ ],
+ });
+ let downloadsPanelPromise = promisePanelOpened();
+ let downloadsPromise = Downloads.getList(Downloads.PUBLIC);
+ let sourceURLBit = "text/csv;foo,bar,foobar";
+
+ info("Loading URI for pref enabled");
+ BrowserTestUtils.loadURIString(gBrowser, kTestURI);
+ info("Waiting for downloads panel to open");
+ await downloadsPanelPromise;
+ info("Getting downloads info after opening downloads panel");
+ let downloadList = await downloadsPromise;
+
+ is(DownloadsPanel.isPanelShowing, true, "DownloadsPanel should be open.");
+ is(
+ downloadList._downloads.length,
+ 1,
+ "File should be successfully downloaded."
+ );
+
+ let [download] = downloadList._downloads;
+ is(download.contentType, "text/csv", "File contentType should be correct.");
+ is(
+ download.source.url,
+ `data:${sourceURLBit}`,
+ "File name should be correct."
+ );
+
+ info("Cleaning up downloads");
+ try {
+ if (Services.appinfo.OS === "WINNT") {
+ // We need to make the file writable to delete it on Windows.
+ await IOUtils.setPermissions(download.target.path, 0o600);
+ }
+ await IOUtils.remove(download.target.path);
+ } catch (ex) {
+ info("The file " + download.target.path + " is not removed, " + ex);
+ }
+
+ await downloadList.remove(download);
+ await download.finalize();
+});
diff --git a/dom/security/test/general/browser_test_framing_error_pages.js b/dom/security/test/general/browser_test_framing_error_pages.js
new file mode 100644
index 0000000000..16e67eb702
--- /dev/null
+++ b/dom/security/test/general/browser_test_framing_error_pages.js
@@ -0,0 +1,53 @@
+"use strict";
+
+const kTestPath = getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "https://example.com"
+);
+const kTestXFrameOptionsURI = kTestPath + "file_framing_error_pages_xfo.html";
+const kTestXFrameOptionsURIFrame =
+ kTestPath + "file_framing_error_pages.sjs?xfo";
+
+const kTestFrameAncestorsURI = kTestPath + "file_framing_error_pages_csp.html";
+const kTestFrameAncestorsURIFrame =
+ kTestPath + "file_framing_error_pages.sjs?csp";
+
+add_task(async function open_test_xfo_error_page() {
+ await BrowserTestUtils.withNewTab("about:blank", async function (browser) {
+ let loaded = BrowserTestUtils.browserLoaded(
+ browser,
+ true,
+ kTestXFrameOptionsURIFrame,
+ true
+ );
+ BrowserTestUtils.loadURIString(browser, kTestXFrameOptionsURI);
+ await loaded;
+
+ await SpecialPowers.spawn(browser, [], async function () {
+ const iframeDoc =
+ content.document.getElementById("testframe").contentDocument;
+ let errorPage = iframeDoc.body.innerHTML;
+ ok(errorPage.includes("csp-xfo-error-title"), "xfo error page correct");
+ });
+ });
+});
+
+add_task(async function open_test_csp_frame_ancestor_error_page() {
+ await BrowserTestUtils.withNewTab("about:blank", async function (browser) {
+ let loaded = BrowserTestUtils.browserLoaded(
+ browser,
+ true,
+ kTestFrameAncestorsURIFrame,
+ true
+ );
+ BrowserTestUtils.loadURIString(browser, kTestFrameAncestorsURI);
+ await loaded;
+
+ await SpecialPowers.spawn(browser, [], async function () {
+ const iframeDoc =
+ content.document.getElementById("testframe").contentDocument;
+ let errorPage = iframeDoc.body.innerHTML;
+ ok(errorPage.includes("csp-xfo-error-title"), "csp error page correct");
+ });
+ });
+});
diff --git a/dom/security/test/general/browser_test_referrer_loadInOtherProcess.js b/dom/security/test/general/browser_test_referrer_loadInOtherProcess.js
new file mode 100644
index 0000000000..7da60b727d
--- /dev/null
+++ b/dom/security/test/general/browser_test_referrer_loadInOtherProcess.js
@@ -0,0 +1,156 @@
+const TEST_PAGE =
+ "https://example.org/browser/browser/base/content/test/general/dummy_page.html";
+const TEST_REFERRER = "http://mochi.test:8888/";
+
+const ReferrerInfo = Components.Constructor(
+ "@mozilla.org/referrer-info;1",
+ "nsIReferrerInfo",
+ "init"
+);
+
+let referrerInfo = new ReferrerInfo(
+ Ci.nsIReferrerInfo.ORIGIN,
+ true,
+ Services.io.newURI(TEST_REFERRER)
+);
+let deReferrerInfo = E10SUtils.serializeReferrerInfo(referrerInfo);
+
+var checkResult = async function (isRemote, browserKey, uri) {
+ is(
+ gBrowser.selectedBrowser.isRemoteBrowser,
+ isRemote,
+ "isRemoteBrowser should be correct"
+ );
+
+ is(
+ gBrowser.selectedBrowser.permanentKey,
+ browserKey,
+ "browser.permanentKey should be correct"
+ );
+
+ if (SpecialPowers.Services.appinfo.sessionHistoryInParent) {
+ let sessionHistory =
+ gBrowser.selectedBrowser.browsingContext.sessionHistory;
+ let entry = sessionHistory.getEntryAtIndex(sessionHistory.count - 1);
+ let args = { uri, referrerInfo: deReferrerInfo, isRemote };
+ Assert.equal(entry.URI.spec, args.uri, "Uri should be correct");
+
+ // Main process like about:mozilla does not trigger the real network request.
+ // So we don't store referrerInfo in sessionHistory in that case.
+ // Besides, the referrerInfo stored in sessionHistory was computed, we only
+ // check pre-computed things.
+ if (args.isRemote) {
+ let resultReferrerInfo = entry.referrerInfo;
+ let expectedReferrerInfo = E10SUtils.deserializeReferrerInfo(
+ args.referrerInfo
+ );
+
+ Assert.equal(
+ resultReferrerInfo.originalReferrer.spec,
+ expectedReferrerInfo.originalReferrer.spec,
+ "originalReferrer should be correct"
+ );
+ Assert.equal(
+ resultReferrerInfo.sendReferrer,
+ expectedReferrerInfo.sendReferrer,
+ "sendReferrer should be correct"
+ );
+ Assert.equal(
+ resultReferrerInfo.referrerPolicy,
+ expectedReferrerInfo.referrerPolicy,
+ "referrerPolicy should be correct"
+ );
+ } else {
+ Assert.equal(entry.referrerInfo, null, "ReferrerInfo should be correct");
+ }
+
+ return;
+ }
+
+ await SpecialPowers.spawn(
+ gBrowser.selectedBrowser,
+ [{ uri, referrerInfo: deReferrerInfo, isRemote }],
+ async function (args) {
+ let webNav = content.docShell.QueryInterface(Ci.nsIWebNavigation);
+ let sessionHistory = webNav.sessionHistory;
+ let entry = sessionHistory.legacySHistory.getEntryAtIndex(
+ sessionHistory.count - 1
+ );
+
+ var { E10SUtils } = SpecialPowers.ChromeUtils.importESModule(
+ "resource://gre/modules/E10SUtils.sys.mjs"
+ );
+
+ Assert.equal(entry.URI.spec, args.uri, "Uri should be correct");
+
+ // Main process like about:mozilla does not trigger the real network request.
+ // So we don't store referrerInfo in sessionHistory in that case.
+ // Besides, the referrerInfo stored in sessionHistory was computed, we only
+ // check pre-computed things.
+ if (args.isRemote) {
+ let resultReferrerInfo = entry.referrerInfo;
+ let expectedReferrerInfo = E10SUtils.deserializeReferrerInfo(
+ args.referrerInfo
+ );
+
+ Assert.equal(
+ resultReferrerInfo.originalReferrer.spec,
+ expectedReferrerInfo.originalReferrer.spec,
+ "originalReferrer should be correct"
+ );
+ Assert.equal(
+ resultReferrerInfo.sendReferrer,
+ expectedReferrerInfo.sendReferrer,
+ "sendReferrer should be correct"
+ );
+ Assert.equal(
+ resultReferrerInfo.referrerPolicy,
+ expectedReferrerInfo.referrerPolicy,
+ "referrerPolicy should be correct"
+ );
+ } else {
+ Assert.equal(
+ entry.referrerInfo,
+ null,
+ "ReferrerInfo should be correct"
+ );
+ }
+ }
+ );
+};
+var waitForLoad = async function (uri) {
+ info("waitForLoad " + uri);
+ let loadURIOptions = {
+ triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
+ referrerInfo,
+ };
+ gBrowser.selectedBrowser.webNavigation.loadURI(
+ Services.io.newURI(uri),
+ loadURIOptions
+ );
+
+ await BrowserTestUtils.browserStopped(gBrowser, uri);
+};
+
+// Tests referrerInfo when navigating from a page in the remote process to main
+// process and vice versa.
+add_task(async function test_navigation() {
+ // Navigate from non remote to remote
+ gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, "about:blank");
+ let testURI = TEST_PAGE;
+ let { permanentKey } = gBrowser.selectedBrowser;
+ await waitForLoad(testURI);
+ await checkResult(true, permanentKey, testURI);
+ gBrowser.removeCurrentTab();
+
+ // Navigate from remote to non-remote
+ gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, TEST_PAGE);
+ // Wait for the non-blank page to finish loading
+ await BrowserTestUtils.browserStopped(gBrowser, TEST_PAGE);
+ testURI = "about:mozilla";
+ permanentKey = gBrowser.selectedBrowser.permanentKey;
+ await waitForLoad(testURI);
+ await checkResult(false, permanentKey, testURI);
+
+ gBrowser.removeCurrentTab();
+});
diff --git a/dom/security/test/general/browser_test_report_blocking.js b/dom/security/test/general/browser_test_report_blocking.js
new file mode 100644
index 0000000000..4937a47c4f
--- /dev/null
+++ b/dom/security/test/general/browser_test_report_blocking.js
@@ -0,0 +1,218 @@
+"use strict";
+
+const { TelemetryArchiveTesting } = ChromeUtils.importESModule(
+ "resource://testing-common/TelemetryArchiveTesting.sys.mjs"
+);
+
+const kTestPath = getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "https://example.com"
+);
+
+const kTestXFrameOptionsURI = kTestPath + "file_framing_error_pages_xfo.html";
+const kTestCspURI = kTestPath + "file_framing_error_pages_csp.html";
+const kTestXFrameOptionsURIFrame =
+ kTestPath + "file_framing_error_pages.sjs?xfo";
+const kTestCspURIFrame = kTestPath + "file_framing_error_pages.sjs?csp";
+
+const kTestExpectedPingXFO = [
+ [["payload", "error_type"], "xfo"],
+ [["payload", "xfo_header"], "deny"],
+ [["payload", "csp_header"], ""],
+ [["payload", "frame_hostname"], "example.com"],
+ [["payload", "top_hostname"], "example.com"],
+ [
+ ["payload", "frame_uri"],
+ "https://example.com/browser/dom/security/test/general/file_framing_error_pages.sjs",
+ ],
+ [
+ ["payload", "top_uri"],
+ "https://example.com/browser/dom/security/test/general/file_framing_error_pages_xfo.html",
+ ],
+];
+
+const kTestExpectedPingCSP = [
+ [["payload", "error_type"], "csp"],
+ [["payload", "xfo_header"], ""],
+ [["payload", "csp_header"], "'none'"],
+ [["payload", "frame_hostname"], "example.com"],
+ [["payload", "top_hostname"], "example.com"],
+ [
+ ["payload", "frame_uri"],
+ "https://example.com/browser/dom/security/test/general/file_framing_error_pages.sjs",
+ ],
+ [
+ ["payload", "top_uri"],
+ "https://example.com/browser/dom/security/test/general/file_framing_error_pages_csp.html",
+ ],
+];
+
+const TEST_CASES = [
+ {
+ type: "xfo",
+ test_uri: kTestXFrameOptionsURI,
+ frame_uri: kTestXFrameOptionsURIFrame,
+ expected_ping: kTestExpectedPingXFO,
+ },
+ {
+ type: "csp",
+ test_uri: kTestCspURI,
+ frame_uri: kTestCspURIFrame,
+ expected_ping: kTestExpectedPingCSP,
+ },
+];
+
+add_setup(async function () {
+ Services.telemetry.setEventRecordingEnabled("security.ui.xfocsperror", true);
+
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["security.xfocsp.errorReporting.enabled", true],
+ ["security.xfocsp.errorReporting.automatic", false],
+ ],
+ });
+});
+
+add_task(async function testReportingCases() {
+ for (const test of TEST_CASES) {
+ await testReporting(test);
+ }
+});
+
+async function testReporting(test) {
+ // Clear telemetry event before testing.
+ Services.telemetry.clearEvents();
+
+ let telemetryChecker = new TelemetryArchiveTesting.Checker();
+ await telemetryChecker.promiseInit();
+
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ "about:blank"
+ );
+ let browser = tab.linkedBrowser;
+
+ let loaded = BrowserTestUtils.browserLoaded(
+ browser,
+ true,
+ test.frame_uri,
+ true
+ );
+ BrowserTestUtils.loadURIString(browser, test.test_uri);
+ await loaded;
+
+ let { type } = test;
+
+ let frameBC = await SpecialPowers.spawn(browser, [], async _ => {
+ const iframe = content.document.getElementById("testframe");
+ return iframe.browsingContext;
+ });
+
+ await SpecialPowers.spawn(frameBC, [type], async obj => {
+ // Wait until the reporting UI is visible.
+ await ContentTaskUtils.waitForCondition(() => {
+ let reportUI = content.document.getElementById("blockingErrorReporting");
+ return ContentTaskUtils.is_visible(reportUI);
+ });
+
+ let reportCheckBox = content.document.getElementById(
+ "automaticallyReportBlockingInFuture"
+ );
+ is(
+ reportCheckBox.checked,
+ false,
+ "The checkbox of the reporting ui should be not checked."
+ );
+
+ // Click on the checkbox.
+ await EventUtils.synthesizeMouseAtCenter(reportCheckBox, {}, content);
+ });
+ BrowserTestUtils.removeTab(tab);
+
+ // Open the error page again
+ tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
+ browser = tab.linkedBrowser;
+
+ loaded = BrowserTestUtils.browserLoaded(browser, true, test.frame_uri, true);
+ BrowserTestUtils.loadURIString(browser, test.test_uri);
+ await loaded;
+
+ frameBC = await SpecialPowers.spawn(browser, [], async _ => {
+ const iframe = content.document.getElementById("testframe");
+ return iframe.browsingContext;
+ });
+
+ await SpecialPowers.spawn(frameBC, [], async _ => {
+ // Wait until the reporting UI is visible.
+ await ContentTaskUtils.waitForCondition(() => {
+ let reportUI = content.document.getElementById("blockingErrorReporting");
+ return ContentTaskUtils.is_visible(reportUI);
+ });
+
+ let reportCheckBox = content.document.getElementById(
+ "automaticallyReportBlockingInFuture"
+ );
+ is(
+ reportCheckBox.checked,
+ true,
+ "The checkbox of the reporting ui should be checked."
+ );
+
+ // Click on the checkbox again to disable the reporting.
+ await EventUtils.synthesizeMouseAtCenter(reportCheckBox, {}, content);
+
+ is(
+ reportCheckBox.checked,
+ false,
+ "The checkbox of the reporting ui should be unchecked."
+ );
+ });
+ BrowserTestUtils.removeTab(tab);
+
+ // Open the error page again to see if the reporting is disabled.
+ tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
+ browser = tab.linkedBrowser;
+
+ loaded = BrowserTestUtils.browserLoaded(browser, true, test.frame_uri, true);
+ BrowserTestUtils.loadURIString(browser, test.test_uri);
+ await loaded;
+
+ frameBC = await SpecialPowers.spawn(browser, [], async _ => {
+ const iframe = content.document.getElementById("testframe");
+ return iframe.browsingContext;
+ });
+
+ await SpecialPowers.spawn(frameBC, [], async _ => {
+ // Wait until the reporting UI is visible.
+ await ContentTaskUtils.waitForCondition(() => {
+ let reportUI = content.document.getElementById("blockingErrorReporting");
+ return ContentTaskUtils.is_visible(reportUI);
+ });
+
+ let reportCheckBox = content.document.getElementById(
+ "automaticallyReportBlockingInFuture"
+ );
+ is(
+ reportCheckBox.checked,
+ false,
+ "The checkbox of the reporting ui should be unchecked."
+ );
+ });
+ BrowserTestUtils.removeTab(tab);
+
+ // Finally, check if the ping has been archived.
+ await new Promise(resolve => {
+ telemetryChecker
+ .promiseFindPing("xfocsp-error-report", test.expected_ping)
+ .then(
+ found => {
+ ok(found, "Telemetry ping submitted successfully");
+ resolve();
+ },
+ err => {
+ ok(false, "Exception finding telemetry ping: " + err);
+ resolve();
+ }
+ );
+ });
+}
diff --git a/dom/security/test/general/browser_test_toplevel_data_navigations.js b/dom/security/test/general/browser_test_toplevel_data_navigations.js
new file mode 100644
index 0000000000..0e006f1fd2
--- /dev/null
+++ b/dom/security/test/general/browser_test_toplevel_data_navigations.js
@@ -0,0 +1,70 @@
+/* eslint-disable mozilla/no-arbitrary-setTimeout */
+
+"use strict";
+
+const kDataBody = "toplevel navigation to data: URI allowed";
+const kDataURI = "data:text/html,<body>" + kDataBody + "</body>";
+const kTestPath = getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "http://example.com"
+);
+const kRedirectURI = kTestPath + "file_toplevel_data_navigations.sjs";
+const kMetaRedirectURI = kTestPath + "file_toplevel_data_meta_redirect.html";
+
+add_task(async function test_nav_data_uri() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["security.data_uri.block_toplevel_data_uri_navigations", true]],
+ });
+ await BrowserTestUtils.withNewTab(kDataURI, async function (browser) {
+ await SpecialPowers.spawn(
+ gBrowser.selectedBrowser,
+ [{ kDataBody }],
+ async function ({ kDataBody }) {
+ // eslint-disable-line
+ is(
+ content.document.body.innerHTML,
+ kDataBody,
+ "data: URI navigation from system should be allowed"
+ );
+ }
+ );
+ });
+});
+
+add_task(async function test_nav_data_uri_redirect() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["security.data_uri.block_toplevel_data_uri_navigations", true]],
+ });
+ let tab = BrowserTestUtils.addTab(gBrowser, kRedirectURI);
+ registerCleanupFunction(async function () {
+ BrowserTestUtils.removeTab(tab);
+ });
+ // wait to make sure data: URI did not load before checking that it got blocked
+ await new Promise(resolve => setTimeout(resolve, 500));
+ await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () {
+ is(
+ content.document.body.innerHTML,
+ "",
+ "data: URI navigation after server redirect should be blocked"
+ );
+ });
+});
+
+add_task(async function test_nav_data_uri_meta_redirect() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["security.data_uri.block_toplevel_data_uri_navigations", true]],
+ });
+ let tab = BrowserTestUtils.addTab(gBrowser, kMetaRedirectURI);
+ registerCleanupFunction(async function () {
+ BrowserTestUtils.removeTab(tab);
+ });
+ // wait to make sure data: URI did not load before checking that it got blocked
+ await new Promise(resolve => setTimeout(resolve, 500));
+ await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () {
+ is(
+ content.document.body.innerHTML,
+ "",
+ "data: URI navigation after meta redirect should be blocked"
+ );
+ });
+});
diff --git a/dom/security/test/general/browser_test_view_image_data_navigation.js b/dom/security/test/general/browser_test_view_image_data_navigation.js
new file mode 100644
index 0000000000..90aace1e3e
--- /dev/null
+++ b/dom/security/test/general/browser_test_view_image_data_navigation.js
@@ -0,0 +1,71 @@
+"use strict";
+
+add_task(async function test_principal_right_click_open_link_in_new_tab() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["security.data_uri.block_toplevel_data_uri_navigations", true]],
+ });
+
+ const TEST_PAGE =
+ getRootDirectory(gTestPath) + "file_view_image_data_navigation.html";
+
+ await BrowserTestUtils.withNewTab(TEST_PAGE, async function (browser) {
+ let loadPromise = BrowserTestUtils.waitForNewTab(gBrowser, null, true);
+
+ // simulate right-click->view-image
+ BrowserTestUtils.waitForEvent(document, "popupshown", false, event => {
+ // These are operations that must be executed synchronously with the event.
+ document.getElementById("context-viewimage").doCommand();
+ event.target.hidePopup();
+ return true;
+ });
+ BrowserTestUtils.synthesizeMouseAtCenter(
+ "#testimage",
+ { type: "contextmenu", button: 2 },
+ gBrowser.selectedBrowser
+ );
+ let tab = await loadPromise;
+
+ let spec = tab.linkedBrowser.currentURI.spec;
+ ok(
+ spec.startsWith("data:image/svg+xml;"),
+ "data:image/svg navigation allowed through right-click view-image"
+ );
+
+ gBrowser.removeTab(tab);
+ });
+});
+
+add_task(async function test_right_click_open_bg_image() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["security.data_uri.block_toplevel_data_uri_navigations", true]],
+ });
+
+ const TEST_PAGE =
+ getRootDirectory(gTestPath) + "file_view_bg_image_data_navigation.html";
+
+ await BrowserTestUtils.withNewTab(TEST_PAGE, async function (browser) {
+ let loadPromise = BrowserTestUtils.waitForNewTab(gBrowser, null, true);
+
+ // simulate right-click->view-image
+ BrowserTestUtils.waitForEvent(document, "popupshown", false, event => {
+ // These are operations that must be executed synchronously with the event.
+ document.getElementById("context-viewimage").doCommand();
+ event.target.hidePopup();
+ return true;
+ });
+ BrowserTestUtils.synthesizeMouseAtCenter(
+ "#testbody",
+ { type: "contextmenu", button: 2 },
+ gBrowser.selectedBrowser
+ );
+ let tab = await loadPromise;
+
+ let spec = tab.linkedBrowser.currentURI.spec;
+ ok(
+ spec.startsWith("data:image/svg+xml;"),
+ "data:image/svg navigation allowed through right-click view-image with background image"
+ );
+
+ gBrowser.removeTab(tab);
+ });
+});
diff --git a/dom/security/test/general/browser_test_xfo_embed_object.js b/dom/security/test/general/browser_test_xfo_embed_object.js
new file mode 100644
index 0000000000..e9aebbe630
--- /dev/null
+++ b/dom/security/test/general/browser_test_xfo_embed_object.js
@@ -0,0 +1,41 @@
+"use strict";
+
+const kTestPath = getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "https://example.com"
+);
+const kTestXFOEmbedURI = kTestPath + "file_framing_xfo_embed.html";
+const kTestXFOObjectURI = kTestPath + "file_framing_xfo_object.html";
+
+const errorMessage = `The loading of “https://example.com/browser/dom/security/test/general/file_framing_xfo_embed_object.sjs” in a frame is denied by “X-Frame-Options“ directive set to “deny“`;
+
+let xfoBlocked = false;
+
+function onXFOMessage(msgObj) {
+ const message = msgObj.message;
+
+ if (message.includes(errorMessage)) {
+ ok(true, "XFO error message logged");
+ xfoBlocked = true;
+ }
+}
+
+add_task(async function open_test_xfo_embed_blocked() {
+ xfoBlocked = false;
+ await BrowserTestUtils.withNewTab("about:blank", async function (browser) {
+ Services.console.registerListener(onXFOMessage);
+ BrowserTestUtils.loadURIString(browser, kTestXFOEmbedURI);
+ await BrowserTestUtils.waitForCondition(() => xfoBlocked);
+ Services.console.unregisterListener(onXFOMessage);
+ });
+});
+
+add_task(async function open_test_xfo_object_blocked() {
+ xfoBlocked = false;
+ await BrowserTestUtils.withNewTab("about:blank", async function (browser) {
+ Services.console.registerListener(onXFOMessage);
+ BrowserTestUtils.loadURIString(browser, kTestXFOObjectURI);
+ await BrowserTestUtils.waitForCondition(() => xfoBlocked);
+ Services.console.unregisterListener(onXFOMessage);
+ });
+});
diff --git a/dom/security/test/general/bug1277803.html b/dom/security/test/general/bug1277803.html
new file mode 100644
index 0000000000..c8033551a0
--- /dev/null
+++ b/dom/security/test/general/bug1277803.html
@@ -0,0 +1,11 @@
+<html>
+
+<head>
+ <link rel='icon' href='favicon_bug1277803.ico'>
+</head>
+
+<body>
+Nothing to see here...
+</body>
+
+</html>
diff --git a/dom/security/test/general/chrome.ini b/dom/security/test/general/chrome.ini
new file mode 100644
index 0000000000..35d7e44d89
--- /dev/null
+++ b/dom/security/test/general/chrome.ini
@@ -0,0 +1,11 @@
+[DEFAULT]
+support-files =
+ favicon_bug1277803.ico
+ bug1277803.html
+
+[test_innerhtml_sanitizer.html]
+[test_innerhtml_sanitizer.xhtml]
+[test_bug1277803.xhtml]
+skip-if = os == 'android'
+ verify
+
diff --git a/dom/security/test/general/closeWindow.sjs b/dom/security/test/general/closeWindow.sjs
new file mode 100644
index 0000000000..996db36f6f
--- /dev/null
+++ b/dom/security/test/general/closeWindow.sjs
@@ -0,0 +1,24 @@
+const BODY = `
+ <script>
+ opener.postMessage("ok!", "*");
+ close();
+ </script>`;
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ if (request.queryString.includes("unset")) {
+ response.setHeader("Set-Cookie", "test=wow", true);
+ }
+
+ if (request.queryString.includes("none")) {
+ response.setHeader("Set-Cookie", "test2=wow2; samesite=none", true);
+ }
+
+ if (request.queryString.includes("lax")) {
+ response.setHeader("Set-Cookie", "test3=wow3; samesite=lax", true);
+ }
+
+ response.write(BODY);
+}
diff --git a/dom/security/test/general/favicon_bug1277803.ico b/dom/security/test/general/favicon_bug1277803.ico
new file mode 100644
index 0000000000..d44438903b
--- /dev/null
+++ b/dom/security/test/general/favicon_bug1277803.ico
Binary files differ
diff --git a/dom/security/test/general/file_1767581.js b/dom/security/test/general/file_1767581.js
new file mode 100644
index 0000000000..259435b1e4
--- /dev/null
+++ b/dom/security/test/general/file_1767581.js
@@ -0,0 +1 @@
+window.testResult = "fail-script-was-loaded";
diff --git a/dom/security/test/general/file_about_child.html b/dom/security/test/general/file_about_child.html
new file mode 100644
index 0000000000..d83e0e4d41
--- /dev/null
+++ b/dom/security/test/general/file_about_child.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1767581</title>
+ <script id="script" src="https://example.com/browser/dom/security/test/general/file_1767581.js"></script>
+</head>
+<body>
+ Just an about page that loads in the privileged about process!
+</body>
+</html> \ No newline at end of file
diff --git a/dom/security/test/general/file_assert_systemprincipal_documents.html b/dom/security/test/general/file_assert_systemprincipal_documents.html
new file mode 100644
index 0000000000..2d7ff4d253
--- /dev/null
+++ b/dom/security/test/general/file_assert_systemprincipal_documents.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1543579: Block web documents loading into system land </title>
+</head>
+<body>
+<h1>This page loads documents from the SystemPrincipal (which should be blocked)</h1>
+<iframe type="chrome" id="testframe" src="http://example.com/browser/dom/security/test/general/file_assert_systemprincipal_documents_iframe.html"></iframe>
+</body>
+</html>
+
diff --git a/dom/security/test/general/file_assert_systemprincipal_documents_iframe.html b/dom/security/test/general/file_assert_systemprincipal_documents_iframe.html
new file mode 100644
index 0000000000..704625a1da
--- /dev/null
+++ b/dom/security/test/general/file_assert_systemprincipal_documents_iframe.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1543579: Block web documents loading into system land </title>
+</head>
+<body>
+<h1>This is the iframe that should not load.</h1>
+</body>
+</html>
diff --git a/dom/security/test/general/file_block_script_wrong_mime_server.sjs b/dom/security/test/general/file_block_script_wrong_mime_server.sjs
new file mode 100644
index 0000000000..0025bbfbe8
--- /dev/null
+++ b/dom/security/test/general/file_block_script_wrong_mime_server.sjs
@@ -0,0 +1,38 @@
+// Custom *.sjs specifically for the needs of:
+// Bug 1288361 - Block scripts with wrong MIME type
+
+"use strict";
+Cu.importGlobalProperties(["URLSearchParams"]);
+
+const WORKER = `
+ onmessage = function(event) {
+ postMessage("worker-loaded");
+ };`;
+
+function handleRequest(request, response) {
+ const query = new URLSearchParams(request.queryString);
+
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ // Set MIME type
+ response.setHeader("Content-Type", query.get("mime"), false);
+
+ // Deliver response
+ switch (query.get("type")) {
+ case "script":
+ response.write("");
+ break;
+ case "worker":
+ response.write(WORKER);
+ break;
+ case "worker-import":
+ response.write(
+ `importScripts("file_block_script_wrong_mime_server.sjs?type=script&mime=${query.get(
+ "mime"
+ )}");`
+ );
+ response.write(WORKER);
+ break;
+ }
+}
diff --git a/dom/security/test/general/file_block_subresource_redir_to_data.sjs b/dom/security/test/general/file_block_subresource_redir_to_data.sjs
new file mode 100644
index 0000000000..1e312bc810
--- /dev/null
+++ b/dom/security/test/general/file_block_subresource_redir_to_data.sjs
@@ -0,0 +1,33 @@
+"use strict";
+
+let SCRIPT_DATA = "alert('this alert should be blocked');";
+let WORKER_DATA =
+ "onmessage = function(event) { postMessage('worker-loaded'); }";
+
+function handleRequest(request, response) {
+ const query = request.queryString;
+
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setStatusLine("1.1", 302, "Found");
+
+ if (query === "script" || query === "modulescript") {
+ response.setHeader(
+ "Location",
+ "data:text/javascript," + escape(SCRIPT_DATA),
+ false
+ );
+ return;
+ }
+
+ if (query === "worker") {
+ response.setHeader(
+ "Location",
+ "data:text/javascript," + escape(WORKER_DATA),
+ false
+ );
+ return;
+ }
+
+ // we should never get here; just in case return something unexpected
+ response.write("do'h");
+}
diff --git a/dom/security/test/general/file_block_toplevel_data_navigation.html b/dom/security/test/general/file_block_toplevel_data_navigation.html
new file mode 100644
index 0000000000..d6e083a247
--- /dev/null
+++ b/dom/security/test/general/file_block_toplevel_data_navigation.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Toplevel data navigation</title>
+</head>
+<body>
+test1: clicking data: URI tries to navigate window<br/>
+<!-- postMessage will not be sent if data: URI is blocked -->
+<a id="testlink" href="data:text/html,<body>toplevel data: URI navigations
+should be blocked</body>">click me</a>
+<script>
+ document.getElementById('testlink').click();
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/file_block_toplevel_data_navigation2.html b/dom/security/test/general/file_block_toplevel_data_navigation2.html
new file mode 100644
index 0000000000..957189ce07
--- /dev/null
+++ b/dom/security/test/general/file_block_toplevel_data_navigation2.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Toplevel data navigation</title>
+</head>
+<body>
+test2: data: URI in iframe tries to window.open(data:, _blank);<br/>
+<iframe id="testFrame" src=""></iframe>
+<script>
+ let DATA_URI = `data:text/html,<body><script>
+ var win = window.open("data:text/html,<body>toplevel data: URI navigations should be blocked</body>", "_blank");
+ <\/script></body>`;
+ document.getElementById('testFrame').src = DATA_URI;
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/file_block_toplevel_data_navigation3.html b/dom/security/test/general/file_block_toplevel_data_navigation3.html
new file mode 100644
index 0000000000..3743a72034
--- /dev/null
+++ b/dom/security/test/general/file_block_toplevel_data_navigation3.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Toplevel data navigation</title>
+</head>
+<body>
+test3: performing data: URI navigation through win.loc.href<br/>
+<script>
+ // postMessage will not be sent if data: URI is blocked
+ window.location.href = "data:text/html,<body><script>" +
+ "window.opener.postMessage('test3','*');<\/script>toplevel data: URI " +
+ "navigations should be blocked</body>";
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/file_block_toplevel_data_redirect.sjs b/dom/security/test/general/file_block_toplevel_data_redirect.sjs
new file mode 100644
index 0000000000..c03ace5f23
--- /dev/null
+++ b/dom/security/test/general/file_block_toplevel_data_redirect.sjs
@@ -0,0 +1,13 @@
+// Custom *.sjs file specifically for the needs of Bug:
+// Bug 1394554 - Block toplevel data: URI navigations after redirect
+
+var DATA_URI =
+ "<body>toplevel data: URI navigations after redirect should be blocked</body>";
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", "data:text/html," + escape(DATA_URI), false);
+}
diff --git a/dom/security/test/general/file_cache_splitting_isloaded.sjs b/dom/security/test/general/file_cache_splitting_isloaded.sjs
new file mode 100644
index 0000000000..a40b9674e5
--- /dev/null
+++ b/dom/security/test/general/file_cache_splitting_isloaded.sjs
@@ -0,0 +1,35 @@
+/*
+ Helper Server -
+ Send a Request with ?queryResult - response will be the
+ queryString of the next request.
+
+*/
+// small red image
+const IMG_BYTES = atob(
+ "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" +
+ "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
+);
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ // save the object state of the initial request, which returns
+ // async once the server has processed the img request.
+ if (request.queryString.includes("wait")) {
+ response.processAsync();
+ setObjectState("wait", response);
+ return;
+ }
+
+ response.write(IMG_BYTES);
+
+ // return the result
+ getObjectState("wait", function (queryResponse) {
+ if (!queryResponse) {
+ return;
+ }
+ queryResponse.write("1");
+ queryResponse.finish();
+ });
+}
diff --git a/dom/security/test/general/file_cache_splitting_server.sjs b/dom/security/test/general/file_cache_splitting_server.sjs
new file mode 100644
index 0000000000..da75986f74
--- /dev/null
+++ b/dom/security/test/general/file_cache_splitting_server.sjs
@@ -0,0 +1,27 @@
+function handleRequest(request, response) {
+ var receivedRequests = parseInt(getState("requests"));
+ if (isNaN(receivedRequests)) {
+ receivedRequests = 0;
+ }
+ if (request.queryString.includes("state")) {
+ response.write(receivedRequests);
+ return;
+ }
+ if (request.queryString.includes("flush")) {
+ setState("requests", "0");
+ response.write("OK");
+ return;
+ }
+ response.setHeader("Cache-Control", "max-age=999999"); // Force caching
+ response.setHeader("Content-Type", "text/css");
+ receivedRequests = receivedRequests + 1;
+ setState("requests", "" + receivedRequests);
+ response.write(`
+ .test{
+ color:red;
+ }
+ .test h1{
+ font-size:200px;
+ }
+ `);
+}
diff --git a/dom/security/test/general/file_cache_splitting_window.html b/dom/security/test/general/file_cache_splitting_window.html
new file mode 100644
index 0000000000..59a2ff2ca9
--- /dev/null
+++ b/dom/security/test/general/file_cache_splitting_window.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>Document</title>
+ <link rel="stylesheet" href="https://example.com/tests/dom/security/test/general/file_cache_splitting_server.sjs">
+</head>
+<body>
+ <h1>HELLO WORLD!</h1>
+
+ <script>
+ window.addEventListener("load",()=>{
+ fetch("file_cache_splitting_isloaded.sjs");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/security/test/general/file_contentpolicytype_targeted_link_iframe.sjs b/dom/security/test/general/file_contentpolicytype_targeted_link_iframe.sjs
new file mode 100644
index 0000000000..9ee73ae3c4
--- /dev/null
+++ b/dom/security/test/general/file_contentpolicytype_targeted_link_iframe.sjs
@@ -0,0 +1,45 @@
+// custom *.sjs for Bug 1255240
+
+const TEST_FRAME = `
+ <!DOCTYPE HTML>
+ <html>
+ <head><meta charset='utf-8'></head>
+ <body>
+ <a id='testlink' target='innerframe' href='file_contentpolicytype_targeted_link_iframe.sjs?innerframe'>click me</a>
+ <iframe name='innerframe'></iframe>
+ <script type='text/javascript'>
+ var link = document.getElementById('testlink');
+ testlink.click();
+ </script>
+ </body>
+ </html> `;
+
+const INNER_FRAME = `
+ <!DOCTYPE HTML>
+ <html>
+ <head><meta charset='utf-8'></head>
+ hello world!
+ </body>
+ </html>`;
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/html", false);
+
+ var queryString = request.queryString;
+
+ if (queryString === "testframe") {
+ response.write(TEST_FRAME);
+ return;
+ }
+
+ if (queryString === "innerframe") {
+ response.write(INNER_FRAME);
+ return;
+ }
+
+ // we should never get here, but just in case
+ // return something unexpected
+ response.write("do'h");
+}
diff --git a/dom/security/test/general/file_data_download.html b/dom/security/test/general/file_data_download.html
new file mode 100644
index 0000000000..4cc92fe8f5
--- /dev/null
+++ b/dom/security/test/general/file_data_download.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test download attribute for data: URI</title>
+</head>
+<body>
+ <a href="data:text/html,<body>data download</body>" download="data-foo.html" id="testlink">download data</a>
+ <script>
+ // click the link to have the downoad panel appear
+ let testlink = document.getElementById("testlink");
+ testlink.click();
+ </script>
+ </body>
+</html>
diff --git a/dom/security/test/general/file_data_text_csv.html b/dom/security/test/general/file_data_text_csv.html
new file mode 100644
index 0000000000..a9ac369d16
--- /dev/null
+++ b/dom/security/test/general/file_data_text_csv.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test open data:text/csv</title>
+</head>
+<body>
+ <a href="data:text/csv;foo,bar,foobar" id="testlink">test text/csv</a>
+ <script>
+ // click the link to have the downoad panel appear
+ let testlink = document.getElementById("testlink");
+ testlink.click();
+ </script>
+ </body>
+</html>
diff --git a/dom/security/test/general/file_framing_error_pages.sjs b/dom/security/test/general/file_framing_error_pages.sjs
new file mode 100644
index 0000000000..fb62a34bdb
--- /dev/null
+++ b/dom/security/test/general/file_framing_error_pages.sjs
@@ -0,0 +1,27 @@
+"use strict";
+
+function handleRequest(request, response) {
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/html", false);
+
+ let query = request.queryString;
+ if (query === "xfo") {
+ response.setHeader("x-frame-options", "deny", false);
+ response.write("<html>xfo test loaded</html>");
+ return;
+ }
+
+ if (query === "csp") {
+ response.setHeader(
+ "content-security-policy",
+ "frame-ancestors 'none'",
+ false
+ );
+ response.write("<html>csp test loaded</html>");
+ return;
+ }
+
+ // we should never get here, but just in case
+ // return something unexpected
+ response.write("do'h");
+}
diff --git a/dom/security/test/general/file_framing_error_pages_csp.html b/dom/security/test/general/file_framing_error_pages_csp.html
new file mode 100644
index 0000000000..2764ed4aa6
--- /dev/null
+++ b/dom/security/test/general/file_framing_error_pages_csp.html
@@ -0,0 +1,7 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+iframe should be blocked <br/>
+<iframe id="testframe" src="https://example.com/browser/dom/security/test/general/file_framing_error_pages.sjs?csp" height=800 width=800></iframe>
+</body>
+</html>
diff --git a/dom/security/test/general/file_framing_error_pages_xfo.html b/dom/security/test/general/file_framing_error_pages_xfo.html
new file mode 100644
index 0000000000..82dd1ee459
--- /dev/null
+++ b/dom/security/test/general/file_framing_error_pages_xfo.html
@@ -0,0 +1,7 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+iframe should be blocked <br/>
+<iframe id="testframe" src="https://example.com/browser/dom/security/test/general/file_framing_error_pages.sjs?xfo" height=800 width=800></iframe>
+</body>
+</html>
diff --git a/dom/security/test/general/file_framing_xfo_embed.html b/dom/security/test/general/file_framing_xfo_embed.html
new file mode 100644
index 0000000000..f5cc761b5b
--- /dev/null
+++ b/dom/security/test/general/file_framing_xfo_embed.html
@@ -0,0 +1,7 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+ embed should be blocked <br/>
+ <embed src="https://example.com/browser/dom/security/test/general/file_framing_xfo_embed_object.sjs"></embed>
+</body>
+</html>
diff --git a/dom/security/test/general/file_framing_xfo_embed_object.sjs b/dom/security/test/general/file_framing_xfo_embed_object.sjs
new file mode 100644
index 0000000000..56616b7930
--- /dev/null
+++ b/dom/security/test/general/file_framing_xfo_embed_object.sjs
@@ -0,0 +1,7 @@
+"use strict";
+
+function handleRequest(request, response) {
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("x-frame-options", "deny", false);
+ response.write("<html>doc with x-frame-options: deny</html>");
+}
diff --git a/dom/security/test/general/file_framing_xfo_object.html b/dom/security/test/general/file_framing_xfo_object.html
new file mode 100644
index 0000000000..c8480a2c42
--- /dev/null
+++ b/dom/security/test/general/file_framing_xfo_object.html
@@ -0,0 +1,7 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+ object should be blocked <br/>
+ <object data="https://example.com/browser/dom/security/test/general/file_framing_xfo_embed_object.sjs"></object>
+</body>
+</html>
diff --git a/dom/security/test/general/file_gpc_server.sjs b/dom/security/test/general/file_gpc_server.sjs
new file mode 100644
index 0000000000..d0b14215b4
--- /dev/null
+++ b/dom/security/test/general/file_gpc_server.sjs
@@ -0,0 +1,14 @@
+"use strict";
+
+function handleRequest(request, response) {
+ response.setHeader("Content-Type", "text/html", false);
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ var gpc = request.hasHeader("Sec-GPC") ? request.getHeader("Sec-GPC") : "";
+
+ if (gpc === "1") {
+ response.write("true");
+ } else {
+ response.write("false");
+ }
+}
diff --git a/dom/security/test/general/file_loads_nonscript.html b/dom/security/test/general/file_loads_nonscript.html
new file mode 100644
index 0000000000..f7692b8066
--- /dev/null
+++ b/dom/security/test/general/file_loads_nonscript.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>File that loads a non-script file-extension as script</title>
+</head>
+<body>
+ <script>
+ /* global equal */
+
+ const files = ["file_nonscript",
+ "file_nonscript.xyz",
+ "file_nonscript.html",
+ "file_nonscript.txt",
+ "file_nonscript.json"];
+
+ async function run() {
+ window.counter = 0;
+
+ for (let file of files) {
+ let script = document.createElement("script");
+ let promise = new Promise((resolve, reject) => {
+ script.addEventListener("error", resolve, {once: true});
+ script.addEventListener("load", reject, {once: true});
+ });
+ script.src = file;
+ document.body.append(script);
+
+ let event = await promise;
+ equal(event.type, "error");
+ equal(window.counter, 0);
+ }
+
+ let script = document.createElement("script");
+ let promise = new Promise((resolve, reject) => {
+ script.addEventListener("load", resolve, {once: true});
+ script.addEventListener("error", reject, {once: true});
+ });
+ script.src = "file_script.js";
+ document.body.append(script);
+
+ let event = await promise;
+ equal(event.type, "load");
+ equal(window.counter, 1);
+
+ window.postMessage("done", "*");
+ }
+ window.addEventListener("message", run, {once: true})
+ </script>
+</html>
diff --git a/dom/security/test/general/file_meta_referrer_in_head.html b/dom/security/test/general/file_meta_referrer_in_head.html
new file mode 100644
index 0000000000..9c4c4cd695
--- /dev/null
+++ b/dom/security/test/general/file_meta_referrer_in_head.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="utf-8">
+<meta name="referrer" content="no-referrer" />
+<title>Bug 1704473 - Remove head requirement for meta name=referrer</title>
+<script type="application/javascript">
+ fetch("https://example.com");
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/dom/security/test/general/file_meta_referrer_notin_head.html b/dom/security/test/general/file_meta_referrer_notin_head.html
new file mode 100644
index 0000000000..55bd38e4c5
--- /dev/null
+++ b/dom/security/test/general/file_meta_referrer_notin_head.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Bug 1704473 - Remove head requirement for meta name=referrer</title>
+
+</head>
+<body>
+ <meta name="referrer" content="no-referrer" />
+ <script type="application/javascript">
+ fetch("https://example.com");
+ </script>
+</body>
+</html>
diff --git a/dom/security/test/general/file_nonscript b/dom/security/test/general/file_nonscript
new file mode 100644
index 0000000000..c339e45d5d
--- /dev/null
+++ b/dom/security/test/general/file_nonscript
@@ -0,0 +1 @@
+window.counter++;
diff --git a/dom/security/test/general/file_nonscript.html b/dom/security/test/general/file_nonscript.html
new file mode 100644
index 0000000000..c339e45d5d
--- /dev/null
+++ b/dom/security/test/general/file_nonscript.html
@@ -0,0 +1 @@
+window.counter++;
diff --git a/dom/security/test/general/file_nonscript.json b/dom/security/test/general/file_nonscript.json
new file mode 100644
index 0000000000..c339e45d5d
--- /dev/null
+++ b/dom/security/test/general/file_nonscript.json
@@ -0,0 +1 @@
+window.counter++;
diff --git a/dom/security/test/general/file_nonscript.txt b/dom/security/test/general/file_nonscript.txt
new file mode 100644
index 0000000000..c339e45d5d
--- /dev/null
+++ b/dom/security/test/general/file_nonscript.txt
@@ -0,0 +1 @@
+window.counter++;
diff --git a/dom/security/test/general/file_nonscript.xyz b/dom/security/test/general/file_nonscript.xyz
new file mode 100644
index 0000000000..c339e45d5d
--- /dev/null
+++ b/dom/security/test/general/file_nonscript.xyz
@@ -0,0 +1 @@
+window.counter++;
diff --git a/dom/security/test/general/file_nosniff_navigation.sjs b/dom/security/test/general/file_nosniff_navigation.sjs
new file mode 100644
index 0000000000..20363ceb76
--- /dev/null
+++ b/dom/security/test/general/file_nosniff_navigation.sjs
@@ -0,0 +1,40 @@
+// Custom *.sjs file specifically for the needs of Bug 1286861
+
+// small red image
+const IMG = atob(
+ "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" +
+ "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
+);
+
+// https://stackoverflow.com/questions/17279712/what-is-the-smallest-possible-valid-pdf
+const PDF = `%PDF-1.0
+1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj 2 0 obj<</Type/Pages/Kids[3 0 R]/Count 1>>endobj 3 0 obj<</Type/Page/MediaBox[0 0 3 3]>>endobj
+trailer<</Size 4/Root 1 0 R>>`;
+
+function getSniffableContent(type) {
+ switch (type) {
+ case "xml":
+ return `<?xml version="1.0"?><test/>`;
+ case "html":
+ return `<!Doctype html> <html> <head></head> <body> Test test </body></html>`;
+ case "css":
+ return `*{ color: pink !important; }`;
+ case "json":
+ return `{ 'test':'yes' }`;
+ case "img":
+ return IMG;
+ case "pdf":
+ return PDF;
+ }
+ return "Basic UTF-8 Text";
+}
+
+function handleRequest(request, response) {
+ Cu.importGlobalProperties(["URLSearchParams"]);
+ let query = new URLSearchParams(request.queryString);
+
+ // avoid confusing cache behaviors (XXXX no sure what this means?)
+ response.setHeader("X-Content-Type-Options", "nosniff"); // Disable Sniffing
+ response.setHeader("Content-Type", query.get("mime"));
+ response.write(getSniffableContent(query.get("content")));
+}
diff --git a/dom/security/test/general/file_nosniff_testserver.sjs b/dom/security/test/general/file_nosniff_testserver.sjs
new file mode 100644
index 0000000000..fd35d8ad4f
--- /dev/null
+++ b/dom/security/test/general/file_nosniff_testserver.sjs
@@ -0,0 +1,61 @@
+"use strict";
+Cu.importGlobalProperties(["URLSearchParams"]);
+
+const SCRIPT = "var foo = 24;";
+const CSS = "body { background-color: green; }";
+
+// small red image
+const IMG = atob(
+ "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" +
+ "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
+);
+
+function handleRequest(request, response) {
+ const query = new URLSearchParams(request.queryString);
+
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ // set the nosniff header
+ response.setHeader("X-Content-Type-Options", " NoSniFF , foo ", false);
+
+ if (query.has("cssCorrectType")) {
+ response.setHeader("Content-Type", "teXt/cSs", false);
+ response.write(CSS);
+ return;
+ }
+
+ if (query.has("cssWrongType")) {
+ response.setHeader("Content-Type", "text/html", false);
+ response.write(CSS);
+ return;
+ }
+
+ if (query.has("scriptCorrectType")) {
+ response.setHeader("Content-Type", "appLIcation/jAvaScriPt;blah", false);
+ response.write(SCRIPT);
+ return;
+ }
+
+ if (query.has("scriptWrongType")) {
+ response.setHeader("Content-Type", "text/html", false);
+ response.write(SCRIPT);
+ return;
+ }
+
+ if (query.has("imgCorrectType")) {
+ response.setHeader("Content-Type", "iMaGe/pnG;blah", false);
+ response.write(IMG);
+ return;
+ }
+
+ if (query.has("imgWrongType")) {
+ response.setHeader("Content-Type", "text/html", false);
+ response.write(IMG);
+ return;
+ }
+
+ // we should never get here, but just in case
+ response.setHeader("Content-Type", "text/html", false);
+ response.write("do'h");
+}
diff --git a/dom/security/test/general/file_same_site_cookies_about.sjs b/dom/security/test/general/file_same_site_cookies_about.sjs
new file mode 100644
index 0000000000..421eb999be
--- /dev/null
+++ b/dom/security/test/general/file_same_site_cookies_about.sjs
@@ -0,0 +1,99 @@
+// Custom *.sjs file specifically for the needs of Bug 1454721
+
+// small red image
+const IMG_BYTES = atob(
+ "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" +
+ "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
+);
+
+const IFRAME_INC = `<iframe src='http://mochi.test:8888/tests/dom/security/test/general/file_same_site_cookies_about.sjs?inclusion'></iframe>`;
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ // using startsWith and discard the math random
+ if (request.queryString.startsWith("setSameSiteCookie")) {
+ response.setHeader(
+ "Set-Cookie",
+ "myKey=mySameSiteAboutCookie; samesite=strict",
+ true
+ );
+ response.setHeader("Content-Type", "image/png");
+ response.write(IMG_BYTES);
+ return;
+ }
+
+ // navigation tests
+ if (request.queryString.includes("loadsrcdocframeNav")) {
+ let FRAME = `
+ <iframe srcdoc="foo"
+ onload="document.location='http://mochi.test:8888/tests/dom/security/test/general/file_same_site_cookies_about.sjs?navigation'">
+ </iframe>`;
+ response.write(FRAME);
+ return;
+ }
+
+ if (request.queryString.includes("loadblankframeNav")) {
+ let FRAME = `
+ <iframe src="about:blank"
+ onload="document.location='http://mochi.test:8888/tests/dom/security/test/general/file_same_site_cookies_about.sjs?navigation'">
+ </iframe>`;
+ response.write(FRAME);
+ return;
+ }
+
+ // inclusion tets
+ if (request.queryString.includes("loadsrcdocframeInc")) {
+ response.write('<iframe srcdoc="' + IFRAME_INC + '"></iframe>');
+ return;
+ }
+
+ if (request.queryString.includes("loadblankframeInc")) {
+ let FRAME =
+ `
+ <iframe id="blankframe" src="about:blank"></iframe>
+ <script>
+ document.getElementById("blankframe").contentDocument.write(\"` +
+ IFRAME_INC +
+ `\");
+ <\/script>`;
+ response.write(FRAME);
+ return;
+ }
+
+ if (request.queryString.includes("navigation")) {
+ const cookies = request.hasHeader("Cookie")
+ ? request.getHeader("Cookie")
+ : "";
+ response.write(`
+ <!DOCTYPE html>
+ <html>
+ <body>
+ <script type="application/javascript">
+ window.parent.postMessage({result: "${cookies}" }, '*');
+ </script>
+ </body>
+ </html>
+ `);
+ }
+
+ if (request.queryString.includes("inclusion")) {
+ const cookies = request.hasHeader("Cookie")
+ ? request.getHeader("Cookie")
+ : "";
+ response.write(`
+ <!DOCTYPE html>
+ <html>
+ <body>
+ <script type="application/javascript">
+ window.parent.parent.parent.postMessage({result: "${cookies}" }, '*');
+ </script>
+ </body>
+ </html>
+ `);
+ }
+
+ // we should never get here, but just in case return something unexpected
+ response.write("D'oh");
+}
diff --git a/dom/security/test/general/file_same_site_cookies_blob_iframe_inclusion.html b/dom/security/test/general/file_same_site_cookies_blob_iframe_inclusion.html
new file mode 100644
index 0000000000..b3456f0b90
--- /dev/null
+++ b/dom/security/test/general/file_same_site_cookies_blob_iframe_inclusion.html
@@ -0,0 +1,34 @@
+<html>
+<body>
+<iframe id="testframe"></iframe>
+<script type="application/javascript">
+
+ // simply passing on the message from the child to parent
+ window.addEventListener("message", receiveMessage);
+ function receiveMessage(event) {
+ window.removeEventListener("message", receiveMessage);
+ window.parent.postMessage({result: event.data.result}, '*');
+ }
+
+ const NESTED_IFRAME_INCLUSION = `
+ <html>
+ <body>
+ <script type="application/javascript">
+ window.addEventListener("message", receiveMessage);
+ function receiveMessage(event) {
+ window.removeEventListener("message", receiveMessage);
+ window.parent.postMessage({result: event.data.result}, '*');
+ }
+ <\/script>
+ <iframe src="http://mochi.test:8888/tests/dom/security/test/general/file_same_site_cookies_iframe.sjs"></iframe>
+ </body>
+ </html>`;
+
+ let NESTED_BLOB_IFRAME_INCLUSION = new Blob([NESTED_IFRAME_INCLUSION], {type:'text/html'});
+
+ // query the testframe and set blob URL
+ let testframe = document.getElementById("testframe");
+ testframe.src = window.URL.createObjectURL(NESTED_BLOB_IFRAME_INCLUSION);
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/file_same_site_cookies_blob_iframe_navigation.html b/dom/security/test/general/file_same_site_cookies_blob_iframe_navigation.html
new file mode 100644
index 0000000000..815c6a6bfc
--- /dev/null
+++ b/dom/security/test/general/file_same_site_cookies_blob_iframe_navigation.html
@@ -0,0 +1,30 @@
+<html>
+<body>
+<iframe id="testframe"></iframe>
+<script type="application/javascript">
+
+ // simply passing on the message from the child to parent
+ window.addEventListener("message", receiveMessage);
+ function receiveMessage(event) {
+ window.removeEventListener("message", receiveMessage);
+ window.parent.postMessage({result: event.data.result}, '*');
+ }
+
+ const NESTED_IFRAME_NAVIGATION = `
+ <html>
+ <body>
+ <a id="testlink" href="http://mochi.test:8888/tests/dom/security/test/general/file_same_site_cookies_iframe.sjs"></a>
+ <script type="application/javascript">
+ let link = document.getElementById("testlink");
+ link.click();
+ <\/script>
+ </body>
+ </html>`;
+ let NESTED_BLOB_IFRAME_NAVIGATION = new Blob([NESTED_IFRAME_NAVIGATION], {type:'text/html'});
+
+ // query the testframe and set blob URL
+ let testframe = document.getElementById("testframe");
+ testframe.src = window.URL.createObjectURL(NESTED_BLOB_IFRAME_NAVIGATION);
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/file_same_site_cookies_bug1748693.sjs b/dom/security/test/general/file_same_site_cookies_bug1748693.sjs
new file mode 100644
index 0000000000..6890bafa17
--- /dev/null
+++ b/dom/security/test/general/file_same_site_cookies_bug1748693.sjs
@@ -0,0 +1,31 @@
+const MESSAGE_PAGE = function (msg) {
+ return `
+<!DOCTYPE html>
+<html>
+ <body>
+ <p id="msg">${msg}</p>
+ <body>
+</html>
+`;
+};
+
+function handleRequest(request, response) {
+ response.setHeader("Cache-Control", "no-store");
+ response.setHeader("Content-Type", "text/html");
+
+ if (request.queryString.includes("setcookies")) {
+ response.setHeader(
+ "Set-Cookie",
+ "auth_secure=foo; SameSite=None; HttpOnly; Secure",
+ true
+ );
+ response.setHeader("Set-Cookie", "auth=foo; HttpOnly;", true);
+ response.write(MESSAGE_PAGE(request.queryString));
+ return;
+ }
+
+ const cookies = request.hasHeader("Cookie")
+ ? request.getHeader("Cookie")
+ : "";
+ response.write(MESSAGE_PAGE(cookies));
+}
diff --git a/dom/security/test/general/file_same_site_cookies_cross_origin_context.sjs b/dom/security/test/general/file_same_site_cookies_cross_origin_context.sjs
new file mode 100644
index 0000000000..9103941653
--- /dev/null
+++ b/dom/security/test/general/file_same_site_cookies_cross_origin_context.sjs
@@ -0,0 +1,54 @@
+// Custom *.sjs file specifically for the needs of Bug 1452496
+
+// small red image
+const IMG_BYTES = atob(
+ "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" +
+ "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
+);
+
+const FRAME = `
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <title>Bug 1452496 - Do not allow same-site cookies in cross site context</title>
+ </head>
+ <body>
+ <script type="application/javascript">
+ let cookie = document.cookie;
+ // now reset the cookie for the next test
+ document.cookie = "myKey=;" + "expires=Thu, 01 Jan 1970 00:00:00 GMT";
+ window.parent.postMessage({result: cookie}, 'http://mochi.test:8888');
+ </script>
+ </body>
+ </html>`;
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ if (request.queryString.includes("setSameSiteCookie")) {
+ response.setHeader(
+ "Set-Cookie",
+ "myKey=strictSameSiteCookie; samesite=strict",
+ true
+ );
+ response.setHeader("Content-Type", "image/png");
+ response.write(IMG_BYTES);
+ return;
+ }
+
+ if (request.queryString.includes("setRegularCookie")) {
+ response.setHeader("Set-Cookie", "myKey=regularCookie;", true);
+ response.setHeader("Content-Type", "image/png");
+ response.write(IMG_BYTES);
+ return;
+ }
+
+ if (request.queryString.includes("loadFrame")) {
+ response.write(FRAME);
+ return;
+ }
+
+ // we should never get here, but just in case return something unexpected
+ response.write("D'oh");
+}
diff --git a/dom/security/test/general/file_same_site_cookies_from_script.sjs b/dom/security/test/general/file_same_site_cookies_from_script.sjs
new file mode 100644
index 0000000000..0df217cf45
--- /dev/null
+++ b/dom/security/test/general/file_same_site_cookies_from_script.sjs
@@ -0,0 +1,48 @@
+// Custom *.sjs file specifically for the needs of Bug 1452496
+
+const SET_COOKIE_FRAME = `
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <title>Bug 1452496 - Do not allow same-site cookies in cross site context</title>
+ </head>
+ <body>
+ <script type="application/javascript">
+ document.cookie = "myKey=sameSiteCookieInlineScript;SameSite=strict";
+ </script>
+ </body>
+ </html>`;
+
+const GET_COOKIE_FRAME = `
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <title>Bug 1452496 - Do not allow same-site cookies in cross site context</title>
+ </head>
+ <body>
+ <script type="application/javascript">
+ let cookie = document.cookie;
+ // now reset the cookie for the next test
+ document.cookie = "myKey=;" + "expires=Thu, 01 Jan 1970 00:00:00 GMT";
+ window.parent.postMessage({result: cookie}, 'http://mochi.test:8888');
+ </script>
+ </body>
+ </html>`;
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ if (request.queryString.includes("setSameSiteCookieUsingInlineScript")) {
+ response.write(SET_COOKIE_FRAME);
+ return;
+ }
+
+ if (request.queryString.includes("getCookieFrame")) {
+ response.write(GET_COOKIE_FRAME);
+ return;
+ }
+
+ // we should never get here, but just in case return something unexpected
+ response.write("D'oh");
+}
diff --git a/dom/security/test/general/file_same_site_cookies_iframe.sjs b/dom/security/test/general/file_same_site_cookies_iframe.sjs
new file mode 100644
index 0000000000..7b511257c3
--- /dev/null
+++ b/dom/security/test/general/file_same_site_cookies_iframe.sjs
@@ -0,0 +1,99 @@
+// Custom *.sjs file specifically for the needs of Bug 1454027
+
+// small red image
+const IMG_BYTES = atob(
+ "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" +
+ "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
+);
+
+const NESTED_IFRAME_NAVIGATION = `
+ <html>
+ <body>
+ <a id="testlink" href="http://mochi.test:8888/tests/dom/security/test/general/file_same_site_cookies_iframe.sjs"></a>
+ <script type="application/javascript">
+ let link = document.getElementById("testlink");
+ link.click();
+ <\/script>
+ </body>
+ </html>`;
+
+const NESTED_IFRAME_INCLUSION = `
+ <html>
+ <body>
+ <script type="application/javascript">
+ // simply passing on the message from the child to parent
+ window.addEventListener("message", receiveMessage);
+ function receiveMessage(event) {
+ window.removeEventListener("message", receiveMessage);
+ window.parent.postMessage({result: event.data.result}, '*');
+ }
+ <\/script>
+ <iframe src="http://mochi.test:8888/tests/dom/security/test/general/file_same_site_cookies_iframe.sjs"></iframe>
+ </body>
+ </html>`;
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ // using startsWith and discard the math random
+ if (request.queryString.startsWith("setSameSiteCookie")) {
+ response.setHeader(
+ "Set-Cookie",
+ "myKey=mySameSiteIframeTestCookie; samesite=strict",
+ true
+ );
+ response.setHeader("Content-Type", "image/png");
+ response.write(IMG_BYTES);
+ return;
+ }
+
+ // navigation tests
+ if (request.queryString === "nestedIframeNavigation") {
+ response.write(NESTED_IFRAME_NAVIGATION);
+ return;
+ }
+
+ if (request.queryString === "nestedSandboxIframeNavigation") {
+ response.setHeader(
+ "Content-Security-Policy",
+ "sandbox allow-scripts",
+ false
+ );
+ response.write(NESTED_IFRAME_NAVIGATION);
+ return;
+ }
+
+ // inclusion tests
+ if (request.queryString === "nestedIframeInclusion") {
+ response.write(NESTED_IFRAME_INCLUSION);
+ return;
+ }
+
+ if (request.queryString === "nestedSandboxIframeInclusion") {
+ response.setHeader(
+ "Content-Security-Policy",
+ "sandbox allow-scripts",
+ false
+ );
+ response.write(NESTED_IFRAME_INCLUSION);
+ return;
+ }
+
+ const cookies = request.hasHeader("Cookie")
+ ? request.getHeader("Cookie")
+ : "";
+ response.write(`
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <title>Bug 1454027 - Update SameSite cookie handling inside iframes</title>
+ </head>
+ <body>
+ <script type="application/javascript">
+ window.parent.postMessage({result: "${cookies}" }, '*');
+ </script>
+ </body>
+ </html>
+ `);
+}
diff --git a/dom/security/test/general/file_same_site_cookies_redirect.sjs b/dom/security/test/general/file_same_site_cookies_redirect.sjs
new file mode 100644
index 0000000000..f7451fb504
--- /dev/null
+++ b/dom/security/test/general/file_same_site_cookies_redirect.sjs
@@ -0,0 +1,103 @@
+// Custom *.sjs file specifically for the needs of Bug 1453814
+
+// small red image
+const IMG_BYTES = atob(
+ "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" +
+ "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
+);
+
+const FRAME = `
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <title>Bug 1453814 - Do not allow same-site cookies for cross origin redirect</title>
+ </head>
+ <body>
+ <script type="application/javascript">
+ let cookie = document.cookie;
+ // now reset the cookie for the next test
+ document.cookie = "myKey=;" + "expires=Thu, 01 Jan 1970 00:00:00 GMT";
+ window.parent.postMessage({result: cookie}, 'http://mochi.test:8888');
+ </script>
+ </body>
+ </html>`;
+
+const SAME_ORIGIN = "http://mochi.test:8888/";
+const CROSS_ORIGIN = "http://example.com/";
+const PATH =
+ "tests/dom/security/test/general/file_same_site_cookies_redirect.sjs";
+
+const FRAME_META_REFRESH_SAME =
+ `
+ <html><head>
+ <meta http-equiv="refresh" content="0;
+ url='` +
+ SAME_ORIGIN +
+ PATH +
+ `?loadFrame'">
+ </head></html>`;
+
+const FRAME_META_REFRESH_CROSS =
+ `
+ <html><head>
+ <meta http-equiv="refresh" content="0;
+ url='` +
+ CROSS_ORIGIN +
+ PATH +
+ `?loadFrame'">
+ </head></html>`;
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ if (request.queryString === "setSameSiteCookie") {
+ response.setHeader(
+ "Set-Cookie",
+ "myKey=strictSameSiteCookie; samesite=strict",
+ true
+ );
+ response.setHeader("Content-Type", "image/png");
+ response.write(IMG_BYTES);
+ return;
+ }
+
+ if (request.queryString === "sameToSameRedirect") {
+ let URL = SAME_ORIGIN + PATH + "?loadFrame";
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", URL, false);
+ return;
+ }
+
+ if (request.queryString === "sameToCrossRedirect") {
+ let URL = CROSS_ORIGIN + PATH + "?loadFrame";
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", URL, false);
+ return;
+ }
+
+ if (request.queryString === "crossToSameRedirect") {
+ let URL = SAME_ORIGIN + PATH + "?loadFrame";
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", URL, false);
+ return;
+ }
+
+ if (request.queryString === "sameToCrossRedirectMeta") {
+ response.write(FRAME_META_REFRESH_CROSS);
+ return;
+ }
+
+ if (request.queryString === "crossToSameRedirectMeta") {
+ response.write(FRAME_META_REFRESH_SAME);
+ return;
+ }
+
+ if (request.queryString === "loadFrame") {
+ response.write(FRAME);
+ return;
+ }
+
+ // we should never get here, but just in case return something unexpected
+ response.write("D'oh");
+}
diff --git a/dom/security/test/general/file_same_site_cookies_subrequest.sjs b/dom/security/test/general/file_same_site_cookies_subrequest.sjs
new file mode 100644
index 0000000000..fdc81344ef
--- /dev/null
+++ b/dom/security/test/general/file_same_site_cookies_subrequest.sjs
@@ -0,0 +1,82 @@
+// Custom *.sjs file specifically for the needs of Bug 1286861
+
+// small red image
+const IMG_BYTES = atob(
+ "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" +
+ "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
+);
+
+const FRAME = `
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <title>Bug 1286861 - Add support for same site cookies</title>
+ </head>
+ <body>
+ <img src = "http://mochi.test:8888/tests/dom/security/test/general/file_same_site_cookies_subrequest.sjs?checkCookie">
+ </body>
+ </html>`;
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ if (request.queryString.includes("setStrictSameSiteCookie")) {
+ response.setHeader(
+ "Set-Cookie",
+ "myKey=strictSameSiteCookie; samesite=strict",
+ true
+ );
+ response.setHeader("Content-Type", "image/png");
+ response.write(IMG_BYTES);
+ return;
+ }
+
+ if (request.queryString.includes("setLaxSameSiteCookie")) {
+ response.setHeader(
+ "Set-Cookie",
+ "myKey=laxSameSiteCookie; samesite=lax",
+ true
+ );
+ response.setHeader("Content-Type", "image/png");
+ response.write(IMG_BYTES);
+ return;
+ }
+
+ // save the object state of the initial request, which returns
+ // async once the server has processed the img request.
+ if (request.queryString.includes("queryresult")) {
+ response.processAsync();
+ setObjectState("queryResult", response);
+ return;
+ }
+
+ if (request.queryString.includes("loadFrame")) {
+ response.write(FRAME);
+ return;
+ }
+
+ if (request.queryString.includes("checkCookie")) {
+ var cookie = "unitialized";
+ if (request.hasHeader("Cookie")) {
+ cookie = request.getHeader("Cookie");
+ } else {
+ cookie = "myKey=noCookie";
+ }
+ response.setHeader("Content-Type", "image/png");
+ response.write(IMG_BYTES);
+
+ // return the result
+ getObjectState("queryResult", function (queryResponse) {
+ if (!queryResponse) {
+ return;
+ }
+ queryResponse.write(cookie);
+ queryResponse.finish();
+ });
+ return;
+ }
+
+ // we should never get here, but just in case return something unexpected
+ response.write("D'oh");
+}
diff --git a/dom/security/test/general/file_same_site_cookies_toplevel_nav.sjs b/dom/security/test/general/file_same_site_cookies_toplevel_nav.sjs
new file mode 100644
index 0000000000..45b515a28b
--- /dev/null
+++ b/dom/security/test/general/file_same_site_cookies_toplevel_nav.sjs
@@ -0,0 +1,96 @@
+// Custom *.sjs file specifically for the needs of Bug 1286861
+
+// small red image
+const IMG_BYTES = atob(
+ "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" +
+ "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
+);
+
+const FRAME = `
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <title>Bug 1286861 - Add support for same site cookies</title>
+ </head>
+ <body>
+ <script type="application/javascript">
+ let myWin = window.open("http://mochi.test:8888/tests/dom/security/test/general/file_same_site_cookies_toplevel_nav.sjs?loadWin");
+ </script>
+ </body>
+ </html>`;
+
+const WIN = `
+ <!DOCTYPE html>
+ <html>
+ <body>
+ just a dummy window
+ <script>
+ window.addEventListener("load",()=>{
+ window.close();
+ });
+ </script>
+ </body>
+ </html>`;
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ if (request.queryString.includes("setStrictSameSiteCookie")) {
+ response.setHeader(
+ "Set-Cookie",
+ "myKey=strictSameSiteCookie; samesite=strict",
+ true
+ );
+ response.setHeader("Content-Type", "image/png");
+ response.write(IMG_BYTES);
+ return;
+ }
+
+ if (request.queryString.includes("setLaxSameSiteCookie")) {
+ response.setHeader(
+ "Set-Cookie",
+ "myKey=laxSameSiteCookie; samesite=lax",
+ true
+ );
+ response.setHeader("Content-Type", "image/png");
+ response.write(IMG_BYTES);
+ return;
+ }
+
+ // save the object state of the initial request, which returns
+ // async once the server has processed the img request.
+ if (request.queryString.includes("queryresult")) {
+ response.processAsync();
+ setObjectState("queryResult", response);
+ return;
+ }
+
+ if (request.queryString.includes("loadFrame")) {
+ response.write(FRAME);
+ return;
+ }
+
+ if (request.queryString.includes("loadWin")) {
+ var cookie = "unitialized";
+ if (request.hasHeader("Cookie")) {
+ cookie = request.getHeader("Cookie");
+ } else {
+ cookie = "myKey=noCookie";
+ }
+ response.write(WIN);
+
+ // return the result
+ getObjectState("queryResult", function (queryResponse) {
+ if (!queryResponse) {
+ return;
+ }
+ queryResponse.write(cookie);
+ queryResponse.finish();
+ });
+ return;
+ }
+
+ // we should never get here, but just in case return something unexpected
+ response.write("D'oh");
+}
diff --git a/dom/security/test/general/file_same_site_cookies_toplevel_set_cookie.sjs b/dom/security/test/general/file_same_site_cookies_toplevel_set_cookie.sjs
new file mode 100644
index 0000000000..34dfe40e23
--- /dev/null
+++ b/dom/security/test/general/file_same_site_cookies_toplevel_set_cookie.sjs
@@ -0,0 +1,68 @@
+// Custom *.sjs file specifically for the needs of Bug 1454242
+
+const WIN = `
+ <html>
+ <body>
+ <script type="application/javascript">
+ let newWin = window.open("http://mochi.test:8888/tests/dom/security/test/general/file_same_site_cookies_toplevel_set_cookie.sjs?loadWinAndSetCookie");
+ newWin.onload = function() {
+ newWin.close();
+ }
+ </script>
+ </body>
+ </html>`;
+
+const DUMMY_WIN = `
+ <html>
+ <body>
+ just a dummy window that sets a same-site=lax cookie
+ <script type="application/javascript">
+ window.opener.opener.postMessage({value: 'testSetupComplete'}, '*');
+ </script>
+ </body>
+ </html>`;
+
+const FRAME = `
+ <html>
+ <body>
+ <script type="application/javascript">
+ let cookie = document.cookie;
+ // now reset the cookie for the next test
+ document.cookie = "myKey=;" + "expires=Thu, 01 Jan 1970 00:00:00 GMT";
+ window.parent.postMessage({value: cookie}, 'http://mochi.test:8888');
+ </script>
+ </body>
+ </html>`;
+
+const SAME_ORIGIN = "http://mochi.test:8888/";
+const CROSS_ORIGIN = "http://example.com/";
+const PATH =
+ "tests/dom/security/test/general/file_same_site_cookies_redirect.sjs";
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ if (request.queryString === "loadWin") {
+ response.write(WIN);
+ return;
+ }
+
+ if (request.queryString === "loadWinAndSetCookie") {
+ response.setHeader(
+ "Set-Cookie",
+ "myKey=laxSameSiteCookie; samesite=lax",
+ true
+ );
+ response.write(DUMMY_WIN);
+ return;
+ }
+
+ if (request.queryString === "checkCookie") {
+ response.write(FRAME);
+ return;
+ }
+
+ // we should never get here, but just in case return something unexpected
+ response.write("D'oh");
+}
diff --git a/dom/security/test/general/file_script.js b/dom/security/test/general/file_script.js
new file mode 100644
index 0000000000..c339e45d5d
--- /dev/null
+++ b/dom/security/test/general/file_script.js
@@ -0,0 +1 @@
+window.counter++;
diff --git a/dom/security/test/general/file_toplevel_data_meta_redirect.html b/dom/security/test/general/file_toplevel_data_meta_redirect.html
new file mode 100644
index 0000000000..e94a61ed48
--- /dev/null
+++ b/dom/security/test/general/file_toplevel_data_meta_redirect.html
@@ -0,0 +1,10 @@
+<html>
+<body>
+<head>
+ <meta http-equiv="refresh"
+ content="0; url='data:text/html,<body>toplevel meta redirect to data: URI should be blocked</body>'">
+</head>
+<body>
+Meta Redirect to data: URI
+</body>
+</html>
diff --git a/dom/security/test/general/file_toplevel_data_navigations.sjs b/dom/security/test/general/file_toplevel_data_navigations.sjs
new file mode 100644
index 0000000000..57c4b527dd
--- /dev/null
+++ b/dom/security/test/general/file_toplevel_data_navigations.sjs
@@ -0,0 +1,13 @@
+// Custom *.sjs file specifically for the needs of Bug:
+// Bug 1394554 - Block toplevel data: URI navigations after redirect
+
+var DATA_URI =
+ "data:text/html,<body>toplevel data: URI navigations after redirect should be blocked</body>";
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", DATA_URI, false);
+}
diff --git a/dom/security/test/general/file_view_bg_image_data_navigation.html b/dom/security/test/general/file_view_bg_image_data_navigation.html
new file mode 100644
index 0000000000..d9aa6ca8b6
--- /dev/null
+++ b/dom/security/test/general/file_view_bg_image_data_navigation.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1658244: Test navigation for right-click view-bg-image on data:image/svg</title>
+<style>
+body {
+ background: fixed #222 url("data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjUwMCIgd2lkdGg9IjUwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PGZpbHRlciBpZD0iYSI+PGZlVHVyYnVsZW5jZSBiYXNlRnJlcXVlbmN5PSIuOSIgbnVtT2N0YXZlcz0iMTAiIHN0aXRjaFRpbGVzPSJzdGl0Y2giIHR5cGU9ImZyYWN0YWxOb2lzZSIvPjwvZmlsdGVyPjxwYXRoIGQ9Im0wIDBoNTAwdjUwMGgtNTAweiIgZmlsbD0iIzExMSIvPjxwYXRoIGQ9Im0wIDBoNTAwdjUwMGgtNTAweiIgZmlsdGVyPSJ1cmwoI2EpIiBvcGFjaXR5PSIuMiIvPjwvc3ZnPgo=");
+ color: #ccc;
+}
+</style>
+</head>
+<body id="testbody">
+ This page has an inline SVG image as a background.
+</body>
+</html>
diff --git a/dom/security/test/general/file_view_image_data_navigation.html b/dom/security/test/general/file_view_image_data_navigation.html
new file mode 100644
index 0000000000..a3f9acfb4d
--- /dev/null
+++ b/dom/security/test/general/file_view_image_data_navigation.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1407891: Test navigation for right-click view-image on data:image/svg</title>
+</head>
+<body>
+
+<img id="testimage" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij4KICA8cGF0aCBkPSJNOCwxMkwzLDcsNCw2bDQsNCw0LTQsMSwxWiIgZmlsbD0iIzZBNkE2QSIgLz4KPC9zdmc+Cg=="></img>
+
+</body>
+</html>
diff --git a/dom/security/test/general/file_xfo_error_page.sjs b/dom/security/test/general/file_xfo_error_page.sjs
new file mode 100644
index 0000000000..b1fa33cbd4
--- /dev/null
+++ b/dom/security/test/general/file_xfo_error_page.sjs
@@ -0,0 +1,8 @@
+"use strict";
+
+function handleRequest(request, response) {
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/html", false);
+ response.setHeader("x-frame-options", "deny", false);
+ response.write("<html>xfo test loaded</html>");
+}
diff --git a/dom/security/test/general/mochitest.ini b/dom/security/test/general/mochitest.ini
new file mode 100644
index 0000000000..ba67830706
--- /dev/null
+++ b/dom/security/test/general/mochitest.ini
@@ -0,0 +1,95 @@
+[DEFAULT]
+support-files =
+ file_contentpolicytype_targeted_link_iframe.sjs
+ file_nosniff_testserver.sjs
+ file_nosniff_navigation.sjs
+ file_block_script_wrong_mime_server.sjs
+ file_block_toplevel_data_navigation.html
+ file_block_toplevel_data_navigation2.html
+ file_block_toplevel_data_navigation3.html
+ file_block_toplevel_data_redirect.sjs
+ file_block_subresource_redir_to_data.sjs
+ file_same_site_cookies_subrequest.sjs
+ file_same_site_cookies_toplevel_nav.sjs
+ file_same_site_cookies_cross_origin_context.sjs
+ file_same_site_cookies_from_script.sjs
+ file_same_site_cookies_redirect.sjs
+ file_same_site_cookies_toplevel_set_cookie.sjs
+ file_same_site_cookies_blob_iframe_navigation.html
+ file_same_site_cookies_blob_iframe_inclusion.html
+ file_same_site_cookies_iframe.sjs
+ file_same_site_cookies_about.sjs
+ file_cache_splitting_server.sjs
+ file_cache_splitting_isloaded.sjs
+ file_cache_splitting_window.html
+ window_nosniff_navigation.html
+
+[test_contentpolicytype_targeted_link_iframe.html]
+skip-if =
+ http3
+[test_nosniff.html]
+[test_cache_split.html]
+skip-if =
+ http3
+[test_nosniff_navigation.html]
+[test_block_script_wrong_mime.html]
+[test_block_toplevel_data_navigation.html]
+[test_block_toplevel_data_img_navigation.html]
+[test_allow_opening_data_pdf.html]
+skip-if = toolkit == 'android' # no pdf reader on Android
+[test_allow_opening_data_json.html]
+[test_block_subresource_redir_to_data.html]
+[test_same_site_cookies_subrequest.html]
+fail-if = xorigin # Cookies set incorrectly
+skip-if =
+ http3
+[test_same_site_cookies_toplevel_nav.html]
+fail-if = xorigin
+skip-if =
+ http3
+[test_same_site_cookies_cross_origin_context.html]
+skip-if =
+ http3
+[test_same_site_cookies_from_script.html]
+fail-if = xorigin
+skip-if =
+ http3
+[test_same_site_cookies_redirect.html]
+fail-if = xorigin
+skip-if =
+ http3
+[test_same_site_cookies_toplevel_set_cookie.html]
+fail-if = xorigin # Cookies not set
+skip-if =
+ http3
+[test_same_site_cookies_iframe.html]
+fail-if = xorigin
+skip-if =
+ http3
+[test_same_site_cookies_about.html]
+fail-if = xorigin
+skip-if =
+ http3
+[test_assert_about_page_no_csp.html]
+skip-if = !debug
+[test_same_site_cookies_laxByDefault.html]
+skip-if = debug
+support-files = closeWindow.sjs
+[test_xfo_error_page.html]
+support-files = file_xfo_error_page.sjs
+skip-if =
+ http3
+[test_bug1450853.html]
+skip-if =
+ http3
+[test_meta_referrer.html]
+support-files =
+ file_meta_referrer_in_head.html
+ file_meta_referrer_notin_head.html
+[test_bug1660452_http.html]
+skip-if =
+ http3
+[test_bug1660452_https.html]
+scheme = https
+[test_gpc.html]
+support-files = file_gpc_server.sjs
diff --git a/dom/security/test/general/test_allow_opening_data_json.html b/dom/security/test/general/test_allow_opening_data_json.html
new file mode 100644
index 0000000000..4b37931e1f
--- /dev/null
+++ b/dom/security/test/general/test_allow_opening_data_json.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1403814: Allow toplevel data URI navigation data:application/json</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+function test_toplevel_data_json() {
+ const DATA_JSON = "data:application/json,{'my_json_key':'my_json_value'}";
+
+ let win = window.open(DATA_JSON);
+ let wrappedWin = SpecialPowers.wrap(win);
+
+ // Unfortunately we can't detect whether the JSON has loaded or not using some
+ // event, hence we are constantly polling location.href till we see that
+ // the data: URI appears. Test times out on failure.
+ var jsonLoaded = setInterval(function() {
+ if (wrappedWin.document.location.href.startsWith("data:application/json")) {
+ clearInterval(jsonLoaded);
+ ok(true, "navigating to data:application/json allowed");
+ wrappedWin.close();
+ SimpleTest.finish();
+ }
+ }, 200);
+}
+
+SpecialPowers.pushPrefEnv({
+ set: [["security.data_uri.block_toplevel_data_uri_navigations", true]]
+}, test_toplevel_data_json);
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_assert_about_page_no_csp.html b/dom/security/test/general/test_assert_about_page_no_csp.html
new file mode 100644
index 0000000000..06be4ce460
--- /dev/null
+++ b/dom/security/test/general/test_assert_about_page_no_csp.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1490977: Test Assertion if content privileged about: page has no CSP</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe id="testframe"></iframe>
+<script class="testbody" type="text/javascript">
+
+ // Test Setup: The test overrules the allowlist of about: pages that are allowed to load
+ // without a CSP and makes sure to hit the assertion within AssertAboutPageHasCSP().
+
+ SpecialPowers.setBoolPref("dom.security.skip_about_page_csp_allowlist_and_assert", true);
+
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.expectAssertions(0, 1);
+
+ ok(true, "sanity: prefs flipped and test runs");
+ let myFrame = document.getElementById("testframe");
+ myFrame.src = "about:blank";
+ // booom :-)
+
+ SpecialPowers.setBoolPref("dom.security.skip_about_page_csp_allowlist_and_assert", false);
+ SimpleTest.finish();
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/security/test/general/test_block_script_wrong_mime.html b/dom/security/test/general/test_block_script_wrong_mime.html
new file mode 100644
index 0000000000..93a4b9d220
--- /dev/null
+++ b/dom/security/test/general/test_block_script_wrong_mime.html
@@ -0,0 +1,92 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1288361 - Block scripts with incorrect MIME type</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<script class="testbody" type="text/javascript">
+
+const MIMETypes = [
+ ["application/javascript", true],
+ ["text/javascript", true],
+
+ ["audio/mpeg", false],
+ ["audio/", false],
+ ["image/jpeg", false],
+ ["image/", false],
+ ["video/mpeg", false],
+ ["video/", false],
+ ["text/csv", false],
+];
+
+// <script src="">
+function testScript([mime, shouldLoad]) {
+ return new Promise((resolve, reject) => {
+ let script = document.createElement("script");
+ script.onload = () => {
+ document.body.removeChild(script);
+ ok(shouldLoad, `script with mime '${mime}' should load`);
+ resolve();
+ };
+ script.onerror = () => {
+ document.body.removeChild(script);
+ ok(!shouldLoad, `script with wrong mime '${mime}' should be blocked`);
+ resolve();
+ };
+ script.src = "file_block_script_wrong_mime_server.sjs?type=script&mime="+mime;
+ document.body.appendChild(script);
+ });
+}
+
+// new Worker()
+function testWorker([mime, shouldLoad]) {
+ return new Promise((resolve, reject) => {
+ let worker = new Worker("file_block_script_wrong_mime_server.sjs?type=worker&mime="+mime);
+ worker.onmessage = (event) => {
+ ok(shouldLoad, `worker with mime '${mime}' should load`)
+ is(event.data, "worker-loaded", "worker should send correct message");
+ resolve();
+ };
+ worker.onerror = (error) => {
+ ok(!shouldLoad, `worker with wrong mime '${mime}' should be blocked`);
+ error.preventDefault();
+ resolve();
+ }
+ worker.postMessage("dummy");
+ });
+}
+
+// new Worker() with importScripts()
+function testWorkerImportScripts([mime, shouldLoad]) {
+ return new Promise((resolve, reject) => {
+ let worker = new Worker("file_block_script_wrong_mime_server.sjs?type=worker-import&mime="+mime);
+ worker.onmessage = (event) => {
+ ok(shouldLoad, `worker/importScripts with mime '${mime}' should load`)
+ is(event.data, "worker-loaded", "worker should send correct message");
+ resolve();
+ };
+ worker.onerror = (error) => {
+ ok(!shouldLoad, `worker/importScripts with wrong mime '${mime}' should be blocked`);
+ error.preventDefault();
+ resolve();
+ }
+ worker.postMessage("dummy");
+ });
+}
+
+SimpleTest.waitForExplicitFinish();
+Promise.all(MIMETypes.map(testScript)).then(() => {
+ return Promise.all(MIMETypes.map(testWorker));
+}).then(() => {
+ return Promise.all(MIMETypes.map(testWorkerImportScripts));
+}).then(() => {
+ return SpecialPowers.popPrefEnv();
+}).then(SimpleTest.finish);
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_block_subresource_redir_to_data.html b/dom/security/test/general/test_block_subresource_redir_to_data.html
new file mode 100644
index 0000000000..eafb6b5d83
--- /dev/null
+++ b/dom/security/test/general/test_block_subresource_redir_to_data.html
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1428793: Block insecure redirects to data: URIs</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<script id="testScriptRedirectToData"></script>
+<script id="testModuleScriptRedirectToData" type="module"></script>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+const NUM_TESTS = 3;
+
+var testCounter = 0;
+function checkFinish() {
+ testCounter++;
+ if (testCounter === NUM_TESTS) {
+ SimpleTest.finish();
+ }
+}
+
+// --- test regular scripts
+let testScriptRedirectToData = document.getElementById("testScriptRedirectToData");
+testScriptRedirectToData.onerror = function() {
+ ok(true, "script that redirects to data: URI should not load");
+ checkFinish();
+}
+testScriptRedirectToData.onload = function() {
+ ok(false, "script that redirects to data: URI should not load");
+ checkFinish();
+}
+testScriptRedirectToData.src = "file_block_subresource_redir_to_data.sjs?script";
+
+// --- test workers
+let worker = new Worker("file_block_subresource_redir_to_data.sjs?worker");
+worker.onerror = function() {
+ // please note that workers need to be same origin, hence the data: URI
+ // redirect is blocked by worker code and not the content security manager!
+ ok(true, "worker script that redirects to data: URI should not load");
+ checkFinish();
+}
+worker.onmessage = function() {
+ ok(false, "worker script that redirects to data: URI should not load");
+ checkFinish();
+};
+worker.postMessage("dummy");
+
+// --- test script modules
+SpecialPowers.pushPrefEnv({set: [["dom.moduleScripts.enabled", true]]}, function() {
+ let testModuleScriptRedirectToData = document.getElementById("testModuleScriptRedirectToData");
+ testModuleScriptRedirectToData.onerror = function() {
+ ok(true, "module script that redirects to data: URI should not load");
+ checkFinish();
+ }
+ testModuleScriptRedirectToData.onload = function() {
+ ok(false, "module script that redirects to data: URI should not load");
+ checkFinish();
+ }
+ testModuleScriptRedirectToData.src = "file_block_subresource_redir_to_data.sjs?modulescript";
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_block_toplevel_data_img_navigation.html b/dom/security/test/general/test_block_toplevel_data_img_navigation.html
new file mode 100644
index 0000000000..07e46b1f2f
--- /dev/null
+++ b/dom/security/test/general/test_block_toplevel_data_img_navigation.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1396798: Do not block toplevel data: navigation to image (except svgs)</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+SpecialPowers.setBoolPref("security.data_uri.block_toplevel_data_uri_navigations", true);
+SimpleTest.registerCleanupFunction(() => {
+ SpecialPowers.clearUserPref("security.data_uri.block_toplevel_data_uri_navigations");
+});
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("have to test that top level data:image loading is blocked/allowed");
+
+function test_toplevel_data_image() {
+ const DATA_PNG =
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
+ let win1 = window.open(DATA_PNG);
+ let wrappedWin1 = SpecialPowers.wrap(win1);
+ setTimeout(function () {
+ let images = wrappedWin1.document.getElementsByTagName('img');
+ is(images.length, 1, "Loading data:image/png should be allowed");
+ is(images[0].src, DATA_PNG, "Sanity: img src matches");
+ wrappedWin1.close();
+ test_toplevel_data_image_svg();
+ }, 1000);
+}
+
+function test_toplevel_data_image_svg() {
+ const DATA_SVG =
+ "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij4KICA8cGF0aCBkPSJNOCwxMkwzLDcsNCw2bDQsNCw0LTQsMSwxWiIgZmlsbD0iIzZBNkE2QSIgLz4KPC9zdmc+Cg==";
+ let win2 = window.open(DATA_SVG);
+ // Unfortunately we can't detect whether the window was closed using some event,
+ // hence we are constantly polling till we see that win == null.
+ // Test times out on failure.
+ var win2Closed = setInterval(function() {
+ if (win2 == null || win2.closed) {
+ clearInterval(win2Closed);
+ ok(true, "Loading data:image/svg+xml should be blocked");
+ SimpleTest.finish();
+ }
+ }, 200);
+}
+// fire up the tests
+test_toplevel_data_image();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_block_toplevel_data_navigation.html b/dom/security/test/general/test_block_toplevel_data_navigation.html
new file mode 100644
index 0000000000..bbadacb218
--- /dev/null
+++ b/dom/security/test/general/test_block_toplevel_data_navigation.html
@@ -0,0 +1,134 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1331351 - Block top level window data: URI navigations</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+
+async function expectBlockedToplevelData() {
+ await SpecialPowers.spawnChrome([], async () => {
+ let progressListener;
+ let bid = await new Promise(resolve => {
+ let bcs = [];
+ progressListener = {
+ QueryInterface: ChromeUtils.generateQI(["nsIWebProgressListener", "nsISupportsWeakReference"]),
+ onStateChange(webProgress, request, stateFlags, status) {
+ if (!(request instanceof Ci.nsIChannel) || !webProgress.isTopLevel ||
+ !(stateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW) ||
+ !(stateFlags & Ci.nsIWebProgressListener.STATE_STOP)) {
+ return;
+ }
+
+ if (!["NS_ERROR_DOM_BAD_URI", "NS_ERROR_CORRUPTED_CONTENT"].includes(ChromeUtils.getXPCOMErrorName(status))) {
+ info(ChromeUtils.getXPCOMErrorName(status));
+ isnot(request.URI.scheme, "data");
+ return;
+ }
+
+ // We can't check for the scheme to be "data" because in the case of a
+ // redirected load, we'll get a `NS_ERROR_DOM_BAD_URI` load error
+ // before observing the redirect, cancelling the load. Instead we just
+ // wait for any load to error with `NS_ERROR_DOM_BAD_URI`.
+ for (let bc of bcs) {
+ try {
+ bc.webProgress.removeProgressListener(progressListener);
+ } catch(e) { }
+ }
+ bcs = [];
+ Services.obs.removeObserver(observer, "browsing-context-attached");
+ resolve(webProgress.browsingContext.browserId);
+ }
+ };
+
+ function observer(subject, topic) {
+ if (!bcs.includes(subject.webProgress)) {
+ bcs.push(subject.webProgress);
+ subject.webProgress.addProgressListener(progressListener, Ci.nsIWebProgress.NOTIFY_ALL);
+ }
+ }
+ Services.obs.addObserver(observer, "browsing-context-attached");
+ });
+ return bid;
+ });
+}
+
+async function expectBlockedURIWarning() {
+ await SpecialPowers.spawnChrome([], async () => {
+ return new Promise(resolve => {
+ Services.console.registerListener(function onConsoleMessage(msg) {
+ info("Seeing console message: " + msg.message);
+ if (!(msg instanceof Ci.nsIScriptError)) {
+ return;
+ }
+ if (msg.category != "DATA_URI_BLOCKED") {
+ return;
+ }
+
+ Services.console.unregisterListener(onConsoleMessage);
+ resolve();
+ });
+ });
+ });
+}
+
+async function expectBrowserDiscarded(browserId) {
+ await SpecialPowers.spawnChrome([browserId], async (browserId) => {
+ return new Promise(resolve => {
+ function check() {
+ if (!BrowsingContext.getCurrentTopByBrowserId(browserId)) {
+ ok(true, `BrowserID ${browserId} discarded`);
+ resolve();
+ Services.obs.removeObserver(check, "browsing-context-discarded");
+ }
+ }
+ Services.obs.addObserver(check, "browsing-context-discarded");
+ check();
+ });
+ });
+}
+
+async function popupTest(uri, expectClose) {
+ info(`Running expect blocked test for ${uri}`);
+ let reqBlockedPromise = expectBlockedToplevelData();
+ let warningPromise = expectBlockedURIWarning();
+ let win = window.open(uri);
+ let browserId = await reqBlockedPromise;
+ await warningPromise;
+ if (expectClose) {
+ await expectBrowserDiscarded(browserId);
+ }
+ win.close();
+}
+
+add_task(async function() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["security.data_uri.block_toplevel_data_uri_navigations", true]],
+ });
+
+ // simple data: URI click navigation should be prevented
+ await popupTest("file_block_toplevel_data_navigation.html", false);
+
+ // data: URI in iframe which opens data: URI in _blank should be blocked
+ await popupTest("file_block_toplevel_data_navigation2.html", false);
+
+ // navigating to a data: URI using window.location.href should be blocked
+ await popupTest("file_block_toplevel_data_navigation3.html", false);
+
+ // navigating to a data: URI using window.open() should be blocked
+ await popupTest("data:text/html,<body>toplevel data: URI navigations should be blocked</body>", false);
+
+ // navigating to a URI which redirects to a data: URI using window.open() should be blocked
+ await popupTest("file_block_toplevel_data_redirect.sjs", false);
+
+ // navigating to a data: URI without a Content Type should be blocked
+ await popupTest("data:,DataURIsWithNoContentTypeShouldBeBlocked", false);
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_bug1277803.xhtml b/dom/security/test/general/test_bug1277803.xhtml
new file mode 100644
index 0000000000..30cc82310b
--- /dev/null
+++ b/dom/security/test/general/test_bug1277803.xhtml
@@ -0,0 +1,65 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+
+<window title="Bug 1277803 test"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ width="600"
+ height="600"
+ onload="runTest();">
+
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ </body>
+
+ <script type="application/javascript"><![CDATA[
+ SimpleTest.requestCompleteLog();
+
+ const BASE_URI = "http://mochi.test:8888/chrome/dom/security/test/general/";
+ const FAVICON_URI = BASE_URI + "favicon_bug1277803.ico";
+ const LOADING_URI = BASE_URI + "bug1277803.html";
+ let testWindow; //will be used to trigger favicon load
+
+ let expectedPrincipal = Services.scriptSecurityManager
+ .createContentPrincipal(Services.io.newURI(LOADING_URI), {});
+ let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
+
+ function runTest() {
+ // Register our observer to intercept favicon requests.
+ function observer(aSubject, aTopic, aData) {
+ // Make sure this is a favicon request.
+ let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
+ if (FAVICON_URI != httpChannel.URI.spec) {
+ return;
+ }
+
+ // Ensure the topic is the one we set an observer for.
+ is(aTopic, "http-on-modify-request", "Expected observer topic");
+
+ // Check for the correct loadingPrincipal, triggeringPrincipal.
+ let triggeringPrincipal = httpChannel.loadInfo.triggeringPrincipal;
+ let loadingPrincipal = httpChannel.loadInfo.loadingPrincipal;
+
+ ok(loadingPrincipal.equals(expectedPrincipal), "Should be loading with the expected principal.");
+ ok(triggeringPrincipal.equals(expectedPrincipal), "Should be triggered with the expected principal.");
+
+ Services.obs.removeObserver(this, "http-on-modify-request");
+ SimpleTest.finish();
+ }
+ Services.obs.addObserver(observer, "http-on-modify-request");
+
+ // Now that the observer is set up, trigger a favicon load with navigation
+ testWindow = window.open(LOADING_URI);
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.registerCleanupFunction(function() {
+ if (testWindow) {
+ testWindow.close();
+ }
+ });
+ ]]></script>
+
+ <browser type="content" primary="true" flex="1" id="content" src="about:blank"/>
+</window>
diff --git a/dom/security/test/general/test_bug1450853.html b/dom/security/test/general/test_bug1450853.html
new file mode 100644
index 0000000000..e6b61ecce0
--- /dev/null
+++ b/dom/security/test/general/test_bug1450853.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1450853
+-->
+<head>
+<meta charset="utf-8">
+<title>Test for Cross-origin resouce status leak via MediaError</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/ChromeTask.js"></script>
+<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+
+<audio autoplay id="audio"></audio>
+
+<script type="application/javascript">
+
+/** Test for Bug 1450853 **/
+var CONST_GENERIC_ERROR_MESSAGE = "Failed to open media";
+
+add_task(function() {
+ return new Promise((resolve) => {
+ let audioElement = document.getElementById("audio");
+
+ audioElement.onerror = function() {
+ let err = this.error;
+ let message = err.message;
+
+ info(`Got Audio Error -> ${message}`);
+ ok(message.includes("404"), "Same-Origin Error Message should contain status data");
+ resolve();
+ };
+ audioElement.src = "http://mochi.test:8888/media/test.mp3";
+ });
+});
+
+add_task(function() {
+ return new Promise((resolve) => {
+ let audioElement = document.getElementById("audio");
+
+ audioElement.onerror = function() {
+ let err = this.error;
+ let message = err.message;
+
+ info(`Got Audio Error -> ${message}`);
+ is(message, CONST_GENERIC_ERROR_MESSAGE, "Cross-Origin Same-Site Error Message should be generic");
+ resolve();
+ };
+ audioElement.src = "http://mochi.test:9999/media/test.mp3";
+ });
+});
+
+add_task(function() {
+ return new Promise((resolve) => {
+ let audioElement = document.getElementById("audio");
+
+ audioElement.onerror = function() {
+ let err = this.error;
+ let message = err.message;
+
+ info(`Got Audio Error -> ${message}`);
+ is(message, CONST_GENERIC_ERROR_MESSAGE, "Cross-Origin Same-Site Error Message should be generic");
+ resolve();
+ };
+ audioElement.src = "http://sub.mochi.test:8888/media/test.mp3";
+ });
+});
+
+add_task(function() {
+ return new Promise((resolve) => {
+ let audioElement = document.getElementById("audio");
+
+ audioElement.onerror = function() {
+ let err = this.error;
+ let message = err.message;
+
+ info(`Got Audio Error -> ${message}`);
+ is(message, CONST_GENERIC_ERROR_MESSAGE, "Cross-Origin Error Message should be generic");
+ resolve();
+ };
+ audioElement.src = "https://example.com/media/test.mp3";
+ });
+});
+
+</script>
+</head>
+
+<body>
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1450853">Mozilla Bug 1450853</a>
+ <iframe width="0" height="0"></iframe>
+ </body>
+</html>
diff --git a/dom/security/test/general/test_bug1660452_http.html b/dom/security/test/general/test_bug1660452_http.html
new file mode 100644
index 0000000000..3a6512da21
--- /dev/null
+++ b/dom/security/test/general/test_bug1660452_http.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Bug 1660452: NullPrincipals need to know whether they were spun off of a Secure Context</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+
+<body>
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+ok(!window.isSecureContext, "top level should not be a secure context");
+
+// eslint-disable-next-line
+let newWin = window.open("data:text/html,<script><"+"/script>");
+ok(!newWin.isSecureContext, "data uri window should not be a secure context");
+newWin.close();
+
+window.addEventListener("message", (event) => {
+ ok(!event.data.isSecureContext, "data uri frames should not be a secure context");
+ if(event.data.finish) {
+ SimpleTest.finish();
+ return;
+ }
+ let f2 = document.createElement("iframe");
+ // eslint-disable-next-line
+ f2.src = "data:text/html,<iframe src=\"data:text/html,<script>parent.parent.postMessage({isSecureContext: window.isSecureContext, finish: true}, '*');<"+"/script>\"></iframe>";
+ document.body.appendChild(f2);
+});
+
+let f = document.createElement("iframe");
+// eslint-disable-next-line
+f.src = "data:text/html,<script>parent.postMessage({isSecureContext: window.isSecureContext}, '*');<"+"/script>";
+document.body.appendChild(f);
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_bug1660452_https.html b/dom/security/test/general/test_bug1660452_https.html
new file mode 100644
index 0000000000..1aed356a21
--- /dev/null
+++ b/dom/security/test/general/test_bug1660452_https.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Bug 1660452: NullPrincipals need to know whether they were spun off of a Secure Context</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+
+<body>
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+ok(window.isSecureContext, "top level should be a secure context");
+
+// eslint-disable-next-line
+let newWin = window.open("data:text/html,<script><"+"/script>");
+ok(newWin.isSecureContext, "data uri window should be a secure context");
+newWin.close();
+
+window.addEventListener("message", (event) => {
+ ok(event.data.isSecureContext, "data uri frames should be a secure context");
+ if(event.data.finish) {
+ SimpleTest.finish();
+ return;
+ }
+ let f2 = document.createElement("iframe");
+ // eslint-disable-next-line
+ f2.src = "data:text/html,<iframe src=\"data:text/html,<script>parent.parent.postMessage({isSecureContext: window.isSecureContext, finish: true}, '*');<"+"/script>\"></iframe>";
+ document.body.appendChild(f2);
+});
+
+let f = document.createElement("iframe");
+// eslint-disable-next-line
+f.src = "data:text/html,<script>parent.postMessage({isSecureContext: window.isSecureContext}, '*');<"+"/script>";
+document.body.appendChild(f);
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_cache_split.html b/dom/security/test/general/test_cache_split.html
new file mode 100644
index 0000000000..f0fc056bce
--- /dev/null
+++ b/dom/security/test/general/test_cache_split.html
@@ -0,0 +1,153 @@
+<!DOCTYPE HTML>
+<html>
+
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1454721 - Add same-site cookie test for about:blank and about:srcdoc</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/ChromeTask.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+
+<body>
+ <img id="cookieImage">
+ <script class="testbody" type="text/javascript">
+ SimpleTest.requestLongerTimeout(2);
+
+ const CROSS_ORIGIN = "http://mochi.test:8888/";
+ const SAME_ORIGIN= "https://example.com/";
+ const PATH = "file_cache_splitting_server.sjs";
+
+ async function getCount() {
+ return fetch(`${PATH}?state`).then(r => r.text());
+ }
+ async function resetCount() {
+ return fetch(`${PATH}?flush`).then(r => r.text());
+ }
+ async function ensureLoaded() {
+ // This Fetch is geting the Response "1", once file_cache_splitting_isloaded
+ // gets a request without a query String issued from the cache_splitting_window.html
+ info("Waiting for Pageload");
+ let result = await fetch("file_cache_splitting_isloaded.sjs?wait").then(r => r.text);
+ info("Page has been Loaded");
+ return result;
+ }
+
+
+ async function openAndLoadWindow(origin) {
+ let isLoaded = ensureLoaded();
+ let url = `${origin}tests/dom/security/test/general/file_cache_splitting_window.html`;
+ let w = window.open(url);
+ // let ew = SpecialPowers.wrap(w);
+ await isLoaded;
+ return w;
+ }
+
+ async function checkStep(step = [SAME_ORIGIN, 1], name) {
+ info(`Doing Step ${JSON.stringify(step)}`);
+ let url = step[0];
+ let should_count = step[1];
+ let w = await openAndLoadWindow(url);
+ let count = await getCount();
+ ok(
+ count == should_count,
+ `${name} req to: ${
+ url == SAME_ORIGIN ? "Same Origin" : "Cross Origin"
+ } expected ${should_count} request to Server, got ${count}`
+ );
+ w.close()
+ }
+ async function clearCache(){
+ info("Clearing Cache");
+ SpecialPowers.DOMWindowUtils.clearSharedStyleSheetCache();
+ await ChromeTask.spawn(null,(()=>{
+ Services.cache2.clear();
+ }));
+ }
+ async function runTest(test) {
+ info(`Starting Job with - ${test.steps.length} - Requests`);
+ await resetCount();
+ let { prefs, steps, name } = test;
+ await SpecialPowers.pushPrefEnv(prefs);
+ for (let step of steps) {
+ await checkStep(step, name);
+ }
+ await clearCache();
+ };
+
+
+ add_task(
+ async () =>
+ runTest({
+ name: `Isolated Cache`,
+ steps: [[SAME_ORIGIN, 1], [SAME_ORIGIN, 1], [CROSS_ORIGIN, 2]],
+ prefs: {
+ set: [
+ ["privacy.partition.network_state", true]
+ ],
+ },
+ })
+ );
+ // Negative Test: The CROSS_ORIGIN should be able to
+ // acess the cache of SAME_ORIGIN
+ add_task(
+ async () =>
+ runTest({
+ name: `Non Isolated Cache`,
+ steps: [[SAME_ORIGIN, 1], [SAME_ORIGIN, 1], [CROSS_ORIGIN, 1]],
+ prefs: {
+ set: [
+ ["privacy.partition.network_state", false]
+ ],
+ },
+ })
+ );
+ // Test that FPI does not affect Cache Isolation
+ add_task(
+ async () =>
+ runTest({
+ name: `FPI interaction`,
+ steps: [[SAME_ORIGIN, 1], [SAME_ORIGIN, 1], [CROSS_ORIGIN, 2]],
+ prefs: {
+ set: [
+ ["privacy.firstparty.isolate", true],
+ ["privacy.partition.network_state", false],
+ ],
+ },
+ })
+ );
+ // Test that cookieBehavior does not affect Cache Isolation
+ for (let i = 0; i < SpecialPowers.Ci.nsICookieService.BEHAVIOR_LAST ; i++) {
+ add_task(
+ async () =>
+ runTest({
+ name: `cookieBehavior interaction ${i}`,
+ steps: [[SAME_ORIGIN, 1], [SAME_ORIGIN, 1], [CROSS_ORIGIN, 2]],
+ prefs: {
+ set: [
+ ["privacy.firstparty.isolate", false],
+ ["network.cookie.cookieBehavior", i],
+ ["privacy.partition.network_state", true],
+ ],
+ },
+ })
+ );
+ }
+ add_task(
+ async () =>
+ runTest({
+ name: `FPI interaction - 2`,
+ steps: [[SAME_ORIGIN, 1], [SAME_ORIGIN, 1], [CROSS_ORIGIN, 2]],
+ prefs: {
+ set: [
+ ["privacy.firstparty.isolate", true],
+ ["privacy.partition.network_state", false],
+ ],
+ },
+ })
+ );
+
+ </script>
+</body>
+
+</html>
diff --git a/dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html b/dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html
new file mode 100644
index 0000000000..99620d06f9
--- /dev/null
+++ b/dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html
@@ -0,0 +1,103 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1255240 - Test content policy types within content policies for targeted links in iframes</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * Let's load a link into a targeted iframe and make sure the content policy
+ * type used for content policy checks is of TYPE_SUBDOCUMENT.
+ */
+
+function createChromeScript() {
+ /* eslint-env mozilla/chrome-script */
+ const POLICYNAME = "@mozilla.org/testpolicy;1";
+ const POLICYID = Components.ID("{6cc95ef3-40e1-4d59-87f0-86f100373227}");
+ const EXPECTED_URL =
+ "http://mochi.test:8888/tests/dom/security/test/general/file_contentpolicytype_targeted_link_iframe.sjs?innerframe";
+
+ var policy = {
+ // nsISupports implementation
+ QueryInterface: ChromeUtils.generateQI([
+ "nsIFactory",
+ "nsIContentPolicy",
+ ]),
+
+ // nsIFactory implementation
+ createInstance(iid) {
+ return this.QueryInterface(iid);
+ },
+
+ // nsIContentPolicy implementation
+ shouldLoad(contentLocation, loadInfo, mimeTypeGuess) {
+ if (contentLocation.asciiSpec === EXPECTED_URL) {
+ sendAsyncMessage("loadBlocked", { policyType: loadInfo.externalContentPolicyType});
+ Services.catMan.deleteCategoryEntry(
+ "content-policy",
+ POLICYNAME,
+ false
+ );
+ componentManager.unregisterFactory(POLICYID, policy);
+ return Ci.nsIContentPolicy.REJECT_REQUEST;
+ }
+ return Ci.nsIContentPolicy.ACCEPT;
+ },
+
+ shouldProcess(contentLocation, loadInfo, mimeTypeGuess) {
+ return Ci.nsIContentPolicy.ACCEPT;
+ }
+ };
+
+ // Register content policy
+ var componentManager = Components.manager.QueryInterface(
+ Ci.nsIComponentRegistrar
+ );
+
+ componentManager.registerFactory(
+ POLICYID,
+ "Test content policy",
+ POLICYNAME,
+ policy
+ );
+ Services.catMan.addCategoryEntry(
+ "content-policy",
+ POLICYNAME,
+ POLICYNAME,
+ false,
+ true
+ );
+
+ // Adding a new category dispatches an event to update
+ // caches, so we need to also dispatch an event to make
+ // sure we don't start the load until after that happens.
+ Services.tm.dispatchToMainThread(() => {
+ sendAsyncMessage("setupComplete");
+ });
+}
+
+add_task(async function() {
+ let chromeScript = SpecialPowers.loadChromeScript(createChromeScript);
+ await chromeScript.promiseOneMessage("setupComplete");
+
+ var testframe = document.getElementById("testframe");
+ testframe.src =
+ "file_contentpolicytype_targeted_link_iframe.sjs?testframe";
+
+ let result = await chromeScript.promiseOneMessage("loadBlocked");
+
+ is(result.policyType, SpecialPowers.Ci.nsIContentPolicy.TYPE_SUBDOCUMENT,
+ "content policy type should TYPESUBDOCUMENT");
+
+ chromeScript.destroy();
+});
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_gpc.html b/dom/security/test/general/test_gpc.html
new file mode 100644
index 0000000000..506629554d
--- /dev/null
+++ b/dom/security/test/general/test_gpc.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Global Privacy Control headers</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script class="testbody" type="application/javascript">
+
+add_task(async function testGlobalPrivacyControlDisabled() {
+ await SpecialPowers.pushPrefEnv({ set: [
+ ["privacy.globalprivacycontrol.enabled", false],
+ ["privacy.globalprivacycontrol.functionality.enabled", true],
+ ]})
+ .then(() => fetch("file_gpc_server.sjs"))
+ .then((response) => response.text())
+ .then((response) => {
+ is(response, "false", "GPC disabled so header unsent");
+ is(navigator.globalPrivacyControl, false, "GPC disabled so navigator property is 0");
+
+ let worker = new Worker(window.URL.createObjectURL(new Blob(["postMessage(navigator.globalPrivacyControl);"])));
+ return new Promise((resolve) => { worker.onmessage = (e) => { resolve(e.data) } });
+ })
+ .then((response) => {
+ is(response, false, "GPC disabled so worker's navigator property is 0");
+ });
+});
+
+add_task(async function testGlobalPrivacyControlEnabled() {
+ await SpecialPowers.pushPrefEnv({ set: [
+ ["privacy.globalprivacycontrol.enabled", true],
+ ["privacy.globalprivacycontrol.functionality.enabled", true],
+ ]})
+ .then(() => fetch("file_gpc_server.sjs"))
+ .then((response) => response.text())
+ .then((response) => {
+ is(response, "true", "GPC enabled so header sent and received");
+ is(navigator.globalPrivacyControl, true, "GPC enabled so navigator property is 1");
+
+ let worker = new Worker(window.URL.createObjectURL(new Blob(["postMessage(navigator.globalPrivacyControl);"])));
+ return new Promise((resolve) => { worker.onmessage = (e) => { resolve(e.data) } });
+ })
+ .then((response) => {
+ is(response, true, "GPC enabled so worker's navigator property is 1");
+ });
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_innerhtml_sanitizer.html b/dom/security/test/general/test_innerhtml_sanitizer.html
new file mode 100644
index 0000000000..4a4e4efed1
--- /dev/null
+++ b/dom/security/test/general/test_innerhtml_sanitizer.html
@@ -0,0 +1,74 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset=utf-8>
+ <title>Test for Bug 1667113</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1667113">Mozilla Bug 1667113</a>
+<div></div>
+<script>
+SimpleTest.waitForExplicitFinish();
+
+// Please note that 'fakeServer' does not exist because the test relies
+// on "csp-on-violate-policy" , and "specialpowers-http-notify-request"
+// which fire if either the request is blocked or fires. The test does
+// not rely on the result of the load.
+
+function fail() {
+ ok(false, "Should not call this")
+}
+
+function examiner() {
+ SpecialPowers.addObserver(this, "csp-on-violate-policy");
+ SpecialPowers.addObserver(this, "specialpowers-http-notify-request");
+}
+examiner.prototype = {
+ observe(subject, topic, data) {
+ if (topic === "csp-on-violate-policy") {
+ let asciiSpec = SpecialPowers.getPrivilegedProps(
+ SpecialPowers.do_QueryInterface(subject, "nsIURI"),
+ "asciiSpec");
+ if (asciiSpec.includes("fakeServer")) {
+ ok (false, "Should not attempt fetch, not even blocked by CSP.");
+ }
+ }
+
+ if (topic === "specialpowers-http-notify-request") {
+ if (data.includes("fakeServer")) {
+ ok (false, "Should not try fetch");
+ }
+ }
+ },
+ remove() {
+ SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+ SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
+ }
+}
+
+window.examiner = new examiner();
+
+let div = document.getElementsByTagName("div")[0];
+div.innerHTML = "<svg><style><title><audio src=fakeServer onerror=fail() onload=fail()>";
+
+let svg = div.firstChild;
+is(svg.nodeName, "svg", "Node name should be svg");
+
+let style = svg.firstChild;
+if (style) {
+ is(style.firstChild, null, "Style should not have child nodes.");
+} else {
+ ok(false, "Should have gotten a node.");
+}
+
+
+SimpleTest.executeSoon(function() {
+ window.examiner.remove();
+ SimpleTest.finish();
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_innerhtml_sanitizer.xhtml b/dom/security/test/general/test_innerhtml_sanitizer.xhtml
new file mode 100644
index 0000000000..4d938bc23b
--- /dev/null
+++ b/dom/security/test/general/test_innerhtml_sanitizer.xhtml
@@ -0,0 +1,73 @@
+<!DOCTYPE HTML>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Test for Bug 1667113</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1667113">Mozilla Bug 1667113</a>
+<div></div>
+<script><![CDATA[
+SimpleTest.waitForExplicitFinish();
+
+// Please note that 'fakeServer' does not exist because the test relies
+// on "csp-on-violate-policy" , and "specialpowers-http-notify-request"
+// which fire if either the request is blocked or fires. The test does
+// not rely on the result of the load.
+
+function fail() {
+ ok(false, "Should not call this")
+}
+
+function examiner() {
+ SpecialPowers.addObserver(this, "csp-on-violate-policy");
+ SpecialPowers.addObserver(this, "specialpowers-http-notify-request");
+}
+examiner.prototype = {
+ observe(subject, topic, data) {
+ if (topic === "csp-on-violate-policy") {
+ let asciiSpec = SpecialPowers.getPrivilegedProps(
+ SpecialPowers.do_QueryInterface(subject, "nsIURI"),
+ "asciiSpec");
+ if (asciiSpec.includes("fakeServer")) {
+ ok (false, "Should not attempt fetch, not even blocked by CSP.");
+ }
+ }
+
+ if (topic === "specialpowers-http-notify-request") {
+ if (data.includes("fakeServer")) {
+ ok (false, "Should not try fetch");
+ }
+ }
+ },
+ remove() {
+ SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+ SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
+ }
+}
+
+window.examiner = new examiner();
+
+let div = document.getElementsByTagName("div")[0];
+div.innerHTML = "<svg xmlns='http://www.w3.org/2000/svg'><style><title><audio xmlns='http://www.w3.org/1999/xhtml' src='fakeServer' onerror='fail()' onload='fail()'></audio></title></style></svg>";
+
+let svg = div.firstChild;
+is(svg.nodeName, "svg", "Node name should be svg");
+
+let style = svg.firstChild;
+if (style) {
+ is(style.firstChild, null, "Style should not have child nodes.");
+} else {
+ ok(false, "Should have gotten a node.");
+}
+
+
+SimpleTest.executeSoon(function() {
+ window.examiner.remove();
+ SimpleTest.finish();
+});
+
+]]></script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_meta_referrer.html b/dom/security/test/general/test_meta_referrer.html
new file mode 100644
index 0000000000..f5e8b649f4
--- /dev/null
+++ b/dom/security/test/general/test_meta_referrer.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1704473 - Remove head requirement for meta name=referrer</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<iframe id="frame_meta_in_head"></iframe>
+<iframe id="frame_meta_notin_head"></iframe>
+
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+let testCounter = 0;
+function checkTestsDone() {
+ testCounter++;
+ if(testCounter == 2) {
+ SimpleTest.finish();
+ }
+}
+var script = SpecialPowers.loadChromeScript(() => {
+ /* eslint-env mozilla/chrome-script */
+ let counter = 0;
+ Services.obs.addObserver(function onExamResp(subject, topic, data) {
+ let channel = subject.QueryInterface(Ci.nsIHttpChannel);
+ if (!channel.URI.spec.startsWith("https://example.com") || counter >= 2) {
+ return;
+ }
+
+ let refererHeaderSet = false;
+ try {
+ channel.getRequestHeader("referer");
+ refererHeaderSet = true;
+ } catch (e) {
+ refererHeaderSet = false;
+ }
+ ok(!refererHeaderSet, "the referer header should not be set");
+ counter++;
+ sendAsyncMessage("checked-referer-header");
+ }, "http-on-stop-request");
+});
+
+script.addMessageListener("checked-referer-header", checkTestsDone);
+
+let frame1 = document.getElementById("frame_meta_in_head");
+frame1.src = "/tests/dom/security/test/general/file_meta_referrer_in_head.html";
+let frame2 = document.getElementById("frame_meta_notin_head");
+frame2.src = "/tests/dom/security/test/general/file_meta_referrer_notin_head.html";
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_nosniff.html b/dom/security/test/general/test_nosniff.html
new file mode 100644
index 0000000000..a22386aea0
--- /dev/null
+++ b/dom/security/test/general/test_nosniff.html
@@ -0,0 +1,88 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 471020 - Add X-Content-Type-Options: nosniff support to Firefox</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <!-- add the two css tests -->
+ <link rel="stylesheet" id="cssCorrectType">
+ <link rel="stylesheet" id="cssWrongType">
+</head>
+<body>
+
+<!-- add the two script tests -->
+<script id="scriptCorrectType"></script>
+<script id="scriptWrongType"></script>
+
+<script class="testbody" type="text/javascript">
+/* Description of the test:
+ * We load 2 css files, 2 script files and 2 image files, where
+ * the sever either responds with the right mime type or
+ * the wrong mime type for each test.
+ */
+
+SimpleTest.waitForExplicitFinish();
+const NUM_TESTS = 4;
+
+var testCounter = 0;
+function checkFinish() {
+ testCounter++;
+ if (testCounter === NUM_TESTS) {
+ SimpleTest.finish();
+ }
+}
+
+ // 1) Test CSS with correct mime type
+ var cssCorrectType = document.getElementById("cssCorrectType");
+ cssCorrectType.onload = function() {
+ ok(true, "style nosniff correct type should load");
+ checkFinish();
+ }
+ cssCorrectType.onerror = function() {
+ ok(false, "style nosniff correct type should load");
+ checkFinish();
+ }
+ cssCorrectType.href = "file_nosniff_testserver.sjs?cssCorrectType";
+
+ // 2) Test CSS with wrong mime type
+ var cssWrongType = document.getElementById("cssWrongType");
+ cssWrongType.onload = function() {
+ ok(false, "style nosniff wrong type should not load");
+ checkFinish();
+ }
+ cssWrongType.onerror = function() {
+ ok(true, "style nosniff wrong type should not load");
+ checkFinish();
+ }
+ cssWrongType.href = "file_nosniff_testserver.sjs?cssWrongType";
+
+ // 3) Test SCRIPT with correct mime type
+ var scriptCorrectType = document.getElementById("scriptCorrectType");
+ scriptCorrectType.onload = function() {
+ ok(true, "script nosniff correct type should load");
+ checkFinish();
+ }
+ scriptCorrectType.onerror = function() {
+ ok(false, "script nosniff correct type should load");
+ checkFinish();
+ }
+ scriptCorrectType.src = "file_nosniff_testserver.sjs?scriptCorrectType";
+
+ // 4) Test SCRIPT with wrong mime type
+ var scriptWrongType = document.getElementById("scriptWrongType");
+ scriptWrongType.onload = function() {
+ ok(false, "script nosniff wrong type should not load");
+ checkFinish();
+ }
+ scriptWrongType.onerror = function() {
+ ok(true, "script nosniff wrong type should not load");
+ checkFinish();
+ }
+ scriptWrongType.src = "file_nosniff_testserver.sjs?scriptWrongType";
+
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_nosniff_navigation.html b/dom/security/test/general/test_nosniff_navigation.html
new file mode 100644
index 0000000000..6710f4f5b9
--- /dev/null
+++ b/dom/security/test/general/test_nosniff_navigation.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+
+<head>
+ <title>Bug 1428473 Support X-Content-Type-Options: nosniff when navigating</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+
+<body>
+
+ <!-- add the two script tests -->
+ <script id="scriptCorrectType"></script>
+ <script id="scriptWrongType"></script>
+
+ <script class="testbody" type="text/javascript">
+ /* Description of the test:
+ * We're testing if Firefox respects the nosniff Header for Top-Level
+ * Navigations.
+ * If Firefox cant Display the Page, it will prompt a download
+ * and the URL of the Page will be about:blank.
+ * So we will try to open different content send with
+ * no-mime, mismatched-mime and garbage-mime types.
+ *
+ */
+
+ SimpleTest.waitForExplicitFinish();
+
+ window.addEventListener("load", async () => {
+ window.open("window_nosniff_navigation.html");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_same_site_cookies_about.html b/dom/security/test/general/test_same_site_cookies_about.html
new file mode 100644
index 0000000000..faf2caab9a
--- /dev/null
+++ b/dom/security/test/general/test_same_site_cookies_about.html
@@ -0,0 +1,116 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1454721 - Add same-site cookie test for about:blank and about:srcdoc</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<img id="cookieImage">
+<iframe id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/*
+ * Description of the test:
+ * 1) We load an image from http://mochi.test which sets a same site cookie
+ * 2) We then load the following iframes:
+ * (a) cross-origin iframe
+ * (b) same-origin iframe
+ * which both load a:
+ * * nested about:srcdoc frame and nested about:blank frame
+ * * navigate about:srcdoc frame and navigate about:blank frame
+ * 3) We evaluate that the same-site cookie is available in the same-origin case.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+const SAME_ORIGIN = "http://mochi.test:8888/"
+const CROSS_ORIGIN = "http://example.com/";
+const PATH = "tests/dom/security/test/general/file_same_site_cookies_about.sjs";
+
+let curTest = 0;
+
+var tests = [
+ // NAVIGATION TESTS
+ {
+ description: "nested same origin iframe about:srcdoc navigation [mochi.test -> mochi.test -> about:srcdoc -> mochi.test]",
+ frameSRC: SAME_ORIGIN + PATH + "?loadsrcdocframeNav",
+ result: "myKey=mySameSiteAboutCookie", // cookie should be set for baseline test
+ },
+ {
+ description: "nested cross origin iframe about:srcdoc navigation [mochi.test -> example.com -> about:srcdoc -> mochi.test]",
+ frameSRC: CROSS_ORIGIN + PATH + "?loadsrcdocframeNav",
+ result: "", // no same-site cookie should be available
+ },
+ {
+ description: "nested same origin iframe about:blank navigation [mochi.test -> mochi.test -> about:blank -> mochi.test]",
+ frameSRC: SAME_ORIGIN + PATH + "?loadblankframeNav",
+ result: "myKey=mySameSiteAboutCookie", // cookie should be set for baseline test
+ },
+ {
+ description: "nested cross origin iframe about:blank navigation [mochi.test -> example.com -> about:blank -> mochi.test]",
+ frameSRC: CROSS_ORIGIN + PATH + "?loadblankframeNav",
+ result: "", // no same-site cookie should be available
+ },
+ // INCLUSION TESTS
+ {
+ description: "nested same origin iframe about:srcdoc inclusion [mochi.test -> mochi.test -> about:srcdoc -> mochi.test]",
+ frameSRC: SAME_ORIGIN + PATH + "?loadsrcdocframeInc",
+ result: "myKey=mySameSiteAboutCookie", // cookie should be set for baseline test
+ },
+ {
+ description: "nested cross origin iframe about:srcdoc inclusion [mochi.test -> example.com -> about:srcdoc -> mochi.test]",
+ frameSRC: CROSS_ORIGIN + PATH + "?loadsrcdocframeInc",
+ result: "", // no same-site cookie should be available
+ },
+ {
+ description: "nested same origin iframe about:blank inclusion [mochi.test -> mochi.test -> about:blank -> mochi.test]",
+ frameSRC: SAME_ORIGIN + PATH + "?loadblankframeInc",
+ result: "myKey=mySameSiteAboutCookie", // cookie should be set for baseline test
+ },
+ {
+ description: "nested cross origin iframe about:blank inclusion [mochi.test -> example.com -> about:blank -> mochi.test]",
+ frameSRC: CROSS_ORIGIN + PATH + "?loadblankframeInc",
+ result: "", // no same-site cookie should be available
+ },
+];
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ is(event.data.result, tests[curTest].result, tests[curTest].description);
+ curTest += 1;
+
+ // lets see if we ran all the tests
+ if (curTest == tests.length) {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+ return;
+ }
+ // otherwise it's time to run the next test
+ setCookieAndInitTest();
+}
+
+function setupQueryResultAndRunTest() {
+ let testframe = document.getElementById("testframe");
+ testframe.src = tests[curTest].frameSRC + curTest;
+}
+
+function setCookieAndInitTest() {
+ var cookieImage = document.getElementById("cookieImage");
+ cookieImage.onload = function() {
+ ok(true, "trying to set cookie for test (" + tests[curTest].description + ")");
+ setupQueryResultAndRunTest();
+ }
+ cookieImage.onerror = function() {
+ ok(false, "could not load image for test (" + tests[curTest].description + ")");
+ }
+ cookieImage.src = SAME_ORIGIN + PATH + "?setSameSiteCookie" + curTest;
+}
+
+// fire up the test
+setCookieAndInitTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_same_site_cookies_cross_origin_context.html b/dom/security/test/general/test_same_site_cookies_cross_origin_context.html
new file mode 100644
index 0000000000..9294a3d030
--- /dev/null
+++ b/dom/security/test/general/test_same_site_cookies_cross_origin_context.html
@@ -0,0 +1,93 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1452496 - Do not allow same-site cookies in cross site context</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<img id="cookieImage">
+<iframe id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/*
+ * Description of the test:
+ * 1) We load an image from http://example.com which tries to
+ * a) a same site cookie
+ * b) a regular cookie
+ * in the context of http://mochi.test
+ * 2) We load an iframe from http://example.com and check if the cookie
+ * is available.
+ * 3) We observe that:
+ * (a) same site cookie has been discarded in a cross origin context.
+ * (b) the regular cookie is available.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+const CROSS_ORIGIN = "http://example.com/";
+const PATH = "tests/dom/security/test/general/file_same_site_cookies_cross_origin_context.sjs";
+
+let curTest = 0;
+
+var tests = [
+ {
+ description: "regular cookie in cross origin context",
+ imgSRC: CROSS_ORIGIN + PATH + "?setRegularCookie",
+ frameSRC: CROSS_ORIGIN + PATH + "?loadFrame",
+ result: "myKey=regularCookie",
+ },
+ {
+ description: "same-site cookie in cross origin context",
+ imgSRC: CROSS_ORIGIN + PATH + "?setSameSiteCookie",
+ frameSRC: CROSS_ORIGIN + PATH + "?loadFrame",
+ result: "", // no cookie should be set
+ },
+];
+
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ is(event.data.result, tests[curTest].result, tests[curTest].description);
+ curTest += 1;
+
+ // lets see if we ran all the tests
+ if (curTest == tests.length) {
+ window.removeEventListener("message", receiveMessage);
+ SpecialPowers.clearUserPref("network.cookie.sameSite.laxByDefault");
+ SimpleTest.finish();
+ return;
+ }
+ // otherwise it's time to run the next test
+ setCookieAndInitTest();
+}
+
+function setupQueryResultAndRunTest() {
+ let testframe = document.getElementById("testframe");
+ testframe.src = tests[curTest].frameSRC + curTest;
+}
+
+function setCookieAndInitTest() {
+ var cookieImage = document.getElementById("cookieImage");
+ cookieImage.onload = function() {
+ ok(true, "trying to set cookie for test (" + tests[curTest].description + ")");
+ setupQueryResultAndRunTest();
+ }
+ cookieImage.onerror = function() {
+ ok(false, "could not load image for test (" + tests[curTest].description + ")");
+ }
+ cookieImage.src = tests[curTest].imgSRC + curTest;
+}
+
+// fire up the test
+SpecialPowers.pushPrefEnv({
+ "set": [
+ // Bug 1617611: Fix all the tests broken by "cookies SameSite=lax by default"
+ ["network.cookie.sameSite.laxByDefault", false],
+ ]
+}, setCookieAndInitTest);
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_same_site_cookies_from_script.html b/dom/security/test/general/test_same_site_cookies_from_script.html
new file mode 100644
index 0000000000..74c38b6249
--- /dev/null
+++ b/dom/security/test/general/test_same_site_cookies_from_script.html
@@ -0,0 +1,86 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1452496 - Do not allow same-site cookies in cross site context</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<iframe id="setCookieFrame"></iframe>
+<iframe id="getCookieFrame"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/*
+ * Description of the test:
+ * 1) We load an iframe which tries to set a same site cookie using an
+ * inline script in top-level context of http://mochi.test.
+ * 2) We load an iframe from http://example.com and check if the cookie
+ * is available.
+ * 3) We observe that:
+ * (a) same site cookie is available in same origin context.
+ * (a) same site cookie has been discarded in a cross origin context.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+const SAME_ORIGIN = "http://mochi.test:8888/";
+const CROSS_ORIGIN = "http://example.com/";
+const PATH = "tests/dom/security/test/general/file_same_site_cookies_from_script.sjs";
+
+let curTest = 0;
+
+var tests = [
+ {
+ description: "same-site cookie inline script within same-site context",
+ setCookieSrc: SAME_ORIGIN + PATH + "?setSameSiteCookieUsingInlineScript",
+ getCookieSrc: SAME_ORIGIN + PATH + "?getCookieFrame",
+ result: "myKey=sameSiteCookieInlineScript",
+ },
+ {
+ description: "same-site cookie inline script within cross-site context",
+ setCookieSrc: CROSS_ORIGIN + PATH + "?setSameSiteCookieUsingInlineScript",
+ getCookieSrc: CROSS_ORIGIN + PATH + "?getCookieFrame",
+ result: "", // same-site cookie should be discarded in cross site context
+ },
+];
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ is(event.data.result, tests[curTest].result, tests[curTest].description);
+ curTest += 1;
+
+ // lets see if we ran all the tests
+ if (curTest == tests.length) {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+ return;
+ }
+ // otherwise it's time to run the next test
+ setCookieAndInitTest();
+}
+
+function setupQueryResultAndRunTest() {
+ let getCookieFrame = document.getElementById("getCookieFrame");
+ getCookieFrame.src = tests[curTest].getCookieSrc + curTest;
+}
+
+function setCookieAndInitTest() {
+ var setCookieFrame = document.getElementById("setCookieFrame");
+ setCookieFrame.onload = function() {
+ ok(true, "trying to set cookie for test (" + tests[curTest].description + ")");
+ setupQueryResultAndRunTest();
+ }
+ setCookieFrame.onerror = function() {
+ ok(false, "could not load image for test (" + tests[curTest].description + ")");
+ }
+ setCookieFrame.src = tests[curTest].setCookieSrc + curTest;
+}
+
+// fire up the test
+setCookieAndInitTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_same_site_cookies_iframe.html b/dom/security/test/general/test_same_site_cookies_iframe.html
new file mode 100644
index 0000000000..45d5d5830a
--- /dev/null
+++ b/dom/security/test/general/test_same_site_cookies_iframe.html
@@ -0,0 +1,168 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1454027 - Update SameSite cookie handling inside iframes</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<img id="cookieImage">
+<iframe id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/*
+ * Description of the test:
+ * 1) We load an image from http://mochi.test which sets a same site cookie
+ * 2) We then load the following iframes:
+ * (a) cross-origin iframe
+ * (b) sandboxed iframe
+ * (c) data: URI iframe
+ * (d) same origin iframe which loads blob: URI iframe (to simulate same origin blobs)
+ * (e) cross origin iframe which loads blob: URI iframe (to simulate cross origin blobs)
+ * which all:
+ * * navigate the iframe to http://mochi.test
+ * * include another iframe from http://mochi.test
+ * 3) We observe that none of the nested iframes have access to the same-site cookie.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+const SAME_ORIGIN = "http://mochi.test:8888/"
+const CROSS_ORIGIN = "http://example.com/";
+const PATH = "tests/dom/security/test/general/";
+const SERVER_FILE = "file_same_site_cookies_iframe.sjs";
+
+const NESTED_DATA_IFRAME_NAVIGATION = `
+ data:text/html,
+ <html>
+ <body>
+ <a id="testlink" href="http://mochi.test:8888/tests/dom/security/test/general/file_same_site_cookies_iframe.sjs"></a>
+ <script type="application/javascript">
+ let link = document.getElementById("testlink");
+ link.click();
+ <\/script>
+ </body>
+ </html>`;
+
+const NESTED_DATA_IFRAME_INCLUSION = `
+ data:text/html,
+ <html>
+ <body>
+ <script type="application/javascript">
+ window.addEventListener("message", receiveMessage);
+ function receiveMessage(event) {
+ window.removeEventListener("message", receiveMessage);
+ window.parent.postMessage({result: event.data.result}, '*');
+ }
+ <\/script>
+ <iframe src="http://mochi.test:8888/tests/dom/security/test/general/file_same_site_cookies_iframe.sjs"></iframe>
+ </body>
+ </html>`;
+
+let curTest = 0;
+
+var tests = [
+ // NAVIGATION TESTS
+ {
+ description: "nested same origin iframe navigation [mochi.test -> mochi.test -> mochi.test]",
+ frameSRC: SAME_ORIGIN + PATH + SERVER_FILE + "?nestedIframeNavigation",
+ result: "myKey=mySameSiteIframeTestCookie", // cookie should be set for baseline test
+ },
+ {
+ description: "nested cross origin iframe navigation [mochi.test -> example.com -> mochi.test]",
+ frameSRC: CROSS_ORIGIN + PATH + SERVER_FILE + "?nestedIframeNavigation",
+ result: "", // no cookie should be set
+ },
+ {
+ description: "nested sandboxed iframe navigation [mochi.test -> sandbox -> mochi.test]",
+ frameSRC: CROSS_ORIGIN + PATH + SERVER_FILE + "?nestedSandboxIframeNavigation",
+ result: "", // no cookie should be set
+ },
+ {
+ description: "nested data iframe navigation [mochi.test -> data: -> mochi.test]",
+ frameSRC: NESTED_DATA_IFRAME_NAVIGATION,
+ result: "", // no cookie should be set
+ },
+ {
+ description: "nested same site blob iframe navigation [mochi.test -> mochi.test -> blob: -> mochi.test]",
+ frameSRC: SAME_ORIGIN + PATH + "file_same_site_cookies_blob_iframe_navigation.html",
+ result: "myKey=mySameSiteIframeTestCookie", // cookie should be set, blobs inherit security context
+ },
+ {
+ description: "nested cross site blob iframe navigation [mochi.test -> example.com -> blob: -> mochi.test]",
+ frameSRC: CROSS_ORIGIN + PATH + "file_same_site_cookies_blob_iframe_navigation.html",
+ result: "", // no cookie should be set
+ },
+ // INCLUSION TESTS
+ {
+ description: "nested same origin iframe inclusion [mochi.test -> mochi.test -> mochi.test]",
+ frameSRC: SAME_ORIGIN + PATH + SERVER_FILE + "?nestedIframeInclusion",
+ result: "myKey=mySameSiteIframeTestCookie", // cookie should be set for baseline test
+ },
+ {
+ description: "nested cross origin iframe inclusion [mochi.test -> example.com -> mochi.test]",
+ frameSRC: CROSS_ORIGIN + PATH + SERVER_FILE + "?nestedIframeInclusion",
+ result: "", // no cookie should be set
+ },
+ {
+ description: "nested sandboxed iframe inclusion [mochi.test -> sandbox -> mochi.test]",
+ frameSRC: CROSS_ORIGIN + PATH + SERVER_FILE + "?nestedSandboxIframeInclusion",
+ result: "", // no cookie should be set
+ },
+ {
+ description: "nested data iframe inclusion [mochi.test -> data: -> mochi.test]",
+ frameSRC: NESTED_DATA_IFRAME_INCLUSION,
+ result: "", // no cookie should be set
+ },
+ {
+ description: "nested same site blob iframe inclusion [mochi.test -> mochi.test -> blob: -> mochi.test]",
+ frameSRC: SAME_ORIGIN + PATH + "file_same_site_cookies_blob_iframe_inclusion.html",
+ result: "myKey=mySameSiteIframeTestCookie", // cookie should be set, blobs inherit security context
+ },
+ {
+ description: "same-site cookie, nested cross site blob iframe inclusion [mochi.test -> example.com -> blob: -> mochi.test]",
+ frameSRC: CROSS_ORIGIN + PATH + "file_same_site_cookies_blob_iframe_inclusion.html",
+ result: "", // no cookie should be set
+ },
+];
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ is(event.data.result, tests[curTest].result, tests[curTest].description);
+ curTest += 1;
+
+ // // lets see if we ran all the tests
+ if (curTest == tests.length) {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+ return;
+ }
+ // otherwise it's time to run the next test
+ setCookieAndInitTest();
+}
+
+function setupQueryResultAndRunTest() {
+ let testframe = document.getElementById("testframe");
+ testframe.src = tests[curTest].frameSRC;
+}
+
+function setCookieAndInitTest() {
+ var cookieImage = document.getElementById("cookieImage");
+ cookieImage.onload = function() {
+ ok(true, "trying to set cookie for test (" + tests[curTest].description + ")");
+ setupQueryResultAndRunTest();
+ }
+ cookieImage.onerror = function() {
+ ok(false, "could not load image for test (" + tests[curTest].description + ")");
+ }
+ // appending math.random to avoid any unexpected caching behavior
+ cookieImage.src = SAME_ORIGIN + PATH + SERVER_FILE + "?setSameSiteCookie" + Math.random();
+}
+
+// fire up the test
+setCookieAndInitTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_same_site_cookies_laxByDefault.html b/dom/security/test/general/test_same_site_cookies_laxByDefault.html
new file mode 100644
index 0000000000..9fd0d0b704
--- /dev/null
+++ b/dom/security/test/general/test_same_site_cookies_laxByDefault.html
@@ -0,0 +1,85 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1551798 - SameSite=lax by default</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+
+const CROSS_ORIGIN = "http://example.com/";
+const PATH = "tests/dom/security/test/general/closeWindow.sjs";
+
+async function realTest(noneRequiresSecure) {
+ let types = ["unset", "lax", "none"];
+ for (let i = 0; i < types.length; ++i) {
+ info("Loading a new top-level page (" + types[i] + ")");
+ await new Promise(resolve => {
+ window.addEventListener("message", _ => {
+ resolve();
+ }, { once: true });
+ window.open(CROSS_ORIGIN + PATH + "?" + types[i]);
+ });
+ }
+
+ info("Check cookies");
+ let chromeScript = SpecialPowers.loadChromeScript(() => {
+ /* eslint-env mozilla/chrome-script */
+ const {sendAsyncMessage} = this;
+ let cookies = { test: null, test2: null, test3: null };
+
+ for (let cookie of Services.cookies.cookies) {
+ if (cookie.host != "example.com") continue;
+
+ if (cookie.name == "test" && cookie.value == "wow") {
+ cookies.test = cookie.sameSite == Ci.nsICookie.SAMESITE_LAX ? 'lax' : 'none';
+ }
+
+ if (cookie.name == "test2" && cookie.value == "wow2") {
+ cookies.test2 = cookie.sameSite == Ci.nsICookie.SAMESITE_LAX ? 'lax' : 'none';
+ }
+
+ if (cookie.name == "test3" && cookie.value == "wow3") {
+ cookies.test3 = cookie.sameSite == Ci.nsICookie.SAMESITE_LAX ? 'lax' : 'none';
+ }
+ }
+
+ Services.cookies.removeAll();
+ sendAsyncMessage('result', cookies);
+ });
+
+ let cookies = await new Promise(resolve => {
+ chromeScript.addMessageListener('result', cookies => {
+ chromeScript.destroy();
+ resolve(cookies);
+ });
+ });
+
+ is(cookies.test, "lax", "Cookie set without samesite is lax by default");
+ if (noneRequiresSecure) {
+ is(cookies.test2, null, "Cookie set with samesite none, but not secure");
+ } else {
+ is(cookies.test2, "none", "Cookie set with samesite none");
+ }
+ is(cookies.test3, "lax", "Cookie set with samesite lax");
+}
+
+SpecialPowers.pushPrefEnv({"set": [
+ ["network.cookie.sameSite.laxByDefault", true],
+ ["network.cookie.sameSite.noneRequiresSecure", false],
+]}).then(_ => {
+ return realTest(false);
+}).then(_ => {
+ return SpecialPowers.pushPrefEnv({"set": [
+ ["network.cookie.sameSite.laxByDefault", true],
+ ["network.cookie.sameSite.noneRequiresSecure", true]]});
+}).then(_ => {
+ return realTest(true);
+}).then(SimpleTest.finish);
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_same_site_cookies_redirect.html b/dom/security/test/general/test_same_site_cookies_redirect.html
new file mode 100644
index 0000000000..59f98b2263
--- /dev/null
+++ b/dom/security/test/general/test_same_site_cookies_redirect.html
@@ -0,0 +1,101 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1453814 - Do not allow same-site cookies for cross origin redirect</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<img id="cookieImage">
+<iframe id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/*
+ * Description of the test:
+ * 1) We load an image from http://mochi.test which set a same site cookie
+ * 2) We then load an iframe that redirects
+ * (a) from same-origin to cross-origin
+ * (b) from cross-origin to same-origin
+ * 3) We observe that in both cases same-site cookies should not be send
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+const SAME_ORIGIN = location.origin + "/";
+const CROSS_ORIGIN = "http://example.com/";
+const PATH = "tests/dom/security/test/general/file_same_site_cookies_redirect.sjs";
+
+let curTest = 0;
+
+var tests = [
+ {
+ description: "baseline: same-site cookie, redirect same-site to same-site",
+ imgSRC: SAME_ORIGIN + PATH + "?setSameSiteCookie",
+ frameSRC: SAME_ORIGIN + PATH + "?sameToSameRedirect",
+ result: "myKey=strictSameSiteCookie",
+ },
+ {
+ description: "same-site cookie, redirect same-site to cross-site",
+ imgSRC: SAME_ORIGIN + PATH + "?setSameSiteCookie",
+ frameSRC: SAME_ORIGIN + PATH + "?sameToCrossRedirect",
+ result: "", // no cookie should be set
+ },
+ {
+ description: "same-site cookie, redirect cross-site to same-site",
+ imgSRC: SAME_ORIGIN + PATH + "?setSameSiteCookie",
+ frameSRC: CROSS_ORIGIN + PATH + "?crossToSameRedirect",
+ result: "", // no cookie should be set
+ },
+ {
+ description: "same-site cookie, meta redirect same-site to cross-site",
+ imgSRC: SAME_ORIGIN + PATH + "?setSameSiteCookie",
+ frameSRC: SAME_ORIGIN + PATH + "?sameToCrossRedirectMeta",
+ result: "", // no cookie should be set
+ },
+ {
+ description: "same-site cookie, meta redirect cross-site to same-site",
+ imgSRC: SAME_ORIGIN + PATH + "?setSameSiteCookie",
+ frameSRC: CROSS_ORIGIN + PATH + "?crossToSameRedirectMeta",
+ result: "", // no cookie should be set
+ },
+];
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ is(event.data.result, tests[curTest].result, tests[curTest].description);
+ curTest += 1;
+
+ // // lets see if we ran all the tests
+ if (curTest == tests.length) {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+ return;
+ }
+ // otherwise it's time to run the next test
+ setCookieAndInitTest();
+}
+
+function setupQueryResultAndRunTest() {
+ let testframe = document.getElementById("testframe");
+ testframe.src = tests[curTest].frameSRC;
+}
+
+function setCookieAndInitTest() {
+ var cookieImage = document.getElementById("cookieImage");
+ cookieImage.onload = function() {
+ ok(true, "trying to set cookie for test (" + tests[curTest].description + ")");
+ setupQueryResultAndRunTest();
+ }
+ cookieImage.onerror = function() {
+ ok(false, "could not load image for test (" + tests[curTest].description + ")");
+ }
+ cookieImage.src = tests[curTest].imgSRC;
+}
+
+// fire up the test
+setCookieAndInitTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_same_site_cookies_subrequest.html b/dom/security/test/general/test_same_site_cookies_subrequest.html
new file mode 100644
index 0000000000..304dbafa9a
--- /dev/null
+++ b/dom/security/test/general/test_same_site_cookies_subrequest.html
@@ -0,0 +1,113 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1286861 - Test same site cookies on subrequests</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<img id="cookieImage">
+<iframe id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/*
+ * Description of the test:
+ * 1) We load an image from http://mochi.test which sets a same site cookie
+ * 2) We load an iframe from:
+ * * http://mochi.test which loads another image from http://mochi.test
+ * * http://example.com which loads another image from http://mochi.test
+ * 3) We observe that the same site cookie is sent in the same origin case,
+ * but not in the cross origin case.
+ *
+ * In detail:
+ * We perform an XHR request to the *.sjs file which is processed async on
+ * the server and waits till the image request has been processed by the server.
+ * Once the image requets was processed, the server responds to the initial
+ * XHR request with the expecuted result (the cookie value).
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+const SAME_ORIGIN = "http://mochi.test:8888/";
+const CROSS_ORIGIN = "http://example.com/";
+const PATH = "tests/dom/security/test/general/file_same_site_cookies_subrequest.sjs";
+
+let curTest = 0;
+
+var tests = [
+ {
+ description: "same origin site using cookie policy 'samesite=strict'",
+ imgSRC: SAME_ORIGIN + PATH + "?setStrictSameSiteCookie",
+ frameSRC: SAME_ORIGIN + PATH + "?loadFrame",
+ result: "myKey=strictSameSiteCookie",
+ },
+ {
+ description: "cross origin site using cookie policy 'samesite=strict'",
+ imgSRC: SAME_ORIGIN + PATH + "?setStrictSameSiteCookie",
+ frameSRC: CROSS_ORIGIN + PATH + "?loadFrame",
+ result: "myKey=noCookie",
+ },
+ {
+ description: "same origin site using cookie policy 'samesite=lax'",
+ imgSRC: SAME_ORIGIN + PATH + "?setLaxSameSiteCookie",
+ frameSRC: SAME_ORIGIN + PATH + "?loadFrame",
+ result: "myKey=laxSameSiteCookie",
+ },
+ {
+ description: "cross origin site using cookie policy 'samesite=lax'",
+ imgSRC: SAME_ORIGIN + PATH + "?setLaxSameSiteCookie",
+ frameSRC: CROSS_ORIGIN + PATH + "?loadFrame",
+ result: "myKey=noCookie",
+ },
+];
+
+function checkResult(aCookieVal) {
+ is(aCookieVal, tests[curTest].result, tests[curTest].description);
+ curTest += 1;
+
+ // lets see if we ran all the tests
+ if (curTest == tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+ // otherwise it's time to run the next test
+ setCookieAndInitTest();
+}
+
+function setupQueryResultAndRunTest() {
+ var myXHR = new XMLHttpRequest();
+ myXHR.open("GET", "file_same_site_cookies_subrequest.sjs?queryresult" + curTest);
+ myXHR.onload = function(e) {
+ checkResult(myXHR.responseText);
+ }
+ myXHR.onerror = function(e) {
+ ok(false, "could not query results from server (" + e.message + ")");
+ }
+ myXHR.send();
+
+ // give it some time and load the test frame
+ SimpleTest.executeSoon(function() {
+ let testframe = document.getElementById("testframe");
+ testframe.src = tests[curTest].frameSRC + curTest;
+ });
+}
+
+function setCookieAndInitTest() {
+ var cookieImage = document.getElementById("cookieImage");
+ cookieImage.onload = function() {
+ ok(true, "set cookie for test (" + tests[curTest].description + ")");
+ setupQueryResultAndRunTest();
+ }
+ cookieImage.onerror = function() {
+ ok(false, "could not set cookie for test (" + tests[curTest].description + ")");
+ }
+ cookieImage.src = tests[curTest].imgSRC + curTest;
+}
+
+// fire up the test
+setCookieAndInitTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_same_site_cookies_toplevel_nav.html b/dom/security/test/general/test_same_site_cookies_toplevel_nav.html
new file mode 100644
index 0000000000..aba825916b
--- /dev/null
+++ b/dom/security/test/general/test_same_site_cookies_toplevel_nav.html
@@ -0,0 +1,117 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1286861 - Test same site cookies on top-level navigations</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<img id="cookieImage">
+
+<script class="testbody" type="text/javascript">
+
+/*
+ * Description of the test:
+ * 1) We load an image from http://mochi.test which sets a same site cookie
+ * 2) We open a new window to
+ * * a same origin location
+ * * a cross origin location
+ * 3) We observe that the same site cookie is sent in the same origin case,
+ * but not in the cross origin case, unless the policy = 'lax', which should
+ * send the cookie in a top-level navigation case.
+ *
+ * In detail:
+ * We perform an XHR request to the *.sjs file which is processed async on
+ * the server and waits till the image request has been processed by the server.
+ * Once the image requets was processed, the server responds to the initial
+ * XHR request with the expecuted result (the cookie value).
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+const SAME_ORIGIN = "http://mochi.test:8888/";
+const CROSS_ORIGIN = "http://example.com/";
+const PATH = "tests/dom/security/test/general/file_same_site_cookies_toplevel_nav.sjs";
+
+let curTest = 0;
+
+let currentWindow;
+var tests = [
+ {
+ description: "same origin navigation using cookie policy 'samesite=strict'",
+ imgSRC: SAME_ORIGIN + PATH + "?setStrictSameSiteCookie",
+ frameSRC: SAME_ORIGIN + PATH + "?loadFrame",
+ result: "myKey=strictSameSiteCookie",
+ },
+ {
+ description: "cross origin navigation using cookie policy 'samesite=strict'",
+ imgSRC: SAME_ORIGIN + PATH + "?setStrictSameSiteCookie",
+ frameSRC: CROSS_ORIGIN + PATH + "?loadFrame",
+ result: "myKey=noCookie",
+ },
+ {
+ description: "same origin navigation using cookie policy 'samesite=lax'",
+ imgSRC: SAME_ORIGIN + PATH + "?setLaxSameSiteCookie",
+ frameSRC: SAME_ORIGIN + PATH + "?loadFrame",
+ result: "myKey=laxSameSiteCookie",
+ },
+ {
+ description: "cross origin navigation using cookie policy 'samesite=lax'",
+ imgSRC: SAME_ORIGIN + PATH + "?setLaxSameSiteCookie",
+ frameSRC: CROSS_ORIGIN + PATH + "?loadFrame",
+ result: "myKey=laxSameSiteCookie",
+ },
+];
+
+function checkResult(aCookieVal) {
+ if(currentWindow){
+ currentWindow.close();
+ currentWindow= null;
+ }
+ is(aCookieVal, tests[curTest].result, tests[curTest].description);
+ curTest += 1;
+
+ // lets see if we ran all the tests
+ if (curTest == tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+ // otherwise it's time to run the next test
+ setCookieAndInitTest();
+}
+
+function setupQueryResultAndRunTest() {
+ var myXHR = new XMLHttpRequest();
+ myXHR.open("GET", "file_same_site_cookies_toplevel_nav.sjs?queryresult" + curTest);
+ myXHR.onload = function(e) {
+ checkResult( myXHR.responseText);
+ }
+ myXHR.onerror = function(e) {
+ ok(false, "could not query results from server (" + e.message + ")");
+ }
+ myXHR.send();
+
+ // give it some time and load the test window
+ SimpleTest.executeSoon(function() {
+ currentWindow = window.open(tests[curTest].frameSRC + curTest);
+ });
+}
+
+function setCookieAndInitTest() {
+ var cookieImage = document.getElementById("cookieImage");
+ cookieImage.onload = function() {
+ ok(true, "set cookie for test (" + tests[curTest].description + ")");
+ setupQueryResultAndRunTest();
+ }
+ cookieImage.onerror = function() {
+ ok(false, "could not set cookie for test (" + tests[curTest].description + ")");
+ }
+ cookieImage.src = tests[curTest].imgSRC + curTest;
+}
+
+// fire up the test
+setCookieAndInitTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_same_site_cookies_toplevel_set_cookie.html b/dom/security/test/general/test_same_site_cookies_toplevel_set_cookie.html
new file mode 100644
index 0000000000..cae2a6174e
--- /dev/null
+++ b/dom/security/test/general/test_same_site_cookies_toplevel_set_cookie.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1454242: Setting samesite cookie should not rely on CookieCommons::IsSameSiteForeign</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<img id="cookieImage">
+<iframe id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/*
+ * Description of the test:
+ * 1) We load a window from example.com which loads a window from mochi.test
+ * which then sets a same-site cookie for mochi.test.
+ * 2) We load an iframe from mochi.test.
+ * 3) We observe that the cookie within (1) was allowed to be set and
+ * is available for mochi.test.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+const SAME_ORIGIN = "http://mochi.test:8888/"
+const CROSS_ORIGIN = "http://example.com/";
+const PATH = "tests/dom/security/test/general/file_same_site_cookies_toplevel_set_cookie.sjs";
+
+let testWin = null;
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ // once the second window (which sets the cookie) loaded, we get a notification
+ // that the test setup is correct and we can now try to query the same-site cookie
+ if (event.data.value === "testSetupComplete") {
+ ok(true, "cookie setup worked");
+ let testframe = document.getElementById("testframe");
+ testframe.src = SAME_ORIGIN + PATH + "?checkCookie";
+ return;
+ }
+
+ // thie second message is the cookie value from verifying the
+ // cookie has been set correctly.
+ is(event.data.value, "myKey=laxSameSiteCookie",
+ "setting same-site cookie on cross origin top-level page");
+
+ window.removeEventListener("message", receiveMessage);
+ testWin.close();
+ SimpleTest.finish();
+}
+
+// fire up the test
+testWin = window.open(CROSS_ORIGIN + PATH + "?loadWin");
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_xfo_error_page.html b/dom/security/test/general/test_xfo_error_page.html
new file mode 100644
index 0000000000..218413b4f9
--- /dev/null
+++ b/dom/security/test/general/test_xfo_error_page.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1626249: Ensure correct display of neterror page for XFO</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="xfo_testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+const XFO_ERROR_PAGE_MSG = "This page has an X-Frame-Options policy that prevents it from being loaded in this context";
+
+let xfo_testframe = document.getElementById("xfo_testframe");
+
+xfo_testframe.onload = function() {
+ let wrappedXFOFrame = SpecialPowers.wrap(xfo_testframe.contentWindow);
+ let frameContentXFO = wrappedXFOFrame.document.body.innerHTML;
+ ok(frameContentXFO.includes(XFO_ERROR_PAGE_MSG), "xfo error page correct");
+ SimpleTest.finish();
+}
+
+xfo_testframe.onerror = function() {
+ ok(false, "sanity: should not fire onerror for xfo_testframe");
+ SimpleTest.finish();
+}
+
+xfo_testframe.src = "file_xfo_error_page.sjs";
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/window_nosniff_navigation.html b/dom/security/test/general/window_nosniff_navigation.html
new file mode 100644
index 0000000000..1287e451b1
--- /dev/null
+++ b/dom/security/test/general/window_nosniff_navigation.html
@@ -0,0 +1,96 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1428473 Support X-Content-Type-Options: nosniff when navigating</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <style>
+ iframe{
+ border: 1px solid orange;
+ }
+ </style>
+
+ <!-- Using Content-Type: */* -->
+ <iframe class="no-mime" src="file_nosniff_navigation.sjs?mime=*%2F*&content=xml"></iframe>
+ <iframe class="no-mime" src="file_nosniff_navigation.sjs?mime=*%2F*&content=html"></iframe>
+ <iframe class="no-mime" src="file_nosniff_navigation.sjs?mime=*%2F*&content=css" ></iframe>
+ <iframe class="no-mime" src="file_nosniff_navigation.sjs?mime=*%2F*&content=json"></iframe>
+ <iframe class="no-mime" src="file_nosniff_navigation.sjs?mime=*%2F*&content=img"></iframe>
+ <iframe class="no-mime" src="file_nosniff_navigation.sjs?mime=*%2F*&content=pdf"></iframe>
+ <iframe class="no-mime" src="file_nosniff_navigation.sjs?mime=*%2F*"></iframe>
+ <hr>
+ <!-- Using Content-Type: image/png -->
+ <iframe class="mismatch-mime" src="file_nosniff_navigation.sjs?mime=image%2Fpng&content=xml"></iframe>
+ <iframe class="mismatch-mime" src="file_nosniff_navigation.sjs?mime=image%2Fpng&content=html"></iframe>
+ <iframe class="mismatch-mime" src="file_nosniff_navigation.sjs?mime=image%2Fpng&content=css"></iframe>
+ <iframe class="mismatch-mime" src="file_nosniff_navigation.sjs?mime=image%2Fpng&content=json"></iframe>
+ <iframe class="mismatch-mime" src="file_nosniff_navigation.sjs?mime=image%2Fpng&content=img"></iframe>
+ <iframe class="mismatch-mime" src="file_nosniff_navigation.sjs?mime=image%2Fpng&content=pdf"></iframe>
+ <iframe class="mismatch-mime" src="file_nosniff_navigation.sjs?mime=image%2Fpng"></iframe>
+ <hr>
+ <!-- Using Content-Type: garbage/garbage -->
+ <iframe class="garbage-mime" src="file_nosniff_navigation.sjs?mime=garbage%2Fgarbage&content=xml"> </iframe>
+ <iframe class="garbage-mime" src="file_nosniff_navigation.sjs?mime=garbage%2Fgarbage&content=html"></iframe>
+ <iframe class="garbage-mime" src="file_nosniff_navigation.sjs?mime=garbage%2Fgarbage&content=css" ></iframe>
+ <iframe class="garbage-mime" src="file_nosniff_navigation.sjs?mime=garbage%2Fgarbage&content=json"></iframe>
+ <iframe class="garbage-mime" src="file_nosniff_navigation.sjs?mime=garbage%2Fgarbage&content=img"></iframe>
+ <iframe class="garbage-mime" src="file_nosniff_navigation.sjs?mime=garbage%2Fgarbage&content=pdf"></iframe>
+ <iframe class="garbage-mime" src="file_nosniff_navigation.sjs?mime=garbage%2Fgarbage"></iframe>
+</head>
+
+<body>
+
+<!-- add the two script tests -->
+<script id="scriptCorrectType"></script>
+<script id="scriptWrongType"></script>
+
+<script class="testbody" type="text/javascript">
+/* Description of the test:
+ * We're testing if Firefox respects the nosniff Header for Top-Level
+ * Navigations.
+ * If Firefox cant Display the Page, it will prompt a download
+ * and the URL of the Page will be about:blank.
+ * So we will try to open different content send with
+ * no-mime, mismatched-mime and garbage-mime types.
+ *
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+window.addEventListener("load", ()=>{
+ let noMimeFrames = Array.from(document.querySelectorAll(".no-mime"));
+ noMimeFrames.forEach(frame => {
+ let doc = frame.contentWindow.document;
+ // In case of no Provided Content Type, not rendering or assuming text/plain is valid
+ let result = doc.URL == "about:blank" || doc.contentType == "text/plain";
+ let sniffTarget = (new URL(frame.src)).searchParams.get("content");
+ window.opener.ok(result, `${sniffTarget} without MIME - was not sniffed`);
+ });
+
+ let mismatchedMimes = Array.from(document.querySelectorAll(".mismatch-mime"));
+ mismatchedMimes.forEach(frame => {
+ // In case the Server mismatches the Mime Type (sends content X as image/png)
+ // assert that we do not sniff and correct this.
+ let result = frame.contentWindow.document.contentType == "image/png";
+ let sniffTarget = (new URL(frame.src)).searchParams.get("content");
+ window.opener.ok(result, `${sniffTarget} send as image/png - was not Sniffed`);
+ });
+
+ let badMimeFrames = Array.from(document.querySelectorAll(".garbage-mime"));
+ badMimeFrames.forEach(frame => {
+ // In the case we got a bogous mime, assert that we dont sniff.
+ // We must not default here to text/plain
+ // as the Server at least provided a mime type.
+ let result = frame.contentWindow.document.URL == "about:blank";
+ let sniffTarget = (new URL(frame.src)).searchParams.get("content");
+ window.opener.ok(result, `${sniffTarget} send as garbage/garbage - was not Sniffed`);
+ });
+
+ window.opener.SimpleTest.finish();
+ this.close();
+});
+</script>
+</body>
+
+</html> \ No newline at end of file