Bug 1057933 - ServiceWorkerRegistrations should use scope and not window to obtain workers. r=baku
authorNikhil Marathe <nsm.nikhil@gmail.com>
Sun, 24 Aug 2014 22:35:03 -0700
changeset 227825 a5d98477ddc917c9f0a85c6eab2f9ae8bb649220
parent 227824 bd5d9e067035b947b9c86b7a3af75b6d30bf1178
child 227826 fe99aeb6ae653c3ac35a9c923e039e03e1c16014
push id611
push userraliiev@mozilla.com
push dateMon, 05 Jan 2015 23:23:16 +0000
treeherdermozilla-release@345cd3b9c445 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1057933
milestone35.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 1057933 - ServiceWorkerRegistrations should use scope and not window to obtain workers. r=baku
dom/interfaces/base/nsIServiceWorkerManager.idl
dom/workers/ServiceWorkerManager.cpp
dom/workers/ServiceWorkerManager.h
dom/workers/ServiceWorkerRegistration.cpp
dom/workers/test/serviceworkers/test_installation_simple.html
--- a/dom/interfaces/base/nsIServiceWorkerManager.idl
+++ b/dom/interfaces/base/nsIServiceWorkerManager.idl
@@ -3,17 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "domstubs.idl"
 
 interface nsIDocument;
 interface nsIURI;
 
-[uuid(91b9d3fc-1654-44da-b438-15123cdbe7aa)]
+[uuid(8d2f64db-5585-4876-a1c9-391e16549068)]
 interface nsIServiceWorkerManager : nsISupports
 {
   /**
    * Registers a ServiceWorker with script loaded from `aScriptURI` to act as
    * the ServiceWorker for aScope.  Requires a valid entry settings object on
    * the stack. This means you must call this from content code 'within'
    * a window.
    *
@@ -56,20 +56,29 @@ interface nsIServiceWorkerManager : nsIS
 
   /**
    * Documents that have called MaybeStartControlling() should call this when
    * they are destroyed. This function may be called multiple times, and is
    * idempotent.
    */
   [notxpcom,nostdcall] void MaybeStopControlling(in nsIDocument aDoc);
 
-  // Returns a ServiceWorker
-  [noscript] nsISupports GetInstalling(in nsIDOMWindow aWindow);
-  [noscript] nsISupports GetWaiting(in nsIDOMWindow aWindow);
-  [noscript] nsISupports GetActive(in nsIDOMWindow aWindow);
+  /*
+   * Returns a ServiceWorker.
+   * window is the window of the caller. scope is the registration's scope and must be
+   * a valid entry that window is allowed to load, otherwise this will return nullptr.
+   * These are only meant to be called from ServiceWorkerRegistration instances.
+   */
+  [noscript] nsISupports GetInstalling(in nsIDOMWindow aWindow, in DOMString aScope);
+  [noscript] nsISupports GetWaiting(in nsIDOMWindow aWindow, in DOMString aScope);
+  [noscript] nsISupports GetActive(in nsIDOMWindow aWindow, in DOMString aScope);
+
+  /*
+   * Returns a ServiceWorker.
+   */
   [noscript] nsISupports GetDocumentController(in nsIDOMWindow aWindow);
 
   // Testing
   DOMString getScopeForUrl(in DOMString path);
 };
 
 %{ C++
 #define SERVICEWORKERMANAGER_CONTRACTID "@mozilla.org/serviceworkers/manager;1"
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -1942,30 +1942,60 @@ ServiceWorkerManager::FireEventOnService
       }
 
       target->DispatchTrustedEvent(aName);
     }
   }
 }
 
 /*
- * This is used for installing, waiting and active, and uses the registration
- * most specifically matching the current scope.
+ * This is used for installing, waiting and active.
  */
 NS_IMETHODIMP
-ServiceWorkerManager::GetServiceWorkerForWindow(nsIDOMWindow* aWindow,
-                                                WhichServiceWorker aWhichWorker,
-                                                nsISupports** aServiceWorker)
+ServiceWorkerManager::GetServiceWorkerForScope(nsIDOMWindow* aWindow,
+                                               const nsAString& aScope,
+                                               WhichServiceWorker aWhichWorker,
+                                               nsISupports** aServiceWorker)
 {
+  AssertIsOnMainThread();
+
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
-  MOZ_ASSERT(window);
+  if (!window) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
+  MOZ_ASSERT(doc);
+
+  ///////////////////////////////////////////
+  // Security check
+  nsCString scope = NS_ConvertUTF16toUTF8(aScope);
+  nsCOMPtr<nsIURI> scopeURI;
+  // We pass nullptr as the base URI since scopes obtained from
+  // ServiceWorkerRegistrations MUST be fully qualified URIs.
+  nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), scope, nullptr, nullptr);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return NS_ERROR_DOM_SECURITY_ERR;
+  }
+
+  nsCOMPtr<nsIPrincipal> documentPrincipal = doc->NodePrincipal();
+  rv = documentPrincipal->CheckMayLoad(scopeURI, true /* report */,
+                                       false /* allowIfInheritsPrinciple */);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return NS_ERROR_DOM_SECURITY_ERR;
+  }
+  ////////////////////////////////////////////
+
+  nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(scope);
+  if (!domainInfo) {
+    return NS_ERROR_FAILURE;
+  }
 
   nsRefPtr<ServiceWorkerRegistrationInfo> registration =
-    GetServiceWorkerRegistrationInfo(window);
-
+    domainInfo->GetRegistration(scope);
   if (!registration) {
     return NS_ERROR_FAILURE;
   }
 
   nsRefPtr<ServiceWorkerInfo> info;
   if (aWhichWorker == WhichServiceWorker::INSTALLING_WORKER) {
     info = registration->mInstallingWorker;
   } else if (aWhichWorker == WhichServiceWorker::WAITING_WORKER) {
@@ -1976,20 +2006,20 @@ ServiceWorkerManager::GetServiceWorkerFo
     MOZ_CRASH("Invalid worker type");
   }
 
   if (!info) {
     return NS_ERROR_DOM_NOT_FOUND_ERR;
   }
 
   nsRefPtr<ServiceWorker> serviceWorker;
-  nsresult rv = CreateServiceWorkerForWindow(window,
-                                             info->GetScriptSpec(),
-                                             registration->mScope,
-                                             getter_AddRefs(serviceWorker));
+  rv = CreateServiceWorkerForWindow(window,
+                                    info->GetScriptSpec(),
+                                    registration->mScope,
+                                    getter_AddRefs(serviceWorker));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   serviceWorker.forget(aServiceWorker);
   return NS_OK;
 }
 
@@ -2031,35 +2061,42 @@ ServiceWorkerManager::GetDocumentControl
   }
 
   serviceWorker.forget(aServiceWorker);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ServiceWorkerManager::GetInstalling(nsIDOMWindow* aWindow,
+                                    const nsAString& aScope,
                                     nsISupports** aServiceWorker)
 {
-  return GetServiceWorkerForWindow(aWindow, WhichServiceWorker::INSTALLING_WORKER,
-                                   aServiceWorker);
+  return GetServiceWorkerForScope(aWindow, aScope,
+                                  WhichServiceWorker::INSTALLING_WORKER,
+                                  aServiceWorker);
 }
 
 NS_IMETHODIMP
 ServiceWorkerManager::GetWaiting(nsIDOMWindow* aWindow,
+                                 const nsAString& aScope,
                                  nsISupports** aServiceWorker)
 {
-  return GetServiceWorkerForWindow(aWindow, WhichServiceWorker::WAITING_WORKER,
-                                   aServiceWorker);
+  return GetServiceWorkerForScope(aWindow, aScope,
+                                  WhichServiceWorker::WAITING_WORKER,
+                                  aServiceWorker);
 }
 
 NS_IMETHODIMP
-ServiceWorkerManager::GetActive(nsIDOMWindow* aWindow, nsISupports** aServiceWorker)
+ServiceWorkerManager::GetActive(nsIDOMWindow* aWindow,
+                                const nsAString& aScope,
+                                nsISupports** aServiceWorker)
 {
-  return GetServiceWorkerForWindow(aWindow, WhichServiceWorker::ACTIVE_WORKER,
-                                   aServiceWorker);
+  return GetServiceWorkerForScope(aWindow, aScope,
+                                  WhichServiceWorker::ACTIVE_WORKER,
+                                  aServiceWorker);
 }
 
 NS_IMETHODIMP
 ServiceWorkerManager::CreateServiceWorker(const nsACString& aScriptSpec,
                                           const nsACString& aScope,
                                           ServiceWorker** aServiceWorker)
 {
   AssertIsOnMainThread();
--- a/dom/workers/ServiceWorkerManager.h
+++ b/dom/workers/ServiceWorkerManager.h
@@ -356,19 +356,20 @@ private:
 
   already_AddRefed<ServiceWorkerDomainInfo>
   GetDomainInfo(nsIURI* aURI);
 
   already_AddRefed<ServiceWorkerDomainInfo>
   GetDomainInfo(const nsCString& aURL);
 
   NS_IMETHODIMP
-  GetServiceWorkerForWindow(nsIDOMWindow* aWindow,
-                            WhichServiceWorker aWhichWorker,
-                            nsISupports** aServiceWorker);
+  GetServiceWorkerForScope(nsIDOMWindow* aWindow,
+                           const nsAString& aScope,
+                           WhichServiceWorker aWhichWorker,
+                           nsISupports** aServiceWorker);
 
   void
   InvalidateServiceWorkerRegistrationWorker(ServiceWorkerRegistrationInfo* aRegistration,
                                             WhichServiceWorker aWhichOnes);
 
   already_AddRefed<ServiceWorkerRegistrationInfo>
   GetServiceWorkerRegistrationInfo(nsPIDOMWindow* aWindow);
 
--- a/dom/workers/ServiceWorkerRegistration.cpp
+++ b/dom/workers/ServiceWorkerRegistration.cpp
@@ -118,33 +118,38 @@ ServiceWorkerRegistration::Unregister(Er
   nsRefPtr<Promise> ret = static_cast<Promise*>(promise.get());
   MOZ_ASSERT(ret);
   return ret.forget();
 }
 
 already_AddRefed<workers::ServiceWorker>
 ServiceWorkerRegistration::GetWorkerReference(WhichServiceWorker aWhichOne)
 {
+  nsCOMPtr<nsPIDOMWindow> window = GetOwner();
+  if (!window) {
+    return nullptr;
+  }
+
   nsresult rv;
   nsCOMPtr<nsIServiceWorkerManager> swm =
     do_GetService(SERVICEWORKERMANAGER_CONTRACTID, &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return nullptr;
   }
 
   nsCOMPtr<nsISupports> serviceWorker;
   switch(aWhichOne) {
     case WhichServiceWorker::INSTALLING_WORKER:
-      rv = swm->GetInstalling(GetOwner(), getter_AddRefs(serviceWorker));
+      rv = swm->GetInstalling(window, mScope, getter_AddRefs(serviceWorker));
       break;
     case WhichServiceWorker::WAITING_WORKER:
-      rv = swm->GetWaiting(GetOwner(), getter_AddRefs(serviceWorker));
+      rv = swm->GetWaiting(window, mScope, getter_AddRefs(serviceWorker));
       break;
     case WhichServiceWorker::ACTIVE_WORKER:
-      rv = swm->GetActive(GetOwner(), getter_AddRefs(serviceWorker));
+      rv = swm->GetActive(window, mScope, getter_AddRefs(serviceWorker));
       break;
     default:
       MOZ_CRASH("Invalid enum value");
   }
 
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return nullptr;
   }
--- a/dom/workers/test/serviceworkers/test_installation_simple.html
+++ b/dom/workers/test/serviceworkers/test_installation_simple.html
@@ -57,17 +57,23 @@
 
   function realWorker() {
     var p = navigator.serviceWorker.register("worker.js", { scope: "realworker" });
     return p.then(function(wr) {
       ok(wr instanceof ServiceWorkerRegistration, "Register a ServiceWorker");
 
       info(wr.scope);
       ok(wr.scope == (new URL("realworker", document.baseURI)).href, "Scope should match");
-
+      // active, waiting, installing should return valid worker instances
+      // because the registration is for the realworker scope, so the workers
+      // should be obtained for that scope and not for
+      // test_installation_simple.html
+      var worker = wr.installing || wr.waiting || wr.active;
+      ok(worker && worker.scope.match(/realworker$/) &&
+         worker.url.match(/worker.js$/), "Valid worker instance should be available.");
     }, function(e) {
       info("Error: " + e.name);
       ok(false, "realWorker Registration should have succeeded!");
     });
   }
 
   function abortPrevious() {
     var p = navigator.serviceWorker.register("worker2.js", { scope: "foo/" });