Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp
Warning:line 547, 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-30-004816-4182763-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 (mPrincipal->GetIsInPrivateBrowsing() &&
495 !StaticPrefs::dom_webnotifications_privateBrowsing_enabled()) {
496 mPermission = NotificationPermission::Denied;
497 blocked = true;
498 } else {
499 // File are automatically granted permission.
500
501 if (mPrincipal->SchemeIs("file")) {
502 mPermission = NotificationPermission::Granted;
503 } else if (!mWindow->IsSecureContext()) {
504 mPermission = NotificationPermission::Denied;
505 blocked = true;
506 nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
507 if (doc) {
508 nsContentUtils::ReportToConsole(
509 nsIScriptError::errorFlag, "DOM"_ns, doc,
510 nsContentUtils::eDOM_PROPERTIES,
511 "NotificationsInsecureRequestIsForbidden");
512 }
513 }
514 }
515
516 // We can't call ShowPrompt() directly here since our logic for determining
517 // whether to display a prompt depends on the checks above as well as the
518 // result of CheckPromptPrefs(). So we have to manually check the prompt
519 // prefs and decide what to do based on that.
520 PromptResult pr = CheckPromptPrefs();
521 switch (pr) {
522 case PromptResult::Granted:
523 mPermission = NotificationPermission::Granted;
524 break;
525 case PromptResult::Denied:
526 mPermission = NotificationPermission::Denied;
527 break;
528 default:
529 // ignore
530 break;
531 }
532
533 if (!mHasValidTransientUserGestureActivation &&
534 !StaticPrefs::dom_webnotifications_requireuserinteraction()) {
535 nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
536 if (doc) {
537 doc->WarnOnceAbout(Document::eNotificationsRequireUserGestureDeprecation);
538 }
539 }
540
541 // Check this after checking the prompt prefs to make sure this pref overrides
542 // those. We rely on this for testing purposes.
543 if (!isSystem && !blocked &&
544 !StaticPrefs::dom_webnotifications_allowcrossoriginiframe() &&
545 !mPrincipal->Subsumes(mTopLevelPrincipal)) {
546 mPermission = NotificationPermission::Denied;
547 blocked = true;
Value stored to 'blocked' is never read
548 nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
549 if (doc) {
550 nsContentUtils::ReportToConsole(
551 nsIScriptError::errorFlag, "DOM"_ns, doc,
552 nsContentUtils::eDOM_PROPERTIES,
553 "NotificationsCrossOriginIframeRequestIsForbidden");
554 }
555 }
556
557 if (mPermission != NotificationPermission::Default) {
558 return DispatchResolvePromise();
559 }
560
561 return nsContentPermissionUtils::AskPermission(this, mWindow);
562}
563
564NS_IMETHODIMPnsresult
565NotificationPermissionRequest::Cancel() {
566 // `Cancel` is called if the user denied permission or dismissed the
567 // permission request. To distinguish between the two, we set the
568 // permission to "default" and query the permission manager in
569 // `ResolvePromise`.
570 mPermission = NotificationPermission::Default;
571 return DispatchResolvePromise();
572}
573
574NS_IMETHODIMPnsresult
575NotificationPermissionRequest::Allow(JS::Handle<JS::Value> aChoices) {
576 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"
, 576); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChoices.isUndefined()"
")"); do { *((volatile int*)__null) = 576; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
577
578 mPermission = NotificationPermission::Granted;
579 return DispatchResolvePromise();
580}
581
582inline nsresult NotificationPermissionRequest::DispatchResolvePromise() {
583 nsCOMPtr<nsIRunnable> resolver =
584 NewRunnableMethod("NotificationPermissionRequest::DispatchResolvePromise",
585 this, &NotificationPermissionRequest::ResolvePromise);
586 return nsGlobalWindowInner::Cast(mWindow.get())->Dispatch(resolver.forget());
587}
588
589nsresult NotificationPermissionRequest::ResolvePromise() {
590 nsresult rv = NS_OK;
591 // This will still be "default" if the user dismissed the doorhanger,
592 // or "denied" otherwise.
593 if (mPermission == NotificationPermission::Default) {
594 // When the front-end has decided to deny the permission request
595 // automatically and we are not handling user input, then log a
596 // warning in the current document that this happened because
597 // Notifications require a user gesture.
598 if (!mHasValidTransientUserGestureActivation &&
599 StaticPrefs::dom_webnotifications_requireuserinteraction()) {
600 nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
601 if (doc) {
602 nsContentUtils::ReportToConsole(nsIScriptError::errorFlag, "DOM"_ns,
603 doc, nsContentUtils::eDOM_PROPERTIES,
604 "NotificationsRequireUserGesture");
605 }
606 }
607
608 mPermission = Notification::TestPermission(mPrincipal);
609 }
610 if (mCallback) {
611 ErrorResult error;
612 RefPtr<NotificationPermissionCallback> callback(mCallback);
613 callback->Call(mPermission, error);
614 rv = error.StealNSResult();
615 }
616 mPromise->MaybeResolve(mPermission);
617 return rv;
618}
619
620// Observer that the alert service calls to do common tasks and/or dispatch to
621// the specific observer for the context e.g. main thread, worker, or service
622// worker.
623class NotificationObserver final : public nsIObserver {
624 public:
625 nsCOMPtr<nsIObserver> mObserver;
626 nsCOMPtr<nsIPrincipal> mPrincipal;
627 bool mInPrivateBrowsing;
628 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:
629 NS_DECL_NSIOBSERVERvirtual nsresult Observe(nsISupports *aSubject, const char * aTopic
, const char16_t * aData) override;
630
631 NotificationObserver(nsIObserver* aObserver, nsIPrincipal* aPrincipal,
632 bool aInPrivateBrowsing)
633 : mObserver(aObserver),
634 mPrincipal(aPrincipal),
635 mInPrivateBrowsing(aInPrivateBrowsing) {
636 AssertIsOnMainThread();
637 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"
, 637); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mObserver" ")"
); do { *((volatile int*)__null) = 637; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
638 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"
, 638); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mPrincipal" ")"
); do { *((volatile int*)__null) = 638; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
639 }
640
641 protected:
642 virtual ~NotificationObserver() { AssertIsOnMainThread(); }
643
644 nsresult AdjustPushQuota(const char* aTopic);
645};
646
647NS_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"
, 647); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
647; __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"
, 647); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"NotificationObserver\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 647; __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"
, 647); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 647
; __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"
, 647); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"NotificationObserver\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 647; __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"
, 647); 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; }
648
649class MainThreadNotificationObserver : public nsIObserver {
650 public:
651 UniquePtr<NotificationRef> mNotificationRef;
652 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:
653 NS_DECL_NSIOBSERVERvirtual nsresult Observe(nsISupports *aSubject, const char * aTopic
, const char16_t * aData) override;
654
655 explicit MainThreadNotificationObserver(UniquePtr<NotificationRef> aRef)
656 : mNotificationRef(std::move(aRef)) {
657 AssertIsOnMainThread();
658 }
659
660 protected:
661 virtual ~MainThreadNotificationObserver() { AssertIsOnMainThread(); }
662};
663
664NS_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"
, 664); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
664; __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"
, 664); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"MainThreadNotificationObserver\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 664; __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"
, 664); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 664
; __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"
, 664); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"MainThreadNotificationObserver\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 664; __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"
, 664); 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; }
665
666NS_IMETHODIMPnsresult
667NotificationTask::Run() {
668 AssertIsOnMainThread();
669
670 // Get a pointer to notification before the notification takes ownership of
671 // the ref (it owns itself temporarily, with ShowInternal() and
672 // CloseInternal() passing on the ownership appropriately.)
673 Notification* notif = mNotificationRef->GetNotification();
674 notif->mTempRef.swap(mNotificationRef);
675 if (mAction == eShow) {
676 notif->ShowInternal();
677 } else if (mAction == eClose) {
678 notif->CloseInternal();
679 } else {
680 MOZ_CRASH("Invalid action")do { do { } while (false); MOZ_ReportCrash("" "Invalid action"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 680); AnnotateMozCrashReason("MOZ_CRASH(" "Invalid action" ")"
); do { *((volatile int*)__null) = 680; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
681 }
682
683 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"
, 683); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mNotificationRef"
")"); do { *((volatile int*)__null) = 683; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
684 return NS_OK;
685}
686
687// static
688bool Notification::PrefEnabled(JSContext* aCx, JSObject* aObj) {
689 return StaticPrefs::dom_webnotifications_enabled();
690}
691
692Notification::Notification(nsIGlobalObject* aGlobal, const nsAString& aID,
693 const nsAString& aTitle, const nsAString& aBody,
694 NotificationDirection aDir, const nsAString& aLang,
695 const nsAString& aTag, const nsAString& aIconUrl,
696 bool aRequireInteraction, bool aSilent,
697 nsTArray<uint32_t>&& aVibrate,
698 const NotificationBehavior& aBehavior)
699 : DOMEventTargetHelper(aGlobal),
700 mWorkerPrivate(nullptr),
701 mObserver(nullptr),
702 mID(aID),
703 mTitle(aTitle),
704 mBody(aBody),
705 mDir(aDir),
706 mLang(aLang),
707 mTag(aTag),
708 mIconUrl(aIconUrl),
709 mRequireInteraction(aRequireInteraction),
710 mSilent(aSilent),
711 mVibrate(std::move(aVibrate)),
712 mBehavior(aBehavior),
713 mData(JS::NullValue()),
714 mIsClosed(false),
715 mIsStored(false),
716 mTaskCount(0) {
717 if (!NS_IsMainThread()) {
718 mWorkerPrivate = GetCurrentThreadWorkerPrivate();
719 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"
, 719); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWorkerPrivate"
")"); do { *((volatile int*)__null) = 719; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
720 }
721}
722
723nsresult Notification::MaybeObserveWindowFrozen() {
724 // NOTE: Non-persistent notifications can also be opened from workers, but we
725 // don't care and nobody else cares. And it's not clear whether we even should
726 // do this for window at all, see
727 // https://github.com/whatwg/notifications/issues/204.
728 // NOTE: Also GlobalFreezeObserver is only supported for window now.
729 if (!mWorkerPrivate) {
730 GlobalFreezeObserver::BindToOwner(GetOwnerGlobal());
731 }
732
733 return NS_OK;
734}
735
736void Notification::SetAlertName() {
737 AssertIsOnMainThread();
738 if (!mAlertName.IsEmpty()) {
739 return;
740 }
741
742 nsAutoString alertName;
743 nsresult rv = GetOrigin(GetPrincipal(), alertName);
744 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"
, 744)
) {
745 return;
746 }
747
748 // Get the notification name that is unique per origin + tag/ID.
749 // The name of the alert is of the form origin#tag/ID.
750 alertName.Append('#');
751 if (!mTag.IsEmpty()) {
752 alertName.AppendLiteral("tag:");
753 alertName.Append(mTag);
754 } else {
755 alertName.AppendLiteral("notag:");
756 alertName.Append(mID);
757 }
758
759 mAlertName = alertName;
760}
761
762// May be called on any thread.
763// static
764already_AddRefed<Notification> Notification::Constructor(
765 const GlobalObject& aGlobal, const nsAString& aTitle,
766 const NotificationOptions& aOptions, ErrorResult& aRv) {
767 // FIXME(nsm): If the sticky flag is set, throw an error.
768 RefPtr<ServiceWorkerGlobalScope> scope;
769 UNWRAP_OBJECT(ServiceWorkerGlobalScope, aGlobal.Get(), scope)mozilla::dom::binding_detail::UnwrapObjectWithCrossOriginAsserts
< mozilla::dom::prototypes::id::ServiceWorkerGlobalScope, mozilla
::dom::ServiceWorkerGlobalScope_Binding::NativeType>(aGlobal
.Get(), scope)
;
770 if (scope) {
771 aRv.ThrowTypeError(
772 "Notification constructor cannot be used in ServiceWorkerGlobalScope. "
773 "Use registration.showNotification() instead.");
774 return nullptr;
775 }
776
777 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
778 RefPtr<Notification> notification =
779 CreateAndShow(aGlobal.Context(), global, aTitle, aOptions, u""_ns, aRv);
780 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"
, 780)
) {
781 return nullptr;
782 }
783 if (NS_WARN_IF(NS_FAILED(notification->MaybeObserveWindowFrozen()))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(notification
->MaybeObserveWindowFrozen())), 0))), "NS_FAILED(notification->MaybeObserveWindowFrozen())"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 783)
) {
784 return nullptr;
785 }
786
787 // This is be ok since we are on the worker thread where this function will
788 // run to completion before the Notification has a chance to go away.
789 return notification.forget();
790}
791
792// static
793Result<already_AddRefed<Notification>, QMResult>
794Notification::ConstructFromFields(
795 nsIGlobalObject* aGlobal, const nsAString& aID, const nsAString& aTitle,
796 const nsAString& aDir, const nsAString& aLang, const nsAString& aBody,
797 const nsAString& aTag, const nsAString& aIcon, const nsAString& aData,
798 const nsAString& aServiceWorkerRegistrationScope) {
799 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"
, 799); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGlobal" ")"
); do { *((volatile int*)__null) = 799; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
800
801 RootedDictionary<NotificationOptions> options(RootingCx());
802 options.mDir = StringToEnum<NotificationDirection>(aDir).valueOr(
803 NotificationDirection::Auto);
804 options.mLang = aLang;
805 options.mBody = aBody;
806 options.mTag = aTag;
807 options.mIcon = aIcon;
808 IgnoredErrorResult rv;
809 RefPtr<Notification> notification =
810 CreateInternal(aGlobal, aID, aTitle, options, rv);
811 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"
, 811)
) {
812 return Err(ToQMResult(NS_ERROR_FAILURE));
813 }
814
815 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"
, 815, mozilla::dom::quota::Severity::Error); return tryResult12
.propagateErr(); }}
;
816
817 notification->SetScope(aServiceWorkerRegistrationScope);
818
819 return notification.forget();
820}
821
822nsresult Notification::PersistNotification() {
823 AssertIsOnMainThread();
824
825 nsCOMPtr<nsINotificationStorage> notificationStorage =
826 GetNotificationStorage(IsInPrivateBrowsing());
827 if (NS_WARN_IF(!notificationStorage)NS_warn_if_impl(!notificationStorage, "!notificationStorage",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 827)
) {
828 return NS_ERROR_UNEXPECTED;
829 }
830
831 nsString origin;
832 nsresult rv = GetOrigin(GetPrincipal(), origin);
833 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"
, 833)
) {
834 return rv;
835 }
836
837 nsString id;
838 GetID(id);
839
840 nsString alertName;
841 GetAlertName(alertName);
842
843 nsAutoString behavior;
844 if (!mBehavior.ToJSON(behavior)) {
845 return NS_ERROR_FAILURE;
846 }
847
848 rv = notificationStorage->Put(origin, id, mTitle, GetEnumString(mDir), mLang,
849 mBody, mTag, mIconUrl, alertName, mDataAsBase64,
850 behavior, mScope);
851
852 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
853 return rv;
854 }
855
856 SetStoredState(true);
857 return NS_OK;
858}
859
860void Notification::UnpersistNotification() {
861 AssertIsOnMainThread();
862 if (IsStored()) {
863 nsCOMPtr<nsINotificationStorage> notificationStorage =
864 GetNotificationStorage(IsInPrivateBrowsing());
865 if (notificationStorage) {
866 nsString origin;
867 nsresult rv = GetOrigin(GetPrincipal(), origin);
868 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
869 notificationStorage->Delete(origin, mID);
870 }
871 }
872 SetStoredState(false);
873 }
874}
875
876// https://notifications.spec.whatwg.org/#create-a-notification
877already_AddRefed<Notification> Notification::CreateInternal(
878 nsIGlobalObject* aGlobal, const nsAString& aID, const nsAString& aTitle,
879 const NotificationOptions& aOptions, ErrorResult& aRv) {
880 nsresult rv;
881 nsString id;
882 if (!aID.IsEmpty()) {
883 id = aID;
884 } else {
885 nsCOMPtr<nsIUUIDGenerator> uuidgen =
886 do_GetService("@mozilla.org/uuid-generator;1");
887 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"
, 887); return nullptr; } } while (false)
;
888 nsID uuid;
889 rv = uuidgen->GenerateUUIDInPlace(&uuid);
890 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"
, 890); return nullptr; } } while (false)
;
891
892 char buffer[NSID_LENGTH39];
893 uuid.ToProvidedString(buffer);
894 NS_ConvertASCIItoUTF16 convertedID(buffer);
895 id = convertedID;
896 }
897
898 // Step 20: Set notification’s silent preference to options["silent"].
899 bool silent = false;
900 if (StaticPrefs::dom_webnotifications_silent_enabled()) {
901 silent = aOptions.mSilent;
902 }
903
904 nsTArray<uint32_t> vibrate;
905 if (StaticPrefs::dom_webnotifications_vibrate_enabled() &&
906 aOptions.mVibrate.WasPassed()) {
907 // Step 4: If options["silent"] is true and options["vibrate"] exists, then
908 // throw a TypeError.
909 if (silent) {
910 aRv.ThrowTypeError(
911 "Silent notifications must not specify vibration patterns.");
912 return nullptr;
913 }
914
915 // Step 17: If options["vibrate"] exists, then validate and normalize it and
916 // set notification’s vibration pattern to the return value.
917 const OwningUnsignedLongOrUnsignedLongSequence& value =
918 aOptions.mVibrate.Value();
919 if (value.IsUnsignedLong()) {
920 AutoTArray<uint32_t, 1> array;
921 array.AppendElement(value.GetAsUnsignedLong());
922 vibrate = SanitizeVibratePattern(array);
923 } else {
924 vibrate = SanitizeVibratePattern(value.GetAsUnsignedLongSequence());
925 }
926 }
927
928 // Step 15: If options["icon"] exists, then parse it using baseURL, and if
929 // that does not return failure, set notification’s icon URL to the return
930 // value. (Otherwise icon URL is not set.)
931 nsString iconUrl = aOptions.mIcon;
932 NotificationBehavior behavior{aOptions.mMozbehavior};
933 ResolveIconAndSoundURL(aGlobal, iconUrl, behavior.mSoundFile);
934
935 RefPtr<Notification> notification = new Notification(
936 aGlobal, id, aTitle, aOptions.mBody, aOptions.mDir, aOptions.mLang,
937 aOptions.mTag, iconUrl, aOptions.mRequireInteraction, silent,
938 std::move(vibrate), behavior);
939 return notification.forget();
940}
941
942Notification::~Notification() {
943 mozilla::DropJSObjects(this);
944 AssertIsOnTargetThread();
945 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"
, 945); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mWorkerRef"
")"); do { *((volatile int*)__null) = 945; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
946 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"
, 946); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mTempRef" ")"
); do { *((volatile int*)__null) = 946; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
947}
948
949NS_IMPL_CYCLE_COLLECTION_CLASS(Notification)Notification::cycleCollection Notification::_cycleCollectorGlobal
;
950NS_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);
951 DOMEventTargetHelper)void Notification::cycleCollection::Unlink(void* p) { Notification
* tmp = DowncastCCParticipant<Notification>(p); nsISupports
* s = static_cast<nsISupports*>(p); DOMEventTargetHelper
::cycleCollection::Unlink(s);
952 tmp->mData.setUndefined();
953NS_IMPL_CYCLE_COLLECTION_UNLINK_END(void)tmp; }
954
955NS_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; }
956 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; }
957NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END(void)tmp; return NS_OK; }
958
959NS_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);
960 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);
961 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mData)aCallbacks.Trace(&tmp->mData, "mData", aClosure);
962NS_IMPL_CYCLE_COLLECTION_TRACE_END(void)tmp; }
963
964NS_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; }
965NS_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; }
966
967NS_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"
, 967); 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
968NS_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; }
969
970nsIPrincipal* Notification::GetPrincipal() {
971 AssertIsOnMainThread();
972 if (mWorkerPrivate) {
973 return mWorkerPrivate->GetPrincipal();
974 }
975 nsGlobalWindowInner* win = GetOwnerWindow();
976 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"
, 976); return nullptr; } } while (false)
;
977 return win->GetPrincipal();
978}
979
980class WorkerNotificationObserver final : public MainThreadNotificationObserver {
981 public:
982 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; }
983 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; }
984 NS_DECL_NSIOBSERVERvirtual nsresult Observe(nsISupports *aSubject, const char * aTopic
, const char16_t * aData) override;
985
986 explicit WorkerNotificationObserver(UniquePtr<NotificationRef> aRef)
987 : MainThreadNotificationObserver(std::move(aRef)) {
988 AssertIsOnMainThread();
989 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"
, 989); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mNotificationRef->GetNotification()->mWorkerPrivate"
")"); do { *((volatile int*)__null) = 989; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
990 }
991
992 void ForgetNotification() {
993 AssertIsOnMainThread();
994 mNotificationRef->Forget();
995 }
996
997 protected:
998 virtual ~WorkerNotificationObserver() {
999 AssertIsOnMainThread();
1000
1001 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"
, 1001); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mNotificationRef"
")"); do { *((volatile int*)__null) = 1001; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1002 Notification* notification = mNotificationRef->GetNotification();
1003 if (notification) {
1004 notification->mObserver = nullptr;
1005 }
1006 }
1007};
1008
1009class ServiceWorkerNotificationObserver final : public nsIObserver {
1010 public:
1011 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:
1012 NS_DECL_NSIOBSERVERvirtual nsresult Observe(nsISupports *aSubject, const char * aTopic
, const char16_t * aData) override;
1013
1014 ServiceWorkerNotificationObserver(
1015 const nsAString& aScope, nsIPrincipal* aPrincipal, const nsAString& aID,
1016 const nsAString& aTitle, NotificationDirection aDir,
1017 const nsAString& aLang, const nsAString& aBody, const nsAString& aTag,
1018 const nsAString& aIcon, const nsAString& aData,
1019 const nsAString& aBehavior)
1020 : mScope(aScope),
1021 mID(aID),
1022 mPrincipal(aPrincipal),
1023 mTitle(aTitle),
1024 mDir(aDir),
1025 mLang(aLang),
1026 mBody(aBody),
1027 mTag(aTag),
1028 mIcon(aIcon),
1029 mData(aData),
1030 mBehavior(aBehavior) {
1031 AssertIsOnMainThread();
1032 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"
, 1032); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPrincipal"
")"); do { *((volatile int*)__null) = 1032; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1033 }
1034
1035 private:
1036 ~ServiceWorkerNotificationObserver() = default;
1037
1038 const nsString mScope;
1039 const nsString mID;
1040 nsCOMPtr<nsIPrincipal> mPrincipal;
1041 const nsString mTitle;
1042 const NotificationDirection mDir;
1043 const nsString mLang;
1044 const nsString mBody;
1045 const nsString mTag;
1046 const nsString mIcon;
1047 const nsString mData;
1048 const nsString mBehavior;
1049};
1050
1051NS_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"
, 1051); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
1051; __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"
, 1051); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"ServiceWorkerNotificationObserver\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 1051; __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"
, 1051); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 1051
; __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"
, 1051); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"ServiceWorkerNotificationObserver\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 1051; __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"
, 1051); 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; }
1052
1053bool Notification::DispatchClickEvent() {
1054 AssertIsOnTargetThread();
1055 RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
1056 event->InitEvent(u"click"_ns, false, true);
1057 event->SetTrusted(true);
1058 WantsPopupControlCheck popupControlCheck(event);
1059 return DispatchEvent(*event, CallerType::System, IgnoreErrors());
1060}
1061
1062// Overrides dispatch and run handlers so we can directly dispatch from main
1063// thread to child workers.
1064class NotificationClickWorkerRunnable final
1065 : public NotificationWorkerRunnable {
1066 Notification* mNotification;
1067 // Optional window that gets focused if click event is not
1068 // preventDefault()ed.
1069 nsMainThreadPtrHandle<nsPIDOMWindowInner> mWindow;
1070
1071 public:
1072 NotificationClickWorkerRunnable(
1073 Notification* aNotification,
1074 const nsMainThreadPtrHandle<nsPIDOMWindowInner>& aWindow)
1075 : NotificationWorkerRunnable(aNotification->mWorkerPrivate,
1076 "NotificationClickWorkerRunnable"),
1077 mNotification(aNotification),
1078 mWindow(aWindow) {
1079 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"
, 1079); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mWindow" ")"
); do { *((volatile int*)__null) = 1079; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1080 }
1081
1082 void WorkerRunInternal(WorkerPrivate* aWorkerPrivate) override {
1083 bool doDefaultAction = mNotification->DispatchClickEvent();
1084 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"
, 1085); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!doDefaultAction"
")"); do { *((volatile int*)__null) = 1085; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1085 !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"
, 1085); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!doDefaultAction"
")"); do { *((volatile int*)__null) = 1085; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1086 if (doDefaultAction) {
1087 RefPtr<FocusWindowRunnable> r = new FocusWindowRunnable(mWindow);
1088 mNotification->mWorkerPrivate->DispatchToMainThread(r.forget());
1089 }
1090 }
1091};
1092
1093NS_IMETHODIMPnsresult
1094NotificationObserver::Observe(nsISupports* aSubject, const char* aTopic,
1095 const char16_t* aData) {
1096 AssertIsOnMainThread();
1097
1098 if (!strcmp("alertdisablecallback", aTopic)) {
1099 if (XRE_IsParentProcess()) {
1100 return Notification::RemovePermission(mPrincipal);
1101 }
1102 // Permissions can't be removed from the content process. Send a message
1103 // to the parent; `ContentParent::RecvDisableNotifications` will call
1104 // `RemovePermission`.
1105 ContentChild::GetSingleton()->SendDisableNotifications(mPrincipal);
1106 return NS_OK;
1107 } else if (!strcmp("alertsettingscallback", aTopic)) {
1108 if (XRE_IsParentProcess()) {
1109 return Notification::OpenSettings(mPrincipal);
1110 }
1111 // `ContentParent::RecvOpenNotificationSettings` notifies observers in the
1112 // parent process.
1113 ContentChild::GetSingleton()->SendOpenNotificationSettings(mPrincipal);
1114 return NS_OK;
1115 } else if (!strcmp("alertshow", aTopic) || !strcmp("alertfinished", aTopic)) {
1116 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"
, 1116)
;
1117 }
1118
1119 return mObserver->Observe(aSubject, aTopic, aData);
1120}
1121
1122nsresult NotificationObserver::AdjustPushQuota(const char* aTopic) {
1123 nsCOMPtr<nsIPushQuotaManager> pushQuotaManager =
1124 do_GetService("@mozilla.org/push/Service;1");
1125 if (!pushQuotaManager) {
1126 return NS_ERROR_FAILURE;
1127 }
1128
1129 nsAutoCString origin;
1130 nsresult rv = mPrincipal->GetOrigin(origin);
1131 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1132 return rv;
1133 }
1134
1135 if (!strcmp("alertshow", aTopic)) {
1136 return pushQuotaManager->NotificationForOriginShown(origin.get());
1137 }
1138 return pushQuotaManager->NotificationForOriginClosed(origin.get());
1139}
1140
1141// MOZ_CAN_RUN_SCRIPT_BOUNDARY until Runnable::Run is MOZ_CAN_RUN_SCRIPT. See
1142// bug 1539845.
1143MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMPnsresult
1144MainThreadNotificationObserver::Observe(nsISupports* aSubject,
1145 const char* aTopic,
1146 const char16_t* aData) {
1147 AssertIsOnMainThread();
1148 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"
, 1148); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mNotificationRef"
")"); do { *((volatile int*)__null) = 1148; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1149 Notification* notification = mNotificationRef->GetNotification();
1150 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"
, 1150); AnnotateMozCrashReason("MOZ_ASSERT" "(" "notification"
")"); do { *((volatile int*)__null) = 1150; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1151 if (!strcmp("alertclickcallback", aTopic)) {
1152 nsCOMPtr<nsPIDOMWindowInner> window = notification->GetOwnerWindow();
1153 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"
, 1153)
) {
1154 // Window has been closed, this observer is not valid anymore
1155 return NS_ERROR_FAILURE;
1156 }
1157
1158 bool doDefaultAction = notification->DispatchClickEvent();
1159 if (doDefaultAction) {
1160 nsCOMPtr<nsPIDOMWindowOuter> outerWindow = window->GetOuterWindow();
1161 nsFocusManager::FocusWindow(outerWindow, CallerType::System);
1162 }
1163 } else if (!strcmp("alertfinished", aTopic)) {
1164 notification->UnpersistNotification();
1165 notification->mIsClosed = true;
1166 notification->DispatchTrustedEvent(u"close"_ns);
1167 } else if (!strcmp("alertshow", aTopic)) {
1168 notification->DispatchTrustedEvent(u"show"_ns);
1169 }
1170 return NS_OK;
1171}
1172
1173NS_IMETHODIMPnsresult
1174WorkerNotificationObserver::Observe(nsISupports* aSubject, const char* aTopic,
1175 const char16_t* aData) {
1176 AssertIsOnMainThread();
1177 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"
, 1177); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mNotificationRef"
")"); do { *((volatile int*)__null) = 1177; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1178 // For an explanation of why it is OK to pass this rawptr to the event
1179 // runnables, see the Notification class comment.
1180 Notification* notification = mNotificationRef->GetNotification();
1181 // We can't assert notification here since the feature could've unset it.
1182 if (NS_WARN_IF(!notification)NS_warn_if_impl(!notification, "!notification", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1182)
) {
1183 return NS_ERROR_FAILURE;
1184 }
1185
1186 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"
, 1186); AnnotateMozCrashReason("MOZ_ASSERT" "(" "notification->mWorkerPrivate"
")"); do { *((volatile int*)__null) = 1186; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1187
1188 RefPtr<WorkerThreadRunnable> r;
1189 if (!strcmp("alertclickcallback", aTopic)) {
1190 nsPIDOMWindowInner* window = nullptr;
1191 if (!notification->mWorkerPrivate->IsServiceWorker()) {
1192 window = notification->mWorkerPrivate->GetAncestorWindow();
1193 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"
, 1193)
) {
1194 // Window has been closed, this observer is not valid anymore
1195 return NS_ERROR_FAILURE;
1196 }
1197 }
1198
1199 // Instead of bothering with adding features and other worker lifecycle
1200 // management, we simply hold strongrefs to the window and document.
1201 nsMainThreadPtrHandle<nsPIDOMWindowInner> windowHandle(
1202 new nsMainThreadPtrHolder<nsPIDOMWindowInner>(
1203 "WorkerNotificationObserver::Observe::nsPIDOMWindowInner", window));
1204
1205 r = new NotificationClickWorkerRunnable(notification, windowHandle);
1206 } else if (!strcmp("alertfinished", aTopic)) {
1207 notification->UnpersistNotification();
1208 notification->mIsClosed = true;
1209 r = new NotificationEventWorkerRunnable(notification, u"close"_ns);
1210 } else if (!strcmp("alertshow", aTopic)) {
1211 r = new NotificationEventWorkerRunnable(notification, u"show"_ns);
1212 }
1213
1214 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"
, 1214); AnnotateMozCrashReason("MOZ_ASSERT" "(" "r" ")"); do
{ *((volatile int*)__null) = 1214; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
1215 if (!r->Dispatch(notification->mWorkerPrivate)) {
1216 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"
, 1216)
;
1217 }
1218 return NS_OK;
1219}
1220
1221NS_IMETHODIMPnsresult
1222ServiceWorkerNotificationObserver::Observe(nsISupports* aSubject,
1223 const char* aTopic,
1224 const char16_t* aData) {
1225 AssertIsOnMainThread();
1226
1227 nsAutoCString originSuffix;
1228 nsresult rv = mPrincipal->GetOriginSuffix(originSuffix);
1229 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"
, 1229)
) {
1230 return rv;
1231 }
1232
1233 if (!strcmp("alertclickcallback", aTopic)) {
1234 if (XRE_IsParentProcess()) {
1235 nsCOMPtr<nsIServiceWorkerManager> swm =
1236 mozilla::components::ServiceWorkerManager::Service();
1237 if (NS_WARN_IF(!swm)NS_warn_if_impl(!swm, "!swm", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1237)
) {
1238 return NS_ERROR_FAILURE;
1239 }
1240
1241 rv = swm->SendNotificationClickEvent(
1242 originSuffix, NS_ConvertUTF16toUTF8(mScope), mID, mTitle,
1243 NS_ConvertASCIItoUTF16(GetEnumString(mDir)), mLang, mBody, mTag,
1244 mIcon, mData, mBehavior);
1245 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"
, 1245)
;
1246 } else {
1247 auto* cc = ContentChild::GetSingleton();
1248 NotificationEventData data(originSuffix, NS_ConvertUTF16toUTF8(mScope),
1249 mID, mTitle,
1250 NS_ConvertASCIItoUTF16(GetEnumString(mDir)),
1251 mLang, mBody, mTag, mIcon, mData, mBehavior);
1252 Unused << cc->SendNotificationEvent(u"click"_ns, data);
1253 }
1254 return NS_OK;
1255 }
1256
1257 if (!strcmp("alertfinished", aTopic)) {
1258 nsString origin;
1259 nsresult rv = Notification::GetOrigin(mPrincipal, origin);
1260 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"
, 1260)
) {
1261 return rv;
1262 }
1263
1264 // Remove closed or dismissed persistent notifications.
1265 nsCOMPtr<nsINotificationStorage> notificationStorage =
1266 GetNotificationStorage(mPrincipal->GetIsInPrivateBrowsing());
1267 if (notificationStorage) {
1268 notificationStorage->Delete(origin, mID);
1269 }
1270
1271 if (XRE_IsParentProcess()) {
1272 nsCOMPtr<nsIServiceWorkerManager> swm =
1273 mozilla::components::ServiceWorkerManager::Service();
1274 if (NS_WARN_IF(!swm)NS_warn_if_impl(!swm, "!swm", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1274)
) {
1275 return NS_ERROR_FAILURE;
1276 }
1277
1278 rv = swm->SendNotificationCloseEvent(
1279 originSuffix, NS_ConvertUTF16toUTF8(mScope), mID, mTitle,
1280 NS_ConvertASCIItoUTF16(GetEnumString(mDir)), mLang, mBody, mTag,
1281 mIcon, mData, mBehavior);
1282 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"
, 1282)
;
1283 } else {
1284 auto* cc = ContentChild::GetSingleton();
1285 NotificationEventData data(originSuffix, NS_ConvertUTF16toUTF8(mScope),
1286 mID, mTitle,
1287 NS_ConvertASCIItoUTF16(GetEnumString(mDir)),
1288 mLang, mBody, mTag, mIcon, mData, mBehavior);
1289 Unused << cc->SendNotificationEvent(u"close"_ns, data);
1290 }
1291 return NS_OK;
1292 }
1293
1294 return NS_OK;
1295}
1296
1297bool Notification::IsInPrivateBrowsing() {
1298 AssertIsOnMainThread();
1299
1300 Document* doc = nullptr;
1301
1302 if (mWorkerPrivate) {
1303 doc = mWorkerPrivate->GetDocument();
1304 } else if (nsGlobalWindowInner* win = GetOwnerWindow()) {
1305 doc = win->GetExtantDoc();
1306 }
1307
1308 if (doc) {
1309 nsCOMPtr<nsILoadContext> loadContext = doc->GetLoadContext();
1310 return loadContext && loadContext->UsePrivateBrowsing();
1311 }
1312
1313 if (mWorkerPrivate) {
1314 // Not all workers may have a document, but with Bug 1107516 fixed, they
1315 // should all have a loadcontext.
1316 nsCOMPtr<nsILoadGroup> loadGroup = mWorkerPrivate->GetLoadGroup();
1317 nsCOMPtr<nsILoadContext> loadContext;
1318 NS_QueryNotificationCallbacks(nullptr, loadGroup,
1319 NS_GET_IID(nsILoadContext)(nsILoadContext::COMTypeInfo<nsILoadContext, void>::kIID
)
,
1320 getter_AddRefs(loadContext));
1321 return loadContext && loadContext->UsePrivateBrowsing();
1322 }
1323
1324 // XXXnsm Should this default to true?
1325 return false;
1326}
1327
1328// Step 4 of
1329// https://notifications.spec.whatwg.org/#dom-notification-notification
1330void Notification::ShowInternal() {
1331 AssertIsOnMainThread();
1332 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"
, 1334); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTempRef" ") ("
"Notification should take ownership of itself before" "calling ShowInternal!"
")"); do { *((volatile int*)__null) = 1334; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1333 "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"
, 1334); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTempRef" ") ("
"Notification should take ownership of itself before" "calling ShowInternal!"
")"); do { *((volatile int*)__null) = 1334; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1334 "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"
, 1334); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTempRef" ") ("
"Notification should take ownership of itself before" "calling ShowInternal!"
")"); do { *((volatile int*)__null) = 1334; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1335 // A notification can only have one observer and one call to ShowInternal.
1336 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"
, 1336); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mObserver"
")"); do { *((volatile int*)__null) = 1336; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1337
1338 // Transfer ownership to local scope so we can either release it at the end
1339 // of this function or transfer it to the observer.
1340 UniquePtr<NotificationRef> ownership;
1341 std::swap(ownership, mTempRef);
1342 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"
, 1342); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ownership->GetNotification() == this"
")"); do { *((volatile int*)__null) = 1342; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1343
1344 nsCOMPtr<nsIAlertsService> alertService = components::Alerts::Service();
1345
1346 // Step 4.1: If the result of getting the notifications permission state is
1347 // not "granted", then queue a task to fire an event named error on this, and
1348 // abort these steps.
1349 //
1350 // XXX(krosylight): But this function is also triggered by
1351 // Notification::ShowPersistentNotification which already does its own
1352 // permission check. Can we split this?
1353 ErrorResult result;
1354 NotificationPermission permission = NotificationPermission::Denied;
1355 if (mWorkerPrivate) {
1356 permission = GetPermissionInternal(mWorkerPrivate->GetPrincipal(), result);
1357 } else {
1358 permission = GetPermissionInternal(GetOwnerWindow(), result);
1359 }
1360 // We rely on GetPermissionInternal returning Denied on all failure codepaths.
1361 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"
, 1361); AnnotateMozCrashReason("MOZ_ASSERT" "(" "permission == NotificationPermission::Denied"
")"); do { *((volatile int*)__null) = 1361; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1362 result.SuppressException();
1363 if (permission != NotificationPermission::Granted || !alertService) {
1364 if (mWorkerPrivate) {
1365 RefPtr<NotificationEventWorkerRunnable> r =
1366 new NotificationEventWorkerRunnable(this, u"error"_ns);
1367 if (!r->Dispatch(mWorkerPrivate)) {
1368 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"
, 1368)
;
1369 }
1370 } else {
1371 DispatchTrustedEvent(u"error"_ns);
1372 }
1373 mIsClosed = true;
1374 return;
1375 }
1376
1377 // Step 4.3 the show steps, which are almost all about processing `tag` and
1378 // then displaying the notification. Both are handled by
1379 // nsIAlertsService::ShowAlert/PersistentNotification. The below is all about
1380 // constructing the observer (for show and close events) right and ultimately
1381 // call the alerts service function.
1382
1383 // XXX(krosylight): Non-persistent notifications probably don't need this
1384 nsresult rv = PersistNotification();
1385 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1386 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"
, 1386)
;
1387 }
1388
1389 bool isPersistent = false;
1390 nsCOMPtr<nsIObserver> observer;
1391 if (mScope.IsEmpty()) {
1392 // Ownership passed to observer.
1393 if (mWorkerPrivate) {
1394 // Scope better be set on ServiceWorker initiated requests.
1395 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"
, 1395); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mWorkerPrivate->IsServiceWorker()"
")"); do { *((volatile int*)__null) = 1395; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1396 // Keep a pointer so that the feature can tell the observer not to release
1397 // the notification.
1398 mObserver = new WorkerNotificationObserver(std::move(ownership));
1399 observer = mObserver;
1400 } else {
1401 observer = new MainThreadNotificationObserver(std::move(ownership));
1402 }
1403 } else {
1404 isPersistent = true;
1405 // This observer does not care about the Notification. It will be released
1406 // at the end of this function.
1407 //
1408 // The observer is wholly owned by the NotificationObserver passed to the
1409 // alert service.
1410 nsAutoString behavior;
1411 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"
, 1411)
) {
1412 behavior.Truncate();
1413 }
1414 observer = new ServiceWorkerNotificationObserver(
1415 mScope, GetPrincipal(), mID, mTitle, mDir, mLang, mBody, mTag, mIconUrl,
1416 mDataAsBase64, behavior);
1417 }
1418 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"
, 1418); AnnotateMozCrashReason("MOZ_ASSERT" "(" "observer" ")"
); do { *((volatile int*)__null) = 1418; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1419 nsCOMPtr<nsIObserver> alertObserver =
1420 new NotificationObserver(observer, GetPrincipal(), IsInPrivateBrowsing());
1421
1422 // In the case of IPC, the parent process uses the cookie to map to
1423 // nsIObserver. Thus the cookie must be unique to differentiate observers.
1424 nsString uniqueCookie = u"notification:"_ns;
1425 uniqueCookie.AppendInt(sCount++);
1426 bool inPrivateBrowsing = IsInPrivateBrowsing();
1427
1428 bool requireInteraction = mRequireInteraction;
1429 if (!StaticPrefs::dom_webnotifications_requireinteraction_enabled()) {
1430 requireInteraction = false;
1431 }
1432
1433 nsAutoString alertName;
1434 GetAlertName(alertName);
1435 nsCOMPtr<nsIAlertNotification> alert =
1436 do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID"@mozilla.org/alert-notification;1");
1437 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"
, 1437); return; } } while (false)
;
1438 nsIPrincipal* principal = GetPrincipal();
1439 rv = alert->Init(alertName, mIconUrl, mTitle, mBody, true, uniqueCookie,
1440 NS_ConvertASCIItoUTF16(GetEnumString(mDir)), mLang,
1441 mDataAsBase64, GetPrincipal(), inPrivateBrowsing,
1442 requireInteraction, mSilent, mVibrate);
1443 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"
, 1443); return; } } while (false)
;
1444
1445 if (isPersistent) {
1446 JSONStringWriteFunc<nsAutoCString> persistentData;
1447 JSONWriter w(persistentData);
1448 w.Start();
1449
1450 nsAutoString origin;
1451 Notification::GetOrigin(principal, origin);
1452 w.StringProperty("origin", NS_ConvertUTF16toUTF8(origin));
1453
1454 w.StringProperty("id", NS_ConvertUTF16toUTF8(mID));
1455
1456 nsAutoCString originSuffix;
1457 principal->GetOriginSuffix(originSuffix);
1458 w.StringProperty("originSuffix", originSuffix);
1459
1460 w.End();
1461
1462 alertService->ShowPersistentNotification(
1463 NS_ConvertUTF8toUTF16(persistentData.StringCRef()), alert,
1464 alertObserver);
1465 } else {
1466 alertService->ShowAlert(alert, alertObserver);
1467 }
1468}
1469
1470/* static */
1471bool Notification::RequestPermissionEnabledForScope(JSContext* aCx,
1472 JSObject* /* unused */) {
1473 // requestPermission() is not allowed on workers. The calling page should ask
1474 // for permission on the worker's behalf. This is to prevent 'which window
1475 // should show the browser pop-up'. See discussion:
1476 // http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2013-October/041272.html
1477 return NS_IsMainThread();
1478}
1479
1480// static
1481already_AddRefed<Promise> Notification::RequestPermission(
1482 const GlobalObject& aGlobal,
1483 const Optional<OwningNonNull<NotificationPermissionCallback> >& aCallback,
1484 ErrorResult& aRv) {
1485 AssertIsOnMainThread();
1486
1487 // Get principal from global to make permission request for notifications.
1488 nsCOMPtr<nsPIDOMWindowInner> window =
1489 do_QueryInterface(aGlobal.GetAsSupports());
1490 nsCOMPtr<nsIScriptObjectPrincipal> sop =
1491 do_QueryInterface(aGlobal.GetAsSupports());
1492 if (!sop || !window) {
1493 aRv.Throw(NS_ERROR_UNEXPECTED);
1494 return nullptr;
1495 }
1496
1497 nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
1498 if (!principal) {
1499 aRv.Throw(NS_ERROR_UNEXPECTED);
1500 return nullptr;
1501 }
1502
1503 RefPtr<Promise> promise = Promise::Create(window->AsGlobal(), aRv);
1504 if (aRv.Failed()) {
1505 return nullptr;
1506 }
1507 NotificationPermissionCallback* permissionCallback = nullptr;
1508 if (aCallback.WasPassed()) {
1509 permissionCallback = &aCallback.Value();
1510 }
1511 nsCOMPtr<nsIRunnable> request = new NotificationPermissionRequest(
1512 principal, window, promise, permissionCallback);
1513
1514 window->AsGlobal()->Dispatch(request.forget());
1515
1516 return promise.forget();
1517}
1518
1519// static
1520NotificationPermission Notification::GetPermission(const GlobalObject& aGlobal,
1521 ErrorResult& aRv) {
1522 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
1523 return GetPermission(global, aRv);
1524}
1525
1526// static
1527NotificationPermission Notification::GetPermission(nsIGlobalObject* aGlobal,
1528 ErrorResult& aRv) {
1529 if (NS_IsMainThread()) {
1530 return GetPermissionInternal(aGlobal->GetAsInnerWindow(), aRv);
1531 } else {
1532 WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
1533 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"
, 1533); AnnotateMozCrashReason("MOZ_ASSERT" "(" "worker" ")"
); do { *((volatile int*)__null) = 1533; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1534 RefPtr<GetPermissionRunnable> r = new GetPermissionRunnable(worker);
1535 r->Dispatch(worker, Canceling, aRv);
1536 if (aRv.Failed()) {
1537 return NotificationPermission::Denied;
1538 }
1539
1540 return r->GetPermission();
1541 }
1542}
1543
1544/* static */
1545NotificationPermission Notification::GetPermissionInternal(
1546 nsPIDOMWindowInner* aWindow, ErrorResult& aRv) {
1547 // Get principal from global to check permission for notifications.
1548 nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
1549 if (!sop) {
1550 aRv.Throw(NS_ERROR_UNEXPECTED);
1551 return NotificationPermission::Denied;
1552 }
1553
1554 nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
1555 if (!principal) {
1556 aRv.Throw(NS_ERROR_UNEXPECTED);
1557 return NotificationPermission::Denied;
1558 }
1559
1560 if (principal->GetIsInPrivateBrowsing() &&
1561 !StaticPrefs::dom_webnotifications_privateBrowsing_enabled()) {
1562 return NotificationPermission::Denied;
1563 }
1564 // Disallow showing notification if our origin is not the same origin as the
1565 // toplevel one, see https://github.com/whatwg/notifications/issues/177.
1566 if (!StaticPrefs::dom_webnotifications_allowcrossoriginiframe()) {
1567 nsCOMPtr<nsIScriptObjectPrincipal> topSop =
1568 do_QueryInterface(aWindow->GetBrowsingContext()->Top()->GetDOMWindow());
1569 nsIPrincipal* topPrincipal = topSop ? topSop->GetPrincipal() : nullptr;
1570 if (!topPrincipal || !principal->Subsumes(topPrincipal)) {
1571 return NotificationPermission::Denied;
1572 }
1573 }
1574
1575 return GetPermissionInternal(principal, aRv);
1576}
1577
1578/* static */
1579NotificationPermission Notification::GetPermissionInternal(
1580 nsIPrincipal* aPrincipal, ErrorResult& aRv) {
1581 AssertIsOnMainThread();
1582 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"
, 1582); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPrincipal"
")"); do { *((volatile int*)__null) = 1582; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1583
1584 if (aPrincipal->IsSystemPrincipal()) {
1585 return NotificationPermission::Granted;
1586 } else {
1587 // Allow files to show notifications by default.
1588 if (aPrincipal->SchemeIs("file")) {
1589 return NotificationPermission::Granted;
1590 }
1591 }
1592
1593 return TestPermission(aPrincipal);
1594}
1595
1596/* static */
1597NotificationPermission Notification::TestPermission(nsIPrincipal* aPrincipal) {
1598 AssertIsOnMainThread();
1599
1600 uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION;
1601
1602 nsCOMPtr<nsIPermissionManager> permissionManager =
1603 components::PermissionManager::Service();
1604 if (!permissionManager) {
1605 return NotificationPermission::Default;
1606 }
1607
1608 permissionManager->TestExactPermissionFromPrincipal(
1609 aPrincipal, "desktop-notification"_ns, &permission);
1610
1611 // Convert the result to one of the enum types.
1612 switch (permission) {
1613 case nsIPermissionManager::ALLOW_ACTION:
1614 return NotificationPermission::Granted;
1615 case nsIPermissionManager::DENY_ACTION:
1616 return NotificationPermission::Denied;
1617 default:
1618 return NotificationPermission::Default;
1619 }
1620}
1621
1622nsresult Notification::ResolveIconAndSoundURL(nsIGlobalObject* aGlobal,
1623 nsString& iconUrl,
1624 nsString& soundUrl) {
1625 nsresult rv = NS_OK;
1626
1627 nsCOMPtr<nsIURI> baseUri = nullptr;
1628
1629 // XXXnsm If I understand correctly, the character encoding for resolving
1630 // URIs in new specs is dictated by the URL spec, which states that unless
1631 // the URL parser is passed an override encoding, the charset to be used is
1632 // UTF-8. The new Notification icon/sound specification just says to use the
1633 // Fetch API, where the Request constructor defers to URL parsing specifying
1634 // the API base URL and no override encoding. So we've to use UTF-8 on
1635 // workers, but for backwards compat keeping it document charset on main
1636 // thread.
1637 auto encoding = UTF_8_ENCODING;
1638
1639 if (nsCOMPtr<nsPIDOMWindowInner> window = aGlobal->GetAsInnerWindow()) {
1640 if (RefPtr<Document> doc = window->GetExtantDoc()) {
1641 baseUri = doc->GetBaseURI();
1642 encoding = doc->GetDocumentCharacterSet();
1643 } else {
1644 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"
, 1644)
;
1645 return NS_ERROR_FAILURE;
1646 }
1647 } else if (WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate()) {
1648 baseUri = workerPrivate->GetBaseURI();
1649 }
1650
1651 if (baseUri) {
1652 if (iconUrl.Length() > 0) {
1653 nsCOMPtr<nsIURI> srcUri;
1654 rv = NS_NewURI(getter_AddRefs(srcUri), iconUrl, encoding, baseUri);
1655 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
1656 nsAutoCString src;
1657 srcUri->GetSpec(src);
1658 CopyUTF8toUTF16(src, iconUrl);
1659 }
1660 }
1661 if (soundUrl.Length() > 0) {
1662 nsCOMPtr<nsIURI> srcUri;
1663 rv = NS_NewURI(getter_AddRefs(srcUri), soundUrl, encoding, baseUri);
1664 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
1665 nsAutoCString src;
1666 srcUri->GetSpec(src);
1667 CopyUTF8toUTF16(src, soundUrl);
1668 }
1669 }
1670 }
1671
1672 return rv;
1673}
1674
1675already_AddRefed<Promise> Notification::Get(
1676 nsPIDOMWindowInner* aWindow, const GetNotificationOptions& aFilter,
1677 const nsAString& aScope, ErrorResult& aRv) {
1678 AssertIsOnMainThread();
1679 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"
, 1679); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWindow" ")"
); do { *((volatile int*)__null) = 1679; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1680
1681 nsCOMPtr<Document> doc = aWindow->GetExtantDoc();
1682 if (!doc) {
1683 aRv.Throw(NS_ERROR_UNEXPECTED);
1684 return nullptr;
1685 }
1686
1687 nsString origin;
1688 aRv = GetOrigin(doc->NodePrincipal(), origin);
1689 if (aRv.Failed()) {
1690 return nullptr;
1691 }
1692
1693 RefPtr<Promise> promise = Promise::Create(aWindow->AsGlobal(), aRv);
1694 if (aRv.Failed()) {
1695 return nullptr;
1696 }
1697
1698 nsCOMPtr<nsINotificationStorageCallback> callback =
1699 new NotificationStorageCallback(aWindow->AsGlobal(), aScope, promise);
1700
1701 RefPtr<NotificationGetRunnable> r = new NotificationGetRunnable(
1702 origin, aFilter.mTag, callback, doc->IsInPrivateBrowsing());
1703
1704 aRv = aWindow->AsGlobal()->Dispatch(r.forget());
1705 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"
, 1705)
) {
1706 return nullptr;
1707 }
1708
1709 return promise.forget();
1710}
1711
1712class WorkerGetResultRunnable final : public NotificationWorkerRunnable {
1713 RefPtr<PromiseWorkerProxy> mPromiseProxy;
1714 const nsTArray<NotificationStrings> mStrings;
1715
1716 public:
1717 WorkerGetResultRunnable(WorkerPrivate* aWorkerPrivate,
1718 PromiseWorkerProxy* aPromiseProxy,
1719 nsTArray<NotificationStrings>&& aStrings)
1720 : NotificationWorkerRunnable(aWorkerPrivate, "WorkerGetResultRunnable"),
1721 mPromiseProxy(aPromiseProxy),
1722 mStrings(std::move(aStrings)) {}
1723
1724 void WorkerRunInternal(WorkerPrivate* aWorkerPrivate) override {
1725 RefPtr<Promise> workerPromise = mPromiseProxy->GetWorkerPromise();
1726 // Once Worker had already started shutdown, workerPromise would be nullptr
1727 if (!workerPromise) {
1728 return;
1729 }
1730
1731 AutoTArray<RefPtr<Notification>, 5> notifications;
1732 for (uint32_t i = 0; i < mStrings.Length(); ++i) {
1733 auto result = Notification::ConstructFromFields(
1734 aWorkerPrivate->GlobalScope(), mStrings[i].mID, mStrings[i].mTitle,
1735 mStrings[i].mDir, mStrings[i].mLang, mStrings[i].mBody,
1736 mStrings[i].mTag, mStrings[i].mIcon, mStrings[i].mData,
1737 /* mStrings[i].mBehavior, not
1738 * supported */
1739 mStrings[i].mServiceWorkerRegistrationScope);
1740 if (result.isErr()) {
1741 continue;
1742 }
1743 RefPtr<Notification> n = result.unwrap();
1744 n->SetStoredState(true);
1745 notifications.AppendElement(n.forget());
1746 }
1747
1748 workerPromise->MaybeResolve(notifications);
1749 mPromiseProxy->CleanUp();
1750 }
1751};
1752
1753class WorkerGetCallback final : public ScopeCheckingGetCallback {
1754 RefPtr<PromiseWorkerProxy> mPromiseProxy;
1755
1756 public:
1757 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:
1758
1759 WorkerGetCallback(PromiseWorkerProxy* aProxy, const nsAString& aScope)
1760 : ScopeCheckingGetCallback(aScope), mPromiseProxy(aProxy) {
1761 AssertIsOnMainThread();
1762 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"
, 1762); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aProxy" ")"
); do { *((volatile int*)__null) = 1762; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1763 }
1764
1765 NS_IMETHODvirtual nsresult Done() final {
1766 AssertIsOnMainThread();
1767 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"
, 1767); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mPromiseProxy"
") (" "Was Done() called twice?" ")"); do { *((volatile int*
)__null) = 1767; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1768
1769 RefPtr<PromiseWorkerProxy> proxy = std::move(mPromiseProxy);
1770 MutexAutoLock lock(proxy->Lock());
1771 if (proxy->CleanedUp()) {
1772 return NS_OK;
1773 }
1774
1775 RefPtr<WorkerGetResultRunnable> r = new WorkerGetResultRunnable(
1776 proxy->GetWorkerPrivate(), proxy, std::move(mStrings));
1777
1778 r->Dispatch(proxy->GetWorkerPrivate());
1779 return NS_OK;
1780 }
1781
1782 private:
1783 ~WorkerGetCallback() = default;
1784};
1785
1786NS_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"
, 1786); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
1786; __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"
, 1786); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WorkerGetCallback\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 1786; __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"
, 1786); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 1786
; __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"
, 1786); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WorkerGetCallback\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 1786; __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"
, 1786); 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; }
1787
1788class WorkerGetRunnable final : public Runnable {
1789 RefPtr<PromiseWorkerProxy> mPromiseProxy;
1790 const nsString mTag;
1791 const nsString mScope;
1792
1793 public:
1794 WorkerGetRunnable(PromiseWorkerProxy* aProxy, const nsAString& aTag,
1795 const nsAString& aScope)
1796 : Runnable("WorkerGetRunnable"),
1797 mPromiseProxy(aProxy),
1798 mTag(aTag),
1799 mScope(aScope) {
1800 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"
, 1800); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mPromiseProxy"
")"); do { *((volatile int*)__null) = 1800; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1801 }
1802
1803 NS_IMETHODvirtual nsresult
1804 Run() override {
1805 AssertIsOnMainThread();
1806
1807 MutexAutoLock lock(mPromiseProxy->Lock());
1808 if (mPromiseProxy->CleanedUp()) {
1809 return NS_OK;
1810 }
1811
1812 auto* principal = mPromiseProxy->GetWorkerPrivate()->GetPrincipal();
1813 auto isPrivate = principal->GetIsInPrivateBrowsing();
1814
1815 nsCOMPtr<nsINotificationStorageCallback> callback =
1816 new WorkerGetCallback(mPromiseProxy, mScope);
1817
1818 nsCOMPtr<nsINotificationStorage> notificationStorage =
1819 GetNotificationStorage(isPrivate);
1820 if (NS_WARN_IF(!notificationStorage)NS_warn_if_impl(!notificationStorage, "!notificationStorage",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 1820)
) {
1821 callback->Done();
1822 return NS_ERROR_UNEXPECTED;
1823 }
1824 nsString origin;
1825 nsresult rv = Notification::GetOrigin(principal, origin);
1826 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"
, 1826)
) {
1827 callback->Done();
1828 return rv;
1829 }
1830
1831 rv = notificationStorage->Get(origin, mTag, callback);
1832 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"
, 1832)
) {
1833 callback->Done();
1834 return rv;
1835 }
1836
1837 return NS_OK;
1838 }
1839
1840 private:
1841 ~WorkerGetRunnable() = default;
1842};
1843
1844// static
1845already_AddRefed<Promise> Notification::WorkerGet(
1846 WorkerPrivate* aWorkerPrivate, const GetNotificationOptions& aFilter,
1847 const nsAString& aScope, ErrorResult& aRv) {
1848 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"
, 1848); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWorkerPrivate"
")"); do { *((volatile int*)__null) = 1848; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1849 aWorkerPrivate->AssertIsOnWorkerThread();
1850 RefPtr<Promise> p = Promise::Create(aWorkerPrivate->GlobalScope(), aRv);
1851 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"
, 1851)
) {
1852 return nullptr;
1853 }
1854
1855 RefPtr<PromiseWorkerProxy> proxy =
1856 PromiseWorkerProxy::Create(aWorkerPrivate, p);
1857 if (!proxy) {
1858 aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
1859 return nullptr;
1860 }
1861
1862 RefPtr<WorkerGetRunnable> r =
1863 new WorkerGetRunnable(proxy, aFilter.mTag, aScope);
1864 // Since this is called from script via
1865 // ServiceWorkerRegistration::GetNotifications, we can assert dispatch.
1866 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"
, 1866); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(aWorkerPrivate->DispatchToMainThread(r.forget()))"
")"); do { *((volatile int*)__null) = 1866; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1867 return p.forget();
1868}
1869
1870JSObject* Notification::WrapObject(JSContext* aCx,
1871 JS::Handle<JSObject*> aGivenProto) {
1872 return mozilla::dom::Notification_Binding::Wrap(aCx, this, aGivenProto);
1873}
1874
1875void Notification::Close() {
1876 AssertIsOnTargetThread();
1877 auto ref = MakeUnique<NotificationRef>(this);
1878 if (!ref->Initialized()) {
1879 return;
1880 }
1881
1882 nsCOMPtr<nsIRunnable> closeNotificationTask = new NotificationTask(
1883 "Notification::Close", std::move(ref), NotificationTask::eClose);
1884 nsresult rv = DispatchToMainThread(closeNotificationTask.forget());
1885
1886 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1887 DispatchTrustedEvent(u"error"_ns);
1888 // If dispatch fails, NotificationTask will release the ref when it goes
1889 // out of scope at the end of this function.
1890 }
1891}
1892
1893void Notification::CloseInternal(bool aContextClosed) {
1894 AssertIsOnMainThread();
1895 // Transfer ownership (if any) to local scope so we can release it at the end
1896 // of this function. This is relevant when the call is from
1897 // NotificationTask::Run().
1898 UniquePtr<NotificationRef> ownership;
1899 std::swap(ownership, mTempRef);
1900
1901 SetAlertName();
1902 UnpersistNotification();
1903 if (!mIsClosed) {
1904 nsCOMPtr<nsIAlertsService> alertService = components::Alerts::Service();
1905 if (alertService) {
1906 nsAutoString alertName;
1907 GetAlertName(alertName);
1908 alertService->CloseAlert(alertName, aContextClosed);
1909 }
1910 }
1911}
1912
1913nsresult Notification::GetOrigin(nsIPrincipal* aPrincipal, nsString& aOrigin) {
1914 if (!aPrincipal) {
1915 return NS_ERROR_FAILURE;
1916 }
1917
1918 nsresult rv =
1919 nsContentUtils::GetWebExposedOriginSerialization(aPrincipal, aOrigin);
1920 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"
, 1920); return rv; } } while (false)
;
1921
1922 return NS_OK;
1923}
1924
1925bool Notification::RequireInteraction() const { return mRequireInteraction; }
1926
1927bool Notification::Silent() const { return mSilent; }
1928
1929void Notification::GetVibrate(nsTArray<uint32_t>& aRetval) const {
1930 aRetval = mVibrate.Clone();
1931}
1932
1933void Notification::GetData(JSContext* aCx,
1934 JS::MutableHandle<JS::Value> aRetval) {
1935 if (mData.isNull() && !mDataAsBase64.IsEmpty()) {
1936 nsresult rv;
1937 RefPtr<nsStructuredCloneContainer> container =
1938 new nsStructuredCloneContainer();
1939 rv = container->InitFromBase64(mDataAsBase64, JS_STRUCTURED_CLONE_VERSION8);
1940 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"
, 1940)
) {
1941 aRetval.setNull();
1942 return;
1943 }
1944
1945 JS::Rooted<JS::Value> data(aCx);
1946 rv = container->DeserializeToJsval(aCx, &data);
1947 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"
, 1947)
) {
1948 aRetval.setNull();
1949 return;
1950 }
1951
1952 if (data.isGCThing()) {
1953 mozilla::HoldJSObjects(this);
1954 }
1955 mData = data;
1956 }
1957 if (mData.isNull()) {
1958 aRetval.setNull();
1959 return;
1960 }
1961
1962 aRetval.set(mData);
1963}
1964
1965void Notification::InitFromJSVal(JSContext* aCx, JS::Handle<JS::Value> aData,
1966 ErrorResult& aRv) {
1967 if (!mDataAsBase64.IsEmpty() || aData.isNull()) {
1968 return;
1969 }
1970 RefPtr<nsStructuredCloneContainer> dataObjectContainer =
1971 new nsStructuredCloneContainer();
1972 aRv = dataObjectContainer->InitFromJSVal(aData, aCx);
1973 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"
, 1973)
) {
1974 return;
1975 }
1976
1977 aRv = dataObjectContainer->GetDataAsBase64(mDataAsBase64);
1978 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"
, 1978)
) {
1979 return;
1980 }
1981}
1982
1983Result<Ok, QMResult> Notification::InitFromBase64(const nsAString& aData) {
1984 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"
, 1984); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDataAsBase64.IsEmpty()"
")"); do { *((volatile int*)__null) = 1984; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1985 if (aData.IsEmpty()) {
1986 // No data; skipping
1987 return Ok();
1988 }
1989
1990 // To and fro to ensure it is valid base64.
1991 RefPtr<nsStructuredCloneContainer> container =
1992 new nsStructuredCloneContainer();
1993 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"
, 1994, mozilla::dom::quota::Severity::Error); return tryResult13
.propagateErr(); }}
1994 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"
, 1994, mozilla::dom::quota::Severity::Error); return tryResult13
.propagateErr(); }}
;
1995 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"
, 1995, mozilla::dom::quota::Severity::Error); return tryResult14
.propagateErr(); }}
;
1996
1997 return Ok();
1998}
1999
2000bool Notification::AddRefObject() {
2001 AssertIsOnTargetThread();
2002 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"
, 2002); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTaskCount == 0"
")"); do { *((volatile int*)__null) = 2002; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2003 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"
, 2003); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTaskCount > 0"
")"); do { *((volatile int*)__null) = 2003; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2004 if (mWorkerPrivate && !mWorkerRef) {
2005 if (!CreateWorkerRef()) {
2006 return false;
2007 }
2008 }
2009 AddRef();
2010 ++mTaskCount;
2011 return true;
2012}
2013
2014void Notification::ReleaseObject() {
2015 AssertIsOnTargetThread();
2016 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"
, 2016); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTaskCount > 0"
")"); do { *((volatile int*)__null) = 2016; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2017 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"
, 2017); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWorkerRef"
")"); do { *((volatile int*)__null) = 2017; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2018
2019 --mTaskCount;
2020 if (mWorkerPrivate && mTaskCount == 0) {
2021 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"
, 2021); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWorkerRef"
")"); do { *((volatile int*)__null) = 2021; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2022 mWorkerRef = nullptr;
2023 }
2024 Release();
2025}
2026
2027/*
2028 * Called from the worker, runs on main thread, blocks worker.
2029 *
2030 * We can freely access mNotification here because the feature supplied it and
2031 * the Notification owns the feature.
2032 */
2033class CloseNotificationRunnable final : public WorkerMainThreadRunnable {
2034 Notification* mNotification;
2035 bool mHadObserver;
2036
2037 public:
2038 explicit CloseNotificationRunnable(Notification* aNotification)
2039 : WorkerMainThreadRunnable(aNotification->mWorkerPrivate,
2040 "Notification :: Close Notification"_ns),
2041 mNotification(aNotification),
2042 mHadObserver(false) {}
2043
2044 bool MainThreadRun() override {
2045 if (mNotification->mObserver) {
2046 // The Notify() take's responsibility of releasing the Notification.
2047 mNotification->mObserver->ForgetNotification();
2048 mNotification->mObserver = nullptr;
2049 mHadObserver = true;
2050 }
2051 mNotification->CloseInternal();
2052 return true;
2053 }
2054
2055 bool HadObserver() { return mHadObserver; }
2056};
2057
2058bool Notification::CreateWorkerRef() {
2059 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"
, 2059); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWorkerPrivate"
")"); do { *((volatile int*)__null) = 2059; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2060 mWorkerPrivate->AssertIsOnWorkerThread();
2061 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"
, 2061); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mWorkerRef"
")"); do { *((volatile int*)__null) = 2061; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2062
2063 RefPtr<Notification> self = this;
2064 mWorkerRef =
2065 StrongWorkerRef::Create(mWorkerPrivate, "Notification", [self]() {
2066 // CloseNotificationRunnable blocks the worker by pushing a sync event
2067 // loop on the stack. Meanwhile, WorkerControlRunnables dispatched to
2068 // the worker can still continue running. One of these is
2069 // ReleaseNotificationControlRunnable that releases the notification,
2070 // invalidating the notification and this feature. We hold this
2071 // reference to keep the notification valid until we are done with it.
2072 //
2073 // An example of when the control runnable could get dispatched to the
2074 // worker is if a Notification is created and the worker is immediately
2075 // closed, but there is no permission to show it so that the main thread
2076 // immediately drops the NotificationRef. In this case, this function
2077 // blocks on the main thread, but the main thread dispatches the control
2078 // runnable, invalidating mNotification.
2079
2080 // Dispatched to main thread, blocks on closing the Notification.
2081 RefPtr<CloseNotificationRunnable> r =
2082 new CloseNotificationRunnable(self);
2083 ErrorResult rv;
2084 r->Dispatch(self->mWorkerPrivate, Killing, rv);
2085 // XXXbz I'm told throwing and returning false from here is pointless
2086 // (and also that doing sync stuff from here is really weird), so I
2087 // guess we just suppress the exception on rv, if any.
2088 rv.SuppressException();
2089
2090 // Only call ReleaseObject() to match the observer's NotificationRef
2091 // ownership (since CloseNotificationRunnable asked the observer to drop
2092 // the reference to the notification).
2093 if (r->HadObserver()) {
2094 self->ReleaseObject();
2095 }
2096
2097 // From this point we cannot touch properties of this feature because
2098 // ReleaseObject() may have led to the notification going away and the
2099 // notification owns this feature!
2100 });
2101
2102 if (NS_WARN_IF(!mWorkerRef)NS_warn_if_impl(!mWorkerRef, "!mWorkerRef", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2102)
) {
2103 return false;
2104 }
2105
2106 return true;
2107}
2108
2109/*
2110 * Checks:
2111 * 1) Is aWorker allowed to show a notification for scope?
2112 * 2) Is aWorker an active worker?
2113 *
2114 * If it is not an active worker, Result() will be NS_ERROR_NOT_AVAILABLE.
2115 */
2116class CheckLoadRunnable final : public WorkerMainThreadRunnable {
2117 nsresult mRv;
2118 nsCString mScope;
2119 ServiceWorkerRegistrationDescriptor mDescriptor;
2120
2121 public:
2122 explicit CheckLoadRunnable(
2123 WorkerPrivate* aWorker, const nsACString& aScope,
2124 const ServiceWorkerRegistrationDescriptor& aDescriptor)
2125 : WorkerMainThreadRunnable(aWorker, "Notification :: Check Load"_ns),
2126 mRv(NS_ERROR_DOM_SECURITY_ERR),
2127 mScope(aScope),
2128 mDescriptor(aDescriptor) {}
2129
2130 bool MainThreadRun() override {
2131 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"
, 2131); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWorkerRef"
")"); do { *((volatile int*)__null) = 2131; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2132 nsIPrincipal* principal = mWorkerRef->Private()->GetPrincipal();
2133 mRv = CheckScope(principal, mScope, mWorkerRef->Private()->WindowID());
2134
2135 if (NS_FAILED(mRv)((bool)(__builtin_expect(!!(NS_FAILED_impl(mRv)), 0)))) {
2136 return true;
2137 }
2138
2139 auto activeWorker = mDescriptor.GetActive();
2140
2141 if (!activeWorker ||
2142 activeWorker.ref().Id() != mWorkerRef->Private()->ServiceWorkerID()) {
2143 mRv = NS_ERROR_NOT_AVAILABLE;
2144 }
2145
2146 return true;
2147 }
2148
2149 nsresult Result() { return mRv; }
2150};
2151
2152// Step 2, 5, 6 of
2153// https://notifications.spec.whatwg.org/#dom-serviceworkerregistration-shownotification
2154/* static */
2155already_AddRefed<Promise> Notification::ShowPersistentNotification(
2156 JSContext* aCx, nsIGlobalObject* aGlobal, const nsAString& aScope,
2157 const nsAString& aTitle, const NotificationOptions& aOptions,
2158 const ServiceWorkerRegistrationDescriptor& aDescriptor, ErrorResult& aRv) {
2159 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"
, 2159); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGlobal" ")"
); do { *((volatile int*)__null) = 2159; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2160
2161 // Validate scope.
2162 // XXXnsm: This may be slow due to blocking the worker and waiting on the main
2163 // thread. On calls from content, we can be sure the scope is valid since
2164 // ServiceWorkerRegistrations have their scope set correctly. Can this be made
2165 // debug only? The problem is that there would be different semantics in
2166 // debug and non-debug builds in such a case.
2167 if (NS_IsMainThread()) {
2168 nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aGlobal);
2169 if (NS_WARN_IF(!sop)NS_warn_if_impl(!sop, "!sop", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2169)
) {
2170 aRv.Throw(NS_ERROR_UNEXPECTED);
2171 return nullptr;
2172 }
2173
2174 nsIPrincipal* principal = sop->GetPrincipal();
2175 if (NS_WARN_IF(!principal)NS_warn_if_impl(!principal, "!principal", "/var/lib/jenkins/workspace/firefox-scan-build/dom/notification/Notification.cpp"
, 2175)
) {
2176 aRv.Throw(NS_ERROR_UNEXPECTED);
2177 return nullptr;
2178 }
2179
2180 uint64_t windowID = 0;
2181 nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(aGlobal);
2182 if (win) {
2183 windowID = win->WindowID();
2184 }
2185
2186 aRv = CheckScope(principal, NS_ConvertUTF16toUTF8(aScope), windowID);
2187 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"
, 2187)
) {
2188 aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
2189 return nullptr;
2190 }
2191 } else {
2192 WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
2193 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"
, 2193); AnnotateMozCrashReason("MOZ_ASSERT" "(" "worker" ")"
); do { *((volatile int*)__null) = 2193; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2194 worker->AssertIsOnWorkerThread();
2195
2196 RefPtr<CheckLoadRunnable> loadChecker = new CheckLoadRunnable(
2197 worker, NS_ConvertUTF16toUTF8(aScope), aDescriptor);
2198 loadChecker->Dispatch(worker, Canceling, aRv);
2199 if (aRv.Failed()) {
2200 return nullptr;
2201 }
2202
2203 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"
, 2203)
) {
2204 if (loadChecker->Result() == NS_ERROR_NOT_AVAILABLE) {
2205 aRv.ThrowTypeError<MSG_NO_ACTIVE_WORKER>(NS_ConvertUTF16toUTF8(aScope));
2206 } else {
2207 aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
2208 }
2209 return nullptr;
2210 }
2211 }
2212
2213 // Step 2: Let promise be a new promise in this’s relevant Realm.
2214 RefPtr<Promise> p = Promise::Create(aGlobal, aRv);
2215 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"
, 2215)
) {
2216 return nullptr;
2217 }
2218
2219 // We check permission here rather than pass the Promise to NotificationTask
2220 // which leads to uglier code.
2221 // XXX: GetPermission is a synchronous blocking function on workers.
2222 NotificationPermission permission = GetPermission(aGlobal, aRv);
2223
2224 // Step 6.1: If the result of getting the notifications permission state is
2225 // not "granted", then queue a global task on the DOM manipulation task source
2226 // given global to reject promise with a TypeError, and abort these steps.
2227 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"
, 2227)
||
2228 permission != NotificationPermission::Granted) {
2229 p->MaybeRejectWithTypeError("Permission to show Notification denied.");
2230 return p.forget();
2231 }
2232
2233 // "Otherwise, resolve promise with undefined."
2234 // The Notification may still not be shown due to other errors, but the spec
2235 // is not concerned with those.
2236 p->MaybeResolveWithUndefined();
2237
2238 // Step 5: Let notification be the result of creating a notification given
2239 // title, options, this’s relevant settings object, and
2240 // serviceWorkerRegistration. If this threw an exception, then reject promise
2241 // with that exception and return promise.
2242 //
2243 // XXX: This should happen before the permission check per the spec, as this
2244 // can throw errors too. This should be split into create and show.
2245 RefPtr<Notification> notification =
2246 CreateAndShow(aCx, aGlobal, aTitle, aOptions, aScope, aRv);
2247 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"
, 2247)
) {
2248 return nullptr;
2249 }
2250
2251 return p.forget();
2252}
2253
2254/* static */
2255already_AddRefed<Notification> Notification::CreateAndShow(
2256 JSContext* aCx, nsIGlobalObject* aGlobal, const nsAString& aTitle,
2257 const NotificationOptions& aOptions, const nsAString& aScope,
2258 ErrorResult& aRv) {
2259 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"
, 2259); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGlobal" ")"
); do { *((volatile int*)__null) = 2259; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2260
2261 RefPtr<Notification> notification =
2262 CreateInternal(aGlobal, u""_ns, aTitle, aOptions, aRv);
2263 if (aRv.Failed()) {
2264 return nullptr;
2265 }
2266
2267 // Make a structured clone of the aOptions.mData object
2268 JS::Rooted<JS::Value> data(aCx, aOptions.mData);
2269 notification->InitFromJSVal(aCx, data, aRv);
2270 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"
, 2270)
) {
2271 return nullptr;
2272 }
2273
2274 notification->SetScope(aScope);
2275
2276 auto ref = MakeUnique<NotificationRef>(notification);
2277 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"
, 2277)
) {
2278 aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
2279 return nullptr;
2280 }
2281
2282 // Queue a task to show the notification.
2283 nsCOMPtr<nsIRunnable> showNotificationTask = new NotificationTask(
2284 "Notification::CreateAndShow", std::move(ref), NotificationTask::eShow);
2285
2286 nsresult rv =
2287 notification->DispatchToMainThread(showNotificationTask.forget());
2288
2289 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"
, 2289)
) {
2290 notification->DispatchTrustedEvent(u"error"_ns);
2291 }
2292
2293 return notification.forget();
2294}
2295
2296/* static */
2297nsresult Notification::RemovePermission(nsIPrincipal* aPrincipal) {
2298 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"
, 2298); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 2298; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2299 nsCOMPtr<nsIPermissionManager> permissionManager =
2300 mozilla::components::PermissionManager::Service();
2301 if (!permissionManager) {
2302 return NS_ERROR_FAILURE;
2303 }
2304 permissionManager->RemoveFromPrincipal(aPrincipal, "desktop-notification"_ns);
2305 return NS_OK;
2306}
2307
2308/* static */
2309nsresult Notification::OpenSettings(nsIPrincipal* aPrincipal) {
2310 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"
, 2310); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 2310; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2311 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
2312 if (!obs) {
2313 return NS_ERROR_FAILURE;
2314 }
2315 // Notify other observers so they can show settings UI.
2316 obs->NotifyObservers(aPrincipal, "notifications-open-settings", nullptr);
2317 return NS_OK;
2318}
2319
2320void Notification::DisconnectFromOwner() {
2321 // Unregister the backend handler if it's non-persistent.
2322 // XXX(krosylight): CloseInternal currently assumes main thread, will be
2323 // fixed by IPC migration (bug 1891807)
2324 if (NS_IsMainThread() && mScope.IsEmpty()) {
2325 CloseInternal(true);
2326 }
2327 DOMEventTargetHelper::DisconnectFromOwner();
2328}
2329
2330void Notification::FrozenCallback(nsIGlobalObject* aOwner) {
2331 CloseInternal(true);
2332 DisconnectFreezeObserver();
2333}
2334
2335nsresult Notification::DispatchToMainThread(
2336 already_AddRefed<nsIRunnable>&& aRunnable) {
2337 if (mWorkerPrivate) {
2338 return mWorkerPrivate->DispatchToMainThread(std::move(aRunnable));
2339 }
2340 AssertIsOnMainThread();
2341 return NS_DispatchToCurrentThread(std::move(aRunnable));
2342}
2343
2344} // namespace mozilla::dom