Bug 752529 - workers shouldn't use string origins as null principals don't have them. Part 2 - nsPrincipal GetBaseDomain (r=bz)
authorIan Melven <imelven@mozilla.com>
Tue, 08 Jan 2013 13:53:32 -0800
changeset 118147 752a9a829df27ecad36c6588e058e25e70b77741
parent 118146 3225d581951ed0ca9fdb22da9f6f15488ee4d727
child 118148 e11cd5e7b8724c3362f5596fb1f0dbf119dbb8e2
push id20872
push userimelven@mozilla.com
push dateTue, 08 Jan 2013 21:56:42 +0000
treeherdermozilla-inbound@752a9a829df2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs752529
milestone21.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 752529 - workers shouldn't use string origins as null principals don't have them. Part 2 - nsPrincipal GetBaseDomain (r=bz)
caps/include/nsPrincipal.h
caps/src/nsNullPrincipal.cpp
caps/src/nsPrincipal.cpp
caps/src/nsSystemPrincipal.cpp
dom/workers/WorkerPrivate.cpp
--- a/caps/include/nsPrincipal.h
+++ b/caps/include/nsPrincipal.h
@@ -67,16 +67,17 @@ public:
   NS_IMETHOD SubsumesIgnoringDomain(nsIPrincipal* other, bool* _retval);
   NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report, bool allowIfInheritsPrincipal);
   NS_IMETHOD GetExtendedOrigin(nsACString& aExtendedOrigin);
   NS_IMETHOD GetAppStatus(uint16_t* aAppStatus);
   NS_IMETHOD GetAppId(uint32_t* aAppStatus);
   NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement);
   NS_IMETHOD GetUnknownAppId(bool* aUnknownAppId);
   NS_IMETHOD GetIsNullPrincipal(bool* aIsNullPrincipal);
+  NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain);
 #ifdef DEBUG
   virtual void dumpImpl();
 #endif
 
   nsPrincipal();
 
   // Init() must be called before the principal is in a usable state.
   nsresult Init(nsIURI* aCodebase,
@@ -149,16 +150,17 @@ public:
   NS_IMETHOD SubsumesIgnoringDomain(nsIPrincipal* other, bool* _retval);
   NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report, bool allowIfInheritsPrincipal);
   NS_IMETHOD GetExtendedOrigin(nsACString& aExtendedOrigin);
   NS_IMETHOD GetAppStatus(uint16_t* aAppStatus);
   NS_IMETHOD GetAppId(uint32_t* aAppStatus);
   NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement);
   NS_IMETHOD GetUnknownAppId(bool* aUnknownAppId);
   NS_IMETHOD GetIsNullPrincipal(bool* aIsNullPrincipal);
+  NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain);
 #ifdef DEBUG
   virtual void dumpImpl();
 #endif
   
   virtual void GetScriptLocation(nsACString &aStr) MOZ_OVERRIDE;
 
 private:
   nsTArray< nsCOMPtr<nsIPrincipal> > mPrincipals;
--- a/caps/src/nsNullPrincipal.cpp
+++ b/caps/src/nsNullPrincipal.cpp
@@ -293,16 +293,23 @@ nsNullPrincipal::GetUnknownAppId(bool* a
 
 NS_IMETHODIMP
 nsNullPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal)
 {
   *aIsNullPrincipal = true;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsNullPrincipal::GetBaseDomain(nsACString& aBaseDomain)
+{
+  // For a null principal, we use our unique uuid as the base domain.
+  return mURI->GetPath(aBaseDomain);
+}
+
 /**
  * nsISerializable implementation
  */
 NS_IMETHODIMP
 nsNullPrincipal::Read(nsIObjectInputStream* aStream)
 {
   // no-op: CID is sufficient to create a useful nsNullPrincipal, since the URI
   // is not really relevant.
--- a/caps/src/nsPrincipal.cpp
+++ b/caps/src/nsPrincipal.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 sw=2 et tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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 "mozIThirdPartyUtil.h"
 #include "nscore.h"
 #include "nsScriptSecurityManager.h"
 #include "nsString.h"
 #include "nsReadableUtils.h"
 #include "plstr.h"
 #include "nsCRT.h"
 #include "nsIURI.h"
 #include "nsIFileURL.h"
@@ -436,17 +437,17 @@ nsPrincipal::CheckMayLoad(nsIURI* aURI, 
         return NS_OK;
       }
     }
 
     if (aReport) {
       nsScriptSecurityManager::ReportError(
         nullptr, NS_LITERAL_STRING("CheckSameOriginError"), mCodebase, aURI);
     }
-    
+
     return NS_ERROR_DOM_BAD_URI;
   }
 
   return NS_OK;
 }
 
 void
 nsPrincipal::SetURI(nsIURI* aURI)
@@ -480,17 +481,17 @@ nsPrincipal::GetDomain(nsIURI** aDomain)
   return NS_EnsureSafeToReturn(mDomain, aDomain);
 }
 
 NS_IMETHODIMP
 nsPrincipal::SetDomain(nsIURI* aDomain)
 {
   mDomain = NS_TryToMakeImmutable(aDomain);
   mDomainImmutable = URIIsImmutable(mDomain);
-  
+
   // Domain has changed, forget cached security policy
   SetSecurityPolicy(nullptr);
 
   // Recompute all wrappers between compartments using this principal and other
   // non-chrome compartments.
   JSContext *cx = nsContentUtils::GetSafeJSContext();
   NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
   JSPrincipals *principals = nsJSPrincipals::get(static_cast<nsIPrincipal*>(this));
@@ -552,16 +553,39 @@ nsPrincipal::GetUnknownAppId(bool* aUnkn
 NS_IMETHODIMP
 nsPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal)
 {
   *aIsNullPrincipal = false;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsPrincipal::GetBaseDomain(nsACString& aBaseDomain)
+{
+  // For a file URI, we return the file path.
+  if (URIIsLocalFile(mCodebase)) {
+    nsCOMPtr<nsIURL> url = do_QueryInterface(mCodebase);
+
+    if (url) {
+      return url->GetFilePath(aBaseDomain);
+    }
+  }
+
+  // For everything else, we ask the TLD service via
+  // the ThirdPartyUtil.
+  nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
+    do_GetService(THIRDPARTYUTIL_CONTRACTID);
+  if (thirdPartyUtil) {
+    return thirdPartyUtil->GetBaseDomain(mCodebase, aBaseDomain);
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsPrincipal::Read(nsIObjectInputStream* aStream)
 {
   nsCOMPtr<nsIURI> codebase;
   nsresult rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(codebase));
   if (NS_FAILED(rv)) {
     return rv;
   }
 
@@ -683,45 +707,45 @@ NS_IMPL_RELEASE_INHERITED(nsExpandedPrin
 nsExpandedPrincipal::nsExpandedPrincipal(nsTArray<nsCOMPtr <nsIPrincipal> > &aWhiteList)
 {
   mPrincipals.AppendElements(aWhiteList);
 }
 
 nsExpandedPrincipal::~nsExpandedPrincipal()
 { }
 
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsExpandedPrincipal::GetDomain(nsIURI** aDomain)
 {
   *aDomain = nullptr;
   return NS_OK;
 }
 
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsExpandedPrincipal::SetDomain(nsIURI* aDomain)
 {
   return NS_OK;
 }
 
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsExpandedPrincipal::GetOrigin(char** aOrigin)
 {
   *aOrigin = ToNewCString(NS_LITERAL_CSTRING(EXPANDED_PRINCIPAL_SPEC));
   return *aOrigin ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
 
 typedef nsresult (NS_STDCALL nsIPrincipal::*nsIPrincipalMemFn)(nsIPrincipal* aOther,
                                                                bool* aResult);
 #define CALL_MEMBER_FUNCTION(THIS,MEM_FN)  ((THIS)->*(MEM_FN))
 
 // nsExpandedPrincipal::Equals and nsExpandedPrincipal::EqualsIgnoringDomain
-// shares the same logic. The difference only that Equals requires 'this' 
-// and 'aOther' to Subsume each other while EqualsIgnoringDomain requires 
+// shares the same logic. The difference only that Equals requires 'this'
+// and 'aOther' to Subsume each other while EqualsIgnoringDomain requires
 // bidirectional SubsumesIgnoringDomain.
-static nsresult 
+static nsresult
 Equals(nsExpandedPrincipal* aThis, nsIPrincipalMemFn aFn, nsIPrincipal* aOther,
        bool* aResult)
 {
   // If (and only if) 'aThis' and 'aOther' both Subsume/SubsumesIgnoringDomain
   // each other, then they are Equal.
   *aResult = false;
   // Calling the corresponding subsume function on this (aFn).
   nsresult rv = CALL_MEMBER_FUNCTION(aThis, aFn)(aOther, aResult);
@@ -745,33 +769,33 @@ NS_IMETHODIMP
 nsExpandedPrincipal::EqualsIgnoringDomain(nsIPrincipal* aOther, bool* aResult)
 {
   return ::Equals(this, &nsIPrincipal::SubsumesIgnoringDomain, aOther, aResult);
 }
 
 // nsExpandedPrincipal::Subsumes and nsExpandedPrincipal::SubsumesIgnoringDomain
 // shares the same logic. The difference only that Subsumes calls are replaced
 //with SubsumesIgnoringDomain calls in the second case.
-static nsresult 
-Subsumes(nsExpandedPrincipal* aThis, nsIPrincipalMemFn aFn, nsIPrincipal* aOther, 
+static nsresult
+Subsumes(nsExpandedPrincipal* aThis, nsIPrincipalMemFn aFn, nsIPrincipal* aOther,
          bool* aResult)
 {
   nsresult rv;
-  nsCOMPtr<nsIExpandedPrincipal> expanded = do_QueryInterface(aOther);  
+  nsCOMPtr<nsIExpandedPrincipal> expanded = do_QueryInterface(aOther);
   if (expanded) {
-    // If aOther is an ExpandedPrincipal too, check if all of its 
+    // If aOther is an ExpandedPrincipal too, check if all of its
     // principals are subsumed.
     nsTArray< nsCOMPtr<nsIPrincipal> >* otherList;
     expanded->GetWhiteList(&otherList);
     for (uint32_t i = 0; i < otherList->Length(); ++i){
       rv = CALL_MEMBER_FUNCTION(aThis, aFn)((*otherList)[i], aResult);
       NS_ENSURE_SUCCESS(rv, rv);
       if (!*aResult) {
         // If we don't subsume at least one principal of aOther, return false.
-        return NS_OK;    
+        return NS_OK;
       }
     }
   } else {
     // For a regular aOther, one of our principals must subsume it.
     nsTArray< nsCOMPtr<nsIPrincipal> >* list;
     aThis->GetWhiteList(&list);
     for (uint32_t i = 0; i < list->Length(); ++i){
       rv = CALL_MEMBER_FUNCTION((*list)[i], aFn)(aOther, aResult);
@@ -821,17 +845,17 @@ nsExpandedPrincipal::GetHashValue(uint32
 
 NS_IMETHODIMP
 nsExpandedPrincipal::GetURI(nsIURI** aURI)
 {
   *aURI = nullptr;
   return NS_OK;
 }
 
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsExpandedPrincipal::GetWhiteList(nsTArray<nsCOMPtr<nsIPrincipal> >** aWhiteList)
 {
   *aWhiteList = &mPrincipals;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsExpandedPrincipal::GetExtendedOrigin(nsACString& aExtendedOrigin)
@@ -869,16 +893,22 @@ nsExpandedPrincipal::GetUnknownAppId(boo
 
 NS_IMETHODIMP
 nsExpandedPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal)
 {
   *aIsNullPrincipal = false;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsExpandedPrincipal::GetBaseDomain(nsACString& aBaseDomain)
+{
+  return NS_ERROR_NOT_AVAILABLE;
+}
+
 void
 nsExpandedPrincipal::GetScriptLocation(nsACString& aStr)
 {
   // Is that a good idea to list it's principals?
   aStr.Assign(EXPANDED_PRINCIPAL_SPEC);
 }
 
 #ifdef DEBUG
--- a/caps/src/nsSystemPrincipal.cpp
+++ b/caps/src/nsSystemPrincipal.cpp
@@ -200,16 +200,23 @@ nsSystemPrincipal::GetUnknownAppId(bool*
 
 NS_IMETHODIMP
 nsSystemPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal)
 {
   *aIsNullPrincipal = false;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsSystemPrincipal::GetBaseDomain(nsACString& aBaseDomain)
+{
+  // No base domain for chrome.
+  return NS_OK;
+}
+
 //////////////////////////////////////////
 // Methods implementing nsISerializable //
 //////////////////////////////////////////
 
 NS_IMETHODIMP
 nsSystemPrincipal::Read(nsIObjectInputStream* aStream)
 {
     // no-op: CID is sufficient to identify the mSystemPrincipal singleton
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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 "WorkerPrivate.h"
 
-#include "mozIThirdPartyUtil.h"
 #include "nsIClassInfo.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIConsoleService.h"
 #include "nsIDOMFile.h"
 #include "nsIDocument.h"
 #include "nsIDocShell.h"
 #include "nsIJSContextStack.h"
 #include "nsIMemoryReporter.h"
@@ -2471,51 +2470,46 @@ WorkerPrivate::Create(JSContext* aCx, JS
       // Use the document's NodePrincipal as our principal if we're not being
       // called from chrome.
       if (!principal) {
         if (!(principal = document->NodePrincipal())) {
           JS_ReportError(aCx, "Could not get document principal!");
           return nullptr;
         }
 
-        nsCOMPtr<nsIURI> codebase;
-        if (NS_FAILED(principal->GetURI(getter_AddRefs(codebase)))) {
-          JS_ReportError(aCx, "Could not determine codebase!");
-          return nullptr;
-        }
-
-        NS_NAMED_LITERAL_CSTRING(file, "file");
-
-        bool isFile;
-        if (NS_FAILED(codebase->SchemeIs(file.get(), &isFile))) {
-          JS_ReportError(aCx, "Could not determine if codebase is file!");
-          return nullptr;
-        }
-
-        if (isFile) {
-          // XXX Fix this, need a real domain here.
-          domain = file;
-        }
-        // Workaround for workers needing a string domain - will be fixed
-        // in a followup after this lands.
-        else if (document->GetSandboxFlags() & SANDBOXED_ORIGIN) {
-          if (NS_FAILED(codebase->GetAsciiSpec(domain))) {
-            JS_ReportError(aCx, "Could not get URI's spec for sandboxed document!");
-            return nullptr;
+        // We use the document's base domain to limit the number of workers
+        // each domain can create. For sandboxed documents, we use the domain
+        // of their first non-sandboxed document, walking up until we find
+        // one. If we can't find one, we fall back to using the GUID of the
+        // null principal as the base domain.
+        if (document->GetSandboxFlags() & SANDBOXED_ORIGIN) {
+          nsCOMPtr<nsIDocument> tmpDoc = document;
+          do {
+            tmpDoc = tmpDoc->GetParentDocument();
+          } while (tmpDoc && tmpDoc->GetSandboxFlags() & SANDBOXED_ORIGIN);
+
+          if (tmpDoc) {
+            // There was an unsandboxed ancestor, yay!
+            nsCOMPtr<nsIPrincipal> tmpPrincipal = tmpDoc->NodePrincipal();
+
+            if (NS_FAILED(tmpPrincipal->GetBaseDomain(domain))) {
+              JS_ReportError(aCx, "Could not determine base domain!");
+              return nullptr;
+            }
+          } else {
+            // No unsandboxed ancestor, use our GUID.
+            if (NS_FAILED(principal->GetBaseDomain(domain))) {
+              JS_ReportError(aCx, "Could not determine base domain!");
+             return nullptr;
+            }
           }
         } else {
-          nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
-            do_GetService(THIRDPARTYUTIL_CONTRACTID);
-          if (!thirdPartyUtil) {
-            JS_ReportError(aCx, "Could not get third party helper service!");
-            return nullptr;
-          }
-
-          if (NS_FAILED(thirdPartyUtil->GetBaseDomain(codebase, domain))) {
-            JS_ReportError(aCx, "Could not get domain!");
+          // Document creating the worker is not sandboxed.
+          if (NS_FAILED(principal->GetBaseDomain(domain))) {
+            JS_ReportError(aCx, "Could not determine base domain!");
             return nullptr;
           }
         }
       }
 
       xhrParamsAllowed = CheckXHRParamsAllowed(window);
     }
     else {