Bug Summary

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