Bug 1322316 - Split SessionStorage and LocalStorage implementation - part 1 - SessionStorage, r=asuth
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 17 May 2017 07:01:12 +0200
changeset 358630 9957d3e640736942b95c21dad5cfea3192cc1e96
parent 358629 159f82e6813c4dca0a72c1fa2a49ec99b087db32
child 358631 d959241eaf7d41b9d391e2dfb027d9321a719b63
push id90362
push useramarchesini@mozilla.com
push dateWed, 17 May 2017 05:03:33 +0000
treeherdermozilla-inbound@2f47ba116b42 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth
bugs1322316
milestone55.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 1322316 - Split SessionStorage and LocalStorage implementation - part 1 - SessionStorage, r=asuth
dom/storage/SessionStorage.cpp
dom/storage/SessionStorage.h
dom/storage/Storage.cpp
dom/storage/Storage.h
dom/storage/StorageCache.cpp
dom/storage/StorageCache.h
dom/storage/StorageManager.cpp
dom/storage/StorageManager.h
dom/storage/moz.build
new file mode 100644
--- /dev/null
+++ b/dom/storage/SessionStorage.cpp
@@ -0,0 +1,285 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=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 "SessionStorage.h"
+#include "StorageManager.h"
+
+#include "mozilla/dom/StorageBinding.h"
+#include "mozilla/Preferences.h"
+#include "nsContentUtils.h"
+#include "nsIPrincipal.h"
+#include "nsPIDOMWindow.h"
+
+namespace mozilla {
+namespace dom {
+
+// ----------------------------------------------------------------------------
+// SessionStorage
+// ----------------------------------------------------------------------------
+
+SessionStorage::SessionStorage(nsPIDOMWindowInner* aWindow,
+                               nsIPrincipal* aPrincipal,
+                               SessionStorageCache* aCache)
+  : Storage(aWindow, aPrincipal)
+  , mCache(aCache)
+{
+  MOZ_ASSERT(aCache);
+}
+
+SessionStorage::~SessionStorage()
+{
+}
+
+int64_t
+SessionStorage::GetOriginQuotaUsage() const
+{
+  return mCache->GetOriginQuotaUsage();
+}
+
+uint32_t
+SessionStorage::GetLength(nsIPrincipal& aSubjectPrincipal,
+                          ErrorResult& aRv)
+{
+  if (!CanUseStorage(aSubjectPrincipal)) {
+    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    return 0;
+  }
+
+  return mCache->Length();
+}
+
+void
+SessionStorage::Key(uint32_t aIndex, nsAString& aResult,
+                    nsIPrincipal& aSubjectPrincipal,
+                    ErrorResult& aRv)
+{
+  if (!CanUseStorage(aSubjectPrincipal)) {
+    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    return;
+  }
+
+  mCache->Key(aIndex, aResult);
+}
+
+void
+SessionStorage::GetItem(const nsAString& aKey, nsAString& aResult,
+                        nsIPrincipal& aSubjectPrincipal,
+                        ErrorResult& aRv)
+{
+  if (!CanUseStorage(aSubjectPrincipal)) {
+    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    return;
+  }
+
+  mCache->GetItem(aKey, aResult);
+}
+
+void
+SessionStorage::GetSupportedNames(nsTArray<nsString>& aKeys)
+{
+  if (!CanUseStorage(*nsContentUtils::SubjectPrincipal())) {
+    // return just an empty array
+    aKeys.Clear();
+    return;
+  }
+
+  mCache->GetKeys(aKeys);
+}
+
+void
+SessionStorage::SetItem(const nsAString& aKey, const nsAString& aValue,
+                        nsIPrincipal& aSubjectPrincipal,
+                        ErrorResult& aRv)
+{
+  if (!CanUseStorage(aSubjectPrincipal)) {
+    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    return;
+  }
+
+  nsString oldValue;
+  nsresult rv = mCache->SetItem(aKey, aValue, oldValue);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    aRv.Throw(rv);
+    return;
+  }
+
+  if (rv == NS_SUCCESS_DOM_NO_OPERATION) {
+    return;
+  }
+
+  BroadcastChangeNotification(aKey, oldValue, aValue);
+}
+
+void
+SessionStorage::RemoveItem(const nsAString& aKey,
+                           nsIPrincipal& aSubjectPrincipal,
+                           ErrorResult& aRv)
+{
+  if (!CanUseStorage(aSubjectPrincipal)) {
+    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    return;
+  }
+
+  nsString oldValue;
+  nsresult rv = mCache->RemoveItem(aKey, oldValue);
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
+
+  if (rv == NS_SUCCESS_DOM_NO_OPERATION) {
+    return;
+  }
+
+  BroadcastChangeNotification(aKey, oldValue, NullString());
+}
+
+void
+SessionStorage::Clear(nsIPrincipal& aSubjectPrincipal,
+                      ErrorResult& aRv)
+{
+  uint32_t length = GetLength(aSubjectPrincipal, aRv);
+  if (!length) {
+    return;
+  }
+
+  mCache->Clear();
+  BroadcastChangeNotification(NullString(), NullString(), NullString());
+}
+
+bool
+SessionStorage::CanUseStorage(nsIPrincipal& aSubjectPrincipal)
+{
+  // This method is responsible for correct setting of mIsSessionOnly.
+  // It doesn't work with mIsPrivate flag at all, since it is checked
+  // regardless mIsSessionOnly flag in DOMStorageCache code.
+
+  if (!mozilla::Preferences::GetBool("dom.storage.enabled")) {
+    return false;
+  }
+
+  nsContentUtils::StorageAccess access =
+    nsContentUtils::StorageAllowedForPrincipal(Principal());
+
+  if (access == nsContentUtils::StorageAccess::eDeny) {
+    return false;
+  }
+
+  return CanAccess(&aSubjectPrincipal);
+}
+
+void
+SessionStorage::BroadcastChangeNotification(const nsAString& aKey,
+                                            const nsAString& aOldValue,
+                                            const nsAString& aNewValue)
+{
+  // TODO
+}
+
+// ----------------------------------------------------------------------------
+// SessionStorageCache
+// ----------------------------------------------------------------------------
+
+SessionStorageCache::SessionStorageCache()
+  : mOriginQuotaUsage(0)
+{}
+
+void
+SessionStorageCache::Key(uint32_t aIndex, nsAString& aResult)
+{
+  aResult.SetIsVoid(true);
+  for (auto iter = mKeys.Iter(); !iter.Done(); iter.Next()) {
+    if (aIndex == 0) {
+      aResult = iter.Key();
+      return;
+    }
+    aIndex--;
+  }
+}
+
+void
+SessionStorageCache::GetItem(const nsAString& aKey, nsAString& aResult)
+{
+  // not using AutoString since we don't want to copy buffer to result
+  nsString value;
+  if (!mKeys.Get(aKey, &value)) {
+    SetDOMStringToNull(value);
+  }
+  aResult = value;
+}
+
+void
+SessionStorageCache::GetKeys(nsTArray<nsString>& aKeys)
+{
+  for (auto iter = mKeys.Iter(); !iter.Done(); iter.Next()) {
+    aKeys.AppendElement(iter.Key());
+  }
+}
+
+nsresult
+SessionStorageCache::SetItem(const nsAString& aKey, const nsAString& aValue,
+                             nsString& aOldValue)
+{
+  int64_t delta = 0;
+
+  if (!mKeys.Get(aKey, &aOldValue)) {
+    SetDOMStringToNull(aOldValue);
+
+    // We only consider key size if the key doesn't exist before.
+    delta = static_cast<int64_t>(aKey.Length());
+  }
+
+  delta += static_cast<int64_t>(aValue.Length()) -
+           static_cast<int64_t>(aOldValue.Length());
+
+  if (aValue == aOldValue &&
+      DOMStringIsNull(aValue) == DOMStringIsNull(aOldValue)) {
+    return NS_SUCCESS_DOM_NO_OPERATION;
+  }
+
+  if (!ProcessUsageDelta(delta)) {
+    return NS_ERROR_DOM_QUOTA_REACHED;
+  }
+
+  mKeys.Put(aKey, nsString(aValue));
+  return NS_OK;
+}
+
+nsresult
+SessionStorageCache::RemoveItem(const nsAString& aKey, nsString& aOldValue)
+{
+  if (!mKeys.Get(aKey, &aOldValue)) {
+    return NS_SUCCESS_DOM_NO_OPERATION;
+  }
+
+  // Recalculate the cached data size
+  ProcessUsageDelta(-(static_cast<int64_t>(aOldValue.Length()) +
+                      static_cast<int64_t>(aKey.Length())));
+
+  mKeys.Remove(aKey);
+  return NS_OK;
+}
+
+void
+SessionStorageCache::Clear()
+{
+  ProcessUsageDelta(-mOriginQuotaUsage);
+  mKeys.Clear();
+}
+
+bool
+SessionStorageCache::ProcessUsageDelta(int64_t aDelta)
+{
+  // Check limit per this origin
+  uint64_t newOriginUsage = mOriginQuotaUsage + aDelta;
+  if (aDelta > 0 && newOriginUsage > StorageManagerBase::GetQuota()) {
+    return false;
+  }
+
+  // Update size in our data set
+  mOriginQuotaUsage = newOriginUsage;
+  return true;
+}
+
+} // dom namespace
+} // mozilla namespace
new file mode 100644
--- /dev/null
+++ b/dom/storage/SessionStorage.h
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=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/. */
+
+#ifndef mozilla_dom_SessionStorage_h
+#define mozilla_dom_SessionStorage_h
+
+#include "Storage.h"
+#include "nsDataHashtable.h"
+
+class nsIPrincipal;
+
+namespace mozilla {
+namespace dom {
+
+class SessionStorageCache;
+
+class SessionStorage final : public Storage
+{
+public:
+  SessionStorage(nsPIDOMWindowInner* aWindow,
+                 nsIPrincipal* aPrincipal,
+                 SessionStorageCache* aCache);
+
+  int64_t GetOriginQuotaUsage() const override;
+
+  // WebIDL
+  uint32_t GetLength(nsIPrincipal& aSubjectPrincipal,
+                     ErrorResult& aRv) override;
+
+  void Key(uint32_t aIndex, nsAString& aResult,
+           nsIPrincipal& aSubjectPrincipal,
+           ErrorResult& aRv) override;
+
+  void GetItem(const nsAString& aKey, nsAString& aResult,
+               nsIPrincipal& aSubjectPrincipal,
+               ErrorResult& aRv) override;
+
+  void GetSupportedNames(nsTArray<nsString>& aKeys) override;
+
+  void SetItem(const nsAString& aKey, const nsAString& aValue,
+               nsIPrincipal& aSubjectPrincipal,
+               ErrorResult& aRv) override;
+
+  void RemoveItem(const nsAString& aKey,
+                  nsIPrincipal& aSubjectPrincipal,
+                  ErrorResult& aRv) override;
+
+  void Clear(nsIPrincipal& aSubjectPrincipal,
+             ErrorResult& aRv) override;
+
+  bool IsSessionOnly() const override { return true; }
+
+private:
+  ~SessionStorage();
+
+  bool CanUseStorage(nsIPrincipal& aSubjectPrincipal);
+
+  bool ProcessUsageDelta(int64_t aDelta);
+
+  void
+  BroadcastChangeNotification(const nsAString& aKey,
+                              const nsAString& aOldValue,
+                              const nsAString& aNewValue);
+
+  RefPtr<SessionStorageCache> mCache;
+};
+
+class SessionStorageCache final
+{
+public:
+  NS_INLINE_DECL_REFCOUNTING(SessionStorageCache)
+
+  SessionStorageCache();
+
+  int64_t GetOriginQuotaUsage() const
+  {
+    return mOriginQuotaUsage;
+  }
+
+  uint32_t Length() const { return mKeys.Count(); }
+
+  void Key(uint32_t aIndex, nsAString& aResult);
+
+  void GetItem(const nsAString& aKey, nsAString& aResult);
+
+  void GetKeys(nsTArray<nsString>& aKeys);
+
+  nsresult SetItem(const nsAString& aKey, const nsAString& aValue,
+                   nsString& aOldValue);
+
+  nsresult RemoveItem(const nsAString& aKey,
+                      nsString& aOldValue);
+
+  void Clear();
+
+private:
+  ~SessionStorageCache() = default;
+
+  bool ProcessUsageDelta(int64_t aDelta);
+
+  int64_t mOriginQuotaUsage;
+  nsDataHashtable<nsStringHashKey, nsString> mKeys;
+};
+
+} // dom namespace
+} // mozilla namespace
+
+#endif //mozilla_dom_SessionStorage_h
--- a/dom/storage/Storage.cpp
+++ b/dom/storage/Storage.cpp
@@ -28,105 +28,128 @@
 #include "nsServiceManagerUtils.h"
 
 namespace mozilla {
 
 using namespace ipc;
 
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Storage, mManager, mPrincipal, mWindow)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Storage, mWindow, mPrincipal)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Storage)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Storage)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Storage)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMStorage)
   NS_INTERFACE_MAP_ENTRY(nsIDOMStorage)
-  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END
 
-Storage::Storage(nsPIDOMWindowInner* aWindow,
-                 StorageManagerBase* aManager,
-                 StorageCache* aCache,
-                 const nsAString& aDocumentURI,
-                 nsIPrincipal* aPrincipal,
-                 bool aIsPrivate)
+Storage::Storage(nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal)
   : mWindow(aWindow)
-  , mManager(aManager)
-  , mCache(aCache)
-  , mDocumentURI(aDocumentURI)
   , mPrincipal(aPrincipal)
-  , mIsPrivate(aIsPrivate)
-  , mIsSessionOnly(false)
 {
-  mCache->Preload();
+  MOZ_ASSERT(aPrincipal);
 }
 
 Storage::~Storage()
+{}
+
+bool
+Storage::CanAccess(nsIPrincipal* aPrincipal)
 {
+  return !aPrincipal || aPrincipal->Subsumes(mPrincipal);
 }
 
 /* virtual */ JSObject*
 Storage::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return StorageBinding::Wrap(aCx, this, aGivenProto);
 }
 
+NS_IMPL_CYCLE_COLLECTION_INHERITED(LocalStorage, Storage, mManager);
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(LocalStorage)
+  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
+NS_INTERFACE_MAP_END_INHERITING(Storage)
+
+NS_IMPL_ADDREF_INHERITED(LocalStorage, Storage)
+NS_IMPL_RELEASE_INHERITED(LocalStorage, Storage)
+
+LocalStorage::LocalStorage(nsPIDOMWindowInner* aWindow,
+                           StorageManagerBase* aManager,
+                           StorageCache* aCache,
+                           const nsAString& aDocumentURI,
+                           nsIPrincipal* aPrincipal,
+                           bool aIsPrivate)
+  : Storage(aWindow, aPrincipal)
+  , mManager(aManager)
+  , mCache(aCache)
+  , mDocumentURI(aDocumentURI)
+  , mIsPrivate(aIsPrivate)
+  , mIsSessionOnly(false)
+{
+  mCache->Preload();
+}
+
+LocalStorage::~LocalStorage()
+{
+}
+
 int64_t
-Storage::GetOriginQuotaUsage() const
+LocalStorage::GetOriginQuotaUsage() const
 {
   return mCache->GetOriginQuotaUsage(this);
 }
 
 uint32_t
-Storage::GetLength(nsIPrincipal& aSubjectPrincipal,
-                   ErrorResult& aRv)
+LocalStorage::GetLength(nsIPrincipal& aSubjectPrincipal,
+                        ErrorResult& aRv)
 {
   if (!CanUseStorage(aSubjectPrincipal)) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return 0;
   }
 
   uint32_t length;
   aRv = mCache->GetLength(this, &length);
   return length;
 }
 
 void
-Storage::Key(uint32_t aIndex, nsAString& aResult,
-             nsIPrincipal& aSubjectPrincipal,
-             ErrorResult& aRv)
+LocalStorage::Key(uint32_t aIndex, nsAString& aResult,
+                  nsIPrincipal& aSubjectPrincipal,
+                  ErrorResult& aRv)
 {
   if (!CanUseStorage(aSubjectPrincipal)) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return;
   }
 
   aRv = mCache->GetKey(this, aIndex, aResult);
 }
 
 void
-Storage::GetItem(const nsAString& aKey, nsAString& aResult,
-                 nsIPrincipal& aSubjectPrincipal,
-                 ErrorResult& aRv)
+LocalStorage::GetItem(const nsAString& aKey, nsAString& aResult,
+                      nsIPrincipal& aSubjectPrincipal,
+                      ErrorResult& aRv)
 {
   if (!CanUseStorage(aSubjectPrincipal)) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return;
   }
 
   aRv = mCache->GetItem(this, aKey, aResult);
 }
 
 void
-Storage::SetItem(const nsAString& aKey, const nsAString& aData,
-                 nsIPrincipal& aSubjectPrincipal,
-                 ErrorResult& aRv)
+LocalStorage::SetItem(const nsAString& aKey, const nsAString& aData,
+                      nsIPrincipal& aSubjectPrincipal,
+                      ErrorResult& aRv)
 {
   if (!CanUseStorage(aSubjectPrincipal)) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return;
   }
 
   nsString data;
   bool ok = data.Assign(aData, fallible);
@@ -142,18 +165,18 @@ Storage::SetItem(const nsAString& aKey, 
   }
 
   if (!aRv.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION)) {
     BroadcastChangeNotification(aKey, old, aData);
   }
 }
 
 void
-Storage::RemoveItem(const nsAString& aKey, nsIPrincipal& aSubjectPrincipal,
-                    ErrorResult& aRv)
+LocalStorage::RemoveItem(const nsAString& aKey, nsIPrincipal& aSubjectPrincipal,
+                         ErrorResult& aRv)
 {
   if (!CanUseStorage(aSubjectPrincipal)) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return;
   }
 
   nsAutoString old;
   aRv = mCache->RemoveItem(this, aKey, old);
@@ -162,17 +185,17 @@ Storage::RemoveItem(const nsAString& aKe
   }
 
   if (!aRv.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION)) {
     BroadcastChangeNotification(aKey, old, NullString());
   }
 }
 
 void
-Storage::Clear(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv)
+LocalStorage::Clear(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv)
 {
   if (!CanUseStorage(aSubjectPrincipal)) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return;
   }
 
   aRv = mCache->Clear(this);
   if (NS_WARN_IF(aRv.Failed())) {
@@ -218,43 +241,43 @@ StorageNotifierRunnable::Run()
                                      mType);
   }
   return NS_OK;
 }
 
 } // namespace
 
 void
-Storage::BroadcastChangeNotification(const nsSubstring& aKey,
-                                     const nsSubstring& aOldValue,
-                                     const nsSubstring& aNewValue)
+LocalStorage::BroadcastChangeNotification(const nsSubstring& aKey,
+                                          const nsSubstring& aOldValue,
+                                          const nsSubstring& aNewValue)
 {
-  if (!XRE_IsParentProcess() && GetType() == LocalStorage && mPrincipal) {
+  if (!XRE_IsParentProcess() && GetType() == eLocalStorage && Principal()) {
     // If we are in a child process, we want to send a message to the parent in
     // order to broadcast the StorageEvent correctly to any child process.
     dom::ContentChild* cc = dom::ContentChild::GetSingleton();
     Unused << NS_WARN_IF(!cc->SendBroadcastLocalStorageChange(
       mDocumentURI, nsString(aKey), nsString(aOldValue), nsString(aNewValue),
-      IPC::Principal(mPrincipal), mIsPrivate));
+      IPC::Principal(Principal()), mIsPrivate));
   }
 
   DispatchStorageEvent(GetType(), mDocumentURI, aKey, aOldValue, aNewValue,
-                       mPrincipal, mIsPrivate, this, false);
+                       Principal(), mIsPrivate, this, false);
 }
 
 /* static */ void
-Storage::DispatchStorageEvent(StorageType aStorageType,
-                              const nsAString& aDocumentURI,
-                              const nsAString& aKey,
-                              const nsAString& aOldValue,
-                              const nsAString& aNewValue,
-                              nsIPrincipal* aPrincipal,
-                              bool aIsPrivate,
-                              Storage* aStorage,
-                              bool aImmediateDispatch)
+LocalStorage::DispatchStorageEvent(StorageType aStorageType,
+                                   const nsAString& aDocumentURI,
+                                   const nsAString& aKey,
+                                   const nsAString& aOldValue,
+                                   const nsAString& aNewValue,
+                                   nsIPrincipal* aPrincipal,
+                                   bool aIsPrivate,
+                                   Storage* aStorage,
+                                   bool aImmediateDispatch)
 {
   StorageEventInit dict;
   dict.mBubbles = false;
   dict.mCancelable = false;
   dict.mKey = aKey;
   dict.mNewValue = aNewValue;
   dict.mOldValue = aOldValue;
   dict.mStorageArea = aStorage;
@@ -264,40 +287,40 @@ Storage::DispatchStorageEvent(StorageTyp
   // nsGlobalWindow.
   RefPtr<StorageEvent> event =
     StorageEvent::Constructor(nullptr, NS_LITERAL_STRING("storage"), dict);
 
   event->SetPrincipal(aPrincipal);
 
   RefPtr<StorageNotifierRunnable> r =
     new StorageNotifierRunnable(event,
-                                aStorageType == LocalStorage
+                                aStorageType == eLocalStorage
                                   ? u"localStorage"
                                   : u"sessionStorage",
                                 aIsPrivate);
 
   if (aImmediateDispatch) {
     Unused << r->Run();
   } else {
     NS_DispatchToMainThread(r);
   }
 
   // If we are in the parent process and we have the principal, we want to
   // broadcast this event to every other process.
-  if (aStorageType == LocalStorage && XRE_IsParentProcess() && aPrincipal) {
+  if (aStorageType == eLocalStorage && XRE_IsParentProcess() && aPrincipal) {
     for (auto* cp : ContentParent::AllProcesses(ContentParent::eLive)) {
       Unused << cp->SendDispatchLocalStorageChange(
         nsString(aDocumentURI), nsString(aKey), nsString(aOldValue),
         nsString(aNewValue), IPC::Principal(aPrincipal), aIsPrivate);
     }
   }
 }
 
 void
-Storage::ApplyEvent(StorageEvent* aStorageEvent)
+LocalStorage::ApplyEvent(StorageEvent* aStorageEvent)
 {
   MOZ_ASSERT(aStorageEvent);
 
   nsAutoString key;
   nsAutoString old;
   nsAutoString value;
 
   aStorageEvent->GetKey(key);
@@ -319,68 +342,56 @@ Storage::ApplyEvent(StorageEvent* aStora
   // Otherwise, we set the new value.
   mCache->SetItem(this, key, value, old, StorageCache::E10sPropagated);
 }
 
 static const char kPermissionType[] = "cookie";
 static const char kStorageEnabled[] = "dom.storage.enabled";
 
 bool
-Storage::CanUseStorage(nsIPrincipal& aSubjectPrincipal)
+LocalStorage::CanUseStorage(nsIPrincipal& aSubjectPrincipal)
 {
   // This method is responsible for correct setting of mIsSessionOnly.
   // It doesn't work with mIsPrivate flag at all, since it is checked
   // regardless mIsSessionOnly flag in DOMStorageCache code.
 
   if (!mozilla::Preferences::GetBool(kStorageEnabled)) {
     return false;
   }
 
   nsContentUtils::StorageAccess access =
-    nsContentUtils::StorageAllowedForPrincipal(mPrincipal);
+    nsContentUtils::StorageAllowedForPrincipal(Principal());
 
   if (access == nsContentUtils::StorageAccess::eDeny) {
     return false;
   }
 
   mIsSessionOnly = access <= nsContentUtils::StorageAccess::eSessionScoped;
   return CanAccess(&aSubjectPrincipal);
 }
 
-Storage::StorageType
-Storage::GetType() const
+LocalStorage::StorageType
+LocalStorage::GetType() const
 {
   return mManager->Type();
 }
 
-nsIPrincipal*
-Storage::GetPrincipal()
-{
-  return mPrincipal;
-}
-
 // Defined in StorageManager.cpp
 extern bool
 PrincipalsEqual(nsIPrincipal* aObjectPrincipal,
                 nsIPrincipal* aSubjectPrincipal);
 
 bool
-Storage::PrincipalEquals(nsIPrincipal* aPrincipal)
+LocalStorage::PrincipalEquals(nsIPrincipal* aPrincipal)
 {
   return PrincipalsEqual(mPrincipal, aPrincipal);
 }
 
-bool
-Storage::CanAccess(nsIPrincipal* aPrincipal)
-{
-  return !aPrincipal || aPrincipal->Subsumes(mPrincipal);
-}
-
 void
-Storage::GetSupportedNames(nsTArray<nsString>& aKeys)
+LocalStorage::GetSupportedNames(nsTArray<nsString>& aKeys)
 {
   if (!CanUseStorage(*nsContentUtils::SubjectPrincipal())) {
     // return just an empty array
     aKeys.Clear();
     return;
   }
 
   mCache->GetKeys(this, aKeys);
--- a/dom/storage/Storage.h
+++ b/dom/storage/Storage.h
@@ -21,117 +21,169 @@ class nsPIDOMWindowInner;
 
 namespace mozilla {
 namespace dom {
 
 class StorageManagerBase;
 class StorageCache;
 class StorageEvent;
 
-class Storage final
-  : public nsIDOMStorage
-  , public nsSupportsWeakReference
-  , public nsWrapperCache
+class Storage : public nsIDOMStorage
+              , public nsWrapperCache
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(Storage,
                                                          nsIDOMStorage)
 
+  Storage(nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal);
+
+  virtual int64_t GetOriginQuotaUsage() const = 0;
+
+  virtual bool CanAccess(nsIPrincipal* aPrincipal);
+
+  // WebIDL
+  JSObject* WrapObject(JSContext* aCx,
+                       JS::Handle<JSObject*> aGivenProto) override;
+
+  nsPIDOMWindowInner* GetParentObject() const
+  {
+    return mWindow;
+  }
+
+  virtual uint32_t
+  GetLength(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) = 0;
+
+  virtual void
+  Key(uint32_t aIndex, nsAString& aResult,
+      nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) = 0;
+
+  virtual void
+  GetItem(const nsAString& aKey, nsAString& aResult,
+          nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) = 0;
+
+  virtual void
+  GetSupportedNames(nsTArray<nsString>& aKeys) = 0;
+
+  void NamedGetter(const nsAString& aKey, bool& aFound, nsAString& aResult,
+                   nsIPrincipal& aSubjectPrincipal,
+                   ErrorResult& aRv)
+  {
+    GetItem(aKey, aResult, aSubjectPrincipal, aRv);
+    aFound = !aResult.IsVoid();
+  }
+
+  virtual void
+  SetItem(const nsAString& aKey, const nsAString& aValue,
+          nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) = 0;
+
+  void NamedSetter(const nsAString& aKey, const nsAString& aValue,
+                   nsIPrincipal& aSubjectPrincipal,
+                   ErrorResult& aRv)
+  {
+    SetItem(aKey, aValue, aSubjectPrincipal, aRv);
+  }
+
+  virtual void
+  RemoveItem(const nsAString& aKey, nsIPrincipal& aSubjectPrincipal,
+             ErrorResult& aRv) = 0;
+
+  void NamedDeleter(const nsAString& aKey, bool& aFound,
+                    nsIPrincipal& aSubjectPrincipal,
+                    ErrorResult& aRv)
+  {
+    RemoveItem(aKey, aSubjectPrincipal, aRv);
+
+    aFound = !aRv.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION);
+  }
+
+  virtual void
+  Clear(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) = 0;
+
+  virtual bool IsSessionOnly() const = 0;
+
+protected:
+  virtual ~Storage();
+
+  nsIPrincipal*
+  Principal() const
+  {
+    return mPrincipal;
+  }
+
+private:
+  nsCOMPtr<nsPIDOMWindowInner> mWindow;
+  nsCOMPtr<nsIPrincipal> mPrincipal;
+};
+
+class LocalStorage final : public Storage
+                         , public nsSupportsWeakReference
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(LocalStorage, Storage)
+
   enum StorageType {
-    LocalStorage = 1,
-    SessionStorage = 2
+    eLocalStorage = 1,
+    eSessionStorage = 2
   };
 
   StorageType GetType() const;
 
   StorageManagerBase* GetManager() const
   {
     return mManager;
   }
 
   StorageCache const* GetCache() const
   {
     return mCache;
   }
 
-  nsIPrincipal* GetPrincipal();
   bool PrincipalEquals(nsIPrincipal* aPrincipal);
-  bool CanAccess(nsIPrincipal* aPrincipal);
 
-  Storage(nsPIDOMWindowInner* aWindow,
-          StorageManagerBase* aManager,
-          StorageCache* aCache,
-          const nsAString& aDocumentURI,
-          nsIPrincipal* aPrincipal,
-          bool aIsPrivate);
+  LocalStorage(nsPIDOMWindowInner* aWindow,
+               StorageManagerBase* aManager,
+               StorageCache* aCache,
+               const nsAString& aDocumentURI,
+               nsIPrincipal* aPrincipal,
+               bool aIsPrivate);
 
   // WebIDL
-  JSObject* WrapObject(JSContext* aCx,
-                       JS::Handle<JSObject*> aGivenProto) override;
 
-  nsPIDOMWindowInner* GetParentObject() const
-  {
-    return mWindow;
-  }
-
-  int64_t GetOriginQuotaUsage() const;
+  int64_t GetOriginQuotaUsage() const override;
 
   uint32_t GetLength(nsIPrincipal& aSubjectPrincipal,
-                     ErrorResult& aRv);
+                     ErrorResult& aRv) override;
 
   void Key(uint32_t aIndex, nsAString& aResult,
            nsIPrincipal& aSubjectPrincipal,
-           ErrorResult& aRv);
+           ErrorResult& aRv) override;
 
   void GetItem(const nsAString& aKey, nsAString& aResult,
                nsIPrincipal& aSubjectPrincipal,
-               ErrorResult& aRv);
-
-  void GetSupportedNames(nsTArray<nsString>& aKeys);
+               ErrorResult& aRv) override;
 
-  void NamedGetter(const nsAString& aKey, bool& aFound, nsAString& aResult,
-                   nsIPrincipal& aSubjectPrincipal,
-                   ErrorResult& aRv)
-  {
-    GetItem(aKey, aResult, aSubjectPrincipal, aRv);
-    aFound = !aResult.IsVoid();
-  }
+  void GetSupportedNames(nsTArray<nsString>& aKeys) override;
 
   void SetItem(const nsAString& aKey, const nsAString& aValue,
                nsIPrincipal& aSubjectPrincipal,
-               ErrorResult& aRv);
-
-  void NamedSetter(const nsAString& aKey, const nsAString& aValue,
-                   nsIPrincipal& aSubjectPrincipal,
-                   ErrorResult& aRv)
-  {
-    SetItem(aKey, aValue, aSubjectPrincipal, aRv);
-  }
+               ErrorResult& aRv) override;
 
   void RemoveItem(const nsAString& aKey,
                   nsIPrincipal& aSubjectPrincipal,
-                  ErrorResult& aRv);
-
-  void NamedDeleter(const nsAString& aKey, bool& aFound,
-                    nsIPrincipal& aSubjectPrincipal,
-                    ErrorResult& aRv)
-  {
-    RemoveItem(aKey, aSubjectPrincipal, aRv);
-
-    aFound = !aRv.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION);
-  }
+                  ErrorResult& aRv) override;
 
   void Clear(nsIPrincipal& aSubjectPrincipal,
-             ErrorResult& aRv);
+             ErrorResult& aRv) override;
 
   bool IsPrivate() const { return mIsPrivate; }
-  bool IsSessionOnly() const { return mIsSessionOnly; }
+  bool IsSessionOnly() const override { return mIsSessionOnly; }
 
-  bool IsForkOf(const Storage* aOther) const
+  bool IsForkOf(const LocalStorage* aOther) const
   {
     MOZ_ASSERT(aOther);
     return mCache == aOther->mCache;
   }
 
   // aStorage can be null if this method is called by ContentChild.
   //
   // aImmediateDispatch is for use by (main-thread) IPC code so that PContent
@@ -160,17 +212,17 @@ protected:
   // on a storage is about to happen and ensures that the storage's
   // session-only flag is properly set according the current settings.
   // It is an optimization since the privileges check and session only
   // state determination are complex and share the code (comes hand in
   // hand together).
   bool CanUseStorage(nsIPrincipal& aSubjectPrincipal);
 
 private:
-  ~Storage();
+  ~LocalStorage();
 
   friend class StorageManagerBase;
   friend class StorageCache;
 
   nsCOMPtr<nsPIDOMWindowInner> mWindow;
   RefPtr<StorageManagerBase> mManager;
   RefPtr<StorageCache> mCache;
   nsString mDocumentURI;
--- a/dom/storage/StorageCache.cpp
+++ b/dom/storage/StorageCache.cpp
@@ -43,17 +43,17 @@ GetDataSetIndex(bool aPrivate, bool aSes
   if (aSessionOnly) {
     return kSessionSet;
   }
 
   return kDefaultSet;
 }
 
 inline uint32_t
-GetDataSetIndex(const Storage* aStorage)
+GetDataSetIndex(const LocalStorage* aStorage)
 {
   return GetDataSetIndex(aStorage->IsPrivate(), aStorage->IsSessionOnly());
 }
 
 } // namespace
 
 // StorageCacheBridge
 
@@ -151,31 +151,31 @@ StorageCache::Init(StorageManagerBase* a
   MOZ_ASSERT(StringBeginsWith(mQuotaOriginScope, mOriginSuffix));
   MOZ_ASSERT(mOriginSuffix.IsEmpty() != StringBeginsWith(mQuotaOriginScope,
                                                          NS_LITERAL_CSTRING("^")));
 
   mUsage = aManager->GetOriginUsage(mQuotaOriginScope);
 }
 
 inline bool
-StorageCache::Persist(const Storage* aStorage) const
+StorageCache::Persist(const LocalStorage* aStorage) const
 {
   return mPersistent &&
          !aStorage->IsSessionOnly() &&
          !aStorage->IsPrivate();
 }
 
 const nsCString
 StorageCache::Origin() const
 {
   return StorageManagerBase::CreateOrigin(mOriginSuffix, mOriginNoSuffix);
 }
 
 StorageCache::Data&
-StorageCache::DataSet(const Storage* aStorage)
+StorageCache::DataSet(const LocalStorage* aStorage)
 {
   uint32_t index = GetDataSetIndex(aStorage);
 
   if (index == kSessionSet && !mSessionOnlyDataSetActive) {
     // Session only data set is demanded but not filled with
     // current data set, copy to session only set now.
 
     WaitForPreload(Telemetry::LOCALDOMSTORAGE_SESSIONONLY_PRELOAD_BLOCKING_MS);
@@ -193,17 +193,17 @@ StorageCache::DataSet(const Storage* aSt
     // for all session only data
     ProcessUsageDelta(kSessionSet, defaultSet.mOriginQuotaUsage);
   }
 
   return mData[index];
 }
 
 bool
-StorageCache::ProcessUsageDelta(const Storage* aStorage, int64_t aDelta,
+StorageCache::ProcessUsageDelta(const LocalStorage* aStorage, int64_t aDelta,
                                 const MutationSource aSource)
 {
   return ProcessUsageDelta(GetDataSetIndex(aStorage), aDelta, aSource);
 }
 
 bool
 StorageCache::ProcessUsageDelta(uint32_t aGetDataSetIndex, const int64_t aDelta,
                                 const MutationSource aSource)
@@ -305,31 +305,31 @@ StorageCache::WaitForPreload(Telemetry::
 
   // No need to check sDatabase for being non-null since preload is either
   // done before we've shut the DB down or when the DB could not start,
   // preload has not even be started.
   sDatabase->SyncPreload(this);
 }
 
 nsresult
-StorageCache::GetLength(const Storage* aStorage, uint32_t* aRetval)
+StorageCache::GetLength(const LocalStorage* aStorage, uint32_t* aRetval)
 {
   if (Persist(aStorage)) {
     WaitForPreload(Telemetry::LOCALDOMSTORAGE_GETLENGTH_BLOCKING_MS);
     if (NS_FAILED(mLoadResult)) {
       return mLoadResult;
     }
   }
 
   *aRetval = DataSet(aStorage).mKeys.Count();
   return NS_OK;
 }
 
 nsresult
-StorageCache::GetKey(const Storage* aStorage, uint32_t aIndex,
+StorageCache::GetKey(const LocalStorage* aStorage, uint32_t aIndex,
                      nsAString& aRetval)
 {
   // XXX: This does a linear search for the key at index, which would
   // suck if there's a large numer of indexes. Do we care? If so,
   // maybe we need to have a lazily populated key array here or
   // something?
   if (Persist(aStorage)) {
     WaitForPreload(Telemetry::LOCALDOMSTORAGE_GETKEY_BLOCKING_MS);
@@ -346,33 +346,33 @@ StorageCache::GetKey(const Storage* aSto
     }
     aIndex--;
   }
 
   return NS_OK;
 }
 
 void
-StorageCache::GetKeys(const Storage* aStorage, nsTArray<nsString>& aKeys)
+StorageCache::GetKeys(const LocalStorage* aStorage, nsTArray<nsString>& aKeys)
 {
   if (Persist(aStorage)) {
     WaitForPreload(Telemetry::LOCALDOMSTORAGE_GETALLKEYS_BLOCKING_MS);
   }
 
   if (NS_FAILED(mLoadResult)) {
     return;
   }
 
   for (auto iter = DataSet(aStorage).mKeys.Iter(); !iter.Done(); iter.Next()) {
     aKeys.AppendElement(iter.Key());
   }
 }
 
 nsresult
-StorageCache::GetItem(const Storage* aStorage, const nsAString& aKey,
+StorageCache::GetItem(const LocalStorage* aStorage, const nsAString& aKey,
                       nsAString& aRetval)
 {
   if (Persist(aStorage)) {
     WaitForPreload(Telemetry::LOCALDOMSTORAGE_GETVALUE_BLOCKING_MS);
     if (NS_FAILED(mLoadResult)) {
       return mLoadResult;
     }
   }
@@ -384,17 +384,17 @@ StorageCache::GetItem(const Storage* aSt
   }
 
   aRetval = value;
 
   return NS_OK;
 }
 
 nsresult
-StorageCache::SetItem(const Storage* aStorage, const nsAString& aKey,
+StorageCache::SetItem(const LocalStorage* aStorage, const nsAString& aKey,
                       const nsString& aValue, nsString& aOld,
                       const MutationSource aSource)
 {
   // Size of the cache that will change after this action.
   int64_t delta = 0;
 
   if (Persist(aStorage)) {
     WaitForPreload(Telemetry::LOCALDOMSTORAGE_SETVALUE_BLOCKING_MS);
@@ -437,17 +437,17 @@ StorageCache::SetItem(const Storage* aSt
 
     return sDatabase->AsyncUpdateItem(this, aKey, aValue);
   }
 
   return NS_OK;
 }
 
 nsresult
-StorageCache::RemoveItem(const Storage* aStorage, const nsAString& aKey,
+StorageCache::RemoveItem(const LocalStorage* aStorage, const nsAString& aKey,
                          nsString& aOld, const MutationSource aSource)
 {
   if (Persist(aStorage)) {
     WaitForPreload(Telemetry::LOCALDOMSTORAGE_REMOVEKEY_BLOCKING_MS);
     if (NS_FAILED(mLoadResult)) {
       return mLoadResult;
     }
   }
@@ -473,17 +473,17 @@ StorageCache::RemoveItem(const Storage* 
 
     return sDatabase->AsyncRemoveItem(this, aKey);
   }
 
   return NS_OK;
 }
 
 nsresult
-StorageCache::Clear(const Storage* aStorage, const MutationSource aSource)
+StorageCache::Clear(const LocalStorage* aStorage, const MutationSource aSource)
 {
   bool refresh = false;
   if (Persist(aStorage)) {
     // We need to preload all data (know the size) before we can proceeed
     // to correctly decrease cached usage number.
     // XXX as in case of unload, this is not technically needed now, but
     // after super-scope quota introduction we have to do this.  Get telemetry
     // right now.
@@ -536,17 +536,17 @@ StorageCache::CloneFrom(const StorageCac
     for (auto it = aThat->mData[i].mKeys.ConstIter(); !it.Done(); it.Next()) {
       mData[i].mKeys.Put(it.Key(), it.UserData());
     }
     ProcessUsageDelta(i, aThat->mData[i].mOriginQuotaUsage);
   }
 }
 
 int64_t
-StorageCache::GetOriginQuotaUsage(const Storage* aStorage) const
+StorageCache::GetOriginQuotaUsage(const LocalStorage* aStorage) const
 {
   return mData[GetDataSetIndex(aStorage)].mOriginQuotaUsage;
 }
 
 // Defined in StorageManager.cpp
 extern bool
 PrincipalsEqual(nsIPrincipal* aObjectPrincipal,
                 nsIPrincipal* aSubjectPrincipal);
--- a/dom/storage/StorageCache.h
+++ b/dom/storage/StorageCache.h
@@ -15,17 +15,17 @@
 #include "nsHashKeys.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/Atomics.h"
 
 namespace mozilla {
 namespace dom {
 
-class Storage;
+class LocalStorage;
 class StorageUsage;
 class StorageManagerBase;
 class StorageDBBridge;
 
 // Interface class on which only the database or IPC may call.
 // Used to populate the cache with DB data.
 class StorageCacheBridge
 {
@@ -79,17 +79,17 @@ public:
   NS_IMETHOD_(void) Release(void);
 
   enum MutationSource {
     // The mutation is a result of an explicit JS mutation in this process.
     // The mutation should be sent to the sDatabase. Quota will be checked and
     // QuotaExceededError may be returned without the mutation being applied.
     ContentMutation,
     // The mutation initially was triggered in a different process and is being
-    // propagated to this cache via Storage::ApplyEvent.  The mutation should
+    // propagated to this cache via LocalStorage::ApplyEvent.  The mutation should
     // not be sent to the sDatabase because the originating process is already
     // doing that.  (In addition to the redundant writes being wasteful, there
     // is the potential for other processes to see inconsistent state from the
     // database while preloading.)  Quota will be updated but not checked
     // because it's assumed it was checked in another process and data-coherency
     // is more important than slightly exceeding quota.
     E10sPropagated
   };
@@ -105,39 +105,39 @@ protected:
 public:
   void Init(StorageManagerBase* aManager, bool aPersistent,
             nsIPrincipal* aPrincipal, const nsACString& aQuotaOriginScope);
 
   // Copies all data from the other storage.
   void CloneFrom(const StorageCache* aThat);
 
   // Get size of per-origin data.
-  int64_t GetOriginQuotaUsage(const Storage* aStorage) const;
+  int64_t GetOriginQuotaUsage(const LocalStorage* aStorage) const;
 
   // Starts async preload of this cache if it persistent and not loaded.
   void Preload();
 
   // The set of methods that are invoked by DOM storage web API.
-  // We are passing the Storage object just to let the cache
+  // We are passing the LocalStorage object just to let the cache
   // read properties like mPrivate, mPrincipal and mSessionOnly.
   // Get* methods return error when load from the database has failed.
-  nsresult GetLength(const Storage* aStorage, uint32_t* aRetval);
-  nsresult GetKey(const Storage* aStorage, uint32_t index, nsAString& aRetval);
-  nsresult GetItem(const Storage* aStorage, const nsAString& aKey,
+  nsresult GetLength(const LocalStorage* aStorage, uint32_t* aRetval);
+  nsresult GetKey(const LocalStorage* aStorage, uint32_t index, nsAString& aRetval);
+  nsresult GetItem(const LocalStorage* aStorage, const nsAString& aKey,
                    nsAString& aRetval);
-  nsresult SetItem(const Storage* aStorage, const nsAString& aKey,
+  nsresult SetItem(const LocalStorage* aStorage, const nsAString& aKey,
                    const nsString& aValue, nsString& aOld,
                    const MutationSource aSource=ContentMutation);
-  nsresult RemoveItem(const Storage* aStorage, const nsAString& aKey,
+  nsresult RemoveItem(const LocalStorage* aStorage, const nsAString& aKey,
                       nsString& aOld,
                       const MutationSource aSource=ContentMutation);
-  nsresult Clear(const Storage* aStorage,
+  nsresult Clear(const LocalStorage* aStorage,
                  const MutationSource aSource=ContentMutation);
 
-  void GetKeys(const Storage* aStorage, nsTArray<nsString>& aKeys);
+  void GetKeys(const LocalStorage* aStorage, nsTArray<nsString>& aKeys);
 
   // Whether the principal equals principal the cache was created for
   bool CheckPrincipal(nsIPrincipal* aPrincipal) const;
   nsIPrincipal* Principal() const { return mPrincipal; }
 
   // Starts the database engine thread or the IPC bridge
   static StorageDBBridge* StartDatabase();
   static StorageDBBridge* GetDatabase();
@@ -188,34 +188,34 @@ private:
 
   void UnloadItems(uint32_t aUnloadFlags);
 
 private:
   // Synchronously blocks until the cache is fully loaded from the database
   void WaitForPreload(mozilla::Telemetry::HistogramID aTelemetryID);
 
   // Helper to get one of the 3 data sets (regular, private, session)
-  Data& DataSet(const Storage* aStorage);
+  Data& DataSet(const LocalStorage* aStorage);
 
   // Whether the storage change is about to persist
-  bool Persist(const Storage* aStorage) const;
+  bool Persist(const LocalStorage* aStorage) const;
 
   // Changes the quota usage on the given data set if it fits the quota.
   // If not, then false is returned and no change to the set must be done.
   // A special case is if aSource==E10sPropagated, then we will return true even
   // if the change would put us over quota.  This is done to ensure coherency of
   // caches between processes in the face of races.  It does allow an attacker
   // to potentially use N multiples of the quota storage limit if they can
   // arrange for their origin to execute code in N processes.  However, this is
   // not considered a particularly concerning threat model because it's already
   // very possible for a rogue page to attempt to intentionally fill up the
   // user's storage through the use of multiple domains.
   bool ProcessUsageDelta(uint32_t aGetDataSetIndex, const int64_t aDelta,
                          const MutationSource aSource=ContentMutation);
-  bool ProcessUsageDelta(const Storage* aStorage, const int64_t aDelta,
+  bool ProcessUsageDelta(const LocalStorage* aStorage, const int64_t aDelta,
                          const MutationSource aSource=ContentMutation);
 
 private:
   // When a cache is reponsible for its life time (in case of localStorage data
   // cache) we need to refer our manager since removal of the cache from the
   // hash table is handled in the destructor by call to the manager.  Cache
   // could potentially overlive the manager, hence the hard ref.
   RefPtr<StorageManagerBase> mManager;
--- a/dom/storage/StorageManager.cpp
+++ b/dom/storage/StorageManager.cpp
@@ -96,17 +96,17 @@ PrincipalsEqual(nsIPrincipal* aObjectPri
   }
 
   return aSubjectPrincipal->Equals(aObjectPrincipal);
 }
 
 NS_IMPL_ISUPPORTS(StorageManagerBase,
                   nsIDOMStorageManager)
 
-StorageManagerBase::StorageManagerBase(Storage::StorageType aType)
+StorageManagerBase::StorageManagerBase(LocalStorage::StorageType aType)
   : mCaches(8)
   , mType(aType)
   , mLowDiskSpace(false)
 {
   StorageObserver* observer = StorageObserver::Self();
   NS_ASSERTION(observer, "No StorageObserver, cannot observe private data delete notifications!");
 
   if (observer) {
@@ -249,17 +249,17 @@ StorageManagerBase::GetOriginUsage(const
 {
   RefPtr<StorageUsage> usage;
   if (mUsages.Get(aOriginNoSuffix, &usage)) {
     return usage.forget();
   }
 
   usage = new StorageUsage(aOriginNoSuffix);
 
-  if (mType == LocalStorage) {
+  if (mType == eLocalStorage) {
     StorageDBBridge* db = StorageCache::StartDatabase();
     if (db) {
       db->AsyncGetUsage(usage);
     }
   }
 
   mUsages.Put(aOriginNoSuffix, usage);
 
@@ -274,23 +274,23 @@ StorageManagerBase::PutCache(const nsACS
   CacheOriginHashtable* table = mCaches.LookupOrAdd(aOriginSuffix);
   StorageCacheHashKey* entry = table->PutEntry(aOriginNoSuffix);
   RefPtr<StorageCache> cache = entry->cache();
 
   nsAutoCString quotaOrigin;
   CreateQuotaDBKey(aPrincipal, quotaOrigin);
 
   switch (mType) {
-  case SessionStorage:
+  case eSessionStorage:
     // Lifetime handled by the manager, don't persist
     entry->HardRef();
     cache->Init(this, false, aPrincipal, quotaOrigin);
     break;
 
-  case LocalStorage:
+  case eLocalStorage:
     // Lifetime handled by the cache, do persist
     cache->Init(this, true, aPrincipal, quotaOrigin);
     break;
 
   default:
     MOZ_ASSERT(false);
   }
 
@@ -349,26 +349,26 @@ StorageManagerBase::GetStorageInternal(C
           return NS_OK;
         }
       }
     }
 
     // There is always a single instance of a cache per scope
     // in a single instance of a DOM storage manager.
     cache = PutCache(originAttrSuffix, originKey, aPrincipal);
-  } else if (mType == SessionStorage) {
+  } else if (mType == eSessionStorage) {
     if (!cache->CheckPrincipal(aPrincipal)) {
       return NS_ERROR_DOM_SECURITY_ERR;
     }
   }
 
   if (aRetval) {
     nsCOMPtr<nsPIDOMWindowInner> inner = nsPIDOMWindowInner::From(aWindow);
 
-    nsCOMPtr<nsIDOMStorage> storage = new Storage(
+    nsCOMPtr<nsIDOMStorage> storage = new LocalStorage(
       inner, this, cache, aDocumentURI, aPrincipal, aPrivate);
     storage.forget(aRetval);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -398,22 +398,22 @@ StorageManagerBase::GetStorage(mozIDOMWi
 {
   return GetStorageInternal(CreateMode::UseIfExistsNeverCreate, aWindow,
                             aPrincipal, EmptyString(), aPrivate, aRetval);
 }
 
 NS_IMETHODIMP
 StorageManagerBase::CloneStorage(nsIDOMStorage* aStorage)
 {
-  if (mType != SessionStorage) {
+  if (mType != eSessionStorage) {
     // Cloning is supported only for sessionStorage
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
-  RefPtr<Storage> storage = static_cast<Storage*>(aStorage);
+  RefPtr<LocalStorage> storage = static_cast<LocalStorage*>(aStorage);
   if (!storage) {
     return NS_ERROR_UNEXPECTED;
   }
 
   const StorageCache* origCache = storage->GetCache();
 
   StorageCache* existingCache = GetCache(origCache->OriginSuffix(),
                                          origCache->OriginNoSuffix());
@@ -434,17 +434,17 @@ StorageManagerBase::CloneStorage(nsIDOMS
 
 NS_IMETHODIMP
 StorageManagerBase::CheckStorage(nsIPrincipal* aPrincipal,
                                  nsIDOMStorage* aStorage,
                                  bool* aRetval)
 {
   nsresult rv;
 
-  RefPtr<Storage> storage = static_cast<Storage*>(aStorage);
+  RefPtr<LocalStorage> storage = static_cast<LocalStorage*>(aStorage);
   if (!storage) {
     return NS_ERROR_UNEXPECTED;
   }
 
   *aRetval = false;
 
   if (!aPrincipal) {
     return NS_ERROR_NOT_AVAILABLE;
@@ -475,17 +475,17 @@ StorageManagerBase::CheckStorage(nsIPrin
 // Obsolete nsIDOMStorageManager methods
 
 NS_IMETHODIMP
 StorageManagerBase::GetLocalStorageForPrincipal(nsIPrincipal* aPrincipal,
                                                 const nsAString& aDocumentURI,
                                                 bool aPrivate,
                                                 nsIDOMStorage** aRetval)
 {
-  if (mType != LocalStorage) {
+  if (mType != eLocalStorage) {
     return NS_ERROR_UNEXPECTED;
   }
 
   return CreateStorage(nullptr, aPrincipal, aDocumentURI, aPrivate, aRetval);
 }
 
 void
 StorageManagerBase::ClearCaches(uint32_t aUnloadFlags,
@@ -549,50 +549,50 @@ StorageManagerBase::Observe(const char* 
   if (!strcmp(aTopic, "private-browsing-data-cleared")) {
     ClearCaches(StorageCache::kUnloadPrivate, pattern, EmptyCString());
     return NS_OK;
   }
 
   // Clear localStorage data beloging to an origin pattern
   if (!strcmp(aTopic, "origin-attr-pattern-cleared")) {
     // sessionStorage is expected to stay
-    if (mType == SessionStorage) {
+    if (mType == eSessionStorage) {
       return NS_OK;
     }
 
     ClearCaches(StorageCache::kUnloadComplete, pattern, EmptyCString());
     return NS_OK;
   }
 
   if (!strcmp(aTopic, "profile-change")) {
     // For case caches are still referenced - clear them completely
     ClearCaches(StorageCache::kUnloadComplete, pattern, EmptyCString());
     mCaches.Clear();
     return NS_OK;
   }
 
   if (!strcmp(aTopic, "low-disk-space")) {
-    if (mType == LocalStorage) {
+    if (mType == eLocalStorage) {
       mLowDiskSpace = true;
     }
 
     return NS_OK;
   }
 
   if (!strcmp(aTopic, "no-low-disk-space")) {
-    if (mType == LocalStorage) {
+    if (mType == eLocalStorage) {
       mLowDiskSpace = false;
     }
 
     return NS_OK;
   }
 
 #ifdef DOM_STORAGE_TESTS
   if (!strcmp(aTopic, "test-reload")) {
-    if (mType != LocalStorage) {
+    if (mType != eLocalStorage) {
       return NS_OK;
     }
 
     // This immediately completely reloads all caches from the database.
     ClearCaches(StorageCache::kTestReload, pattern, EmptyCString());
     return NS_OK;
   }
 
@@ -610,17 +610,17 @@ StorageManagerBase::Observe(const char* 
 
   NS_ERROR("Unexpected topic");
   return NS_ERROR_UNEXPECTED;
 }
 
 // DOMLocalStorageManager
 
 DOMLocalStorageManager::DOMLocalStorageManager()
-  : StorageManagerBase(LocalStorage)
+  : StorageManagerBase(eLocalStorage)
 {
   NS_ASSERTION(!sSelf, "Somebody is trying to do_CreateInstance(\"@mozilla/dom/localStorage-manager;1\"");
   sSelf = this;
 
   if (!XRE_IsParentProcess()) {
     // Do this only on the child process.  The thread IPC bridge
     // is also used to communicate chrome observer notifications.
     // Note: must be called after we set sSelf
@@ -646,17 +646,17 @@ DOMLocalStorageManager::Ensure()
   MOZ_ASSERT(sSelf, "Didn't initialize?");
 
   return sSelf;
 }
 
 // DOMSessionStorageManager
 
 DOMSessionStorageManager::DOMSessionStorageManager()
-  : StorageManagerBase(SessionStorage)
+  : StorageManagerBase(eSessionStorage)
 {
   if (!XRE_IsParentProcess()) {
     // Do this only on the child process.  The thread IPC bridge
     // is also used to communicate chrome observer notifications.
     StorageCache::StartDatabase();
   }
 }
 
--- a/dom/storage/StorageManager.h
+++ b/dom/storage/StorageManager.h
@@ -19,41 +19,41 @@
 #include "nsHashKeys.h"
 
 namespace mozilla {
 
 class OriginAttributesPattern;
 
 namespace dom {
 
-const Storage::StorageType SessionStorage = Storage::SessionStorage;
-const Storage::StorageType LocalStorage = Storage::LocalStorage;
+const LocalStorage::StorageType eSessionStorage = LocalStorage::eSessionStorage;
+const LocalStorage::StorageType eLocalStorage = LocalStorage::eLocalStorage;
 
 class StorageManagerBase : public nsIDOMStorageManager
                          , public StorageObserverSink
 {
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMSTORAGEMANAGER
 
 public:
-  virtual Storage::StorageType Type() { return mType; }
+  virtual LocalStorage::StorageType Type() { return mType; }
 
   // Reads the preference for DOM storage quota
   static uint32_t GetQuota();
   // Gets (but not ensures) cache for the given scope
   StorageCache* GetCache(const nsACString& aOriginSuffix,
                          const nsACString& aOriginNoSuffix);
   // Returns object keeping usage cache for the scope.
   already_AddRefed<StorageUsage> GetOriginUsage(const nsACString& aOriginNoSuffix);
 
   static nsCString CreateOrigin(const nsACString& aOriginSuffix,
                                 const nsACString& aOriginNoSuffix);
 
 protected:
-  explicit StorageManagerBase(Storage::StorageType aType);
+  explicit StorageManagerBase(LocalStorage::StorageType aType);
   virtual ~StorageManagerBase();
 
 private:
   // StorageObserverSink, handler to various chrome clearing notification
   virtual nsresult Observe(const char* aTopic,
                            const nsAString& aOriginAttributesPattern,
                            const nsACString& aOriginScope) override;
 
@@ -106,17 +106,17 @@ private:
                               const nsAString& aDocumentURI,
                               bool aPrivate,
                               nsIDOMStorage** aRetval);
 
   // Suffix->origin->cache map
   typedef nsTHashtable<StorageCacheHashKey> CacheOriginHashtable;
   nsClassHashtable<nsCStringHashKey, CacheOriginHashtable> mCaches;
 
-  const Storage::StorageType mType;
+  const LocalStorage::StorageType mType;
 
   // If mLowDiskSpace is true it indicates a low device storage situation and
   // so no localStorage writes are allowed. sessionStorage writes are still
   // allowed.
   bool mLowDiskSpace;
   bool IsLowDiskSpace() const { return mLowDiskSpace; };
 
   void ClearCaches(uint32_t aUnloadFlags,
--- a/dom/storage/moz.build
+++ b/dom/storage/moz.build
@@ -3,21 +3,23 @@
 # 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/.
 
 with Files("**"):
     BUG_COMPONENT = ("Core", "DOM")
 
 EXPORTS.mozilla.dom += [
+    'SessionStorage.h',
     'Storage.h',
     'StorageIPC.h',
 ]
 
 UNIFIED_SOURCES += [
+    'SessionStorage.cpp',
     'Storage.cpp',
     'StorageCache.cpp',
     'StorageDBThread.cpp',
     'StorageDBUpdater.cpp',
     'StorageIPC.cpp',
     'StorageManager.cpp',
     'StorageObserver.cpp',
 ]