Storage.cpp (4916B)
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 "Storage.h" 8 9 #include "StorageNotifierService.h" 10 #include "mozilla/BasePrincipal.h" 11 #include "mozilla/Preferences.h" 12 #include "mozilla/SchedulerGroup.h" 13 #include "mozilla/Services.h" 14 #include "mozilla/StaticPrefs_dom.h" 15 #include "mozilla/StorageAccess.h" 16 #include "mozilla/dom/StorageBinding.h" 17 #include "mozilla/dom/StorageEvent.h" 18 #include "mozilla/dom/StorageEventBinding.h" 19 #include "nsIObserverService.h" 20 #include "nsPIDOMWindow.h" 21 22 namespace mozilla::dom { 23 24 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Storage, mWindow, mPrincipal, 25 mStoragePrincipal) 26 27 NS_IMPL_CYCLE_COLLECTING_ADDREF(Storage) 28 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(Storage, LastRelease()) 29 30 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Storage) 31 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 32 NS_INTERFACE_MAP_ENTRY(nsISupports) 33 NS_INTERFACE_MAP_END 34 35 Storage::Storage(nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal, 36 nsIPrincipal* aStoragePrincipal) 37 : mWindow(aWindow), 38 mPrincipal(aPrincipal), 39 mStoragePrincipal(aStoragePrincipal), 40 mPrivateBrowsing(false), 41 mPrivateBrowsingOrLess(false) { 42 MOZ_ASSERT(aPrincipal); 43 44 if (mPrincipal->IsSystemPrincipal()) { 45 mPrivateBrowsing = false; 46 mPrivateBrowsingOrLess = false; 47 } else if (mWindow) { 48 uint32_t rejectedReason = 0; 49 StorageAccess access = StorageAllowedForWindow(mWindow, &rejectedReason); 50 51 mPrivateBrowsing = access == StorageAccess::ePrivateBrowsing; 52 mPrivateBrowsingOrLess = access <= StorageAccess::ePrivateBrowsing; 53 } 54 } 55 56 Storage::~Storage() = default; 57 58 /* static */ 59 bool Storage::StoragePrefIsEnabled() { 60 return StaticPrefs::dom_storage_enabled(); 61 } 62 63 int64_t Storage::GetSnapshotUsage(nsIPrincipal& aSubjectPrincipal, 64 ErrorResult& aRv) { 65 aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); 66 return 0; 67 } 68 69 bool Storage::CanUseStorage(nsIPrincipal& aSubjectPrincipal) { 70 if (!StoragePrefIsEnabled()) { 71 return false; 72 } 73 74 return aSubjectPrincipal.Subsumes(mPrincipal); 75 } 76 77 /* virtual */ 78 JSObject* Storage::WrapObject(JSContext* aCx, 79 JS::Handle<JSObject*> aGivenProto) { 80 return Storage_Binding::Wrap(aCx, this, aGivenProto); 81 } 82 83 namespace { 84 85 class StorageNotifierRunnable : public Runnable { 86 public: 87 StorageNotifierRunnable(nsISupports* aSubject, const char16_t* aStorageType, 88 bool aPrivateBrowsing) 89 : Runnable("StorageNotifierRunnable"), 90 mSubject(aSubject), 91 mStorageType(aStorageType), 92 mPrivateBrowsing(aPrivateBrowsing) {} 93 94 NS_IMETHOD 95 Run() override { 96 nsCOMPtr<nsIObserverService> observerService = 97 mozilla::services::GetObserverService(); 98 if (observerService) { 99 observerService->NotifyObservers(mSubject, 100 mPrivateBrowsing 101 ? "dom-private-storage2-changed" 102 : "dom-storage2-changed", 103 mStorageType); 104 } 105 return NS_OK; 106 } 107 108 private: 109 nsCOMPtr<nsISupports> mSubject; 110 const char16_t* mStorageType; 111 const bool mPrivateBrowsing; 112 }; 113 114 } // namespace 115 116 /* static */ 117 void Storage::NotifyChange(Storage* aStorage, nsIPrincipal* aPrincipal, 118 const nsAString& aKey, const nsAString& aOldValue, 119 const nsAString& aNewValue, 120 const char16_t* aStorageType, 121 const nsAString& aDocumentURI, bool aIsPrivate, 122 bool aImmediateDispatch) { 123 StorageEventInit dict; 124 dict.mBubbles = false; 125 dict.mCancelable = false; 126 dict.mKey = aKey; 127 dict.mNewValue = aNewValue; 128 dict.mOldValue = aOldValue; 129 dict.mStorageArea = aStorage; 130 dict.mUrl = aDocumentURI; 131 132 // Note, this DOM event should never reach JS. It is cloned later in 133 // nsGlobalWindow. 134 RefPtr<StorageEvent> event = 135 StorageEvent::Constructor(nullptr, u"storage"_ns, dict); 136 137 event->SetPrincipal(aPrincipal); 138 139 // This will send the event to any registered window. 140 StorageNotifierService::Broadcast(event, aStorageType, aIsPrivate, 141 aImmediateDispatch); 142 143 // This runnable is mainly used by devtools. Windows receive notification by 144 // StorageNotifierService. 145 146 RefPtr<StorageNotifierRunnable> r = 147 new StorageNotifierRunnable(event, aStorageType, aIsPrivate); 148 149 if (aImmediateDispatch) { 150 (void)r->Run(); 151 } else { 152 SchedulerGroup::Dispatch(r.forget()); 153 } 154 } 155 156 } // namespace mozilla::dom