tor-browser

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

LocalStorage.cpp (6160B)


      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 "LocalStorage.h"
      8 
      9 #include "LocalStorageCache.h"
     10 #include "LocalStorageManager.h"
     11 #include "StorageUtils.h"
     12 #include "mozilla/Preferences.h"
     13 #include "mozilla/dom/PermissionMessageUtils.h"
     14 #include "mozilla/dom/StorageBinding.h"
     15 #include "mozilla/dom/StorageEvent.h"
     16 #include "mozilla/dom/StorageEventBinding.h"
     17 #include "mozilla/ipc/BackgroundChild.h"
     18 #include "mozilla/ipc/PBackgroundChild.h"
     19 #include "nsContentUtils.h"
     20 #include "nsIPrincipal.h"
     21 #include "nsServiceManagerUtils.h"
     22 #include "nsThreadUtils.h"
     23 
     24 namespace mozilla {
     25 
     26 using namespace ipc;
     27 
     28 namespace dom {
     29 
     30 NS_IMPL_CYCLE_COLLECTION_CLASS(LocalStorage)
     31 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(LocalStorage, Storage)
     32  NS_IMPL_CYCLE_COLLECTION_UNLINK(mManager)
     33  NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE
     34 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     35 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(LocalStorage, Storage)
     36  CycleCollectionNoteChild(
     37      cb, NS_ISUPPORTS_CAST(nsIDOMStorageManager*, tmp->mManager.get()),
     38      "mManager");
     39 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     40 
     41 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(LocalStorage)
     42  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     43 NS_INTERFACE_MAP_END_INHERITING(Storage)
     44 
     45 NS_IMPL_ADDREF_INHERITED(LocalStorage, Storage)
     46 NS_IMPL_RELEASE_INHERITED(LocalStorage, Storage)
     47 
     48 LocalStorage::LocalStorage(nsPIDOMWindowInner* aWindow,
     49                           LocalStorageManager* aManager,
     50                           LocalStorageCache* aCache,
     51                           const nsAString& aDocumentURI,
     52                           nsIPrincipal* aPrincipal,
     53                           nsIPrincipal* aStoragePrincipal, bool aIsPrivate)
     54    : Storage(aWindow, aPrincipal, aStoragePrincipal),
     55      mManager(aManager),
     56      mCache(aCache),
     57      mDocumentURI(aDocumentURI),
     58      mIsPrivate(aIsPrivate) {
     59  mCache->Preload();
     60 }
     61 
     62 LocalStorage::~LocalStorage() = default;
     63 
     64 int64_t LocalStorage::GetOriginQuotaUsage() const {
     65  return mCache->GetOriginQuotaUsage(this);
     66 }
     67 
     68 uint32_t LocalStorage::GetLength(nsIPrincipal& aSubjectPrincipal,
     69                                 ErrorResult& aRv) {
     70  if (!CanUseStorage(aSubjectPrincipal)) {
     71    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     72    return 0;
     73  }
     74 
     75  uint32_t length;
     76  aRv = mCache->GetLength(this, &length);
     77  return length;
     78 }
     79 
     80 void LocalStorage::Key(uint32_t aIndex, nsAString& aResult,
     81                       nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) {
     82  if (!CanUseStorage(aSubjectPrincipal)) {
     83    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     84    return;
     85  }
     86 
     87  aRv = mCache->GetKey(this, aIndex, aResult);
     88 }
     89 
     90 void LocalStorage::GetItem(const nsAString& aKey, nsAString& aResult,
     91                           nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) {
     92  if (!CanUseStorage(aSubjectPrincipal)) {
     93    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     94    return;
     95  }
     96 
     97  aRv = mCache->GetItem(this, aKey, aResult);
     98 }
     99 
    100 void LocalStorage::SetItem(const nsAString& aKey, const nsAString& aData,
    101                           nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) {
    102  if (!CanUseStorage(aSubjectPrincipal)) {
    103    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    104    return;
    105  }
    106 
    107  nsString data;
    108  bool ok = data.Assign(aData, fallible);
    109  if (!ok) {
    110    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
    111    return;
    112  }
    113 
    114  nsString old;
    115  aRv = mCache->SetItem(this, aKey, data, old);
    116  if (aRv.Failed()) {
    117    return;
    118  }
    119 
    120  if (!aRv.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION)) {
    121    OnChange(aKey, old, aData);
    122  }
    123 }
    124 
    125 void LocalStorage::RemoveItem(const nsAString& aKey,
    126                              nsIPrincipal& aSubjectPrincipal,
    127                              ErrorResult& aRv) {
    128  if (!CanUseStorage(aSubjectPrincipal)) {
    129    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    130    return;
    131  }
    132 
    133  nsAutoString old;
    134  aRv = mCache->RemoveItem(this, aKey, old);
    135  if (aRv.Failed()) {
    136    return;
    137  }
    138 
    139  if (!aRv.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION)) {
    140    OnChange(aKey, old, VoidString());
    141  }
    142 }
    143 
    144 void LocalStorage::Clear(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) {
    145  if (!CanUseStorage(aSubjectPrincipal)) {
    146    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    147    return;
    148  }
    149 
    150  aRv = mCache->Clear(this);
    151  if (NS_WARN_IF(aRv.Failed())) {
    152    return;
    153  }
    154 
    155  if (!aRv.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION)) {
    156    OnChange(VoidString(), VoidString(), VoidString());
    157  }
    158 }
    159 
    160 void LocalStorage::OnChange(const nsAString& aKey, const nsAString& aOldValue,
    161                            const nsAString& aNewValue) {
    162  NotifyChange(/* aStorage */ this, StoragePrincipal(), aKey, aOldValue,
    163               aNewValue, /* aStorageType */ u"localStorage", mDocumentURI,
    164               mIsPrivate, /* aImmediateDispatch */ false);
    165 }
    166 
    167 void LocalStorage::ApplyEvent(StorageEvent* aStorageEvent) {
    168  MOZ_ASSERT(aStorageEvent);
    169 
    170  nsAutoString key;
    171  nsAutoString old;
    172  nsAutoString value;
    173 
    174  aStorageEvent->GetKey(key);
    175  aStorageEvent->GetNewValue(value);
    176 
    177  // No key means clearing the full storage.
    178  if (key.IsVoid()) {
    179    MOZ_ASSERT(value.IsVoid());
    180    mCache->Clear(this, LocalStorageCache::E10sPropagated);
    181    return;
    182  }
    183 
    184  // No new value means removing the key.
    185  if (value.IsVoid()) {
    186    mCache->RemoveItem(this, key, old, LocalStorageCache::E10sPropagated);
    187    return;
    188  }
    189 
    190  // Otherwise, we set the new value.
    191  mCache->SetItem(this, key, value, old, LocalStorageCache::E10sPropagated);
    192 }
    193 
    194 void LocalStorage::GetSupportedNames(nsTArray<nsString>& aKeys) {
    195  if (!CanUseStorage(*nsContentUtils::SubjectPrincipal())) {
    196    // return just an empty array
    197    aKeys.Clear();
    198    return;
    199  }
    200 
    201  mCache->GetKeys(this, aKeys);
    202 }
    203 
    204 bool LocalStorage::IsForkOf(const Storage* aOther) const {
    205  MOZ_ASSERT(aOther);
    206  if (aOther->Type() != eLocalStorage) {
    207    return false;
    208  }
    209 
    210  return mCache == static_cast<const LocalStorage*>(aOther)->mCache;
    211 }
    212 
    213 }  // namespace dom
    214 }  // namespace mozilla