Bug 1137245 - ServiceWorkerManager should set WorkerPrivate::LoadInfo::mIndexedDBAllowed correctly. r=bent, bkelly
authorFernando Jimenez <ferjmoreno@gmail.com>
Thu, 11 Jun 2015 15:32:54 +0200
changeset 248320 219780d1c8fd5edeceebcd6fe1f3cfc6ff1e0d77
parent 248319 ee938679a81159110609927c32b248b7bcb8babd
child 248321 637b40497d85a9c9d935d134aab348869fdc9cc5
push id28893
push userkwierso@gmail.com
push dateFri, 12 Jun 2015 00:02:58 +0000
treeherderautoland@8cf9d3e497f9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbent, bkelly
bugs1137245
milestone41.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 1137245 - ServiceWorkerManager should set WorkerPrivate::LoadInfo::mIndexedDBAllowed correctly. r=bent, bkelly
dom/indexedDB/IDBFactory.cpp
dom/indexedDB/IDBFactory.h
dom/indexedDB/test/mochitest.ini
dom/indexedDB/test/service_worker.js
dom/indexedDB/test/service_worker_client.html
dom/indexedDB/test/test_serviceworker.html
dom/workers/ServiceWorkerManager.cpp
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -362,25 +362,24 @@ IDBFactory::AllowedForWindowInternal(nsP
   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;
   }
 
-  if (nsContentUtils::IsSystemPrincipal(principal)) {
-    principal.forget(aPrincipal);
-    return NS_OK;
+  bool isSystemPrincipal;
+  if (!AllowedForPrincipal(principal, &isSystemPrincipal)) {
+    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
-  bool isNullPrincipal;
-  if (NS_WARN_IF(NS_FAILED(principal->GetIsNullPrincipal(&isNullPrincipal))) ||
-      isNullPrincipal) {
-    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  if (isSystemPrincipal) {
+    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;
 
   nsCOMPtr<nsIURI> uri;
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(principal->GetURI(getter_AddRefs(uri))));
@@ -419,16 +418,46 @@ IDBFactory::AllowedForWindowInternal(nsP
       return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
     }
   }
 
   principal.forget(aPrincipal);
   return NS_OK;
 }
 
+// static
+bool
+IDBFactory::AllowedForPrincipal(nsIPrincipal* aPrincipal,
+                                bool* aIsSystemPrincipal)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aPrincipal);
+
+  if (NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate())) {
+    return false;
+  }
+
+  if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
+    if (aIsSystemPrincipal) {
+      *aIsSystemPrincipal = true;
+    }
+    return true;
+  } else if (aIsSystemPrincipal) {
+    *aIsSystemPrincipal = false;
+  }
+
+  bool isNullPrincipal;
+  if (NS_WARN_IF(NS_FAILED(aPrincipal->GetIsNullPrincipal(&isNullPrincipal))) ||
+      isNullPrincipal) {
+    return false;
+  }
+
+  return true;
+}
+
 #ifdef DEBUG
 
 void
 IDBFactory::AssertIsOnOwningThread() const
 {
   MOZ_ASSERT(mOwningThread);
   MOZ_ASSERT(PR_GetCurrentThread() == mOwningThread);
 }
--- a/dom/indexedDB/IDBFactory.h
+++ b/dom/indexedDB/IDBFactory.h
@@ -100,16 +100,20 @@ public:
                   JS::Handle<JSObject*> aOwningObject,
                   const PrincipalInfo& aPrincipalInfo,
                   uint64_t aInnerWindowID,
                   IDBFactory** aFactory);
 
   static bool
   AllowedForWindow(nsPIDOMWindow* aWindow);
 
+  static bool
+  AllowedForPrincipal(nsIPrincipal* aPrincipal,
+                      bool* aIsSystemPrincipal = nullptr);
+
   void
   AssertIsOnOwningThread() const
 #ifdef DEBUG
   ;
 #else
   { }
 #endif
 
--- a/dom/indexedDB/test/mochitest.ini
+++ b/dom/indexedDB/test/mochitest.ini
@@ -7,16 +7,18 @@ support-files =
   error_events_abort_transactions_iframe.html
   event_propagation_iframe.html
   exceptions_in_events_iframe.html
   file.js
   file_app_isolation.html
   file_app_isolation.js
   helpers.js
   leaving_page_iframe.html
+  service_worker.js
+  service_worker_client.html
   third_party_iframe1.html
   third_party_iframe2.html
   unit/test_add_put.js
   unit/test_add_twice_failure.js
   unit/test_advance.js
   unit/test_autoIncrement.js
   unit/test_autoIncrement_indexes.js
   unit/test_blob_file_backed.js
@@ -372,8 +374,10 @@ skip-if = buildapp == 'b2g' || buildapp 
 [test_webapp_clearBrowserData_inproc_oop.html]
 # The clearBrowserData tests are only supposed to run in the main process.
 # They currently time out on android.
 skip-if = buildapp == 'b2g' || buildapp == 'mulet' || e10s || toolkit == 'android'
 [test_webapp_clearBrowserData_oop_inproc.html]
 # The clearBrowserData tests are only supposed to run in the main process.
 # They currently time out on android.
 skip-if = buildapp == 'b2g' || buildapp == 'mulet' || e10s || toolkit == 'android'
+[test_serviceworker.html]
+skip-if = buildapp == 'b2g'
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/service_worker.js
@@ -0,0 +1,10 @@
+onmessage = function(e) {
+  self.clients.matchAll().then(function(res) {
+    if (!res.length) {
+      dump("Error: no clients are currently controlled.\n");
+      return;
+    }
+    res[0].postMessage(indexedDB ? { available: true } :
+                                   { available: false });
+  });
+};
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/service_worker_client.html
@@ -0,0 +1,28 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>controlled page</title>
+<script class="testbody" type="text/javascript">
+  if (!parent) {
+      info("service_worker_client.html should not be launched directly!");
+  }
+
+  window.onload = function() {
+    navigator.serviceWorker.onmessage = function(msg) {
+      // Forward messages coming from the service worker to the test page.
+      parent.postMessage(msg.data, "*");
+    };
+    navigator.serviceWorker.ready.then(function(swr) {
+      parent.postMessage("READY", "*");
+    });
+  }
+</script>
+
+</head>
+<body>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/test_serviceworker.html
@@ -0,0 +1,71 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Bug 1137245 - Allow IndexedDB usage in ServiceWorkers</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+<script class="testbody" type="text/javascript">
+
+  function simpleRegister() {
+    return navigator.serviceWorker.register("service_worker.js", {
+      scope: 'service_worker_client.html'
+    });
+  }
+
+  function testIndexedDBAvailable(sw) {
+    var p = new Promise(function(resolve, reject) {
+      window.onmessage = function(e) {
+        if (e.data === "READY") {
+          sw.active.postMessage("GO");
+          return;
+        }
+
+        if (!("available" in e.data)) {
+          ok(false, "Something went wrong");
+          reject();
+          return;
+        }
+
+        ok(e.data.available, "IndexedDB available in service worker.");
+        resolve();
+      }
+    });
+
+    var content = document.getElementById("content");
+    ok(content, "Parent exists.");
+
+    iframe = document.createElement("iframe");
+    iframe.setAttribute('src', "service_worker_client.html");
+    content.appendChild(iframe);
+
+    return p.then(() => content.removeChild(iframe));
+  }
+
+  function runTest() {
+    simpleRegister()
+      .then(testIndexedDBAvailable)
+      .then(SimpleTest.finish)
+      .catch(function(e) {
+        ok(false, "Some test failed with error " + e);
+        SimpleTest.finish();
+      });
+  }
+
+  SimpleTest.waitForExplicitFinish();
+  SpecialPowers.pushPrefEnv({"set": [
+    ["dom.serviceWorkers.enabled", true],
+    ["dom.serviceWorkers.testing.enabled", true]
+  ]}, runTest);
+</script>
+</pre>
+</body>
+</html>
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -29,16 +29,17 @@
 #include "mozilla/ErrorNames.h"
 #include "mozilla/LoadContext.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/DOMError.h"
 #include "mozilla/dom/ErrorEvent.h"
 #include "mozilla/dom/Headers.h"
+#include "mozilla/dom/indexedDB/IDBFactory.h"
 #include "mozilla/dom/InternalHeaders.h"
 #include "mozilla/dom/Navigator.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"
@@ -3535,16 +3536,19 @@ 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);
+
   // NOTE: this defaults the SW load context to:
   //  - private browsing = false
   //  - content = true
   //  - use remote tabs = false
   // Alternatively we could persist the original load group values and use
   // them here.
   WorkerPrivate::OverrideLoadInfoLoadGroup(info);