From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../test/browser/browser_favicon_userContextId.js | 406 +++++++++++++++++++++ 1 file changed, 406 insertions(+) create mode 100644 browser/components/originattributes/test/browser/browser_favicon_userContextId.js (limited to 'browser/components/originattributes/test/browser/browser_favicon_userContextId.js') diff --git a/browser/components/originattributes/test/browser/browser_favicon_userContextId.js b/browser/components/originattributes/test/browser/browser_favicon_userContextId.js new file mode 100644 index 0000000000..282f2a83b7 --- /dev/null +++ b/browser/components/originattributes/test/browser/browser_favicon_userContextId.js @@ -0,0 +1,406 @@ +/** + * Bug 1277803 - A test caes for testing favicon loading across different userContextId. + */ + +if (SpecialPowers.useRemoteSubframes) { + requestLongerTimeout(2); +} + +let EventUtils = {}; +Services.scriptloader.loadSubScript( + "chrome://mochikit/content/tests/SimpleTest/EventUtils.js", + EventUtils +); + +ChromeUtils.defineESModuleGetters(this, { + PlacesTestUtils: "resource://testing-common/PlacesTestUtils.sys.mjs", + PromiseUtils: "resource://gre/modules/PromiseUtils.sys.mjs", +}); + +const TEST_SITE = "https://example.org"; +const TEST_THIRD_PARTY_SITE = "https://example.net"; + +const TEST_PAGE = + TEST_SITE + + "/browser/browser/components/originattributes/" + + "test/browser/file_favicon.html"; +const FAVICON_URI = + TEST_SITE + + "/browser/browser/components/originattributes/" + + "test/browser/file_favicon.png"; +const TEST_THIRD_PARTY_PAGE = + "http://example.net/browser/browser/components/" + + "originattributes/test/browser/file_favicon_thirdParty.html"; +const THIRD_PARTY_FAVICON_URI = + TEST_THIRD_PARTY_SITE + + "/browser/browser/components/" + + "originattributes/test/browser/file_favicon.png"; + +const USER_CONTEXT_ID_PERSONAL = 1; +const USER_CONTEXT_ID_WORK = 2; + +let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal(); + +function clearAllImageCaches() { + var tools = SpecialPowers.Cc["@mozilla.org/image/tools;1"].getService( + SpecialPowers.Ci.imgITools + ); + var imageCache = tools.getImgCacheForDocument(window.document); + imageCache.clearCache(true); // true=chrome + imageCache.clearCache(false); // false=content +} + +function clearAllPlacesFavicons() { + let faviconService = Cc["@mozilla.org/browser/favicon-service;1"].getService( + Ci.nsIFaviconService + ); + + return new Promise(resolve => { + let observer = { + observe(aSubject, aTopic, aData) { + if (aTopic === "places-favicons-expired") { + resolve(); + Services.obs.removeObserver(observer, "places-favicons-expired"); + } + }, + }; + + Services.obs.addObserver(observer, "places-favicons-expired"); + faviconService.expireAllFavicons(); + }); +} + +function FaviconObserver( + aUserContextId, + aExpectedCookie, + aPageURI, + aFaviconURL +) { + this.reset(aUserContextId, aExpectedCookie, aPageURI, aFaviconURL); +} + +FaviconObserver.prototype = { + observe(aSubject, aTopic, aData) { + // Make sure that the topic is 'http-on-modify-request'. + if (aTopic === "http-on-modify-request") { + // We check the userContextId for the originAttributes of the loading + // channel. All requests for the favicon should contain the correct + // userContextId. There are two requests for a favicon loading, one + // from the Places library and one from the XUL image. The difference + // of them is the loading principal. The Places will use the content + // principal and the XUL image will use the system principal. + + let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel); + let reqLoadInfo = httpChannel.loadInfo; + let loadingPrincipal, triggeringPrincipal; + + // Make sure this is a favicon request. + if (httpChannel.URI.spec !== this._faviconURL) { + return; + } + + if (reqLoadInfo) { + loadingPrincipal = reqLoadInfo.loadingPrincipal; + triggeringPrincipal = reqLoadInfo.triggeringPrincipal; + } + + // Check the userContextId. + is( + reqLoadInfo.originAttributes.userContextId, + this._curUserContextId, + "The loadInfo has correct userContextId" + ); + + ok( + loadingPrincipal.equals(this._expectedPrincipal), + "The loadingPrincipal of favicon loading from content should be the content prinicpal" + ); + ok( + triggeringPrincipal.equals(this._expectedPrincipal), + "The triggeringPrincipal of favicon loading from content should be the content prinicpal" + ); + + let faviconCookie = httpChannel.getRequestHeader("cookie"); + + is( + faviconCookie, + this._expectedCookie, + "The cookie of the favicon loading is correct." + ); + } else { + ok(false, "Received unexpected topic: ", aTopic); + } + + this._faviconLoaded.resolve(); + }, + + reset(aUserContextId, aExpectedCookie, aPageURI, aFaviconURL) { + this._curUserContextId = aUserContextId; + this._expectedCookie = aExpectedCookie; + this._expectedPrincipal = + Services.scriptSecurityManager.createContentPrincipal(aPageURI, { + userContextId: aUserContextId, + }); + this._faviconURL = aFaviconURL; + this._faviconLoaded = PromiseUtils.defer(); + }, + + get promise() { + return this._faviconLoaded.promise; + }, +}; + +function waitOnFaviconLoaded(aFaviconURL) { + return PlacesTestUtils.waitForNotification("favicon-changed", events => + events.some(e => e.faviconUrl == aFaviconURL) + ); +} + +async function generateCookies(aHost) { + // we generate two different cookies for two userContextIds. + let cookies = []; + cookies.push(Math.random().toString()); + cookies.push(Math.random().toString()); + + // Then, we add cookies into the site for 'personal' and 'work'. + let tabInfoA = await openTabInUserContext(aHost, USER_CONTEXT_ID_PERSONAL); + let tabInfoB = await openTabInUserContext(aHost, USER_CONTEXT_ID_WORK); + + await SpecialPowers.spawn( + tabInfoA.browser, + [cookies[0]], + async function (value) { + content.document.cookie = value; + } + ); + + await SpecialPowers.spawn( + tabInfoB.browser, + [cookies[1]], + async function (value) { + content.document.cookie = value; + } + ); + + BrowserTestUtils.removeTab(tabInfoA.tab); + BrowserTestUtils.removeTab(tabInfoB.tab); + + return cookies; +} + +async function doTest(aTestPage, aFaviconHost, aFaviconURL) { + let cookies = await generateCookies(aFaviconHost); + let pageURI = makeURI(aTestPage); + + // Create the observer object for observing request channels of the personal + // container. + let observer = new FaviconObserver( + USER_CONTEXT_ID_PERSONAL, + cookies[0], + pageURI, + aFaviconURL + ); + + // Add the observer earlier in case we miss it. + let promiseWaitOnFaviconLoaded = waitOnFaviconLoaded(aFaviconURL); + + Services.obs.addObserver(observer, "http-on-modify-request"); + + // Open the tab with the personal container. + let tabInfo = await openTabInUserContext(aTestPage, USER_CONTEXT_ID_PERSONAL); + + // Waiting for favicon requests are all made. + await observer.promise; + // Waiting for favicon loaded. + await promiseWaitOnFaviconLoaded; + + // Close the tab. + BrowserTestUtils.removeTab(tabInfo.tab); + // FIXME: We need to wait for the next event tick here to avoid observing + // the previous tab info in the next step (bug 1446725). + await new Promise(executeSoon); + + // Reset the observer for observing requests for the work container. + observer.reset(USER_CONTEXT_ID_WORK, cookies[1], pageURI, aFaviconURL); + tabInfo = await openTabInUserContext(aTestPage, USER_CONTEXT_ID_WORK); + + // Waiting for favicon requests are all made. + await observer.promise; + + Services.obs.removeObserver(observer, "http-on-modify-request"); + + BrowserTestUtils.removeTab(tabInfo.tab); +} + +function assertIconIsData(item) { + is( + item.getAttribute("image").substring(0, 5), + "data:", + "Expected the image element to be a data URI" + ); +} + +async function doTestForAllTabsFavicon(aTestPage, aFaviconHost, aFaviconURL) { + await generateCookies(aFaviconHost); + + // Set the 'overflow' attribute to make allTabs button available. + let tabBrowser = document.getElementById("tabbrowser-tabs"); + tabBrowser.setAttribute("overflow", true); + + // Add the observer earlier in case we miss it. + let promiseWaitOnFaviconLoaded = waitOnFaviconLoaded(aFaviconURL); + + // Open the tab with the personal container. + let tabInfo = await openTabInUserContext(aTestPage, USER_CONTEXT_ID_PERSONAL); + + // Waiting for favicon loaded. + await promiseWaitOnFaviconLoaded; + + // We need to clear the image cache here for making sure the network request will + // be made for the favicon of allTabs menuitem. + clearAllImageCaches(); + + gTabsPanel.init(); + + // Make the popup of allTabs showing up and trigger the loading of the favicon. + let allTabsView = document.getElementById("allTabsMenu-allTabsView"); + let allTabsPopupShownPromise = BrowserTestUtils.waitForEvent( + allTabsView, + "ViewShown" + ); + gTabsPanel.showAllTabsPanel(); + await allTabsPopupShownPromise; + + assertIconIsData( + gTabsPanel.allTabsViewTabs.lastElementChild.firstElementChild + ); + + // Close the popup of allTabs and wait until it's done. + let allTabsPopupHiddenPromise = BrowserTestUtils.waitForEvent( + allTabsView.panelMultiView, + "PanelMultiViewHidden" + ); + gTabsPanel.hideAllTabsPanel(); + await allTabsPopupHiddenPromise; + + // Close the tab. + BrowserTestUtils.removeTab(tabInfo.tab); + // FIXME: We need to wait for the next event tick here to avoid observing + // the previous tab info in the next step (bug 1446725). + await new Promise(executeSoon); + + // Open the tab under the work container and wait until the favicon is loaded. + promiseWaitOnFaviconLoaded = waitOnFaviconLoaded(aFaviconURL); + tabInfo = await openTabInUserContext(aTestPage, USER_CONTEXT_ID_WORK); + await promiseWaitOnFaviconLoaded; + + // Clear the image cache again. + clearAllImageCaches(); + + // Make the popup of allTabs showing up again. + allTabsPopupShownPromise = BrowserTestUtils.waitForEvent( + allTabsView, + "ViewShown" + ); + gTabsPanel.showAllTabsPanel(); + await allTabsPopupShownPromise; + + assertIconIsData( + gTabsPanel.allTabsViewTabs.lastElementChild.firstElementChild + ); + + // Close the popup of allTabs and wait until it's done. + allTabsPopupHiddenPromise = BrowserTestUtils.waitForEvent( + allTabsView.panelMultiView, + "PanelMultiViewHidden" + ); + gTabsPanel.hideAllTabsPanel(); + await allTabsPopupHiddenPromise; + + // Close the tab. + BrowserTestUtils.removeTab(tabInfo.tab); + + // Reset the 'overflow' attribute to make the allTabs button hidden again. + tabBrowser.removeAttribute("overflow"); +} + +add_setup(async function () { + // Make sure userContext is enabled. + await SpecialPowers.pushPrefEnv({ + set: [["privacy.userContext.enabled", true]], + }); +}); + +// A clean up function to prevent affecting other tests. +registerCleanupFunction(() => { + // Clear all cookies. + Services.cookies.removeAll(); + + // Clear all image caches and network caches. + clearAllImageCaches(); + + Services.cache2.clear(); + + // Clear Places favicon caches. + clearAllPlacesFavicons(); +}); + +add_task(async function test_favicon_userContextId() { + // Clear all image caches before running the test. + clearAllImageCaches(); + + // Clear all network caches. + Services.cache2.clear(); + + // Clear Places favicon caches. + await clearAllPlacesFavicons(); + + await doTest(TEST_PAGE, TEST_SITE, FAVICON_URI); +}); + +add_task(async function test_thirdPartyFavicon_userContextId() { + // Clear all image caches before running the test. + clearAllImageCaches(); + + // Clear all network caches. + Services.cache2.clear(); + + // Clear Places favicon caches. + await clearAllPlacesFavicons(); + + await doTest( + TEST_THIRD_PARTY_PAGE, + TEST_THIRD_PARTY_SITE, + THIRD_PARTY_FAVICON_URI + ); +}); + +add_task(async function test_allTabs_favicon_userContextId() { + // Clear all image caches before running the test. + clearAllImageCaches(); + + // Clear all network caches. + Services.cache2.clear(); + + // Clear Places favicon caches. + await clearAllPlacesFavicons(); + + await doTestForAllTabsFavicon(TEST_PAGE, TEST_SITE, FAVICON_URI); +}); + +add_task(async function test_allTabs_thirdPartyFavicon_userContextId() { + // Clear all image caches before running the test. + clearAllImageCaches(); + + // Clear all network caches. + Services.cache2.clear(); + + // Clear Places favicon caches. + await clearAllPlacesFavicons(); + + await doTestForAllTabsFavicon( + TEST_THIRD_PARTY_PAGE, + TEST_THIRD_PARTY_SITE, + THIRD_PARTY_FAVICON_URI + ); +}); -- cgit v1.2.3