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