Bug 1147821 - Update IndexedDB to use common StorageAllowedForWindow logic, r=khuey
authorMichael Layzell <michael@thelayzells.com>
Wed, 15 Jul 2015 17:01:02 -0400
changeset 259794 cc93773031259aecc93d38e2e69efab68d39a644
parent 259793 d67c4fd50c16f587c7e2b27a953ff8ffbf26234f
child 259795 dfeb2c9934355465442383a740e6b9bd05fc12eb
push id64335
push usermichael@thelayzells.com
push dateFri, 28 Aug 2015 14:11:11 +0000
treeherdermozilla-inbound@48700cf2b4af [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs1147821
milestone43.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 1147821 - Update IndexedDB to use common StorageAllowedForWindow logic, r=khuey
dom/indexedDB/IDBFactory.cpp
dom/indexedDB/test/test_third_party.html
dom/workers/ServiceWorkerManager.cpp
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
dom/workers/WorkerScope.cpp
dom/workers/Workers.h
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -357,77 +357,61 @@ IDBFactory::AllowedForWindowInternal(nsP
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aWindow);
   MOZ_ASSERT(aWindow->IsInnerWindow());
 
   if (NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate())) {
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
-  nsIDocument* document = aWindow->GetExtantDoc();
-  if (document->GetSandboxFlags() & SANDBOXED_ORIGIN) {
+  nsContentUtils::StorageAccess access =
+    nsContentUtils::StorageAllowedForWindow(aWindow);
+
+  // the factory callsite records whether the browser is in private browsing.
+  // and thus we don't have to respect that setting here. IndexedDB has no
+  // concept of session-local storage, and thus ignores it.
+  if (access == nsContentUtils::StorageAccess::eDeny) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
   MOZ_ASSERT(sop);
 
   nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
   if (NS_WARN_IF(!principal)) {
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+
   }
 
-  bool isSystemPrincipal;
-  if (!AllowedForPrincipal(principal, &isSystemPrincipal)) {
-    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-  }
-
-  if (isSystemPrincipal) {
+  if (nsContentUtils::IsSystemPrincipal(principal)) {
     principal.forget(aPrincipal);
     return NS_OK;
   }
 
-  // Whitelist about:home, since it doesn't have a base domain it would not
-  // pass the ThirdPartyUtil check, though it should be able to use indexedDB.
-  bool skipThirdPartyCheck = false;
-
+  // About URIs shouldn't be able to access IndexedDB unless they have the
+  // nsIAboutModule::ENABLE_INDEXED_DB flag set on them.
   nsCOMPtr<nsIURI> uri;
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(principal->GetURI(getter_AddRefs(uri))));
+  MOZ_ASSERT(uri);
 
-  bool isAbout;
+  bool isAbout = false;
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(uri->SchemeIs("about", &isAbout)));
 
   if (isAbout) {
     nsCOMPtr<nsIAboutModule> module;
     if (NS_SUCCEEDED(NS_GetAboutModule(uri, getter_AddRefs(module)))) {
       uint32_t flags;
       if (NS_SUCCEEDED(module->GetURIFlags(uri, &flags))) {
-        skipThirdPartyCheck = flags & nsIAboutModule::ENABLE_INDEXED_DB;
+        if (!(flags & nsIAboutModule::ENABLE_INDEXED_DB)) {
+          return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
+        }
       } else {
-        NS_WARNING("GetURIFlags failed!");
+        return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
       }
     } else {
-      NS_WARNING("NS_GetAboutModule failed!");
-    }
-  }
-
-  if (!skipThirdPartyCheck) {
-    nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
-      do_GetService(THIRDPARTYUTIL_CONTRACTID);
-    MOZ_ASSERT(thirdPartyUtil);
-
-    bool isThirdParty;
-    if (NS_WARN_IF(NS_FAILED(
-          thirdPartyUtil->IsThirdPartyWindow(aWindow,
-                                             nullptr,
-                                             &isThirdParty)))) {
-      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-    }
-
-    if (isThirdParty) {
       return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
     }
   }
 
   principal.forget(aPrincipal);
   return NS_OK;
 }
 
--- a/dom/indexedDB/test/test_third_party.html
+++ b/dom/indexedDB/test/test_third_party.html
@@ -5,21 +5,41 @@
 <html>
 <head>
   <title>Indexed Database Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
+    const BEHAVIOR_ACCEPT = 0;
+    const BEHAVIOR_REJECTFOREIGN = 1;
+    const BEHAVIOR_REJECT = 2;
+    const BEHAVIOR_LIMITFOREIGN = 3;
+
     const testData = [
-      { host: "http://" + window.location.host, expectedResult: true },
-      { host: "http://example.com", expectedResult: false },
-      { host: "http://sub1.test2.example.org:8000", expectedResult: false },
-      { host: "http://" + window.location.host, expectedResult: true }
+      { host: "http://" + window.location.host, cookieBehavior: BEHAVIOR_ACCEPT, expectedResult: true },
+      { host: "http://example.com", cookieBehavior: BEHAVIOR_ACCEPT, expectedResult: true },
+      { host: "http://sub1.test2.example.org:8000", cookieBehavior: BEHAVIOR_ACCEPT, expectedResult: true },
+      { host: "http://" + window.location.host, cookieBehavior: BEHAVIOR_ACCEPT, expectedResult: true },
+
+      { host: "http://" + window.location.host, cookieBehavior: BEHAVIOR_REJECT, expectedResult: false },
+      { host: "http://example.com", cookieBehavior: BEHAVIOR_REJECT, expectedResult: false },
+      { host: "http://sub1.test2.example.org:8000", cookieBehavior: BEHAVIOR_REJECT, expectedResult: false },
+      { host: "http://" + window.location.host, cookieBehavior: BEHAVIOR_REJECT, expectedResult: false },
+
+      { host: "http://" + window.location.host, cookieBehavior: BEHAVIOR_REJECTFOREIGN, expectedResult: true },
+      { host: "http://example.com", cookieBehavior: BEHAVIOR_REJECTFOREIGN, expectedResult: false },
+      { host: "http://sub1.test2.example.org:8000", cookieBehavior: BEHAVIOR_REJECTFOREIGN, expectedResult: false },
+      { host: "http://" + window.location.host, cookieBehavior: BEHAVIOR_REJECTFOREIGN, expectedResult: true },
+
+      { host: "http://" + window.location.host, cookieBehavior: BEHAVIOR_LIMITFOREIGN, expectedResult: true },
+      { host: "http://example.com", cookieBehavior: BEHAVIOR_LIMITFOREIGN, expectedResult: false },
+      { host: "http://sub1.test2.example.org:8000", cookieBehavior: BEHAVIOR_LIMITFOREIGN, expectedResult: false },
+      { host: "http://" + window.location.host, cookieBehavior: BEHAVIOR_LIMITFOREIGN, expectedResult: true }
     ];
 
     const iframe1Path =
       window.location.pathname.replace("test_third_party.html",
                                        "third_party_iframe1.html");
     const iframe2URL =
       "http://" + window.location.host +
       window.location.pathname.replace("test_third_party.html",
@@ -36,18 +56,22 @@
 
     function setiframe() {
       let iframe = document.getElementById("iframe1");
 
       if (!testRunning) {
         testRunning = true;
         iframe.addEventListener("load", iframeLoaded, false);
       }
-
-      iframe.src = testData[testIndex].host + iframe1Path;
+      SpecialPowers.pushPrefEnv({
+        'set': [["network.cookie.cookieBehavior", testData[testIndex].cookieBehavior]]
+      }, () => {
+        iframe.src = testData[testIndex].host + iframe1Path;
+      });
+      // SpecialPowers.setIntPref("network.cookie.cookieBehavior", testData[testIndex].cookieBehavior);
     }
 
     function messageListener(event) {
       let message = eval(event.data);
 
       is(message.source, "iframe", "Good source");
       is(message.result, testData[testIndex].expectedResult, "Good result");
 
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -41,16 +41,17 @@
 #include "mozilla/dom/NotificationEvent.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/Request.h"
 #include "mozilla/dom/RootedDictionary.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/PBackgroundChild.h"
 #include "mozilla/ipc/PBackgroundSharedTypes.h"
 #include "mozilla/unused.h"
+#include "mozilla/EnumSet.h"
 
 #include "nsContentUtils.h"
 #include "nsGlobalWindow.h"
 #include "nsNetUtil.h"
 #include "nsIURL.h"
 #include "nsProxyRelease.h"
 #include "nsQueryObject.h"
 #include "nsTArray.h"
@@ -4052,16 +4053,19 @@ NS_IMETHODIMP
 ServiceWorkerManager::CreateServiceWorker(nsIPrincipal* aPrincipal,
                                           ServiceWorkerInfo* aInfo,
                                           nsIRunnable* aLoadFailedRunnable,
                                           ServiceWorker** aServiceWorker)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aPrincipal);
 
+  // Ensure that the IndexedDatabaseManager is initialized
+  NS_WARN_IF(!indexedDB::IndexedDatabaseManager::GetOrCreate());
+
   WorkerLoadInfo info;
   nsresult rv = NS_NewURI(getter_AddRefs(info.mBaseURI), aInfo->ScriptSpec(),
                           nullptr, nullptr);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   info.mResolvedScriptURI = info.mBaseURI;
@@ -4071,19 +4075,22 @@ ServiceWorkerManager::CreateServiceWorke
 
   rv = info.mBaseURI->GetHost(info.mDomain);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   info.mPrincipal = aPrincipal;
 
-  info.mIndexedDBAllowed =
-    indexedDB::IDBFactory::AllowedForPrincipal(aPrincipal);
-   info.mPrivateBrowsing = false;
+  nsContentUtils::StorageAccess access =
+    nsContentUtils::StorageAllowedForPrincipal(aPrincipal);
+  info.mStorageAllowed =
+    access > nsContentUtils::StorageAccess::ePrivateBrowsing;
+
+  info.mPrivateBrowsing = false;
 
   nsCOMPtr<nsIContentSecurityPolicy> csp;
   rv = aPrincipal->GetCsp(getter_AddRefs(csp));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   info.mCSP = csp;
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -1668,17 +1668,17 @@ WorkerLoadInfo::WorkerLoadInfo()
   , mServiceWorkerID(0)
   , mFromWindow(false)
   , mEvalAllowed(false)
   , mReportCSPViolations(false)
   , mXHRParamsAllowed(false)
   , mPrincipalIsSystem(false)
   , mIsInPrivilegedApp(false)
   , mIsInCertifiedApp(false)
-  , mIndexedDBAllowed(false)
+  , mStorageAllowed(false)
   , mPrivateBrowsing(true)
   , mServiceWorkersTestingInWindow(false)
 {
   MOZ_COUNT_CTOR(WorkerLoadInfo);
 }
 
 WorkerLoadInfo::~WorkerLoadInfo()
 {
@@ -1727,17 +1727,17 @@ WorkerLoadInfo::StealFrom(WorkerLoadInfo
   mServiceWorkerID = aOther.mServiceWorkerID;
   mFromWindow = aOther.mFromWindow;
   mEvalAllowed = aOther.mEvalAllowed;
   mReportCSPViolations = aOther.mReportCSPViolations;
   mXHRParamsAllowed = aOther.mXHRParamsAllowed;
   mPrincipalIsSystem = aOther.mPrincipalIsSystem;
   mIsInPrivilegedApp = aOther.mIsInPrivilegedApp;
   mIsInCertifiedApp = aOther.mIsInCertifiedApp;
-  mIndexedDBAllowed = aOther.mIndexedDBAllowed;
+  mStorageAllowed = aOther.mStorageAllowed;
   mPrivateBrowsing = aOther.mPrivateBrowsing;
   mServiceWorkersTestingInWindow = aOther.mServiceWorkersTestingInWindow;
 }
 
 template <class Derived>
 class WorkerPrivateParent<Derived>::EventTarget final
   : public nsIEventTarget
 {
@@ -4261,23 +4261,26 @@ WorkerPrivate::GetLoadInfo(JSContext* aC
         NS_WARNING("Failed to proxy release of channel, leaking instead!");
       }
       return NS_ERROR_FAILURE;
     }
 
     loadInfo.mDomain = aParent->Domain();
     loadInfo.mFromWindow = aParent->IsFromWindow();
     loadInfo.mWindowID = aParent->WindowID();
-    loadInfo.mIndexedDBAllowed = aParent->IsIndexedDBAllowed();
+    loadInfo.mStorageAllowed = aParent->IsStorageAllowed();
     loadInfo.mPrivateBrowsing = aParent->IsInPrivateBrowsing();
     loadInfo.mServiceWorkersTestingInWindow =
       aParent->ServiceWorkersTestingInWindow();
   } else {
     AssertIsOnMainThread();
 
+    // Make sure that the IndexedDatabaseManager is set up
+    NS_WARN_IF(!indexedDB::IndexedDatabaseManager::GetOrCreate());
+
     nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
     MOZ_ASSERT(ssm);
 
     bool isChrome = nsContentUtils::IsCallerChrome();
 
     // First check to make sure the caller has permission to make a privileged
     // worker if they called the ChromeWorker/ChromeSharedWorker constructor.
     if (aIsChromeWorker && !isChrome) {
@@ -4386,17 +4389,19 @@ WorkerPrivate::GetLoadInfo(JSContext* aC
 
       uint16_t appStatus = loadInfo.mPrincipal->GetAppStatus();
       loadInfo.mIsInPrivilegedApp =
         (appStatus == nsIPrincipal::APP_STATUS_CERTIFIED ||
          appStatus == nsIPrincipal::APP_STATUS_PRIVILEGED);
       loadInfo.mIsInCertifiedApp = (appStatus == nsIPrincipal::APP_STATUS_CERTIFIED);
       loadInfo.mFromWindow = true;
       loadInfo.mWindowID = globalWindow->WindowID();
-      loadInfo.mIndexedDBAllowed = IDBFactory::AllowedForWindow(globalWindow);
+      nsContentUtils::StorageAccess access =
+        nsContentUtils::StorageAllowedForWindow(globalWindow);
+      loadInfo.mStorageAllowed = access > nsContentUtils::StorageAccess::eDeny;
       loadInfo.mPrivateBrowsing = nsContentUtils::IsInPrivateBrowsing(document);
     } else {
       // Not a window
       MOZ_ASSERT(isChrome);
 
       // We're being created outside of a window. Need to figure out the script
       // that is creating us in order for us to use relative URIs later on.
       JS::AutoFilename fileName;
@@ -4428,17 +4433,17 @@ WorkerPrivate::GetLoadInfo(JSContext* aC
         }
         if (NS_FAILED(rv)) {
           return rv;
         }
       }
       loadInfo.mXHRParamsAllowed = true;
       loadInfo.mFromWindow = false;
       loadInfo.mWindowID = UINT64_MAX;
-      loadInfo.mIndexedDBAllowed = true;
+      loadInfo.mStorageAllowed = true;
       loadInfo.mPrivateBrowsing = false;
     }
 
     MOZ_ASSERT(loadInfo.mPrincipal);
     MOZ_ASSERT(isChrome || !loadInfo.mDomain.IsEmpty());
 
     if (!nsContentUtils::GetContentSecurityPolicy(getter_AddRefs(loadInfo.mCSP))) {
       NS_WARNING("Failed to get CSP!");
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -761,19 +761,19 @@ public:
   uint64_t
   NextMessagePortSerial()
   {
     AssertIsOnMainThread();
     return mMessagePortSerial++;
   }
 
   bool
-  IsIndexedDBAllowed() const
+  IsStorageAllowed() const
   {
-    return mLoadInfo.mIndexedDBAllowed;
+    return mLoadInfo.mStorageAllowed;
   }
 
   bool
   IsInPrivateBrowsing() const
   {
     return mLoadInfo.mPrivateBrowsing;
   }
 
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -353,18 +353,19 @@ WorkerGlobalScope::Fetch(const RequestOr
 already_AddRefed<IDBFactory>
 WorkerGlobalScope::GetIndexedDB(ErrorResult& aErrorResult)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 
   nsRefPtr<IDBFactory> indexedDB = mIndexedDB;
 
   if (!indexedDB) {
-    if (!mWorkerPrivate->IsIndexedDBAllowed()) {
+    if (!mWorkerPrivate->IsStorageAllowed()) {
       NS_WARNING("IndexedDB is not allowed in this worker!");
+      aErrorResult = NS_ERROR_DOM_SECURITY_ERR;
       return nullptr;
     }
 
     JSContext* cx = mWorkerPrivate->GetJSContext();
     MOZ_ASSERT(cx);
 
     JS::Rooted<JSObject*> owningObject(cx, GetGlobalJSObject());
     MOZ_ASSERT(owningObject);
--- a/dom/workers/Workers.h
+++ b/dom/workers/Workers.h
@@ -268,17 +268,17 @@ struct WorkerLoadInfo
 
   bool mFromWindow;
   bool mEvalAllowed;
   bool mReportCSPViolations;
   bool mXHRParamsAllowed;
   bool mPrincipalIsSystem;
   bool mIsInPrivilegedApp;
   bool mIsInCertifiedApp;
-  bool mIndexedDBAllowed;
+  bool mStorageAllowed;
   bool mPrivateBrowsing;
   bool mServiceWorkersTestingInWindow;
 
   WorkerLoadInfo();
   ~WorkerLoadInfo();
 
   void StealFrom(WorkerLoadInfo& aOther);
 };