Bug 1344170: set firstPartyDomai on blob: URI. r=smaug
authorYoshi Huang <allstars.chh@mozilla.com>
Wed, 12 Apr 2017 14:47:48 +0800
changeset 567072 89407b3607a2feedd46b2d13717724bc5f41b33b
parent 567071 9f2fe5e3f78c8174fab116ebc9091d0e357fb121
child 567073 288f9c879d41b61c90f16af0e002d6331df921bd
push id55429
push userbmo:hskupin@gmail.com
push dateMon, 24 Apr 2017 10:48:57 +0000
reviewerssmaug
bugs1344170
milestone55.0a1
Bug 1344170: set firstPartyDomai on blob: URI. r=smaug A web page could generate an URL by URl.createObjectURL(new Blob(...)); then navigate to this generated URL. In this case the (top-level) document URI will be blob:{origin}:{uuid}. And we try to add firstPartyDomain on this top-level document with blob URI, so the following request from this document could have correct origin attributes.
browser/components/originattributes/test/browser/browser.ini
browser/components/originattributes/test/browser/browser_firstPartyIsolation.js
browser/components/originattributes/test/browser/browser_firstPartyIsolation_blobURI.js
caps/OriginAttributes.cpp
--- a/browser/components/originattributes/test/browser/browser.ini
+++ b/browser/components/originattributes/test/browser/browser.ini
@@ -60,16 +60,17 @@ support-files =
 
 [browser_broadcastChannel.js]
 [browser_cache.js]
 [browser_cookieIsolation.js]
 [browser_favicon_firstParty.js]
 [browser_favicon_userContextId.js]
 [browser_firstPartyIsolation.js]
 [browser_firstPartyIsolation_aboutPages.js]
+[browser_firstPartyIsolation_blobURI.js]
 [browser_firstPartyIsolation_js_uri.js]
 [browser_localStorageIsolation.js]
 [browser_blobURLIsolation.js]
 [browser_imageCacheIsolation.js]
 [browser_sharedworker.js]
 [browser_httpauth.js]
 [browser_clientAuth.js]
 [browser_cacheAPI.js]
--- a/browser/components/originattributes/test/browser/browser_firstPartyIsolation.js
+++ b/browser/components/originattributes/test/browser/browser_firstPartyIsolation.js
@@ -1,15 +1,16 @@
 const BASE_URL = "http://mochi.test:8888/browser/browser/components/originattributes/test/browser/";
 const BASE_DOMAIN = "mochi.test";
 
 add_task(function* setup() {
   Services.prefs.setBoolPref("privacy.firstparty.isolate", true);
   registerCleanupFunction(function() {
     Services.prefs.clearUserPref("privacy.firstparty.isolate");
+    Services.cookies.removeAll();
   });
 });
 
 /**
  * Test for the top-level document and child iframes should have the
  * firstPartyDomain attribute.
  */
 add_task(function* principal_test() {
new file mode 100644
--- /dev/null
+++ b/browser/components/originattributes/test/browser/browser_firstPartyIsolation_blobURI.js
@@ -0,0 +1,76 @@
+add_task(function* setup() {
+  Services.prefs.setBoolPref("privacy.firstparty.isolate", true);
+
+  registerCleanupFunction(function() {
+    Services.prefs.clearUserPref("privacy.firstparty.isolate");
+    Services.cookies.removeAll();
+  });
+});
+
+/**
+ * First we generate a Blob URI by using URL.createObjectURL(new Blob(..));
+ * then we navigate to this Blob URI, hence to make the top-level document URI
+ * is Blob URI.
+ * Later we create an iframe on this Blob: document, and we test that the iframe
+ * has correct firstPartyDomain.
+ */
+add_task(function* test_blob_uri_inherit_oa_from_content() {
+  const BASE_URI = "http://mochi.test:8888/browser/browser/components/" +
+                   "originattributes/test/browser/dummy.html";
+  const BASE_DOMAIN = "mochi.test";
+
+  // First we load a normal web page.
+  let win = yield BrowserTestUtils.openNewBrowserWindow({ remote: true });
+  let browser = win.gBrowser.selectedBrowser;
+  browser.loadURI(BASE_URI);
+  yield BrowserTestUtils.browserLoaded(browser);
+
+  // Then navigate to the blob: URI.
+  yield ContentTask.spawn(browser, { firstPartyDomain: BASE_DOMAIN }, function* (attrs) {
+    info("origin " + content.document.nodePrincipal.origin);
+    Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
+                 attrs.firstPartyDomain, "The document should have firstPartyDomain");
+
+    // Now we use createObjectURL to generate a blob URI and navigate to it.
+    let url = content.window.URL.createObjectURL(new content.window.Blob([
+      `<script src="http://mochi.test:8888/browser/browser/components/originattributes/test/browser/test.js"></script>`],
+      {"type": "text/html"}));
+    content.document.location = url;
+  });
+
+  // Wait for the Blob: URI to be loaded.
+  yield BrowserTestUtils.browserLoaded(browser, false, function(url) {
+    info("BrowserTestUtils.browserLoaded url=" + url);
+    return url.startsWith("blob:http://mochi.test:8888/");
+  });
+
+  // We verify the blob document has correct origin attributes.
+  // Then we inject an iframe to it.
+  yield ContentTask.spawn(browser, { firstPartyDomain: BASE_DOMAIN }, function* (attrs) {
+    Assert.ok(content.document.documentURI.startsWith("blob:http://mochi.test:8888/"),
+              "the document URI should be a blob URI.");
+    info("origin " + content.document.nodePrincipal.origin);
+    Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
+                 attrs.firstPartyDomain, "The document should have firstPartyDomain");
+
+    let iframe = content.document.createElement("iframe");
+    iframe.src = "http://example.com";
+    iframe.id = "iframe1";
+    content.document.body.appendChild(iframe);
+  });
+
+  // Wait for the iframe to be loaded.
+//  yield BrowserTestUtils.browserLoaded(browser, true, function(url) {
+//    info("BrowserTestUtils.browserLoaded iframe url=" + url);
+//    return url == "http://example.com/";
+//  });
+
+  // Finally we verify the iframe has correct origin attributes.
+  yield ContentTask.spawn(browser, { firstPartyDomain: BASE_DOMAIN }, function* (attrs) {
+    let iframe = content.document.getElementById("iframe1");
+    Assert.equal(iframe.contentDocument.nodePrincipal.originAttributes.firstPartyDomain,
+                 attrs.firstPartyDomain, "iframe should inherit firstPartyDomain from blob: URI");
+  });
+
+  win.close();
+});
--- a/caps/OriginAttributes.cpp
+++ b/caps/OriginAttributes.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/OriginAttributes.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/URLSearchParams.h"
 #include "mozilla/dom/quota/QuotaManager.h"
 #include "nsIEffectiveTLDService.h"
 #include "nsIURI.h"
+#include "nsIURIWithPrincipal.h"
 
 namespace mozilla {
 
 using dom::URLParams;
 
 bool OriginAttributes::sFirstPartyIsolation = false;
 bool OriginAttributes::sRestrictedOpenerAccess = false;
 
@@ -47,26 +48,39 @@ OriginAttributes::SetFirstPartyDomain(co
     do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
   MOZ_ASSERT(tldService);
   if (!tldService) {
     return;
   }
 
   nsAutoCString baseDomain;
   nsresult rv = tldService->GetBaseDomain(aURI, 0, baseDomain);
-  if (NS_FAILED(rv)) {
-    nsAutoCString scheme;
-    rv = aURI->GetScheme(scheme);
-    NS_ENSURE_SUCCESS_VOID(rv);
-    if (scheme.EqualsLiteral("about")) {
-      baseDomain.AssignLiteral(ABOUT_URI_FIRST_PARTY_DOMAIN);
+  if (NS_SUCCEEDED(rv)) {
+    mFirstPartyDomain = NS_ConvertUTF8toUTF16(baseDomain);
+    return;
+  }
+
+  nsAutoCString scheme;
+  rv = aURI->GetScheme(scheme);
+  NS_ENSURE_SUCCESS_VOID(rv);
+  if (scheme.EqualsLiteral("about")) {
+    mFirstPartyDomain.AssignLiteral(ABOUT_URI_FIRST_PARTY_DOMAIN);
+  } else if (scheme.EqualsLiteral("blob")) {
+    nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(aURI);
+    if (uriPrinc) {
+      nsCOMPtr<nsIPrincipal> principal;
+      rv = uriPrinc->GetPrincipal(getter_AddRefs(principal));
+      NS_ENSURE_SUCCESS_VOID(rv);
+
+      MOZ_ASSERT(principal, "blob URI but no principal.");
+      if (principal) {
+        mFirstPartyDomain = principal->OriginAttributesRef().mFirstPartyDomain;
+      }
     }
   }
-
-  mFirstPartyDomain = NS_ConvertUTF8toUTF16(baseDomain);
 }
 
 void
 OriginAttributes::SetFirstPartyDomain(const bool aIsTopLevelDocument,
                                       const nsACString& aDomain)
 {
   bool isFirstPartyEnabled = IsFirstPartyEnabled();