diff --git a/browser/components/originattributes/test/browser/browser.ini b/browser/components/originattributes/test/browser/browser.ini
index fb56e877af95..1093c841c21e 100644
--- a/browser/components/originattributes/test/browser/browser.ini
+++ b/browser/components/originattributes/test/browser/browser.ini
@@ -65,6 +65,7 @@ support-files =
[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]
diff --git a/browser/components/originattributes/test/browser/browser_firstPartyIsolation.js b/browser/components/originattributes/test/browser/browser_firstPartyIsolation.js
index 1f2e82263003..3f9fce56eca7 100644
--- a/browser/components/originattributes/test/browser/browser_firstPartyIsolation.js
+++ b/browser/components/originattributes/test/browser/browser_firstPartyIsolation.js
@@ -5,6 +5,7 @@ add_task(function* setup() {
Services.prefs.setBoolPref("privacy.firstparty.isolate", true);
registerCleanupFunction(function() {
Services.prefs.clearUserPref("privacy.firstparty.isolate");
+ Services.cookies.removeAll();
});
});
diff --git a/browser/components/originattributes/test/browser/browser_firstPartyIsolation_blobURI.js b/browser/components/originattributes/test/browser/browser_firstPartyIsolation_blobURI.js
new file mode 100644
index 000000000000..79abc9067e93
--- /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([
+ ``],
+ {"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();
+});
diff --git a/caps/OriginAttributes.cpp b/caps/OriginAttributes.cpp
index 9ee38822e33a..93137d5dabf9 100644
--- a/caps/OriginAttributes.cpp
+++ b/caps/OriginAttributes.cpp
@@ -10,6 +10,7 @@
#include "mozilla/dom/quota/QuotaManager.h"
#include "nsIEffectiveTLDService.h"
#include "nsIURI.h"
+#include "nsIURIWithPrincipal.h"
namespace mozilla {
@@ -52,16 +53,29 @@ OriginAttributes::SetFirstPartyDomain(const bool aIsTopLevelDocument,
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;
}
- mFirstPartyDomain = NS_ConvertUTF8toUTF16(baseDomain);
+ 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 uriPrinc = do_QueryInterface(aURI);
+ if (uriPrinc) {
+ nsCOMPtr 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;
+ }
+ }
+ }
}
void