Bug 1277803 - Part 6 : Add a test case for favicon loading in different userContextIds. r=baku
authorTim Huang <tihuang@mozilla.com>
Thu, 13 Oct 2016 15:44:02 +0800
changeset 317848 df5881a8b808dc85c527cd288b51253bde7bbc16
parent 317847 4bb1c64b40595e9f3815b1fe52553f72e35f8181
child 317849 b6b99627c2daabb0b0941b9ba1bf575860164a7a
push id33170
push usercbook@mozilla.com
push dateFri, 14 Oct 2016 10:37:07 +0000
treeherderautoland@0d101ebfd95c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1277803
milestone52.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1277803 - Part 6 : Add a test case for favicon loading in different userContextIds. r=baku
browser/components/originattributes/test/browser/browser.ini
browser/components/originattributes/test/browser/browser_favicon_userContextId.js
browser/components/originattributes/test/browser/file_favicon.html
browser/components/originattributes/test/browser/file_favicon.png
browser/components/originattributes/test/browser/file_favicon.png^headers^
browser/components/originattributes/test/browser/file_favicon_thirdParty.html
--- a/browser/components/originattributes/test/browser/browser.ini
+++ b/browser/components/originattributes/test/browser/browser.ini
@@ -1,13 +1,17 @@
 [DEFAULT]
 skip-if = buildapp == "mulet"
 tags = usercontextid firstpartyisolation originattributes
 support-files =
   dummy.html
+  file_favicon.html
+  file_favicon.png
+  file_favicon.png^headers^
+  file_favicon_thirdParty.html
   file_firstPartyBasic.html
   file_sharedworker.html
   file_sharedworker.js
   head.js
   test.js
   test.js^headers^
   test.html
   test2.html
@@ -19,14 +23,15 @@ support-files =
   test_firstParty_http_redirect.html
   test_firstParty_http_redirect.html^headers^
   test_firstParty_iframe_http_redirect.html
   test_firstParty_postMessage.html
   window.html
   worker_blobify.js
   worker_deblobify.js
 
+[browser_favicon_userContextId.js]
 [browser_firstPartyIsolation.js]
 [browser_localStorageIsolation.js]
 [browser_blobURLIsolation.js]
 [browser_imageCacheIsolation.js]
 [browser_sharedworker.js]
 [browser_httpauth.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/originattributes/test/browser/browser_favicon_userContextId.js
@@ -0,0 +1,250 @@
+/**
+ * Bug 1277803 - A test caes for testing favicon loading across different userContextId.
+ */
+
+const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components;
+
+XPCOMUtils.defineLazyModuleGetter(this, "Promise",
+  "resource://gre/modules/Promise.jsm");
+
+const TEST_SITE = "http://mochi.test:8888";
+
+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.com/browser/browser/components/" +
+                              "originattributes/test/browser/file_favicon_thirdParty.html";
+
+const USER_CONTEXT_ID_PERSONAL = 1;
+const USER_CONTEXT_ID_WORK     = 2;
+
+let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
+let makeURI = Cu.import("resource://gre/modules/BrowserUtils.jsm", {}).BrowserUtils.makeURI;
+
+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", false);
+        }
+      }
+    };
+
+    Services.obs.addObserver(observer, "places-favicons-expired", false);
+    faviconService.expireAllFavicons();
+  });
+}
+
+function FaviconObserver(aUserContextId, aExpectedCookie, aPageURI) {
+  this.reset(aUserContextId, aExpectedCookie, aPageURI);
+}
+
+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;
+      let triggeringPrincipal;
+
+      // Make sure this is a favicon request.
+      if (httpChannel.URI.spec !== FAVICON_URI) {
+        return;
+      }
+
+      if (reqLoadInfo) {
+        loadingPrincipal = reqLoadInfo.loadingPrincipal;
+        triggeringPrincipal = reqLoadInfo.triggeringPrincipal;
+      }
+
+      // Check the userContextId.
+      is(reqLoadInfo.originAttributes.userContextId, this._curUserContextId,
+        "The loadInfo has correct userContextId");
+
+      if (loadingPrincipal.equals(systemPrincipal)) {
+        this._faviconReqXUL = true;
+        ok(triggeringPrincipal.equals(this._expectedPrincipal),
+          "The triggeringPrincipal of favicon loading from XUL should be the content principal.");
+      } else {
+        this._faviconReqPlaces = true;
+        ok(loadingPrincipal.equals(this._expectedPrincipal),
+          "The loadingPrincipal of favicon loading from Places 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);
+    }
+
+    if (this._faviconReqXUL && this._faviconReqPlaces) {
+      this._faviconLoaded.resolve();
+    }
+  },
+
+  reset(aUserContextId, aExpectedCookie, aPageURI) {
+    this._curUserContextId = aUserContextId;
+    this._expectedCookie = aExpectedCookie;
+    this._expectedPrincipal = Services.scriptSecurityManager
+                                      .createCodebasePrincipal(aPageURI, { userContextId: aUserContextId });
+    this._faviconReqXUL = false;
+    this._faviconReqPlaces = false;
+    this._faviconLoaded = new Promise.defer();
+  },
+
+  get promise() {
+    return this._faviconLoaded.promise;
+  }
+};
+
+function waitOnFaviconLoaded(aFaviconURL) {
+  return new Promise(resolve => {
+    let observer = {
+      onPageChanged(uri, attr, value, id) {
+
+        if (attr === Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON &&
+            value === aFaviconURL) {
+          resolve();
+          PlacesUtils.history.removeObserver(observer, false);
+        }
+      },
+    };
+
+    PlacesUtils.history.addObserver(observer, false);
+  });
+}
+
+function* generateCookies() {
+  // 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 = yield openTabInUserContext(TEST_SITE, USER_CONTEXT_ID_PERSONAL);
+  let tabInfoB = yield openTabInUserContext(TEST_SITE, USER_CONTEXT_ID_WORK);
+
+  yield ContentTask.spawn(tabInfoA.browser, cookies[0], function* (value) {
+    content.document.cookie = value;
+  });
+
+  yield ContentTask.spawn(tabInfoB.browser, cookies[1], function* (value) {
+    content.document.cookie = value;
+  });
+
+  yield BrowserTestUtils.removeTab(tabInfoA.tab);
+  yield BrowserTestUtils.removeTab(tabInfoB.tab);
+
+  return cookies;
+}
+
+function* doTest(aTestPage) {
+  let cookies = yield generateCookies();
+  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);
+
+  Services.obs.addObserver(observer, "http-on-modify-request", false);
+
+  // Open the tab with the personal container.
+  let tabInfo = yield openTabInUserContext(aTestPage, USER_CONTEXT_ID_PERSONAL);
+
+  // Waiting for favicon requests are all made.
+  yield observer.promise;
+  // Waiting for favicon loaded.
+  yield waitOnFaviconLoaded(FAVICON_URI);
+
+  // Close the tab.
+  yield BrowserTestUtils.removeTab(tabInfo.tab);
+
+  // Reset the observer for observing requests for the work container.
+  observer.reset(USER_CONTEXT_ID_WORK, cookies[1], pageURI);
+  tabInfo = yield openTabInUserContext(aTestPage, USER_CONTEXT_ID_WORK);
+
+  // Waiting for favicon requests are all made.
+  yield observer.promise;
+
+  Services.obs.removeObserver(observer, "http-on-modify-request", false);
+
+  yield BrowserTestUtils.removeTab(tabInfo.tab);
+}
+
+add_task(function* setup() {
+  // Make sure userContext is enabled.
+  yield SpecialPowers.pushPrefEnv({"set": [
+      ["privacy.userContext.enabled", true]
+  ]});
+});
+
+// A clean up function to prevent affecting other tests.
+registerCleanupFunction(() => {
+  // Clear all cookies.
+  let cookieMgr = Cc["@mozilla.org/cookiemanager;1"]
+                     .getService(Ci.nsICookieManager);
+  cookieMgr.removeAll();
+
+  // Clear all image caches and network caches.
+  clearAllImageCaches();
+
+  let networkCache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
+                        .getService(Ci.nsICacheStorageService);
+  networkCache.clear();
+
+  // Clear Places favicon caches.
+  clearAllPlacesFavicons();
+});
+
+add_task(function* test_favicon_userContextId() {
+  // Clear all image caches before running the test.
+  clearAllImageCaches();
+
+  // Clear all network caches.
+  let networkCache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
+                        .getService(Ci.nsICacheStorageService);
+  networkCache.clear();
+
+  // Clear Places favicon caches.
+  yield clearAllPlacesFavicons();
+
+  yield doTest(TEST_PAGE);
+});
+
+add_task(function* test_thirdPartyFavicon_userContextId() {
+  // Clear all image caches before running the test.
+  clearAllImageCaches();
+
+  // Clear all network caches.
+  let networkCache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
+                        .getService(Ci.nsICacheStorageService);
+  networkCache.clear();
+
+  // Clear Places favicon caches.
+  yield clearAllPlacesFavicons();
+
+  yield doTest(TEST_THIRD_PARTY_PAGE);
+});
new file mode 100644
--- /dev/null
+++ b/browser/components/originattributes/test/browser/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>
\ No newline at end of file
new file mode 100644
index 0000000000000000000000000000000000000000..5535363c94df7314765551f65311ec6f98729d8e
GIT binary patch
literal 344
zc$@)P0jK_nP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80003WNkl<ZSi@ud
z|NsAgh5-aj3<C^C9l%0R#sBwE#yKee29*B}N^?LcMg=I}1WL<7#aV`G2>ibbr58i#
zeNc((P#P98>`-}V2r!yL=>({_1(eS*I75IDqa1+6`Tu4pJs&FZfkdNSpkC~N^7XN%
ziNTl#4nlptmQ0_+z#gbM8_{x!@L&&t|69@WIcn7X|AQkj;gW}$#~3qYLI76MeMc4k
zL!iLKDUaQ}p<fv>vJfohhiYxer~!@C3s8YCB*r;9fSSj^Ib=e>8|uYfC?P<0IRG;c
zE&mVZy1*Xl@?ezO@c*9=cpEsFAp@-q8U3Mr{vneF1fh&<D9wk`BKrRaM~jF7M~jF-
q8*kfi5VnX$TC13Gv~M`#9RL8-wO_*zBf!o80000<MNUMnLSTX;M3C|T
new file mode 100644
--- /dev/null
+++ b/browser/components/originattributes/test/browser/file_favicon.png^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-cache
new file mode 100644
--- /dev/null
+++ b/browser/components/originattributes/test/browser/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/components/originattributes/test/browser/file_favicon.png" />
+  </head>
+  <body>
+    Third Party Favicon!!
+  </body>
+</html>
\ No newline at end of file