tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SessionStorage.cpp (6893B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "SessionStorage.h"
      8 
      9 #include "SessionStorageCache.h"
     10 #include "SessionStorageManager.h"
     11 #include "mozilla/Preferences.h"
     12 #include "mozilla/dom/StorageBinding.h"
     13 #include "nsContentUtils.h"
     14 #include "nsIPrincipal.h"
     15 #include "nsPIDOMWindow.h"
     16 #include "nsThreadUtils.h"
     17 
     18 namespace mozilla::dom {
     19 
     20 NS_IMPL_CYCLE_COLLECTION_INHERITED(SessionStorage, Storage, mManager);
     21 
     22 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SessionStorage)
     23 NS_INTERFACE_MAP_END_INHERITING(Storage)
     24 
     25 NS_IMPL_ADDREF_INHERITED(SessionStorage, Storage)
     26 NS_IMPL_RELEASE_INHERITED(SessionStorage, Storage)
     27 
     28 SessionStorage::SessionStorage(nsPIDOMWindowInner* aWindow,
     29                               nsIPrincipal* aPrincipal,
     30                               nsIPrincipal* aStoragePrincipal,
     31                               SessionStorageCache* aCache,
     32                               SessionStorageManager* aManager,
     33                               const nsAString& aDocumentURI, bool aIsPrivate)
     34    : Storage(aWindow, aPrincipal, aStoragePrincipal),
     35      mCache(aCache),
     36      mManager(aManager),
     37      mDocumentURI(aDocumentURI),
     38      mIsPrivate(aIsPrivate),
     39      mHasPendingStableStateCallback(false) {
     40  MOZ_ASSERT(aCache);
     41 }
     42 
     43 SessionStorage::~SessionStorage() = default;
     44 
     45 int64_t SessionStorage::GetOriginQuotaUsage() const {
     46  nsresult rv = EnsureCacheLoadedOrCloned();
     47  if (NS_WARN_IF(NS_FAILED(rv))) {
     48    return 0;
     49  }
     50 
     51  return mCache->GetOriginQuotaUsage();
     52 }
     53 
     54 uint32_t SessionStorage::GetLength(nsIPrincipal& aSubjectPrincipal,
     55                                   ErrorResult& aRv) {
     56  if (!CanUseStorage(aSubjectPrincipal)) {
     57    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     58    return 0;
     59  }
     60 
     61  nsresult rv = EnsureCacheLoadedOrCloned();
     62  if (NS_WARN_IF(NS_FAILED(rv))) {
     63    aRv.Throw(rv);
     64    return 0;
     65  }
     66 
     67  return mCache->Length();
     68 }
     69 
     70 void SessionStorage::Key(uint32_t aIndex, nsAString& aResult,
     71                         nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) {
     72  if (!CanUseStorage(aSubjectPrincipal)) {
     73    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     74    return;
     75  }
     76 
     77  nsresult rv = EnsureCacheLoadedOrCloned();
     78  if (NS_WARN_IF(NS_FAILED(rv))) {
     79    aRv.Throw(rv);
     80    return;
     81  }
     82 
     83  mCache->Key(aIndex, aResult);
     84 }
     85 
     86 void SessionStorage::GetItem(const nsAString& aKey, nsAString& aResult,
     87                             nsIPrincipal& aSubjectPrincipal,
     88                             ErrorResult& aRv) {
     89  if (!CanUseStorage(aSubjectPrincipal)) {
     90    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     91    return;
     92  }
     93 
     94  nsresult rv = EnsureCacheLoadedOrCloned();
     95  if (NS_WARN_IF(NS_FAILED(rv))) {
     96    aRv.Throw(rv);
     97    return;
     98  }
     99 
    100  mCache->GetItem(aKey, aResult);
    101 }
    102 
    103 void SessionStorage::GetSupportedNames(nsTArray<nsString>& aKeys) {
    104  if (!CanUseStorage(*nsContentUtils::SubjectPrincipal())) {
    105    // return just an empty array
    106    aKeys.Clear();
    107    return;
    108  }
    109 
    110  nsresult rv = EnsureCacheLoadedOrCloned();
    111  if (NS_WARN_IF(NS_FAILED(rv))) {
    112    // return just an empty array
    113    aKeys.Clear();
    114    return;
    115  }
    116 
    117  mCache->GetKeys(aKeys);
    118 }
    119 
    120 void SessionStorage::SetItem(const nsAString& aKey, const nsAString& aValue,
    121                             nsIPrincipal& aSubjectPrincipal,
    122                             ErrorResult& aRv) {
    123  if (!CanUseStorage(aSubjectPrincipal)) {
    124    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    125    return;
    126  }
    127 
    128  nsresult rv = EnsureCacheLoadedOrCloned();
    129  if (NS_WARN_IF(NS_FAILED(rv))) {
    130    aRv.Throw(rv);
    131    return;
    132  }
    133 
    134  nsString oldValue;
    135  rv = mCache->SetItem(aKey, aValue, oldValue);
    136  if (NS_WARN_IF(NS_FAILED(rv))) {
    137    aRv.Throw(rv);
    138    return;
    139  }
    140 
    141  if (rv == NS_SUCCESS_DOM_NO_OPERATION) {
    142    return;
    143  }
    144 
    145  BroadcastChangeNotification(aKey, oldValue, aValue);
    146 }
    147 
    148 void SessionStorage::RemoveItem(const nsAString& aKey,
    149                                nsIPrincipal& aSubjectPrincipal,
    150                                ErrorResult& aRv) {
    151  if (!CanUseStorage(aSubjectPrincipal)) {
    152    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    153    return;
    154  }
    155 
    156  nsresult rv = EnsureCacheLoadedOrCloned();
    157  if (NS_WARN_IF(NS_FAILED(rv))) {
    158    aRv.Throw(rv);
    159    return;
    160  }
    161 
    162  nsString oldValue;
    163  rv = mCache->RemoveItem(aKey, oldValue);
    164  MOZ_ASSERT(NS_SUCCEEDED(rv));
    165 
    166  if (rv == NS_SUCCESS_DOM_NO_OPERATION) {
    167    return;
    168  }
    169 
    170  BroadcastChangeNotification(aKey, oldValue, VoidString());
    171 }
    172 
    173 void SessionStorage::Clear(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) {
    174  uint32_t length = GetLength(aSubjectPrincipal, aRv);
    175  if (!length) {
    176    return;
    177  }
    178 
    179  nsresult rv = EnsureCacheLoadedOrCloned();
    180  if (NS_WARN_IF(NS_FAILED(rv))) {
    181    aRv.Throw(rv);
    182    return;
    183  }
    184 
    185  mCache->Clear();
    186  BroadcastChangeNotification(VoidString(), VoidString(), VoidString());
    187 }
    188 
    189 void SessionStorage::BroadcastChangeNotification(const nsAString& aKey,
    190                                                 const nsAString& aOldValue,
    191                                                 const nsAString& aNewValue) {
    192  NotifyChange(this, StoragePrincipal(), aKey, aOldValue, aNewValue,
    193               u"sessionStorage", mDocumentURI, mIsPrivate, false);
    194 
    195  // Sync changes on SessionStorageCache at the next statble state.
    196  if (mManager->CanLoadData()) {
    197    MaybeScheduleStableStateCallback();
    198  }
    199 }
    200 
    201 bool SessionStorage::IsForkOf(const Storage* aOther) const {
    202  MOZ_ASSERT(aOther);
    203  if (aOther->Type() != eSessionStorage) {
    204    return false;
    205  }
    206 
    207  return mCache == static_cast<const SessionStorage*>(aOther)->mCache;
    208 }
    209 
    210 void SessionStorage::MaybeScheduleStableStateCallback() {
    211  AssertIsOnOwningThread();
    212 
    213  if (!mHasPendingStableStateCallback) {
    214    nsContentUtils::RunInStableState(
    215        NewRunnableMethod("SessionStorage::StableStateCallback", this,
    216                          &SessionStorage::StableStateCallback));
    217 
    218    mHasPendingStableStateCallback = true;
    219  }
    220 }
    221 
    222 void SessionStorage::StableStateCallback() {
    223  AssertIsOnOwningThread();
    224  MOZ_ASSERT(mHasPendingStableStateCallback);
    225  MOZ_ASSERT(mManager);
    226  MOZ_ASSERT(mCache);
    227 
    228  mHasPendingStableStateCallback = false;
    229 
    230  if (mManager->CanLoadData()) {
    231    mManager->CheckpointData(*StoragePrincipal(), *mCache);
    232  }
    233 }
    234 
    235 nsresult SessionStorage::EnsureCacheLoadedOrCloned() const {
    236  AssertIsOnOwningThread();
    237  MOZ_ASSERT(mManager);
    238 
    239  if (!mManager->CanLoadData()) {
    240    return NS_OK;
    241  }
    242 
    243  // Ensure manager actor.
    244  nsresult rv = mManager->EnsureManager();
    245  if (NS_WARN_IF(NS_FAILED(rv))) {
    246    return rv;
    247  }
    248 
    249  // Ensure cache is loaded or cloned.
    250  if (mCache->WasLoadedOrCloned()) {
    251    return NS_OK;
    252  }
    253 
    254  return mManager->LoadData(*StoragePrincipal(), *mCache);
    255 }
    256 
    257 }  // namespace mozilla::dom