Bug 1951379 - Part 1: Use IPCNotification as a member in Notification r=asuth
This also modifies InitFromJSVal and InitFromBase64 into static functions, to allow mIPCNotification to be const. Differential Revision: https://phabricator.services.mozilla.com/D240169
This commit is contained in:
@@ -286,23 +286,10 @@ bool Notification::PrefEnabled(JSContext* aCx, JSObject* aObj) {
|
||||
return StaticPrefs::dom_webnotifications_enabled();
|
||||
}
|
||||
|
||||
Notification::Notification(nsIGlobalObject* aGlobal, const nsAString& aID,
|
||||
const nsAString& aTitle, const nsAString& aBody,
|
||||
NotificationDirection aDir, const nsAString& aLang,
|
||||
const nsAString& aTag, const nsAString& aIconUrl,
|
||||
bool aRequireInteraction, bool aSilent,
|
||||
nsTArray<uint32_t>&& aVibrate)
|
||||
Notification::Notification(nsIGlobalObject* aGlobal,
|
||||
IPCNotification&& aIPCNotification)
|
||||
: DOMEventTargetHelper(aGlobal),
|
||||
mID(aID),
|
||||
mTitle(aTitle),
|
||||
mBody(aBody),
|
||||
mDir(aDir),
|
||||
mLang(aLang),
|
||||
mTag(aTag),
|
||||
mIconUrl(aIconUrl),
|
||||
mRequireInteraction(aRequireInteraction),
|
||||
mSilent(aSilent),
|
||||
mVibrate(std::move(aVibrate)),
|
||||
mIPCNotification(std::move(aIPCNotification)),
|
||||
mData(JS::NullValue()) {
|
||||
KeepAliveIfHasListenersFor(nsGkAtoms::onclick);
|
||||
KeepAliveIfHasListenersFor(nsGkAtoms::onshow);
|
||||
@@ -357,14 +344,33 @@ already_AddRefed<Notification> Notification::Constructor(
|
||||
return notification.forget();
|
||||
}
|
||||
|
||||
// NOTE(krosylight): Maybe move this check to the parent process?
|
||||
Result<Ok, nsresult> ValidateBase64Data(const nsAString& aData) {
|
||||
if (aData.IsEmpty()) {
|
||||
return Ok();
|
||||
}
|
||||
|
||||
// To and from to ensure it is valid base64.
|
||||
RefPtr<nsStructuredCloneContainer> container =
|
||||
new nsStructuredCloneContainer();
|
||||
MOZ_TRY(container->InitFromBase64(aData, JS_STRUCTURED_CLONE_VERSION));
|
||||
|
||||
nsString result;
|
||||
MOZ_TRY(container->GetDataAsBase64(result));
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
// static
|
||||
Result<already_AddRefed<Notification>, QMResult> Notification::ConstructFromIPC(
|
||||
Result<already_AddRefed<Notification>, nsresult> Notification::ConstructFromIPC(
|
||||
nsIGlobalObject* aGlobal, const IPCNotification& aIPCNotification,
|
||||
const nsAString& aServiceWorkerRegistrationScope) {
|
||||
MOZ_ASSERT(aGlobal);
|
||||
|
||||
const IPCNotificationOptions& ipcOptions = aIPCNotification.options();
|
||||
|
||||
MOZ_TRY(ValidateBase64Data(ipcOptions.dataSerialized()));
|
||||
|
||||
RootedDictionary<NotificationOptions> options(RootingCx());
|
||||
options.mDir = ipcOptions.dir();
|
||||
options.mLang = ipcOptions.lang();
|
||||
@@ -372,14 +378,13 @@ Result<already_AddRefed<Notification>, QMResult> Notification::ConstructFromIPC(
|
||||
options.mTag = ipcOptions.tag();
|
||||
options.mIcon = ipcOptions.icon();
|
||||
IgnoredErrorResult rv;
|
||||
RefPtr<Notification> notification = CreateInternal(
|
||||
aGlobal, aIPCNotification.id(), ipcOptions.title(), options, rv);
|
||||
RefPtr<Notification> notification =
|
||||
CreateInternal(aGlobal, aIPCNotification.id(), ipcOptions.title(),
|
||||
ipcOptions.dataSerialized(), options, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return Err(ToQMResult(NS_ERROR_FAILURE));
|
||||
return Err(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
QM_TRY(notification->InitFromBase64(ipcOptions.dataSerialized()));
|
||||
|
||||
notification->SetScope(aServiceWorkerRegistrationScope);
|
||||
|
||||
return notification.forget();
|
||||
@@ -396,8 +401,9 @@ void Notification::MaybeNotifyClose() {
|
||||
// https://notifications.spec.whatwg.org/#create-a-notification
|
||||
already_AddRefed<Notification> Notification::CreateInternal(
|
||||
nsIGlobalObject* aGlobal, const nsAString& aID, const nsAString& aTitle,
|
||||
const NotificationOptions& aOptions, ErrorResult& aRv) {
|
||||
// Step 20: Set notification’s silent preference to options["silent"].
|
||||
const nsAString& aDataSerialized, const NotificationOptions& aOptions,
|
||||
ErrorResult& aRv) {
|
||||
// Step 17: Set notification’s silent preference to options["silent"].
|
||||
bool silent = false;
|
||||
if (StaticPrefs::dom_webnotifications_silent_enabled()) {
|
||||
silent = aOptions.mSilent;
|
||||
@@ -406,7 +412,7 @@ already_AddRefed<Notification> Notification::CreateInternal(
|
||||
nsTArray<uint32_t> vibrate;
|
||||
if (StaticPrefs::dom_webnotifications_vibrate_enabled() &&
|
||||
aOptions.mVibrate.WasPassed()) {
|
||||
// Step 4: If options["silent"] is true and options["vibrate"] exists, then
|
||||
// Step 2: If options["silent"] is true and options["vibrate"] exists, then
|
||||
// throw a TypeError.
|
||||
if (silent) {
|
||||
aRv.ThrowTypeError(
|
||||
@@ -414,7 +420,7 @@ already_AddRefed<Notification> Notification::CreateInternal(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Step 17: If options["vibrate"] exists, then validate and normalize it and
|
||||
// Step 14: If options["vibrate"] exists, then validate and normalize it and
|
||||
// set notification’s vibration pattern to the return value.
|
||||
const OwningUnsignedLongOrUnsignedLongSequence& value =
|
||||
aOptions.mVibrate.Value();
|
||||
@@ -427,16 +433,22 @@ already_AddRefed<Notification> Notification::CreateInternal(
|
||||
}
|
||||
}
|
||||
|
||||
// Step 15: If options["icon"] exists, then parse it using baseURL, and if
|
||||
// Step 12: If options["icon"] exists, then parse it using baseURL, and if
|
||||
// that does not return failure, set notification’s icon URL to the return
|
||||
// value. (Otherwise icon URL is not set.)
|
||||
nsString iconUrl = aOptions.mIcon;
|
||||
ResolveIconURL(aGlobal, iconUrl);
|
||||
|
||||
RefPtr<Notification> notification = new Notification(
|
||||
aGlobal, aID, aTitle, aOptions.mBody, aOptions.mDir, aOptions.mLang,
|
||||
aOptions.mTag, iconUrl, aOptions.mRequireInteraction, silent,
|
||||
std::move(vibrate));
|
||||
IPCNotification ipcNotification(
|
||||
nsString(aID),
|
||||
IPCNotificationOptions(nsString(aTitle), aOptions.mDir,
|
||||
nsString(aOptions.mLang), nsString(aOptions.mBody),
|
||||
nsString(aOptions.mTag), iconUrl,
|
||||
aOptions.mRequireInteraction, silent, vibrate,
|
||||
nsString(aDataSerialized)));
|
||||
|
||||
RefPtr<Notification> notification =
|
||||
new Notification(aGlobal, std::move(ipcNotification));
|
||||
return notification.forget();
|
||||
}
|
||||
|
||||
@@ -668,21 +680,26 @@ void Notification::Close() {
|
||||
}
|
||||
}
|
||||
|
||||
bool Notification::RequireInteraction() const { return mRequireInteraction; }
|
||||
bool Notification::RequireInteraction() const {
|
||||
return mIPCNotification.options().requireInteraction();
|
||||
}
|
||||
|
||||
bool Notification::Silent() const { return mSilent; }
|
||||
bool Notification::Silent() const {
|
||||
return mIPCNotification.options().silent();
|
||||
}
|
||||
|
||||
void Notification::GetVibrate(nsTArray<uint32_t>& aRetval) const {
|
||||
aRetval = mVibrate.Clone();
|
||||
aRetval = mIPCNotification.options().vibrate().Clone();
|
||||
}
|
||||
|
||||
void Notification::GetData(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aRetval) {
|
||||
if (mData.isNull() && !mDataAsBase64.IsEmpty()) {
|
||||
const nsString& dataSerialized = mIPCNotification.options().dataSerialized();
|
||||
if (mData.isNull() && !dataSerialized.IsEmpty()) {
|
||||
nsresult rv;
|
||||
RefPtr<nsStructuredCloneContainer> container =
|
||||
new nsStructuredCloneContainer();
|
||||
rv = container->InitFromBase64(mDataAsBase64, JS_STRUCTURED_CLONE_VERSION);
|
||||
rv = container->InitFromBase64(dataSerialized, JS_STRUCTURED_CLONE_VERSION);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRetval.setNull();
|
||||
return;
|
||||
@@ -708,39 +725,19 @@ void Notification::GetData(JSContext* aCx,
|
||||
aRetval.set(mData);
|
||||
}
|
||||
|
||||
void Notification::InitFromJSVal(JSContext* aCx, JS::Handle<JS::Value> aData,
|
||||
ErrorResult& aRv) {
|
||||
if (!mDataAsBase64.IsEmpty() || aData.isNull()) {
|
||||
return;
|
||||
static Result<nsString, nsresult> SerializeDataAsBase64(
|
||||
JSContext* aCx, JS::Handle<JS::Value> aData) {
|
||||
if (aData.isNull()) {
|
||||
return nsString();
|
||||
}
|
||||
RefPtr<nsStructuredCloneContainer> dataObjectContainer =
|
||||
new nsStructuredCloneContainer();
|
||||
aRv = dataObjectContainer->InitFromJSVal(aData, aCx);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
MOZ_TRY(dataObjectContainer->InitFromJSVal(aData, aCx));
|
||||
|
||||
aRv = dataObjectContainer->GetDataAsBase64(mDataAsBase64);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
nsString result;
|
||||
MOZ_TRY(dataObjectContainer->GetDataAsBase64(result));
|
||||
|
||||
Result<Ok, QMResult> Notification::InitFromBase64(const nsAString& aData) {
|
||||
MOZ_ASSERT(mDataAsBase64.IsEmpty());
|
||||
if (aData.IsEmpty()) {
|
||||
// No data; skipping
|
||||
return Ok();
|
||||
}
|
||||
|
||||
// To and fro to ensure it is valid base64.
|
||||
RefPtr<nsStructuredCloneContainer> container =
|
||||
new nsStructuredCloneContainer();
|
||||
QM_TRY(QM_TO_RESULT(
|
||||
container->InitFromBase64(aData, JS_STRUCTURED_CLONE_VERSION)));
|
||||
QM_TRY(QM_TO_RESULT(container->GetDataAsBase64(mDataAsBase64)));
|
||||
|
||||
return Ok();
|
||||
return result;
|
||||
}
|
||||
|
||||
// Steps 2-5 of
|
||||
@@ -795,22 +792,25 @@ already_AddRefed<Promise> Notification::ShowPersistentNotification(
|
||||
}
|
||||
|
||||
/* static */
|
||||
// https://notifications.spec.whatwg.org/#create-a-notification
|
||||
already_AddRefed<Notification> Notification::Create(
|
||||
JSContext* aCx, nsIGlobalObject* aGlobal, const nsAString& aTitle,
|
||||
const NotificationOptions& aOptions, const nsAString& aScope,
|
||||
ErrorResult& aRv) {
|
||||
MOZ_ASSERT(aGlobal);
|
||||
|
||||
RefPtr<Notification> notification =
|
||||
CreateInternal(aGlobal, u""_ns, aTitle, aOptions, aRv);
|
||||
if (aRv.Failed()) {
|
||||
// Step 4: Set notification’s data to
|
||||
// StructuredSerializeForStorage(options["data"]).
|
||||
JS::Rooted<JS::Value> data(aCx, aOptions.mData);
|
||||
Result<nsString, nsresult> dataResult = SerializeDataAsBase64(aCx, data);
|
||||
if (dataResult.isErr()) {
|
||||
aRv = dataResult.unwrapErr();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Make a structured clone of the aOptions.mData object
|
||||
JS::Rooted<JS::Value> data(aCx, aOptions.mData);
|
||||
notification->InitFromJSVal(aCx, data, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
RefPtr<Notification> notification = CreateInternal(
|
||||
aGlobal, u""_ns, aTitle, dataResult.unwrap(), aOptions, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -822,9 +822,6 @@ already_AddRefed<Notification> Notification::Create(
|
||||
bool Notification::CreateActor() {
|
||||
mozilla::ipc::PBackgroundChild* backgroundActor =
|
||||
mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
|
||||
IPCNotificationOptions options(mTitle, mDir, mLang, mBody, mTag, mIconUrl,
|
||||
mRequireInteraction, mSilent, mVibrate,
|
||||
mDataAsBase64);
|
||||
|
||||
// Note: We are not using the typical PBackground managed actor here as we
|
||||
// want the actor to be in the main thread of the main process. Instead we
|
||||
@@ -866,8 +863,8 @@ bool Notification::CreateActor() {
|
||||
|
||||
(void)backgroundActor->SendCreateNotificationParent(
|
||||
std::move(parentEndpoint), WrapNotNull(principal),
|
||||
WrapNotNull(effectiveStoragePrincipal), isSecureContext, mID, mScope,
|
||||
options);
|
||||
WrapNotNull(effectiveStoragePrincipal), isSecureContext, mScope,
|
||||
mIPCNotification);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -77,23 +77,33 @@ class Notification : public DOMEventTargetHelper, public SupportsWeakPtr {
|
||||
/**
|
||||
* Used when retrieving notification objects from the parent process.
|
||||
*/
|
||||
static Result<already_AddRefed<Notification>, QMResult> ConstructFromIPC(
|
||||
static Result<already_AddRefed<Notification>, nsresult> ConstructFromIPC(
|
||||
nsIGlobalObject* aGlobal, const IPCNotification& aIPCNotification,
|
||||
const nsAString& aServiceWorkerRegistrationScope);
|
||||
|
||||
void GetID(nsAString& aRetval) { aRetval = mID; }
|
||||
void GetID(nsAString& aRetval) { aRetval = mIPCNotification.id(); }
|
||||
|
||||
void GetTitle(nsAString& aRetval) { aRetval = mTitle; }
|
||||
void GetTitle(nsAString& aRetval) {
|
||||
aRetval = mIPCNotification.options().title();
|
||||
}
|
||||
|
||||
NotificationDirection Dir() { return mDir; }
|
||||
NotificationDirection Dir() { return mIPCNotification.options().dir(); }
|
||||
|
||||
void GetLang(nsAString& aRetval) { aRetval = mLang; }
|
||||
void GetLang(nsAString& aRetval) {
|
||||
aRetval = mIPCNotification.options().lang();
|
||||
}
|
||||
|
||||
void GetBody(nsAString& aRetval) { aRetval = mBody; }
|
||||
void GetBody(nsAString& aRetval) {
|
||||
aRetval = mIPCNotification.options().body();
|
||||
}
|
||||
|
||||
void GetTag(nsAString& aRetval) { aRetval = mTag; }
|
||||
void GetTag(nsAString& aRetval) {
|
||||
aRetval = mIPCNotification.options().tag();
|
||||
}
|
||||
|
||||
void GetIcon(nsAString& aRetval) { aRetval = mIconUrl; }
|
||||
void GetIcon(nsAString& aRetval) {
|
||||
aRetval = mIPCNotification.options().icon();
|
||||
}
|
||||
|
||||
void MaybeNotifyClose();
|
||||
|
||||
@@ -133,11 +143,6 @@ class Notification : public DOMEventTargetHelper, public SupportsWeakPtr {
|
||||
|
||||
void GetData(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval);
|
||||
|
||||
void InitFromJSVal(JSContext* aCx, JS::Handle<JS::Value> aData,
|
||||
ErrorResult& aRv);
|
||||
|
||||
Result<Ok, QMResult> InitFromBase64(const nsAString& aData);
|
||||
|
||||
static NotificationPermission GetPermission(
|
||||
nsIGlobalObject* aGlobal, notification::PermissionCheckPurpose aPurpose,
|
||||
ErrorResult& aRv);
|
||||
@@ -147,16 +152,12 @@ class Notification : public DOMEventTargetHelper, public SupportsWeakPtr {
|
||||
nsresult DispatchToMainThread(already_AddRefed<nsIRunnable>&& aRunnable);
|
||||
|
||||
protected:
|
||||
Notification(nsIGlobalObject* aGlobal, const nsAString& aID,
|
||||
const nsAString& aTitle, const nsAString& aBody,
|
||||
NotificationDirection aDir, const nsAString& aLang,
|
||||
const nsAString& aTag, const nsAString& aIconUrl,
|
||||
bool aRequireInteraction, bool aSilent,
|
||||
nsTArray<uint32_t>&& aVibrate);
|
||||
Notification(nsIGlobalObject* aGlobal, IPCNotification&& aIPCNotification);
|
||||
|
||||
static already_AddRefed<Notification> CreateInternal(
|
||||
nsIGlobalObject* aGlobal, const nsAString& aID, const nsAString& aTitle,
|
||||
const NotificationOptions& aOptions, ErrorResult& aRv);
|
||||
const nsAString& aDataSerialized, const NotificationOptions& aOptions,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void Deactivate();
|
||||
|
||||
@@ -171,19 +172,7 @@ class Notification : public DOMEventTargetHelper, public SupportsWeakPtr {
|
||||
|
||||
WeakPtr<notification::NotificationChild> mActor;
|
||||
|
||||
// An existing ID loaded from NotificationDB. Leave it empty if we are
|
||||
// creating a new notification.
|
||||
const nsString mID;
|
||||
const nsString mTitle;
|
||||
const nsString mBody;
|
||||
const NotificationDirection mDir;
|
||||
const nsString mLang;
|
||||
const nsString mTag;
|
||||
const nsString mIconUrl;
|
||||
const bool mRequireInteraction;
|
||||
const bool mSilent;
|
||||
nsTArray<uint32_t> mVibrate;
|
||||
nsString mDataAsBase64;
|
||||
const IPCNotification mIPCNotification;
|
||||
|
||||
// It's null until GetData is first called
|
||||
JS::Heap<JS::Value> mData;
|
||||
|
||||
@@ -26,15 +26,14 @@ class NotificationParent final : public PNotificationParent,
|
||||
|
||||
NotificationParent(NotNull<nsIPrincipal*> aPrincipal,
|
||||
NotNull<nsIPrincipal*> aEffectiveStoragePrincipal,
|
||||
bool aIsSecureContext, const nsAString& aId,
|
||||
const nsAString& aScope,
|
||||
const IPCNotificationOptions& aOptions)
|
||||
bool aIsSecureContext, const nsAString& aScope,
|
||||
const IPCNotification& aNotification)
|
||||
: mPrincipal(aPrincipal),
|
||||
mEffectiveStoragePrincipal(aEffectiveStoragePrincipal),
|
||||
mIsSecureContext(aIsSecureContext),
|
||||
mId(aId),
|
||||
mId(aNotification.id()),
|
||||
mScope(aScope),
|
||||
mOptions(aOptions) {};
|
||||
mOptions(aNotification.options()) {};
|
||||
|
||||
IPCResult RecvShow(ShowResolver&& aResolver);
|
||||
IPCResult RecvClose();
|
||||
@@ -64,7 +63,7 @@ class NotificationParent final : public PNotificationParent,
|
||||
// stay empty if the function fails.
|
||||
nsString mId;
|
||||
nsString mScope;
|
||||
IPCNotificationOptions mOptions;
|
||||
const IPCNotificationOptions mOptions;
|
||||
|
||||
nsString mAlertName;
|
||||
|
||||
|
||||
@@ -484,15 +484,15 @@ mozilla::ipc::IPCResult BackgroundParentImpl::RecvCreateNotificationParent(
|
||||
Endpoint<dom::notification::PNotificationParent>&& aParentEndpoint,
|
||||
NotNull<nsIPrincipal*> aPrincipal,
|
||||
NotNull<nsIPrincipal*> aEffectiveStoragePrincipal,
|
||||
const bool& aIsSecureContext, const nsAString& aId, const nsAString& aScope,
|
||||
const IPCNotificationOptions& aOptions,
|
||||
const bool& aIsSecureContext, const nsAString& aScope,
|
||||
const IPCNotification& aNotification,
|
||||
CreateNotificationParentResolver&& aResolver) {
|
||||
AssertIsInMainProcess();
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
auto actor = MakeRefPtr<dom::notification::NotificationParent>(
|
||||
aPrincipal, aEffectiveStoragePrincipal, aIsSecureContext, aId, aScope,
|
||||
aOptions);
|
||||
aPrincipal, aEffectiveStoragePrincipal, aIsSecureContext, aScope,
|
||||
aNotification);
|
||||
actor->BindToMainThread(std::move(aParentEndpoint), std::move(aResolver));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
@@ -133,8 +133,8 @@ class BackgroundParentImpl : public PBackgroundParent {
|
||||
Endpoint<dom::notification::PNotificationParent>&& aParentEndpoint,
|
||||
NotNull<nsIPrincipal*> aPrincipal,
|
||||
NotNull<nsIPrincipal*> aEffectiveStoragePrincipal,
|
||||
const bool& aIsSecureContext, const nsAString& aId,
|
||||
const nsAString& aScope, const IPCNotificationOptions& aOptions,
|
||||
const bool& aIsSecureContext, const nsAString& aScope,
|
||||
const IPCNotification& aNotification,
|
||||
CreateNotificationParentResolver&& aResolver) final;
|
||||
|
||||
already_AddRefed<PIdleSchedulerParent> AllocPIdleSchedulerParent() override;
|
||||
|
||||
@@ -196,9 +196,8 @@ parent:
|
||||
nsIPrincipal aPrincipal,
|
||||
nsIPrincipal aEffectiveStoragePrincipal,
|
||||
bool aIsSecureContext,
|
||||
nsString aId,
|
||||
nsString aScope,
|
||||
IPCNotificationOptions aOptions
|
||||
IPCNotification aNotification
|
||||
) returns (bool rv);
|
||||
|
||||
async PVsync();
|
||||
|
||||
Reference in New Issue
Block a user