StorageNotifierService.cpp (4115B)
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 "StorageNotifierService.h" 8 9 #include "StorageUtils.h" 10 #include "mozilla/ClearOnShutdown.h" 11 #include "mozilla/StaticPtr.h" 12 #include "mozilla/dom/StorageEvent.h" 13 #include "nsThreadUtils.h" 14 15 namespace mozilla::dom { 16 17 namespace { 18 19 // This boolean is used to avoid the creation of the service after been 20 // distroyed on shutdown. 21 bool gStorageShuttingDown = false; 22 23 StaticRefPtr<StorageNotifierService> gStorageNotifierService; 24 25 } // namespace 26 27 /* static */ 28 StorageNotifierService* StorageNotifierService::GetOrCreate() { 29 MOZ_ASSERT(NS_IsMainThread()); 30 if (!gStorageNotifierService && !gStorageShuttingDown) { 31 gStorageNotifierService = new StorageNotifierService(); 32 ClearOnShutdown(&gStorageNotifierService); 33 } 34 35 return gStorageNotifierService; 36 } 37 38 StorageNotifierService::StorageNotifierService() { 39 MOZ_ASSERT(NS_IsMainThread()); 40 MOZ_ASSERT(!gStorageNotifierService); 41 } 42 43 StorageNotifierService::~StorageNotifierService() { 44 MOZ_ASSERT(NS_IsMainThread()); 45 MOZ_ASSERT(!gStorageNotifierService); 46 gStorageShuttingDown = true; 47 } 48 49 /* static */ 50 void StorageNotifierService::Broadcast(StorageEvent* aEvent, 51 const char16_t* aStorageType, 52 bool aPrivateBrowsing, 53 bool aImmediateDispatch) { 54 MOZ_ASSERT(NS_IsMainThread()); 55 56 RefPtr<StorageNotifierService> service = gStorageNotifierService; 57 if (!service) { 58 return; 59 } 60 61 RefPtr<StorageEvent> event = aEvent; 62 63 for (const auto& observer : service->mObservers.ForwardRange()) { 64 // Enforce that the source storage area's private browsing state matches 65 // this window's state. These flag checks and their maintenance independent 66 // from the principal's OriginAttributes matter because chrome docshells 67 // that are part of private browsing windows can be private browsing without 68 // having their OriginAttributes set (because they have the system 69 // principal). 70 if (aPrivateBrowsing != observer->IsPrivateBrowsing()) { 71 continue; 72 } 73 74 // No reasons to continue if the principal of the event doesn't match with 75 // the window's one. 76 if (!StorageUtils::PrincipalsEqual( 77 aEvent->GetPrincipal(), observer->GetEffectiveStoragePrincipal())) { 78 continue; 79 } 80 81 const auto pinnedObserver = observer; 82 83 RefPtr<Runnable> r = NS_NewRunnableFunction( 84 "StorageNotifierService::Broadcast", 85 [pinnedObserver, event, aStorageType, aPrivateBrowsing, 86 aImmediateDispatch]() { 87 // Check principals again. EffectiveStoragePrincipal may be changed 88 // when relaxed. 89 if (!aImmediateDispatch && 90 !StorageUtils::PrincipalsEqual( 91 event->GetPrincipal(), 92 pinnedObserver->GetEffectiveStoragePrincipal())) { 93 return; 94 } 95 96 pinnedObserver->ObserveStorageNotification(event, aStorageType, 97 aPrivateBrowsing); 98 }); 99 100 if (aImmediateDispatch) { 101 r->Run(); 102 } else { 103 nsCOMPtr<nsIEventTarget> et = pinnedObserver->GetEventTarget(); 104 if (et) { 105 et->Dispatch(r.forget()); 106 } 107 } 108 } 109 } 110 111 void StorageNotifierService::Register(StorageNotificationObserver* aObserver) { 112 MOZ_ASSERT(NS_IsMainThread()); 113 MOZ_ASSERT(aObserver); 114 MOZ_ASSERT(!mObservers.Contains(aObserver)); 115 116 mObservers.AppendElement(aObserver); 117 } 118 119 void StorageNotifierService::Unregister( 120 StorageNotificationObserver* aObserver) { 121 MOZ_ASSERT(NS_IsMainThread()); 122 MOZ_ASSERT(aObserver); 123 124 // No assertion about mObservers containing aObserver because window calls 125 // this method multiple times. 126 127 mObservers.RemoveElement(aObserver); 128 } 129 130 } // namespace mozilla::dom