Bug 1268726 - isolate shared worker by first party domain. r=baku
authorArthur Edelstein <arthuredelstein@gmail.com>
Mon, 19 Sep 2016 21:13:00 -0400
changeset 314666 39b278f56017236b2f98f3b93e93553426f05be0
parent 314665 5f261677780f86df3e090e099676069023133c38
child 314667 6fb622c938dee9dac8fceddff71908e4d75bb3df
push id30732
push usercbook@mozilla.com
push dateWed, 21 Sep 2016 10:04:03 +0000
treeherdermozilla-central@560b2c805bf7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1268726, 15564
milestone52.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 1268726 - isolate shared worker by first party domain. r=baku Tor 15564: Isolate SharedWorker by first party domain uplift/refactor by Dave Huseby <dhuseby@mozilla.com> review tweaks
dom/base/nsContentUtils.cpp
dom/base/nsContentUtils.h
dom/cache/CacheStorage.cpp
dom/workers/RuntimeService.cpp
dom/workers/ScriptLoader.cpp
dom/workers/ServiceWorkerInfo.cpp
dom/workers/ServiceWorkerInfo.h
dom/workers/ServiceWorkerPrivate.cpp
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
dom/workers/Workers.h
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -3093,16 +3093,58 @@ nsContentUtils::CanLoadImage(nsIURI* aUR
   if (aImageBlockingStatus) {
     *aImageBlockingStatus =
       NS_FAILED(rv) ? nsIContentPolicy::REJECT_REQUEST : decision;
   }
   return NS_FAILED(rv) ? false : NS_CP_ACCEPTED(decision);
 }
 
 // static
+mozilla::PrincipalOriginAttributes
+nsContentUtils::GetOriginAttributes(nsIDocument* aDocument)
+{
+  if (!aDocument) {
+    return mozilla::PrincipalOriginAttributes();
+  }
+
+  nsCOMPtr<nsILoadGroup> loadGroup = aDocument->GetDocumentLoadGroup();
+  if (loadGroup) {
+    return GetOriginAttributes(loadGroup);
+  }
+
+  mozilla::PrincipalOriginAttributes attrs;
+  mozilla::NeckoOriginAttributes nattrs;
+  nsCOMPtr<nsIChannel> channel = aDocument->GetChannel();
+  if (channel && NS_GetOriginAttributes(channel, nattrs)) {
+    attrs.InheritFromNecko(nattrs);
+  }
+  return attrs;
+}
+
+// static
+mozilla::PrincipalOriginAttributes
+nsContentUtils::GetOriginAttributes(nsILoadGroup* aLoadGroup)
+{
+  if (!aLoadGroup) {
+    return mozilla::PrincipalOriginAttributes();
+  }
+  mozilla::PrincipalOriginAttributes attrs;
+  mozilla::DocShellOriginAttributes dsattrs;
+  nsCOMPtr<nsIInterfaceRequestor> callbacks;
+  aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
+  if (callbacks) {
+    nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks);
+    if (loadContext && loadContext->GetOriginAttributes(dsattrs)) {
+      attrs.InheritFromDocShellToDoc(dsattrs, nullptr);
+    }
+  }
+  return attrs;
+}
+
+// static
 bool
 nsContentUtils::IsInPrivateBrowsing(nsIDocument* aDoc)
 {
   if (!aDoc) {
     return false;
   }
 
   nsCOMPtr<nsILoadGroup> loadGroup = aDoc->GetDocumentLoadGroup();
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -781,16 +781,28 @@ public:
    * SVG's "evt" and the rest of the world's "event", and because onerror
    * on window takes 5 args.
    */
   static void GetEventArgNames(int32_t aNameSpaceID, nsIAtom *aEventName,
                                bool aIsForWindow,
                                uint32_t *aArgCount, const char*** aArgNames);
 
   /**
+   * Returns origin attributes of the document.
+   **/
+  static mozilla::PrincipalOriginAttributes
+  GetOriginAttributes(nsIDocument* aDoc);
+
+  /**
+   * Returns origin attributes of the load group.
+   **/
+  static mozilla::PrincipalOriginAttributes
+  GetOriginAttributes(nsILoadGroup* aLoadGroup);
+
+  /**
    * Returns true if this document is in a Private Browsing window.
    */
   static bool IsInPrivateBrowsing(nsIDocument* aDoc);
 
   /**
    * Returns true if this loadGroup uses Private Browsing.
    */
   static bool IsInPrivateBrowsing(nsILoadGroup* aLoadGroup);
--- a/dom/cache/CacheStorage.cpp
+++ b/dom/cache/CacheStorage.cpp
@@ -191,17 +191,17 @@ CacheStorage::CreateOnWorker(Namespace a
   aWorkerPrivate->AssertIsOnWorkerThread();
 
   if (!aWorkerPrivate->IsStorageAllowed()) {
     NS_WARNING("CacheStorage is not allowed.");
     RefPtr<CacheStorage> ref = new CacheStorage(NS_ERROR_DOM_SECURITY_ERR);
     return ref.forget();
   }
 
-  if (aWorkerPrivate->IsInPrivateBrowsing()) {
+  if (aWorkerPrivate->GetOriginAttributes().mPrivateBrowsingId > 0) {
     NS_WARNING("CacheStorage not supported during private browsing.");
     RefPtr<CacheStorage> ref = new CacheStorage(NS_ERROR_DOM_SECURITY_ERR);
     return ref.forget();
   }
 
   RefPtr<CacheWorkerHolder> workerHolder =
     CacheWorkerHolder::Create(aWorkerPrivate);
   if (!workerHolder) {
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -240,39 +240,34 @@ GetWorkerPref(const nsACString& aPref,
     else {
       result = aDefault;
     }
   }
 
   return result;
 }
 
-// This function creates a key for a SharedWorker composed by "name|scriptSpec".
-// If the name contains a '|', this will be replaced by '||'.
+// This fn creates a key for a SharedWorker that contains the name, script
+// spec, and the serialized origin attributes:
+// "name|scriptSpec^key1=val1&key2=val2&key3=val3"
 void
-GenerateSharedWorkerKey(const nsACString& aScriptSpec, const nsACString& aName,
-                        bool aPrivateBrowsing, nsCString& aKey)
+GenerateSharedWorkerKey(const nsACString& aScriptSpec,
+                        const nsACString& aName,
+                        const PrincipalOriginAttributes& aAttrs,
+                        nsCString& aKey)
 {
+  nsAutoCString suffix;
+  aAttrs.CreateSuffix(suffix);
+
   aKey.Truncate();
-  aKey.SetCapacity(aScriptSpec.Length() + aName.Length() + 3);
-  aKey.Append(aPrivateBrowsing ? "1|" : "0|");
-
-  nsACString::const_iterator start, end;
-  aName.BeginReading(start);
-  aName.EndReading(end);
-  for (; start != end; ++start) {
-    if (*start == '|') {
-      aKey.AppendASCII("||");
-    } else {
-      aKey.Append(*start);
-    }
-  }
-
+  aKey.SetCapacity(aName.Length() + aScriptSpec.Length() + suffix.Length() + 2);
+  aKey.Append(aName);
   aKey.Append('|');
   aKey.Append(aScriptSpec);
+  aKey.Append(suffix);
 }
 
 void
 LoadContextOptions(const char* aPrefName, void* /* aClosure */)
 {
   AssertIsOnMainThread();
 
   RuntimeService* rts = RuntimeService::GetService();
@@ -1636,17 +1631,17 @@ RuntimeService::RegisterWorker(WorkerPri
     else {
       domainInfo->mActiveWorkers.AppendElement(aWorkerPrivate);
     }
 
     if (isSharedWorker) {
       const nsCString& sharedWorkerName = aWorkerPrivate->WorkerName();
       nsAutoCString key;
       GenerateSharedWorkerKey(sharedWorkerScriptSpec, sharedWorkerName,
-                              aWorkerPrivate->IsInPrivateBrowsing(), key);
+                              aWorkerPrivate->GetOriginAttributes(), key);
       MOZ_ASSERT(!domainInfo->mSharedWorkerInfos.Get(key));
 
       SharedWorkerInfo* sharedWorkerInfo =
         new SharedWorkerInfo(aWorkerPrivate, sharedWorkerScriptSpec,
                              sharedWorkerName);
       domainInfo->mSharedWorkerInfos.Put(key, sharedWorkerInfo);
     }
   }
@@ -1713,17 +1708,17 @@ RuntimeService::RemoveSharedWorker(Worke
   for (auto iter = aDomainInfo->mSharedWorkerInfos.Iter();
        !iter.Done();
        iter.Next()) {
     SharedWorkerInfo* data = iter.UserData();
     if (data->mWorkerPrivate == aWorkerPrivate) {
 #ifdef DEBUG
       nsAutoCString key;
       GenerateSharedWorkerKey(data->mScriptSpec, data->mName,
-                              aWorkerPrivate->IsInPrivateBrowsing(), key);
+                              aWorkerPrivate->GetOriginAttributes(), key);
       MOZ_ASSERT(iter.Key() == key);
 #endif
       iter.Remove();
       break;
     }
   }
 }
 
@@ -2429,19 +2424,20 @@ RuntimeService::CreateSharedWorkerFromLo
 
     WorkerDomainInfo* domainInfo;
     SharedWorkerInfo* sharedWorkerInfo;
 
     nsCString scriptSpec;
     nsresult rv = aLoadInfo->mResolvedScriptURI->GetSpec(scriptSpec);
     NS_ENSURE_SUCCESS(rv, rv);
 
+    MOZ_ASSERT(aLoadInfo->mPrincipal);
     nsAutoCString key;
     GenerateSharedWorkerKey(scriptSpec, aName,
-                            aLoadInfo->mPrivateBrowsing, key);
+        BasePrincipal::Cast(aLoadInfo->mPrincipal)->OriginAttributesRef(), key);
 
     if (mDomainMap.Get(aLoadInfo->mDomain, &domainInfo) &&
         domainInfo->mSharedWorkerInfos.Get(key, &sharedWorkerInfo)) {
       workerPrivate = sharedWorkerInfo->mWorkerPrivate;
     }
   }
 
   // Keep a reference to the window before spawning the worker. If the worker is
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -345,17 +345,17 @@ class CacheScriptLoader;
 
 class CacheCreator final : public PromiseNativeHandler
 {
 public:
   NS_DECL_ISUPPORTS
 
   explicit CacheCreator(WorkerPrivate* aWorkerPrivate)
     : mCacheName(aWorkerPrivate->ServiceWorkerCacheName())
-    , mPrivateBrowsing(aWorkerPrivate->IsInPrivateBrowsing())
+    , mOriginAttributes(aWorkerPrivate->GetOriginAttributes())
   {
     MOZ_ASSERT(aWorkerPrivate->IsServiceWorker());
     MOZ_ASSERT(aWorkerPrivate->LoadScriptAsPartOfLoadingServiceWorkerScript());
     AssertIsOnMainThread();
   }
 
   void
   AddLoader(CacheScriptLoader* aLoader)
@@ -406,17 +406,17 @@ private:
   FailLoaders(nsresult aRv);
 
   RefPtr<Cache> mCache;
   RefPtr<CacheStorage> mCacheStorage;
   nsCOMPtr<nsIGlobalObject> mSandboxGlobalObject;
   nsTArray<RefPtr<CacheScriptLoader>> mLoaders;
 
   nsString mCacheName;
-  bool mPrivateBrowsing;
+  PrincipalOriginAttributes mOriginAttributes;
 };
 
 NS_IMPL_ISUPPORTS0(CacheCreator)
 
 class CacheScriptLoader final : public PromiseNativeHandler
                                   , public nsIStreamLoaderObserver
 {
 public:
@@ -1462,28 +1462,29 @@ CacheCreator::CreateCacheStorage(nsIPrin
   mSandboxGlobalObject = xpc::NativeGlobal(sandbox);
   if (NS_WARN_IF(!mSandboxGlobalObject)) {
     return NS_ERROR_FAILURE;
   }
 
   // If we're in private browsing mode, don't even try to create the
   // CacheStorage.  Instead, just fail immediately to terminate the
   // ServiceWorker load.
-  if (NS_WARN_IF(mPrivateBrowsing)) {
+  if (NS_WARN_IF(mOriginAttributes.mPrivateBrowsingId > 0)) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   // Create a CacheStorage bypassing its trusted origin checks.  The
   // ServiceWorker has already performed its own checks before getting
   // to this point.
   ErrorResult error;
   mCacheStorage =
     CacheStorage::CreateOnMainThread(mozilla::dom::cache::CHROME_ONLY_NAMESPACE,
                                      mSandboxGlobalObject,
-                                     aPrincipal, mPrivateBrowsing,
+                                     aPrincipal,
+                                     false, /* privateBrowsing can't be true here */
                                      true /* force trusted origin */,
                                      error);
   if (NS_WARN_IF(error.Failed())) {
     return error.StealNSResult();
   }
 
   return NS_OK;
 }
--- a/dom/workers/ServiceWorkerInfo.cpp
+++ b/dom/workers/ServiceWorkerInfo.cpp
@@ -155,16 +155,18 @@ ServiceWorkerInfo::ServiceWorkerInfo(nsI
   , mScriptSpec(aScriptSpec)
   , mCacheName(aCacheName)
   , mState(ServiceWorkerState::EndGuard_)
   , mServiceWorkerID(GetNextID())
   , mServiceWorkerPrivate(new ServiceWorkerPrivate(this))
   , mSkipWaitingFlag(false)
 {
   MOZ_ASSERT(mPrincipal);
+  // cache origin attributes so we can use them off main thread
+  mOriginAttributes = BasePrincipal::Cast(mPrincipal)->OriginAttributesRef();
   MOZ_ASSERT(!mScope.IsEmpty());
   MOZ_ASSERT(!mScriptSpec.IsEmpty());
   MOZ_ASSERT(!mCacheName.IsEmpty());
 }
 
 ServiceWorkerInfo::~ServiceWorkerInfo()
 {
   MOZ_ASSERT(mServiceWorkerPrivate);
--- a/dom/workers/ServiceWorkerInfo.h
+++ b/dom/workers/ServiceWorkerInfo.h
@@ -26,16 +26,17 @@ class ServiceWorkerPrivate;
 class ServiceWorkerInfo final : public nsIServiceWorkerInfo
 {
 private:
   nsCOMPtr<nsIPrincipal> mPrincipal;
   const nsCString mScope;
   const nsCString mScriptSpec;
   const nsString mCacheName;
   ServiceWorkerState mState;
+  PrincipalOriginAttributes mOriginAttributes;
 
   // This id is shared with WorkerPrivate to match requests issued by service
   // workers to their corresponding serviceWorkerInfo.
   uint64_t mServiceWorkerID;
 
   // We hold rawptrs since the ServiceWorker constructor and destructor ensure
   // addition and removal.
   // There is a high chance of there being at least one ServiceWorker
@@ -99,16 +100,22 @@ public:
                     const nsAString& aCacheName);
 
   ServiceWorkerState
   State() const
   {
     return mState;
   }
 
+  const PrincipalOriginAttributes&
+  GetOriginAttributes() const
+  {
+    return mOriginAttributes;
+  }
+
   const nsString&
   CacheName() const
   {
     return mCacheName;
   }
 
   uint64_t
   ID() const
--- a/dom/workers/ServiceWorkerPrivate.cpp
+++ b/dom/workers/ServiceWorkerPrivate.cpp
@@ -1709,17 +1709,17 @@ ServiceWorkerPrivate::SpawnWorkerIfNeede
     return rv;
   }
 
   info.mPrincipal = mInfo->GetPrincipal();
 
   nsContentUtils::StorageAccess access =
     nsContentUtils::StorageAllowedForPrincipal(info.mPrincipal);
   info.mStorageAllowed = access > nsContentUtils::StorageAccess::ePrivateBrowsing;
-  info.mPrivateBrowsing = false;
+  info.mOriginAttributes = mInfo->GetOriginAttributes();
 
   nsCOMPtr<nsIContentSecurityPolicy> csp;
   rv = info.mPrincipal->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
@@ -1734,17 +1734,16 @@ WorkerLoadInfo::WorkerLoadInfo()
   , mServiceWorkerID(0)
   , mReferrerPolicy(net::RP_Default)
   , mFromWindow(false)
   , mEvalAllowed(false)
   , mReportCSPViolations(false)
   , mXHRParamsAllowed(false)
   , mPrincipalIsSystem(false)
   , mStorageAllowed(false)
-  , mPrivateBrowsing(true)
   , mServiceWorkersTestingInWindow(false)
 {
   MOZ_COUNT_CTOR(WorkerLoadInfo);
 }
 
 WorkerLoadInfo::~WorkerLoadInfo()
 {
   MOZ_COUNT_DTOR(WorkerLoadInfo);
@@ -1792,18 +1791,18 @@ WorkerLoadInfo::StealFrom(WorkerLoadInfo
   mServiceWorkerID = aOther.mServiceWorkerID;
   mReferrerPolicy = aOther.mReferrerPolicy;
   mFromWindow = aOther.mFromWindow;
   mEvalAllowed = aOther.mEvalAllowed;
   mReportCSPViolations = aOther.mReportCSPViolations;
   mXHRParamsAllowed = aOther.mXHRParamsAllowed;
   mPrincipalIsSystem = aOther.mPrincipalIsSystem;
   mStorageAllowed = aOther.mStorageAllowed;
-  mPrivateBrowsing = aOther.mPrivateBrowsing;
   mServiceWorkersTestingInWindow = aOther.mServiceWorkersTestingInWindow;
+  mOriginAttributes = aOther.mOriginAttributes;
 }
 
 template <class Derived>
 class WorkerPrivateParent<Derived>::EventTarget final
   : public nsIEventTarget
 {
   // This mutex protects mWorkerPrivate and must be acquired *before* the
   // WorkerPrivate's mutex whenever they must both be held.
@@ -3421,17 +3420,17 @@ WorkerPrivateParent<Derived>::SetPrincip
   } else {
     mLoadInfo.mEvalAllowed = true;
     mLoadInfo.mReportCSPViolations = false;
   }
 
   mLoadInfo.mLoadGroup = aLoadGroup;
 
   mLoadInfo.mPrincipalInfo = new PrincipalInfo();
-  mLoadInfo.mPrivateBrowsing = nsContentUtils::IsInPrivateBrowsing(aLoadGroup);
+  mLoadInfo.mOriginAttributes = nsContentUtils::GetOriginAttributes(aLoadGroup);
 
   MOZ_ALWAYS_SUCCEEDS(
     PrincipalToPrincipalInfo(aPrincipal, mLoadInfo.mPrincipalInfo));
 }
 
 template <class Derived>
 void
 WorkerPrivateParent<Derived>::UpdateOverridenLoadGroup(nsILoadGroup* aBaseLoadGroup)
@@ -4188,17 +4187,17 @@ WorkerPrivate::GetLoadInfo(JSContext* aC
       NS_ReleaseOnMainThread(loadInfo.mChannel.forget());
       return NS_ERROR_FAILURE;
     }
 
     loadInfo.mDomain = aParent->Domain();
     loadInfo.mFromWindow = aParent->IsFromWindow();
     loadInfo.mWindowID = aParent->WindowID();
     loadInfo.mStorageAllowed = aParent->IsStorageAllowed();
-    loadInfo.mPrivateBrowsing = aParent->IsInPrivateBrowsing();
+    loadInfo.mOriginAttributes = aParent->GetOriginAttributes();
     loadInfo.mServiceWorkersTestingInWindow =
       aParent->ServiceWorkersTestingInWindow();
   } else {
     AssertIsOnMainThread();
 
     // Make sure that the IndexedDatabaseManager is set up
     Unused << NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate());
 
@@ -4312,17 +4311,17 @@ WorkerPrivate::GetLoadInfo(JSContext* aC
 
       loadInfo.mXHRParamsAllowed = perm == nsIPermissionManager::ALLOW_ACTION;
 
       loadInfo.mFromWindow = true;
       loadInfo.mWindowID = globalWindow->WindowID();
       nsContentUtils::StorageAccess access =
         nsContentUtils::StorageAllowedForWindow(globalWindow);
       loadInfo.mStorageAllowed = access > nsContentUtils::StorageAccess::eDeny;
-      loadInfo.mPrivateBrowsing = nsContentUtils::IsInPrivateBrowsing(document);
+      loadInfo.mOriginAttributes = nsContentUtils::GetOriginAttributes(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;
       if (JS::DescribeScriptedCaller(aCx, &fileName)) {
@@ -4354,17 +4353,17 @@ WorkerPrivate::GetLoadInfo(JSContext* aC
         if (NS_FAILED(rv)) {
           return rv;
         }
       }
       loadInfo.mXHRParamsAllowed = true;
       loadInfo.mFromWindow = false;
       loadInfo.mWindowID = UINT64_MAX;
       loadInfo.mStorageAllowed = true;
-      loadInfo.mPrivateBrowsing = false;
+      loadInfo.mOriginAttributes = PrincipalOriginAttributes();
     }
 
     MOZ_ASSERT(loadInfo.mPrincipal);
     MOZ_ASSERT(isChrome || !loadInfo.mDomain.IsEmpty());
 
     if (!loadInfo.mLoadGroup || aLoadGroupBehavior == OverrideLoadGroup) {
       OverrideLoadInfoLoadGroup(loadInfo);
     }
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -778,20 +778,20 @@ public:
   }
 
   bool
   IsStorageAllowed() const
   {
     return mLoadInfo.mStorageAllowed;
   }
 
-  bool
-  IsInPrivateBrowsing() const
+  const PrincipalOriginAttributes&
+  GetOriginAttributes() const
   {
-    return mLoadInfo.mPrivateBrowsing;
+    return mLoadInfo.mOriginAttributes;
   }
 
   // Determine if the SW testing per-window flag is set by devtools
   bool
   ServiceWorkersTestingInWindow() const
   {
     return mLoadInfo.mServiceWorkersTestingInWindow;
   }
--- a/dom/workers/Workers.h
+++ b/dom/workers/Workers.h
@@ -264,18 +264,18 @@ struct WorkerLoadInfo
 
   net::ReferrerPolicy mReferrerPolicy;
   bool mFromWindow;
   bool mEvalAllowed;
   bool mReportCSPViolations;
   bool mXHRParamsAllowed;
   bool mPrincipalIsSystem;
   bool mStorageAllowed;
-  bool mPrivateBrowsing;
   bool mServiceWorkersTestingInWindow;
+  PrincipalOriginAttributes mOriginAttributes;
 
   WorkerLoadInfo();
   ~WorkerLoadInfo();
 
   void StealFrom(WorkerLoadInfo& aOther);
 };
 
 // All of these are implemented in RuntimeService.cpp