summaryrefslogtreecommitdiffstats
path: root/browser/base/content/test/favicons
diff options
context:
space:
mode:
Diffstat (limited to 'browser/base/content/test/favicons')
-rw-r--r--browser/base/content/test/favicons/accept.html9
-rw-r--r--browser/base/content/test/favicons/accept.sjs15
-rw-r--r--browser/base/content/test/favicons/auth_test.html11
-rw-r--r--browser/base/content/test/favicons/auth_test.png0
-rw-r--r--browser/base/content/test/favicons/auth_test.png^headers^2
-rw-r--r--browser/base/content/test/favicons/blank.html6
-rw-r--r--browser/base/content/test/favicons/browser.ini113
-rw-r--r--browser/base/content/test/favicons/browser_bug408415.js34
-rw-r--r--browser/base/content/test/favicons/browser_bug550565.js35
-rw-r--r--browser/base/content/test/favicons/browser_favicon_accept.js30
-rw-r--r--browser/base/content/test/favicons/browser_favicon_auth.js27
-rw-r--r--browser/base/content/test/favicons/browser_favicon_cache.js50
-rw-r--r--browser/base/content/test/favicons/browser_favicon_change.js33
-rw-r--r--browser/base/content/test/favicons/browser_favicon_change_not_in_document.js55
-rw-r--r--browser/base/content/test/favicons/browser_favicon_credentials.js89
-rw-r--r--browser/base/content/test/favicons/browser_favicon_crossorigin.js61
-rw-r--r--browser/base/content/test/favicons/browser_favicon_load.js168
-rw-r--r--browser/base/content/test/favicons/browser_favicon_nostore.js169
-rw-r--r--browser/base/content/test/favicons/browser_favicon_referer.js62
-rw-r--r--browser/base/content/test/favicons/browser_favicon_store.js56
-rw-r--r--browser/base/content/test/favicons/browser_icon_discovery.js136
-rw-r--r--browser/base/content/test/favicons/browser_invalid_href_fallback.js29
-rw-r--r--browser/base/content/test/favicons/browser_missing_favicon.js36
-rw-r--r--browser/base/content/test/favicons/browser_mixed_content.js26
-rw-r--r--browser/base/content/test/favicons/browser_multiple_icons_in_short_timeframe.js37
-rw-r--r--browser/base/content/test/favicons/browser_oversized.js25
-rw-r--r--browser/base/content/test/favicons/browser_preferred_icons.js140
-rw-r--r--browser/base/content/test/favicons/browser_redirect.js20
-rw-r--r--browser/base/content/test/favicons/browser_rich_icons.js50
-rw-r--r--browser/base/content/test/favicons/browser_rooticon.js24
-rw-r--r--browser/base/content/test/favicons/browser_subframe_favicons_not_used.js22
-rw-r--r--browser/base/content/test/favicons/browser_title_flicker.js185
-rw-r--r--browser/base/content/test/favicons/cookie_favicon.html11
-rw-r--r--browser/base/content/test/favicons/cookie_favicon.sjs26
-rw-r--r--browser/base/content/test/favicons/credentials.pngbin0 -> 580 bytes
-rw-r--r--browser/base/content/test/favicons/credentials.png^headers^3
-rw-r--r--browser/base/content/test/favicons/credentials1.html10
-rw-r--r--browser/base/content/test/favicons/credentials2.html10
-rw-r--r--browser/base/content/test/favicons/crossorigin.html10
-rw-r--r--browser/base/content/test/favicons/crossorigin.pngbin0 -> 580 bytes
-rw-r--r--browser/base/content/test/favicons/crossorigin.png^headers^1
-rw-r--r--browser/base/content/test/favicons/datauri-favicon.html8
-rw-r--r--browser/base/content/test/favicons/discovery.html8
-rw-r--r--browser/base/content/test/favicons/file_bug970276_favicon1.icobin0 -> 1406 bytes
-rw-r--r--browser/base/content/test/favicons/file_bug970276_favicon2.icobin0 -> 1406 bytes
-rw-r--r--browser/base/content/test/favicons/file_bug970276_popup1.html14
-rw-r--r--browser/base/content/test/favicons/file_bug970276_popup2.html12
-rw-r--r--browser/base/content/test/favicons/file_favicon.html11
-rw-r--r--browser/base/content/test/favicons/file_favicon.pngbin0 -> 344 bytes
-rw-r--r--browser/base/content/test/favicons/file_favicon.png^headers^1
-rw-r--r--browser/base/content/test/favicons/file_favicon_change.html13
-rw-r--r--browser/base/content/test/favicons/file_favicon_change_not_in_document.html20
-rw-r--r--browser/base/content/test/favicons/file_favicon_no_referrer.html11
-rw-r--r--browser/base/content/test/favicons/file_favicon_redirect.html12
-rw-r--r--browser/base/content/test/favicons/file_favicon_redirect.ico0
-rw-r--r--browser/base/content/test/favicons/file_favicon_redirect.ico^headers^2
-rw-r--r--browser/base/content/test/favicons/file_favicon_thirdParty.html11
-rw-r--r--browser/base/content/test/favicons/file_generic_favicon.icobin0 -> 1406 bytes
-rw-r--r--browser/base/content/test/favicons/file_insecure_favicon.html11
-rw-r--r--browser/base/content/test/favicons/file_invalid_href.html12
-rw-r--r--browser/base/content/test/favicons/file_mask_icon.html11
-rw-r--r--browser/base/content/test/favicons/file_rich_icon.html12
-rw-r--r--browser/base/content/test/favicons/file_with_favicon.html12
-rw-r--r--browser/base/content/test/favicons/file_with_slow_favicon.html10
-rw-r--r--browser/base/content/test/favicons/head.js98
-rw-r--r--browser/base/content/test/favicons/icon.svg11
-rw-r--r--browser/base/content/test/favicons/large.pngbin0 -> 21237 bytes
-rw-r--r--browser/base/content/test/favicons/large_favicon.html12
-rw-r--r--browser/base/content/test/favicons/moz.pngbin0 -> 580 bytes
-rw-r--r--browser/base/content/test/favicons/no-store.html11
-rw-r--r--browser/base/content/test/favicons/no-store.pngbin0 -> 580 bytes
-rw-r--r--browser/base/content/test/favicons/no-store.png^headers^1
-rw-r--r--browser/base/content/test/favicons/rich_moz_1.pngbin0 -> 580 bytes
-rw-r--r--browser/base/content/test/favicons/rich_moz_2.pngbin0 -> 580 bytes
74 files changed, 2150 insertions, 0 deletions
diff --git a/browser/base/content/test/favicons/accept.html b/browser/base/content/test/favicons/accept.html
new file mode 100644
index 0000000000..4bb00243b3
--- /dev/null
+++ b/browser/base/content/test/favicons/accept.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test file for accept header</title>
+ <link rel="icon" href="accept.sjs">
+</head>
+<body>
+</body>
+</html>
diff --git a/browser/base/content/test/favicons/accept.sjs b/browser/base/content/test/favicons/accept.sjs
new file mode 100644
index 0000000000..3e798ba817
--- /dev/null
+++ b/browser/base/content/test/favicons/accept.sjs
@@ -0,0 +1,15 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function handleRequest(request, response) {
+ // Doesn't seem any way to get the value from prefs from here. :(
+ let expected = "image/avif,image/webp,*/*";
+ if (expected != request.getHeader("Accept")) {
+ response.setStatusLine(request.httpVersion, 404, "Not Found");
+ return;
+ }
+
+ response.setStatusLine(request.httpVersion, 302, "Moved Temporarily");
+ response.setHeader("Location", "moz.png");
+}
diff --git a/browser/base/content/test/favicons/auth_test.html b/browser/base/content/test/favicons/auth_test.html
new file mode 100644
index 0000000000..90b78432f8
--- /dev/null
+++ b/browser/base/content/test/favicons/auth_test.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset='utf-8'>
+ <title>Favicon Test for http auth</title>
+ <link rel="icon" type="image/png" href="auth_test.png" />
+ </head>
+ <body>
+ Favicon!!
+ </body>
+</html>
diff --git a/browser/base/content/test/favicons/auth_test.png b/browser/base/content/test/favicons/auth_test.png
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/browser/base/content/test/favicons/auth_test.png
diff --git a/browser/base/content/test/favicons/auth_test.png^headers^ b/browser/base/content/test/favicons/auth_test.png^headers^
new file mode 100644
index 0000000000..5024ae1c4b
--- /dev/null
+++ b/browser/base/content/test/favicons/auth_test.png^headers^
@@ -0,0 +1,2 @@
+HTTP 401 Unauthorized
+WWW-Authenticate: Basic realm="Favicon auth"
diff --git a/browser/base/content/test/favicons/blank.html b/browser/base/content/test/favicons/blank.html
new file mode 100644
index 0000000000..297eb8cd78
--- /dev/null
+++ b/browser/base/content/test/favicons/blank.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+</head>
+</html>
diff --git a/browser/base/content/test/favicons/browser.ini b/browser/base/content/test/favicons/browser.ini
new file mode 100644
index 0000000000..a5fc30ecfd
--- /dev/null
+++ b/browser/base/content/test/favicons/browser.ini
@@ -0,0 +1,113 @@
+[DEFAULT]
+support-files =
+ head.js
+ discovery.html
+ moz.png
+ rich_moz_1.png
+ rich_moz_2.png
+ file_bug970276_favicon1.ico
+ file_generic_favicon.ico
+ file_with_favicon.html
+prefs =
+ browser.chrome.guess_favicon=true
+
+[browser_bug408415.js]
+[browser_bug550565.js]
+[browser_favicon_accept.js]
+support-files =
+ accept.html
+ accept.sjs
+[browser_favicon_auth.js]
+support-files =
+ auth_test.html
+ auth_test.png
+ auth_test.png^headers^
+[browser_favicon_cache.js]
+support-files =
+ cookie_favicon.sjs
+ cookie_favicon.html
+[browser_favicon_change.js]
+support-files =
+ file_favicon_change.html
+[browser_favicon_change_not_in_document.js]
+support-files =
+ file_favicon_change_not_in_document.html
+[browser_favicon_credentials.js]
+https_first_disabled = true
+support-files =
+ credentials1.html
+ credentials2.html
+ credentials.png
+ credentials.png^headers^
+[browser_favicon_crossorigin.js]
+https_first_disabled = true
+support-files =
+ crossorigin.html
+ crossorigin.png
+ crossorigin.png^headers^
+[browser_favicon_load.js]
+https_first_disabled = true
+support-files =
+ file_favicon.html
+ file_favicon.png
+ file_favicon.png^headers^
+ file_favicon_thirdParty.html
+[browser_favicon_nostore.js]
+https_first_disabled = true
+support-files =
+ no-store.html
+ no-store.png
+ no-store.png^headers^
+[browser_favicon_referer.js]
+support-files =
+ file_favicon_no_referrer.html
+[browser_favicon_store.js]
+support-files =
+ datauri-favicon.html
+ file_favicon.html
+ file_favicon.png
+ file_favicon.png^headers^
+[browser_icon_discovery.js]
+[browser_invalid_href_fallback.js]
+https_first_disabled = true
+support-files =
+ file_invalid_href.html
+[browser_missing_favicon.js]
+support-files =
+ blank.html
+[browser_mixed_content.js]
+support-files =
+ file_insecure_favicon.html
+ file_favicon.png
+[browser_multiple_icons_in_short_timeframe.js]
+[browser_oversized.js]
+support-files =
+ large_favicon.html
+ large.png
+[browser_preferred_icons.js]
+support-files =
+ icon.svg
+[browser_redirect.js]
+support-files =
+ file_favicon_redirect.html
+ file_favicon_redirect.ico
+ file_favicon_redirect.ico^headers^
+[browser_rich_icons.js]
+support-files =
+ file_rich_icon.html
+ file_mask_icon.html
+[browser_rooticon.js]
+https_first_disabled = true
+support-files =
+ blank.html
+[browser_subframe_favicons_not_used.js]
+support-files =
+ file_bug970276_popup1.html
+ file_bug970276_popup2.html
+ file_bug970276_favicon2.ico
+[browser_title_flicker.js]
+https_first_disabled = true
+support-files =
+ file_with_slow_favicon.html
+ blank.html
+ file_favicon.png
diff --git a/browser/base/content/test/favicons/browser_bug408415.js b/browser/base/content/test/favicons/browser_bug408415.js
new file mode 100644
index 0000000000..1526477db3
--- /dev/null
+++ b/browser/base/content/test/favicons/browser_bug408415.js
@@ -0,0 +1,34 @@
+add_task(async function test() {
+ let testPath = getRootDirectory(gTestPath);
+
+ await BrowserTestUtils.withNewTab(
+ { gBrowser, url: "about:blank" },
+ async function (tabBrowser) {
+ const URI = testPath + "file_with_favicon.html";
+ const expectedIcon = testPath + "file_generic_favicon.ico";
+ let faviconPromise = waitForLinkAvailable(tabBrowser);
+
+ BrowserTestUtils.loadURIString(tabBrowser, URI);
+
+ let iconURI = await faviconPromise;
+ is(iconURI, expectedIcon, "Correct icon before pushState.");
+
+ faviconPromise = waitForLinkAvailable(tabBrowser);
+
+ await SpecialPowers.spawn(tabBrowser, [], function () {
+ content.location.href += "#foo";
+ });
+
+ TestUtils.executeSoon(() => {
+ faviconPromise.cancel();
+ });
+
+ try {
+ await faviconPromise;
+ ok(false, "Should not have seen a new icon load.");
+ } catch (e) {
+ ok(true, "Should have been able to cancel the promise.");
+ }
+ }
+ );
+});
diff --git a/browser/base/content/test/favicons/browser_bug550565.js b/browser/base/content/test/favicons/browser_bug550565.js
new file mode 100644
index 0000000000..32a7527bbf
--- /dev/null
+++ b/browser/base/content/test/favicons/browser_bug550565.js
@@ -0,0 +1,35 @@
+add_task(async function test() {
+ let testPath = getRootDirectory(gTestPath);
+
+ await BrowserTestUtils.withNewTab(
+ { gBrowser, url: "about:blank" },
+ async function (tabBrowser) {
+ const URI = testPath + "file_with_favicon.html";
+ const expectedIcon = testPath + "file_generic_favicon.ico";
+ let faviconPromise = waitForLinkAvailable(tabBrowser);
+
+ BrowserTestUtils.loadURIString(tabBrowser, URI);
+
+ let iconURI = await faviconPromise;
+ is(iconURI, expectedIcon, "Correct icon before pushState.");
+
+ faviconPromise = waitForLinkAvailable(tabBrowser);
+
+ await SpecialPowers.spawn(tabBrowser, [], function () {
+ content.history.pushState("page2", "page2", "page2");
+ });
+
+ // We've navigated and shouldn't get a call to onLinkIconAvailable.
+ TestUtils.executeSoon(() => {
+ faviconPromise.cancel();
+ });
+
+ try {
+ await faviconPromise;
+ ok(false, "Should not have seen a new icon load.");
+ } catch (e) {
+ ok(true, "Should have been able to cancel the promise.");
+ }
+ }
+ );
+});
diff --git a/browser/base/content/test/favicons/browser_favicon_accept.js b/browser/base/content/test/favicons/browser_favicon_accept.js
new file mode 100644
index 0000000000..dc59a406b5
--- /dev/null
+++ b/browser/base/content/test/favicons/browser_favicon_accept.js
@@ -0,0 +1,30 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const ROOT = getRootDirectory(gTestPath).replace(
+ "chrome://mochitest/content/",
+ "http://mochi.test:8888/"
+);
+
+add_task(async () => {
+ await BrowserTestUtils.withNewTab(
+ { gBrowser, url: "about:blank" },
+ async browser => {
+ let faviconPromise = waitForFaviconMessage(true, `${ROOT}accept.sjs`);
+
+ BrowserTestUtils.loadURIString(browser, ROOT + "accept.html");
+ await BrowserTestUtils.browserLoaded(browser);
+
+ try {
+ let result = await faviconPromise;
+ Assert.equal(
+ result.iconURL,
+ `${ROOT}accept.sjs`,
+ "Should have seen the icon"
+ );
+ } catch (e) {
+ Assert.ok(false, "Favicon load failed.");
+ }
+ }
+ );
+});
diff --git a/browser/base/content/test/favicons/browser_favicon_auth.js b/browser/base/content/test/favicons/browser_favicon_auth.js
new file mode 100644
index 0000000000..fb0e75f2ab
--- /dev/null
+++ b/browser/base/content/test/favicons/browser_favicon_auth.js
@@ -0,0 +1,27 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const ROOT = getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content/",
+ "http://mochi.test:8888/"
+);
+
+add_task(async () => {
+ await BrowserTestUtils.withNewTab(
+ { gBrowser, url: "about:blank" },
+ async browser => {
+ let faviconPromise = waitForFaviconMessage(true, `${ROOT}auth_test.png`);
+
+ BrowserTestUtils.loadURIString(browser, `${ROOT}auth_test.html`);
+ await BrowserTestUtils.browserLoaded(browser);
+
+ await Assert.rejects(
+ faviconPromise,
+ result => {
+ return result.iconURL == `${ROOT}auth_test.png`;
+ },
+ "Should have failed to load the icon."
+ );
+ }
+ );
+});
diff --git a/browser/base/content/test/favicons/browser_favicon_cache.js b/browser/base/content/test/favicons/browser_favicon_cache.js
new file mode 100644
index 0000000000..903f038d6c
--- /dev/null
+++ b/browser/base/content/test/favicons/browser_favicon_cache.js
@@ -0,0 +1,50 @@
+add_task(async () => {
+ const testPath =
+ // eslint-disable-next-line @microsoft/sdl/no-insecure-url
+ "http://example.com/browser/browser/base/content/test/favicons/cookie_favicon.html";
+ const resetPath =
+ // eslint-disable-next-line @microsoft/sdl/no-insecure-url
+ "http://example.com/browser/browser/base/content/test/favicons/cookie_favicon.sjs?reset";
+
+ let tab = BrowserTestUtils.addTab(gBrowser, testPath);
+ gBrowser.selectedTab = tab;
+ let browser = tab.linkedBrowser;
+
+ let faviconPromise = waitForLinkAvailable(browser);
+ await BrowserTestUtils.browserLoaded(browser);
+ await faviconPromise;
+ let cookies = Services.cookies.getCookiesFromHost(
+ "example.com",
+ browser.contentPrincipal.originAttributes
+ );
+ let seenCookie = false;
+ for (let cookie of cookies) {
+ if (cookie.name == "faviconCookie") {
+ seenCookie = true;
+ is(cookie.value, "1", "Should have seen the right initial cookie.");
+ }
+ }
+ ok(seenCookie, "Should have seen the cookie.");
+
+ faviconPromise = waitForLinkAvailable(browser);
+ BrowserTestUtils.loadURIString(browser, testPath);
+ await BrowserTestUtils.browserLoaded(browser);
+ await faviconPromise;
+ cookies = Services.cookies.getCookiesFromHost(
+ "example.com",
+ browser.contentPrincipal.originAttributes
+ );
+ seenCookie = false;
+ for (let cookie of cookies) {
+ if (cookie.name == "faviconCookie") {
+ seenCookie = true;
+ is(cookie.value, "1", "Should have seen the cached cookie.");
+ }
+ }
+ ok(seenCookie, "Should have seen the cookie.");
+
+ // Reset the cookie so if this test is run again it will still pass.
+ await fetch(resetPath);
+
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/browser/base/content/test/favicons/browser_favicon_change.js b/browser/base/content/test/favicons/browser_favicon_change.js
new file mode 100644
index 0000000000..8faf266665
--- /dev/null
+++ b/browser/base/content/test/favicons/browser_favicon_change.js
@@ -0,0 +1,33 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const TEST_ROOT =
+ "http://mochi.test:8888/browser/browser/base/content/test/favicons/";
+const TEST_URL = TEST_ROOT + "file_favicon_change.html";
+
+add_task(async function () {
+ let extraTab = (gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser));
+ let haveChanged = waitForFavicon(
+ extraTab.linkedBrowser,
+ TEST_ROOT + "file_bug970276_favicon1.ico"
+ );
+
+ BrowserTestUtils.loadURIString(extraTab.linkedBrowser, TEST_URL);
+ await BrowserTestUtils.browserLoaded(extraTab.linkedBrowser);
+ await haveChanged;
+
+ haveChanged = waitForFavicon(extraTab.linkedBrowser, TEST_ROOT + "moz.png");
+
+ SpecialPowers.spawn(extraTab.linkedBrowser, [], function () {
+ let ev = new content.CustomEvent("PleaseChangeFavicon", {});
+ content.dispatchEvent(ev);
+ });
+
+ await haveChanged;
+
+ ok(true, "Saw all the icons we expected.");
+
+ gBrowser.removeTab(extraTab);
+});
diff --git a/browser/base/content/test/favicons/browser_favicon_change_not_in_document.js b/browser/base/content/test/favicons/browser_favicon_change_not_in_document.js
new file mode 100644
index 0000000000..34c5ae8baf
--- /dev/null
+++ b/browser/base/content/test/favicons/browser_favicon_change_not_in_document.js
@@ -0,0 +1,55 @@
+"use strict";
+
+const TEST_ROOT =
+ "http://mochi.test:8888/browser/browser/base/content/test/favicons/";
+const TEST_URL = TEST_ROOT + "file_favicon_change_not_in_document.html";
+
+/*
+ * This test tests a link element won't fire DOMLinkChanged/DOMLinkAdded unless
+ * it is added to the DOM. See more details in bug 1083895.
+ *
+ * Note that there is debounce logic in ContentLinkHandler.jsm, adding a new
+ * icon link after the icon parsing timeout will trigger a new icon extraction
+ * cycle. Hence, there should be two favicons loads in this test as it appends
+ * a new link to the DOM in the timeout callback defined in the test HTML page.
+ * However, the not-yet-added link element with href as "http://example.org/other-icon"
+ * should not fire the DOMLinkAdded event, nor should it fire the DOMLinkChanged
+ * event after its href gets updated later.
+ */
+add_task(async function () {
+ let extraTab = (gBrowser.selectedTab = BrowserTestUtils.addTab(
+ gBrowser,
+ TEST_ROOT
+ ));
+ let domLinkAddedFired = 0;
+ let domLinkChangedFired = 0;
+ const linkAddedHandler = event => domLinkAddedFired++;
+ const linkChangedhandler = event => domLinkChangedFired++;
+ BrowserTestUtils.addContentEventListener(
+ gBrowser.selectedBrowser,
+ "DOMLinkAdded",
+ linkAddedHandler
+ );
+ BrowserTestUtils.addContentEventListener(
+ gBrowser.selectedBrowser,
+ "DOMLinkChanged",
+ linkChangedhandler
+ );
+
+ let expectedFavicon = TEST_ROOT + "file_generic_favicon.ico";
+ let faviconPromise = waitForFavicon(extraTab.linkedBrowser, expectedFavicon);
+
+ BrowserTestUtils.loadURIString(extraTab.linkedBrowser, TEST_URL);
+ await BrowserTestUtils.browserLoaded(extraTab.linkedBrowser);
+
+ await faviconPromise;
+
+ is(
+ domLinkAddedFired,
+ 2,
+ "Should fire the correct number of DOMLinkAdded event."
+ );
+ is(domLinkChangedFired, 0, "Should not fire any DOMLinkChanged event.");
+
+ gBrowser.removeTab(extraTab);
+});
diff --git a/browser/base/content/test/favicons/browser_favicon_credentials.js b/browser/base/content/test/favicons/browser_favicon_credentials.js
new file mode 100644
index 0000000000..405c620c8a
--- /dev/null
+++ b/browser/base/content/test/favicons/browser_favicon_credentials.js
@@ -0,0 +1,89 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const ROOT_DIR = getRootDirectory(gTestPath);
+
+const EXAMPLE_NET_ROOT = ROOT_DIR.replace(
+ "chrome://mochitests/content/",
+ "https://example.net/"
+);
+
+const EXAMPLE_COM_ROOT = ROOT_DIR.replace(
+ "chrome://mochitests/content/",
+ "https://example.com/"
+);
+
+const FAVICON_URL = EXAMPLE_COM_ROOT + "credentials.png";
+
+// Bug 1746646: Make mochitests work with TCP enabled (cookieBehavior = 5)
+// All instances of addPermission and removePermission set up 3rd-party storage
+// access in a way that allows the test to proceed with TCP enabled.
+
+function run_test(url, shouldHaveCookies, description) {
+ add_task(async () => {
+ await SpecialPowers.addPermission(
+ "3rdPartyStorage^https://example.com",
+ true,
+ url
+ );
+
+ await BrowserTestUtils.withNewTab(
+ { gBrowser, url: "about:blank" },
+ async browser => {
+ const faviconPromise = waitForFaviconMessage(true, FAVICON_URL);
+
+ BrowserTestUtils.loadURIString(browser, url);
+ await BrowserTestUtils.browserLoaded(browser);
+
+ await faviconPromise;
+
+ const seenCookie = Services.cookies
+ .getCookiesFromHost(
+ "example.com", // the icon's host, not the page's
+ browser.contentPrincipal.originAttributes
+ )
+ .some(cookie => cookie.name == "faviconCookie2");
+
+ // Clean up.
+ Services.cookies.removeAll();
+ Services.cache2.clear();
+
+ if (shouldHaveCookies) {
+ Assert.ok(
+ seenCookie,
+ `Should have seen the cookie (${description}).`
+ );
+ } else {
+ Assert.ok(
+ !seenCookie,
+ `Should have not seen the cookie (${description}).`
+ );
+ }
+ }
+ );
+ await SpecialPowers.removePermission(
+ "3rdPartyStorage^https://example.com",
+ url
+ );
+ });
+}
+
+// crossorigin="" only has credentials in the same-origin case
+run_test(`${EXAMPLE_NET_ROOT}credentials1.html`, false, "anonymous, remote");
+run_test(
+ `${EXAMPLE_COM_ROOT}credentials1.html`,
+ true,
+ "anonymous, same-origin"
+);
+
+// crossorigin="use-credentials" always has them
+run_test(
+ `${EXAMPLE_NET_ROOT}credentials2.html`,
+ true,
+ "use-credentials, remote"
+);
+run_test(
+ `${EXAMPLE_COM_ROOT}credentials2.html`,
+ true,
+ "use-credentials, same-origin"
+);
diff --git a/browser/base/content/test/favicons/browser_favicon_crossorigin.js b/browser/base/content/test/favicons/browser_favicon_crossorigin.js
new file mode 100644
index 0000000000..c1ae18f765
--- /dev/null
+++ b/browser/base/content/test/favicons/browser_favicon_crossorigin.js
@@ -0,0 +1,61 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const ROOT_DIR = getRootDirectory(gTestPath);
+
+const MOCHI_ROOT = ROOT_DIR.replace(
+ "chrome://mochitests/content/",
+ "http://mochi.test:8888/"
+);
+
+const EXAMPLE_NET_ROOT = ROOT_DIR.replace(
+ "chrome://mochitests/content/",
+ "http://example.net/"
+);
+
+const EXAMPLE_COM_ROOT = ROOT_DIR.replace(
+ "chrome://mochitests/content/",
+ "http://example.com/"
+);
+
+const FAVICON_URL = EXAMPLE_COM_ROOT + "crossorigin.png";
+
+function run_test(root, shouldSucceed, description) {
+ add_task(async () => {
+ await BrowserTestUtils.withNewTab(
+ { gBrowser, url: "about:blank" },
+ async browser => {
+ const faviconPromise = waitForFaviconMessage(true, FAVICON_URL);
+
+ BrowserTestUtils.loadURIString(browser, `${root}crossorigin.html`);
+ await BrowserTestUtils.browserLoaded(browser);
+
+ if (shouldSucceed) {
+ try {
+ const result = await faviconPromise;
+ Assert.equal(
+ result.iconURL,
+ FAVICON_URL,
+ `Should have seen the icon (${description}).`
+ );
+ } catch (e) {
+ Assert.ok(false, `Favicon load failed (${description}).`);
+ }
+ } else {
+ await Assert.rejects(
+ faviconPromise,
+ result => result.iconURL == FAVICON_URL,
+ `Should have failed to load the icon (${description}).`
+ );
+ }
+ }
+ );
+ });
+}
+
+// crossorigin.png only allows CORS for MOCHI_ROOT.
+run_test(EXAMPLE_NET_ROOT, false, "remote origin not allowed");
+run_test(MOCHI_ROOT, true, "remote origin allowed");
+
+// Same-origin but with the crossorigin attribute.
+run_test(EXAMPLE_COM_ROOT, true, "same-origin");
diff --git a/browser/base/content/test/favicons/browser_favicon_load.js b/browser/base/content/test/favicons/browser_favicon_load.js
new file mode 100644
index 0000000000..f948b681b0
--- /dev/null
+++ b/browser/base/content/test/favicons/browser_favicon_load.js
@@ -0,0 +1,168 @@
+/**
+ * Bug 1247843 - A test case for testing whether the channel used to load favicon
+ * has correct classFlags.
+ * Note that this test is modified based on browser_favicon_userContextId.js.
+ */
+
+const CC = Components.Constructor;
+
+// eslint-disable-next-line @microsoft/sdl/no-insecure-url
+const TEST_SITE = "http://example.net";
+const TEST_THIRD_PARTY_SITE = "http://mochi.test:8888";
+
+const TEST_PAGE =
+ TEST_SITE + "/browser/browser/base/content/test/favicons/file_favicon.html";
+const FAVICON_URI =
+ TEST_SITE + "/browser/browser/base/content/test/favicons/file_favicon.png";
+const TEST_THIRD_PARTY_PAGE =
+ TEST_SITE +
+ "/browser/browser/base/content/test/favicons/file_favicon_thirdParty.html";
+const THIRD_PARTY_FAVICON_URI =
+ TEST_THIRD_PARTY_SITE +
+ "/browser/browser/base/content/test/favicons/file_favicon.png";
+
+ChromeUtils.defineESModuleGetters(this, {
+ PlacesTestUtils: "resource://testing-common/PlacesTestUtils.sys.mjs",
+ PromiseUtils: "resource://gre/modules/PromiseUtils.sys.mjs",
+});
+
+let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
+
+function clearAllImageCaches() {
+ var tools = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools);
+ var imageCache = tools.getImgCacheForDocument(window.document);
+ imageCache.clearCache(true); // true=chrome
+ imageCache.clearCache(false); // false=content
+}
+
+function clearAllPlacesFavicons() {
+ return new Promise(resolve => {
+ Services.obs.addObserver(function observer() {
+ Services.obs.removeObserver(observer, "places-favicons-expired");
+ resolve();
+ }, "places-favicons-expired");
+
+ PlacesUtils.favicons.expireAllFavicons();
+ });
+}
+
+function FaviconObserver(aPageURI, aFaviconURL, aTailingEnabled) {
+ this.reset(aPageURI, aFaviconURL, aTailingEnabled);
+}
+
+FaviconObserver.prototype = {
+ observe(aSubject, aTopic, aData) {
+ // Make sure that the topic is 'http-on-modify-request'.
+ if (aTopic === "http-on-modify-request") {
+ let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
+ let reqLoadInfo = httpChannel.loadInfo;
+ // Make sure this is a favicon request.
+ if (httpChannel.URI.spec !== this._faviconURL) {
+ return;
+ }
+
+ let cos = aSubject.QueryInterface(Ci.nsIClassOfService);
+ if (!cos) {
+ ok(false, "Http channel should implement nsIClassOfService.");
+ return;
+ }
+
+ if (!reqLoadInfo) {
+ ok(false, "Should have load info.");
+ return;
+ }
+
+ let haveTailFlag = !!(cos.classFlags & Ci.nsIClassOfService.Tail);
+ info("classFlags=" + cos.classFlags);
+ is(haveTailFlag, this._tailingEnabled, "Should have correct cos flag.");
+ } else {
+ ok(false, "Received unexpected topic: ", aTopic);
+ }
+
+ this._faviconLoaded.resolve();
+ },
+
+ reset(aPageURI, aFaviconURL, aTailingEnabled) {
+ this._faviconURL = aFaviconURL;
+ this._faviconLoaded = PromiseUtils.defer();
+ this._tailingEnabled = aTailingEnabled;
+ },
+
+ get promise() {
+ return this._faviconLoaded.promise;
+ },
+};
+
+function waitOnFaviconLoaded(aFaviconURL) {
+ return PlacesTestUtils.waitForNotification("favicon-changed", events =>
+ events.some(e => e.faviconUrl == aFaviconURL)
+ );
+}
+
+async function doTest(aTestPage, aFaviconURL, aTailingEnabled) {
+ let pageURI = Services.io.newURI(aTestPage);
+
+ // Create the observer object for observing favion channels.
+ let observer = new FaviconObserver(pageURI, aFaviconURL, aTailingEnabled);
+
+ let promiseWaitOnFaviconLoaded = waitOnFaviconLoaded(aFaviconURL);
+
+ // Add the observer earlier in case we miss it.
+ Services.obs.addObserver(observer, "http-on-modify-request");
+
+ // Open the tab.
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, aTestPage);
+ // Waiting for favicon requests are all made.
+ await observer.promise;
+ // Waiting for favicon loaded.
+ await promiseWaitOnFaviconLoaded;
+
+ Services.obs.removeObserver(observer, "http-on-modify-request");
+
+ // Close the tab.
+ BrowserTestUtils.removeTab(tab);
+}
+
+async function setupTailingPreference(aTailingEnabled) {
+ await SpecialPowers.pushPrefEnv({
+ set: [["network.http.tailing.enabled", aTailingEnabled]],
+ });
+}
+
+async function cleanup() {
+ // Clear all cookies.
+ Services.cookies.removeAll();
+ // Clear cache.
+ Services.cache2.clear();
+ // Clear Places favicon caches.
+ await clearAllPlacesFavicons();
+ // Clear all image caches and network caches.
+ clearAllImageCaches();
+ // Clear Places history.
+ await PlacesUtils.history.clear();
+}
+
+// A clean up function to prevent affecting other tests.
+registerCleanupFunction(async () => {
+ await cleanup();
+});
+
+add_task(async function test_favicon_with_tailing_enabled() {
+ await cleanup();
+
+ let tailingEnabled = true;
+
+ await setupTailingPreference(tailingEnabled);
+
+ await doTest(TEST_PAGE, FAVICON_URI, tailingEnabled);
+});
+
+add_task(async function test_favicon_with_tailing_disabled() {
+ await cleanup();
+
+ let tailingEnabled = false;
+
+ await setupTailingPreference(tailingEnabled);
+
+ await doTest(TEST_THIRD_PARTY_PAGE, THIRD_PARTY_FAVICON_URI, tailingEnabled);
+});
diff --git a/browser/base/content/test/favicons/browser_favicon_nostore.js b/browser/base/content/test/favicons/browser_favicon_nostore.js
new file mode 100644
index 0000000000..3fec666bbe
--- /dev/null
+++ b/browser/base/content/test/favicons/browser_favicon_nostore.js
@@ -0,0 +1,169 @@
+/* Any copyright is dedicated to the Public Domain.
+ * https://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that a favicon with Cache-Control: no-store is not stored in Places.
+// Also tests that favicons added after pageshow are not stored.
+
+const TEST_SITE = "http://example.net";
+const ICON_URL =
+ TEST_SITE + "/browser/browser/base/content/test/favicons/no-store.png";
+const PAGE_URL =
+ TEST_SITE + "/browser/browser/base/content/test/favicons/no-store.html";
+
+async function cleanup() {
+ Services.cache2.clear();
+ await PlacesTestUtils.clearFavicons();
+ await PlacesUtils.history.clear();
+}
+
+add_task(async function browser_loader() {
+ await cleanup();
+ let iconPromise = waitForFaviconMessage(true, ICON_URL);
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE_URL);
+ registerCleanupFunction(async () => {
+ await cleanup();
+ });
+
+ let { iconURL } = await iconPromise;
+ is(iconURL, ICON_URL, "Should have seen the expected icon.");
+
+ // Ensure the favicon has not been stored.
+ /* eslint-disable mozilla/no-arbitrary-setTimeout */
+ await new Promise(resolve => setTimeout(resolve, 1000));
+ await new Promise((resolve, reject) => {
+ PlacesUtils.favicons.getFaviconURLForPage(
+ Services.io.newURI(PAGE_URL),
+ foundIconURI => {
+ if (foundIconURI) {
+ reject(new Error("An icon has been stored " + foundIconURI.spec));
+ }
+ resolve();
+ }
+ );
+ });
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function places_loader() {
+ await cleanup();
+
+ // Ensure the favicon is not stored even if Places is directly invoked.
+ await PlacesTestUtils.addVisits(PAGE_URL);
+ let faviconData = new Map();
+ faviconData.set(PAGE_URL, ICON_URL);
+ // We can't wait for the promise due to bug 740457, so we race with a timer.
+ await Promise.race([
+ PlacesTestUtils.addFavicons(faviconData),
+ /* eslint-disable mozilla/no-arbitrary-setTimeout */
+ new Promise(resolve => setTimeout(resolve, 1000)),
+ ]);
+ await new Promise((resolve, reject) => {
+ PlacesUtils.favicons.getFaviconURLForPage(
+ Services.io.newURI(PAGE_URL),
+ foundIconURI => {
+ if (foundIconURI) {
+ reject(new Error("An icon has been stored " + foundIconURI.spec));
+ }
+ resolve();
+ }
+ );
+ });
+});
+
+async function later_addition(iconUrl) {
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE_URL);
+ registerCleanupFunction(async () => {
+ await cleanup();
+ BrowserTestUtils.removeTab(tab);
+ });
+
+ let iconPromise = waitForFaviconMessage(true, iconUrl);
+ await ContentTask.spawn(gBrowser.selectedBrowser, iconUrl, href => {
+ let doc = content.document;
+ let head = doc.head;
+ let link = doc.createElement("link");
+ link.rel = "icon";
+ link.href = href;
+ link.type = "image/png";
+ head.appendChild(link);
+ });
+ let { iconURL } = await iconPromise;
+ is(iconURL, iconUrl, "Should have seen the expected icon.");
+
+ // Ensure the favicon has not been stored.
+ /* eslint-disable mozilla/no-arbitrary-setTimeout */
+ await new Promise(resolve => setTimeout(resolve, 1000));
+ await new Promise((resolve, reject) => {
+ PlacesUtils.favicons.getFaviconURLForPage(
+ Services.io.newURI(PAGE_URL),
+ foundIconURI => {
+ if (foundIconURI) {
+ reject(new Error("An icon has been stored " + foundIconURI.spec));
+ }
+ resolve();
+ }
+ );
+ });
+ BrowserTestUtils.removeTab(tab);
+}
+
+add_task(async function test_later_addition() {
+ for (let iconUrl of [
+ TEST_SITE + "/browser/browser/base/content/test/favicons/moz.png",
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABH0lEQVRYw2P8////f4YBBEwMAwxGHcBCUMX/91DGOSj/BpT/DkpzQChGBSjfBErLQsVZhmoI/L8LpRdD6X1QietQGhYy7FB5aAgwmkLpBKi4BZTPMThDgBGjHIDF+f9mKD0fKvGBRKNdoF7sgPL1saaJwZgGDkJ9vpZMn8PAHqg5G9FyifBgD4H/W9HyOWrU/f+DIzHhkoeZxxgzZEIAVtJ9RxX+Q6DAxCmP3byhXxkxshAs5odqbcioAY3UC1CBLyTGOTqAmsfAOWRCwBvqxV0oIUB2OQAzDy3/D+a6wB7q8mCU2vD/nw94GziYIQOtDRn9oXz+IZMGBKGMbCjNh9Ii+v8HR4uIAUeLiEEbb9twELaIRlqrmHG0bzjiHQAA1LVfww8jwM4AAAAASUVORK5CYII=",
+ ]) {
+ await later_addition(iconUrl);
+ }
+});
+
+add_task(async function root_icon_stored() {
+ XPCShellContentUtils.ensureInitialized(this);
+ let server = XPCShellContentUtils.createHttpServer({
+ hosts: ["www.nostore.com"],
+ });
+ server.registerFile(
+ "/favicon.ico",
+ new FileUtils.File(
+ PathUtils.join(
+ Services.dirsvc.get("CurWorkD", Ci.nsIFile).path,
+ "browser",
+ "browser",
+ "base",
+ "content",
+ "test",
+ "favicons",
+ "no-store.png"
+ )
+ )
+ );
+ server.registerPathHandler("/page", (request, response) => {
+ response.write("<html>A page without icon</html>");
+ });
+
+ let noStorePromise = TestUtils.topicObserved(
+ "http-on-stop-request",
+ (s, t, d) => {
+ let chan = s.QueryInterface(Ci.nsIHttpChannel);
+ return chan?.URI.spec == "http://www.nostore.com/favicon.ico";
+ }
+ ).then(([chan]) => chan.isNoStoreResponse());
+
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url: "http://www.nostore.com/page",
+ },
+ async function (browser) {
+ await TestUtils.waitForCondition(async () => {
+ let uri = await new Promise(resolve =>
+ PlacesUtils.favicons.getFaviconURLForPage(
+ Services.io.newURI("http://www.nostore.com/page"),
+ resolve
+ )
+ );
+ return uri?.spec == "http://www.nostore.com/favicon.ico";
+ }, "wait for the favicon to be stored");
+ Assert.ok(await noStorePromise, "Should have received no-store header");
+ }
+ );
+});
diff --git a/browser/base/content/test/favicons/browser_favicon_referer.js b/browser/base/content/test/favicons/browser_favicon_referer.js
new file mode 100644
index 0000000000..ad1cb5d9b1
--- /dev/null
+++ b/browser/base/content/test/favicons/browser_favicon_referer.js
@@ -0,0 +1,62 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const FOLDER = getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content/",
+ "http://mochi.test:8888/"
+);
+
+add_task(async function test_check_referrer_for_discovered_favicon() {
+ await BrowserTestUtils.withNewTab(
+ { gBrowser, url: "about:blank" },
+ async browser => {
+ let referrerPromise = TestUtils.topicObserved(
+ "http-on-modify-request",
+ (s, t, d) => {
+ let chan = s.QueryInterface(Ci.nsIHttpChannel);
+ return chan.URI.spec == "http://mochi.test:8888/favicon.ico";
+ }
+ ).then(([chan]) => chan.getRequestHeader("Referer"));
+
+ BrowserTestUtils.loadURIString(browser, `${FOLDER}discovery.html`);
+
+ let referrer = await referrerPromise;
+ is(
+ referrer,
+ `${FOLDER}discovery.html`,
+ "Should have sent referrer for autodiscovered favicon."
+ );
+ }
+ );
+});
+
+add_task(
+ async function test_check_referrer_for_referrerpolicy_explicit_favicon() {
+ await BrowserTestUtils.withNewTab(
+ { gBrowser, url: "about:blank" },
+ async browser => {
+ let referrerPromise = TestUtils.topicObserved(
+ "http-on-modify-request",
+ (s, t, d) => {
+ let chan = s.QueryInterface(Ci.nsIHttpChannel);
+ return chan.URI.spec == `${FOLDER}file_favicon.png`;
+ }
+ ).then(([chan]) => chan.getRequestHeader("Referer"));
+
+ BrowserTestUtils.loadURIString(
+ browser,
+ `${FOLDER}file_favicon_no_referrer.html`
+ );
+
+ let referrer = await referrerPromise;
+ is(
+ referrer,
+ "http://mochi.test:8888/",
+ "Should have sent the origin referrer only due to the per-link referrer policy specified."
+ );
+ }
+ );
+ }
+);
diff --git a/browser/base/content/test/favicons/browser_favicon_store.js b/browser/base/content/test/favicons/browser_favicon_store.js
new file mode 100644
index 0000000000..a183effe1a
--- /dev/null
+++ b/browser/base/content/test/favicons/browser_favicon_store.js
@@ -0,0 +1,56 @@
+/* Any copyright is dedicated to the Public Domain.
+ * https://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that favicons are stored.
+
+registerCleanupFunction(async () => {
+ Services.cache2.clear();
+ await PlacesTestUtils.clearFavicons();
+ await PlacesUtils.history.clear();
+});
+
+async function test_icon(pageUrl, iconUrl) {
+ let iconPromise = waitForFaviconMessage(true, iconUrl);
+ let storedIconPromise = PlacesTestUtils.waitForNotification(
+ "favicon-changed",
+ events => events.some(e => e.url == pageUrl)
+ );
+ await BrowserTestUtils.withNewTab(pageUrl, async () => {
+ let { iconURL } = await iconPromise;
+ Assert.equal(iconURL, iconUrl, "Should have seen the expected icon.");
+
+ // Ensure the favicon has been stored.
+ await storedIconPromise;
+ await new Promise((resolve, reject) => {
+ PlacesUtils.favicons.getFaviconURLForPage(
+ Services.io.newURI(pageUrl),
+ foundIconURI => {
+ if (foundIconURI) {
+ Assert.equal(
+ foundIconURI.spec,
+ iconUrl,
+ "Should have stored the expected icon."
+ );
+ resolve();
+ }
+ reject();
+ }
+ );
+ });
+ });
+}
+
+add_task(async function test_icon_stored() {
+ for (let [pageUrl, iconUrl] of [
+ [
+ "https://example.net/browser/browser/base/content/test/favicons/datauri-favicon.html",
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAATklEQVRYhe3SIQ4AIBADwf7/04elBAtrVlSduGnSTDJ7cuT1PQJwwO+Hl7sAGAA07gjAAfgIBeAAoHFHAA7ARygABwCNOwJwAD5CATRgAYXh+kypw86nAAAAAElFTkSuQmCC",
+ ],
+ [
+ "https://example.net/browser/browser/base/content/test/favicons/file_favicon.html",
+ "https://example.net/browser/browser/base/content/test/favicons/file_favicon.png",
+ ],
+ ]) {
+ await test_icon(pageUrl, iconUrl);
+ }
+});
diff --git a/browser/base/content/test/favicons/browser_icon_discovery.js b/browser/base/content/test/favicons/browser_icon_discovery.js
new file mode 100644
index 0000000000..6dc57b9880
--- /dev/null
+++ b/browser/base/content/test/favicons/browser_icon_discovery.js
@@ -0,0 +1,136 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/* eslint-disable mozilla/no-arbitrary-setTimeout */
+
+const ROOTURI =
+ "http://mochi.test:8888/browser/browser/base/content/test/favicons/";
+const ICON = "moz.png";
+const DATAURL =
+ "data:image/x-icon;base64,AAABAAEAEBAAAAAAAABoBQAAFgAAACgAAAAQAAAAIAAAAAEACAAAAAAAAAEAAAAAAAAAAAAAAAEAAAABAAAAAAAAAACAAACAAAAAgIAAgAAAAIAAgACAgAAAwMDAAMDcwADwyqYABAQEAAgICAAMDAwAERERABYWFgAcHBwAIiIiACkpKQBVVVUATU1NAEJCQgA5OTkAgHz/AFBQ/wCTANYA/+zMAMbW7wDW5+cAkKmtAAAAMwAAAGYAAACZAAAAzAAAMwAAADMzAAAzZgAAM5kAADPMAAAz/wAAZgAAAGYzAABmZgAAZpkAAGbMAABm/wAAmQAAAJkzAACZZgAAmZkAAJnMAACZ/wAAzAAAAMwzAADMZgAAzJkAAMzMAADM/wAA/2YAAP+ZAAD/zAAzAAAAMwAzADMAZgAzAJkAMwDMADMA/wAzMwAAMzMzADMzZgAzM5kAMzPMADMz/wAzZgAAM2YzADNmZgAzZpkAM2bMADNm/wAzmQAAM5kzADOZZgAzmZkAM5nMADOZ/wAzzAAAM8wzADPMZgAzzJkAM8zMADPM/wAz/zMAM/9mADP/mQAz/8wAM///AGYAAABmADMAZgBmAGYAmQBmAMwAZgD/AGYzAABmMzMAZjNmAGYzmQBmM8wAZjP/AGZmAABmZjMAZmZmAGZmmQBmZswAZpkAAGaZMwBmmWYAZpmZAGaZzABmmf8AZswAAGbMMwBmzJkAZszMAGbM/wBm/wAAZv8zAGb/mQBm/8wAzAD/AP8AzACZmQAAmTOZAJkAmQCZAMwAmQAAAJkzMwCZAGYAmTPMAJkA/wCZZgAAmWYzAJkzZgCZZpkAmWbMAJkz/wCZmTMAmZlmAJmZmQCZmcwAmZn/AJnMAACZzDMAZsxmAJnMmQCZzMwAmcz/AJn/AACZ/zMAmcxmAJn/mQCZ/8wAmf//AMwAAACZADMAzABmAMwAmQDMAMwAmTMAAMwzMwDMM2YAzDOZAMwzzADMM/8AzGYAAMxmMwCZZmYAzGaZAMxmzACZZv8AzJkAAMyZMwDMmWYAzJmZAMyZzADMmf8AzMwAAMzMMwDMzGYAzMyZAMzMzADMzP8AzP8AAMz/MwCZ/2YAzP+ZAMz/zADM//8AzAAzAP8AZgD/AJkAzDMAAP8zMwD/M2YA/zOZAP8zzAD/M/8A/2YAAP9mMwDMZmYA/2aZAP9mzADMZv8A/5kAAP+ZMwD/mWYA/5mZAP+ZzAD/mf8A/8wAAP/MMwD/zGYA/8yZAP/MzAD/zP8A//8zAMz/ZgD//5kA///MAGZm/wBm/2YAZv//AP9mZgD/Zv8A//9mACEApQBfX18Ad3d3AIaGhgCWlpYAy8vLALKysgDX19cA3d3dAOPj4wDq6uoA8fHxAPj4+ADw+/8ApKCgAICAgAAAAP8AAP8AAAD//wD/AAAA/wD/AP//AAD///8ACgoKCgoKCgoKCgoKCgoKCgoKCgoHAQEMbQoKCgoKCgoAAAdDH/kgHRIAAAAAAAAAAADrHfn5ASQQAAAAAAAAAArsBx0B+fkgHesAAAAAAAD/Cgwf+fn5IA4dEus/IvcACgcMAfkg+QEB+SABHushbf8QHR/5HQH5+QEdHetEHx4K7B/5+QH5+fkdDBL5+SBE/wwdJfkf+fn5AR8g+fkfEArsCh/5+QEeJR/5+SAeBwAACgoe+SAlHwFAEhAfAAAAAPcKHh8eASYBHhAMAAAAAAAA9EMdIB8gHh0dBwAAAAAAAAAA7BAdQ+wHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//AADwfwAAwH8AAMB/AAAAPwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAQAAgAcAAIAPAADADwAA8D8AAP//AAA=";
+
+let iconDiscoveryTests = [
+ {
+ text: "rel icon discovered",
+ icons: [{}],
+ },
+ {
+ text: "rel may contain additional rels separated by spaces",
+ icons: [{ rel: "abcdefg icon qwerty" }],
+ },
+ {
+ text: "rel is case insensitive",
+ icons: [{ rel: "ICON" }],
+ },
+ {
+ text: "rel shortcut-icon not discovered",
+ expectedIcon: ROOTURI + ICON,
+ icons: [
+ // We will prefer the later icon if detected
+ {},
+ { rel: "shortcut-icon", href: "nothere.png" },
+ ],
+ },
+ {
+ text: "relative href works",
+ icons: [{ href: "moz.png" }],
+ },
+ {
+ text: "404'd icon is removed properly",
+ pass: false,
+ icons: [{ href: "notthere.png" }],
+ },
+ {
+ text: "data: URIs work",
+ icons: [{ href: DATAURL, type: "image/x-icon" }],
+ },
+ {
+ text: "type may have optional parameters (RFC2046)",
+ icons: [{ type: "image/png; charset=utf-8" }],
+ },
+ {
+ text: "apple-touch-icon discovered",
+ richIcon: true,
+ icons: [{ rel: "apple-touch-icon" }],
+ },
+ {
+ text: "apple-touch-icon-precomposed discovered",
+ richIcon: true,
+ icons: [{ rel: "apple-touch-icon-precomposed" }],
+ },
+ {
+ text: "fluid-icon discovered",
+ richIcon: true,
+ icons: [{ rel: "fluid-icon" }],
+ },
+ {
+ text: "unknown icon not discovered",
+ expectedIcon: ROOTURI + ICON,
+ richIcon: true,
+ icons: [
+ // We will prefer the larger icon if detected
+ { rel: "apple-touch-icon", sizes: "32x32" },
+ { rel: "unknown-icon", sizes: "128x128", href: "notthere.png" },
+ ],
+ },
+];
+
+add_task(async function () {
+ let url = ROOTURI + "discovery.html";
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
+
+ for (let testCase of iconDiscoveryTests) {
+ info(`Running test "${testCase.text}"`);
+
+ if (testCase.pass === undefined) {
+ testCase.pass = true;
+ }
+
+ if (testCase.icons.length > 1 && !testCase.expectedIcon) {
+ ok(false, "Invalid test data, missing expectedIcon");
+ continue;
+ }
+
+ let expectedIcon = testCase.expectedIcon || testCase.icons[0].href || ICON;
+ expectedIcon = new URL(expectedIcon, ROOTURI).href;
+
+ let iconPromise = waitForFaviconMessage(!testCase.richIcon, expectedIcon);
+
+ await SpecialPowers.spawn(
+ gBrowser.selectedBrowser,
+ [[testCase.icons, ROOTURI + ICON]],
+ ([icons, defaultIcon]) => {
+ let doc = content.document;
+ let head = doc.head;
+
+ for (let icon of icons) {
+ let link = doc.createElement("link");
+ link.rel = icon.rel || "icon";
+ link.href = icon.href || defaultIcon;
+ link.type = icon.type || "image/png";
+ if (icon.sizes) {
+ link.sizes = icon.sizes;
+ }
+ head.appendChild(link);
+ }
+ }
+ );
+
+ try {
+ let { iconURL } = await iconPromise;
+ ok(testCase.pass, testCase.text);
+ is(iconURL, expectedIcon, "Should have seen the expected icon.");
+ } catch (e) {
+ ok(!testCase.pass, testCase.text);
+ }
+
+ await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
+ let links = content.document.querySelectorAll("link");
+ for (let link of links) {
+ link.remove();
+ }
+ });
+ }
+
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/browser/base/content/test/favicons/browser_invalid_href_fallback.js b/browser/base/content/test/favicons/browser_invalid_href_fallback.js
new file mode 100644
index 0000000000..d2a36b970d
--- /dev/null
+++ b/browser/base/content/test/favicons/browser_invalid_href_fallback.js
@@ -0,0 +1,29 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+add_task(async () => {
+ const testPath =
+ // eslint-disable-next-line @microsoft/sdl/no-insecure-url
+ "http://example.com/browser/browser/base/content/test/favicons/";
+ // eslint-disable-next-line @microsoft/sdl/no-insecure-url
+ const expectedIcon = "http://example.com/favicon.ico";
+
+ await BrowserTestUtils.withNewTab(
+ { gBrowser, url: "about:blank" },
+ async browser => {
+ let faviconPromise = waitForLinkAvailable(browser);
+ BrowserTestUtils.loadURIString(
+ browser,
+ testPath + "file_invalid_href.html"
+ );
+ await BrowserTestUtils.browserLoaded(browser);
+
+ let iconURI = await faviconPromise;
+ Assert.equal(
+ iconURI,
+ expectedIcon,
+ "Should have fallen back to the default site favicon for an invalid href attribute"
+ );
+ }
+ );
+});
diff --git a/browser/base/content/test/favicons/browser_missing_favicon.js b/browser/base/content/test/favicons/browser_missing_favicon.js
new file mode 100644
index 0000000000..40dce7f7a9
--- /dev/null
+++ b/browser/base/content/test/favicons/browser_missing_favicon.js
@@ -0,0 +1,36 @@
+add_task(async () => {
+ let testPath = getRootDirectory(gTestPath);
+
+ // The default favicon would interfere with this test.
+ Services.prefs.setBoolPref("browser.chrome.guess_favicon", false);
+ registerCleanupFunction(() => {
+ Services.prefs.setBoolPref("browser.chrome.guess_favicon", true);
+ });
+
+ await BrowserTestUtils.withNewTab(
+ { gBrowser, url: "about:blank" },
+ async browser => {
+ const expectedIcon = testPath + "file_generic_favicon.ico";
+ let faviconPromise = waitForLinkAvailable(browser);
+
+ BrowserTestUtils.loadURIString(
+ browser,
+ testPath + "file_with_favicon.html"
+ );
+ await BrowserTestUtils.browserLoaded(browser);
+
+ let iconURI = await faviconPromise;
+ is(iconURI, expectedIcon, "Got correct icon.");
+
+ BrowserTestUtils.loadURIString(browser, testPath + "blank.html");
+ await BrowserTestUtils.browserLoaded(browser);
+
+ is(browser.mIconURL, null, "Should have blanked the icon.");
+ is(
+ gBrowser.getTabForBrowser(browser).getAttribute("image"),
+ "",
+ "Should have blanked the tab icon."
+ );
+ }
+ );
+});
diff --git a/browser/base/content/test/favicons/browser_mixed_content.js b/browser/base/content/test/favicons/browser_mixed_content.js
new file mode 100644
index 0000000000..37bc86f12f
--- /dev/null
+++ b/browser/base/content/test/favicons/browser_mixed_content.js
@@ -0,0 +1,26 @@
+add_task(async () => {
+ await SpecialPowers.pushPrefEnv({
+ set: [["security.mixed_content.upgrade_display_content", false]],
+ });
+
+ const testPath =
+ "https://example.com/browser/browser/base/content/test/favicons/file_insecure_favicon.html";
+ const expectedIcon =
+ "http://example.com/browser/browser/base/content/test/favicons/file_favicon.png";
+
+ let tab = BrowserTestUtils.addTab(gBrowser, testPath);
+ gBrowser.selectedTab = tab;
+ let browser = tab.linkedBrowser;
+
+ let faviconPromise = waitForLinkAvailable(browser);
+ await BrowserTestUtils.browserLoaded(browser);
+ let iconURI = await faviconPromise;
+ is(iconURI, expectedIcon, "Got correct icon.");
+
+ ok(
+ gIdentityHandler._isMixedPassiveContentLoaded,
+ "Should have seen mixed content."
+ );
+
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/browser/base/content/test/favicons/browser_multiple_icons_in_short_timeframe.js b/browser/base/content/test/favicons/browser_multiple_icons_in_short_timeframe.js
new file mode 100644
index 0000000000..80a45a9288
--- /dev/null
+++ b/browser/base/content/test/favicons/browser_multiple_icons_in_short_timeframe.js
@@ -0,0 +1,37 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+add_task(async function () {
+ const ROOT =
+ "http://mochi.test:8888/browser/browser/base/content/test/favicons/";
+ const URL = ROOT + "discovery.html";
+
+ let iconPromise = waitForFaviconMessage(
+ true,
+ "http://mochi.test:8888/favicon.ico"
+ );
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
+ let icon = await iconPromise;
+
+ await SpecialPowers.spawn(gBrowser.selectedBrowser, [ROOT], root => {
+ let doc = content.document;
+ let head = doc.head;
+ let link = doc.createElement("link");
+ link.rel = "icon";
+ link.href = root + "rich_moz_1.png";
+ link.type = "image/png";
+ head.appendChild(link);
+ let link2 = link.cloneNode(false);
+ link2.href = root + "rich_moz_2.png";
+ head.appendChild(link2);
+ });
+
+ icon = await waitForFaviconMessage();
+ Assert.equal(
+ icon.iconURL,
+ ROOT + "rich_moz_2.png",
+ "The expected icon has been set"
+ );
+
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/browser/base/content/test/favicons/browser_oversized.js b/browser/base/content/test/favicons/browser_oversized.js
new file mode 100644
index 0000000000..4756873a30
--- /dev/null
+++ b/browser/base/content/test/favicons/browser_oversized.js
@@ -0,0 +1,25 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const ROOT =
+ "http://mochi.test:8888/browser/browser/base/content/test/favicons/";
+
+add_task(async () => {
+ await BrowserTestUtils.withNewTab(
+ { gBrowser, url: "about:blank" },
+ async browser => {
+ let faviconPromise = waitForFaviconMessage(true, `${ROOT}large.png`);
+
+ BrowserTestUtils.loadURIString(browser, ROOT + "large_favicon.html");
+ await BrowserTestUtils.browserLoaded(browser);
+
+ await Assert.rejects(
+ faviconPromise,
+ result => {
+ return result.iconURL == `${ROOT}large.png`;
+ },
+ "Should have failed to load the large icon."
+ );
+ }
+ );
+});
diff --git a/browser/base/content/test/favicons/browser_preferred_icons.js b/browser/base/content/test/favicons/browser_preferred_icons.js
new file mode 100644
index 0000000000..25f548c717
--- /dev/null
+++ b/browser/base/content/test/favicons/browser_preferred_icons.js
@@ -0,0 +1,140 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const ROOT =
+ "http://mochi.test:8888/browser/browser/base/content/test/favicons/";
+
+async function waitIcon(url) {
+ let icon = await waitForFaviconMessage(true, url);
+ is(icon.iconURL, url, "Should have seen the right icon.");
+}
+
+function createLinks(linkInfos) {
+ return SpecialPowers.spawn(gBrowser.selectedBrowser, [linkInfos], links => {
+ let doc = content.document;
+ let head = doc.head;
+ for (let l of links) {
+ let link = doc.createElement("link");
+ link.rel = "icon";
+ link.href = l.href;
+ if (l.type) {
+ link.type = l.type;
+ }
+ if (l.size) {
+ link.setAttribute("sizes", `${l.size}x${l.size}`);
+ }
+ head.appendChild(link);
+ }
+ });
+}
+
+add_setup(async function () {
+ const URL = ROOT + "discovery.html";
+ let iconPromise = waitIcon("http://mochi.test:8888/favicon.ico");
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
+ await iconPromise;
+ registerCleanupFunction(async function () {
+ BrowserTestUtils.removeTab(tab);
+ });
+});
+
+add_task(async function prefer_svg() {
+ let promise = waitIcon(ROOT + "icon.svg");
+ await createLinks([
+ { href: ROOT + "icon.ico", type: "image/x-icon" },
+ { href: ROOT + "icon.svg", type: "image/svg+xml" },
+ {
+ href: ROOT + "icon.png",
+ type: "image/png",
+ size: 16 * Math.ceil(window.devicePixelRatio),
+ },
+ ]);
+ await promise;
+});
+
+add_task(async function prefer_sized() {
+ let promise = waitIcon(ROOT + "moz.png");
+ await createLinks([
+ { href: ROOT + "icon.ico", type: "image/x-icon" },
+ {
+ href: ROOT + "moz.png",
+ type: "image/png",
+ size: 16 * Math.ceil(window.devicePixelRatio),
+ },
+ { href: ROOT + "icon2.ico", type: "image/x-icon" },
+ ]);
+ await promise;
+});
+
+add_task(async function prefer_last_ico() {
+ let promise = waitIcon(ROOT + "file_generic_favicon.ico");
+ await createLinks([
+ { href: ROOT + "icon.ico", type: "image/x-icon" },
+ { href: ROOT + "icon.png", type: "image/png" },
+ { href: ROOT + "file_generic_favicon.ico", type: "image/x-icon" },
+ ]);
+ await promise;
+});
+
+add_task(async function fuzzy_ico() {
+ let promise = waitIcon(ROOT + "file_generic_favicon.ico");
+ await createLinks([
+ { href: ROOT + "icon.ico", type: "image/x-icon" },
+ { href: ROOT + "icon.png", type: "image/png" },
+ {
+ href: ROOT + "file_generic_favicon.ico",
+ type: "image/vnd.microsoft.icon",
+ },
+ ]);
+ await promise;
+});
+
+add_task(async function guess_svg() {
+ let promise = waitIcon(ROOT + "icon.svg");
+ await createLinks([
+ { href: ROOT + "icon.svg" },
+ {
+ href: ROOT + "icon.png",
+ type: "image/png",
+ size: 16 * Math.ceil(window.devicePixelRatio),
+ },
+ { href: ROOT + "icon.ico", type: "image/x-icon" },
+ ]);
+ await promise;
+});
+
+add_task(async function guess_ico() {
+ let promise = waitIcon(ROOT + "file_generic_favicon.ico");
+ await createLinks([
+ { href: ROOT + "file_generic_favicon.ico" },
+ { href: ROOT + "icon.png", type: "image/png" },
+ ]);
+ await promise;
+});
+
+add_task(async function guess_invalid() {
+ let promise = waitIcon(ROOT + "icon.svg");
+ // Create strange links to make sure they don't break us
+ await createLinks([
+ { href: ROOT + "icon.svg" },
+ { href: ROOT + "icon" },
+ { href: ROOT + "icon?.svg" },
+ { href: ROOT + "icon#.svg" },
+ { href: "data:text/plain,icon" },
+ { href: "file:///icon" },
+ { href: "about:icon" },
+ ]);
+ await promise;
+});
+
+add_task(async function guess_bestSized() {
+ let preferredWidth = 16 * Math.ceil(window.devicePixelRatio);
+ let promise = waitIcon(ROOT + "moz.png");
+ await createLinks([
+ { href: ROOT + "icon.png", type: "image/png", size: preferredWidth - 1 },
+ { href: ROOT + "icon2.png", type: "image/png" },
+ { href: ROOT + "moz.png", type: "image/png", size: preferredWidth + 1 },
+ { href: ROOT + "icon4.png", type: "image/png", size: preferredWidth + 2 },
+ ]);
+ await promise;
+});
diff --git a/browser/base/content/test/favicons/browser_redirect.js b/browser/base/content/test/favicons/browser_redirect.js
new file mode 100644
index 0000000000..ea2b053be7
--- /dev/null
+++ b/browser/base/content/test/favicons/browser_redirect.js
@@ -0,0 +1,20 @@
+const ROOT =
+ "http://mochi.test:8888/browser/browser/base/content/test/favicons/";
+
+add_task(async () => {
+ const URL = ROOT + "file_favicon_redirect.html";
+ const EXPECTED_ICON = ROOT + "file_favicon_redirect.ico";
+
+ let promise = waitForFaviconMessage(true, EXPECTED_ICON);
+
+ const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
+ let tabIcon = await promise;
+
+ is(
+ tabIcon.iconURL,
+ EXPECTED_ICON,
+ "should use the redirected icon for the tab"
+ );
+
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/browser/base/content/test/favicons/browser_rich_icons.js b/browser/base/content/test/favicons/browser_rich_icons.js
new file mode 100644
index 0000000000..2020b7bdad
--- /dev/null
+++ b/browser/base/content/test/favicons/browser_rich_icons.js
@@ -0,0 +1,50 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/* eslint-disable mozilla/no-arbitrary-setTimeout */
+
+const ROOT =
+ "http://mochi.test:8888/browser/browser/base/content/test/favicons/";
+
+add_task(async function test_richIcons() {
+ const URL = ROOT + "file_rich_icon.html";
+ const EXPECTED_ICON = ROOT + "moz.png";
+ const EXPECTED_RICH_ICON = ROOT + "rich_moz_2.png";
+
+ let tabPromises = Promise.all([
+ waitForFaviconMessage(true, EXPECTED_ICON),
+ waitForFaviconMessage(false, EXPECTED_RICH_ICON),
+ ]);
+
+ const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
+ let [tabIcon, richIcon] = await tabPromises;
+
+ is(
+ richIcon.iconURL,
+ EXPECTED_RICH_ICON,
+ "should choose the largest rich icon"
+ );
+ is(
+ tabIcon.iconURL,
+ EXPECTED_ICON,
+ "should use the non-rich icon for the tab"
+ );
+
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_maskIcons() {
+ const URL = ROOT + "file_mask_icon.html";
+ const EXPECTED_ICON = "http://mochi.test:8888/favicon.ico";
+
+ let promise = waitForFaviconMessage(true, EXPECTED_ICON);
+ const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
+ let tabIcon = await promise;
+ is(
+ tabIcon.iconURL,
+ EXPECTED_ICON,
+ "should ignore the mask icons and load the root favicon"
+ );
+
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/browser/base/content/test/favicons/browser_rooticon.js b/browser/base/content/test/favicons/browser_rooticon.js
new file mode 100644
index 0000000000..6e642070c7
--- /dev/null
+++ b/browser/base/content/test/favicons/browser_rooticon.js
@@ -0,0 +1,24 @@
+add_task(async () => {
+ const testPath =
+ // eslint-disable-next-line @microsoft/sdl/no-insecure-url
+ "http://example.com/browser/browser/base/content/test/favicons/blank.html";
+ // eslint-disable-next-line @microsoft/sdl/no-insecure-url
+ const expectedIcon = "http://example.com/favicon.ico";
+
+ let tab = BrowserTestUtils.addTab(gBrowser, testPath);
+ gBrowser.selectedTab = tab;
+ let browser = tab.linkedBrowser;
+
+ let faviconPromise = waitForLinkAvailable(browser);
+ await BrowserTestUtils.browserLoaded(browser);
+ let iconURI = await faviconPromise;
+ is(iconURI, expectedIcon, "Got correct initial icon.");
+
+ faviconPromise = waitForLinkAvailable(browser);
+ BrowserTestUtils.loadURIString(browser, testPath);
+ await BrowserTestUtils.browserLoaded(browser);
+ iconURI = await faviconPromise;
+ is(iconURI, expectedIcon, "Got correct icon on second load.");
+
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/browser/base/content/test/favicons/browser_subframe_favicons_not_used.js b/browser/base/content/test/favicons/browser_subframe_favicons_not_used.js
new file mode 100644
index 0000000000..ff48bcd475
--- /dev/null
+++ b/browser/base/content/test/favicons/browser_subframe_favicons_not_used.js
@@ -0,0 +1,22 @@
+/* Make sure <link rel="..."> isn't respected in sub-frames. */
+
+add_task(async function () {
+ const ROOT =
+ "http://mochi.test:8888/browser/browser/base/content/test/favicons/";
+ const URL = ROOT + "file_bug970276_popup1.html";
+
+ let promiseIcon = waitForFaviconMessage(
+ true,
+ ROOT + "file_bug970276_favicon1.ico"
+ );
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
+ let icon = await promiseIcon;
+
+ Assert.equal(
+ icon.iconURL,
+ ROOT + "file_bug970276_favicon1.ico",
+ "The expected icon has been set"
+ );
+
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/browser/base/content/test/favicons/browser_title_flicker.js b/browser/base/content/test/favicons/browser_title_flicker.js
new file mode 100644
index 0000000000..71fadce908
--- /dev/null
+++ b/browser/base/content/test/favicons/browser_title_flicker.js
@@ -0,0 +1,185 @@
+const TEST_PATH =
+ // eslint-disable-next-line @microsoft/sdl/no-insecure-url
+ "http://example.com/browser/browser/base/content/test/favicons/";
+
+function waitForAttributeChange(tab, attr) {
+ info(`Waiting for attribute ${attr}`);
+ return new Promise(resolve => {
+ let listener = event => {
+ if (event.detail.changed.includes(attr)) {
+ tab.removeEventListener("TabAttrModified", listener);
+ resolve();
+ }
+ };
+
+ tab.addEventListener("TabAttrModified", listener);
+ });
+}
+
+function waitForPendingIcon() {
+ return new Promise(resolve => {
+ let listener = () => {
+ LinkHandlerParent.removeListenerForTests(listener);
+ resolve();
+ };
+
+ LinkHandlerParent.addListenerForTests(listener);
+ });
+}
+
+// Verify that the title doesn't flicker if the icon takes too long to load.
+// We expect to see events in the following order:
+// "label" added to tab
+// "busy" removed from tab
+// icon available
+// In all those cases the title should be in the same position.
+add_task(async () => {
+ await BrowserTestUtils.withNewTab(
+ { gBrowser, url: "about:blank" },
+ async browser => {
+ let tab = gBrowser.getTabForBrowser(browser);
+ BrowserTestUtils.loadURIString(
+ browser,
+ TEST_PATH + "file_with_slow_favicon.html"
+ );
+
+ await waitForAttributeChange(tab, "label");
+ ok(tab.hasAttribute("busy"), "Should have seen the busy attribute");
+ let label = tab.textLabel;
+ let bounds = label.getBoundingClientRect();
+
+ await waitForAttributeChange(tab, "busy");
+ ok(
+ !tab.hasAttribute("busy"),
+ "Should have seen the busy attribute removed"
+ );
+ let newBounds = label.getBoundingClientRect();
+ is(
+ bounds.x,
+ newBounds.left,
+ "Should have seen the title in the same place."
+ );
+
+ await waitForFaviconMessage(true);
+ newBounds = label.getBoundingClientRect();
+ is(
+ bounds.x,
+ newBounds.left,
+ "Should have seen the title in the same place."
+ );
+ }
+ );
+});
+
+// Verify that the title doesn't flicker if a new icon is detected after load.
+add_task(async () => {
+ let iconAvailable = waitForFaviconMessage(true);
+ await BrowserTestUtils.withNewTab(
+ { gBrowser, url: TEST_PATH + "blank.html" },
+ async browser => {
+ let icon = await iconAvailable;
+ // eslint-disable-next-line @microsoft/sdl/no-insecure-url
+ is(icon.iconURL, "http://example.com/favicon.ico");
+
+ let tab = gBrowser.getTabForBrowser(browser);
+ let label = tab.textLabel;
+ let bounds = label.getBoundingClientRect();
+
+ await SpecialPowers.spawn(browser, [], () => {
+ let link = content.document.createElement("link");
+ link.setAttribute("href", "file_favicon.png");
+ link.setAttribute("rel", "icon");
+ link.setAttribute("type", "image/png");
+ content.document.head.appendChild(link);
+ });
+
+ ok(
+ !tab.hasAttribute("pendingicon"),
+ "Should not have marked a pending icon"
+ );
+ let newBounds = label.getBoundingClientRect();
+ is(
+ bounds.x,
+ newBounds.left,
+ "Should have seen the title in the same place."
+ );
+
+ await waitForPendingIcon();
+
+ ok(
+ !tab.hasAttribute("pendingicon"),
+ "Should not have marked a pending icon"
+ );
+ newBounds = label.getBoundingClientRect();
+ is(
+ bounds.x,
+ newBounds.left,
+ "Should have seen the title in the same place."
+ );
+
+ icon = await waitForFaviconMessage(true);
+ is(
+ icon.iconURL,
+ TEST_PATH + "file_favicon.png",
+ "Should have loaded the new icon."
+ );
+
+ ok(
+ !tab.hasAttribute("pendingicon"),
+ "Should not have marked a pending icon"
+ );
+ newBounds = label.getBoundingClientRect();
+ is(
+ bounds.x,
+ newBounds.left,
+ "Should have seen the title in the same place."
+ );
+ }
+ );
+});
+
+// Verify that pinned tabs don't change size when an icon is pending.
+add_task(async () => {
+ await BrowserTestUtils.withNewTab(
+ { gBrowser, url: "about:blank" },
+ async browser => {
+ let tab = gBrowser.getTabForBrowser(browser);
+ gBrowser.pinTab(tab);
+
+ let bounds = tab.getBoundingClientRect();
+ BrowserTestUtils.loadURIString(
+ browser,
+ TEST_PATH + "file_with_slow_favicon.html"
+ );
+
+ await waitForAttributeChange(tab, "label");
+ ok(tab.hasAttribute("busy"), "Should have seen the busy attribute");
+ let newBounds = tab.getBoundingClientRect();
+ is(
+ bounds.width,
+ newBounds.width,
+ "Should have seen tab remain the same size."
+ );
+
+ await waitForAttributeChange(tab, "busy");
+ ok(
+ !tab.hasAttribute("busy"),
+ "Should have seen the busy attribute removed"
+ );
+ newBounds = tab.getBoundingClientRect();
+ is(
+ bounds.width,
+ newBounds.width,
+ "Should have seen tab remain the same size."
+ );
+
+ await waitForFaviconMessage(true);
+ newBounds = tab.getBoundingClientRect();
+ is(
+ bounds.width,
+ newBounds.width,
+ "Should have seen tab remain the same size."
+ );
+ }
+ );
+});
diff --git a/browser/base/content/test/favicons/cookie_favicon.html b/browser/base/content/test/favicons/cookie_favicon.html
new file mode 100644
index 0000000000..618ac1850b
--- /dev/null
+++ b/browser/base/content/test/favicons/cookie_favicon.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset='utf-8'>
+ <title>Favicon Test for caching</title>
+ <link rel="icon" type="image/png" href="cookie_favicon.sjs" />
+ </head>
+ <body>
+ Favicon!!
+ </body>
+</html>
diff --git a/browser/base/content/test/favicons/cookie_favicon.sjs b/browser/base/content/test/favicons/cookie_favicon.sjs
new file mode 100644
index 0000000000..a00d48d09a
--- /dev/null
+++ b/browser/base/content/test/favicons/cookie_favicon.sjs
@@ -0,0 +1,26 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function handleRequest(request, response) {
+ if (request.queryString == "reset") {
+ setState("cache_cookie", "0");
+ response.setStatusLine(request.httpVersion, 200, "Ok");
+ response.write("Reset");
+ return;
+ }
+
+ let state = getState("cache_cookie");
+ if (!state) {
+ state = 0;
+ }
+
+ response.setStatusLine(request.httpVersion, 302, "Moved Temporarily");
+ response.setHeader("Set-Cookie", `faviconCookie=${++state}`);
+ response.setHeader(
+ "Location",
+ // eslint-disable-next-line @microsoft/sdl/no-insecure-url
+ "http://example.com/browser/browser/base/content/test/favicons/moz.png"
+ );
+ setState("cache_cookie", `${state}`);
+}
diff --git a/browser/base/content/test/favicons/credentials.png b/browser/base/content/test/favicons/credentials.png
new file mode 100644
index 0000000000..769c636340
--- /dev/null
+++ b/browser/base/content/test/favicons/credentials.png
Binary files differ
diff --git a/browser/base/content/test/favicons/credentials.png^headers^ b/browser/base/content/test/favicons/credentials.png^headers^
new file mode 100644
index 0000000000..72339d67f0
--- /dev/null
+++ b/browser/base/content/test/favicons/credentials.png^headers^
@@ -0,0 +1,3 @@
+Access-Control-Allow-Origin: https://example.net
+Access-Control-Allow-Credentials: true
+Set-Cookie: faviconCookie2=test; SameSite=None; Secure;
diff --git a/browser/base/content/test/favicons/credentials1.html b/browser/base/content/test/favicons/credentials1.html
new file mode 100644
index 0000000000..2ccfd00e79
--- /dev/null
+++ b/browser/base/content/test/favicons/credentials1.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="UTF-8" />
+ <title>Favicon test for cross-origin credentials</title>
+ <link rel="icon" href="https://example.com/browser/browser/base/content/test/favicons/credentials.png" crossorigin />
+</head>
+<body>
+</body>
+</html>
diff --git a/browser/base/content/test/favicons/credentials2.html b/browser/base/content/test/favicons/credentials2.html
new file mode 100644
index 0000000000..cc28ca77bd
--- /dev/null
+++ b/browser/base/content/test/favicons/credentials2.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="UTF-8" />
+ <title>Favicon test for cross-origin credentials</title>
+ <link rel="icon" href="https://example.com/browser/browser/base/content/test/favicons/credentials.png" crossorigin="use-credentials" />
+</head>
+<body>
+</body>
+</html>
diff --git a/browser/base/content/test/favicons/crossorigin.html b/browser/base/content/test/favicons/crossorigin.html
new file mode 100644
index 0000000000..26a6a85d17
--- /dev/null
+++ b/browser/base/content/test/favicons/crossorigin.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="UTF-8" />
+ <title>Favicon test for the crossorigin attribute</title>
+ <link rel="icon" href="http://example.com/browser/browser/base/content/test/favicons/crossorigin.png" crossorigin />
+</head>
+<body>
+</body>
+</html>
diff --git a/browser/base/content/test/favicons/crossorigin.png b/browser/base/content/test/favicons/crossorigin.png
new file mode 100644
index 0000000000..769c636340
--- /dev/null
+++ b/browser/base/content/test/favicons/crossorigin.png
Binary files differ
diff --git a/browser/base/content/test/favicons/crossorigin.png^headers^ b/browser/base/content/test/favicons/crossorigin.png^headers^
new file mode 100644
index 0000000000..3a6a85d894
--- /dev/null
+++ b/browser/base/content/test/favicons/crossorigin.png^headers^
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: http://mochi.test:8888
diff --git a/browser/base/content/test/favicons/datauri-favicon.html b/browser/base/content/test/favicons/datauri-favicon.html
new file mode 100644
index 0000000000..35954f67a1
--- /dev/null
+++ b/browser/base/content/test/favicons/datauri-favicon.html
@@ -0,0 +1,8 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Favicon tab</title>
+ <link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAATklEQVRYhe3SIQ4AIBADwf7/04elBAtrVlSduGnSTDJ7cuT1PQJwwO+Hl7sAGAA07gjAAfgIBeAAoHFHAA7ARygABwCNOwJwAD5CATRgAYXh+kypw86nAAAAAElFTkSuQmCC">
+ <head>
+ <body>Some page with a favicon</body>
+</html>
diff --git a/browser/base/content/test/favicons/discovery.html b/browser/base/content/test/favicons/discovery.html
new file mode 100644
index 0000000000..2ff2aaa5f2
--- /dev/null
+++ b/browser/base/content/test/favicons/discovery.html
@@ -0,0 +1,8 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Autodiscovery Test</title>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/browser/base/content/test/favicons/file_bug970276_favicon1.ico b/browser/base/content/test/favicons/file_bug970276_favicon1.ico
new file mode 100644
index 0000000000..d44438903b
--- /dev/null
+++ b/browser/base/content/test/favicons/file_bug970276_favicon1.ico
Binary files differ
diff --git a/browser/base/content/test/favicons/file_bug970276_favicon2.ico b/browser/base/content/test/favicons/file_bug970276_favicon2.ico
new file mode 100644
index 0000000000..d44438903b
--- /dev/null
+++ b/browser/base/content/test/favicons/file_bug970276_favicon2.ico
Binary files differ
diff --git a/browser/base/content/test/favicons/file_bug970276_popup1.html b/browser/base/content/test/favicons/file_bug970276_popup1.html
new file mode 100644
index 0000000000..5ce7dab879
--- /dev/null
+++ b/browser/base/content/test/favicons/file_bug970276_popup1.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test file for bug 970276.</title>
+
+ <!--Set a favicon; that's the whole point of this file.-->
+ <link rel="icon" href="file_bug970276_favicon1.ico">
+</head>
+<body>
+ Test file for bug 970276.
+
+ <iframe src="file_bug970276_popup2.html">
+</body>
+</html>
diff --git a/browser/base/content/test/favicons/file_bug970276_popup2.html b/browser/base/content/test/favicons/file_bug970276_popup2.html
new file mode 100644
index 0000000000..0b9e5294ef
--- /dev/null
+++ b/browser/base/content/test/favicons/file_bug970276_popup2.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test file for bug 970276.</title>
+
+ <!--Set a favicon; that's the whole point of this file.-->
+ <link rel="icon" href="file_bug970276_favicon2.ico">
+</head>
+<body>
+ Test inner file for bug 970276.
+</body>
+</html>
diff --git a/browser/base/content/test/favicons/file_favicon.html b/browser/base/content/test/favicons/file_favicon.html
new file mode 100644
index 0000000000..f294b47758
--- /dev/null
+++ b/browser/base/content/test/favicons/file_favicon.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset='utf-8'>
+ <title>Favicon Test for originAttributes</title>
+ <link rel="icon" type="image/png" href="file_favicon.png" />
+ </head>
+ <body>
+ Favicon!!
+ </body>
+</html>
diff --git a/browser/base/content/test/favicons/file_favicon.png b/browser/base/content/test/favicons/file_favicon.png
new file mode 100644
index 0000000000..5535363c94
--- /dev/null
+++ b/browser/base/content/test/favicons/file_favicon.png
Binary files differ
diff --git a/browser/base/content/test/favicons/file_favicon.png^headers^ b/browser/base/content/test/favicons/file_favicon.png^headers^
new file mode 100644
index 0000000000..9e23c73b7f
--- /dev/null
+++ b/browser/base/content/test/favicons/file_favicon.png^headers^
@@ -0,0 +1 @@
+Cache-Control: no-cache
diff --git a/browser/base/content/test/favicons/file_favicon_change.html b/browser/base/content/test/favicons/file_favicon_change.html
new file mode 100644
index 0000000000..035549c5aa
--- /dev/null
+++ b/browser/base/content/test/favicons/file_favicon_change.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html><head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <link rel="icon" href="file_bug970276_favicon1.ico" type="image/ico" id="i">
+</head>
+<body>
+ <script>
+ window.addEventListener("PleaseChangeFavicon", function() {
+ var ico = document.getElementById("i");
+ ico.setAttribute("href", "moz.png");
+ });
+ </script>
+</body></html>
diff --git a/browser/base/content/test/favicons/file_favicon_change_not_in_document.html b/browser/base/content/test/favicons/file_favicon_change_not_in_document.html
new file mode 100644
index 0000000000..c44a2f8153
--- /dev/null
+++ b/browser/base/content/test/favicons/file_favicon_change_not_in_document.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html><head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <link rel="icon" href="file_bug970276_favicon1.ico" type="image/ico" id="i">
+</head>
+<body onload="onload()">
+ <script>
+ function onload() {
+ var ico = document.createElement("link");
+ ico.setAttribute("rel", "icon");
+ ico.setAttribute("type", "image/ico");
+ ico.setAttribute("href", "file_bug970276_favicon1.ico");
+ setTimeout(function() {
+ ico.setAttribute("href", "file_generic_favicon.ico");
+ document.getElementById("i").remove();
+ document.head.appendChild(ico);
+ }, 1000);
+ }
+ </script>
+</body></html>
diff --git a/browser/base/content/test/favicons/file_favicon_no_referrer.html b/browser/base/content/test/favicons/file_favicon_no_referrer.html
new file mode 100644
index 0000000000..4f363ffd04
--- /dev/null
+++ b/browser/base/content/test/favicons/file_favicon_no_referrer.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset='utf-8'>
+ <title>Favicon Test for referrer</title>
+ <link rel="icon" type="image/png" referrerpolicy="origin" href="file_favicon.png" />
+ </head>
+ <body>
+ Favicon!!
+ </body>
+</html>
diff --git a/browser/base/content/test/favicons/file_favicon_redirect.html b/browser/base/content/test/favicons/file_favicon_redirect.html
new file mode 100644
index 0000000000..9da4777591
--- /dev/null
+++ b/browser/base/content/test/favicons/file_favicon_redirect.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test file with an icon that redirects</title>
+
+ <!--Set a favicon; that's the whole point of this file.-->
+ <link rel="icon" href="file_favicon_redirect.ico">
+</head>
+<body>
+ Test file for bugs with favicons
+</body>
+</html>
diff --git a/browser/base/content/test/favicons/file_favicon_redirect.ico b/browser/base/content/test/favicons/file_favicon_redirect.ico
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/browser/base/content/test/favicons/file_favicon_redirect.ico
diff --git a/browser/base/content/test/favicons/file_favicon_redirect.ico^headers^ b/browser/base/content/test/favicons/file_favicon_redirect.ico^headers^
new file mode 100644
index 0000000000..380fa3d3a4
--- /dev/null
+++ b/browser/base/content/test/favicons/file_favicon_redirect.ico^headers^
@@ -0,0 +1,2 @@
+HTTP 302 Found
+Location: http://example.com/browser/browser/base/content/test/favicons/file_generic_favicon.ico
diff --git a/browser/base/content/test/favicons/file_favicon_thirdParty.html b/browser/base/content/test/favicons/file_favicon_thirdParty.html
new file mode 100644
index 0000000000..7d690e5981
--- /dev/null
+++ b/browser/base/content/test/favicons/file_favicon_thirdParty.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset='utf-8'>
+ <title>Favicon Test for originAttributes</title>
+ <link rel="icon" type="image/png" href="http://mochi.test:8888/browser/browser/base/content/test/favicons/file_favicon.png" />
+ </head>
+ <body>
+ Third Party Favicon!!
+ </body>
+</html>
diff --git a/browser/base/content/test/favicons/file_generic_favicon.ico b/browser/base/content/test/favicons/file_generic_favicon.ico
new file mode 100644
index 0000000000..d44438903b
--- /dev/null
+++ b/browser/base/content/test/favicons/file_generic_favicon.ico
Binary files differ
diff --git a/browser/base/content/test/favicons/file_insecure_favicon.html b/browser/base/content/test/favicons/file_insecure_favicon.html
new file mode 100644
index 0000000000..7b13b47829
--- /dev/null
+++ b/browser/base/content/test/favicons/file_insecure_favicon.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset='utf-8'>
+ <title>Favicon Test for mixed content</title>
+ <link rel="icon" type="image/png" href="http://example.com/browser/browser/base/content/test/favicons/file_favicon.png" />
+ </head>
+ <body>
+ Favicon!!
+ </body>
+</html>
diff --git a/browser/base/content/test/favicons/file_invalid_href.html b/browser/base/content/test/favicons/file_invalid_href.html
new file mode 100644
index 0000000000..087ff01403
--- /dev/null
+++ b/browser/base/content/test/favicons/file_invalid_href.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test file for bugs with invalid hrefs for favicons</title>
+
+ <!--Empty href; that's the whole point of this file.-->
+ <link rel="icon" href="">
+</head>
+<body>
+ Test file for bugs with invalid hrefs for favicons
+</body>
+</html>
diff --git a/browser/base/content/test/favicons/file_mask_icon.html b/browser/base/content/test/favicons/file_mask_icon.html
new file mode 100644
index 0000000000..5bcd9e694f
--- /dev/null
+++ b/browser/base/content/test/favicons/file_mask_icon.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset="UTF-8" />
+ <title>Mask Icon</title>
+ <link rel="icon" mask href="moz.png" type="image/png" />
+ <link rel="mask-icon" href="moz.png" type="image/png" />
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/browser/base/content/test/favicons/file_rich_icon.html b/browser/base/content/test/favicons/file_rich_icon.html
new file mode 100644
index 0000000000..ce7550b611
--- /dev/null
+++ b/browser/base/content/test/favicons/file_rich_icon.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset="UTF-8" />
+ <title>Rich Icons</title>
+ <link rel="icon" href="moz.png" type="image/png" />
+ <link rel="apple-touch-icon" sizes="96x96" href="rich_moz_1.png" type="image/png" />
+ <link rel="apple-touch-icon" sizes="256x256" href="rich_moz_2.png" type="image/png" />
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/browser/base/content/test/favicons/file_with_favicon.html b/browser/base/content/test/favicons/file_with_favicon.html
new file mode 100644
index 0000000000..0702b4aaba
--- /dev/null
+++ b/browser/base/content/test/favicons/file_with_favicon.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test file for bugs with favicons</title>
+
+ <!--Set a favicon; that's the whole point of this file.-->
+ <link rel="icon" href="file_generic_favicon.ico">
+</head>
+<body>
+ Test file for bugs with favicons
+</body>
+</html>
diff --git a/browser/base/content/test/favicons/file_with_slow_favicon.html b/browser/base/content/test/favicons/file_with_slow_favicon.html
new file mode 100644
index 0000000000..76fb015587
--- /dev/null
+++ b/browser/base/content/test/favicons/file_with_slow_favicon.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for title flicker</title>
+</head>
+<body>
+ <!-- Putting the icon down here means we won't start loading it until the doc is fully parsed -->
+ <link rel="icon" href="file_generic_favicon.ico">
+</body>
+</html>
diff --git a/browser/base/content/test/favicons/head.js b/browser/base/content/test/favicons/head.js
new file mode 100644
index 0000000000..ce16afd33f
--- /dev/null
+++ b/browser/base/content/test/favicons/head.js
@@ -0,0 +1,98 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+ChromeUtils.defineESModuleGetters(this, {
+ LinkHandlerParent: "resource:///actors/LinkHandlerParent.sys.mjs",
+ PlacesTestUtils: "resource://testing-common/PlacesTestUtils.sys.mjs",
+ PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs",
+
+ XPCShellContentUtils:
+ "resource://testing-common/XPCShellContentUtils.sys.mjs",
+});
+
+// Clear the network cache between every test to make sure we get a stable state
+Services.cache2.clear();
+
+function waitForFaviconMessage(isTabIcon = undefined, expectedURL = undefined) {
+ return new Promise((resolve, reject) => {
+ let listener = (name, data) => {
+ if (name != "SetIcon" && name != "SetFailedIcon") {
+ return; // Ignore unhandled messages
+ }
+
+ // If requested filter out loads of the wrong kind of icon.
+ if (isTabIcon != undefined && isTabIcon != data.canUseForTab) {
+ return;
+ }
+
+ if (expectedURL && data.originalURL != expectedURL) {
+ return;
+ }
+
+ LinkHandlerParent.removeListenerForTests(listener);
+
+ if (name == "SetIcon") {
+ resolve({
+ iconURL: data.originalURL,
+ dataURL: data.iconURL,
+ canUseForTab: data.canUseForTab,
+ });
+ } else {
+ reject({
+ iconURL: data.originalURL,
+ canUseForTab: data.canUseForTab,
+ });
+ }
+ };
+
+ LinkHandlerParent.addListenerForTests(listener);
+ });
+}
+
+function waitForFavicon(browser, url) {
+ return new Promise(resolve => {
+ let listener = {
+ onLinkIconAvailable(b, dataURI, iconURI) {
+ if (b !== browser || iconURI != url) {
+ return;
+ }
+
+ gBrowser.removeTabsProgressListener(listener);
+ resolve();
+ },
+ };
+
+ gBrowser.addTabsProgressListener(listener);
+ });
+}
+
+function waitForLinkAvailable(browser) {
+ let resolve, reject;
+
+ let listener = {
+ onLinkIconAvailable(b, dataURI, iconURI) {
+ // Ignore icons for other browsers or empty icons.
+ if (browser !== b || !iconURI) {
+ return;
+ }
+
+ gBrowser.removeTabsProgressListener(listener);
+ resolve(iconURI);
+ },
+ };
+
+ let promise = new Promise((res, rej) => {
+ resolve = res;
+ reject = rej;
+
+ gBrowser.addTabsProgressListener(listener);
+ });
+
+ promise.cancel = () => {
+ gBrowser.removeTabsProgressListener(listener);
+
+ reject();
+ };
+
+ return promise;
+}
diff --git a/browser/base/content/test/favicons/icon.svg b/browser/base/content/test/favicons/icon.svg
new file mode 100644
index 0000000000..6de9c64503
--- /dev/null
+++ b/browser/base/content/test/favicons/icon.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+ <circle cx="8" cy="8" r="8" fill="#8d20ae" />
+ <circle cx="8" cy="8" r="7.5" stroke="#7b149a" stroke-width="1" fill="none" />
+ <path d="M11.309,10.995C10.061,10.995,9.2,9.5,8,9.5s-2.135,1.5-3.309,1.5c-1.541,0-2.678-1.455-2.7-3.948C1.983,5.5,2.446,5.005,4.446,5.005S7.031,5.822,8,5.822s1.555-.817,3.555-0.817S14.017,5.5,14.006,7.047C13.987,9.54,12.85,10.995,11.309,10.995ZM5.426,6.911a1.739,1.739,0,0,0-1.716.953A2.049,2.049,0,0,0,5.3,8.544c0.788,0,1.716-.288,1.716-0.544A1.428,1.428,0,0,0,5.426,6.911Zm5.148,0A1.429,1.429,0,0,0,8.981,8c0,0.257.928,0.544,1.716,0.544a2.049,2.049,0,0,0,1.593-.681A1.739,1.739,0,0,0,10.574,6.911Z" stroke="#670c83" stroke-width="2" fill="none" />
+ <path d="M11.309,10.995C10.061,10.995,9.2,9.5,8,9.5s-2.135,1.5-3.309,1.5c-1.541,0-2.678-1.455-2.7-3.948C1.983,5.5,2.446,5.005,4.446,5.005S7.031,5.822,8,5.822s1.555-.817,3.555-0.817S14.017,5.5,14.006,7.047C13.987,9.54,12.85,10.995,11.309,10.995ZM5.426,6.911a1.739,1.739,0,0,0-1.716.953A2.049,2.049,0,0,0,5.3,8.544c0.788,0,1.716-.288,1.716-0.544A1.428,1.428,0,0,0,5.426,6.911Zm5.148,0A1.429,1.429,0,0,0,8.981,8c0,0.257.928,0.544,1.716,0.544a2.049,2.049,0,0,0,1.593-.681A1.739,1.739,0,0,0,10.574,6.911Z" fill="#fff" />
+</svg>
diff --git a/browser/base/content/test/favicons/large.png b/browser/base/content/test/favicons/large.png
new file mode 100644
index 0000000000..37012cf965
--- /dev/null
+++ b/browser/base/content/test/favicons/large.png
Binary files differ
diff --git a/browser/base/content/test/favicons/large_favicon.html b/browser/base/content/test/favicons/large_favicon.html
new file mode 100644
index 0000000000..48c5e8f19d
--- /dev/null
+++ b/browser/base/content/test/favicons/large_favicon.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test file for bugs with favicons</title>
+
+ <!--Set a favicon; that's the whole point of this file.-->
+ <link rel="icon" href="large.png">
+</head>
+<body>
+ Test file for bugs with favicons
+</body>
+</html>
diff --git a/browser/base/content/test/favicons/moz.png b/browser/base/content/test/favicons/moz.png
new file mode 100644
index 0000000000..769c636340
--- /dev/null
+++ b/browser/base/content/test/favicons/moz.png
Binary files differ
diff --git a/browser/base/content/test/favicons/no-store.html b/browser/base/content/test/favicons/no-store.html
new file mode 100644
index 0000000000..0d5bbbb475
--- /dev/null
+++ b/browser/base/content/test/favicons/no-store.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset='utf-8'>
+ <title>Favicon Test for Cache-Control: no-store</title>
+ <link rel="icon" type="image/png" href="no-store.png" />
+ </head>
+ <body>
+ Favicon!!
+ </body>
+</html>
diff --git a/browser/base/content/test/favicons/no-store.png b/browser/base/content/test/favicons/no-store.png
new file mode 100644
index 0000000000..769c636340
--- /dev/null
+++ b/browser/base/content/test/favicons/no-store.png
Binary files differ
diff --git a/browser/base/content/test/favicons/no-store.png^headers^ b/browser/base/content/test/favicons/no-store.png^headers^
new file mode 100644
index 0000000000..15a2442249
--- /dev/null
+++ b/browser/base/content/test/favicons/no-store.png^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store, no-cache, must-revalidate
diff --git a/browser/base/content/test/favicons/rich_moz_1.png b/browser/base/content/test/favicons/rich_moz_1.png
new file mode 100644
index 0000000000..769c636340
--- /dev/null
+++ b/browser/base/content/test/favicons/rich_moz_1.png
Binary files differ
diff --git a/browser/base/content/test/favicons/rich_moz_2.png b/browser/base/content/test/favicons/rich_moz_2.png
new file mode 100644
index 0000000000..769c636340
--- /dev/null
+++ b/browser/base/content/test/favicons/rich_moz_2.png
Binary files differ