diff options
Diffstat (limited to 'browser/base/content/test/favicons')
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 Binary files differnew file mode 100644 index 0000000000..769c636340 --- /dev/null +++ b/browser/base/content/test/favicons/credentials.png 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 Binary files differnew file mode 100644 index 0000000000..769c636340 --- /dev/null +++ b/browser/base/content/test/favicons/crossorigin.png 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 Binary files differnew file mode 100644 index 0000000000..d44438903b --- /dev/null +++ b/browser/base/content/test/favicons/file_bug970276_favicon1.ico diff --git a/browser/base/content/test/favicons/file_bug970276_favicon2.ico b/browser/base/content/test/favicons/file_bug970276_favicon2.ico Binary files differnew file mode 100644 index 0000000000..d44438903b --- /dev/null +++ b/browser/base/content/test/favicons/file_bug970276_favicon2.ico 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 Binary files differnew file mode 100644 index 0000000000..5535363c94 --- /dev/null +++ b/browser/base/content/test/favicons/file_favicon.png 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 Binary files differnew file mode 100644 index 0000000000..d44438903b --- /dev/null +++ b/browser/base/content/test/favicons/file_generic_favicon.ico 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 Binary files differnew file mode 100644 index 0000000000..37012cf965 --- /dev/null +++ b/browser/base/content/test/favicons/large.png 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 Binary files differnew file mode 100644 index 0000000000..769c636340 --- /dev/null +++ b/browser/base/content/test/favicons/moz.png 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 Binary files differnew file mode 100644 index 0000000000..769c636340 --- /dev/null +++ b/browser/base/content/test/favicons/no-store.png 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 Binary files differnew file mode 100644 index 0000000000..769c636340 --- /dev/null +++ b/browser/base/content/test/favicons/rich_moz_1.png diff --git a/browser/base/content/test/favicons/rich_moz_2.png b/browser/base/content/test/favicons/rich_moz_2.png Binary files differnew file mode 100644 index 0000000000..769c636340 --- /dev/null +++ b/browser/base/content/test/favicons/rich_moz_2.png |