Bug 1534431 - Part 1: Verify LS request parameters as part of LS request state machine; r=asuth a=jcristau
authorJan Varga <jan.varga@gmail.com>
Mon, 03 Jun 2019 15:32:50 +0200
changeset 536845 e9a8bcc1834245886d249b4c91467ca2a5984396
parent 536844 2a42b81259f661b8b91573daee509d494a50e1f5
child 536846 5bc174324f871a279ffa0fb7272bbe397703df36
push id2082
push userffxbld-merge
push dateMon, 01 Jul 2019 08:34:18 +0000
treeherdermozilla-release@2fb19d0466d2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth, jcristau
bugs1534431
milestone68.0
Bug 1534431 - Part 1: Verify LS request parameters as part of LS request state machine; r=asuth a=jcristau LS Request parameters are now verified as part of the state machine so an actor is always created. Before this patch, we were doing verification prior to actor creation. If the verification failed, we didn't create an actor and content was endlessly waiting for a reply.
dom/localstorage/ActorsParent.cpp
--- a/dom/localstorage/ActorsParent.cpp
+++ b/dom/localstorage/ActorsParent.cpp
@@ -2194,23 +2194,23 @@ class Observer final : public PBackgroun
 
   mozilla::ipc::IPCResult RecvDeleteMe() override;
 };
 
 class LSRequestBase : public DatastoreOperationBase,
                       public PBackgroundLSRequestParent {
  protected:
   enum class State {
-    // Just created on the PBackground thread. Next step is Opening.
+    // Just created on the PBackground thread. Next step is StartingRequest.
     Initial,
 
-    // Waiting to open/opening on the main thread. Next step is either
-    // Nesting if a subclass needs to process more nested states or
+    // Waiting to start/starting request on the PBackground thread. Next step is
+    // either Nesting if a subclass needs to process more nested states or
     // SendingReadyMessage if a subclass doesn't need any nested processing.
-    Opening,
+    StartingRequest,
 
     // Doing nested processing.
     Nesting,
 
     // Waiting to send/sending the ready message on the PBackground thread. Next
     // step is WaitingForFinish.
     SendingReadyMessage,
 
@@ -2222,40 +2222,48 @@ class LSRequestBase : public DatastoreOp
     // Completed.
     SendingResults,
 
     // All done.
     Completed
   };
 
   nsCOMPtr<nsIEventTarget> mMainEventTarget;
+  const LSRequestParams mParams;
+  Maybe<ContentParentId> mContentParentId;
   State mState;
   bool mWaitingForFinish;
 
  public:
-  explicit LSRequestBase(nsIEventTarget* aMainEventTarget);
+  LSRequestBase(nsIEventTarget* aMainEventTarget,
+                const LSRequestParams& aParams,
+                const Maybe<ContentParentId>& aContentParentId);
 
   void Dispatch();
 
  protected:
   ~LSRequestBase() override;
 
-  virtual nsresult Open() = 0;
+  virtual nsresult Start() = 0;
 
   virtual nsresult NestedRun();
 
   virtual void GetResponse(LSRequestResponse& aResponse) = 0;
 
   virtual void Cleanup() {}
 
   void LogState();
 
   virtual void LogNestedState() {}
 
  private:
+  bool VerifyRequestParams();
+
+  nsresult StartRequest();
+
   void SendReadyMessage();
 
   nsresult SendReadyMessageInternal();
 
   void Finish();
 
   void FinishInternal();
 
@@ -2337,18 +2345,16 @@ class PrepareDatastoreOp
   RefPtr<DirectoryLock> mPendingDirectoryLock;
   RefPtr<DirectoryLock> mDirectoryLock;
   RefPtr<Connection> mConnection;
   RefPtr<Datastore> mDatastore;
   nsAutoPtr<ArchivedOriginScope> mArchivedOriginScope;
   LoadDataOp* mLoadDataOp;
   nsDataHashtable<nsStringHashKey, LSValue> mValues;
   nsTArray<LSItemInfo> mOrderedItems;
-  const LSRequestCommonParams mParams;
-  Maybe<ContentParentId> mContentParentId;
   nsCString mSuffix;
   nsCString mGroup;
   nsCString mMainThreadOrigin;
   nsCString mOrigin;
   nsString mDatabaseFilePath;
   uint32_t mPrivateBrowsingId;
   int64_t mUsage;
   int64_t mSizeOfKeys;
@@ -2392,17 +2398,17 @@ class PrepareDatastoreOp
     AssertIsOnOwningThread();
 
     mInvalidated = true;
   }
 
  private:
   ~PrepareDatastoreOp() override;
 
-  nsresult Open() override;
+  nsresult Start() override;
 
   nsresult CheckExistingOperations();
 
   nsresult CheckClosingDatastoreInternal();
 
   nsresult CheckClosingDatastore();
 
   nsresult BeginDatastorePreparationInternal();
@@ -2490,81 +2496,89 @@ class PrepareDatastoreOp::CompressibleFu
  private:
   ~CompressibleFunction() = default;
 
   NS_DECL_ISUPPORTS
   NS_DECL_MOZISTORAGEFUNCTION
 };
 
 class PrepareObserverOp : public LSRequestBase {
-  const LSRequestPrepareObserverParams mParams;
   nsCString mOrigin;
 
  public:
   PrepareObserverOp(nsIEventTarget* aMainEventTarget,
-                    const LSRequestParams& aParams);
+                    const LSRequestParams& aParams,
+                    const Maybe<ContentParentId>& aContentParentId);
 
  private:
-  nsresult Open() override;
+  nsresult Start() override;
 
   void GetResponse(LSRequestResponse& aResponse) override;
 };
 
 class LSSimpleRequestBase : public DatastoreOperationBase,
                             public PBackgroundLSSimpleRequestParent {
  protected:
   enum class State {
-    // Just created on the PBackground thread. Next step is Opening.
+    // Just created on the PBackground thread. Next step is StartingRequest.
     Initial,
 
-    // Waiting to open/opening on the main thread. Next step is SendingResults.
-    Opening,
+    // Waiting to start/starting request on the PBackground thread. Next step is
+    // SendingResults.
+    StartingRequest,
 
     // Waiting to send/sending results on the PBackground thread. Next step is
     // Completed.
     SendingResults,
 
     // All done.
     Completed
   };
 
+  const LSSimpleRequestParams mParams;
+  Maybe<ContentParentId> mContentParentId;
   State mState;
 
  public:
-  LSSimpleRequestBase();
+  LSSimpleRequestBase(const LSSimpleRequestParams& aParams,
+                      const Maybe<ContentParentId>& aContentParentId);
 
   void Dispatch();
 
  protected:
   ~LSSimpleRequestBase() override;
 
-  virtual nsresult Open() = 0;
+  virtual nsresult Start() = 0;
 
   virtual void GetResponse(LSSimpleRequestResponse& aResponse) = 0;
 
  private:
+  bool VerifyRequestParams();
+
+  nsresult StartRequest();
+
   void SendResults();
 
   // Common nsIRunnable implementation that subclasses may not override.
   NS_IMETHOD
   Run() final;
 
   // IPDL methods.
   void ActorDestroy(ActorDestroyReason aWhy) override;
 };
 
 class PreloadedOp : public LSSimpleRequestBase {
-  const LSSimpleRequestPreloadedParams mParams;
   nsCString mOrigin;
 
  public:
-  explicit PreloadedOp(const LSSimpleRequestParams& aParams);
+  PreloadedOp(const LSSimpleRequestParams& aParams,
+              const Maybe<ContentParentId>& aContentParentId);
 
  private:
-  nsresult Open() override;
+  nsresult Start() override;
 
   void GetResponse(LSSimpleRequestResponse& aResponse) override;
 };
 
 /*******************************************************************************
  * Other class declarations
  ******************************************************************************/
 
@@ -3135,16 +3149,63 @@ void RequestAllowToCloseIf(P aPredicate)
 
   for (Database* database : databases) {
     database->RequestAllowToClose();
   }
 
   databases.Clear();
 }
 
+bool VerifyPrincipalInfo(const Maybe<ContentParentId>& aContentParentId,
+                         const PrincipalInfo& aPrincipalInfo,
+                         const PrincipalInfo& aStoragePrincipalInfo,
+                         const Maybe<nsID>& aClientId) {
+  AssertIsOnBackgroundThread();
+
+  if (NS_WARN_IF(!QuotaManager::IsPrincipalInfoValid(aPrincipalInfo))) {
+    return false;
+  }
+
+  if (gClientValidation && aClientId.isSome()) {
+    RefPtr<ClientManagerService> svc = ClientManagerService::GetInstance();
+    if (svc && NS_WARN_IF(!svc->HasWindow(aContentParentId, aPrincipalInfo,
+                                          aClientId.ref()))) {
+      return false;
+    }
+  }
+
+  if (NS_WARN_IF(!StoragePrincipalHelper::
+                     VerifyValidStoragePrincipalInfoForPrincipalInfo(
+                         aStoragePrincipalInfo, aPrincipalInfo))) {
+    return false;
+  }
+
+  return true;
+}
+
+bool VerifyOriginKey(const nsACString& aOriginKey,
+                     const PrincipalInfo& aPrincipalInfo) {
+  AssertIsOnBackgroundThread();
+
+  nsCString originAttrSuffix;
+  nsCString originKey;
+  nsresult rv = GenerateOriginKey2(aPrincipalInfo, originAttrSuffix, originKey);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return false;
+  }
+
+  if (NS_WARN_IF(originKey != aOriginKey)) {
+    LS_WARNING("originKey (%s) doesn't match passed one (%s)!", originKey.get(),
+               nsCString(aOriginKey).get());
+    return false;
+  }
+
+  return true;
+}
+
 }  // namespace
 
 /*******************************************************************************
  * Exported functions
  ******************************************************************************/
 
 void InitializeLocalStorage() {
   MOZ_ASSERT(XRE_IsParentProcess());
@@ -3331,158 +3392,32 @@ bool DeallocPBackgroundLSObserverParent(
   MOZ_ASSERT(aActor);
 
   // Transfer ownership back from IPDL.
   RefPtr<Observer> actor = dont_AddRef(static_cast<Observer*>(aActor));
 
   return true;
 }
 
-bool VerifyPrincipalInfo(const Maybe<ContentParentId>& aContentParentId,
-                         const PrincipalInfo& aPrincipalInfo,
-                         const PrincipalInfo& aStoragePrincipalInfo,
-                         const Maybe<nsID>& aClientId) {
-  AssertIsOnBackgroundThread();
-
-  if (NS_WARN_IF(!QuotaManager::IsPrincipalInfoValid(aPrincipalInfo))) {
-    ASSERT_UNLESS_FUZZING();
-    return false;
-  }
-
-  if (aClientId.isSome() && gClientValidation) {
-    RefPtr<ClientManagerService> svc = ClientManagerService::GetInstance();
-    if (svc &&
-        !svc->HasWindow(aContentParentId, aPrincipalInfo, aClientId.ref())) {
-      ASSERT_UNLESS_FUZZING();
-      return false;
-    }
-  }
-
-  return StoragePrincipalHelper::
-      VerifyValidStoragePrincipalInfoForPrincipalInfo(aStoragePrincipalInfo,
-                                                      aPrincipalInfo);
-}
-
-bool VerifyOriginKey(const nsACString& aOriginKey,
-                     const PrincipalInfo& aPrincipalInfo) {
-  AssertIsOnBackgroundThread();
-
-  nsCString originAttrSuffix;
-  nsCString originKey;
-  nsresult rv = GenerateOriginKey2(aPrincipalInfo, originAttrSuffix, originKey);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    ASSERT_UNLESS_FUZZING();
-    return false;
-  }
-
-  if (NS_WARN_IF(originKey != aOriginKey)) {
-    LS_WARNING("originKey (%s) doesn't match passed one (%s)!", originKey.get(),
-               nsCString(aOriginKey).get());
-    ASSERT_UNLESS_FUZZING();
-    return false;
-  }
-
-  return true;
-}
-
-bool VerifyRequestParams(const Maybe<ContentParentId>& aContentParentId,
-                         const LSRequestParams& aParams) {
-  AssertIsOnBackgroundThread();
-  MOZ_ASSERT(aParams.type() != LSRequestParams::T__None);
-
-  switch (aParams.type()) {
-    case LSRequestParams::TLSRequestPreloadDatastoreParams: {
-      const LSRequestCommonParams& params =
-          aParams.get_LSRequestPreloadDatastoreParams().commonParams();
-
-      if (NS_WARN_IF(
-              !VerifyPrincipalInfo(aContentParentId, params.principalInfo(),
-                                   params.storagePrincipalInfo(), Nothing()))) {
-        ASSERT_UNLESS_FUZZING();
-        return false;
-      }
-
-      if (NS_WARN_IF(
-              !VerifyOriginKey(params.originKey(), params.principalInfo()))) {
-        ASSERT_UNLESS_FUZZING();
-        return false;
-      }
-      break;
-    }
-
-    case LSRequestParams::TLSRequestPrepareDatastoreParams: {
-      const LSRequestPrepareDatastoreParams& params =
-          aParams.get_LSRequestPrepareDatastoreParams();
-
-      const LSRequestCommonParams& commonParams = params.commonParams();
-
-      if (NS_WARN_IF(!VerifyPrincipalInfo(
-              aContentParentId, commonParams.principalInfo(),
-              commonParams.storagePrincipalInfo(), params.clientId()))) {
-        ASSERT_UNLESS_FUZZING();
-        return false;
-      }
-
-      if (NS_WARN_IF(!VerifyOriginKey(commonParams.originKey(),
-                                      commonParams.principalInfo()))) {
-        ASSERT_UNLESS_FUZZING();
-        return false;
-      }
-      break;
-    }
-
-    case LSRequestParams::TLSRequestPrepareObserverParams: {
-      const LSRequestPrepareObserverParams& params =
-          aParams.get_LSRequestPrepareObserverParams();
-
-      if (NS_WARN_IF(!VerifyPrincipalInfo(
-              aContentParentId, params.principalInfo(),
-              params.storagePrincipalInfo(), params.clientId()))) {
-        ASSERT_UNLESS_FUZZING();
-        return false;
-      }
-      break;
-    }
-
-    default:
-      MOZ_CRASH("Should never get here!");
-  }
-
-  return true;
-}
-
 PBackgroundLSRequestParent* AllocPBackgroundLSRequestParent(
     PBackgroundParent* aBackgroundActor, const LSRequestParams& aParams) {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aParams.type() != LSRequestParams::T__None);
 
   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread())) {
     return nullptr;
   }
 
-#ifdef DEBUG
-  // Always verify parameters in DEBUG builds!
-  bool trustParams = false;
-#else
-  bool trustParams = !BackgroundParent::IsOtherProcessActor(aBackgroundActor);
-#endif
-
   Maybe<ContentParentId> contentParentId;
 
   uint64_t childID = BackgroundParent::GetChildID(aBackgroundActor);
   if (childID) {
     contentParentId = Some(ContentParentId(childID));
   }
 
-  if (!trustParams &&
-      NS_WARN_IF(!VerifyRequestParams(contentParentId, aParams))) {
-    ASSERT_UNLESS_FUZZING();
-    return nullptr;
-  }
-
   // If we're in the same process as the actor, we need to get the target event
   // queue from the current RequestHelper.
   nsCOMPtr<nsIEventTarget> mainEventTarget;
   if (!BackgroundParent::IsOtherProcessActor(aBackgroundActor)) {
     mainEventTarget = LSObject::GetSyncLoopEventTarget();
   }
 
   RefPtr<LSRequestBase> actor;
@@ -3500,17 +3435,17 @@ PBackgroundLSRequestParent* AllocPBackgr
 
       actor = std::move(prepareDatastoreOp);
 
       break;
     }
 
     case LSRequestParams::TLSRequestPrepareObserverParams: {
       RefPtr<PrepareObserverOp> prepareObserverOp =
-          new PrepareObserverOp(mainEventTarget, aParams);
+          new PrepareObserverOp(mainEventTarget, aParams, contentParentId);
 
       actor = std::move(prepareObserverOp);
 
       break;
     }
 
     default:
       MOZ_CRASH("Should never get here!");
@@ -3541,77 +3476,38 @@ bool DeallocPBackgroundLSRequestParent(P
 
   // Transfer ownership back from IPDL.
   RefPtr<LSRequestBase> actor =
       dont_AddRef(static_cast<LSRequestBase*>(aActor));
 
   return true;
 }
 
-bool VerifyRequestParams(const Maybe<ContentParentId>& aContentParentId,
-                         const LSSimpleRequestParams& aParams) {
-  AssertIsOnBackgroundThread();
-  MOZ_ASSERT(aParams.type() != LSSimpleRequestParams::T__None);
-
-  switch (aParams.type()) {
-    case LSSimpleRequestParams::TLSSimpleRequestPreloadedParams: {
-      const LSSimpleRequestPreloadedParams& params =
-          aParams.get_LSSimpleRequestPreloadedParams();
-
-      if (NS_WARN_IF(
-              !VerifyPrincipalInfo(aContentParentId, params.principalInfo(),
-                                   params.storagePrincipalInfo(), Nothing()))) {
-        ASSERT_UNLESS_FUZZING();
-        return false;
-      }
-      break;
-    }
-
-    default:
-      MOZ_CRASH("Should never get here!");
-  }
-
-  return true;
-}
-
 PBackgroundLSSimpleRequestParent* AllocPBackgroundLSSimpleRequestParent(
     PBackgroundParent* aBackgroundActor, const LSSimpleRequestParams& aParams) {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aParams.type() != LSSimpleRequestParams::T__None);
 
   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread())) {
     return nullptr;
   }
 
-#ifdef DEBUG
-  // Always verify parameters in DEBUG builds!
-  bool trustParams = false;
-#else
-  bool trustParams = !BackgroundParent::IsOtherProcessActor(aBackgroundActor);
-#endif
-
-  if (!trustParams) {
-    Maybe<ContentParentId> contentParentId;
-
-    uint64_t childID = BackgroundParent::GetChildID(aBackgroundActor);
-    if (childID) {
-      contentParentId = Some(ContentParentId(childID));
-    }
-
-    if (NS_WARN_IF(!VerifyRequestParams(contentParentId, aParams))) {
-      ASSERT_UNLESS_FUZZING();
-      return nullptr;
-    }
+  Maybe<ContentParentId> contentParentId;
+
+  uint64_t childID = BackgroundParent::GetChildID(aBackgroundActor);
+  if (childID) {
+    contentParentId = Some(ContentParentId(childID));
   }
 
   RefPtr<LSSimpleRequestBase> actor;
 
   switch (aParams.type()) {
     case LSSimpleRequestParams::TLSSimpleRequestPreloadedParams: {
-      RefPtr<PreloadedOp> preloadedOp = new PreloadedOp(aParams);
+      RefPtr<PreloadedOp> preloadedOp =
+          new PreloadedOp(aParams, contentParentId);
 
       actor = std::move(preloadedOp);
 
       break;
     }
 
     default:
       MOZ_CRASH("Should never get here!");
@@ -6418,30 +6314,34 @@ mozilla::ipc::IPCResult Observer::RecvDe
   }
   return IPC_OK();
 }
 
 /*******************************************************************************
  * LSRequestBase
  ******************************************************************************/
 
-LSRequestBase::LSRequestBase(nsIEventTarget* aMainEventTarget)
+LSRequestBase::LSRequestBase(nsIEventTarget* aMainEventTarget,
+                             const LSRequestParams& aParams,
+                             const Maybe<ContentParentId>& aContentParentId)
     : mMainEventTarget(aMainEventTarget),
+      mParams(aParams),
+      mContentParentId(aContentParentId),
       mState(State::Initial),
       mWaitingForFinish(false) {}
 
 LSRequestBase::~LSRequestBase() {
   MOZ_ASSERT_IF(MayProceedOnNonOwningThread(),
                 mState == State::Initial || mState == State::Completed);
 }
 
 void LSRequestBase::Dispatch() {
   AssertIsOnOwningThread();
 
-  mState = State::Opening;
+  mState = State::StartingRequest;
 
   MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(this));
 }
 
 nsresult LSRequestBase::NestedRun() { return NS_OK; }
 
 void LSRequestBase::LogState() {
   AssertIsOnOwningThread();
@@ -6454,18 +6354,18 @@ void LSRequestBase::LogState() {
 
   nsCString state;
 
   switch (mState) {
     case State::Initial:
       state.AssignLiteral("Initial");
       break;
 
-    case State::Opening:
-      state.AssignLiteral("Opening");
+    case State::StartingRequest:
+      state.AssignLiteral("StartingRequest");
       break;
 
     case State::Nesting:
       state.AssignLiteral("Nesting");
       break;
 
     case State::SendingReadyMessage:
       state.AssignLiteral("SendingReadyMessage");
@@ -6493,16 +6393,108 @@ void LSRequestBase::LogState() {
     case State::Nesting:
       LogNestedState();
       break;
 
     default:;
   }
 }
 
+bool LSRequestBase::VerifyRequestParams() {
+  AssertIsOnBackgroundThread();
+
+  MOZ_ASSERT(mParams.type() != LSRequestParams::T__None);
+
+  switch (mParams.type()) {
+    case LSRequestParams::TLSRequestPreloadDatastoreParams: {
+      const LSRequestCommonParams& params =
+          mParams.get_LSRequestPreloadDatastoreParams().commonParams();
+
+      if (NS_WARN_IF(
+              !VerifyPrincipalInfo(mContentParentId, params.principalInfo(),
+                                   params.storagePrincipalInfo(), Nothing()))) {
+        return false;
+      }
+
+      if (NS_WARN_IF(
+              !VerifyOriginKey(params.originKey(), params.principalInfo()))) {
+        return false;
+      }
+
+      break;
+    }
+
+    case LSRequestParams::TLSRequestPrepareDatastoreParams: {
+      const LSRequestPrepareDatastoreParams& params =
+          mParams.get_LSRequestPrepareDatastoreParams();
+
+      const LSRequestCommonParams& commonParams = params.commonParams();
+
+      if (NS_WARN_IF(!VerifyPrincipalInfo(
+              mContentParentId, commonParams.principalInfo(),
+              commonParams.storagePrincipalInfo(), params.clientId()))) {
+        return false;
+      }
+
+      if (NS_WARN_IF(!VerifyOriginKey(commonParams.originKey(),
+                                      commonParams.principalInfo()))) {
+        return false;
+      }
+
+      break;
+    }
+
+    case LSRequestParams::TLSRequestPrepareObserverParams: {
+      const LSRequestPrepareObserverParams& params =
+          mParams.get_LSRequestPrepareObserverParams();
+
+      if (NS_WARN_IF(!VerifyPrincipalInfo(
+              mContentParentId, params.principalInfo(),
+              params.storagePrincipalInfo(), params.clientId()))) {
+        return false;
+      }
+
+      break;
+    }
+
+    default:
+      MOZ_CRASH("Should never get here!");
+  }
+
+  return true;
+}
+
+nsresult LSRequestBase::StartRequest() {
+  AssertIsOnOwningThread();
+  MOZ_ASSERT(mState == State::StartingRequest);
+
+  if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
+      !MayProceed()) {
+    return NS_ERROR_FAILURE;
+  }
+
+#ifdef DEBUG
+  // Always verify parameters in DEBUG builds!
+  bool trustParams = false;
+#else
+  bool trustParams = !BackgroundParent::IsOtherProcessActor(Manager());
+#endif
+
+  if (!trustParams && NS_WARN_IF(!VerifyRequestParams())) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsresult rv = Start();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+
 void LSRequestBase::SendReadyMessage() {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mState == State::SendingReadyMessage);
 
   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
       !MayProceed()) {
     MaybeSetFailureCode(NS_ERROR_FAILURE);
   }
@@ -6583,18 +6575,18 @@ void LSRequestBase::SendResults() {
   mState = State::Completed;
 }
 
 NS_IMETHODIMP
 LSRequestBase::Run() {
   nsresult rv;
 
   switch (mState) {
-    case State::Opening:
-      rv = Open();
+    case State::StartingRequest:
+      rv = StartRequest();
       break;
 
     case State::Nesting:
       rv = NestedRun();
       break;
 
     case State::SendingReadyMessage:
       SendReadyMessage();
@@ -6677,24 +6669,19 @@ mozilla::ipc::IPCResult LSRequestBase::R
 
 /*******************************************************************************
  * PrepareDatastoreOp
  ******************************************************************************/
 
 PrepareDatastoreOp::PrepareDatastoreOp(
     nsIEventTarget* aMainEventTarget, const LSRequestParams& aParams,
     const Maybe<ContentParentId>& aContentParentId)
-    : LSRequestBase(aMainEventTarget),
+    : LSRequestBase(aMainEventTarget, aParams, aContentParentId),
       mMainEventTarget(aMainEventTarget),
       mLoadDataOp(nullptr),
-      mParams(
-          aParams.type() == LSRequestParams::TLSRequestPreloadDatastoreParams
-              ? aParams.get_LSRequestPreloadDatastoreParams().commonParams()
-              : aParams.get_LSRequestPrepareDatastoreParams().commonParams()),
-      mContentParentId(aContentParentId),
       mPrivateBrowsingId(0),
       mUsage(0),
       mSizeOfKeys(0),
       mSizeOfItems(0),
       mDatastoreId(0),
       mNestedState(NestedState::BeforeNesting),
       mForPreload(aParams.type() ==
                   LSRequestParams::TLSRequestPreloadDatastoreParams),
@@ -6713,27 +6700,30 @@ PrepareDatastoreOp::PrepareDatastoreOp(
 
 PrepareDatastoreOp::~PrepareDatastoreOp() {
   MOZ_ASSERT(!mDirectoryLock);
   MOZ_ASSERT_IF(MayProceedOnNonOwningThread(),
                 mState == State::Initial || mState == State::Completed);
   MOZ_ASSERT(!mLoadDataOp);
 }
 
-nsresult PrepareDatastoreOp::Open() {
+nsresult PrepareDatastoreOp::Start() {
   AssertIsOnOwningThread();
-  MOZ_ASSERT(mState == State::Opening);
+  MOZ_ASSERT(mState == State::StartingRequest);
   MOZ_ASSERT(mNestedState == NestedState::BeforeNesting);
-
-  if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
-      !MayProceedOnNonOwningThread()) {
-    return NS_ERROR_FAILURE;
-  }
-
-  const PrincipalInfo& storagePrincipalInfo = mParams.storagePrincipalInfo();
+  MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
+  MOZ_ASSERT(MayProceed());
+
+  const LSRequestCommonParams& commonParams =
+      mForPreload
+          ? mParams.get_LSRequestPreloadDatastoreParams().commonParams()
+          : mParams.get_LSRequestPrepareDatastoreParams().commonParams();
+
+  const PrincipalInfo& storagePrincipalInfo =
+      commonParams.storagePrincipalInfo();
 
   if (storagePrincipalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
     QuotaManager::GetInfoForChrome(&mSuffix, &mGroup, &mOrigin);
   } else {
     MOZ_ASSERT(storagePrincipalInfo.type() ==
                PrincipalInfo::TContentPrincipalInfo);
 
     QuotaManager::GetInfoFromValidatedPrincipalInfo(
@@ -6754,17 +6744,23 @@ nsresult PrepareDatastoreOp::CheckExisti
   MOZ_ASSERT(mNestedState == NestedState::CheckExistingOperations);
   MOZ_ASSERT(gPrepareDatastoreOps);
 
   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
       !MayProceed()) {
     return NS_ERROR_FAILURE;
   }
 
-  const PrincipalInfo& storagePrincipalInfo = mParams.storagePrincipalInfo();
+  const LSRequestCommonParams& commonParams =
+      mForPreload
+          ? mParams.get_LSRequestPreloadDatastoreParams().commonParams()
+          : mParams.get_LSRequestPrepareDatastoreParams().commonParams();
+
+  const PrincipalInfo& storagePrincipalInfo =
+      commonParams.storagePrincipalInfo();
 
   nsCString originAttrSuffix;
   uint32_t privateBrowsingId;
 
   if (storagePrincipalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
     privateBrowsingId = 0;
   } else {
     MOZ_ASSERT(storagePrincipalInfo.type() ==
@@ -6774,17 +6770,17 @@ nsresult PrepareDatastoreOp::CheckExisti
         storagePrincipalInfo.get_ContentPrincipalInfo();
     const OriginAttributes& attrs = info.attrs();
     attrs.CreateSuffix(originAttrSuffix);
 
     privateBrowsingId = attrs.mPrivateBrowsingId;
   }
 
   mArchivedOriginScope = ArchivedOriginScope::CreateFromOrigin(
-      originAttrSuffix, mParams.originKey());
+      originAttrSuffix, commonParams.originKey());
   MOZ_ASSERT(mArchivedOriginScope);
 
   // Normally it's safe to access member variables without a mutex because even
   // though we hop between threads, the variables are never accessed by multiple
   // threads at the same time.
   // However, the methods OriginIsKnown and Origin can be called at any time.
   // So we have to make sure the member variable is set on the same thread as
   // those methods are called.
@@ -7539,16 +7535,18 @@ nsresult PrepareDatastoreOp::NestedRun()
 
   return NS_OK;
 }
 
 void PrepareDatastoreOp::GetResponse(LSRequestResponse& aResponse) {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mState == State::SendingResults);
   MOZ_ASSERT(NS_SUCCEEDED(ResultCode()));
+  MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
+  MOZ_ASSERT(MayProceed());
 
   // A datastore is not created when we are just trying to preload data and
   // there's no database file.
   if (mDatabaseNotAvailable && mForPreload) {
     LSRequestPreloadDatastoreResponse preloadDatastoreResponse;
 
     aResponse = preloadDatastoreResponse;
 
@@ -8014,34 +8012,34 @@ PrepareDatastoreOp::CompressibleFunction
   result.forget(aResult);
   return NS_OK;
 }
 
 /*******************************************************************************
  * PrepareObserverOp
  ******************************************************************************/
 
-PrepareObserverOp::PrepareObserverOp(nsIEventTarget* aMainEventTarget,
-                                     const LSRequestParams& aParams)
-    : LSRequestBase(aMainEventTarget),
-      mParams(aParams.get_LSRequestPrepareObserverParams()) {
+PrepareObserverOp::PrepareObserverOp(
+    nsIEventTarget* aMainEventTarget, const LSRequestParams& aParams,
+    const Maybe<ContentParentId>& aContentParentId)
+    : LSRequestBase(aMainEventTarget, aParams, aContentParentId) {
   MOZ_ASSERT(aParams.type() ==
              LSRequestParams::TLSRequestPrepareObserverParams);
 }
 
-nsresult PrepareObserverOp::Open() {
+nsresult PrepareObserverOp::Start() {
   AssertIsOnOwningThread();
-  MOZ_ASSERT(mState == State::Opening);
-
-  if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
-      !MayProceedOnNonOwningThread()) {
-    return NS_ERROR_FAILURE;
-  }
-
-  const PrincipalInfo& storagePrincipalInfo = mParams.storagePrincipalInfo();
+  MOZ_ASSERT(mState == State::StartingRequest);
+  MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
+  MOZ_ASSERT(MayProceed());
+
+  const LSRequestPrepareObserverParams params =
+      mParams.get_LSRequestPrepareObserverParams();
+
+  const PrincipalInfo& storagePrincipalInfo = params.storagePrincipalInfo();
 
   if (storagePrincipalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
     QuotaManager::GetInfoForChrome(nullptr, nullptr, &mOrigin);
   } else {
     MOZ_ASSERT(storagePrincipalInfo.type() ==
                PrincipalInfo::TContentPrincipalInfo);
 
     QuotaManager::GetInfoFromValidatedPrincipalInfo(storagePrincipalInfo,
@@ -8053,16 +8051,18 @@ nsresult PrepareObserverOp::Open() {
 
   return NS_OK;
 }
 
 void PrepareObserverOp::GetResponse(LSRequestResponse& aResponse) {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mState == State::SendingResults);
   MOZ_ASSERT(NS_SUCCEEDED(ResultCode()));
+  MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
+  MOZ_ASSERT(MayProceed());
 
   uint64_t observerId = ++gLastObserverId;
 
   RefPtr<Observer> observer = new Observer(mOrigin);
 
   if (!gPreparedObsevers) {
     gPreparedObsevers = new PreparedObserverHashtable();
   }
@@ -8074,31 +8074,90 @@ void PrepareObserverOp::GetResponse(LSRe
   aResponse = prepareObserverResponse;
 }
 
 /*******************************************************************************
 + * LSSimpleRequestBase
 +
 ******************************************************************************/
 
-LSSimpleRequestBase::LSSimpleRequestBase() : mState(State::Initial) {}
+LSSimpleRequestBase::LSSimpleRequestBase(
+    const LSSimpleRequestParams& aParams,
+    const Maybe<ContentParentId>& aContentParentId)
+    : mParams(aParams),
+      mContentParentId(aContentParentId),
+      mState(State::Initial) {}
 
 LSSimpleRequestBase::~LSSimpleRequestBase() {
   MOZ_ASSERT_IF(MayProceedOnNonOwningThread(),
                 mState == State::Initial || mState == State::Completed);
 }
 
 void LSSimpleRequestBase::Dispatch() {
   AssertIsOnOwningThread();
 
-  mState = State::Opening;
+  mState = State::StartingRequest;
 
   MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(this));
 }
 
+bool LSSimpleRequestBase::VerifyRequestParams() {
+  AssertIsOnBackgroundThread();
+
+  MOZ_ASSERT(mParams.type() != LSSimpleRequestParams::T__None);
+
+  switch (mParams.type()) {
+    case LSSimpleRequestParams::TLSSimpleRequestPreloadedParams: {
+      const LSSimpleRequestPreloadedParams& params =
+          mParams.get_LSSimpleRequestPreloadedParams();
+
+      if (NS_WARN_IF(
+              !VerifyPrincipalInfo(mContentParentId, params.principalInfo(),
+                                   params.storagePrincipalInfo(), Nothing()))) {
+        return false;
+      }
+
+      break;
+    }
+
+    default:
+      MOZ_CRASH("Should never get here!");
+  }
+
+  return true;
+}
+
+nsresult LSSimpleRequestBase::StartRequest() {
+  AssertIsOnOwningThread();
+  MOZ_ASSERT(mState == State::StartingRequest);
+
+  if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
+      !MayProceed()) {
+    return NS_ERROR_FAILURE;
+  }
+
+#ifdef DEBUG
+  // Always verify parameters in DEBUG builds!
+  bool trustParams = false;
+#else
+  bool trustParams = !BackgroundParent::IsOtherProcessActor(Manager());
+#endif
+
+  if (!trustParams && NS_WARN_IF(!VerifyRequestParams())) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsresult rv = Start();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+
 void LSSimpleRequestBase::SendResults() {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mState == State::SendingResults);
 
   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
       !MayProceed()) {
     MaybeSetFailureCode(NS_ERROR_FAILURE);
   }
@@ -8118,18 +8177,18 @@ void LSSimpleRequestBase::SendResults() 
   mState = State::Completed;
 }
 
 NS_IMETHODIMP
 LSSimpleRequestBase::Run() {
   nsresult rv;
 
   switch (mState) {
-    case State::Opening:
-      rv = Open();
+    case State::StartingRequest:
+      rv = StartRequest();
       break;
 
     case State::SendingResults:
       SendResults();
       return NS_OK;
 
     default:
       MOZ_CRASH("Bad state!");
@@ -8158,32 +8217,33 @@ void LSSimpleRequestBase::ActorDestroy(A
 
   NoteComplete();
 }
 
 /*******************************************************************************
  * PreloadedOp
  ******************************************************************************/
 
-PreloadedOp::PreloadedOp(const LSSimpleRequestParams& aParams)
-    : mParams(aParams.get_LSSimpleRequestPreloadedParams()) {
+PreloadedOp::PreloadedOp(const LSSimpleRequestParams& aParams,
+                         const Maybe<ContentParentId>& aContentParentId)
+    : LSSimpleRequestBase(aParams, aContentParentId) {
   MOZ_ASSERT(aParams.type() ==
              LSSimpleRequestParams::TLSSimpleRequestPreloadedParams);
 }
 
-nsresult PreloadedOp::Open() {
+nsresult PreloadedOp::Start() {
   AssertIsOnOwningThread();
-  MOZ_ASSERT(mState == State::Opening);
-
-  if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
-      !MayProceedOnNonOwningThread()) {
-    return NS_ERROR_FAILURE;
-  }
-
-  const PrincipalInfo& storagePrincipalInfo = mParams.storagePrincipalInfo();
+  MOZ_ASSERT(mState == State::StartingRequest);
+  MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
+  MOZ_ASSERT(MayProceed());
+
+  const LSSimpleRequestPreloadedParams& params =
+      mParams.get_LSSimpleRequestPreloadedParams();
+
+  const PrincipalInfo& storagePrincipalInfo = params.storagePrincipalInfo();
 
   if (storagePrincipalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
     QuotaManager::GetInfoForChrome(nullptr, nullptr, &mOrigin);
   } else {
     MOZ_ASSERT(storagePrincipalInfo.type() ==
                PrincipalInfo::TContentPrincipalInfo);
 
     QuotaManager::GetInfoFromValidatedPrincipalInfo(storagePrincipalInfo,
@@ -8195,16 +8255,18 @@ nsresult PreloadedOp::Open() {
 
   return NS_OK;
 }
 
 void PreloadedOp::GetResponse(LSSimpleRequestResponse& aResponse) {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mState == State::SendingResults);
   MOZ_ASSERT(NS_SUCCEEDED(ResultCode()));
+  MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
+  MOZ_ASSERT(MayProceed());
 
   bool preloaded;
   RefPtr<Datastore> datastore;
   if ((datastore = GetDatastore(mOrigin)) && !datastore->IsClosed()) {
     preloaded = true;
   } else {
     preloaded = false;
   }