Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp
Warning:line 549, column 5
Value stored to 'blocked' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_dom_notification0.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/notification -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/notification -resource-dir /usr/lib/llvm-18/lib/clang/18 -include /var/lib/jenkins/workspace/firefox-scan-build/config/gcc_hidden.h -include /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /var/lib/jenkins/workspace/firefox-scan-build/dom/notification -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/notification -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /var/lib/jenkins/workspace/firefox-scan-build/ipc/chromium/src -I /var/lib/jenkins/workspace/firefox-scan-build/dom/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/ipc -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -fdeprecated-macro -ferror-limit 19 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-07-09-005712-2187284-1 -x c++ Unified_cpp_dom_notification0.cpp
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 "mozilla/dom/Notification.h"
8
9#include <utility>
10
11#include "mozilla/BasePrincipal.h"
12#include "mozilla/Components.h"
13#include "mozilla/Encoding.h"
14#include "mozilla/EventStateManager.h"
15#include "mozilla/HoldDropJSObjects.h"
16#include "mozilla/JSONStringWriteFuncs.h"
17#include "mozilla/OwningNonNull.h"
18#include "mozilla/Preferences.h"
19#include "mozilla/StaticPrefs_dom.h"
20#include "mozilla/Unused.h"
21#include "mozilla/dom/AppNotificationServiceOptionsBinding.h"
22#include "mozilla/dom/BindingUtils.h"
23#include "mozilla/dom/ContentChild.h"
24#include "mozilla/dom/Document.h"
25#include "mozilla/dom/Promise.h"
26#include "mozilla/dom/PromiseWorkerProxy.h"
27#include "mozilla/dom/QMResult.h"
28#include "mozilla/dom/RootedDictionary.h"
29#include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h"
30#include "mozilla/dom/ServiceWorkerUtils.h"
31#include "mozilla/dom/WorkerRunnable.h"
32#include "mozilla/dom/WorkerScope.h"
33#include "mozilla/dom/quota/ResultExtensions.h"
34#include "Navigator.h"
35#include "nsComponentManagerUtils.h"
36#include "nsContentPermissionHelper.h"
37#include "nsContentUtils.h"
38#include "nsFocusManager.h"
39#include "nsIAlertsService.h"
40#include "nsIContentPermissionPrompt.h"
41#include "nsILoadContext.h"
42#include "nsINotificationStorage.h"
43#include "nsIPermission.h"
44#include "nsIPermissionManager.h"
45#include "nsIPushService.h"
46#include "nsIScriptError.h"
47#include "nsIServiceWorkerManager.h"
48#include "nsIUUIDGenerator.h"
49#include "nsNetUtil.h"
50#include "nsProxyRelease.h"
51#include "nsServiceManagerUtils.h"
52#include "nsStructuredCloneContainer.h"
53#include "nsThreadUtils.h"
54#include "nsXULAppAPI.h"
55
56namespace mozilla::dom {
57
58struct NotificationStrings {
59 const nsString mID;
60 const nsString mTitle;
61 const nsString mDir;
62 const nsString mLang;
63 const nsString mBody;
64 const nsString mTag;
65 const nsString mIcon;
66 const nsString mData;
67 const nsString mBehavior;
68 const nsString mServiceWorkerRegistrationScope;
69};
70
71class ScopeCheckingGetCallback : public nsINotificationStorageCallback {
72 const nsString mScope;
73
74 public:
75 explicit ScopeCheckingGetCallback(const nsAString& aScope) : mScope(aScope) {}
76
77 NS_IMETHODvirtual nsresult Handle(const nsAString& aID, const nsAString& aTitle,
78 const nsAString& aDir, const nsAString& aLang,
79 const nsAString& aBody, const nsAString& aTag,
80 const nsAString& aIcon, const nsAString& aData,
81 const nsAString& aBehavior,
82 const nsAString& aServiceWorkerRegistrationScope) final {
83 AssertIsOnMainThread();
84 MOZ_ASSERT(!aID.IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aID.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aID.IsEmpty()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!aID.IsEmpty()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 84); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aID.IsEmpty()"
")"); do { *((volatile int*)__null) = 84; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
85
86 // Skip scopes that don't match when called from getNotifications().
87 if (!mScope.IsEmpty() && !mScope.Equals(aServiceWorkerRegistrationScope)) {
88 return NS_OK;
89 }
90
91 NotificationStrings strings = {
92 nsString(aID), nsString(aTitle),
93 nsString(aDir), nsString(aLang),
94 nsString(aBody), nsString(aTag),
95 nsString(aIcon), nsString(aData),
96 nsString(aBehavior), nsString(aServiceWorkerRegistrationScope),
97 };
98
99 mStrings.AppendElement(std::move(strings));
100 return NS_OK;
101 }
102
103 NS_IMETHODvirtual nsresult Done() override = 0;
104
105 protected:
106 virtual ~ScopeCheckingGetCallback() = default;
107
108 nsTArray<NotificationStrings> mStrings;
109};
110
111class NotificationStorageCallback final : public ScopeCheckingGetCallback {
112 public:
113 NS_DECL_CYCLE_COLLECTING_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsCycleCollectingAutoRefCnt mRefCnt; nsAutoOwningThread
_mOwningThread; public: virtual void DeleteCycleCollectable(
void); public:
114 NS_DECL_CYCLE_COLLECTION_CLASS(NotificationStorageCallback)class cycleCollection : public nsXPCOMCycleCollectionParticipant
{ public: constexpr explicit cycleCollection(Flags aFlags = 0
) : nsXPCOMCycleCollectionParticipant(aFlags) {} private: public
: virtual nsresult TraverseNative(void* p, nsCycleCollectionTraversalCallback
& cb) override; virtual const char* ClassName() override {
return "NotificationStorageCallback"; }; virtual void DeleteCycleCollectable
(void* p) override { DowncastCCParticipant<NotificationStorageCallback
>(p)->DeleteCycleCollectable(); } static NotificationStorageCallback
* Downcast(nsISupports* s) { return static_cast<NotificationStorageCallback
*>(static_cast<NotificationStorageCallback*>(s)); } static
nsISupports* Upcast(NotificationStorageCallback* p) { return
static_cast<nsISupports*>(static_cast<NotificationStorageCallback
*>(p)); } template <typename T> friend nsISupports* ToSupports
(T* p, cycleCollection* dummy); virtual void Unlink(void* p) override
; static constexpr nsXPCOMCycleCollectionParticipant* GetParticipant
() { return &NotificationStorageCallback::_cycleCollectorGlobal
; } }; virtual void CheckForRightParticipant() { nsXPCOMCycleCollectionParticipant
* p; CallQueryInterface(this, &p); do { static_assert( mozilla
::detail::AssertionConditionType<decltype(p == &_cycleCollectorGlobal
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(p == &_cycleCollectorGlobal))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("p == &_cycleCollectorGlobal"
" (" "NotificationStorageCallback" " should QI to its own CC participant"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 114); AnnotateMozCrashReason("MOZ_ASSERT" "(" "p == &_cycleCollectorGlobal"
") (" "NotificationStorageCallback" " should QI to its own CC participant"
")"); do { *((volatile int*)__null) = 114; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } static cycleCollection
_cycleCollectorGlobal; virtual void BaseCycleCollectable() final
{}
115
116 NotificationStorageCallback(nsIGlobalObject* aWindow, const nsAString& aScope,
117 Promise* aPromise)
118 : ScopeCheckingGetCallback(aScope), mWindow(aWindow), mPromise(aPromise) {
119 AssertIsOnMainThread();
120 MOZ_ASSERT(aWindow)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aWindow)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aWindow))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aWindow", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 120); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWindow" ")"
); do { *((volatile int*)__null) = 120; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
121 MOZ_ASSERT(aPromise)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPromise)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPromise))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aPromise", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 121); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPromise" ")"
); do { *((volatile int*)__null) = 121; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
122 }
123
124 NS_IMETHODvirtual nsresult Done() final {
125 AutoTArray<RefPtr<Notification>, 5> notifications;
126
127 for (uint32_t i = 0; i < mStrings.Length(); ++i) {
128 auto result = Notification::ConstructFromFields(
129 mWindow, mStrings[i].mID, mStrings[i].mTitle, mStrings[i].mDir,
130 mStrings[i].mLang, mStrings[i].mBody, mStrings[i].mTag,
131 mStrings[i].mIcon, mStrings[i].mData,
132 /* mStrings[i].mBehavior, not
133 * supported */
134 mStrings[i].mServiceWorkerRegistrationScope);
135 if (result.isErr()) {
136 continue;
137 }
138 RefPtr<Notification> n = result.unwrap();
139 n->SetStoredState(true);
140 notifications.AppendElement(n.forget());
141 }
142
143 mPromise->MaybeResolve(notifications);
144 return NS_OK;
145 }
146
147 private:
148 virtual ~NotificationStorageCallback() = default;
149
150 nsCOMPtr<nsIGlobalObject> mWindow;
151 RefPtr<Promise> mPromise;
152 const nsString mScope;
153};
154
155NS_IMPL_CYCLE_COLLECTING_ADDREF(NotificationStorageCallback)MozExternalRefCountType NotificationStorageCallback::AddRef(void
) { static_assert(!std::is_destructible_v<NotificationStorageCallback
>, "Reference-counted class " "NotificationStorageCallback"
" should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 155); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
155; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); _mOwningThread.AssertOwnership("NotificationStorageCallback"
" not thread-safe"); nsISupports* base = NotificationStorageCallback
::cycleCollection::Upcast(this); nsrefcnt count = mRefCnt.incr
(base); NS_LogAddRef((this), (count), ("NotificationStorageCallback"
), (uint32_t)(sizeof(*this))); return count; }
156NS_IMPL_CYCLE_COLLECTING_RELEASE(NotificationStorageCallback)MozExternalRefCountType NotificationStorageCallback::Release(
void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 156); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 156
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); _mOwningThread.AssertOwnership("NotificationStorageCallback"
" not thread-safe"); nsISupports* base = NotificationStorageCallback
::cycleCollection::Upcast(this); nsrefcnt count = mRefCnt.decr
(base); NS_LogRelease((this), (count), ("NotificationStorageCallback"
)); return count; } void NotificationStorageCallback::DeleteCycleCollectable
(void) { delete (this); }
157NS_IMPL_CYCLE_COLLECTION(NotificationStorageCallback, mWindow, mPromise)NotificationStorageCallback::cycleCollection NotificationStorageCallback
::_cycleCollectorGlobal; void NotificationStorageCallback::cycleCollection
::Unlink(void* p) { NotificationStorageCallback* tmp = DowncastCCParticipant
<NotificationStorageCallback>(p); ImplCycleCollectionUnlink
(tmp->mWindow); ImplCycleCollectionUnlink(tmp->mPromise
); (void)tmp; } nsresult NotificationStorageCallback::cycleCollection
::TraverseNative( void* p, nsCycleCollectionTraversalCallback
& cb) { NotificationStorageCallback* tmp = DowncastCCParticipant
<NotificationStorageCallback>(p); cb.DescribeRefCountedNode
(tmp->mRefCnt.get(), "NotificationStorageCallback"); ImplCycleCollectionTraverse
(cb, tmp->mWindow, "mWindow", 0); ImplCycleCollectionTraverse
(cb, tmp->mPromise, "mPromise", 0); (void)tmp; return NS_OK
; }
;
158
159NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(NotificationStorageCallback)nsresult NotificationStorageCallback::QueryInterface(const nsIID
& aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) {
NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 159); MOZ_PretendNoReturn(); } } while (0); nsISupports* foundInterface
; if (TopThreeWordsEquals( aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID), (nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID)) && (LowWordEquals(aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID)) || LowWordEquals(aIID, (nsCycleCollectionISupports::COMTypeInfo
<nsCycleCollectionISupports, void>::kIID)))) { if (LowWordEquals
(aIID, (nsXPCOMCycleCollectionParticipant::COMTypeInfo<nsXPCOMCycleCollectionParticipant
, void>::kIID))) { *aInstancePtr = NotificationStorageCallback
::cycleCollection::GetParticipant(); return NS_OK; } if (LowWordEquals
(aIID, (nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID))) { *aInstancePtr = NotificationStorageCallback
::cycleCollection::Upcast(this); return NS_OK; } foundInterface
= nullptr; } else
160 NS_INTERFACE_MAP_ENTRY(nsINotificationStorageCallback)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsINotificationStorageCallback>))
foundInterface = static_cast<nsINotificationStorageCallback
*>(this); else
161 NS_INTERFACE_MAP_ENTRY(nsISupports)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupports>)) foundInterface = static_cast
<nsISupports*>(this); else
162NS_INTERFACE_MAP_ENDfoundInterface = 0; nsresult status; if (!foundInterface) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(!aIID.Equals((nsISupports::COMTypeInfo<nsISupports
, void>::kIID)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aIID.Equals((nsISupports::COMTypeInfo
<nsISupports, void>::kIID))))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 162); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
")"); do { *((volatile int*)__null) = 162; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); status = NS_NOINTERFACE
; } else { (foundInterface)->AddRef(); status = NS_OK; } *
aInstancePtr = foundInterface; return status; }
163
164nsCOMPtr<nsINotificationStorage> GetNotificationStorage(bool isPrivate) {
165 return do_GetService(isPrivate ? NS_MEMORY_NOTIFICATION_STORAGE_CONTRACTID"@mozilla.org/memoryNotificationStorage;1"
166 : NS_NOTIFICATION_STORAGE_CONTRACTID"@mozilla.org/notificationStorage;1");
167}
168
169class NotificationGetRunnable final : public Runnable {
170 bool mIsPrivate;
171 const nsString mOrigin;
172 const nsString mTag;
173 nsCOMPtr<nsINotificationStorageCallback> mCallback;
174
175 public:
176 NotificationGetRunnable(const nsAString& aOrigin, const nsAString& aTag,
177 nsINotificationStorageCallback* aCallback,
178 bool aIsPrivate)
179 : Runnable("NotificationGetRunnable"),
180 mIsPrivate(aIsPrivate),
181 mOrigin(aOrigin),
182 mTag(aTag),
183 mCallback(aCallback) {}
184
185 NS_IMETHODvirtual nsresult
186 Run() override {
187 nsCOMPtr<nsINotificationStorage> notificationStorage =
188 GetNotificationStorage(mIsPrivate);
189 if (NS_WARN_IF(!notificationStorage)NS_warn_if_impl(!notificationStorage, "!notificationStorage",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 189)
) {
190 return NS_ERROR_UNEXPECTED;
191 }
192
193 nsresult rv = notificationStorage->Get(mOrigin, mTag, mCallback);
194 // XXXnsm Is it guaranteed mCallback will be called in case of failure?
195 Unused << NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 195)
;
196 return rv;
197 }
198};
199
200class NotificationPermissionRequest : public ContentPermissionRequestBase,
201 public nsIRunnable,
202 public nsINamed {
203 public:
204 NS_DECL_NSIRUNNABLEvirtual nsresult Run(void) override;
205 NS_DECL_ISUPPORTS_INHERITEDpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override;
206 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(NotificationPermissionRequest,class cycleCollection : public ContentPermissionRequestBase::
cycleCollection { public: constexpr explicit cycleCollection(
Flags aFlags = 0) : ContentPermissionRequestBase::cycleCollection
(aFlags) {} private: public: virtual nsresult TraverseNative(
void* p, nsCycleCollectionTraversalCallback& cb) override
; virtual const char* ClassName() override { return "NotificationPermissionRequest"
; }; static NotificationPermissionRequest* Downcast(nsISupports
* s) { return static_cast<NotificationPermissionRequest*>
(static_cast<ContentPermissionRequestBase*>( ContentPermissionRequestBase
::cycleCollection::Downcast(s))); } virtual void Unlink(void*
p) override; static constexpr nsXPCOMCycleCollectionParticipant
* GetParticipant() { return &NotificationPermissionRequest
::_cycleCollectorGlobal; } }; virtual void CheckForRightParticipant
() override { nsXPCOMCycleCollectionParticipant* p; CallQueryInterface
(this, &p); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(p == &_cycleCollectorGlobal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(p == &_cycleCollectorGlobal
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"p == &_cycleCollectorGlobal" " (" "NotificationPermissionRequest"
" should QI to its own CC participant" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 207); AnnotateMozCrashReason("MOZ_ASSERT" "(" "p == &_cycleCollectorGlobal"
") (" "NotificationPermissionRequest" " should QI to its own CC participant"
")"); do { *((volatile int*)__null) = 207; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } static cycleCollection
_cycleCollectorGlobal;
207 ContentPermissionRequestBase)class cycleCollection : public ContentPermissionRequestBase::
cycleCollection { public: constexpr explicit cycleCollection(
Flags aFlags = 0) : ContentPermissionRequestBase::cycleCollection
(aFlags) {} private: public: virtual nsresult TraverseNative(
void* p, nsCycleCollectionTraversalCallback& cb) override
; virtual const char* ClassName() override { return "NotificationPermissionRequest"
; }; static NotificationPermissionRequest* Downcast(nsISupports
* s) { return static_cast<NotificationPermissionRequest*>
(static_cast<ContentPermissionRequestBase*>( ContentPermissionRequestBase
::cycleCollection::Downcast(s))); } virtual void Unlink(void*
p) override; static constexpr nsXPCOMCycleCollectionParticipant
* GetParticipant() { return &NotificationPermissionRequest
::_cycleCollectorGlobal; } }; virtual void CheckForRightParticipant
() override { nsXPCOMCycleCollectionParticipant* p; CallQueryInterface
(this, &p); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(p == &_cycleCollectorGlobal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(p == &_cycleCollectorGlobal
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"p == &_cycleCollectorGlobal" " (" "NotificationPermissionRequest"
" should QI to its own CC participant" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 207); AnnotateMozCrashReason("MOZ_ASSERT" "(" "p == &_cycleCollectorGlobal"
") (" "NotificationPermissionRequest" " should QI to its own CC participant"
")"); do { *((volatile int*)__null) = 207; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } static cycleCollection
_cycleCollectorGlobal;
208
209 // nsIContentPermissionRequest
210 NS_IMETHODvirtual nsresult Cancel(void) override;
211 NS_IMETHODvirtual nsresult Allow(JS::Handle<JS::Value> choices) override;
212
213 NotificationPermissionRequest(nsIPrincipal* aPrincipal,
214 nsPIDOMWindowInner* aWindow, Promise* aPromise,
215 NotificationPermissionCallback* aCallback)
216 : ContentPermissionRequestBase(aPrincipal, aWindow, "notification"_ns,
217 "desktop-notification"_ns),
218 mPermission(NotificationPermission::Default),
219 mPromise(aPromise),
220 mCallback(aCallback) {
221 MOZ_ASSERT(aPromise)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPromise)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPromise))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aPromise", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 221); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPromise" ")"
); do { *((volatile int*)__null) = 221; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
222 }
223
224 NS_IMETHODvirtual nsresult GetName(nsACString& aName) override {
225 aName.AssignLiteral("NotificationPermissionRequest");
226 return NS_OK;
227 }
228
229 protected:
230 ~NotificationPermissionRequest() = default;
231
232 MOZ_CAN_RUN_SCRIPT nsresult ResolvePromise();
233 nsresult DispatchResolvePromise();
234 NotificationPermission mPermission;
235 RefPtr<Promise> mPromise;
236 RefPtr<NotificationPermissionCallback> mCallback;
237};
238
239namespace {
240class ReleaseNotificationControlRunnable final
241 : public MainThreadWorkerControlRunnable {
242 Notification* mNotification;
243
244 public:
245 explicit ReleaseNotificationControlRunnable(Notification* aNotification)
246 : MainThreadWorkerControlRunnable("ReleaseNotificationControlRunnable"),
247 mNotification(aNotification) {}
248
249 bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
250 mNotification->ReleaseObject();
251 return true;
252 }
253};
254
255class GetPermissionRunnable final : public WorkerMainThreadRunnable {
256 NotificationPermission mPermission;
257
258 public:
259 explicit GetPermissionRunnable(WorkerPrivate* aWorker)
260 : WorkerMainThreadRunnable(aWorker, "Notification :: Get Permission"_ns),
261 mPermission(NotificationPermission::Denied) {}
262
263 bool MainThreadRun() override {
264 ErrorResult result;
265 MOZ_ASSERT(mWorkerRef)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mWorkerRef)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mWorkerRef))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("mWorkerRef", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 265); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWorkerRef" ")"
); do { *((volatile int*)__null) = 265; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
266 mPermission = Notification::GetPermissionInternal(
267 mWorkerRef->Private()->GetPrincipal(), result);
268 return true;
269 }
270
271 NotificationPermission GetPermission() { return mPermission; }
272};
273
274class FocusWindowRunnable final : public Runnable {
275 nsMainThreadPtrHandle<nsPIDOMWindowInner> mWindow;
276
277 public:
278 explicit FocusWindowRunnable(
279 const nsMainThreadPtrHandle<nsPIDOMWindowInner>& aWindow)
280 : Runnable("FocusWindowRunnable"), mWindow(aWindow) {}
281
282 // MOZ_CAN_RUN_SCRIPT_BOUNDARY until Runnable::Run is MOZ_CAN_RUN_SCRIPT. See
283 // bug 1535398.
284 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODvirtual nsresult Run() override {
285 AssertIsOnMainThread();
286 if (!mWindow->IsCurrentInnerWindow()) {
287 // Window has been closed, this observer is not valid anymore
288 return NS_OK;
289 }
290
291 nsCOMPtr<nsPIDOMWindowOuter> outerWindow = mWindow->GetOuterWindow();
292 nsFocusManager::FocusWindow(outerWindow, CallerType::System);
293 return NS_OK;
294 }
295};
296
297nsresult CheckScope(nsIPrincipal* aPrincipal, const nsACString& aScope,
298 uint64_t aWindowID) {
299 AssertIsOnMainThread();
300 MOZ_ASSERT(aPrincipal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPrincipal))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aPrincipal", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 300); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPrincipal" ")"
); do { *((volatile int*)__null) = 300; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
301
302 nsCOMPtr<nsIURI> scopeURI;
303 nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), aScope);
304 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 304)
) {
305 return rv;
306 }
307
308 return aPrincipal->CheckMayLoadWithReporting(
309 scopeURI,
310 /* allowIfInheritsPrincipal = */ false, aWindowID);
311}
312} // anonymous namespace
313
314// Subclass that can be directly dispatched to child workers from the main
315// thread.
316class NotificationWorkerRunnable : public MainThreadWorkerRunnable {
317 protected:
318 explicit NotificationWorkerRunnable(
319 WorkerPrivate* aWorkerPrivate,
320 const char* aName = "NotificationWorkerRunnable")
321 : MainThreadWorkerRunnable(aName) {}
322
323 bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
324 aWorkerPrivate->AssertIsOnWorkerThread();
325 // WorkerScope might start dying at the moment. And WorkerRunInternal()
326 // should not be executed once WorkerScope is dying, since
327 // WorkerRunInternal() might access resources which already been freed
328 // during WorkerRef::Notify().
329 if (aWorkerPrivate->GlobalScope() &&
330 !aWorkerPrivate->GlobalScope()->IsDying()) {
331 WorkerRunInternal(aWorkerPrivate);
332 }
333 return true;
334 }
335
336 virtual void WorkerRunInternal(WorkerPrivate* aWorkerPrivate) = 0;
337};
338
339// Overrides dispatch and run handlers so we can directly dispatch from main
340// thread to child workers.
341class NotificationEventWorkerRunnable final
342 : public NotificationWorkerRunnable {
343 Notification* mNotification;
344 const nsString mEventName;
345
346 public:
347 NotificationEventWorkerRunnable(Notification* aNotification,
348 const nsString& aEventName)
349 : NotificationWorkerRunnable(aNotification->mWorkerPrivate,
350 "NotificationEventWorkerRunnable"),
351 mNotification(aNotification),
352 mEventName(aEventName) {}
353
354 void WorkerRunInternal(WorkerPrivate* aWorkerPrivate) override {
355 mNotification->DispatchTrustedEvent(mEventName);
356 }
357};
358
359class ReleaseNotificationRunnable final : public NotificationWorkerRunnable {
360 Notification* mNotification;
361
362 public:
363 explicit ReleaseNotificationRunnable(Notification* aNotification)
364 : NotificationWorkerRunnable(aNotification->mWorkerPrivate,
365 "ReleaseNotificationRunnable"),
366 mNotification(aNotification) {}
367
368 bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
369 aWorkerPrivate->AssertIsOnWorkerThread();
370 // ReleaseNotificationRunnable is only used in StrongWorkerRef's shutdown
371 // callback. At the moment, it is supposed to executing
372 // mNotification->ReleaseObject() safely even though the corresponding
373 // WorkerScope::IsDying() is true. It is unlike other
374 // NotificationWorkerRunnable.
375 WorkerRunInternal(aWorkerPrivate);
376 return true;
377 }
378
379 void WorkerRunInternal(WorkerPrivate* aWorkerPrivate) override {
380 mNotification->ReleaseObject();
381 }
382
383 nsresult Cancel() override {
384 mNotification->ReleaseObject();
385 return NS_OK;
386 }
387};
388
389// Create one whenever you require ownership of the notification. Use with
390// UniquePtr<>. See Notification.h for details.
391class NotificationRef final {
392 friend class WorkerNotificationObserver;
393
394 private:
395 Notification* mNotification;
396 bool mInited;
397
398 // Only useful for workers.
399 void Forget() { mNotification = nullptr; }
400
401 public:
402 explicit NotificationRef(Notification* aNotification)
403 : mNotification(aNotification) {
404 MOZ_ASSERT(mNotification)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mNotification)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mNotification))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("mNotification",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 404); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mNotification"
")"); do { *((volatile int*)__null) = 404; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
405 if (mNotification->mWorkerPrivate) {
406 mNotification->mWorkerPrivate->AssertIsOnWorkerThread();
407 } else {
408 AssertIsOnMainThread();
409 }
410
411 mInited = mNotification->AddRefObject();
412 }
413
414 // This is only required because Gecko runs script in a worker's onclose
415 // handler (non-standard, Bug 790919) where calls to HoldWorker() will
416 // fail. Due to non-standardness and added complications if we decide to
417 // support this, attempts to create a Notification in onclose just throw
418 // exceptions.
419 bool Initialized() { return mInited; }
420
421 ~NotificationRef() {
422 if (Initialized() && mNotification) {
423 Notification* notification = mNotification;
424 mNotification = nullptr;
425 if (notification->mWorkerPrivate && NS_IsMainThread()) {
426 // Try to pass ownership back to the worker. If the dispatch succeeds we
427 // are guaranteed this runnable will run, and that it will run after
428 // queued event runnables, so event runnables will have a safe pointer
429 // to the Notification.
430 //
431 // If the dispatch fails, the worker isn't running anymore and the event
432 // runnables have already run or been canceled. We can use a control
433 // runnable to release the reference.
434 RefPtr<ReleaseNotificationRunnable> r =
435 new ReleaseNotificationRunnable(notification);
436
437 if (!r->Dispatch(notification->mWorkerPrivate)) {
438 RefPtr<ReleaseNotificationControlRunnable> r =
439 new ReleaseNotificationControlRunnable(notification);
440 MOZ_ALWAYS_TRUE(r->Dispatch(notification->mWorkerPrivate))do { if ((__builtin_expect(!!(r->Dispatch(notification->
mWorkerPrivate)), 1))) { } else { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(false)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(false))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("false" " (" "r->Dispatch(notification->mWorkerPrivate)"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 440); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "r->Dispatch(notification->mWorkerPrivate)" ")")
; do { *((volatile int*)__null) = 440; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
441 }
442 } else {
443 notification->AssertIsOnTargetThread();
444 notification->ReleaseObject();
445 }
446 }
447 }
448
449 // XXXnsm, is it worth having some sort of WeakPtr like wrapper instead of
450 // a rawptr that the NotificationRef can invalidate?
451 Notification* GetNotification() {
452 MOZ_ASSERT(Initialized())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(Initialized())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(Initialized()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("Initialized()",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 452); AnnotateMozCrashReason("MOZ_ASSERT" "(" "Initialized()"
")"); do { *((volatile int*)__null) = 452; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
453 return mNotification;
454 }
455};
456
457class NotificationTask : public Runnable {
458 public:
459 enum NotificationAction { eShow, eClose };
460
461 NotificationTask(const char* aName, UniquePtr<NotificationRef> aRef,
462 NotificationAction aAction)
463 : Runnable(aName), mNotificationRef(std::move(aRef)), mAction(aAction) {}
464
465 NS_IMETHODvirtual nsresult
466 Run() override;
467
468 protected:
469 virtual ~NotificationTask() = default;
470
471 UniquePtr<NotificationRef> mNotificationRef;
472 NotificationAction mAction;
473};
474
475uint32_t Notification::sCount = 0;
476
477NS_IMPL_CYCLE_COLLECTION_INHERITED(NotificationPermissionRequest,NotificationPermissionRequest::cycleCollection NotificationPermissionRequest
::_cycleCollectorGlobal; void NotificationPermissionRequest::
cycleCollection::Unlink(void* p) { NotificationPermissionRequest
* tmp = DowncastCCParticipant<NotificationPermissionRequest
>(p); nsISupports* s = static_cast<nsISupports*>(p);
ContentPermissionRequestBase::cycleCollection::Unlink(s); ImplCycleCollectionUnlink
(tmp->mCallback); (void)tmp; } nsresult NotificationPermissionRequest
::cycleCollection::TraverseNative( void* p, nsCycleCollectionTraversalCallback
& cb) { NotificationPermissionRequest* tmp = DowncastCCParticipant
<NotificationPermissionRequest>(p); nsISupports* s = static_cast
<nsISupports*>(p); if (ContentPermissionRequestBase::cycleCollection
::TraverseNative(s, cb) == NS_SUCCESS_INTERRUPTED_TRAVERSE) {
return NS_SUCCESS_INTERRUPTED_TRAVERSE; } ImplCycleCollectionTraverse
(cb, tmp->mCallback, "mCallback", 0); (void)tmp; return NS_OK
; }
478 ContentPermissionRequestBase, mCallback)NotificationPermissionRequest::cycleCollection NotificationPermissionRequest
::_cycleCollectorGlobal; void NotificationPermissionRequest::
cycleCollection::Unlink(void* p) { NotificationPermissionRequest
* tmp = DowncastCCParticipant<NotificationPermissionRequest
>(p); nsISupports* s = static_cast<nsISupports*>(p);
ContentPermissionRequestBase::cycleCollection::Unlink(s); ImplCycleCollectionUnlink
(tmp->mCallback); (void)tmp; } nsresult NotificationPermissionRequest
::cycleCollection::TraverseNative( void* p, nsCycleCollectionTraversalCallback
& cb) { NotificationPermissionRequest* tmp = DowncastCCParticipant
<NotificationPermissionRequest>(p); nsISupports* s = static_cast
<nsISupports*>(p); if (ContentPermissionRequestBase::cycleCollection
::TraverseNative(s, cb) == NS_SUCCESS_INTERRUPTED_TRAVERSE) {
return NS_SUCCESS_INTERRUPTED_TRAVERSE; } ImplCycleCollectionTraverse
(cb, tmp->mCallback, "mCallback", 0); (void)tmp; return NS_OK
; }
479NS_IMPL_ADDREF_INHERITED(NotificationPermissionRequest,MozExternalRefCountType NotificationPermissionRequest::AddRef
(void) { static_assert(!std::is_destructible_v<NotificationPermissionRequest
>, "Reference-counted class " "NotificationPermissionRequest"
" should not have a public destructor. " "Make this class's destructor non-public"
); nsrefcnt r = ContentPermissionRequestBase::AddRef(); if constexpr
(::mozilla::detail::ShouldLogInheritedRefcnt<NotificationPermissionRequest
>) { NS_LogAddRef((this), (r), ("NotificationPermissionRequest"
), (uint32_t)(sizeof(*this))); } return r; }
480 ContentPermissionRequestBase)MozExternalRefCountType NotificationPermissionRequest::AddRef
(void) { static_assert(!std::is_destructible_v<NotificationPermissionRequest
>, "Reference-counted class " "NotificationPermissionRequest"
" should not have a public destructor. " "Make this class's destructor non-public"
); nsrefcnt r = ContentPermissionRequestBase::AddRef(); if constexpr
(::mozilla::detail::ShouldLogInheritedRefcnt<NotificationPermissionRequest
>) { NS_LogAddRef((this), (r), ("NotificationPermissionRequest"
), (uint32_t)(sizeof(*this))); } return r; }
481NS_IMPL_RELEASE_INHERITED(NotificationPermissionRequest,MozExternalRefCountType NotificationPermissionRequest::Release
(void) { nsrefcnt r = ContentPermissionRequestBase::Release()
; if constexpr (::mozilla::detail::ShouldLogInheritedRefcnt<
NotificationPermissionRequest>) { NS_LogRelease((this), (r
), ("NotificationPermissionRequest")); } return r; }
482 ContentPermissionRequestBase)MozExternalRefCountType NotificationPermissionRequest::Release
(void) { nsrefcnt r = ContentPermissionRequestBase::Release()
; if constexpr (::mozilla::detail::ShouldLogInheritedRefcnt<
NotificationPermissionRequest>) { NS_LogRelease((this), (r
), ("NotificationPermissionRequest")); } return r; }
483
484NS_IMPL_QUERY_INTERFACE_CYCLE_COLLECTION_INHERITED(nsresult NotificationPermissionRequest::QueryInterface(const nsIID
& aIID, void** aInstancePtr) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(aInstancePtr)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aInstancePtr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aInstancePtr" " (" "null out param" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 486); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aInstancePtr"
") (" "null out param" ")"); do { *((volatile int*)__null) =
486; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); if (TopThreeWordsEquals(aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID), (nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID))) { if (LowWordEquals(aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID))) { *aInstancePtr = NotificationPermissionRequest::cycleCollection
::GetParticipant(); return NS_OK; } if (LowWordEquals(aIID, (
nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID))) { *aInstancePtr = NotificationPermissionRequest
::cycleCollection::Upcast(this); return NS_OK; } } nsresult rv
= NS_ERROR_FAILURE; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE_INHERITED"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<NotificationPermissionRequest, nsIRunnable
>, int32_t( reinterpret_cast<char*>(static_cast<nsIRunnable
*>((NotificationPermissionRequest*)0x1000)) - reinterpret_cast
<char*>((NotificationPermissionRequest*)0x1000))}, {&
mozilla::detail::kImplementedIID<NotificationPermissionRequest
, nsINamed>, int32_t( reinterpret_cast<char*>(static_cast
<nsINamed*>((NotificationPermissionRequest*)0x1000)) - reinterpret_cast
<char*>((NotificationPermissionRequest*)0x1000))}, { nullptr
, 0 } } ; static_assert((sizeof(table) / sizeof(table[0])) >
1, "need at least 1 interface"); rv = NS_TableDrivenQI(static_cast
<void*>(this), aIID, aInstancePtr, table); if (((bool)(
__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) return rv; return
ContentPermissionRequestBase::QueryInterface(aIID, aInstancePtr
); }
485 NotificationPermissionRequest, ContentPermissionRequestBase, nsIRunnable,nsresult NotificationPermissionRequest::QueryInterface(const nsIID
& aIID, void** aInstancePtr) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(aInstancePtr)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aInstancePtr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aInstancePtr" " (" "null out param" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 486); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aInstancePtr"
") (" "null out param" ")"); do { *((volatile int*)__null) =
486; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); if (TopThreeWordsEquals(aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID), (nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID))) { if (LowWordEquals(aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID))) { *aInstancePtr = NotificationPermissionRequest::cycleCollection
::GetParticipant(); return NS_OK; } if (LowWordEquals(aIID, (
nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID))) { *aInstancePtr = NotificationPermissionRequest
::cycleCollection::Upcast(this); return NS_OK; } } nsresult rv
= NS_ERROR_FAILURE; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE_INHERITED"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<NotificationPermissionRequest, nsIRunnable
>, int32_t( reinterpret_cast<char*>(static_cast<nsIRunnable
*>((NotificationPermissionRequest*)0x1000)) - reinterpret_cast
<char*>((NotificationPermissionRequest*)0x1000))}, {&
mozilla::detail::kImplementedIID<NotificationPermissionRequest
, nsINamed>, int32_t( reinterpret_cast<char*>(static_cast
<nsINamed*>((NotificationPermissionRequest*)0x1000)) - reinterpret_cast
<char*>((NotificationPermissionRequest*)0x1000))}, { nullptr
, 0 } } ; static_assert((sizeof(table) / sizeof(table[0])) >
1, "need at least 1 interface"); rv = NS_TableDrivenQI(static_cast
<void*>(this), aIID, aInstancePtr, table); if (((bool)(
__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) return rv; return
ContentPermissionRequestBase::QueryInterface(aIID, aInstancePtr
); }
486 nsINamed)nsresult NotificationPermissionRequest::QueryInterface(const nsIID
& aIID, void** aInstancePtr) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(aInstancePtr)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aInstancePtr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aInstancePtr" " (" "null out param" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 486); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aInstancePtr"
") (" "null out param" ")"); do { *((volatile int*)__null) =
486; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); if (TopThreeWordsEquals(aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID), (nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID))) { if (LowWordEquals(aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID))) { *aInstancePtr = NotificationPermissionRequest::cycleCollection
::GetParticipant(); return NS_OK; } if (LowWordEquals(aIID, (
nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID))) { *aInstancePtr = NotificationPermissionRequest
::cycleCollection::Upcast(this); return NS_OK; } } nsresult rv
= NS_ERROR_FAILURE; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE_INHERITED"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<NotificationPermissionRequest, nsIRunnable
>, int32_t( reinterpret_cast<char*>(static_cast<nsIRunnable
*>((NotificationPermissionRequest*)0x1000)) - reinterpret_cast
<char*>((NotificationPermissionRequest*)0x1000))}, {&
mozilla::detail::kImplementedIID<NotificationPermissionRequest
, nsINamed>, int32_t( reinterpret_cast<char*>(static_cast
<nsINamed*>((NotificationPermissionRequest*)0x1000)) - reinterpret_cast
<char*>((NotificationPermissionRequest*)0x1000))}, { nullptr
, 0 } } ; static_assert((sizeof(table) / sizeof(table[0])) >
1, "need at least 1 interface"); rv = NS_TableDrivenQI(static_cast
<void*>(this), aIID, aInstancePtr, table); if (((bool)(
__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) return rv; return
ContentPermissionRequestBase::QueryInterface(aIID, aInstancePtr
); }
487
488NS_IMETHODIMPnsresult
489NotificationPermissionRequest::Run() {
490 bool isSystem = mPrincipal->IsSystemPrincipal();
491 bool blocked = false;
492 if (isSystem) {
493 mPermission = NotificationPermission::Granted;
494 } else if (
495 mPrincipal->GetPrivateBrowsingId() != 0 &&
496 !StaticPrefs::
497 dom_webnotifications_privateBrowsing_enableDespiteLimitations()) {
498 mPermission = NotificationPermission::Denied;
499 blocked = true;
500 } else {
501 // File are automatically granted permission.
502
503 if (mPrincipal->SchemeIs("file")) {
504 mPermission = NotificationPermission::Granted;
505 } else if (!mWindow->IsSecureContext()) {
506 mPermission = NotificationPermission::Denied;
507 blocked = true;
508 nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
509 if (doc) {
510 nsContentUtils::ReportToConsole(
511 nsIScriptError::errorFlag, "DOM"_ns, doc,
512 nsContentUtils::eDOM_PROPERTIES,
513 "NotificationsInsecureRequestIsForbidden");
514 }
515 }
516 }
517
518 // We can't call ShowPrompt() directly here since our logic for determining
519 // whether to display a prompt depends on the checks above as well as the
520 // result of CheckPromptPrefs(). So we have to manually check the prompt
521 // prefs and decide what to do based on that.
522 PromptResult pr = CheckPromptPrefs();
523 switch (pr) {
524 case PromptResult::Granted:
525 mPermission = NotificationPermission::Granted;
526 break;
527 case PromptResult::Denied:
528 mPermission = NotificationPermission::Denied;
529 break;
530 default:
531 // ignore
532 break;
533 }
534
535 if (!mHasValidTransientUserGestureActivation &&
536 !StaticPrefs::dom_webnotifications_requireuserinteraction()) {
537 nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
538 if (doc) {
539 doc->WarnOnceAbout(Document::eNotificationsRequireUserGestureDeprecation);
540 }
541 }
542
543 // Check this after checking the prompt prefs to make sure this pref overrides
544 // those. We rely on this for testing purposes.
545 if (!isSystem && !blocked &&
546 !StaticPrefs::dom_webnotifications_allowcrossoriginiframe() &&
547 !mPrincipal->Subsumes(mTopLevelPrincipal)) {
548 mPermission = NotificationPermission::Denied;
549 blocked = true;
Value stored to 'blocked' is never read
550 nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
551 if (doc) {
552 nsContentUtils::ReportToConsole(
553 nsIScriptError::errorFlag, "DOM"_ns, doc,
554 nsContentUtils::eDOM_PROPERTIES,
555 "NotificationsCrossOriginIframeRequestIsForbidden");
556 }
557 }
558
559 if (mPermission != NotificationPermission::Default) {
560 return DispatchResolvePromise();
561 }
562
563 return nsContentPermissionUtils::AskPermission(this, mWindow);
564}
565
566NS_IMETHODIMPnsresult
567NotificationPermissionRequest::Cancel() {
568 // `Cancel` is called if the user denied permission or dismissed the
569 // permission request. To distinguish between the two, we set the
570 // permission to "default" and query the permission manager in
571 // `ResolvePromise`.
572 mPermission = NotificationPermission::Default;
573 return DispatchResolvePromise();
574}
575
576NS_IMETHODIMPnsresult
577NotificationPermissionRequest::Allow(JS::Handle<JS::Value> aChoices) {
578 MOZ_ASSERT(aChoices.isUndefined())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChoices.isUndefined())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aChoices.isUndefined()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aChoices.isUndefined()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 578); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChoices.isUndefined()"
")"); do { *((volatile int*)__null) = 578; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
579
580 mPermission = NotificationPermission::Granted;
581 return DispatchResolvePromise();
582}
583
584inline nsresult NotificationPermissionRequest::DispatchResolvePromise() {
585 nsCOMPtr<nsIRunnable> resolver =
586 NewRunnableMethod("NotificationPermissionRequest::DispatchResolvePromise",
587 this, &NotificationPermissionRequest::ResolvePromise);
588 return nsGlobalWindowInner::Cast(mWindow.get())->Dispatch(resolver.forget());
589}
590
591nsresult NotificationPermissionRequest::ResolvePromise() {
592 nsresult rv = NS_OK;
593 // This will still be "default" if the user dismissed the doorhanger,
594 // or "denied" otherwise.
595 if (mPermission == NotificationPermission::Default) {
596 // When the front-end has decided to deny the permission request
597 // automatically and we are not handling user input, then log a
598 // warning in the current document that this happened because
599 // Notifications require a user gesture.
600 if (!mHasValidTransientUserGestureActivation &&
601 StaticPrefs::dom_webnotifications_requireuserinteraction()) {
602 nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
603 if (doc) {
604 nsContentUtils::ReportToConsole(nsIScriptError::errorFlag, "DOM"_ns,
605 doc, nsContentUtils::eDOM_PROPERTIES,
606 "NotificationsRequireUserGesture");
607 }
608 }
609
610 mPermission = Notification::TestPermission(mPrincipal);
611 }
612 if (mCallback) {
613 ErrorResult error;
614 RefPtr<NotificationPermissionCallback> callback(mCallback);
615 callback->Call(mPermission, error);
616 rv = error.StealNSResult();
617 }
618 mPromise->MaybeResolve(mPermission);
619 return rv;
620}
621
622// Observer that the alert service calls to do common tasks and/or dispatch to
623// the specific observer for the context e.g. main thread, worker, or service
624// worker.
625class NotificationObserver final : public nsIObserver {
626 public:
627 nsCOMPtr<nsIObserver> mObserver;
628 nsCOMPtr<nsIPrincipal> mPrincipal;
629 bool mInPrivateBrowsing;
630 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
631 NS_DECL_NSIOBSERVERvirtual nsresult Observe(nsISupports *aSubject, const char * aTopic
, const char16_t * aData) override;
632
633 NotificationObserver(nsIObserver* aObserver, nsIPrincipal* aPrincipal,
634 bool aInPrivateBrowsing)
635 : mObserver(aObserver),
636 mPrincipal(aPrincipal),
637 mInPrivateBrowsing(aInPrivateBrowsing) {
638 AssertIsOnMainThread();
639 MOZ_ASSERT(mObserver)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mObserver)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mObserver))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mObserver", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 639); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mObserver" ")"
); do { *((volatile int*)__null) = 639; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
640 MOZ_ASSERT(mPrincipal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mPrincipal))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("mPrincipal", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 640); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mPrincipal" ")"
); do { *((volatile int*)__null) = 640; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
641 }
642
643 protected:
644 virtual ~NotificationObserver() { AssertIsOnMainThread(); }
645
646 nsresult AdjustPushQuota(const char* aTopic);
647};
648
649NS_IMPL_ISUPPORTS(NotificationObserver, nsIObserver)MozExternalRefCountType NotificationObserver::AddRef(void) { static_assert
(!std::is_destructible_v<NotificationObserver>, "Reference-counted class "
"NotificationObserver" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 649); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
649; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("NotificationObserver" != nullptr)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!("NotificationObserver" != nullptr))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("\"NotificationObserver\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 649); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"NotificationObserver\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 649; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("NotificationObserver" " not thread-safe"); nsrefcnt
count = ++mRefCnt; NS_LogAddRef((this), (count), ("NotificationObserver"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
NotificationObserver::Release(void) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(int32_t(mRefCnt)
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 649); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 649
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("NotificationObserver" != nullptr)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!("NotificationObserver" != nullptr))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("\"NotificationObserver\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 649); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"NotificationObserver\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 649; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("NotificationObserver" " not thread-safe"); const
char* const nametmp = "NotificationObserver"; nsrefcnt count
= --mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (
count == 0) { mRefCnt = 1; delete (this); return 0; } return count
; } nsresult NotificationObserver::QueryInterface(const nsIID
& aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) {
NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 649); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<NotificationObserver, nsIObserver>, int32_t
( reinterpret_cast<char*>(static_cast<nsIObserver*>
((NotificationObserver*)0x1000)) - reinterpret_cast<char*>
((NotificationObserver*)0x1000))}, {&mozilla::detail::kImplementedIID
<NotificationObserver, nsISupports>, int32_t(reinterpret_cast
<char*>(static_cast<nsISupports*>( static_cast<
nsIObserver*>((NotificationObserver*)0x1000))) - reinterpret_cast
<char*>((NotificationObserver*)0x1000))}, { nullptr, 0 }
} ; static_assert((sizeof(table) / sizeof(table[0])) > 1,
"need at least 1 interface"); rv = NS_TableDrivenQI(static_cast
<void*>(this), aIID, aInstancePtr, table); return rv; }
650
651class MainThreadNotificationObserver : public nsIObserver {
652 public:
653 UniquePtr<NotificationRef> mNotificationRef;
654 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
655 NS_DECL_NSIOBSERVERvirtual nsresult Observe(nsISupports *aSubject, const char * aTopic
, const char16_t * aData) override;
656
657 explicit MainThreadNotificationObserver(UniquePtr<NotificationRef> aRef)
658 : mNotificationRef(std::move(aRef)) {
659 AssertIsOnMainThread();
660 }
661
662 protected:
663 virtual ~MainThreadNotificationObserver() { AssertIsOnMainThread(); }
664};
665
666NS_IMPL_ISUPPORTS(MainThreadNotificationObserver, nsIObserver)MozExternalRefCountType MainThreadNotificationObserver::AddRef
(void) { static_assert(!std::is_destructible_v<MainThreadNotificationObserver
>, "Reference-counted class " "MainThreadNotificationObserver"
" should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 666); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
666; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("MainThreadNotificationObserver" != nullptr)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("MainThreadNotificationObserver" != nullptr))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("\"MainThreadNotificationObserver\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 666); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"MainThreadNotificationObserver\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 666; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("MainThreadNotificationObserver" " not thread-safe"
); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), (
"MainThreadNotificationObserver"), (uint32_t)(sizeof(*this)))
; return count; } MozExternalRefCountType MainThreadNotificationObserver
::Release(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 666); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 666
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("MainThreadNotificationObserver" != nullptr)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("MainThreadNotificationObserver" != nullptr))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("\"MainThreadNotificationObserver\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 666); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"MainThreadNotificationObserver\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 666; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("MainThreadNotificationObserver" " not thread-safe"
); const char* const nametmp = "MainThreadNotificationObserver"
; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (
nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return
0; } return count; } nsresult MainThreadNotificationObserver
::QueryInterface(const nsIID& aIID, void** aInstancePtr) {
do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "QueryInterface requires a non-NULL destination!", "aInstancePtr"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 666); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<MainThreadNotificationObserver, nsIObserver
>, int32_t( reinterpret_cast<char*>(static_cast<nsIObserver
*>((MainThreadNotificationObserver*)0x1000)) - reinterpret_cast
<char*>((MainThreadNotificationObserver*)0x1000))}, {&
mozilla::detail::kImplementedIID<MainThreadNotificationObserver
, nsISupports>, int32_t(reinterpret_cast<char*>(static_cast
<nsISupports*>( static_cast<nsIObserver*>((MainThreadNotificationObserver
*)0x1000))) - reinterpret_cast<char*>((MainThreadNotificationObserver
*)0x1000))}, { nullptr, 0 } } ; static_assert((sizeof(table) /
sizeof(table[0])) > 1, "need at least 1 interface"); rv =
NS_TableDrivenQI(static_cast<void*>(this), aIID, aInstancePtr
, table); return rv; }
667
668NS_IMETHODIMPnsresult
669NotificationTask::Run() {
670 AssertIsOnMainThread();
671
672 // Get a pointer to notification before the notification takes ownership of
673 // the ref (it owns itself temporarily, with ShowInternal() and
674 // CloseInternal() passing on the ownership appropriately.)
675 Notification* notif = mNotificationRef->GetNotification();
676 notif->mTempRef.swap(mNotificationRef);
677 if (mAction == eShow) {
678 notif->ShowInternal();
679 } else if (mAction == eClose) {
680 notif->CloseInternal();
681 } else {
682 MOZ_CRASH("Invalid action")do { do { } while (false); MOZ_ReportCrash("" "Invalid action"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 682); AnnotateMozCrashReason("MOZ_CRASH(" "Invalid action" ")"
); do { *((volatile int*)__null) = 682; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
683 }
684
685 MOZ_ASSERT(!mNotificationRef)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mNotificationRef)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mNotificationRef))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mNotificationRef"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 685); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mNotificationRef"
")"); do { *((volatile int*)__null) = 685; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
686 return NS_OK;
687}
688
689// static
690bool Notification::PrefEnabled(JSContext* aCx, JSObject* aObj) {
691 return StaticPrefs::dom_webnotifications_enabled();
692}
693
694Notification::Notification(nsIGlobalObject* aGlobal, const nsAString& aID,
695 const nsAString& aTitle, const nsAString& aBody,
696 NotificationDirection aDir, const nsAString& aLang,
697 const nsAString& aTag, const nsAString& aIconUrl,
698 bool aRequireInteraction, bool aSilent,
699 nsTArray<uint32_t>&& aVibrate,
700 const NotificationBehavior& aBehavior)
701 : DOMEventTargetHelper(aGlobal),
702 mWorkerPrivate(nullptr),
703 mObserver(nullptr),
704 mID(aID),
705 mTitle(aTitle),
706 mBody(aBody),
707 mDir(aDir),
708 mLang(aLang),
709 mTag(aTag),
710 mIconUrl(aIconUrl),
711 mRequireInteraction(aRequireInteraction),
712 mSilent(aSilent),
713 mVibrate(std::move(aVibrate)),
714 mBehavior(aBehavior),
715 mData(JS::NullValue()),
716 mIsClosed(false),
717 mIsStored(false),
718 mTaskCount(0) {
719 if (!NS_IsMainThread()) {
720 mWorkerPrivate = GetCurrentThreadWorkerPrivate();
721 MOZ_ASSERT(mWorkerPrivate)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mWorkerPrivate)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mWorkerPrivate))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mWorkerPrivate"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 721); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWorkerPrivate"
")"); do { *((volatile int*)__null) = 721; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
722 }
723}
724
725nsresult Notification::MaybeObserveWindowFrozenOrDestroyed() {
726 // NOTE: Non-persistent notifications can also be opened from workers, but we
727 // don't care and nobody else cares. And it's not clear whether we even should
728 // do this for window at all, see
729 // https://github.com/whatwg/notifications/issues/204.
730 // TODO: Somehow extend GlobalTeardownObserver to deal with FROZEN_TOPIC?
731 if (!mWorkerPrivate) {
732 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
733 NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(obs)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "obs" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 733); return NS_ERROR_FAILURE; } } while (false)
;
734
735 nsresult rv = obs->AddObserver(this, DOM_WINDOW_DESTROYED_TOPIC"dom-window-destroyed", true);
736 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 736); return rv; } } while (false)
;
737
738 rv = obs->AddObserver(this, DOM_WINDOW_FROZEN_TOPIC"dom-window-frozen", true);
739 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 739); return rv; } } while (false)
;
740 }
741
742 return NS_OK;
743}
744
745void Notification::SetAlertName() {
746 AssertIsOnMainThread();
747 if (!mAlertName.IsEmpty()) {
748 return;
749 }
750
751 nsAutoString alertName;
752 nsresult rv = GetOrigin(GetPrincipal(), alertName);
753 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 753)
) {
754 return;
755 }
756
757 // Get the notification name that is unique per origin + tag/ID.
758 // The name of the alert is of the form origin#tag/ID.
759 alertName.Append('#');
760 if (!mTag.IsEmpty()) {
761 alertName.AppendLiteral("tag:");
762 alertName.Append(mTag);
763 } else {
764 alertName.AppendLiteral("notag:");
765 alertName.Append(mID);
766 }
767
768 mAlertName = alertName;
769}
770
771// May be called on any thread.
772// static
773already_AddRefed<Notification> Notification::Constructor(
774 const GlobalObject& aGlobal, const nsAString& aTitle,
775 const NotificationOptions& aOptions, ErrorResult& aRv) {
776 // FIXME(nsm): If the sticky flag is set, throw an error.
777 RefPtr<ServiceWorkerGlobalScope> scope;
778 UNWRAP_OBJECT(ServiceWorkerGlobalScope, aGlobal.Get(), scope)mozilla::dom::binding_detail::UnwrapObjectWithCrossOriginAsserts
< mozilla::dom::prototypes::id::ServiceWorkerGlobalScope, mozilla
::dom::ServiceWorkerGlobalScope_Binding::NativeType>(aGlobal
.Get(), scope)
;
779 if (scope) {
780 aRv.ThrowTypeError(
781 "Notification constructor cannot be used in ServiceWorkerGlobalScope. "
782 "Use registration.showNotification() instead.");
783 return nullptr;
784 }
785
786 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
787 RefPtr<Notification> notification =
788 CreateAndShow(aGlobal.Context(), global, aTitle, aOptions, u""_ns, aRv);
789 if (NS_WARN_IF(aRv.Failed())NS_warn_if_impl(aRv.Failed(), "aRv.Failed()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 789)
) {
790 return nullptr;
791 }
792 if (NS_WARN_IF(NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(notification
->MaybeObserveWindowFrozenOrDestroyed())), 0))), "NS_FAILED(notification->MaybeObserveWindowFrozenOrDestroyed())"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 793)
793 NS_FAILED(notification->MaybeObserveWindowFrozenOrDestroyed()))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(notification
->MaybeObserveWindowFrozenOrDestroyed())), 0))), "NS_FAILED(notification->MaybeObserveWindowFrozenOrDestroyed())"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 793)
) {
794 return nullptr;
795 }
796
797 // This is be ok since we are on the worker thread where this function will
798 // run to completion before the Notification has a chance to go away.
799 return notification.forget();
800}
801
802// static
803Result<already_AddRefed<Notification>, QMResult>
804Notification::ConstructFromFields(
805 nsIGlobalObject* aGlobal, const nsAString& aID, const nsAString& aTitle,
806 const nsAString& aDir, const nsAString& aLang, const nsAString& aBody,
807 const nsAString& aTag, const nsAString& aIcon, const nsAString& aData,
808 const nsAString& aServiceWorkerRegistrationScope) {
809 MOZ_ASSERT(aGlobal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGlobal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aGlobal))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aGlobal", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 809); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGlobal" ")"
); do { *((volatile int*)__null) = 809; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
810
811 RootedDictionary<NotificationOptions> options(RootingCx());
812 options.mDir = StringToEnum<NotificationDirection>(aDir).valueOr(
813 NotificationDirection::Auto);
814 options.mLang = aLang;
815 options.mBody = aBody;
816 options.mTag = aTag;
817 options.mIcon = aIcon;
818 IgnoredErrorResult rv;
819 RefPtr<Notification> notification =
820 CreateInternal(aGlobal, aID, aTitle, options, rv);
821 if (NS_WARN_IF(rv.Failed())NS_warn_if_impl(rv.Failed(), "rv.Failed()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 821)
) {
822 return Err(ToQMResult(NS_ERROR_FAILURE));
823 }
824
825 QM_TRY(notification->InitFromBase64(aData)){auto tryResult12 = (notification->InitFromBase64(aData));
static_assert(std::is_empty_v<typename decltype(tryResult12
)::ok_type>); if ((__builtin_expect(!!(tryResult12.isErr()
), 0))) { mozilla::dom::quota::HandleError("notification->InitFromBase64(aData)"
, tryResult12.inspectErr(), "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 825, mozilla::dom::quota::Severity::Error); return tryResult12
.propagateErr(); }}
;
826
827 notification->SetScope(aServiceWorkerRegistrationScope);
828
829 return notification.forget();
830}
831
832nsresult Notification::PersistNotification() {
833 AssertIsOnMainThread();
834
835 nsCOMPtr<nsINotificationStorage> notificationStorage =
836 GetNotificationStorage(IsInPrivateBrowsing());
837 if (NS_WARN_IF(!notificationStorage)NS_warn_if_impl(!notificationStorage, "!notificationStorage",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 837)
) {
838 return NS_ERROR_UNEXPECTED;
839 }
840
841 nsString origin;
842 nsresult rv = GetOrigin(GetPrincipal(), origin);
843 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 843)
) {
844 return rv;
845 }
846
847 nsString id;
848 GetID(id);
849
850 nsString alertName;
851 GetAlertName(alertName);
852
853 nsAutoString behavior;
854 if (!mBehavior.ToJSON(behavior)) {
855 return NS_ERROR_FAILURE;
856 }
857
858 rv = notificationStorage->Put(origin, id, mTitle, GetEnumString(mDir), mLang,
859 mBody, mTag, mIconUrl, alertName, mDataAsBase64,
860 behavior, mScope);
861
862 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
863 return rv;
864 }
865
866 SetStoredState(true);
867 return NS_OK;
868}
869
870void Notification::UnpersistNotification() {
871 AssertIsOnMainThread();
872 if (IsStored()) {
873 nsCOMPtr<nsINotificationStorage> notificationStorage =
874 GetNotificationStorage(IsInPrivateBrowsing());
875 if (notificationStorage) {
876 nsString origin;
877 nsresult rv = GetOrigin(GetPrincipal(), origin);
878 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
879 notificationStorage->Delete(origin, mID);
880 }
881 }
882 SetStoredState(false);
883 }
884}
885
886// https://notifications.spec.whatwg.org/#create-a-notification
887already_AddRefed<Notification> Notification::CreateInternal(
888 nsIGlobalObject* aGlobal, const nsAString& aID, const nsAString& aTitle,
889 const NotificationOptions& aOptions, ErrorResult& aRv) {
890 nsresult rv;
891 nsString id;
892 if (!aID.IsEmpty()) {
893 id = aID;
894 } else {
895 nsCOMPtr<nsIUUIDGenerator> uuidgen =
896 do_GetService("@mozilla.org/uuid-generator;1");
897 NS_ENSURE_TRUE(uuidgen, nullptr)do { if ((__builtin_expect(!!(!(uuidgen)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "uuidgen" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 897); return nullptr; } } while (false)
;
898 nsID uuid;
899 rv = uuidgen->GenerateUUIDInPlace(&uuid);
900 NS_ENSURE_SUCCESS(rv, nullptr)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "nullptr", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 900); return nullptr; } } while (false)
;
901
902 char buffer[NSID_LENGTH39];
903 uuid.ToProvidedString(buffer);
904 NS_ConvertASCIItoUTF16 convertedID(buffer);
905 id = convertedID;
906 }
907
908 // Step 20: Set notification’s silent preference to options["silent"].
909 bool silent = false;
910 if (StaticPrefs::dom_webnotifications_silent_enabled()) {
911 silent = aOptions.mSilent;
912 }
913
914 nsTArray<uint32_t> vibrate;
915 if (StaticPrefs::dom_webnotifications_vibrate_enabled() &&
916 aOptions.mVibrate.WasPassed()) {
917 // Step 4: If options["silent"] is true and options["vibrate"] exists, then
918 // throw a TypeError.
919 if (silent) {
920 aRv.ThrowTypeError(
921 "Silent notifications must not specify vibration patterns.");
922 return nullptr;
923 }
924
925 // Step 17: If options["vibrate"] exists, then validate and normalize it and
926 // set notification’s vibration pattern to the return value.
927 const OwningUnsignedLongOrUnsignedLongSequence& value =
928 aOptions.mVibrate.Value();
929 if (value.IsUnsignedLong()) {
930 AutoTArray<uint32_t, 1> array;
931 array.AppendElement(value.GetAsUnsignedLong());
932 vibrate = SanitizeVibratePattern(array);
933 } else {
934 vibrate = SanitizeVibratePattern(value.GetAsUnsignedLongSequence());
935 }
936 }
937
938 // Step 15: If options["icon"] exists, then parse it using baseURL, and if
939 // that does not return failure, set notification’s icon URL to the return
940 // value. (Otherwise icon URL is not set.)
941 nsString iconUrl = aOptions.mIcon;
942 NotificationBehavior behavior{aOptions.mMozbehavior};
943 ResolveIconAndSoundURL(aGlobal, iconUrl, behavior.mSoundFile);
944
945 RefPtr<Notification> notification = new Notification(
946 aGlobal, id, aTitle, aOptions.mBody, aOptions.mDir, aOptions.mLang,
947 aOptions.mTag, iconUrl, aOptions.mRequireInteraction, silent,
948 std::move(vibrate), behavior);
949 return notification.forget();
950}
951
952Notification::~Notification() {
953 mozilla::DropJSObjects(this);
954 AssertIsOnTargetThread();
955 MOZ_ASSERT(!mWorkerRef)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mWorkerRef)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mWorkerRef))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!mWorkerRef", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 955); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mWorkerRef"
")"); do { *((volatile int*)__null) = 955; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
956 MOZ_ASSERT(!mTempRef)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mTempRef)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mTempRef))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!mTempRef", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 956); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mTempRef" ")"
); do { *((volatile int*)__null) = 956; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
957}
958
959NS_IMPL_CYCLE_COLLECTION_CLASS(Notification)Notification::cycleCollection Notification::_cycleCollectorGlobal
;
960NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Notification,void Notification::cycleCollection::Unlink(void* p) { Notification
* tmp = DowncastCCParticipant<Notification>(p); nsISupports
* s = static_cast<nsISupports*>(p); DOMEventTargetHelper
::cycleCollection::Unlink(s);
961 DOMEventTargetHelper)void Notification::cycleCollection::Unlink(void* p) { Notification
* tmp = DowncastCCParticipant<Notification>(p); nsISupports
* s = static_cast<nsISupports*>(p); DOMEventTargetHelper
::cycleCollection::Unlink(s);
962 tmp->mData.setUndefined();
963 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCEtmp->ClearWeakReferences();
964NS_IMPL_CYCLE_COLLECTION_UNLINK_END(void)tmp; }
965
966NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Notification,nsresult Notification::cycleCollection::TraverseNative( void*
p, nsCycleCollectionTraversalCallback& cb) { Notification
* tmp = DowncastCCParticipant<Notification>(p); nsISupports
* s = static_cast<nsISupports*>(p); if (DOMEventTargetHelper
::cycleCollection::TraverseNative(s, cb) == NS_SUCCESS_INTERRUPTED_TRAVERSE
) { return NS_SUCCESS_INTERRUPTED_TRAVERSE; }
967 DOMEventTargetHelper)nsresult Notification::cycleCollection::TraverseNative( void*
p, nsCycleCollectionTraversalCallback& cb) { Notification
* tmp = DowncastCCParticipant<Notification>(p); nsISupports
* s = static_cast<nsISupports*>(p); if (DOMEventTargetHelper
::cycleCollection::TraverseNative(s, cb) == NS_SUCCESS_INTERRUPTED_TRAVERSE
) { return NS_SUCCESS_INTERRUPTED_TRAVERSE; }
968NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END(void)tmp; return NS_OK; }
969
970NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(Notification,void Notification::cycleCollection::Trace( void* p, const TraceCallbacks
& aCallbacks, void* aClosure) { Notification* tmp = DowncastCCParticipant
<Notification>(p); nsISupports* s = static_cast<nsISupports
*>(p); DOMEventTargetHelper::cycleCollection::Trace(s, aCallbacks
, aClosure);
971 DOMEventTargetHelper)void Notification::cycleCollection::Trace( void* p, const TraceCallbacks
& aCallbacks, void* aClosure) { Notification* tmp = DowncastCCParticipant
<Notification>(p); nsISupports* s = static_cast<nsISupports
*>(p); DOMEventTargetHelper::cycleCollection::Trace(s, aCallbacks
, aClosure);
972 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mData)aCallbacks.Trace(&tmp->mData, "mData", aClosure);
973NS_IMPL_CYCLE_COLLECTION_TRACE_END(void)tmp; }
974
975NS_IMPL_ADDREF_INHERITED(Notification, DOMEventTargetHelper)MozExternalRefCountType Notification::AddRef(void) { static_assert
(!std::is_destructible_v<Notification>, "Reference-counted class "
"Notification" " should not have a public destructor. " "Make this class's destructor non-public"
); nsrefcnt r = DOMEventTargetHelper::AddRef(); if constexpr (
::mozilla::detail::ShouldLogInheritedRefcnt<Notification>
) { NS_LogAddRef((this), (r), ("Notification"), (uint32_t)(sizeof
(*this))); } return r; }
976NS_IMPL_RELEASE_INHERITED(Notification, DOMEventTargetHelper)MozExternalRefCountType Notification::Release(void) { nsrefcnt
r = DOMEventTargetHelper::Release(); if constexpr (::mozilla
::detail::ShouldLogInheritedRefcnt<Notification>) { NS_LogRelease
((this), (r), ("Notification")); } return r; }
977
978NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Notification)nsresult Notification::QueryInterface(const nsIID& aIID, void
** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak(
NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 978); MOZ_PretendNoReturn(); } } while (0); nsISupports* foundInterface
; if (TopThreeWordsEquals( aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID), (nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID)) && (LowWordEquals(aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID)) || LowWordEquals(aIID, (nsCycleCollectionISupports::COMTypeInfo
<nsCycleCollectionISupports, void>::kIID)))) { if (LowWordEquals
(aIID, (nsXPCOMCycleCollectionParticipant::COMTypeInfo<nsXPCOMCycleCollectionParticipant
, void>::kIID))) { *aInstancePtr = Notification::cycleCollection
::GetParticipant(); return NS_OK; } if (LowWordEquals(aIID, (
nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID))) { *aInstancePtr = Notification::cycleCollection
::Upcast(this); return NS_OK; } foundInterface = nullptr; } else
979 NS_INTERFACE_MAP_ENTRY(nsIObserver)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIObserver>)) foundInterface = static_cast
<nsIObserver*>(this); else
980 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupportsWeakReference>)) foundInterface
= static_cast<nsISupportsWeakReference*>(this); else
981NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)foundInterface = 0; nsresult status; if (!foundInterface) status
= DOMEventTargetHelper::QueryInterface(aIID, (void**)&foundInterface
); else { (foundInterface)->AddRef(); status = NS_OK; } *aInstancePtr
= foundInterface; return status; }
982
983nsIPrincipal* Notification::GetPrincipal() {
984 AssertIsOnMainThread();
985 if (mWorkerPrivate) {
986 return mWorkerPrivate->GetPrincipal();
987 }
988 nsGlobalWindowInner* win = GetOwnerWindow();
989 NS_ENSURE_TRUE(win, nullptr)do { if ((__builtin_expect(!!(!(win)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "win" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 989); return nullptr; } } while (false)
;
990 return win->GetPrincipal();
991}
992
993class WorkerNotificationObserver final : public MainThreadNotificationObserver {
994 public:
995 NS_INLINE_DECL_REFCOUNTING_INHERITED(WorkerNotificationObserver,virtual MozExternalRefCountType AddRef() override { static_assert
(!std::is_destructible_v<WorkerNotificationObserver>, "Reference-counted class "
"WorkerNotificationObserver" " should not have a public destructor. "
"Make this class's destructor non-public"); nsrefcnt r = MainThreadNotificationObserver
::AddRef(); if constexpr (::mozilla::detail::ShouldLogInheritedRefcnt
<WorkerNotificationObserver>) { NS_LogAddRef((this), (r
), ("WorkerNotificationObserver"), (uint32_t)(sizeof(*this)))
; } return r; } virtual MozExternalRefCountType Release() override
{ nsrefcnt r = MainThreadNotificationObserver::Release(); if
constexpr (::mozilla::detail::ShouldLogInheritedRefcnt<WorkerNotificationObserver
>) { NS_LogRelease((this), (r), ("WorkerNotificationObserver"
)); } return r; }
996 MainThreadNotificationObserver)virtual MozExternalRefCountType AddRef() override { static_assert
(!std::is_destructible_v<WorkerNotificationObserver>, "Reference-counted class "
"WorkerNotificationObserver" " should not have a public destructor. "
"Make this class's destructor non-public"); nsrefcnt r = MainThreadNotificationObserver
::AddRef(); if constexpr (::mozilla::detail::ShouldLogInheritedRefcnt
<WorkerNotificationObserver>) { NS_LogAddRef((this), (r
), ("WorkerNotificationObserver"), (uint32_t)(sizeof(*this)))
; } return r; } virtual MozExternalRefCountType Release() override
{ nsrefcnt r = MainThreadNotificationObserver::Release(); if
constexpr (::mozilla::detail::ShouldLogInheritedRefcnt<WorkerNotificationObserver
>) { NS_LogRelease((this), (r), ("WorkerNotificationObserver"
)); } return r; }
997 NS_DECL_NSIOBSERVERvirtual nsresult Observe(nsISupports *aSubject, const char * aTopic
, const char16_t * aData) override;
998
999 explicit WorkerNotificationObserver(UniquePtr<NotificationRef> aRef)
1000 : MainThreadNotificationObserver(std::move(aRef)) {
1001 AssertIsOnMainThread();
1002 MOZ_ASSERT(mNotificationRef->GetNotification()->mWorkerPrivate)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mNotificationRef->GetNotification()->mWorkerPrivate
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mNotificationRef->GetNotification()->mWorkerPrivate
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mNotificationRef->GetNotification()->mWorkerPrivate", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1002); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mNotificationRef->GetNotification()->mWorkerPrivate"
")"); do { *((volatile int*)__null) = 1002; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1003 }
1004
1005 void ForgetNotification() {
1006 AssertIsOnMainThread();
1007 mNotificationRef->Forget();
1008 }
1009
1010 protected:
1011 virtual ~WorkerNotificationObserver() {
1012 AssertIsOnMainThread();
1013
1014 MOZ_ASSERT(mNotificationRef)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mNotificationRef)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mNotificationRef))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mNotificationRef"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1014); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mNotificationRef"
")"); do { *((volatile int*)__null) = 1014; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1015 Notification* notification = mNotificationRef->GetNotification();
1016 if (notification) {
1017 notification->mObserver = nullptr;
1018 }
1019 }
1020};
1021
1022class ServiceWorkerNotificationObserver final : public nsIObserver {
1023 public:
1024 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
1025 NS_DECL_NSIOBSERVERvirtual nsresult Observe(nsISupports *aSubject, const char * aTopic
, const char16_t * aData) override;
1026
1027 ServiceWorkerNotificationObserver(
1028 const nsAString& aScope, nsIPrincipal* aPrincipal, const nsAString& aID,
1029 const nsAString& aTitle, NotificationDirection aDir,
1030 const nsAString& aLang, const nsAString& aBody, const nsAString& aTag,
1031 const nsAString& aIcon, const nsAString& aData,
1032 const nsAString& aBehavior)
1033 : mScope(aScope),
1034 mID(aID),
1035 mPrincipal(aPrincipal),
1036 mTitle(aTitle),
1037 mDir(aDir),
1038 mLang(aLang),
1039 mBody(aBody),
1040 mTag(aTag),
1041 mIcon(aIcon),
1042 mData(aData),
1043 mBehavior(aBehavior) {
1044 AssertIsOnMainThread();
1045 MOZ_ASSERT(aPrincipal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPrincipal))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aPrincipal", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1045); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPrincipal"
")"); do { *((volatile int*)__null) = 1045; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1046 }
1047
1048 private:
1049 ~ServiceWorkerNotificationObserver() = default;
1050
1051 const nsString mScope;
1052 const nsString mID;
1053 nsCOMPtr<nsIPrincipal> mPrincipal;
1054 const nsString mTitle;
1055 const NotificationDirection mDir;
1056 const nsString mLang;
1057 const nsString mBody;
1058 const nsString mTag;
1059 const nsString mIcon;
1060 const nsString mData;
1061 const nsString mBehavior;
1062};
1063
1064NS_IMPL_ISUPPORTS(ServiceWorkerNotificationObserver, nsIObserver)MozExternalRefCountType ServiceWorkerNotificationObserver::AddRef
(void) { static_assert(!std::is_destructible_v<ServiceWorkerNotificationObserver
>, "Reference-counted class " "ServiceWorkerNotificationObserver"
" should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1064); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
1064; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("ServiceWorkerNotificationObserver" != nullptr)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("ServiceWorkerNotificationObserver" != nullptr))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("\"ServiceWorkerNotificationObserver\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1064); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"ServiceWorkerNotificationObserver\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 1064; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("ServiceWorkerNotificationObserver" " not thread-safe"
); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), (
"ServiceWorkerNotificationObserver"), (uint32_t)(sizeof(*this
))); return count; } MozExternalRefCountType ServiceWorkerNotificationObserver
::Release(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1064); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 1064
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("ServiceWorkerNotificationObserver" != nullptr)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("ServiceWorkerNotificationObserver" != nullptr))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("\"ServiceWorkerNotificationObserver\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1064); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"ServiceWorkerNotificationObserver\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 1064; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("ServiceWorkerNotificationObserver" " not thread-safe"
); const char* const nametmp = "ServiceWorkerNotificationObserver"
; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (
nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return
0; } return count; } nsresult ServiceWorkerNotificationObserver
::QueryInterface(const nsIID& aIID, void** aInstancePtr) {
do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "QueryInterface requires a non-NULL destination!", "aInstancePtr"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1064); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<ServiceWorkerNotificationObserver, nsIObserver
>, int32_t( reinterpret_cast<char*>(static_cast<nsIObserver
*>((ServiceWorkerNotificationObserver*)0x1000)) - reinterpret_cast
<char*>((ServiceWorkerNotificationObserver*)0x1000))}, {
&mozilla::detail::kImplementedIID<ServiceWorkerNotificationObserver
, nsISupports>, int32_t(reinterpret_cast<char*>(static_cast
<nsISupports*>( static_cast<nsIObserver*>((ServiceWorkerNotificationObserver
*)0x1000))) - reinterpret_cast<char*>((ServiceWorkerNotificationObserver
*)0x1000))}, { nullptr, 0 } } ; static_assert((sizeof(table) /
sizeof(table[0])) > 1, "need at least 1 interface"); rv =
NS_TableDrivenQI(static_cast<void*>(this), aIID, aInstancePtr
, table); return rv; }
1065
1066bool Notification::DispatchClickEvent() {
1067 AssertIsOnTargetThread();
1068 RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
1069 event->InitEvent(u"click"_ns, false, true);
1070 event->SetTrusted(true);
1071 WantsPopupControlCheck popupControlCheck(event);
1072 return DispatchEvent(*event, CallerType::System, IgnoreErrors());
1073}
1074
1075// Overrides dispatch and run handlers so we can directly dispatch from main
1076// thread to child workers.
1077class NotificationClickWorkerRunnable final
1078 : public NotificationWorkerRunnable {
1079 Notification* mNotification;
1080 // Optional window that gets focused if click event is not
1081 // preventDefault()ed.
1082 nsMainThreadPtrHandle<nsPIDOMWindowInner> mWindow;
1083
1084 public:
1085 NotificationClickWorkerRunnable(
1086 Notification* aNotification,
1087 const nsMainThreadPtrHandle<nsPIDOMWindowInner>& aWindow)
1088 : NotificationWorkerRunnable(aNotification->mWorkerPrivate,
1089 "NotificationClickWorkerRunnable"),
1090 mNotification(aNotification),
1091 mWindow(aWindow) {
1092 MOZ_ASSERT_IF(mNotification->mWorkerPrivate->IsServiceWorker(), !mWindow)do { if (mNotification->mWorkerPrivate->IsServiceWorker
()) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(!mWindow)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mWindow))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!mWindow", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1092); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mWindow" ")"
); do { *((volatile int*)__null) = 1092; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1093 }
1094
1095 void WorkerRunInternal(WorkerPrivate* aWorkerPrivate) override {
1096 bool doDefaultAction = mNotification->DispatchClickEvent();
1097 MOZ_ASSERT_IF(mNotification->mWorkerPrivate->IsServiceWorker(),do { if (mNotification->mWorkerPrivate->IsServiceWorker
()) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(!doDefaultAction)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!doDefaultAction))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!doDefaultAction"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1098); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!doDefaultAction"
")"); do { *((volatile int*)__null) = 1098; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1098 !doDefaultAction)do { if (mNotification->mWorkerPrivate->IsServiceWorker
()) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(!doDefaultAction)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!doDefaultAction))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!doDefaultAction"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1098); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!doDefaultAction"
")"); do { *((volatile int*)__null) = 1098; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1099 if (doDefaultAction) {
1100 RefPtr<FocusWindowRunnable> r = new FocusWindowRunnable(mWindow);
1101 mNotification->mWorkerPrivate->DispatchToMainThread(r.forget());
1102 }
1103 }
1104};
1105
1106NS_IMETHODIMPnsresult
1107NotificationObserver::Observe(nsISupports* aSubject, const char* aTopic,
1108 const char16_t* aData) {
1109 AssertIsOnMainThread();
1110
1111 if (!strcmp("alertdisablecallback", aTopic)) {
1112 if (XRE_IsParentProcess()) {
1113 return Notification::RemovePermission(mPrincipal);
1114 }
1115 // Permissions can't be removed from the content process. Send a message
1116 // to the parent; `ContentParent::RecvDisableNotifications` will call
1117 // `RemovePermission`.
1118 ContentChild::GetSingleton()->SendDisableNotifications(mPrincipal);
1119 return NS_OK;
1120 } else if (!strcmp("alertsettingscallback", aTopic)) {
1121 if (XRE_IsParentProcess()) {
1122 return Notification::OpenSettings(mPrincipal);
1123 }
1124 // `ContentParent::RecvOpenNotificationSettings` notifies observers in the
1125 // parent process.
1126 ContentChild::GetSingleton()->SendOpenNotificationSettings(mPrincipal);
1127 return NS_OK;
1128 } else if (!strcmp("alertshow", aTopic) || !strcmp("alertfinished", aTopic)) {
1129 Unused << NS_WARN_IF(NS_FAILED(AdjustPushQuota(aTopic)))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(AdjustPushQuota
(aTopic))), 0))), "NS_FAILED(AdjustPushQuota(aTopic))", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1129)
;
1130 }
1131
1132 return mObserver->Observe(aSubject, aTopic, aData);
1133}
1134
1135nsresult NotificationObserver::AdjustPushQuota(const char* aTopic) {
1136 nsCOMPtr<nsIPushQuotaManager> pushQuotaManager =
1137 do_GetService("@mozilla.org/push/Service;1");
1138 if (!pushQuotaManager) {
1139 return NS_ERROR_FAILURE;
1140 }
1141
1142 nsAutoCString origin;
1143 nsresult rv = mPrincipal->GetOrigin(origin);
1144 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1145 return rv;
1146 }
1147
1148 if (!strcmp("alertshow", aTopic)) {
1149 return pushQuotaManager->NotificationForOriginShown(origin.get());
1150 }
1151 return pushQuotaManager->NotificationForOriginClosed(origin.get());
1152}
1153
1154// MOZ_CAN_RUN_SCRIPT_BOUNDARY until Runnable::Run is MOZ_CAN_RUN_SCRIPT. See
1155// bug 1539845.
1156MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMPnsresult
1157MainThreadNotificationObserver::Observe(nsISupports* aSubject,
1158 const char* aTopic,
1159 const char16_t* aData) {
1160 AssertIsOnMainThread();
1161 MOZ_ASSERT(mNotificationRef)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mNotificationRef)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mNotificationRef))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mNotificationRef"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1161); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mNotificationRef"
")"); do { *((volatile int*)__null) = 1161; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1162 Notification* notification = mNotificationRef->GetNotification();
1163 MOZ_ASSERT(notification)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(notification)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(notification))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("notification", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1163); AnnotateMozCrashReason("MOZ_ASSERT" "(" "notification"
")"); do { *((volatile int*)__null) = 1163; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1164 if (!strcmp("alertclickcallback", aTopic)) {
1165 nsCOMPtr<nsPIDOMWindowInner> window = notification->GetOwnerWindow();
1166 if (NS_WARN_IF(!window || !window->IsCurrentInnerWindow())NS_warn_if_impl(!window || !window->IsCurrentInnerWindow()
, "!window || !window->IsCurrentInnerWindow()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1166)
) {
1167 // Window has been closed, this observer is not valid anymore
1168 return NS_ERROR_FAILURE;
1169 }
1170
1171 bool doDefaultAction = notification->DispatchClickEvent();
1172 if (doDefaultAction) {
1173 nsCOMPtr<nsPIDOMWindowOuter> outerWindow = window->GetOuterWindow();
1174 nsFocusManager::FocusWindow(outerWindow, CallerType::System);
1175 }
1176 } else if (!strcmp("alertfinished", aTopic)) {
1177 notification->UnpersistNotification();
1178 notification->mIsClosed = true;
1179 notification->DispatchTrustedEvent(u"close"_ns);
1180 } else if (!strcmp("alertshow", aTopic)) {
1181 notification->DispatchTrustedEvent(u"show"_ns);
1182 }
1183 return NS_OK;
1184}
1185
1186NS_IMETHODIMPnsresult
1187WorkerNotificationObserver::Observe(nsISupports* aSubject, const char* aTopic,
1188 const char16_t* aData) {
1189 AssertIsOnMainThread();
1190 MOZ_ASSERT(mNotificationRef)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mNotificationRef)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mNotificationRef))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mNotificationRef"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1190); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mNotificationRef"
")"); do { *((volatile int*)__null) = 1190; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1191 // For an explanation of why it is OK to pass this rawptr to the event
1192 // runnables, see the Notification class comment.
1193 Notification* notification = mNotificationRef->GetNotification();
1194 // We can't assert notification here since the feature could've unset it.
1195 if (NS_WARN_IF(!notification)NS_warn_if_impl(!notification, "!notification", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1195)
) {
1196 return NS_ERROR_FAILURE;
1197 }
1198
1199 MOZ_ASSERT(notification->mWorkerPrivate)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(notification->mWorkerPrivate)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(notification->mWorkerPrivate
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"notification->mWorkerPrivate", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1199); AnnotateMozCrashReason("MOZ_ASSERT" "(" "notification->mWorkerPrivate"
")"); do { *((volatile int*)__null) = 1199; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1200
1201 RefPtr<WorkerThreadRunnable> r;
1202 if (!strcmp("alertclickcallback", aTopic)) {
1203 nsPIDOMWindowInner* window = nullptr;
1204 if (!notification->mWorkerPrivate->IsServiceWorker()) {
1205 WorkerPrivate* top = notification->mWorkerPrivate;
1206 while (top->GetParent()) {
1207 top = top->GetParent();
1208 }
1209
1210 window = top->GetWindow();
1211 if (NS_WARN_IF(!window || !window->IsCurrentInnerWindow())NS_warn_if_impl(!window || !window->IsCurrentInnerWindow()
, "!window || !window->IsCurrentInnerWindow()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1211)
) {
1212 // Window has been closed, this observer is not valid anymore
1213 return NS_ERROR_FAILURE;
1214 }
1215 }
1216
1217 // Instead of bothering with adding features and other worker lifecycle
1218 // management, we simply hold strongrefs to the window and document.
1219 nsMainThreadPtrHandle<nsPIDOMWindowInner> windowHandle(
1220 new nsMainThreadPtrHolder<nsPIDOMWindowInner>(
1221 "WorkerNotificationObserver::Observe::nsPIDOMWindowInner", window));
1222
1223 r = new NotificationClickWorkerRunnable(notification, windowHandle);
1224 } else if (!strcmp("alertfinished", aTopic)) {
1225 notification->UnpersistNotification();
1226 notification->mIsClosed = true;
1227 r = new NotificationEventWorkerRunnable(notification, u"close"_ns);
1228 } else if (!strcmp("alertshow", aTopic)) {
1229 r = new NotificationEventWorkerRunnable(notification, u"show"_ns);
1230 }
1231
1232 MOZ_ASSERT(r)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(r)>::isValid, "invalid assertion condition"); if (
(__builtin_expect(!!(!(!!(r))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("r", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1232); AnnotateMozCrashReason("MOZ_ASSERT" "(" "r" ")"); do
{ *((volatile int*)__null) = 1232; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
1233 if (!r->Dispatch(notification->mWorkerPrivate)) {
1234 NS_WARNING("Could not dispatch event to worker notification")NS_DebugBreak(NS_DEBUG_WARNING, "Could not dispatch event to worker notification"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1234)
;
1235 }
1236 return NS_OK;
1237}
1238
1239NS_IMETHODIMPnsresult
1240ServiceWorkerNotificationObserver::Observe(nsISupports* aSubject,
1241 const char* aTopic,
1242 const char16_t* aData) {
1243 AssertIsOnMainThread();
1244
1245 nsAutoCString originSuffix;
1246 nsresult rv = mPrincipal->GetOriginSuffix(originSuffix);
1247 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1247)
) {
1248 return rv;
1249 }
1250
1251 if (!strcmp("alertclickcallback", aTopic)) {
1252 if (XRE_IsParentProcess()) {
1253 nsCOMPtr<nsIServiceWorkerManager> swm =
1254 mozilla::components::ServiceWorkerManager::Service();
1255 if (NS_WARN_IF(!swm)NS_warn_if_impl(!swm, "!swm", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1255)
) {
1256 return NS_ERROR_FAILURE;
1257 }
1258
1259 rv = swm->SendNotificationClickEvent(
1260 originSuffix, NS_ConvertUTF16toUTF8(mScope), mID, mTitle,
1261 NS_ConvertASCIItoUTF16(GetEnumString(mDir)), mLang, mBody, mTag,
1262 mIcon, mData, mBehavior);
1263 Unused << NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1263)
;
1264 } else {
1265 auto* cc = ContentChild::GetSingleton();
1266 NotificationEventData data(originSuffix, NS_ConvertUTF16toUTF8(mScope),
1267 mID, mTitle,
1268 NS_ConvertASCIItoUTF16(GetEnumString(mDir)),
1269 mLang, mBody, mTag, mIcon, mData, mBehavior);
1270 Unused << cc->SendNotificationEvent(u"click"_ns, data);
1271 }
1272 return NS_OK;
1273 }
1274
1275 if (!strcmp("alertfinished", aTopic)) {
1276 nsString origin;
1277 nsresult rv = Notification::GetOrigin(mPrincipal, origin);
1278 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1278)
) {
1279 return rv;
1280 }
1281
1282 // Remove closed or dismissed persistent notifications.
1283 nsCOMPtr<nsINotificationStorage> notificationStorage =
1284 GetNotificationStorage(mPrincipal->GetPrivateBrowsingId() != 0);
1285 if (notificationStorage) {
1286 notificationStorage->Delete(origin, mID);
1287 }
1288
1289 if (XRE_IsParentProcess()) {
1290 nsCOMPtr<nsIServiceWorkerManager> swm =
1291 mozilla::components::ServiceWorkerManager::Service();
1292 if (NS_WARN_IF(!swm)NS_warn_if_impl(!swm, "!swm", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1292)
) {
1293 return NS_ERROR_FAILURE;
1294 }
1295
1296 rv = swm->SendNotificationCloseEvent(
1297 originSuffix, NS_ConvertUTF16toUTF8(mScope), mID, mTitle,
1298 NS_ConvertASCIItoUTF16(GetEnumString(mDir)), mLang, mBody, mTag,
1299 mIcon, mData, mBehavior);
1300 Unused << NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1300)
;
1301 } else {
1302 auto* cc = ContentChild::GetSingleton();
1303 NotificationEventData data(originSuffix, NS_ConvertUTF16toUTF8(mScope),
1304 mID, mTitle,
1305 NS_ConvertASCIItoUTF16(GetEnumString(mDir)),
1306 mLang, mBody, mTag, mIcon, mData, mBehavior);
1307 Unused << cc->SendNotificationEvent(u"close"_ns, data);
1308 }
1309 return NS_OK;
1310 }
1311
1312 return NS_OK;
1313}
1314
1315bool Notification::IsInPrivateBrowsing() {
1316 AssertIsOnMainThread();
1317
1318 Document* doc = nullptr;
1319
1320 if (mWorkerPrivate) {
1321 doc = mWorkerPrivate->GetDocument();
1322 } else if (nsGlobalWindowInner* win = GetOwnerWindow()) {
1323 doc = win->GetExtantDoc();
1324 }
1325
1326 if (doc) {
1327 nsCOMPtr<nsILoadContext> loadContext = doc->GetLoadContext();
1328 return loadContext && loadContext->UsePrivateBrowsing();
1329 }
1330
1331 if (mWorkerPrivate) {
1332 // Not all workers may have a document, but with Bug 1107516 fixed, they
1333 // should all have a loadcontext.
1334 nsCOMPtr<nsILoadGroup> loadGroup = mWorkerPrivate->GetLoadGroup();
1335 nsCOMPtr<nsILoadContext> loadContext;
1336 NS_QueryNotificationCallbacks(nullptr, loadGroup,
1337 NS_GET_IID(nsILoadContext)(nsILoadContext::COMTypeInfo<nsILoadContext, void>::kIID
)
,
1338 getter_AddRefs(loadContext));
1339 return loadContext && loadContext->UsePrivateBrowsing();
1340 }
1341
1342 // XXXnsm Should this default to true?
1343 return false;
1344}
1345
1346// Step 4 of
1347// https://notifications.spec.whatwg.org/#dom-notification-notification
1348void Notification::ShowInternal() {
1349 AssertIsOnMainThread();
1350 MOZ_ASSERT(mTempRef,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTempRef)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mTempRef))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mTempRef" " (" "Notification should take ownership of itself before"
"calling ShowInternal!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1352); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTempRef" ") ("
"Notification should take ownership of itself before" "calling ShowInternal!"
")"); do { *((volatile int*)__null) = 1352; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1351 "Notification should take ownership of itself before"do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTempRef)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mTempRef))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mTempRef" " (" "Notification should take ownership of itself before"
"calling ShowInternal!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1352); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTempRef" ") ("
"Notification should take ownership of itself before" "calling ShowInternal!"
")"); do { *((volatile int*)__null) = 1352; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1352 "calling ShowInternal!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTempRef)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mTempRef))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mTempRef" " (" "Notification should take ownership of itself before"
"calling ShowInternal!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1352); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTempRef" ") ("
"Notification should take ownership of itself before" "calling ShowInternal!"
")"); do { *((volatile int*)__null) = 1352; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1353 // A notification can only have one observer and one call to ShowInternal.
1354 MOZ_ASSERT(!mObserver)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mObserver)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mObserver))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!mObserver", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1354); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mObserver"
")"); do { *((volatile int*)__null) = 1354; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1355
1356 // Transfer ownership to local scope so we can either release it at the end
1357 // of this function or transfer it to the observer.
1358 UniquePtr<NotificationRef> ownership;
1359 std::swap(ownership, mTempRef);
1360 MOZ_ASSERT(ownership->GetNotification() == this)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ownership->GetNotification() == this)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(ownership->GetNotification() == this))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("ownership->GetNotification() == this"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1360); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ownership->GetNotification() == this"
")"); do { *((volatile int*)__null) = 1360; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1361
1362 nsCOMPtr<nsIAlertsService> alertService = components::Alerts::Service();
1363
1364 // Step 4.1: If the result of getting the notifications permission state is
1365 // not "granted", then queue a task to fire an event named error on this, and
1366 // abort these steps.
1367 //
1368 // XXX(krosylight): But this function is also triggered by
1369 // Notification::ShowPersistentNotification which already does its own
1370 // permission check. Can we split this?
1371 ErrorResult result;
1372 NotificationPermission permission = NotificationPermission::Denied;
1373 if (mWorkerPrivate) {
1374 permission = GetPermissionInternal(mWorkerPrivate->GetPrincipal(), result);
1375 } else {
1376 permission = GetPermissionInternal(GetOwnerWindow(), result);
1377 }
1378 // We rely on GetPermissionInternal returning Denied on all failure codepaths.
1379 MOZ_ASSERT_IF(result.Failed(), permission == NotificationPermission::Denied)do { if (result.Failed()) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(permission == NotificationPermission
::Denied)>::isValid, "invalid assertion condition"); if ((
__builtin_expect(!!(!(!!(permission == NotificationPermission
::Denied))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("permission == NotificationPermission::Denied", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1379); AnnotateMozCrashReason("MOZ_ASSERT" "(" "permission == NotificationPermission::Denied"
")"); do { *((volatile int*)__null) = 1379; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1380 result.SuppressException();
1381 if (permission != NotificationPermission::Granted || !alertService) {
1382 if (mWorkerPrivate) {
1383 RefPtr<NotificationEventWorkerRunnable> r =
1384 new NotificationEventWorkerRunnable(this, u"error"_ns);
1385 if (!r->Dispatch(mWorkerPrivate)) {
1386 NS_WARNING("Could not dispatch event to worker notification")NS_DebugBreak(NS_DEBUG_WARNING, "Could not dispatch event to worker notification"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1386)
;
1387 }
1388 } else {
1389 DispatchTrustedEvent(u"error"_ns);
1390 }
1391 mIsClosed = true;
1392 return;
1393 }
1394
1395 // Step 4.3 the show steps, which are almost all about processing `tag` and
1396 // then displaying the notification. Both are handled by
1397 // nsIAlertsService::ShowAlert/PersistentNotification. The below is all about
1398 // constructing the observer (for show and close events) right and ultimately
1399 // call the alerts service function.
1400
1401 // XXX(krosylight): Non-persistent notifications probably don't need this
1402 nsresult rv = PersistNotification();
1403 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1404 NS_WARNING("Could not persist Notification")NS_DebugBreak(NS_DEBUG_WARNING, "Could not persist Notification"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1404)
;
1405 }
1406
1407 bool isPersistent = false;
1408 nsCOMPtr<nsIObserver> observer;
1409 if (mScope.IsEmpty()) {
1410 // Ownership passed to observer.
1411 if (mWorkerPrivate) {
1412 // Scope better be set on ServiceWorker initiated requests.
1413 MOZ_ASSERT(!mWorkerPrivate->IsServiceWorker())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mWorkerPrivate->IsServiceWorker())>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(!mWorkerPrivate->IsServiceWorker()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!mWorkerPrivate->IsServiceWorker()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1413); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mWorkerPrivate->IsServiceWorker()"
")"); do { *((volatile int*)__null) = 1413; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1414 // Keep a pointer so that the feature can tell the observer not to release
1415 // the notification.
1416 mObserver = new WorkerNotificationObserver(std::move(ownership));
1417 observer = mObserver;
1418 } else {
1419 observer = new MainThreadNotificationObserver(std::move(ownership));
1420 }
1421 } else {
1422 isPersistent = true;
1423 // This observer does not care about the Notification. It will be released
1424 // at the end of this function.
1425 //
1426 // The observer is wholly owned by the NotificationObserver passed to the
1427 // alert service.
1428 nsAutoString behavior;
1429 if (NS_WARN_IF(!mBehavior.ToJSON(behavior))NS_warn_if_impl(!mBehavior.ToJSON(behavior), "!mBehavior.ToJSON(behavior)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1429)
) {
1430 behavior.Truncate();
1431 }
1432 observer = new ServiceWorkerNotificationObserver(
1433 mScope, GetPrincipal(), mID, mTitle, mDir, mLang, mBody, mTag, mIconUrl,
1434 mDataAsBase64, behavior);
1435 }
1436 MOZ_ASSERT(observer)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(observer)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(observer))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("observer", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1436); AnnotateMozCrashReason("MOZ_ASSERT" "(" "observer" ")"
); do { *((volatile int*)__null) = 1436; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1437 nsCOMPtr<nsIObserver> alertObserver =
1438 new NotificationObserver(observer, GetPrincipal(), IsInPrivateBrowsing());
1439
1440 // In the case of IPC, the parent process uses the cookie to map to
1441 // nsIObserver. Thus the cookie must be unique to differentiate observers.
1442 nsString uniqueCookie = u"notification:"_ns;
1443 uniqueCookie.AppendInt(sCount++);
1444 bool inPrivateBrowsing = IsInPrivateBrowsing();
1445
1446 bool requireInteraction = mRequireInteraction;
1447 if (!StaticPrefs::dom_webnotifications_requireinteraction_enabled()) {
1448 requireInteraction = false;
1449 }
1450
1451 nsAutoString alertName;
1452 GetAlertName(alertName);
1453 nsCOMPtr<nsIAlertNotification> alert =
1454 do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID"@mozilla.org/alert-notification;1");
1455 NS_ENSURE_TRUE_VOID(alert)do { if ((__builtin_expect(!!(!(alert)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "alert" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1455); return; } } while (false)
;
1456 nsIPrincipal* principal = GetPrincipal();
1457 rv = alert->Init(alertName, mIconUrl, mTitle, mBody, true, uniqueCookie,
1458 NS_ConvertASCIItoUTF16(GetEnumString(mDir)), mLang,
1459 mDataAsBase64, GetPrincipal(), inPrivateBrowsing,
1460 requireInteraction, mSilent, mVibrate);
1461 NS_ENSURE_SUCCESS_VOID(rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS_VOID(%s) failed with "
"result 0x%" "X" "%s%s%s", "rv", static_cast<uint32_t>
(__rv), name ? " (" : "", name ? name : "", name ? ")" : "");
NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1461); return; } } while (false)
;
1462
1463 if (isPersistent) {
1464 JSONStringWriteFunc<nsAutoCString> persistentData;
1465 JSONWriter w(persistentData);
1466 w.Start();
1467
1468 nsAutoString origin;
1469 Notification::GetOrigin(principal, origin);
1470 w.StringProperty("origin", NS_ConvertUTF16toUTF8(origin));
1471
1472 w.StringProperty("id", NS_ConvertUTF16toUTF8(mID));
1473
1474 nsAutoCString originSuffix;
1475 principal->GetOriginSuffix(originSuffix);
1476 w.StringProperty("originSuffix", originSuffix);
1477
1478 w.End();
1479
1480 alertService->ShowPersistentNotification(
1481 NS_ConvertUTF8toUTF16(persistentData.StringCRef()), alert,
1482 alertObserver);
1483 } else {
1484 alertService->ShowAlert(alert, alertObserver);
1485 }
1486}
1487
1488/* static */
1489bool Notification::RequestPermissionEnabledForScope(JSContext* aCx,
1490 JSObject* /* unused */) {
1491 // requestPermission() is not allowed on workers. The calling page should ask
1492 // for permission on the worker's behalf. This is to prevent 'which window
1493 // should show the browser pop-up'. See discussion:
1494 // http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2013-October/041272.html
1495 return NS_IsMainThread();
1496}
1497
1498// static
1499already_AddRefed<Promise> Notification::RequestPermission(
1500 const GlobalObject& aGlobal,
1501 const Optional<OwningNonNull<NotificationPermissionCallback> >& aCallback,
1502 ErrorResult& aRv) {
1503 AssertIsOnMainThread();
1504
1505 // Get principal from global to make permission request for notifications.
1506 nsCOMPtr<nsPIDOMWindowInner> window =
1507 do_QueryInterface(aGlobal.GetAsSupports());
1508 nsCOMPtr<nsIScriptObjectPrincipal> sop =
1509 do_QueryInterface(aGlobal.GetAsSupports());
1510 if (!sop || !window) {
1511 aRv.Throw(NS_ERROR_UNEXPECTED);
1512 return nullptr;
1513 }
1514
1515 nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
1516 if (!principal) {
1517 aRv.Throw(NS_ERROR_UNEXPECTED);
1518 return nullptr;
1519 }
1520
1521 RefPtr<Promise> promise = Promise::Create(window->AsGlobal(), aRv);
1522 if (aRv.Failed()) {
1523 return nullptr;
1524 }
1525 NotificationPermissionCallback* permissionCallback = nullptr;
1526 if (aCallback.WasPassed()) {
1527 permissionCallback = &aCallback.Value();
1528 }
1529 nsCOMPtr<nsIRunnable> request = new NotificationPermissionRequest(
1530 principal, window, promise, permissionCallback);
1531
1532 window->AsGlobal()->Dispatch(request.forget());
1533
1534 return promise.forget();
1535}
1536
1537// static
1538NotificationPermission Notification::GetPermission(const GlobalObject& aGlobal,
1539 ErrorResult& aRv) {
1540 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
1541 return GetPermission(global, aRv);
1542}
1543
1544// static
1545NotificationPermission Notification::GetPermission(nsIGlobalObject* aGlobal,
1546 ErrorResult& aRv) {
1547 if (NS_IsMainThread()) {
1548 return GetPermissionInternal(aGlobal->GetAsInnerWindow(), aRv);
1549 } else {
1550 WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
1551 MOZ_ASSERT(worker)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(worker)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(worker))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("worker", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1551); AnnotateMozCrashReason("MOZ_ASSERT" "(" "worker" ")"
); do { *((volatile int*)__null) = 1551; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1552 RefPtr<GetPermissionRunnable> r = new GetPermissionRunnable(worker);
1553 r->Dispatch(worker, Canceling, aRv);
1554 if (aRv.Failed()) {
1555 return NotificationPermission::Denied;
1556 }
1557
1558 return r->GetPermission();
1559 }
1560}
1561
1562/* static */
1563NotificationPermission Notification::GetPermissionInternal(
1564 nsPIDOMWindowInner* aWindow, ErrorResult& aRv) {
1565 // Get principal from global to check permission for notifications.
1566 nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
1567 if (!sop) {
1568 aRv.Throw(NS_ERROR_UNEXPECTED);
1569 return NotificationPermission::Denied;
1570 }
1571
1572 nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
1573 if (!principal) {
1574 aRv.Throw(NS_ERROR_UNEXPECTED);
1575 return NotificationPermission::Denied;
1576 }
1577
1578 if (principal->GetPrivateBrowsingId() != 0 &&
1579 !StaticPrefs::
1580 dom_webnotifications_privateBrowsing_enableDespiteLimitations()) {
1581 return NotificationPermission::Denied;
1582 }
1583 // Disallow showing notification if our origin is not the same origin as the
1584 // toplevel one, see https://github.com/whatwg/notifications/issues/177.
1585 if (!StaticPrefs::dom_webnotifications_allowcrossoriginiframe()) {
1586 nsCOMPtr<nsIScriptObjectPrincipal> topSop =
1587 do_QueryInterface(aWindow->GetBrowsingContext()->Top()->GetDOMWindow());
1588 nsIPrincipal* topPrincipal = topSop ? topSop->GetPrincipal() : nullptr;
1589 if (!topPrincipal || !principal->Subsumes(topPrincipal)) {
1590 return NotificationPermission::Denied;
1591 }
1592 }
1593
1594 return GetPermissionInternal(principal, aRv);
1595}
1596
1597/* static */
1598NotificationPermission Notification::GetPermissionInternal(
1599 nsIPrincipal* aPrincipal, ErrorResult& aRv) {
1600 AssertIsOnMainThread();
1601 MOZ_ASSERT(aPrincipal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPrincipal))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aPrincipal", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1601); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPrincipal"
")"); do { *((volatile int*)__null) = 1601; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1602
1603 if (aPrincipal->IsSystemPrincipal()) {
1604 return NotificationPermission::Granted;
1605 } else {
1606 // Allow files to show notifications by default.
1607 if (aPrincipal->SchemeIs("file")) {
1608 return NotificationPermission::Granted;
1609 }
1610 }
1611
1612 return TestPermission(aPrincipal);
1613}
1614
1615/* static */
1616NotificationPermission Notification::TestPermission(nsIPrincipal* aPrincipal) {
1617 AssertIsOnMainThread();
1618
1619 uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION;
1620
1621 nsCOMPtr<nsIPermissionManager> permissionManager =
1622 components::PermissionManager::Service();
1623 if (!permissionManager) {
1624 return NotificationPermission::Default;
1625 }
1626
1627 permissionManager->TestExactPermissionFromPrincipal(
1628 aPrincipal, "desktop-notification"_ns, &permission);
1629
1630 // Convert the result to one of the enum types.
1631 switch (permission) {
1632 case nsIPermissionManager::ALLOW_ACTION:
1633 return NotificationPermission::Granted;
1634 case nsIPermissionManager::DENY_ACTION:
1635 return NotificationPermission::Denied;
1636 default:
1637 return NotificationPermission::Default;
1638 }
1639}
1640
1641nsresult Notification::ResolveIconAndSoundURL(nsIGlobalObject* aGlobal,
1642 nsString& iconUrl,
1643 nsString& soundUrl) {
1644 nsresult rv = NS_OK;
1645
1646 nsCOMPtr<nsIURI> baseUri = nullptr;
1647
1648 // XXXnsm If I understand correctly, the character encoding for resolving
1649 // URIs in new specs is dictated by the URL spec, which states that unless
1650 // the URL parser is passed an override encoding, the charset to be used is
1651 // UTF-8. The new Notification icon/sound specification just says to use the
1652 // Fetch API, where the Request constructor defers to URL parsing specifying
1653 // the API base URL and no override encoding. So we've to use UTF-8 on
1654 // workers, but for backwards compat keeping it document charset on main
1655 // thread.
1656 auto encoding = UTF_8_ENCODING;
1657
1658 if (nsCOMPtr<nsPIDOMWindowInner> window = aGlobal->GetAsInnerWindow()) {
1659 if (RefPtr<Document> doc = window->GetExtantDoc()) {
1660 baseUri = doc->GetBaseURI();
1661 encoding = doc->GetDocumentCharacterSet();
1662 } else {
1663 NS_WARNING("No document found for main thread notification!")NS_DebugBreak(NS_DEBUG_WARNING, "No document found for main thread notification!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1663)
;
1664 return NS_ERROR_FAILURE;
1665 }
1666 } else if (WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate()) {
1667 baseUri = workerPrivate->GetBaseURI();
1668 }
1669
1670 if (baseUri) {
1671 if (iconUrl.Length() > 0) {
1672 nsCOMPtr<nsIURI> srcUri;
1673 rv = NS_NewURI(getter_AddRefs(srcUri), iconUrl, encoding, baseUri);
1674 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
1675 nsAutoCString src;
1676 srcUri->GetSpec(src);
1677 CopyUTF8toUTF16(src, iconUrl);
1678 }
1679 }
1680 if (soundUrl.Length() > 0) {
1681 nsCOMPtr<nsIURI> srcUri;
1682 rv = NS_NewURI(getter_AddRefs(srcUri), soundUrl, encoding, baseUri);
1683 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
1684 nsAutoCString src;
1685 srcUri->GetSpec(src);
1686 CopyUTF8toUTF16(src, soundUrl);
1687 }
1688 }
1689 }
1690
1691 return rv;
1692}
1693
1694already_AddRefed<Promise> Notification::Get(
1695 nsPIDOMWindowInner* aWindow, const GetNotificationOptions& aFilter,
1696 const nsAString& aScope, ErrorResult& aRv) {
1697 AssertIsOnMainThread();
1698 MOZ_ASSERT(aWindow)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aWindow)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aWindow))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aWindow", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1698); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWindow" ")"
); do { *((volatile int*)__null) = 1698; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1699
1700 nsCOMPtr<Document> doc = aWindow->GetExtantDoc();
1701 if (!doc) {
1702 aRv.Throw(NS_ERROR_UNEXPECTED);
1703 return nullptr;
1704 }
1705
1706 nsString origin;
1707 aRv = GetOrigin(doc->NodePrincipal(), origin);
1708 if (aRv.Failed()) {
1709 return nullptr;
1710 }
1711
1712 RefPtr<Promise> promise = Promise::Create(aWindow->AsGlobal(), aRv);
1713 if (aRv.Failed()) {
1714 return nullptr;
1715 }
1716
1717 nsCOMPtr<nsINotificationStorageCallback> callback =
1718 new NotificationStorageCallback(aWindow->AsGlobal(), aScope, promise);
1719
1720 RefPtr<NotificationGetRunnable> r = new NotificationGetRunnable(
1721 origin, aFilter.mTag, callback, doc->IsInPrivateBrowsing());
1722
1723 aRv = aWindow->AsGlobal()->Dispatch(r.forget());
1724 if (NS_WARN_IF(aRv.Failed())NS_warn_if_impl(aRv.Failed(), "aRv.Failed()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1724)
) {
1725 return nullptr;
1726 }
1727
1728 return promise.forget();
1729}
1730
1731class WorkerGetResultRunnable final : public NotificationWorkerRunnable {
1732 RefPtr<PromiseWorkerProxy> mPromiseProxy;
1733 const nsTArray<NotificationStrings> mStrings;
1734
1735 public:
1736 WorkerGetResultRunnable(WorkerPrivate* aWorkerPrivate,
1737 PromiseWorkerProxy* aPromiseProxy,
1738 nsTArray<NotificationStrings>&& aStrings)
1739 : NotificationWorkerRunnable(aWorkerPrivate, "WorkerGetResultRunnable"),
1740 mPromiseProxy(aPromiseProxy),
1741 mStrings(std::move(aStrings)) {}
1742
1743 void WorkerRunInternal(WorkerPrivate* aWorkerPrivate) override {
1744 RefPtr<Promise> workerPromise = mPromiseProxy->GetWorkerPromise();
1745 // Once Worker had already started shutdown, workerPromise would be nullptr
1746 if (!workerPromise) {
1747 return;
1748 }
1749
1750 AutoTArray<RefPtr<Notification>, 5> notifications;
1751 for (uint32_t i = 0; i < mStrings.Length(); ++i) {
1752 auto result = Notification::ConstructFromFields(
1753 aWorkerPrivate->GlobalScope(), mStrings[i].mID, mStrings[i].mTitle,
1754 mStrings[i].mDir, mStrings[i].mLang, mStrings[i].mBody,
1755 mStrings[i].mTag, mStrings[i].mIcon, mStrings[i].mData,
1756 /* mStrings[i].mBehavior, not
1757 * supported */
1758 mStrings[i].mServiceWorkerRegistrationScope);
1759 if (result.isErr()) {
1760 continue;
1761 }
1762 RefPtr<Notification> n = result.unwrap();
1763 n->SetStoredState(true);
1764 notifications.AppendElement(n.forget());
1765 }
1766
1767 workerPromise->MaybeResolve(notifications);
1768 mPromiseProxy->CleanUp();
1769 }
1770};
1771
1772class WorkerGetCallback final : public ScopeCheckingGetCallback {
1773 RefPtr<PromiseWorkerProxy> mPromiseProxy;
1774
1775 public:
1776 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
1777
1778 WorkerGetCallback(PromiseWorkerProxy* aProxy, const nsAString& aScope)
1779 : ScopeCheckingGetCallback(aScope), mPromiseProxy(aProxy) {
1780 AssertIsOnMainThread();
1781 MOZ_ASSERT(aProxy)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aProxy)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aProxy))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aProxy", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1781); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aProxy" ")"
); do { *((volatile int*)__null) = 1781; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1782 }
1783
1784 NS_IMETHODvirtual nsresult Done() final {
1785 AssertIsOnMainThread();
1786 MOZ_ASSERT(mPromiseProxy, "Was Done() called twice?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mPromiseProxy)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mPromiseProxy))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("mPromiseProxy" " ("
"Was Done() called twice?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1786); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mPromiseProxy"
") (" "Was Done() called twice?" ")"); do { *((volatile int*
)__null) = 1786; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1787
1788 RefPtr<PromiseWorkerProxy> proxy = std::move(mPromiseProxy);
1789 MutexAutoLock lock(proxy->Lock());
1790 if (proxy->CleanedUp()) {
1791 return NS_OK;
1792 }
1793
1794 RefPtr<WorkerGetResultRunnable> r = new WorkerGetResultRunnable(
1795 proxy->GetWorkerPrivate(), proxy, std::move(mStrings));
1796
1797 r->Dispatch(proxy->GetWorkerPrivate());
1798 return NS_OK;
1799 }
1800
1801 private:
1802 ~WorkerGetCallback() = default;
1803};
1804
1805NS_IMPL_ISUPPORTS(WorkerGetCallback, nsINotificationStorageCallback)MozExternalRefCountType WorkerGetCallback::AddRef(void) { static_assert
(!std::is_destructible_v<WorkerGetCallback>, "Reference-counted class "
"WorkerGetCallback" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1805); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
1805; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("WorkerGetCallback" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("WorkerGetCallback" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"WorkerGetCallback\" != nullptr" " (" "Must specify a name"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1805); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WorkerGetCallback\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 1805; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("WorkerGetCallback" " not thread-safe"); nsrefcnt
count = ++mRefCnt; NS_LogAddRef((this), (count), ("WorkerGetCallback"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
WorkerGetCallback::Release(void) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(int32_t(mRefCnt)
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1805); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 1805
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("WorkerGetCallback" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("WorkerGetCallback" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"WorkerGetCallback\" != nullptr" " (" "Must specify a name"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1805); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WorkerGetCallback\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 1805; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("WorkerGetCallback" " not thread-safe"); const
char* const nametmp = "WorkerGetCallback"; nsrefcnt count = --
mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (count
== 0) { mRefCnt = 1; delete (this); return 0; } return count
; } nsresult WorkerGetCallback::QueryInterface(const nsIID&
aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1805); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<WorkerGetCallback, nsINotificationStorageCallback
>, int32_t( reinterpret_cast<char*>(static_cast<nsINotificationStorageCallback
*>((WorkerGetCallback*)0x1000)) - reinterpret_cast<char
*>((WorkerGetCallback*)0x1000))}, {&mozilla::detail::kImplementedIID
<WorkerGetCallback, nsISupports>, int32_t(reinterpret_cast
<char*>(static_cast<nsISupports*>( static_cast<
nsINotificationStorageCallback*>((WorkerGetCallback*)0x1000
))) - reinterpret_cast<char*>((WorkerGetCallback*)0x1000
))}, { nullptr, 0 } } ; static_assert((sizeof(table) / sizeof
(table[0])) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI
(static_cast<void*>(this), aIID, aInstancePtr, table); return
rv; }
1806
1807class WorkerGetRunnable final : public Runnable {
1808 RefPtr<PromiseWorkerProxy> mPromiseProxy;
1809 const nsString mTag;
1810 const nsString mScope;
1811
1812 public:
1813 WorkerGetRunnable(PromiseWorkerProxy* aProxy, const nsAString& aTag,
1814 const nsAString& aScope)
1815 : Runnable("WorkerGetRunnable"),
1816 mPromiseProxy(aProxy),
1817 mTag(aTag),
1818 mScope(aScope) {
1819 MOZ_ASSERT(mPromiseProxy)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mPromiseProxy)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mPromiseProxy))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("mPromiseProxy",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1819); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mPromiseProxy"
")"); do { *((volatile int*)__null) = 1819; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1820 }
1821
1822 NS_IMETHODvirtual nsresult
1823 Run() override {
1824 AssertIsOnMainThread();
1825
1826 MutexAutoLock lock(mPromiseProxy->Lock());
1827 if (mPromiseProxy->CleanedUp()) {
1828 return NS_OK;
1829 }
1830
1831 auto* principal = mPromiseProxy->GetWorkerPrivate()->GetPrincipal();
1832 auto isPrivate = principal->GetPrivateBrowsingId() != 0;
1833
1834 nsCOMPtr<nsINotificationStorageCallback> callback =
1835 new WorkerGetCallback(mPromiseProxy, mScope);
1836
1837 nsCOMPtr<nsINotificationStorage> notificationStorage =
1838 GetNotificationStorage(isPrivate);
1839 if (NS_WARN_IF(!notificationStorage)NS_warn_if_impl(!notificationStorage, "!notificationStorage",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1839)
) {
1840 callback->Done();
1841 return NS_ERROR_UNEXPECTED;
1842 }
1843 nsString origin;
1844 nsresult rv = Notification::GetOrigin(principal, origin);
1845 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1845)
) {
1846 callback->Done();
1847 return rv;
1848 }
1849
1850 rv = notificationStorage->Get(origin, mTag, callback);
1851 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1851)
) {
1852 callback->Done();
1853 return rv;
1854 }
1855
1856 return NS_OK;
1857 }
1858
1859 private:
1860 ~WorkerGetRunnable() = default;
1861};
1862
1863// static
1864already_AddRefed<Promise> Notification::WorkerGet(
1865 WorkerPrivate* aWorkerPrivate, const GetNotificationOptions& aFilter,
1866 const nsAString& aScope, ErrorResult& aRv) {
1867 MOZ_ASSERT(aWorkerPrivate)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aWorkerPrivate)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aWorkerPrivate))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aWorkerPrivate"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1867); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWorkerPrivate"
")"); do { *((volatile int*)__null) = 1867; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1868 aWorkerPrivate->AssertIsOnWorkerThread();
1869 RefPtr<Promise> p = Promise::Create(aWorkerPrivate->GlobalScope(), aRv);
1870 if (NS_WARN_IF(aRv.Failed())NS_warn_if_impl(aRv.Failed(), "aRv.Failed()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1870)
) {
1871 return nullptr;
1872 }
1873
1874 RefPtr<PromiseWorkerProxy> proxy =
1875 PromiseWorkerProxy::Create(aWorkerPrivate, p);
1876 if (!proxy) {
1877 aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
1878 return nullptr;
1879 }
1880
1881 RefPtr<WorkerGetRunnable> r =
1882 new WorkerGetRunnable(proxy, aFilter.mTag, aScope);
1883 // Since this is called from script via
1884 // ServiceWorkerRegistration::GetNotifications, we can assert dispatch.
1885 MOZ_ALWAYS_SUCCEEDS(aWorkerPrivate->DispatchToMainThread(r.forget()))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(aWorkerPrivate->DispatchToMainThread(r.forget()))), 1))))
, 1))) { } else { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(false)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("false" " (" "NS_SUCCEEDED(aWorkerPrivate->DispatchToMainThread(r.forget()))"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1885); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(aWorkerPrivate->DispatchToMainThread(r.forget()))"
")"); do { *((volatile int*)__null) = 1885; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1886 return p.forget();
1887}
1888
1889JSObject* Notification::WrapObject(JSContext* aCx,
1890 JS::Handle<JSObject*> aGivenProto) {
1891 return mozilla::dom::Notification_Binding::Wrap(aCx, this, aGivenProto);
1892}
1893
1894void Notification::Close() {
1895 AssertIsOnTargetThread();
1896 auto ref = MakeUnique<NotificationRef>(this);
1897 if (!ref->Initialized()) {
1898 return;
1899 }
1900
1901 nsCOMPtr<nsIRunnable> closeNotificationTask = new NotificationTask(
1902 "Notification::Close", std::move(ref), NotificationTask::eClose);
1903 nsresult rv = DispatchToMainThread(closeNotificationTask.forget());
1904
1905 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1906 DispatchTrustedEvent(u"error"_ns);
1907 // If dispatch fails, NotificationTask will release the ref when it goes
1908 // out of scope at the end of this function.
1909 }
1910}
1911
1912void Notification::CloseInternal(bool aContextClosed) {
1913 AssertIsOnMainThread();
1914 // Transfer ownership (if any) to local scope so we can release it at the end
1915 // of this function. This is relevant when the call is from
1916 // NotificationTask::Run().
1917 UniquePtr<NotificationRef> ownership;
1918 std::swap(ownership, mTempRef);
1919
1920 SetAlertName();
1921 UnpersistNotification();
1922 if (!mIsClosed) {
1923 nsCOMPtr<nsIAlertsService> alertService = components::Alerts::Service();
1924 if (alertService) {
1925 nsAutoString alertName;
1926 GetAlertName(alertName);
1927 alertService->CloseAlert(alertName, aContextClosed);
1928 }
1929 }
1930}
1931
1932nsresult Notification::GetOrigin(nsIPrincipal* aPrincipal, nsString& aOrigin) {
1933 if (!aPrincipal) {
1934 return NS_ERROR_FAILURE;
1935 }
1936
1937 nsresult rv =
1938 nsContentUtils::GetWebExposedOriginSerialization(aPrincipal, aOrigin);
1939 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1939); return rv; } } while (false)
;
1940
1941 return NS_OK;
1942}
1943
1944bool Notification::RequireInteraction() const { return mRequireInteraction; }
1945
1946bool Notification::Silent() const { return mSilent; }
1947
1948void Notification::GetVibrate(nsTArray<uint32_t>& aRetval) const {
1949 aRetval = mVibrate.Clone();
1950}
1951
1952void Notification::GetData(JSContext* aCx,
1953 JS::MutableHandle<JS::Value> aRetval) {
1954 if (mData.isNull() && !mDataAsBase64.IsEmpty()) {
1955 nsresult rv;
1956 RefPtr<nsStructuredCloneContainer> container =
1957 new nsStructuredCloneContainer();
1958 rv = container->InitFromBase64(mDataAsBase64, JS_STRUCTURED_CLONE_VERSION8);
1959 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1959)
) {
1960 aRetval.setNull();
1961 return;
1962 }
1963
1964 JS::Rooted<JS::Value> data(aCx);
1965 rv = container->DeserializeToJsval(aCx, &data);
1966 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1966)
) {
1967 aRetval.setNull();
1968 return;
1969 }
1970
1971 if (data.isGCThing()) {
1972 mozilla::HoldJSObjects(this);
1973 }
1974 mData = data;
1975 }
1976 if (mData.isNull()) {
1977 aRetval.setNull();
1978 return;
1979 }
1980
1981 aRetval.set(mData);
1982}
1983
1984void Notification::InitFromJSVal(JSContext* aCx, JS::Handle<JS::Value> aData,
1985 ErrorResult& aRv) {
1986 if (!mDataAsBase64.IsEmpty() || aData.isNull()) {
1987 return;
1988 }
1989 RefPtr<nsStructuredCloneContainer> dataObjectContainer =
1990 new nsStructuredCloneContainer();
1991 aRv = dataObjectContainer->InitFromJSVal(aData, aCx);
1992 if (NS_WARN_IF(aRv.Failed())NS_warn_if_impl(aRv.Failed(), "aRv.Failed()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1992)
) {
1993 return;
1994 }
1995
1996 aRv = dataObjectContainer->GetDataAsBase64(mDataAsBase64);
1997 if (NS_WARN_IF(aRv.Failed())NS_warn_if_impl(aRv.Failed(), "aRv.Failed()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1997)
) {
1998 return;
1999 }
2000}
2001
2002Result<Ok, QMResult> Notification::InitFromBase64(const nsAString& aData) {
2003 MOZ_ASSERT(mDataAsBase64.IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDataAsBase64.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDataAsBase64.IsEmpty()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mDataAsBase64.IsEmpty()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2003); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDataAsBase64.IsEmpty()"
")"); do { *((volatile int*)__null) = 2003; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2004 if (aData.IsEmpty()) {
2005 // No data; skipping
2006 return Ok();
2007 }
2008
2009 // To and fro to ensure it is valid base64.
2010 RefPtr<nsStructuredCloneContainer> container =
2011 new nsStructuredCloneContainer();
2012 QM_TRY(QM_TO_RESULT({auto tryResult13 = (ToResult<QMResult>(container->InitFromBase64
(aData, 8))); static_assert(std::is_empty_v<typename decltype
(tryResult13)::ok_type>); if ((__builtin_expect(!!(tryResult13
.isErr()), 0))) { mozilla::dom::quota::HandleError("ToResult<QMResult>(container->InitFromBase64(aData, 8))"
, tryResult13.inspectErr(), "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2013, mozilla::dom::quota::Severity::Error); return tryResult13
.propagateErr(); }}
2013 container->InitFromBase64(aData, JS_STRUCTURED_CLONE_VERSION))){auto tryResult13 = (ToResult<QMResult>(container->InitFromBase64
(aData, 8))); static_assert(std::is_empty_v<typename decltype
(tryResult13)::ok_type>); if ((__builtin_expect(!!(tryResult13
.isErr()), 0))) { mozilla::dom::quota::HandleError("ToResult<QMResult>(container->InitFromBase64(aData, 8))"
, tryResult13.inspectErr(), "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2013, mozilla::dom::quota::Severity::Error); return tryResult13
.propagateErr(); }}
;
2014 QM_TRY(QM_TO_RESULT(container->GetDataAsBase64(mDataAsBase64))){auto tryResult14 = (ToResult<QMResult>(container->GetDataAsBase64
(mDataAsBase64))); static_assert(std::is_empty_v<typename decltype
(tryResult14)::ok_type>); if ((__builtin_expect(!!(tryResult14
.isErr()), 0))) { mozilla::dom::quota::HandleError("ToResult<QMResult>(container->GetDataAsBase64(mDataAsBase64))"
, tryResult14.inspectErr(), "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2014, mozilla::dom::quota::Severity::Error); return tryResult14
.propagateErr(); }}
;
2015
2016 return Ok();
2017}
2018
2019bool Notification::AddRefObject() {
2020 AssertIsOnTargetThread();
2021 MOZ_ASSERT_IF(mWorkerPrivate && !mWorkerRef, mTaskCount == 0)do { if (mWorkerPrivate && !mWorkerRef) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(mTaskCount
== 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mTaskCount == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mTaskCount == 0", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2021); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTaskCount == 0"
")"); do { *((volatile int*)__null) = 2021; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2022 MOZ_ASSERT_IF(mWorkerPrivate && mWorkerRef, mTaskCount > 0)do { if (mWorkerPrivate && mWorkerRef) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(mTaskCount
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mTaskCount > 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mTaskCount > 0", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2022); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTaskCount > 0"
")"); do { *((volatile int*)__null) = 2022; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2023 if (mWorkerPrivate && !mWorkerRef) {
2024 if (!CreateWorkerRef()) {
2025 return false;
2026 }
2027 }
2028 AddRef();
2029 ++mTaskCount;
2030 return true;
2031}
2032
2033void Notification::ReleaseObject() {
2034 AssertIsOnTargetThread();
2035 MOZ_ASSERT(mTaskCount > 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTaskCount > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mTaskCount > 0))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mTaskCount > 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2035); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTaskCount > 0"
")"); do { *((volatile int*)__null) = 2035; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2036 MOZ_ASSERT_IF(mWorkerPrivate, mWorkerRef)do { if (mWorkerPrivate) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(mWorkerRef)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mWorkerRef))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mWorkerRef", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2036); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWorkerRef"
")"); do { *((volatile int*)__null) = 2036; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2037
2038 --mTaskCount;
2039 if (mWorkerPrivate && mTaskCount == 0) {
2040 MOZ_ASSERT(mWorkerRef)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mWorkerRef)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mWorkerRef))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("mWorkerRef", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2040); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWorkerRef"
")"); do { *((volatile int*)__null) = 2040; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2041 mWorkerRef = nullptr;
2042 }
2043 Release();
2044}
2045
2046/*
2047 * Called from the worker, runs on main thread, blocks worker.
2048 *
2049 * We can freely access mNotification here because the feature supplied it and
2050 * the Notification owns the feature.
2051 */
2052class CloseNotificationRunnable final : public WorkerMainThreadRunnable {
2053 Notification* mNotification;
2054 bool mHadObserver;
2055
2056 public:
2057 explicit CloseNotificationRunnable(Notification* aNotification)
2058 : WorkerMainThreadRunnable(aNotification->mWorkerPrivate,
2059 "Notification :: Close Notification"_ns),
2060 mNotification(aNotification),
2061 mHadObserver(false) {}
2062
2063 bool MainThreadRun() override {
2064 if (mNotification->mObserver) {
2065 // The Notify() take's responsibility of releasing the Notification.
2066 mNotification->mObserver->ForgetNotification();
2067 mNotification->mObserver = nullptr;
2068 mHadObserver = true;
2069 }
2070 mNotification->CloseInternal();
2071 return true;
2072 }
2073
2074 bool HadObserver() { return mHadObserver; }
2075};
2076
2077bool Notification::CreateWorkerRef() {
2078 MOZ_ASSERT(mWorkerPrivate)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mWorkerPrivate)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mWorkerPrivate))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mWorkerPrivate"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2078); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWorkerPrivate"
")"); do { *((volatile int*)__null) = 2078; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2079 mWorkerPrivate->AssertIsOnWorkerThread();
2080 MOZ_ASSERT(!mWorkerRef)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mWorkerRef)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mWorkerRef))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!mWorkerRef", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2080); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mWorkerRef"
")"); do { *((volatile int*)__null) = 2080; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2081
2082 RefPtr<Notification> self = this;
2083 mWorkerRef =
2084 StrongWorkerRef::Create(mWorkerPrivate, "Notification", [self]() {
2085 // CloseNotificationRunnable blocks the worker by pushing a sync event
2086 // loop on the stack. Meanwhile, WorkerControlRunnables dispatched to
2087 // the worker can still continue running. One of these is
2088 // ReleaseNotificationControlRunnable that releases the notification,
2089 // invalidating the notification and this feature. We hold this
2090 // reference to keep the notification valid until we are done with it.
2091 //
2092 // An example of when the control runnable could get dispatched to the
2093 // worker is if a Notification is created and the worker is immediately
2094 // closed, but there is no permission to show it so that the main thread
2095 // immediately drops the NotificationRef. In this case, this function
2096 // blocks on the main thread, but the main thread dispatches the control
2097 // runnable, invalidating mNotification.
2098
2099 // Dispatched to main thread, blocks on closing the Notification.
2100 RefPtr<CloseNotificationRunnable> r =
2101 new CloseNotificationRunnable(self);
2102 ErrorResult rv;
2103 r->Dispatch(self->mWorkerPrivate, Killing, rv);
2104 // XXXbz I'm told throwing and returning false from here is pointless
2105 // (and also that doing sync stuff from here is really weird), so I
2106 // guess we just suppress the exception on rv, if any.
2107 rv.SuppressException();
2108
2109 // Only call ReleaseObject() to match the observer's NotificationRef
2110 // ownership (since CloseNotificationRunnable asked the observer to drop
2111 // the reference to the notification).
2112 if (r->HadObserver()) {
2113 self->ReleaseObject();
2114 }
2115
2116 // From this point we cannot touch properties of this feature because
2117 // ReleaseObject() may have led to the notification going away and the
2118 // notification owns this feature!
2119 });
2120
2121 if (NS_WARN_IF(!mWorkerRef)NS_warn_if_impl(!mWorkerRef, "!mWorkerRef", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2121)
) {
2122 return false;
2123 }
2124
2125 return true;
2126}
2127
2128/*
2129 * Checks:
2130 * 1) Is aWorker allowed to show a notification for scope?
2131 * 2) Is aWorker an active worker?
2132 *
2133 * If it is not an active worker, Result() will be NS_ERROR_NOT_AVAILABLE.
2134 */
2135class CheckLoadRunnable final : public WorkerMainThreadRunnable {
2136 nsresult mRv;
2137 nsCString mScope;
2138 ServiceWorkerRegistrationDescriptor mDescriptor;
2139
2140 public:
2141 explicit CheckLoadRunnable(
2142 WorkerPrivate* aWorker, const nsACString& aScope,
2143 const ServiceWorkerRegistrationDescriptor& aDescriptor)
2144 : WorkerMainThreadRunnable(aWorker, "Notification :: Check Load"_ns),
2145 mRv(NS_ERROR_DOM_SECURITY_ERR),
2146 mScope(aScope),
2147 mDescriptor(aDescriptor) {}
2148
2149 bool MainThreadRun() override {
2150 MOZ_ASSERT(mWorkerRef)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mWorkerRef)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mWorkerRef))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("mWorkerRef", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2150); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWorkerRef"
")"); do { *((volatile int*)__null) = 2150; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2151 nsIPrincipal* principal = mWorkerRef->Private()->GetPrincipal();
2152 mRv = CheckScope(principal, mScope, mWorkerRef->Private()->WindowID());
2153
2154 if (NS_FAILED(mRv)((bool)(__builtin_expect(!!(NS_FAILED_impl(mRv)), 0)))) {
2155 return true;
2156 }
2157
2158 auto activeWorker = mDescriptor.GetActive();
2159
2160 if (!activeWorker ||
2161 activeWorker.ref().Id() != mWorkerRef->Private()->ServiceWorkerID()) {
2162 mRv = NS_ERROR_NOT_AVAILABLE;
2163 }
2164
2165 return true;
2166 }
2167
2168 nsresult Result() { return mRv; }
2169};
2170
2171// Step 2, 5, 6 of
2172// https://notifications.spec.whatwg.org/#dom-serviceworkerregistration-shownotification
2173/* static */
2174already_AddRefed<Promise> Notification::ShowPersistentNotification(
2175 JSContext* aCx, nsIGlobalObject* aGlobal, const nsAString& aScope,
2176 const nsAString& aTitle, const NotificationOptions& aOptions,
2177 const ServiceWorkerRegistrationDescriptor& aDescriptor, ErrorResult& aRv) {
2178 MOZ_ASSERT(aGlobal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGlobal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aGlobal))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aGlobal", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2178); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGlobal" ")"
); do { *((volatile int*)__null) = 2178; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2179
2180 // Validate scope.
2181 // XXXnsm: This may be slow due to blocking the worker and waiting on the main
2182 // thread. On calls from content, we can be sure the scope is valid since
2183 // ServiceWorkerRegistrations have their scope set correctly. Can this be made
2184 // debug only? The problem is that there would be different semantics in
2185 // debug and non-debug builds in such a case.
2186 if (NS_IsMainThread()) {
2187 nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aGlobal);
2188 if (NS_WARN_IF(!sop)NS_warn_if_impl(!sop, "!sop", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2188)
) {
2189 aRv.Throw(NS_ERROR_UNEXPECTED);
2190 return nullptr;
2191 }
2192
2193 nsIPrincipal* principal = sop->GetPrincipal();
2194 if (NS_WARN_IF(!principal)NS_warn_if_impl(!principal, "!principal", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2194)
) {
2195 aRv.Throw(NS_ERROR_UNEXPECTED);
2196 return nullptr;
2197 }
2198
2199 uint64_t windowID = 0;
2200 nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(aGlobal);
2201 if (win) {
2202 windowID = win->WindowID();
2203 }
2204
2205 aRv = CheckScope(principal, NS_ConvertUTF16toUTF8(aScope), windowID);
2206 if (NS_WARN_IF(aRv.Failed())NS_warn_if_impl(aRv.Failed(), "aRv.Failed()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2206)
) {
2207 aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
2208 return nullptr;
2209 }
2210 } else {
2211 WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
2212 MOZ_ASSERT(worker)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(worker)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(worker))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("worker", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2212); AnnotateMozCrashReason("MOZ_ASSERT" "(" "worker" ")"
); do { *((volatile int*)__null) = 2212; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2213 worker->AssertIsOnWorkerThread();
2214
2215 RefPtr<CheckLoadRunnable> loadChecker = new CheckLoadRunnable(
2216 worker, NS_ConvertUTF16toUTF8(aScope), aDescriptor);
2217 loadChecker->Dispatch(worker, Canceling, aRv);
2218 if (aRv.Failed()) {
2219 return nullptr;
2220 }
2221
2222 if (NS_WARN_IF(NS_FAILED(loadChecker->Result()))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(loadChecker
->Result())), 0))), "NS_FAILED(loadChecker->Result())",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2222)
) {
2223 if (loadChecker->Result() == NS_ERROR_NOT_AVAILABLE) {
2224 aRv.ThrowTypeError<MSG_NO_ACTIVE_WORKER>(NS_ConvertUTF16toUTF8(aScope));
2225 } else {
2226 aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
2227 }
2228 return nullptr;
2229 }
2230 }
2231
2232 // Step 2: Let promise be a new promise in this’s relevant Realm.
2233 RefPtr<Promise> p = Promise::Create(aGlobal, aRv);
2234 if (NS_WARN_IF(aRv.Failed())NS_warn_if_impl(aRv.Failed(), "aRv.Failed()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2234)
) {
2235 return nullptr;
2236 }
2237
2238 // We check permission here rather than pass the Promise to NotificationTask
2239 // which leads to uglier code.
2240 // XXX: GetPermission is a synchronous blocking function on workers.
2241 NotificationPermission permission = GetPermission(aGlobal, aRv);
2242
2243 // Step 6.1: If the result of getting the notifications permission state is
2244 // not "granted", then queue a global task on the DOM manipulation task source
2245 // given global to reject promise with a TypeError, and abort these steps.
2246 if (NS_WARN_IF(aRv.Failed())NS_warn_if_impl(aRv.Failed(), "aRv.Failed()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2246)
||
2247 permission != NotificationPermission::Granted) {
2248 p->MaybeRejectWithTypeError("Permission to show Notification denied.");
2249 return p.forget();
2250 }
2251
2252 // "Otherwise, resolve promise with undefined."
2253 // The Notification may still not be shown due to other errors, but the spec
2254 // is not concerned with those.
2255 p->MaybeResolveWithUndefined();
2256
2257 // Step 5: Let notification be the result of creating a notification given
2258 // title, options, this’s relevant settings object, and
2259 // serviceWorkerRegistration. If this threw an exception, then reject promise
2260 // with that exception and return promise.
2261 //
2262 // XXX: This should happen before the permission check per the spec, as this
2263 // can throw errors too. This should be split into create and show.
2264 RefPtr<Notification> notification =
2265 CreateAndShow(aCx, aGlobal, aTitle, aOptions, aScope, aRv);
2266 if (NS_WARN_IF(aRv.Failed())NS_warn_if_impl(aRv.Failed(), "aRv.Failed()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2266)
) {
2267 return nullptr;
2268 }
2269
2270 return p.forget();
2271}
2272
2273/* static */
2274already_AddRefed<Notification> Notification::CreateAndShow(
2275 JSContext* aCx, nsIGlobalObject* aGlobal, const nsAString& aTitle,
2276 const NotificationOptions& aOptions, const nsAString& aScope,
2277 ErrorResult& aRv) {
2278 MOZ_ASSERT(aGlobal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGlobal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aGlobal))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aGlobal", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2278); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGlobal" ")"
); do { *((volatile int*)__null) = 2278; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2279
2280 RefPtr<Notification> notification =
2281 CreateInternal(aGlobal, u""_ns, aTitle, aOptions, aRv);
2282 if (aRv.Failed()) {
2283 return nullptr;
2284 }
2285
2286 // Make a structured clone of the aOptions.mData object
2287 JS::Rooted<JS::Value> data(aCx, aOptions.mData);
2288 notification->InitFromJSVal(aCx, data, aRv);
2289 if (NS_WARN_IF(aRv.Failed())NS_warn_if_impl(aRv.Failed(), "aRv.Failed()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2289)
) {
2290 return nullptr;
2291 }
2292
2293 notification->SetScope(aScope);
2294
2295 auto ref = MakeUnique<NotificationRef>(notification);
2296 if (NS_WARN_IF(!ref->Initialized())NS_warn_if_impl(!ref->Initialized(), "!ref->Initialized()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2296)
) {
2297 aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
2298 return nullptr;
2299 }
2300
2301 // Queue a task to show the notification.
2302 nsCOMPtr<nsIRunnable> showNotificationTask = new NotificationTask(
2303 "Notification::CreateAndShow", std::move(ref), NotificationTask::eShow);
2304
2305 nsresult rv =
2306 notification->DispatchToMainThread(showNotificationTask.forget());
2307
2308 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2308)
) {
2309 notification->DispatchTrustedEvent(u"error"_ns);
2310 }
2311
2312 return notification.forget();
2313}
2314
2315/* static */
2316nsresult Notification::RemovePermission(nsIPrincipal* aPrincipal) {
2317 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2317); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 2317; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2318 nsCOMPtr<nsIPermissionManager> permissionManager =
2319 mozilla::components::PermissionManager::Service();
2320 if (!permissionManager) {
2321 return NS_ERROR_FAILURE;
2322 }
2323 permissionManager->RemoveFromPrincipal(aPrincipal, "desktop-notification"_ns);
2324 return NS_OK;
2325}
2326
2327/* static */
2328nsresult Notification::OpenSettings(nsIPrincipal* aPrincipal) {
2329 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2329); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 2329; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2330 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
2331 if (!obs) {
2332 return NS_ERROR_FAILURE;
2333 }
2334 // Notify other observers so they can show settings UI.
2335 obs->NotifyObservers(aPrincipal, "notifications-open-settings", nullptr);
2336 return NS_OK;
2337}
2338
2339NS_IMETHODIMPnsresult
2340Notification::Observe(nsISupports* aSubject, const char* aTopic,
2341 const char16_t* aData) {
2342 AssertIsOnMainThread();
2343
2344 if (!strcmp(aTopic, DOM_WINDOW_DESTROYED_TOPIC"dom-window-destroyed") ||
2345 !strcmp(aTopic, DOM_WINDOW_FROZEN_TOPIC"dom-window-frozen")) {
2346 if (SameCOMIdentity(aSubject, ToSupports(GetOwnerWindow()))) {
2347 if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
2348 obs->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC"dom-window-destroyed");
2349 obs->RemoveObserver(this, DOM_WINDOW_FROZEN_TOPIC"dom-window-frozen");
2350 }
2351
2352 CloseInternal(true);
2353 }
2354 }
2355
2356 return NS_OK;
2357}
2358
2359nsresult Notification::DispatchToMainThread(
2360 already_AddRefed<nsIRunnable>&& aRunnable) {
2361 if (mWorkerPrivate) {
2362 return mWorkerPrivate->DispatchToMainThread(std::move(aRunnable));
2363 }
2364 AssertIsOnMainThread();
2365 return NS_DispatchToCurrentThread(std::move(aRunnable));
2366}
2367
2368} // namespace mozilla::dom