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