Bug Summary

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