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 --- .../browser/browser_privatebrowsing_favicon.js | 322 +++++++++++++++++++++ 1 file changed, 322 insertions(+) create mode 100644 browser/components/privatebrowsing/test/browser/browser_privatebrowsing_favicon.js (limited to 'browser/components/privatebrowsing/test/browser/browser_privatebrowsing_favicon.js') diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_favicon.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_favicon.js new file mode 100644 index 0000000000..eea0ab07ca --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_favicon.js @@ -0,0 +1,322 @@ +/* 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/. */ + +// This test make sure that the favicon of the private browsing is isolated. + +const TEST_SITE = "https://example.com"; +const TEST_CACHE_SITE = "https://test1.example.com"; +const TEST_DIRECTORY = + "/browser/browser/components/privatebrowsing/test/browser/"; + +const TEST_PAGE = TEST_SITE + TEST_DIRECTORY + "file_favicon.html"; +const TEST_CACHE_PAGE = TEST_CACHE_SITE + TEST_DIRECTORY + "file_favicon.html"; +const FAVICON_URI = TEST_SITE + TEST_DIRECTORY + "file_favicon.png"; +const FAVICON_CACHE_URI = TEST_CACHE_SITE + TEST_DIRECTORY + "file_favicon.png"; + +let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal(); + +function clearAllImageCaches() { + let tools = SpecialPowers.Cc["@mozilla.org/image/tools;1"].getService( + SpecialPowers.Ci.imgITools + ); + let 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 observeFavicon(aIsPrivate, aExpectedCookie, aPageURI) { + let attr = {}; + + if (aIsPrivate) { + attr.privateBrowsingId = 1; + } + + let expectedPrincipal = Services.scriptSecurityManager.createContentPrincipal( + aPageURI, + attr + ); + + return new Promise(resolve => { + let observer = { + observe(aSubject, aTopic, aData) { + // Make sure that the topic is 'http-on-modify-request'. + if (aTopic === "http-on-modify-request") { + // We check the privateBrowsingId for the originAttributes of the loading + // channel. All requests for the favicon should contain the correct + // privateBrowsingId. 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 = reqLoadInfo.loadingPrincipal; + + // Make sure this is a favicon request. + if (httpChannel.URI.spec !== FAVICON_URI) { + return; + } + + // Check the privateBrowsingId. + if (aIsPrivate) { + is( + reqLoadInfo.originAttributes.privateBrowsingId, + 1, + "The loadInfo has correct privateBrowsingId" + ); + } else { + is( + reqLoadInfo.originAttributes.privateBrowsingId, + 0, + "The loadInfo has correct privateBrowsingId" + ); + } + + ok( + loadingPrincipal.equals(expectedPrincipal), + "The loadingPrincipal of favicon loading from Places should be the content prinicpal" + ); + + let faviconCookie = httpChannel.getRequestHeader("cookie"); + + is( + faviconCookie, + aExpectedCookie, + "The cookie of the favicon loading is correct." + ); + } else { + ok(false, "Received unexpected topic: ", aTopic); + } + + resolve(); + Services.obs.removeObserver(observer, "http-on-modify-request"); + }, + }; + + Services.obs.addObserver(observer, "http-on-modify-request"); + }); +} + +function waitOnFaviconResponse(aFaviconURL) { + return new Promise(resolve => { + let observer = { + observe(aSubject, aTopic, aData) { + if ( + aTopic === "http-on-examine-response" || + aTopic === "http-on-examine-cached-response" + ) { + let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel); + let loadInfo = httpChannel.loadInfo; + + if (httpChannel.URI.spec !== aFaviconURL) { + return; + } + + let result = { + topic: aTopic, + privateBrowsingId: loadInfo.originAttributes.privateBrowsingId, + }; + + resolve(result); + Services.obs.removeObserver(observer, "http-on-examine-response"); + Services.obs.removeObserver( + observer, + "http-on-examine-cached-response" + ); + } + }, + }; + + Services.obs.addObserver(observer, "http-on-examine-response"); + Services.obs.addObserver(observer, "http-on-examine-cached-response"); + }); +} + +function waitOnFaviconLoaded(aFaviconURL) { + return PlacesTestUtils.waitForNotification("favicon-changed", events => + events.some(e => e.faviconUrl == aFaviconURL) + ); +} + +async function assignCookies(aBrowser, aURL, aCookieValue) { + let tabInfo = await openTab(aBrowser, aURL); + + await SpecialPowers.spawn( + tabInfo.browser, + [aCookieValue], + async function (value) { + content.document.cookie = value; + } + ); + + BrowserTestUtils.removeTab(tabInfo.tab); +} + +async function openTab(aBrowser, aURL) { + let tab = BrowserTestUtils.addTab(aBrowser, aURL); + + // Select tab and make sure its browser is focused. + aBrowser.selectedTab = tab; + tab.ownerGlobal.focus(); + + let browser = aBrowser.getBrowserForTab(tab); + await BrowserTestUtils.browserLoaded(browser); + return { tab, browser }; +} + +registerCleanupFunction(async () => { + Services.cookies.removeAll(); + clearAllImageCaches(); + Services.cache2.clear(); + await PlacesUtils.history.clear(); + await PlacesUtils.bookmarks.eraseEverything(); +}); + +add_task(async function test_favicon_privateBrowsing() { + // Clear all image caches before running the test. + clearAllImageCaches(); + // Clear all favicons in Places. + await clearAllPlacesFavicons(); + + // Create a private browsing window. + let privateWindow = await BrowserTestUtils.openNewBrowserWindow({ + private: true, + }); + let pageURI = Services.io.newURI(TEST_PAGE); + + // Generate two random cookies for non-private window and private window + // respectively. + let cookies = []; + cookies.push(Math.random().toString()); + cookies.push(Math.random().toString()); + + // Open a tab in private window and add a cookie into it. + await assignCookies(privateWindow.gBrowser, TEST_SITE, cookies[0]); + + // Open a tab in non-private window and add a cookie into it. + await assignCookies(gBrowser, TEST_SITE, cookies[1]); + + // Add the observer earlier in case we don't capture events in time. + let promiseObserveFavicon = observeFavicon(true, cookies[0], pageURI); + + // The page must be bookmarked for favicon requests to go through in PB mode. + await PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + url: TEST_PAGE, + }); + + // Open a tab for the private window. + let tabInfo = await openTab(privateWindow.gBrowser, TEST_PAGE); + + info("Waiting until favicon requests are all made in private window."); + await promiseObserveFavicon; + + // 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); + + // Add the observer earlier in case we don't capture events in time. + promiseObserveFavicon = observeFavicon(false, cookies[1], pageURI); + + // Open a tab for the non-private window. + tabInfo = await openTab(gBrowser, TEST_PAGE); + + info("Waiting until favicon requests are all made in non-private window."); + await promiseObserveFavicon; + + // Close the tab. + BrowserTestUtils.removeTab(tabInfo.tab); + await BrowserTestUtils.closeWindow(privateWindow); +}); + +add_task(async function test_favicon_cache_privateBrowsing() { + // Clear all image caches and network cache before running the test. + clearAllImageCaches(); + + Services.cache2.clear(); + + // Clear all favicons in Places. + await clearAllPlacesFavicons(); + + // Add an observer for making sure the favicon has been loaded and cached. + let promiseFaviconLoaded = waitOnFaviconLoaded(FAVICON_CACHE_URI); + let promiseFaviconResponse = waitOnFaviconResponse(FAVICON_CACHE_URI); + + // Open a tab for the non-private window. + let tabInfoNonPrivate = await openTab(gBrowser, TEST_CACHE_PAGE); + + let response = await promiseFaviconResponse; + + await promiseFaviconLoaded; + + // Check that the favicon response has come from the network and it has the + // correct privateBrowsingId. + is( + response.topic, + "http-on-examine-response", + "The favicon image should be loaded through network." + ); + is( + response.privateBrowsingId, + 0, + "We should observe the network response for the non-private tab." + ); + + // Create a private browsing window. + let privateWindow = await BrowserTestUtils.openNewBrowserWindow({ + private: true, + }); + + // The page must be bookmarked for favicon requests to go through in PB mode. + await PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + url: TEST_CACHE_PAGE, + }); + + promiseFaviconResponse = waitOnFaviconResponse(FAVICON_CACHE_URI); + + // Open a tab for the private window. + let tabInfoPrivate = await openTab(privateWindow.gBrowser, TEST_CACHE_PAGE); + + // Wait for the favicon response of the private tab. + response = await promiseFaviconResponse; + + // Make sure the favicon is loaded through the network and its privateBrowsingId is correct. + is( + response.topic, + "http-on-examine-response", + "The favicon image should be loaded through the network again." + ); + is( + response.privateBrowsingId, + 1, + "We should observe the network response for the private tab." + ); + + BrowserTestUtils.removeTab(tabInfoPrivate.tab); + BrowserTestUtils.removeTab(tabInfoNonPrivate.tab); + await BrowserTestUtils.closeWindow(privateWindow); +}); -- cgit v1.2.3