summaryrefslogtreecommitdiffstats
path: root/browser/components/originattributes/test/browser/browser_favicon_userContextId.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/originattributes/test/browser/browser_favicon_userContextId.js')
-rw-r--r--browser/components/originattributes/test/browser/browser_favicon_userContextId.js406
1 files changed, 406 insertions, 0 deletions
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
+ );
+});