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 #include "StorageUtils.h"
9 #include "mozilla/dom/StorageEvent.h"
10 #include "mozilla/ClearOnShutdown.h"
11 #include "mozilla/StaticPtr.h"
12 #include "nsThreadUtils.h"
13
14 namespace mozilla {
15 namespace 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 */
GetOrCreate()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
StorageNotifierService()38 StorageNotifierService::StorageNotifierService() {
39 MOZ_ASSERT(NS_IsMainThread());
40 MOZ_ASSERT(!gStorageNotifierService);
41 }
42
~StorageNotifierService()43 StorageNotifierService::~StorageNotifierService() {
44 MOZ_ASSERT(NS_IsMainThread());
45 MOZ_ASSERT(!gStorageNotifierService);
46 gStorageShuttingDown = true;
47 }
48
49 /* static */
Broadcast(StorageEvent * aEvent,const char16_t * aStorageType,bool aPrivateBrowsing,bool aImmediateDispatch)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
Register(StorageNotificationObserver * aObserver)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
Unregister(StorageNotificationObserver * aObserver)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 dom
131 } // namespace mozilla
132