2015-05-03 22:32:37 +03:00
|
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2013-03-18 17:24:54 +04:00
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
|
|
#include "mozilla/dom/Notification.h"
|
2015-08-06 15:45:21 +03:00
|
|
|
|
|
|
|
|
|
#include "mozilla/Move.h"
|
|
|
|
|
#include "mozilla/OwningNonNull.h"
|
|
|
|
|
#include "mozilla/Preferences.h"
|
|
|
|
|
#include "mozilla/Services.h"
|
|
|
|
|
#include "mozilla/unused.h"
|
|
|
|
|
|
2013-10-11 22:12:13 +04:00
|
|
|
|
#include "mozilla/dom/AppNotificationServiceOptionsBinding.h"
|
2014-08-21 04:56:12 +04:00
|
|
|
|
#include "mozilla/dom/BindingUtils.h"
|
2015-10-23 00:10:14 +03:00
|
|
|
|
#include "mozilla/dom/ContentChild.h"
|
2015-08-06 15:45:21 +03:00
|
|
|
|
#include "mozilla/dom/NotificationEvent.h"
|
|
|
|
|
#include "mozilla/dom/PermissionMessageUtils.h"
|
2013-10-03 05:27:53 +04:00
|
|
|
|
#include "mozilla/dom/Promise.h"
|
2015-06-26 04:50:25 +03:00
|
|
|
|
#include "mozilla/dom/PromiseWorkerProxy.h"
|
2015-08-06 15:45:21 +03:00
|
|
|
|
#include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h"
|
|
|
|
|
|
|
|
|
|
#include "nsContentPermissionHelper.h"
|
2013-03-18 17:24:54 +04:00
|
|
|
|
#include "nsContentUtils.h"
|
2015-08-06 15:45:21 +03:00
|
|
|
|
#include "nsDOMJSUtils.h"
|
|
|
|
|
#include "nsGlobalWindow.h"
|
2013-03-18 17:24:54 +04:00
|
|
|
|
#include "nsIAlertsService.h"
|
2013-10-03 05:27:53 +04:00
|
|
|
|
#include "nsIAppsService.h"
|
2013-03-18 17:24:54 +04:00
|
|
|
|
#include "nsIContentPermissionPrompt.h"
|
|
|
|
|
#include "nsIDocument.h"
|
2015-08-06 15:45:21 +03:00
|
|
|
|
#include "nsILoadContext.h"
|
2013-10-03 05:27:53 +04:00
|
|
|
|
#include "nsINotificationStorage.h"
|
2013-03-18 17:24:54 +04:00
|
|
|
|
#include "nsIPermissionManager.h"
|
2015-08-06 15:45:21 +03:00
|
|
|
|
#include "nsIScriptSecurityManager.h"
|
2015-06-26 04:50:25 +03:00
|
|
|
|
#include "nsIServiceWorkerManager.h"
|
2013-10-03 05:27:53 +04:00
|
|
|
|
#include "nsIUUIDGenerator.h"
|
2015-08-06 15:45:21 +03:00
|
|
|
|
#include "nsIXPConnect.h"
|
|
|
|
|
#include "nsNetUtil.h"
|
|
|
|
|
#include "nsProxyRelease.h"
|
2013-03-18 17:24:54 +04:00
|
|
|
|
#include "nsServiceManagerUtils.h"
|
2014-08-21 04:56:12 +04:00
|
|
|
|
#include "nsStructuredCloneContainer.h"
|
2013-03-18 17:24:54 +04:00
|
|
|
|
#include "nsToolkitCompsCID.h"
|
2015-10-23 00:10:14 +03:00
|
|
|
|
#include "nsXULAppAPI.h"
|
2015-06-26 04:50:24 +03:00
|
|
|
|
#include "ServiceWorkerManager.h"
|
2015-06-26 04:53:02 +03:00
|
|
|
|
#include "WorkerPrivate.h"
|
|
|
|
|
#include "WorkerRunnable.h"
|
2015-06-26 04:50:25 +03:00
|
|
|
|
#include "WorkerScope.h"
|
2015-06-26 04:53:02 +03:00
|
|
|
|
|
2015-08-06 15:45:21 +03:00
|
|
|
|
#ifdef MOZ_B2G
|
|
|
|
|
#include "nsIDOMDesktopNotification.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
2013-03-18 17:24:54 +04:00
|
|
|
|
namespace mozilla {
|
|
|
|
|
namespace dom {
|
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
using namespace workers;
|
|
|
|
|
|
2015-06-26 04:50:25 +03:00
|
|
|
|
struct NotificationStrings
|
2015-05-04 16:04:25 +03:00
|
|
|
|
{
|
2015-06-26 04:50:25 +03:00
|
|
|
|
const nsString mID;
|
|
|
|
|
const nsString mTitle;
|
|
|
|
|
const nsString mDir;
|
|
|
|
|
const nsString mLang;
|
|
|
|
|
const nsString mBody;
|
|
|
|
|
const nsString mTag;
|
|
|
|
|
const nsString mIcon;
|
|
|
|
|
const nsString mData;
|
|
|
|
|
const nsString mBehavior;
|
|
|
|
|
const nsString mServiceWorkerRegistrationID;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class ScopeCheckingGetCallback : public nsINotificationStorageCallback
|
|
|
|
|
{
|
|
|
|
|
const nsString mScope;
|
2013-10-03 05:27:53 +04:00
|
|
|
|
public:
|
2015-06-26 04:50:25 +03:00
|
|
|
|
explicit ScopeCheckingGetCallback(const nsAString& aScope)
|
|
|
|
|
: mScope(aScope)
|
|
|
|
|
{}
|
2013-10-03 05:27:53 +04:00
|
|
|
|
|
|
|
|
|
NS_IMETHOD Handle(const nsAString& aID,
|
|
|
|
|
const nsAString& aTitle,
|
|
|
|
|
const nsAString& aDir,
|
|
|
|
|
const nsAString& aLang,
|
|
|
|
|
const nsAString& aBody,
|
|
|
|
|
const nsAString& aTag,
|
|
|
|
|
const nsAString& aIcon,
|
2014-08-21 04:56:12 +04:00
|
|
|
|
const nsAString& aData,
|
2014-09-17 01:12:00 +04:00
|
|
|
|
const nsAString& aBehavior,
|
2015-06-26 04:50:25 +03:00
|
|
|
|
const nsAString& aServiceWorkerRegistrationID,
|
2015-06-26 04:50:25 +03:00
|
|
|
|
JSContext* aCx) final
|
2013-10-03 05:27:53 +04:00
|
|
|
|
{
|
2015-06-26 04:50:25 +03:00
|
|
|
|
AssertIsOnMainThread();
|
2013-10-03 05:27:53 +04:00
|
|
|
|
MOZ_ASSERT(!aID.IsEmpty());
|
|
|
|
|
|
2015-06-26 04:50:25 +03:00
|
|
|
|
// Skip scopes that don't match when called from getNotifications().
|
|
|
|
|
if (!mScope.IsEmpty() && !mScope.Equals(aServiceWorkerRegistrationID)) {
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:50:25 +03:00
|
|
|
|
NotificationStrings strings = {
|
|
|
|
|
nsString(aID),
|
|
|
|
|
nsString(aTitle),
|
|
|
|
|
nsString(aDir),
|
|
|
|
|
nsString(aLang),
|
|
|
|
|
nsString(aBody),
|
|
|
|
|
nsString(aTag),
|
|
|
|
|
nsString(aIcon),
|
|
|
|
|
nsString(aData),
|
|
|
|
|
nsString(aBehavior),
|
|
|
|
|
nsString(aServiceWorkerRegistrationID),
|
|
|
|
|
};
|
2015-06-26 02:52:40 +03:00
|
|
|
|
|
2015-06-26 04:50:25 +03:00
|
|
|
|
mStrings.AppendElement(Move(strings));
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
2015-06-26 04:50:25 +03:00
|
|
|
|
|
2015-06-26 04:50:25 +03:00
|
|
|
|
NS_IMETHOD Done(JSContext* aCx) override = 0;
|
2015-06-26 02:52:40 +03:00
|
|
|
|
|
2015-06-26 04:50:25 +03:00
|
|
|
|
protected:
|
|
|
|
|
virtual ~ScopeCheckingGetCallback()
|
|
|
|
|
{}
|
2015-06-26 04:50:25 +03:00
|
|
|
|
|
2015-06-26 04:50:25 +03:00
|
|
|
|
nsTArray<NotificationStrings> mStrings;
|
|
|
|
|
};
|
2015-06-26 02:52:40 +03:00
|
|
|
|
|
2015-06-26 04:50:25 +03:00
|
|
|
|
class NotificationStorageCallback final : public ScopeCheckingGetCallback
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
|
|
|
|
NS_DECL_CYCLE_COLLECTION_CLASS(NotificationStorageCallback)
|
|
|
|
|
|
|
|
|
|
NotificationStorageCallback(nsIGlobalObject* aWindow, const nsAString& aScope,
|
|
|
|
|
Promise* aPromise)
|
|
|
|
|
: ScopeCheckingGetCallback(aScope),
|
|
|
|
|
mWindow(aWindow),
|
|
|
|
|
mPromise(aPromise)
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnMainThread();
|
|
|
|
|
MOZ_ASSERT(aWindow);
|
|
|
|
|
MOZ_ASSERT(aPromise);
|
2015-05-04 16:04:25 +03:00
|
|
|
|
}
|
2015-04-28 00:18:54 +03:00
|
|
|
|
|
2015-06-26 04:50:25 +03:00
|
|
|
|
NS_IMETHOD Done(JSContext* aCx) final
|
2015-05-04 16:04:25 +03:00
|
|
|
|
{
|
2015-06-26 04:50:25 +03:00
|
|
|
|
AutoJSAPI jsapi;
|
|
|
|
|
DebugOnly<bool> ok = jsapi.Init(mWindow, aCx);
|
|
|
|
|
MOZ_ASSERT(ok);
|
|
|
|
|
|
2015-06-26 04:50:25 +03:00
|
|
|
|
ErrorResult result;
|
2015-10-18 08:24:48 +03:00
|
|
|
|
nsAutoTArray<RefPtr<Notification>, 5> notifications;
|
2015-06-26 04:50:25 +03:00
|
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < mStrings.Length(); ++i) {
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<Notification> n =
|
2015-06-26 04:50:25 +03:00
|
|
|
|
Notification::ConstructFromFields(mWindow,
|
|
|
|
|
mStrings[i].mID,
|
|
|
|
|
mStrings[i].mTitle,
|
|
|
|
|
mStrings[i].mDir,
|
|
|
|
|
mStrings[i].mLang,
|
|
|
|
|
mStrings[i].mBody,
|
|
|
|
|
mStrings[i].mTag,
|
|
|
|
|
mStrings[i].mIcon,
|
|
|
|
|
mStrings[i].mData,
|
|
|
|
|
/* mStrings[i].mBehavior, not
|
|
|
|
|
* supported */
|
|
|
|
|
mStrings[i].mServiceWorkerRegistrationID,
|
|
|
|
|
result);
|
|
|
|
|
|
|
|
|
|
n->SetStoredState(true);
|
2015-11-02 08:53:26 +03:00
|
|
|
|
Unused << NS_WARN_IF(result.Failed());
|
2015-06-26 04:50:25 +03:00
|
|
|
|
if (!result.Failed()) {
|
|
|
|
|
notifications.AppendElement(n.forget());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mPromise->MaybeResolve(notifications);
|
2015-06-26 02:52:40 +03:00
|
|
|
|
return NS_OK;
|
2013-10-03 05:27:53 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 02:52:40 +03:00
|
|
|
|
private:
|
|
|
|
|
virtual ~NotificationStorageCallback()
|
2015-06-26 04:50:25 +03:00
|
|
|
|
{}
|
2013-10-03 05:27:53 +04:00
|
|
|
|
|
2015-06-26 04:50:25 +03:00
|
|
|
|
nsCOMPtr<nsIGlobalObject> mWindow;
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<Promise> mPromise;
|
2015-06-26 04:50:25 +03:00
|
|
|
|
const nsString mScope;
|
2013-10-03 05:27:53 +04:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(NotificationStorageCallback)
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(NotificationStorageCallback)
|
2015-06-26 04:50:25 +03:00
|
|
|
|
NS_IMPL_CYCLE_COLLECTION(NotificationStorageCallback, mWindow, mPromise);
|
2013-10-03 05:27:53 +04:00
|
|
|
|
|
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(NotificationStorageCallback)
|
2015-07-30 04:56:30 +03:00
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsINotificationStorageCallback)
|
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
|
|
|
NS_INTERFACE_MAP_END
|
2015-05-06 23:52:41 +03:00
|
|
|
|
|
2015-06-26 04:50:24 +03:00
|
|
|
|
class NotificationGetRunnable final : public nsRunnable
|
|
|
|
|
{
|
|
|
|
|
const nsString mOrigin;
|
|
|
|
|
const nsString mTag;
|
|
|
|
|
nsCOMPtr<nsINotificationStorageCallback> mCallback;
|
|
|
|
|
public:
|
|
|
|
|
NotificationGetRunnable(const nsAString& aOrigin,
|
|
|
|
|
const nsAString& aTag,
|
|
|
|
|
nsINotificationStorageCallback* aCallback)
|
|
|
|
|
: mOrigin(aOrigin), mTag(aTag), mCallback(aCallback)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
NS_IMETHOD
|
|
|
|
|
Run() override
|
|
|
|
|
{
|
|
|
|
|
nsresult rv;
|
|
|
|
|
nsCOMPtr<nsINotificationStorage> notificationStorage =
|
|
|
|
|
do_GetService(NS_NOTIFICATION_STORAGE_CONTRACTID, &rv);
|
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rv = notificationStorage->Get(mOrigin, mTag, mCallback);
|
|
|
|
|
//XXXnsm Is it guaranteed mCallback will be called in case of failure?
|
2015-11-02 08:53:26 +03:00
|
|
|
|
Unused << NS_WARN_IF(NS_FAILED(rv));
|
2015-06-26 04:50:24 +03:00
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2013-03-18 17:24:54 +04:00
|
|
|
|
class NotificationPermissionRequest : public nsIContentPermissionRequest,
|
|
|
|
|
public nsIRunnable
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
|
|
|
|
NS_DECL_NSICONTENTPERMISSIONREQUEST
|
|
|
|
|
NS_DECL_NSIRUNNABLE
|
|
|
|
|
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(NotificationPermissionRequest,
|
|
|
|
|
nsIContentPermissionRequest)
|
|
|
|
|
|
|
|
|
|
NotificationPermissionRequest(nsIPrincipal* aPrincipal, nsPIDOMWindow* aWindow,
|
|
|
|
|
NotificationPermissionCallback* aCallback)
|
|
|
|
|
: mPrincipal(aPrincipal), mWindow(aWindow),
|
2013-05-06 23:28:13 +04:00
|
|
|
|
mPermission(NotificationPermission::Default),
|
2015-04-14 04:08:00 +03:00
|
|
|
|
mCallback(aCallback)
|
|
|
|
|
{
|
|
|
|
|
mRequester = new nsContentPermissionRequester(mWindow);
|
|
|
|
|
}
|
2013-03-18 17:24:54 +04:00
|
|
|
|
|
|
|
|
|
protected:
|
2014-06-23 23:56:07 +04:00
|
|
|
|
virtual ~NotificationPermissionRequest() {}
|
|
|
|
|
|
2013-03-18 17:24:54 +04:00
|
|
|
|
nsresult CallCallback();
|
2012-07-12 19:45:38 +04:00
|
|
|
|
nsresult DispatchCallback();
|
2013-03-18 17:24:54 +04:00
|
|
|
|
nsCOMPtr<nsIPrincipal> mPrincipal;
|
|
|
|
|
nsCOMPtr<nsPIDOMWindow> mWindow;
|
|
|
|
|
NotificationPermission mPermission;
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<NotificationPermissionCallback> mCallback;
|
2015-04-14 04:08:00 +03:00
|
|
|
|
nsCOMPtr<nsIContentPermissionRequester> mRequester;
|
2013-03-18 17:24:54 +04:00
|
|
|
|
};
|
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
namespace {
|
|
|
|
|
class ReleaseNotificationControlRunnable final : public MainThreadWorkerControlRunnable
|
2015-06-25 21:36:53 +03:00
|
|
|
|
{
|
2015-06-26 04:53:02 +03:00
|
|
|
|
Notification* mNotification;
|
|
|
|
|
|
2015-06-25 21:36:53 +03:00
|
|
|
|
public:
|
2015-06-26 04:53:02 +03:00
|
|
|
|
explicit ReleaseNotificationControlRunnable(Notification* aNotification)
|
|
|
|
|
: MainThreadWorkerControlRunnable(aNotification->mWorkerPrivate)
|
|
|
|
|
, mNotification(aNotification)
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
|
|
|
|
{
|
|
|
|
|
mNotification->ReleaseObject();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class GetPermissionRunnable final : public WorkerMainThreadRunnable
|
|
|
|
|
{
|
|
|
|
|
NotificationPermission mPermission;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit GetPermissionRunnable(WorkerPrivate* aWorker)
|
|
|
|
|
: WorkerMainThreadRunnable(aWorker)
|
|
|
|
|
, mPermission(NotificationPermission::Denied)
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
MainThreadRun() override
|
|
|
|
|
{
|
|
|
|
|
ErrorResult result;
|
|
|
|
|
mPermission =
|
|
|
|
|
Notification::GetPermissionInternal(mWorkerPrivate->GetPrincipal(),
|
|
|
|
|
result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NotificationPermission
|
|
|
|
|
GetPermission()
|
|
|
|
|
{
|
|
|
|
|
return mPermission;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class FocusWindowRunnable final : public nsRunnable
|
|
|
|
|
{
|
|
|
|
|
nsMainThreadPtrHandle<nsPIDOMWindow> mWindow;
|
|
|
|
|
public:
|
|
|
|
|
explicit FocusWindowRunnable(const nsMainThreadPtrHandle<nsPIDOMWindow>& aWindow)
|
|
|
|
|
: mWindow(aWindow)
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
NS_IMETHOD
|
|
|
|
|
Run()
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnMainThread();
|
|
|
|
|
if (!mWindow->IsCurrentInnerWindow()) {
|
|
|
|
|
// Window has been closed, this observer is not valid anymore
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nsIDocument* doc = mWindow->GetExtantDoc();
|
|
|
|
|
if (doc) {
|
|
|
|
|
// Browser UI may use DOMWebNotificationClicked to focus the tab
|
|
|
|
|
// from which the event was dispatched.
|
|
|
|
|
nsContentUtils::DispatchChromeEvent(doc, mWindow->GetOuterWindow(),
|
|
|
|
|
NS_LITERAL_STRING("DOMWebNotificationClicked"),
|
|
|
|
|
true, true);
|
|
|
|
|
}
|
2015-05-06 23:52:41 +03:00
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
};
|
2015-06-26 04:50:24 +03:00
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
|
CheckScope(nsIPrincipal* aPrincipal, const nsACString& aScope)
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnMainThread();
|
|
|
|
|
MOZ_ASSERT(aPrincipal);
|
|
|
|
|
|
|
|
|
|
nsCOMPtr<nsIURI> scopeURI;
|
|
|
|
|
nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), aScope, nullptr, nullptr);
|
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return aPrincipal->CheckMayLoad(scopeURI, /* report = */ true,
|
|
|
|
|
/* allowIfInheritsPrincipal = */ false);
|
|
|
|
|
}
|
|
|
|
|
} // anonymous namespace
|
2013-03-18 17:24:54 +04:00
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
// Subclass that can be directly dispatched to child workers from the main
|
|
|
|
|
// thread.
|
|
|
|
|
class NotificationWorkerRunnable : public WorkerRunnable
|
|
|
|
|
{
|
2014-06-23 23:56:07 +04:00
|
|
|
|
protected:
|
2015-06-26 04:53:02 +03:00
|
|
|
|
explicit NotificationWorkerRunnable(WorkerPrivate* aWorkerPrivate)
|
|
|
|
|
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
|
|
|
|
bool aDispatchResult) override
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
|
|
|
|
{
|
|
|
|
|
aWorkerPrivate->AssertIsOnWorkerThread();
|
|
|
|
|
aWorkerPrivate->ModifyBusyCountFromWorker(aCx, true);
|
2015-06-26 04:50:25 +03:00
|
|
|
|
WorkerRunInternal(aCx, aWorkerPrivate);
|
2015-06-26 04:53:02 +03:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
|
|
|
|
bool aRunResult) override
|
|
|
|
|
{
|
|
|
|
|
aWorkerPrivate->ModifyBusyCountFromWorker(aCx, false);
|
|
|
|
|
}
|
2015-06-25 21:36:53 +03:00
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
virtual void
|
2015-06-26 04:50:25 +03:00
|
|
|
|
WorkerRunInternal(JSContext* aCx, WorkerPrivate* aWorkerPrivate) = 0;
|
2013-03-18 17:24:54 +04:00
|
|
|
|
};
|
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
// Overrides dispatch and run handlers so we can directly dispatch from main
|
|
|
|
|
// thread to child workers.
|
|
|
|
|
class NotificationEventWorkerRunnable final : public NotificationWorkerRunnable
|
2013-03-18 17:24:54 +04:00
|
|
|
|
{
|
2015-06-26 04:53:02 +03:00
|
|
|
|
Notification* mNotification;
|
|
|
|
|
const nsString mEventName;
|
2015-06-25 21:36:53 +03:00
|
|
|
|
public:
|
2015-06-26 04:53:02 +03:00
|
|
|
|
NotificationEventWorkerRunnable(Notification* aNotification,
|
|
|
|
|
const nsString& aEventName)
|
|
|
|
|
: NotificationWorkerRunnable(aNotification->mWorkerPrivate)
|
|
|
|
|
, mNotification(aNotification)
|
|
|
|
|
, mEventName(aEventName)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
void
|
2015-06-26 04:50:25 +03:00
|
|
|
|
WorkerRunInternal(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
2015-06-26 04:53:02 +03:00
|
|
|
|
{
|
|
|
|
|
mNotification->DispatchTrustedEvent(mEventName);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2015-08-25 01:40:57 +03:00
|
|
|
|
class ReleaseNotificationRunnable final : public NotificationWorkerRunnable
|
|
|
|
|
{
|
|
|
|
|
Notification* mNotification;
|
|
|
|
|
public:
|
|
|
|
|
explicit ReleaseNotificationRunnable(Notification* aNotification)
|
|
|
|
|
: NotificationWorkerRunnable(aNotification->mWorkerPrivate)
|
|
|
|
|
, mNotification(aNotification)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
WorkerRunInternal(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
|
|
|
|
{
|
|
|
|
|
mNotification->ReleaseObject();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
// Create one whenever you require ownership of the notification. Use with
|
|
|
|
|
// UniquePtr<>. See Notification.h for details.
|
2015-06-26 04:53:02 +03:00
|
|
|
|
class NotificationRef final {
|
|
|
|
|
friend class WorkerNotificationObserver;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
Notification* mNotification;
|
2015-06-26 04:53:02 +03:00
|
|
|
|
bool mInited;
|
2015-06-26 04:53:02 +03:00
|
|
|
|
|
|
|
|
|
// Only useful for workers.
|
|
|
|
|
void
|
|
|
|
|
Forget()
|
|
|
|
|
{
|
|
|
|
|
mNotification = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit NotificationRef(Notification* aNotification)
|
|
|
|
|
: mNotification(aNotification)
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(mNotification);
|
|
|
|
|
if (mNotification->mWorkerPrivate) {
|
|
|
|
|
mNotification->mWorkerPrivate->AssertIsOnWorkerThread();
|
|
|
|
|
} else {
|
|
|
|
|
AssertIsOnMainThread();
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
mInited = mNotification->AddRefObject();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This is only required because Gecko runs script in a worker's onclose
|
|
|
|
|
// handler (non-standard, Bug 790919) where calls to AddFeature() will fail.
|
|
|
|
|
// Due to non-standardness and added complications if we decide to support
|
|
|
|
|
// this, attempts to create a Notification in onclose just throw exceptions.
|
|
|
|
|
bool
|
|
|
|
|
Initialized()
|
|
|
|
|
{
|
|
|
|
|
return mInited;
|
2015-06-26 04:53:02 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~NotificationRef()
|
|
|
|
|
{
|
2015-06-26 04:53:02 +03:00
|
|
|
|
if (Initialized() && mNotification) {
|
2015-08-25 01:40:57 +03:00
|
|
|
|
Notification* notification = mNotification;
|
|
|
|
|
mNotification = nullptr;
|
|
|
|
|
if (notification->mWorkerPrivate && NS_IsMainThread()) {
|
|
|
|
|
// Try to pass ownership back to the worker. If the dispatch succeeds we
|
|
|
|
|
// are guaranteed this runnable will run, and that it will run after queued
|
|
|
|
|
// event runnables, so event runnables will have a safe pointer to the
|
|
|
|
|
// Notification.
|
|
|
|
|
//
|
|
|
|
|
// If the dispatch fails, the worker isn't running anymore and the event
|
|
|
|
|
// runnables have already run or been canceled. We can use a control
|
|
|
|
|
// runnable to release the reference.
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<ReleaseNotificationRunnable> r =
|
2015-08-25 01:40:57 +03:00
|
|
|
|
new ReleaseNotificationRunnable(notification);
|
|
|
|
|
|
|
|
|
|
AutoJSAPI jsapi;
|
|
|
|
|
jsapi.Init();
|
|
|
|
|
if (!r->Dispatch(jsapi.cx())) {
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<ReleaseNotificationControlRunnable> r =
|
2015-08-25 01:40:57 +03:00
|
|
|
|
new ReleaseNotificationControlRunnable(notification);
|
|
|
|
|
MOZ_ALWAYS_TRUE(r->Dispatch(jsapi.cx()));
|
2015-06-26 04:53:02 +03:00
|
|
|
|
}
|
|
|
|
|
} else {
|
2015-08-25 01:40:57 +03:00
|
|
|
|
notification->AssertIsOnTargetThread();
|
|
|
|
|
notification->ReleaseObject();
|
2015-06-26 04:53:02 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// XXXnsm, is it worth having some sort of WeakPtr like wrapper instead of
|
|
|
|
|
// a rawptr that the NotificationRef can invalidate?
|
|
|
|
|
Notification*
|
|
|
|
|
GetNotification()
|
|
|
|
|
{
|
2015-06-26 04:53:02 +03:00
|
|
|
|
MOZ_ASSERT(Initialized());
|
2015-06-26 04:53:02 +03:00
|
|
|
|
return mNotification;
|
|
|
|
|
}
|
|
|
|
|
};
|
2013-03-18 17:24:54 +04:00
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
class NotificationTask : public nsRunnable
|
|
|
|
|
{
|
|
|
|
|
public:
|
2013-03-18 17:24:54 +04:00
|
|
|
|
enum NotificationAction {
|
|
|
|
|
eShow,
|
|
|
|
|
eClose
|
|
|
|
|
};
|
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
NotificationTask(UniquePtr<NotificationRef> aRef, NotificationAction aAction)
|
2015-06-26 04:50:24 +03:00
|
|
|
|
: mNotificationRef(Move(aRef)), mAction(aAction)
|
|
|
|
|
{}
|
2013-03-18 17:24:54 +04:00
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
NS_IMETHOD
|
|
|
|
|
Run() override;
|
2014-06-23 23:56:07 +04:00
|
|
|
|
protected:
|
2013-03-18 17:24:54 +04:00
|
|
|
|
virtual ~NotificationTask() {}
|
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
UniquePtr<NotificationRef> mNotificationRef;
|
2013-03-18 17:24:54 +04:00
|
|
|
|
NotificationAction mAction;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
uint32_t Notification::sCount = 0;
|
|
|
|
|
|
2014-04-25 20:49:00 +04:00
|
|
|
|
NS_IMPL_CYCLE_COLLECTION(NotificationPermissionRequest, mWindow)
|
2013-03-18 17:24:54 +04:00
|
|
|
|
|
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(NotificationPermissionRequest)
|
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest)
|
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIRunnable)
|
|
|
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentPermissionRequest)
|
|
|
|
|
NS_INTERFACE_MAP_END
|
|
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(NotificationPermissionRequest)
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(NotificationPermissionRequest)
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
NotificationPermissionRequest::Run()
|
|
|
|
|
{
|
2013-05-24 02:38:00 +04:00
|
|
|
|
if (nsContentUtils::IsSystemPrincipal(mPrincipal)) {
|
2013-05-06 23:28:13 +04:00
|
|
|
|
mPermission = NotificationPermission::Granted;
|
2013-05-24 02:38:00 +04:00
|
|
|
|
} else {
|
|
|
|
|
// File are automatically granted permission.
|
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
|
mPrincipal->GetURI(getter_AddRefs(uri));
|
|
|
|
|
|
|
|
|
|
if (uri) {
|
|
|
|
|
bool isFile;
|
|
|
|
|
uri->SchemeIs("file", &isFile);
|
|
|
|
|
if (isFile) {
|
|
|
|
|
mPermission = NotificationPermission::Granted;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-07-12 19:45:38 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Grant permission if pref'ed on.
|
|
|
|
|
if (Preferences::GetBool("notification.prompt.testing", false)) {
|
|
|
|
|
if (Preferences::GetBool("notification.prompt.testing.allow", true)) {
|
2013-05-06 23:28:13 +04:00
|
|
|
|
mPermission = NotificationPermission::Granted;
|
2012-07-12 19:45:38 +04:00
|
|
|
|
} else {
|
2013-05-06 23:28:13 +04:00
|
|
|
|
mPermission = NotificationPermission::Denied;
|
2012-07-12 19:45:38 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-06 23:28:13 +04:00
|
|
|
|
if (mPermission != NotificationPermission::Default) {
|
2012-07-12 19:45:38 +04:00
|
|
|
|
return DispatchCallback();
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-01 11:22:20 +04:00
|
|
|
|
return nsContentPermissionUtils::AskPermission(this, mWindow);
|
2013-03-18 17:24:54 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
NotificationPermissionRequest::GetPrincipal(nsIPrincipal** aRequestingPrincipal)
|
|
|
|
|
{
|
|
|
|
|
NS_ADDREF(*aRequestingPrincipal = mPrincipal);
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
NotificationPermissionRequest::GetWindow(nsIDOMWindow** aRequestingWindow)
|
|
|
|
|
{
|
|
|
|
|
NS_ADDREF(*aRequestingWindow = mWindow);
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
NotificationPermissionRequest::GetElement(nsIDOMElement** aElement)
|
|
|
|
|
{
|
2013-09-04 19:40:16 +04:00
|
|
|
|
NS_ENSURE_ARG_POINTER(aElement);
|
|
|
|
|
*aElement = nullptr;
|
|
|
|
|
return NS_OK;
|
2013-03-18 17:24:54 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
NotificationPermissionRequest::Cancel()
|
|
|
|
|
{
|
2013-05-06 23:28:13 +04:00
|
|
|
|
mPermission = NotificationPermission::Denied;
|
2012-07-12 19:45:38 +04:00
|
|
|
|
return DispatchCallback();
|
2013-03-18 17:24:54 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2013-09-10 19:41:59 +04:00
|
|
|
|
NotificationPermissionRequest::Allow(JS::HandleValue aChoices)
|
2013-03-18 17:24:54 +04:00
|
|
|
|
{
|
2013-09-10 19:41:59 +04:00
|
|
|
|
MOZ_ASSERT(aChoices.isUndefined());
|
|
|
|
|
|
2013-05-06 23:28:13 +04:00
|
|
|
|
mPermission = NotificationPermission::Granted;
|
2012-07-12 19:45:38 +04:00
|
|
|
|
return DispatchCallback();
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-14 04:08:00 +03:00
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
NotificationPermissionRequest::GetRequester(nsIContentPermissionRequester** aRequester)
|
|
|
|
|
{
|
|
|
|
|
NS_ENSURE_ARG_POINTER(aRequester);
|
|
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContentPermissionRequester> requester = mRequester;
|
|
|
|
|
requester.forget(aRequester);
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-12 19:45:38 +04:00
|
|
|
|
inline nsresult
|
|
|
|
|
NotificationPermissionRequest::DispatchCallback()
|
|
|
|
|
{
|
|
|
|
|
if (!mCallback) {
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-18 17:24:54 +04:00
|
|
|
|
nsCOMPtr<nsIRunnable> callbackRunnable = NS_NewRunnableMethod(this,
|
|
|
|
|
&NotificationPermissionRequest::CallCallback);
|
2012-07-12 19:45:38 +04:00
|
|
|
|
return NS_DispatchToMainThread(callbackRunnable);
|
2013-03-18 17:24:54 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
|
NotificationPermissionRequest::CallCallback()
|
|
|
|
|
{
|
|
|
|
|
ErrorResult rv;
|
|
|
|
|
mCallback->Call(mPermission, rv);
|
2015-04-27 16:18:51 +03:00
|
|
|
|
return rv.StealNSResult();
|
2013-03-18 17:24:54 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2014-02-10 00:34:40 +04:00
|
|
|
|
NotificationPermissionRequest::GetTypes(nsIArray** aTypes)
|
2013-03-18 17:24:54 +04:00
|
|
|
|
{
|
2013-09-10 19:41:59 +04:00
|
|
|
|
nsTArray<nsString> emptyOptions;
|
2014-08-01 11:22:20 +04:00
|
|
|
|
return nsContentPermissionUtils::CreatePermissionArray(NS_LITERAL_CSTRING("desktop-notification"),
|
2015-05-03 22:32:33 +03:00
|
|
|
|
NS_LITERAL_CSTRING("unused"),
|
|
|
|
|
emptyOptions,
|
|
|
|
|
aTypes);
|
2013-03-18 17:24:54 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-09-25 23:18:28 +03:00
|
|
|
|
// Observer that the alert service calls to do common tasks and/or dispatch to the
|
|
|
|
|
// specific observer for the context e.g. main thread, worker, or service worker.
|
|
|
|
|
class NotificationObserver final : public nsIObserver
|
2015-06-26 04:53:02 +03:00
|
|
|
|
{
|
|
|
|
|
public:
|
2015-09-25 23:18:28 +03:00
|
|
|
|
nsCOMPtr<nsIObserver> mObserver;
|
|
|
|
|
nsCOMPtr<nsIPrincipal> mPrincipal;
|
2015-06-26 04:53:02 +03:00
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
|
NS_DECL_NSIOBSERVER
|
|
|
|
|
|
2015-09-25 23:18:28 +03:00
|
|
|
|
NotificationObserver(nsIObserver* aObserver, nsIPrincipal* aPrincipal)
|
|
|
|
|
: mObserver(aObserver), mPrincipal(aPrincipal)
|
2015-06-26 04:53:02 +03:00
|
|
|
|
{
|
|
|
|
|
AssertIsOnMainThread();
|
2015-09-25 23:18:28 +03:00
|
|
|
|
MOZ_ASSERT(mObserver);
|
|
|
|
|
MOZ_ASSERT(mPrincipal);
|
2015-06-26 04:53:02 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
virtual ~NotificationObserver()
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnMainThread();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS(NotificationObserver, nsIObserver)
|
2013-03-18 17:24:54 +04:00
|
|
|
|
|
2015-09-25 23:18:28 +03:00
|
|
|
|
class MainThreadNotificationObserver : public nsIObserver
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
UniquePtr<NotificationRef> mNotificationRef;
|
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
|
NS_DECL_NSIOBSERVER
|
|
|
|
|
|
|
|
|
|
explicit MainThreadNotificationObserver(UniquePtr<NotificationRef> aRef)
|
|
|
|
|
: mNotificationRef(Move(aRef))
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnMainThread();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
virtual ~MainThreadNotificationObserver()
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnMainThread();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS(MainThreadNotificationObserver, nsIObserver)
|
|
|
|
|
|
2013-03-18 17:24:54 +04:00
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
NotificationTask::Run()
|
|
|
|
|
{
|
2015-06-26 04:53:02 +03:00
|
|
|
|
AssertIsOnMainThread();
|
|
|
|
|
|
|
|
|
|
// Get a pointer to notification before the notification takes ownership of
|
|
|
|
|
// the ref (it owns itself temporarily, with ShowInternal() and
|
|
|
|
|
// CloseInternal() passing on the ownership appropriately.)
|
|
|
|
|
Notification* notif = mNotificationRef->GetNotification();
|
|
|
|
|
notif->mTempRef.swap(mNotificationRef);
|
|
|
|
|
if (mAction == eShow) {
|
|
|
|
|
notif->ShowInternal();
|
|
|
|
|
} else if (mAction == eClose) {
|
|
|
|
|
notif->CloseInternal();
|
|
|
|
|
} else {
|
|
|
|
|
MOZ_CRASH("Invalid action");
|
2013-03-18 17:24:54 +04:00
|
|
|
|
}
|
2015-06-26 04:53:02 +03:00
|
|
|
|
|
|
|
|
|
MOZ_ASSERT(!mNotificationRef);
|
2013-10-03 05:27:53 +04:00
|
|
|
|
return NS_OK;
|
2013-03-18 17:24:54 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
// static
|
|
|
|
|
bool
|
|
|
|
|
Notification::PrefEnabled(JSContext* aCx, JSObject* aObj)
|
2013-03-18 17:24:54 +04:00
|
|
|
|
{
|
2015-06-26 04:53:02 +03:00
|
|
|
|
if (NS_IsMainThread()) {
|
|
|
|
|
return Preferences::GetBool("dom.webnotifications.enabled", false);
|
2014-06-04 14:06:00 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
|
|
|
|
|
if (!workerPrivate) {
|
|
|
|
|
return false;
|
2013-03-18 17:24:54 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-09-15 22:58:32 +03:00
|
|
|
|
if (workerPrivate->IsServiceWorker()) {
|
|
|
|
|
return workerPrivate->DOMServiceWorkerNotificationEnabled();
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
return workerPrivate->DOMWorkerNotificationEnabled();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// static
|
|
|
|
|
bool
|
|
|
|
|
Notification::IsGetEnabled(JSContext* aCx, JSObject* aObj)
|
|
|
|
|
{
|
|
|
|
|
return NS_IsMainThread();
|
2013-03-18 17:24:54 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:50:25 +03:00
|
|
|
|
Notification::Notification(nsIGlobalObject* aGlobal, const nsAString& aID,
|
|
|
|
|
const nsAString& aTitle, const nsAString& aBody,
|
2013-03-18 17:24:54 +04:00
|
|
|
|
NotificationDirection aDir, const nsAString& aLang,
|
2014-01-07 06:53:23 +04:00
|
|
|
|
const nsAString& aTag, const nsAString& aIconUrl,
|
2015-06-26 04:50:24 +03:00
|
|
|
|
const NotificationBehavior& aBehavior)
|
2015-06-26 04:53:02 +03:00
|
|
|
|
: DOMEventTargetHelper(),
|
|
|
|
|
mWorkerPrivate(nullptr), mObserver(nullptr),
|
2014-01-07 06:53:23 +04:00
|
|
|
|
mID(aID), mTitle(aTitle), mBody(aBody), mDir(aDir), mLang(aLang),
|
2015-07-30 22:44:14 +03:00
|
|
|
|
mTag(aTag), mIconUrl(aIconUrl), mBehavior(aBehavior), mData(JS::NullValue()),
|
|
|
|
|
mIsClosed(false), mIsStored(false), mTaskCount(0)
|
2015-05-06 23:52:41 +03:00
|
|
|
|
{
|
2015-06-26 04:50:25 +03:00
|
|
|
|
if (NS_IsMainThread()) {
|
|
|
|
|
// We can only call this on the main thread because
|
|
|
|
|
// Event::SetEventType() called down the call chain when dispatching events
|
|
|
|
|
// using DOMEventTargetHelper::DispatchTrustedEvent() will assume the event
|
|
|
|
|
// is a main thread event if it has a valid owner. It will then attempt to
|
|
|
|
|
// fetch the atom for the event name which asserts main thread only.
|
|
|
|
|
BindToOwner(aGlobal);
|
|
|
|
|
} else {
|
2015-06-26 04:53:02 +03:00
|
|
|
|
mWorkerPrivate = GetCurrentThreadWorkerPrivate();
|
|
|
|
|
MOZ_ASSERT(mWorkerPrivate);
|
|
|
|
|
}
|
2015-06-26 04:50:24 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Notification::SetAlertName()
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnMainThread();
|
2015-06-26 04:50:25 +03:00
|
|
|
|
if (!mAlertName.IsEmpty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:50:24 +03:00
|
|
|
|
nsAutoString alertName;
|
2015-09-01 22:08:36 +03:00
|
|
|
|
nsresult rv = GetOrigin(GetPrincipal(), alertName);
|
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2014-05-09 01:16:00 +04:00
|
|
|
|
|
|
|
|
|
// Get the notification name that is unique per origin + tag/ID.
|
|
|
|
|
// The name of the alert is of the form origin#tag/ID.
|
2014-05-22 07:48:51 +04:00
|
|
|
|
alertName.Append('#');
|
2014-05-09 01:16:00 +04:00
|
|
|
|
if (!mTag.IsEmpty()) {
|
2014-05-22 07:48:50 +04:00
|
|
|
|
alertName.AppendLiteral("tag:");
|
2014-05-09 01:16:00 +04:00
|
|
|
|
alertName.Append(mTag);
|
|
|
|
|
} else {
|
2014-05-22 07:48:50 +04:00
|
|
|
|
alertName.AppendLiteral("notag:");
|
2014-05-09 01:16:00 +04:00
|
|
|
|
alertName.Append(mID);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mAlertName = alertName;
|
2013-03-18 17:24:54 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
// May be called on any thread.
|
2013-10-03 05:27:53 +04:00
|
|
|
|
// static
|
2013-03-18 17:24:54 +04:00
|
|
|
|
already_AddRefed<Notification>
|
|
|
|
|
Notification::Constructor(const GlobalObject& aGlobal,
|
|
|
|
|
const nsAString& aTitle,
|
|
|
|
|
const NotificationOptions& aOptions,
|
|
|
|
|
ErrorResult& aRv)
|
|
|
|
|
{
|
2015-06-26 04:50:24 +03:00
|
|
|
|
// FIXME(nsm): If the sticky flag is set, throw an error.
|
|
|
|
|
ServiceWorkerGlobalScope* scope = nullptr;
|
|
|
|
|
UNWRAP_WORKER_OBJECT(ServiceWorkerGlobalScope, aGlobal.Get(), scope);
|
|
|
|
|
if (scope) {
|
2015-10-05 19:38:14 +03:00
|
|
|
|
aRv.ThrowTypeError<MSG_NOTIFICATION_NO_CONSTRUCTOR_IN_SERVICEWORKER>();
|
2015-06-26 01:01:01 +03:00
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:50:24 +03:00
|
|
|
|
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<Notification> notification =
|
2015-06-26 04:50:25 +03:00
|
|
|
|
CreateAndShow(global, aTitle, aOptions, EmptyString(), aRv);
|
2015-06-26 04:50:24 +03:00
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
2015-06-26 04:53:02 +03:00
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:50:24 +03:00
|
|
|
|
// This is be ok since we are on the worker thread where this function will
|
|
|
|
|
// run to completion before the Notification has a chance to go away.
|
2015-06-26 04:53:02 +03:00
|
|
|
|
return notification.forget();
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:50:25 +03:00
|
|
|
|
// static
|
|
|
|
|
already_AddRefed<Notification>
|
|
|
|
|
Notification::ConstructFromFields(
|
|
|
|
|
nsIGlobalObject* aGlobal,
|
|
|
|
|
const nsAString& aID,
|
|
|
|
|
const nsAString& aTitle,
|
|
|
|
|
const nsAString& aDir,
|
|
|
|
|
const nsAString& aLang,
|
|
|
|
|
const nsAString& aBody,
|
|
|
|
|
const nsAString& aTag,
|
|
|
|
|
const nsAString& aIcon,
|
|
|
|
|
const nsAString& aData,
|
2015-06-26 04:50:25 +03:00
|
|
|
|
const nsAString& aServiceWorkerRegistrationID,
|
2015-06-26 04:50:25 +03:00
|
|
|
|
ErrorResult& aRv)
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(aGlobal);
|
|
|
|
|
|
|
|
|
|
AutoJSAPI jsapi;
|
|
|
|
|
DebugOnly<bool> ok = jsapi.Init(aGlobal);
|
|
|
|
|
MOZ_ASSERT(ok);
|
|
|
|
|
|
|
|
|
|
RootedDictionary<NotificationOptions> options(jsapi.cx());
|
|
|
|
|
options.mDir = Notification::StringToDirection(nsString(aDir));
|
|
|
|
|
options.mLang = aLang;
|
|
|
|
|
options.mBody = aBody;
|
|
|
|
|
options.mTag = aTag;
|
|
|
|
|
options.mIcon = aIcon;
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<Notification> notification = CreateInternal(aGlobal, aID, aTitle,
|
2015-06-26 04:50:25 +03:00
|
|
|
|
options);
|
2015-06-26 04:50:25 +03:00
|
|
|
|
|
|
|
|
|
notification->InitFromBase64(jsapi.cx(), aData, aRv);
|
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:50:25 +03:00
|
|
|
|
notification->SetScope(aServiceWorkerRegistrationID);
|
2015-06-26 04:50:25 +03:00
|
|
|
|
|
2015-06-26 04:50:25 +03:00
|
|
|
|
return notification.forget();
|
|
|
|
|
}
|
2015-06-26 04:50:24 +03:00
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
nsresult
|
|
|
|
|
Notification::PersistNotification()
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnMainThread();
|
2013-10-03 05:27:53 +04:00
|
|
|
|
nsresult rv;
|
|
|
|
|
nsCOMPtr<nsINotificationStorage> notificationStorage =
|
|
|
|
|
do_GetService(NS_NOTIFICATION_STORAGE_CONTRACTID, &rv);
|
|
|
|
|
if (NS_FAILED(rv)) {
|
2015-06-26 04:53:02 +03:00
|
|
|
|
return rv;
|
2013-10-03 05:27:53 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nsString origin;
|
2015-06-26 04:50:24 +03:00
|
|
|
|
rv = GetOrigin(GetPrincipal(), origin);
|
2015-09-01 22:08:36 +03:00
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
2013-10-03 05:27:53 +04:00
|
|
|
|
|
|
|
|
|
nsString id;
|
2015-06-26 04:53:02 +03:00
|
|
|
|
GetID(id);
|
2014-05-09 01:16:00 +04:00
|
|
|
|
|
|
|
|
|
nsString alertName;
|
2015-06-26 04:53:02 +03:00
|
|
|
|
GetAlertName(alertName);
|
2014-05-09 01:16:00 +04:00
|
|
|
|
|
2014-09-17 01:12:00 +04:00
|
|
|
|
nsAutoString behavior;
|
2015-06-26 04:53:02 +03:00
|
|
|
|
if (!mBehavior.ToJSON(behavior)) {
|
|
|
|
|
return NS_ERROR_FAILURE;
|
2014-09-17 01:12:00 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
rv = notificationStorage->Put(origin,
|
|
|
|
|
id,
|
|
|
|
|
mTitle,
|
|
|
|
|
DirectionToString(mDir),
|
|
|
|
|
mLang,
|
|
|
|
|
mBody,
|
|
|
|
|
mTag,
|
|
|
|
|
mIconUrl,
|
|
|
|
|
alertName,
|
2015-07-30 22:44:14 +03:00
|
|
|
|
mDataAsBase64,
|
2015-06-26 04:50:25 +03:00
|
|
|
|
behavior,
|
|
|
|
|
mScope);
|
2014-08-21 04:56:12 +04:00
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
|
return rv;
|
2013-10-03 05:27:53 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
SetStoredState(true);
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
2014-09-12 18:50:00 +04:00
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
void
|
|
|
|
|
Notification::UnpersistNotification()
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnMainThread();
|
2015-06-26 04:50:24 +03:00
|
|
|
|
if (IsStored()) {
|
2015-06-26 04:53:02 +03:00
|
|
|
|
nsCOMPtr<nsINotificationStorage> notificationStorage =
|
|
|
|
|
do_GetService(NS_NOTIFICATION_STORAGE_CONTRACTID);
|
|
|
|
|
if (notificationStorage) {
|
|
|
|
|
nsString origin;
|
2015-06-26 04:50:24 +03:00
|
|
|
|
nsresult rv = GetOrigin(GetPrincipal(), origin);
|
2015-06-26 04:53:02 +03:00
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
|
notificationStorage->Delete(origin, mID);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
SetStoredState(false);
|
|
|
|
|
}
|
2013-10-03 05:27:53 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
already_AddRefed<Notification>
|
2015-06-26 04:50:25 +03:00
|
|
|
|
Notification::CreateInternal(nsIGlobalObject* aGlobal,
|
|
|
|
|
const nsAString& aID,
|
2013-10-03 05:27:53 +04:00
|
|
|
|
const nsAString& aTitle,
|
|
|
|
|
const NotificationOptions& aOptions)
|
|
|
|
|
{
|
|
|
|
|
nsString id;
|
|
|
|
|
if (!aID.IsEmpty()) {
|
|
|
|
|
id = aID;
|
2013-03-18 17:24:54 +04:00
|
|
|
|
} else {
|
2013-10-03 05:27:53 +04:00
|
|
|
|
nsCOMPtr<nsIUUIDGenerator> uuidgen =
|
|
|
|
|
do_GetService("@mozilla.org/uuid-generator;1");
|
|
|
|
|
NS_ENSURE_TRUE(uuidgen, nullptr);
|
|
|
|
|
nsID uuid;
|
|
|
|
|
nsresult rv = uuidgen->GenerateUUIDInPlace(&uuid);
|
|
|
|
|
NS_ENSURE_SUCCESS(rv, nullptr);
|
|
|
|
|
|
|
|
|
|
char buffer[NSID_LENGTH];
|
|
|
|
|
uuid.ToProvidedString(buffer);
|
|
|
|
|
NS_ConvertASCIItoUTF16 convertedID(buffer);
|
|
|
|
|
id = convertedID;
|
2013-03-18 17:24:54 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<Notification> notification = new Notification(aGlobal, id, aTitle,
|
2013-03-18 17:24:54 +04:00
|
|
|
|
aOptions.mBody,
|
|
|
|
|
aOptions.mDir,
|
|
|
|
|
aOptions.mLang,
|
2013-10-03 05:27:53 +04:00
|
|
|
|
aOptions.mTag,
|
2014-01-07 06:53:23 +04:00
|
|
|
|
aOptions.mIcon,
|
2015-06-26 04:50:24 +03:00
|
|
|
|
aOptions.mMozbehavior);
|
2013-03-18 17:24:54 +04:00
|
|
|
|
return notification.forget();
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
Notification::~Notification()
|
|
|
|
|
{
|
2015-07-30 22:44:14 +03:00
|
|
|
|
mData.setUndefined();
|
|
|
|
|
mozilla::DropJSObjects(this);
|
2015-06-26 04:53:02 +03:00
|
|
|
|
AssertIsOnTargetThread();
|
|
|
|
|
MOZ_ASSERT(!mFeature);
|
|
|
|
|
MOZ_ASSERT(!mTempRef);
|
|
|
|
|
}
|
2014-08-21 04:56:12 +04:00
|
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(Notification)
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Notification, DOMEventTargetHelper)
|
2015-07-30 22:44:14 +03:00
|
|
|
|
tmp->mData.setUndefined();
|
2014-08-21 04:56:12 +04:00
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Notification, DOMEventTargetHelper)
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
|
|
2015-07-30 22:44:14 +03:00
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(Notification, DOMEventTargetHelper)
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mData);
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
|
|
|
|
|
2014-08-21 04:56:12 +04:00
|
|
|
|
NS_IMPL_ADDREF_INHERITED(Notification, DOMEventTargetHelper)
|
|
|
|
|
NS_IMPL_RELEASE_INHERITED(Notification, DOMEventTargetHelper)
|
|
|
|
|
|
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(Notification)
|
|
|
|
|
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
|
|
|
|
|
2013-11-12 03:56:21 +04:00
|
|
|
|
nsIPrincipal*
|
|
|
|
|
Notification::GetPrincipal()
|
|
|
|
|
{
|
2015-06-26 04:53:02 +03:00
|
|
|
|
AssertIsOnMainThread();
|
|
|
|
|
if (mWorkerPrivate) {
|
|
|
|
|
return mWorkerPrivate->GetPrincipal();
|
|
|
|
|
} else {
|
|
|
|
|
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(GetOwner());
|
|
|
|
|
NS_ENSURE_TRUE(sop, nullptr);
|
|
|
|
|
return sop->GetPrincipal();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-25 23:18:28 +03:00
|
|
|
|
class WorkerNotificationObserver final : public MainThreadNotificationObserver
|
2015-06-26 04:53:02 +03:00
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
NS_DECL_ISUPPORTS_INHERITED
|
|
|
|
|
NS_DECL_NSIOBSERVER
|
|
|
|
|
|
|
|
|
|
explicit WorkerNotificationObserver(UniquePtr<NotificationRef> aRef)
|
2015-09-25 23:18:28 +03:00
|
|
|
|
: MainThreadNotificationObserver(Move(aRef))
|
2015-06-26 04:53:02 +03:00
|
|
|
|
{
|
|
|
|
|
AssertIsOnMainThread();
|
|
|
|
|
MOZ_ASSERT(mNotificationRef->GetNotification()->mWorkerPrivate);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ForgetNotification()
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnMainThread();
|
|
|
|
|
mNotificationRef->Forget();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
virtual ~WorkerNotificationObserver()
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnMainThread();
|
|
|
|
|
|
|
|
|
|
MOZ_ASSERT(mNotificationRef);
|
2015-09-02 19:07:14 +03:00
|
|
|
|
Notification* notification = mNotificationRef->GetNotification();
|
|
|
|
|
if (notification) {
|
|
|
|
|
notification->mObserver = nullptr;
|
|
|
|
|
}
|
2015-06-26 04:53:02 +03:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2015-09-25 23:18:28 +03:00
|
|
|
|
NS_IMPL_ISUPPORTS_INHERITED0(WorkerNotificationObserver, MainThreadNotificationObserver)
|
2015-06-26 04:53:02 +03:00
|
|
|
|
|
2015-06-26 04:50:25 +03:00
|
|
|
|
class ServiceWorkerNotificationObserver final : public nsIObserver
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
|
NS_DECL_NSIOBSERVER
|
|
|
|
|
|
|
|
|
|
ServiceWorkerNotificationObserver(const nsAString& aScope,
|
|
|
|
|
nsIPrincipal* aPrincipal,
|
|
|
|
|
const nsAString& aID)
|
|
|
|
|
: mScope(aScope), mID(aID), mPrincipal(aPrincipal)
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnMainThread();
|
|
|
|
|
MOZ_ASSERT(aPrincipal);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
~ServiceWorkerNotificationObserver()
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
const nsString mScope;
|
|
|
|
|
const nsString mID;
|
|
|
|
|
nsCOMPtr<nsIPrincipal> mPrincipal;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS(ServiceWorkerNotificationObserver, nsIObserver)
|
|
|
|
|
|
|
|
|
|
// For ServiceWorkers.
|
|
|
|
|
bool
|
|
|
|
|
Notification::DispatchNotificationClickEvent()
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(mWorkerPrivate);
|
|
|
|
|
MOZ_ASSERT(mWorkerPrivate->IsServiceWorker());
|
|
|
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
|
|
|
|
|
|
|
|
NotificationEventInit options;
|
|
|
|
|
options.mNotification = this;
|
|
|
|
|
|
|
|
|
|
ErrorResult result;
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<EventTarget> target = mWorkerPrivate->GlobalScope();
|
|
|
|
|
RefPtr<NotificationEvent> event =
|
2015-06-26 04:50:25 +03:00
|
|
|
|
NotificationEvent::Constructor(target,
|
|
|
|
|
NS_LITERAL_STRING("notificationclick"),
|
|
|
|
|
options,
|
|
|
|
|
result);
|
|
|
|
|
if (NS_WARN_IF(result.Failed())) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
event->SetTrusted(true);
|
|
|
|
|
WantsPopupControlCheck popupControlCheck(event);
|
|
|
|
|
target->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
|
|
|
|
|
// We always return false since in case of dispatching on the serviceworker,
|
|
|
|
|
// there is no well defined window to focus. The script may use the
|
|
|
|
|
// Client.focus() API if it wishes.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
bool
|
|
|
|
|
Notification::DispatchClickEvent()
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnTargetThread();
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
|
2015-11-13 03:09:42 +03:00
|
|
|
|
event->InitEvent(NS_LITERAL_STRING("click"), false, true);
|
2015-06-26 04:53:02 +03:00
|
|
|
|
event->SetTrusted(true);
|
|
|
|
|
WantsPopupControlCheck popupControlCheck(event);
|
|
|
|
|
bool doDefaultAction = true;
|
|
|
|
|
DispatchEvent(event, &doDefaultAction);
|
|
|
|
|
return doDefaultAction;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Overrides dispatch and run handlers so we can directly dispatch from main
|
|
|
|
|
// thread to child workers.
|
|
|
|
|
class NotificationClickWorkerRunnable final : public NotificationWorkerRunnable
|
|
|
|
|
{
|
|
|
|
|
Notification* mNotification;
|
|
|
|
|
// Optional window that gets focused if click event is not
|
|
|
|
|
// preventDefault()ed.
|
|
|
|
|
nsMainThreadPtrHandle<nsPIDOMWindow> mWindow;
|
|
|
|
|
public:
|
|
|
|
|
NotificationClickWorkerRunnable(Notification* aNotification,
|
|
|
|
|
const nsMainThreadPtrHandle<nsPIDOMWindow>& aWindow)
|
|
|
|
|
: NotificationWorkerRunnable(aNotification->mWorkerPrivate)
|
|
|
|
|
, mNotification(aNotification)
|
|
|
|
|
, mWindow(aWindow)
|
2015-06-26 04:50:25 +03:00
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT_IF(mWorkerPrivate->IsServiceWorker(), !mWindow);
|
|
|
|
|
}
|
2015-06-26 04:53:02 +03:00
|
|
|
|
|
|
|
|
|
void
|
2015-06-26 04:50:25 +03:00
|
|
|
|
WorkerRunInternal(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
2015-06-26 04:53:02 +03:00
|
|
|
|
{
|
|
|
|
|
bool doDefaultAction = mNotification->DispatchClickEvent();
|
2015-06-26 04:50:25 +03:00
|
|
|
|
MOZ_ASSERT_IF(mWorkerPrivate->IsServiceWorker(), !doDefaultAction);
|
2015-06-26 04:53:02 +03:00
|
|
|
|
if (doDefaultAction) {
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<FocusWindowRunnable> r = new FocusWindowRunnable(mWindow);
|
2015-06-26 04:53:02 +03:00
|
|
|
|
NS_DispatchToMainThread(r);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
NotificationObserver::Observe(nsISupports* aSubject, const char* aTopic,
|
|
|
|
|
const char16_t* aData)
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnMainThread();
|
2015-09-25 23:18:28 +03:00
|
|
|
|
|
|
|
|
|
if (!strcmp("alertdisablecallback", aTopic)) {
|
2015-10-23 00:10:14 +03:00
|
|
|
|
if (XRE_IsParentProcess()) {
|
|
|
|
|
return Notification::RemovePermission(mPrincipal);
|
2015-09-25 23:18:28 +03:00
|
|
|
|
}
|
2015-10-23 00:10:14 +03:00
|
|
|
|
// Permissions can't be removed from the content process. Send a message
|
|
|
|
|
// to the parent; `ContentParent::RecvDisableNotifications` will call
|
|
|
|
|
// `RemovePermission`.
|
|
|
|
|
ContentChild::GetSingleton()->SendDisableNotifications(
|
|
|
|
|
IPC::Principal(mPrincipal));
|
2015-09-25 23:18:28 +03:00
|
|
|
|
return NS_OK;
|
2015-09-25 23:18:29 +03:00
|
|
|
|
} else if (!strcmp("alertsettingscallback", aTopic)) {
|
2015-10-23 00:20:51 +03:00
|
|
|
|
if (XRE_IsParentProcess()) {
|
|
|
|
|
return Notification::OpenSettings(mPrincipal);
|
2015-09-25 23:18:29 +03:00
|
|
|
|
}
|
2015-10-23 00:20:51 +03:00
|
|
|
|
// `ContentParent::RecvOpenNotificationSettings` notifies observers in the
|
|
|
|
|
// parent process.
|
|
|
|
|
ContentChild::GetSingleton()->SendOpenNotificationSettings(
|
|
|
|
|
IPC::Principal(mPrincipal));
|
2015-09-25 23:18:29 +03:00
|
|
|
|
return NS_OK;
|
2015-09-25 23:18:28 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return mObserver->Observe(aSubject, aTopic, aData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
MainThreadNotificationObserver::Observe(nsISupports* aSubject, const char* aTopic,
|
|
|
|
|
const char16_t* aData)
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnMainThread();
|
2015-06-26 04:53:02 +03:00
|
|
|
|
MOZ_ASSERT(mNotificationRef);
|
|
|
|
|
Notification* notification = mNotificationRef->GetNotification();
|
|
|
|
|
MOZ_ASSERT(notification);
|
|
|
|
|
if (!strcmp("alertclickcallback", aTopic)) {
|
|
|
|
|
nsCOMPtr<nsPIDOMWindow> window = notification->GetOwner();
|
2015-06-26 04:53:02 +03:00
|
|
|
|
if (NS_WARN_IF(!window || !window->IsCurrentInnerWindow())) {
|
2015-06-26 04:53:02 +03:00
|
|
|
|
// Window has been closed, this observer is not valid anymore
|
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool doDefaultAction = notification->DispatchClickEvent();
|
|
|
|
|
if (doDefaultAction) {
|
|
|
|
|
nsIDocument* doc = window ? window->GetExtantDoc() : nullptr;
|
|
|
|
|
if (doc) {
|
|
|
|
|
// Browser UI may use DOMWebNotificationClicked to focus the tab
|
|
|
|
|
// from which the event was dispatched.
|
|
|
|
|
nsContentUtils::DispatchChromeEvent(doc, window->GetOuterWindow(),
|
|
|
|
|
NS_LITERAL_STRING("DOMWebNotificationClicked"),
|
|
|
|
|
true, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (!strcmp("alertfinished", aTopic)) {
|
2015-07-13 23:45:17 +03:00
|
|
|
|
// In b2g-desktop, if the app is closed, closing a notification still
|
|
|
|
|
// triggers the observer which might be alive even though the owner window
|
|
|
|
|
// was closed. Keeping this until we remove the close event (Bug 1139363)
|
|
|
|
|
// from implementation.
|
|
|
|
|
nsCOMPtr<nsPIDOMWindow> window = notification->GetOwner();
|
|
|
|
|
if (NS_WARN_IF(!window || !window->IsCurrentInnerWindow())) {
|
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
notification->UnpersistNotification();
|
|
|
|
|
notification->mIsClosed = true;
|
|
|
|
|
notification->DispatchTrustedEvent(NS_LITERAL_STRING("close"));
|
|
|
|
|
} else if (!strcmp("alertshow", aTopic)) {
|
|
|
|
|
notification->DispatchTrustedEvent(NS_LITERAL_STRING("show"));
|
|
|
|
|
}
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
WorkerNotificationObserver::Observe(nsISupports* aSubject, const char* aTopic,
|
|
|
|
|
const char16_t* aData)
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnMainThread();
|
|
|
|
|
MOZ_ASSERT(mNotificationRef);
|
|
|
|
|
// For an explanation of why it is OK to pass this rawptr to the event
|
|
|
|
|
// runnables, see the Notification class comment.
|
|
|
|
|
Notification* notification = mNotificationRef->GetNotification();
|
|
|
|
|
// We can't assert notification here since the feature could've unset it.
|
2015-06-26 04:53:02 +03:00
|
|
|
|
if (NS_WARN_IF(!notification)) {
|
2015-06-26 04:53:02 +03:00
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MOZ_ASSERT(notification->mWorkerPrivate);
|
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<WorkerRunnable> r;
|
2015-06-26 04:53:02 +03:00
|
|
|
|
if (!strcmp("alertclickcallback", aTopic)) {
|
2015-06-26 04:50:25 +03:00
|
|
|
|
nsPIDOMWindow* window = nullptr;
|
|
|
|
|
if (!notification->mWorkerPrivate->IsServiceWorker()) {
|
|
|
|
|
WorkerPrivate* top = notification->mWorkerPrivate;
|
|
|
|
|
while (top->GetParent()) {
|
|
|
|
|
top = top->GetParent();
|
|
|
|
|
}
|
2015-06-26 04:53:02 +03:00
|
|
|
|
|
2015-06-26 04:50:25 +03:00
|
|
|
|
window = top->GetWindow();
|
|
|
|
|
if (NS_WARN_IF(!window || !window->IsCurrentInnerWindow())) {
|
|
|
|
|
// Window has been closed, this observer is not valid anymore
|
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
}
|
2015-06-26 04:53:02 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Instead of bothering with adding features and other worker lifecycle
|
|
|
|
|
// management, we simply hold strongrefs to the window and document.
|
|
|
|
|
nsMainThreadPtrHandle<nsPIDOMWindow> windowHandle(
|
|
|
|
|
new nsMainThreadPtrHolder<nsPIDOMWindow>(window));
|
|
|
|
|
|
|
|
|
|
r = new NotificationClickWorkerRunnable(notification, windowHandle);
|
|
|
|
|
} else if (!strcmp("alertfinished", aTopic)) {
|
|
|
|
|
notification->UnpersistNotification();
|
|
|
|
|
notification->mIsClosed = true;
|
|
|
|
|
r = new NotificationEventWorkerRunnable(notification,
|
|
|
|
|
NS_LITERAL_STRING("close"));
|
|
|
|
|
} else if (!strcmp("alertshow", aTopic)) {
|
|
|
|
|
r = new NotificationEventWorkerRunnable(notification,
|
|
|
|
|
NS_LITERAL_STRING("show"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MOZ_ASSERT(r);
|
|
|
|
|
AutoSafeJSContext cx;
|
|
|
|
|
if (!r->Dispatch(cx)) {
|
|
|
|
|
NS_WARNING("Could not dispatch event to worker notification");
|
|
|
|
|
}
|
|
|
|
|
return NS_OK;
|
2015-06-25 21:36:53 +03:00
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:50:25 +03:00
|
|
|
|
class NotificationClickEventCallback final : public nsINotificationStorageCallback
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
|
|
|
|
|
|
NotificationClickEventCallback(nsIPrincipal* aPrincipal,
|
|
|
|
|
const nsAString& aScope)
|
|
|
|
|
: mPrincipal(aPrincipal), mScope(aScope)
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(aPrincipal);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NS_IMETHOD Handle(const nsAString& aID,
|
|
|
|
|
const nsAString& aTitle,
|
|
|
|
|
const nsAString& aDir,
|
|
|
|
|
const nsAString& aLang,
|
|
|
|
|
const nsAString& aBody,
|
|
|
|
|
const nsAString& aTag,
|
|
|
|
|
const nsAString& aIcon,
|
|
|
|
|
const nsAString& aData,
|
|
|
|
|
const nsAString& aBehavior,
|
2015-06-26 04:50:25 +03:00
|
|
|
|
const nsAString& aServiceWorkerRegistrationID,
|
2015-06-26 04:50:25 +03:00
|
|
|
|
JSContext* aCx) override
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(!aID.IsEmpty());
|
2015-06-26 04:50:25 +03:00
|
|
|
|
MOZ_ASSERT(mScope.Equals(aServiceWorkerRegistrationID));
|
2015-06-26 04:50:25 +03:00
|
|
|
|
|
|
|
|
|
AssertIsOnMainThread();
|
|
|
|
|
|
|
|
|
|
nsAutoCString originSuffix;
|
|
|
|
|
nsresult rv = mPrincipal->GetOriginSuffix(originSuffix);
|
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nsCOMPtr<nsIServiceWorkerManager> swm =
|
|
|
|
|
mozilla::services::GetServiceWorkerManager();
|
|
|
|
|
|
|
|
|
|
if (swm) {
|
|
|
|
|
swm->SendNotificationClickEvent(originSuffix,
|
|
|
|
|
NS_ConvertUTF16toUTF8(mScope),
|
|
|
|
|
aID,
|
|
|
|
|
aTitle,
|
|
|
|
|
aDir,
|
|
|
|
|
aLang,
|
|
|
|
|
aBody,
|
|
|
|
|
aTag,
|
|
|
|
|
aIcon,
|
|
|
|
|
aData,
|
|
|
|
|
aBehavior);
|
|
|
|
|
}
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NS_IMETHOD Done(JSContext* aCx) override
|
|
|
|
|
{
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
~NotificationClickEventCallback()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nsCOMPtr<nsIPrincipal> mPrincipal;
|
|
|
|
|
nsString mScope;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS(NotificationClickEventCallback, nsINotificationStorageCallback)
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
ServiceWorkerNotificationObserver::Observe(nsISupports* aSubject,
|
|
|
|
|
const char* aTopic,
|
|
|
|
|
const char16_t* aData)
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnMainThread();
|
|
|
|
|
// Persistent notifications only care about the click event.
|
|
|
|
|
if (!strcmp("alertclickcallback", aTopic)) {
|
|
|
|
|
nsresult rv;
|
|
|
|
|
nsCOMPtr<nsINotificationStorage> notificationStorage =
|
|
|
|
|
do_GetService(NS_NOTIFICATION_STORAGE_CONTRACTID, &rv);
|
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nsCOMPtr<nsINotificationStorageCallback> callback =
|
|
|
|
|
new NotificationClickEventCallback(mPrincipal, mScope);
|
|
|
|
|
|
|
|
|
|
nsAutoString origin;
|
|
|
|
|
rv = Notification::GetOrigin(mPrincipal, origin);
|
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rv = notificationStorage->GetByID(origin, mID, callback);
|
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 02:52:40 +03:00
|
|
|
|
void
|
|
|
|
|
Notification::ShowInternal()
|
2015-06-25 21:36:53 +03:00
|
|
|
|
{
|
2015-06-26 04:53:02 +03:00
|
|
|
|
AssertIsOnMainThread();
|
|
|
|
|
MOZ_ASSERT(mTempRef, "Notification should take ownership of itself before"
|
|
|
|
|
"calling ShowInternal!");
|
|
|
|
|
// A notification can only have one observer and one call to ShowInternal.
|
|
|
|
|
MOZ_ASSERT(!mObserver);
|
|
|
|
|
|
|
|
|
|
// Transfer ownership to local scope so we can either release it at the end
|
|
|
|
|
// of this function or transfer it to the observer.
|
|
|
|
|
UniquePtr<NotificationRef> ownership;
|
|
|
|
|
mozilla::Swap(ownership, mTempRef);
|
|
|
|
|
MOZ_ASSERT(ownership->GetNotification() == this);
|
|
|
|
|
|
2015-06-26 04:50:24 +03:00
|
|
|
|
nsresult rv = PersistNotification();
|
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
|
NS_WARNING("Could not persist Notification");
|
2015-06-26 04:53:02 +03:00
|
|
|
|
}
|
|
|
|
|
|
2013-03-18 17:24:54 +04:00
|
|
|
|
nsCOMPtr<nsIAlertsService> alertService =
|
|
|
|
|
do_GetService(NS_ALERTSERVICE_CONTRACTID);
|
|
|
|
|
|
|
|
|
|
ErrorResult result;
|
2015-06-26 04:53:02 +03:00
|
|
|
|
NotificationPermission permission = NotificationPermission::Denied;
|
|
|
|
|
if (mWorkerPrivate) {
|
|
|
|
|
permission = GetPermissionInternal(mWorkerPrivate->GetPrincipal(), result);
|
|
|
|
|
} else {
|
|
|
|
|
permission = GetPermissionInternal(GetOwner(), result);
|
|
|
|
|
}
|
|
|
|
|
if (permission != NotificationPermission::Granted || !alertService) {
|
|
|
|
|
if (mWorkerPrivate) {
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<NotificationEventWorkerRunnable> r =
|
2015-06-26 04:53:02 +03:00
|
|
|
|
new NotificationEventWorkerRunnable(this,
|
|
|
|
|
NS_LITERAL_STRING("error"));
|
|
|
|
|
AutoSafeJSContext cx;
|
|
|
|
|
if (!r->Dispatch(cx)) {
|
|
|
|
|
NS_WARNING("Could not dispatch event to worker notification");
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
DispatchTrustedEvent(NS_LITERAL_STRING("error"));
|
|
|
|
|
}
|
2013-10-03 05:27:53 +04:00
|
|
|
|
return;
|
2013-03-18 17:24:54 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
nsAutoString iconUrl;
|
2014-09-17 01:12:00 +04:00
|
|
|
|
nsAutoString soundUrl;
|
2015-06-26 04:53:02 +03:00
|
|
|
|
ResolveIconAndSoundURL(iconUrl, soundUrl);
|
|
|
|
|
|
|
|
|
|
nsCOMPtr<nsIObserver> observer;
|
2015-06-26 04:50:25 +03:00
|
|
|
|
if (mScope.IsEmpty()) {
|
|
|
|
|
// Ownership passed to observer.
|
|
|
|
|
if (mWorkerPrivate) {
|
|
|
|
|
// Scope better be set on ServiceWorker initiated requests.
|
|
|
|
|
MOZ_ASSERT(!mWorkerPrivate->IsServiceWorker());
|
|
|
|
|
// Keep a pointer so that the feature can tell the observer not to release
|
|
|
|
|
// the notification.
|
|
|
|
|
mObserver = new WorkerNotificationObserver(Move(ownership));
|
|
|
|
|
observer = mObserver;
|
|
|
|
|
} else {
|
2015-09-25 23:18:28 +03:00
|
|
|
|
observer = new MainThreadNotificationObserver(Move(ownership));
|
2015-06-26 04:50:25 +03:00
|
|
|
|
}
|
2015-06-26 04:53:02 +03:00
|
|
|
|
} else {
|
2015-06-26 04:50:25 +03:00
|
|
|
|
// This observer does not care about the Notification. It will be released
|
|
|
|
|
// at the end of this function.
|
|
|
|
|
//
|
2015-09-25 23:18:28 +03:00
|
|
|
|
// The observer is wholly owned by the NotificationObserver passed to the alert service.
|
2015-06-26 04:50:25 +03:00
|
|
|
|
observer = new ServiceWorkerNotificationObserver(mScope, GetPrincipal(), mID);
|
2013-03-18 17:24:54 +04:00
|
|
|
|
}
|
2015-06-26 04:50:25 +03:00
|
|
|
|
MOZ_ASSERT(observer);
|
2015-09-25 23:18:28 +03:00
|
|
|
|
nsCOMPtr<nsIObserver> alertObserver = new NotificationObserver(observer,
|
|
|
|
|
GetPrincipal());
|
|
|
|
|
|
2015-06-26 02:52:40 +03:00
|
|
|
|
|
2013-09-10 18:49:09 +04:00
|
|
|
|
#ifdef MOZ_B2G
|
|
|
|
|
nsCOMPtr<nsIAppNotificationService> appNotifier =
|
|
|
|
|
do_GetService("@mozilla.org/system-alerts-service;1");
|
|
|
|
|
if (appNotifier) {
|
2015-06-26 04:53:02 +03:00
|
|
|
|
uint32_t appId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
|
|
|
|
|
if (mWorkerPrivate) {
|
|
|
|
|
appId = mWorkerPrivate->GetPrincipal()->GetAppId();
|
|
|
|
|
} else {
|
|
|
|
|
nsCOMPtr<nsPIDOMWindow> window = GetOwner();
|
|
|
|
|
appId = (window.get())->GetDoc()->NodePrincipal()->GetAppId();
|
|
|
|
|
}
|
2013-09-10 18:49:09 +04:00
|
|
|
|
|
|
|
|
|
if (appId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
|
|
|
|
|
nsCOMPtr<nsIAppsService> appsService = do_GetService("@mozilla.org/AppsService;1");
|
|
|
|
|
nsString manifestUrl = EmptyString();
|
2015-06-26 04:53:02 +03:00
|
|
|
|
nsresult rv = appsService->GetManifestURLByLocalId(appId, manifestUrl);
|
2013-10-03 05:27:53 +04:00
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
|
mozilla::AutoSafeJSContext cx;
|
2013-11-11 12:04:41 +04:00
|
|
|
|
JS::Rooted<JS::Value> val(cx);
|
2013-10-03 05:27:53 +04:00
|
|
|
|
AppNotificationServiceOptions ops;
|
|
|
|
|
ops.mTextClickable = true;
|
|
|
|
|
ops.mManifestURL = manifestUrl;
|
2015-06-26 04:50:24 +03:00
|
|
|
|
GetAlertName(ops.mId);
|
2014-03-18 20:01:13 +04:00
|
|
|
|
ops.mDbId = mID;
|
2013-10-03 05:27:53 +04:00
|
|
|
|
ops.mDir = DirectionToString(mDir);
|
|
|
|
|
ops.mLang = mLang;
|
2014-01-09 19:55:44 +04:00
|
|
|
|
ops.mTag = mTag;
|
2015-07-30 22:44:14 +03:00
|
|
|
|
ops.mData = mDataAsBase64;
|
2014-09-17 01:12:00 +04:00
|
|
|
|
ops.mMozbehavior = mBehavior;
|
|
|
|
|
ops.mMozbehavior.mSoundFile = soundUrl;
|
2013-10-03 05:27:53 +04:00
|
|
|
|
|
2014-06-11 23:38:55 +04:00
|
|
|
|
if (!ToJSValue(cx, ops, &val)) {
|
2013-10-03 05:27:53 +04:00
|
|
|
|
NS_WARNING("Converting dict to object failed!");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
appNotifier->ShowAppNotification(iconUrl, mTitle, mBody,
|
2015-09-25 23:18:28 +03:00
|
|
|
|
alertObserver, val);
|
2013-10-03 05:27:53 +04:00
|
|
|
|
return;
|
2013-10-11 22:12:13 +04:00
|
|
|
|
}
|
2013-09-10 18:49:09 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2013-03-18 17:24:54 +04:00
|
|
|
|
// In the case of IPC, the parent process uses the cookie to map to
|
|
|
|
|
// nsIObserver. Thus the cookie must be unique to differentiate observers.
|
|
|
|
|
nsString uniqueCookie = NS_LITERAL_STRING("notification:");
|
|
|
|
|
uniqueCookie.AppendInt(sCount++);
|
2015-06-26 04:53:02 +03:00
|
|
|
|
//XXXnsm Should this default to true?
|
2014-11-28 22:08:29 +03:00
|
|
|
|
bool inPrivateBrowsing = false;
|
2015-06-26 04:53:02 +03:00
|
|
|
|
nsIDocument* doc = mWorkerPrivate ? mWorkerPrivate->GetDocument()
|
|
|
|
|
: GetOwner()->GetExtantDoc();
|
2014-11-28 22:08:29 +03:00
|
|
|
|
if (doc) {
|
|
|
|
|
nsCOMPtr<nsILoadContext> loadContext = doc->GetLoadContext();
|
|
|
|
|
inPrivateBrowsing = loadContext && loadContext->UsePrivateBrowsing();
|
2015-06-26 04:53:02 +03:00
|
|
|
|
} else if (mWorkerPrivate) {
|
|
|
|
|
// Not all workers may have a document, but with Bug 1107516 fixed, they
|
|
|
|
|
// should all have a loadcontext.
|
|
|
|
|
nsCOMPtr<nsILoadGroup> loadGroup = mWorkerPrivate->GetLoadGroup();
|
|
|
|
|
nsCOMPtr<nsILoadContext> loadContext;
|
|
|
|
|
NS_QueryNotificationCallbacks(nullptr, loadGroup, NS_GET_IID(nsILoadContext),
|
|
|
|
|
getter_AddRefs(loadContext));
|
|
|
|
|
inPrivateBrowsing = loadContext && loadContext->UsePrivateBrowsing();
|
2014-11-28 22:08:29 +03:00
|
|
|
|
}
|
2015-06-26 04:50:24 +03:00
|
|
|
|
|
|
|
|
|
nsAutoString alertName;
|
|
|
|
|
GetAlertName(alertName);
|
2015-06-26 04:53:02 +03:00
|
|
|
|
alertService->ShowAlertNotification(iconUrl, mTitle, mBody, true,
|
2015-09-25 23:18:28 +03:00
|
|
|
|
uniqueCookie, alertObserver, alertName,
|
2013-11-12 03:56:21 +04:00
|
|
|
|
DirectionToString(mDir), mLang,
|
2015-07-30 22:44:14 +03:00
|
|
|
|
mDataAsBase64, GetPrincipal(),
|
2014-11-28 22:08:29 +03:00
|
|
|
|
inPrivateBrowsing);
|
2013-03-18 17:24:54 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
/* static */ bool
|
|
|
|
|
Notification::RequestPermissionEnabledForScope(JSContext* aCx, JSObject* /* unused */)
|
|
|
|
|
{
|
|
|
|
|
// requestPermission() is not allowed on workers. The calling page should ask
|
|
|
|
|
// for permission on the worker's behalf. This is to prevent 'which window
|
|
|
|
|
// should show the browser pop-up'. See discussion:
|
|
|
|
|
// http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2013-October/041272.html
|
|
|
|
|
return NS_IsMainThread();
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-18 17:24:54 +04:00
|
|
|
|
void
|
|
|
|
|
Notification::RequestPermission(const GlobalObject& aGlobal,
|
|
|
|
|
const Optional<OwningNonNull<NotificationPermissionCallback> >& aCallback,
|
|
|
|
|
ErrorResult& aRv)
|
|
|
|
|
{
|
|
|
|
|
// Get principal from global to make permission request for notifications.
|
2013-08-23 09:17:08 +04:00
|
|
|
|
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
|
|
|
|
|
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aGlobal.GetAsSupports());
|
2013-03-18 17:24:54 +04:00
|
|
|
|
if (!sop) {
|
|
|
|
|
aRv.Throw(NS_ERROR_UNEXPECTED);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
|
|
|
|
|
|
|
|
|
|
NotificationPermissionCallback* permissionCallback = nullptr;
|
|
|
|
|
if (aCallback.WasPassed()) {
|
2013-06-19 22:48:43 +04:00
|
|
|
|
permissionCallback = &aCallback.Value();
|
2013-03-18 17:24:54 +04:00
|
|
|
|
}
|
|
|
|
|
nsCOMPtr<nsIRunnable> request =
|
|
|
|
|
new NotificationPermissionRequest(principal, window, permissionCallback);
|
|
|
|
|
|
|
|
|
|
NS_DispatchToMainThread(request);
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:50:24 +03:00
|
|
|
|
// static
|
2013-03-18 17:24:54 +04:00
|
|
|
|
NotificationPermission
|
|
|
|
|
Notification::GetPermission(const GlobalObject& aGlobal, ErrorResult& aRv)
|
2015-06-26 04:50:24 +03:00
|
|
|
|
{
|
|
|
|
|
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
|
|
|
|
return GetPermission(global, aRv);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// static
|
|
|
|
|
NotificationPermission
|
|
|
|
|
Notification::GetPermission(nsIGlobalObject* aGlobal, ErrorResult& aRv)
|
2015-05-06 23:52:41 +03:00
|
|
|
|
{
|
2015-06-26 04:53:02 +03:00
|
|
|
|
if (NS_IsMainThread()) {
|
2015-06-26 04:50:24 +03:00
|
|
|
|
return GetPermissionInternal(aGlobal, aRv);
|
2015-06-26 04:53:02 +03:00
|
|
|
|
} else {
|
|
|
|
|
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
|
|
|
|
MOZ_ASSERT(worker);
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<GetPermissionRunnable> r =
|
2015-06-26 04:53:02 +03:00
|
|
|
|
new GetPermissionRunnable(worker);
|
|
|
|
|
if (!r->Dispatch(worker->GetJSContext())) {
|
|
|
|
|
aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
|
|
|
|
|
return NotificationPermission::Denied;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return r->GetPermission();
|
|
|
|
|
}
|
2015-05-06 23:52:41 +03:00
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
/* static */ NotificationPermission
|
2013-03-18 17:24:54 +04:00
|
|
|
|
Notification::GetPermissionInternal(nsISupports* aGlobal, ErrorResult& aRv)
|
|
|
|
|
{
|
|
|
|
|
// Get principal from global to check permission for notifications.
|
|
|
|
|
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aGlobal);
|
|
|
|
|
if (!sop) {
|
|
|
|
|
aRv.Throw(NS_ERROR_UNEXPECTED);
|
2013-05-06 23:28:13 +04:00
|
|
|
|
return NotificationPermission::Denied;
|
2013-03-18 17:24:54 +04:00
|
|
|
|
}
|
|
|
|
|
|
2013-05-24 02:38:00 +04:00
|
|
|
|
nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
|
2015-06-26 04:53:02 +03:00
|
|
|
|
return GetPermissionInternal(principal, aRv);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* static */ NotificationPermission
|
|
|
|
|
Notification::GetPermissionInternal(nsIPrincipal* aPrincipal,
|
|
|
|
|
ErrorResult& aRv)
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnMainThread();
|
|
|
|
|
MOZ_ASSERT(aPrincipal);
|
|
|
|
|
|
|
|
|
|
if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
|
2013-05-06 23:28:13 +04:00
|
|
|
|
return NotificationPermission::Granted;
|
2013-05-24 02:38:00 +04:00
|
|
|
|
} else {
|
|
|
|
|
// Allow files to show notifications by default.
|
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
2015-06-26 04:53:02 +03:00
|
|
|
|
aPrincipal->GetURI(getter_AddRefs(uri));
|
2013-05-24 02:38:00 +04:00
|
|
|
|
if (uri) {
|
|
|
|
|
bool isFile;
|
|
|
|
|
uri->SchemeIs("file", &isFile);
|
|
|
|
|
if (isFile) {
|
|
|
|
|
return NotificationPermission::Granted;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-07-12 19:45:38 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We also allow notifications is they are pref'ed on.
|
|
|
|
|
if (Preferences::GetBool("notification.prompt.testing", false)) {
|
|
|
|
|
if (Preferences::GetBool("notification.prompt.testing.allow", true)) {
|
2013-05-06 23:28:13 +04:00
|
|
|
|
return NotificationPermission::Granted;
|
2012-07-12 19:45:38 +04:00
|
|
|
|
} else {
|
2013-05-06 23:28:13 +04:00
|
|
|
|
return NotificationPermission::Denied;
|
2012-07-12 19:45:38 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-18 17:24:54 +04:00
|
|
|
|
uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION;
|
|
|
|
|
|
2013-08-16 00:15:07 +04:00
|
|
|
|
nsCOMPtr<nsIPermissionManager> permissionManager =
|
2014-04-29 21:27:26 +04:00
|
|
|
|
services::GetPermissionManager();
|
2013-03-18 17:24:54 +04:00
|
|
|
|
|
2015-10-06 02:39:34 +03:00
|
|
|
|
permissionManager->TestExactPermissionFromPrincipal(aPrincipal,
|
|
|
|
|
"desktop-notification",
|
|
|
|
|
&permission);
|
2013-03-18 17:24:54 +04:00
|
|
|
|
|
|
|
|
|
// Convert the result to one of the enum types.
|
|
|
|
|
switch (permission) {
|
|
|
|
|
case nsIPermissionManager::ALLOW_ACTION:
|
2013-05-06 23:28:13 +04:00
|
|
|
|
return NotificationPermission::Granted;
|
2013-03-18 17:24:54 +04:00
|
|
|
|
case nsIPermissionManager::DENY_ACTION:
|
2013-05-06 23:28:13 +04:00
|
|
|
|
return NotificationPermission::Denied;
|
2013-03-18 17:24:54 +04:00
|
|
|
|
default:
|
2013-05-06 23:28:13 +04:00
|
|
|
|
return NotificationPermission::Default;
|
2013-03-18 17:24:54 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
nsresult
|
|
|
|
|
Notification::ResolveIconAndSoundURL(nsString& iconUrl, nsString& soundUrl)
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnMainThread();
|
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
|
|
|
|
|
nsCOMPtr<nsIURI> baseUri;
|
|
|
|
|
|
|
|
|
|
// XXXnsm If I understand correctly, the character encoding for resolving
|
|
|
|
|
// URIs in new specs is dictated by the URL spec, which states that unless
|
|
|
|
|
// the URL parser is passed an override encoding, the charset to be used is
|
|
|
|
|
// UTF-8. The new Notification icon/sound specification just says to use the
|
|
|
|
|
// Fetch API, where the Request constructor defers to URL parsing specifying
|
|
|
|
|
// the API base URL and no override encoding. So we've to use UTF-8 on
|
|
|
|
|
// workers, but for backwards compat keeping it document charset on main
|
|
|
|
|
// thread.
|
|
|
|
|
const char* charset = "UTF-8";
|
|
|
|
|
|
|
|
|
|
if (mWorkerPrivate) {
|
|
|
|
|
baseUri = mWorkerPrivate->GetBaseURI();
|
|
|
|
|
} else {
|
|
|
|
|
nsIDocument* doc = GetOwner()->GetExtantDoc();
|
|
|
|
|
if (doc) {
|
|
|
|
|
baseUri = doc->GetBaseURI();
|
|
|
|
|
charset = doc->GetDocumentCharacterSet().get();
|
|
|
|
|
} else {
|
|
|
|
|
NS_WARNING("No document found for main thread notification!");
|
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (baseUri) {
|
|
|
|
|
if (mIconUrl.Length() > 0) {
|
|
|
|
|
nsCOMPtr<nsIURI> srcUri;
|
|
|
|
|
rv = NS_NewURI(getter_AddRefs(srcUri), mIconUrl, charset, baseUri);
|
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
|
nsAutoCString src;
|
|
|
|
|
srcUri->GetSpec(src);
|
|
|
|
|
iconUrl = NS_ConvertUTF8toUTF16(src);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (mBehavior.mSoundFile.Length() > 0) {
|
|
|
|
|
nsCOMPtr<nsIURI> srcUri;
|
|
|
|
|
rv = NS_NewURI(getter_AddRefs(srcUri), mBehavior.mSoundFile, charset, baseUri);
|
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
|
nsAutoCString src;
|
|
|
|
|
srcUri->GetSpec(src);
|
|
|
|
|
soundUrl = NS_ConvertUTF8toUTF16(src);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-03 05:27:53 +04:00
|
|
|
|
already_AddRefed<Promise>
|
2015-06-26 04:50:25 +03:00
|
|
|
|
Notification::Get(nsPIDOMWindow* aWindow,
|
2013-10-03 05:27:53 +04:00
|
|
|
|
const GetNotificationOptions& aFilter,
|
2015-06-26 04:50:25 +03:00
|
|
|
|
const nsAString& aScope,
|
2013-10-03 05:27:53 +04:00
|
|
|
|
ErrorResult& aRv)
|
|
|
|
|
{
|
2015-06-26 04:50:25 +03:00
|
|
|
|
MOZ_ASSERT(aWindow);
|
2015-06-26 04:50:24 +03:00
|
|
|
|
|
2015-06-26 04:50:25 +03:00
|
|
|
|
nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
|
2013-10-03 05:27:53 +04:00
|
|
|
|
if (!doc) {
|
|
|
|
|
aRv.Throw(NS_ERROR_UNEXPECTED);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nsString origin;
|
2015-06-26 04:50:24 +03:00
|
|
|
|
aRv = GetOrigin(doc->NodePrincipal(), origin);
|
2013-10-03 05:27:53 +04:00
|
|
|
|
if (aRv.Failed()) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:50:25 +03:00
|
|
|
|
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aWindow);
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<Promise> promise = Promise::Create(global, aRv);
|
2014-07-19 05:31:11 +04:00
|
|
|
|
if (aRv.Failed()) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
2015-06-26 04:50:24 +03:00
|
|
|
|
|
2013-10-03 05:27:53 +04:00
|
|
|
|
nsCOMPtr<nsINotificationStorageCallback> callback =
|
2015-06-26 04:50:25 +03:00
|
|
|
|
new NotificationStorageCallback(global, aScope, promise);
|
2015-06-26 04:50:24 +03:00
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<NotificationGetRunnable> r =
|
2015-06-26 04:50:24 +03:00
|
|
|
|
new NotificationGetRunnable(origin, aFilter.mTag, callback);
|
|
|
|
|
|
|
|
|
|
aRv = NS_DispatchToMainThread(r);
|
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
2013-10-03 05:27:53 +04:00
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return promise.forget();
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:50:25 +03:00
|
|
|
|
already_AddRefed<Promise>
|
|
|
|
|
Notification::Get(const GlobalObject& aGlobal,
|
|
|
|
|
const GetNotificationOptions& aFilter,
|
|
|
|
|
ErrorResult& aRv)
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnMainThread();
|
|
|
|
|
nsCOMPtr<nsIGlobalObject> global =
|
|
|
|
|
do_QueryInterface(aGlobal.GetAsSupports());
|
|
|
|
|
MOZ_ASSERT(global);
|
|
|
|
|
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(global);
|
|
|
|
|
|
|
|
|
|
return Get(window, aFilter, EmptyString(), aRv);
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:50:25 +03:00
|
|
|
|
class WorkerGetResultRunnable final : public NotificationWorkerRunnable
|
|
|
|
|
{
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<PromiseWorkerProxy> mPromiseProxy;
|
2015-06-26 04:50:25 +03:00
|
|
|
|
const nsTArray<NotificationStrings> mStrings;
|
|
|
|
|
public:
|
|
|
|
|
WorkerGetResultRunnable(WorkerPrivate* aWorkerPrivate,
|
|
|
|
|
PromiseWorkerProxy* aPromiseProxy,
|
|
|
|
|
const nsTArray<NotificationStrings>&& aStrings)
|
|
|
|
|
: NotificationWorkerRunnable(aWorkerPrivate)
|
|
|
|
|
, mPromiseProxy(aPromiseProxy)
|
|
|
|
|
, mStrings(Move(aStrings))
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
WorkerRunInternal(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
|
|
|
|
{
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<Promise> workerPromise = mPromiseProxy->WorkerPromise();
|
2015-06-26 04:50:25 +03:00
|
|
|
|
|
|
|
|
|
ErrorResult result;
|
2015-10-18 08:24:48 +03:00
|
|
|
|
nsAutoTArray<RefPtr<Notification>, 5> notifications;
|
2015-06-26 04:50:25 +03:00
|
|
|
|
for (uint32_t i = 0; i < mStrings.Length(); ++i) {
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<Notification> n =
|
2015-06-26 04:50:25 +03:00
|
|
|
|
Notification::ConstructFromFields(aWorkerPrivate->GlobalScope(),
|
|
|
|
|
mStrings[i].mID,
|
|
|
|
|
mStrings[i].mTitle,
|
|
|
|
|
mStrings[i].mDir,
|
|
|
|
|
mStrings[i].mLang,
|
|
|
|
|
mStrings[i].mBody,
|
|
|
|
|
mStrings[i].mTag,
|
|
|
|
|
mStrings[i].mIcon,
|
|
|
|
|
mStrings[i].mData,
|
|
|
|
|
/* mStrings[i].mBehavior, not
|
|
|
|
|
* supported */
|
|
|
|
|
mStrings[i].mServiceWorkerRegistrationID,
|
|
|
|
|
result);
|
|
|
|
|
|
|
|
|
|
n->SetStoredState(true);
|
2015-11-02 08:53:26 +03:00
|
|
|
|
Unused << NS_WARN_IF(result.Failed());
|
2015-06-26 04:50:25 +03:00
|
|
|
|
if (!result.Failed()) {
|
|
|
|
|
notifications.AppendElement(n.forget());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
workerPromise->MaybeResolve(notifications);
|
|
|
|
|
mPromiseProxy->CleanUp(aCx);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class WorkerGetCallback final : public ScopeCheckingGetCallback
|
|
|
|
|
{
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<PromiseWorkerProxy> mPromiseProxy;
|
2015-06-26 04:50:25 +03:00
|
|
|
|
public:
|
2015-07-30 04:56:30 +03:00
|
|
|
|
NS_DECL_ISUPPORTS
|
2015-06-26 04:50:25 +03:00
|
|
|
|
|
|
|
|
|
WorkerGetCallback(PromiseWorkerProxy* aProxy, const nsAString& aScope)
|
|
|
|
|
: ScopeCheckingGetCallback(aScope), mPromiseProxy(aProxy)
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnMainThread();
|
|
|
|
|
MOZ_ASSERT(aProxy);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NS_IMETHOD Done(JSContext* aCx) final
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnMainThread();
|
|
|
|
|
MOZ_ASSERT(mPromiseProxy, "Was Done() called twice?");
|
2015-09-02 20:07:26 +03:00
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<PromiseWorkerProxy> proxy = mPromiseProxy.forget();
|
2015-09-02 20:07:26 +03:00
|
|
|
|
MutexAutoLock lock(proxy->Lock());
|
|
|
|
|
if (proxy->CleanedUp()) {
|
2015-06-26 04:50:25 +03:00
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<WorkerGetResultRunnable> r =
|
2015-09-02 20:07:26 +03:00
|
|
|
|
new WorkerGetResultRunnable(proxy->GetWorkerPrivate(),
|
|
|
|
|
proxy,
|
2015-06-26 04:50:25 +03:00
|
|
|
|
Move(mStrings));
|
|
|
|
|
|
2015-09-02 20:07:26 +03:00
|
|
|
|
r->Dispatch(aCx);
|
2015-06-26 04:50:25 +03:00
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
~WorkerGetCallback()
|
|
|
|
|
{}
|
|
|
|
|
};
|
|
|
|
|
|
2015-07-30 04:56:30 +03:00
|
|
|
|
NS_IMPL_ISUPPORTS(WorkerGetCallback, nsINotificationStorageCallback)
|
2015-06-26 04:50:25 +03:00
|
|
|
|
|
|
|
|
|
class WorkerGetRunnable final : public nsRunnable
|
|
|
|
|
{
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<PromiseWorkerProxy> mPromiseProxy;
|
2015-06-26 04:50:25 +03:00
|
|
|
|
const nsString mTag;
|
|
|
|
|
const nsString mScope;
|
|
|
|
|
public:
|
2015-09-02 20:07:26 +03:00
|
|
|
|
WorkerGetRunnable(PromiseWorkerProxy* aProxy,
|
2015-06-26 04:50:25 +03:00
|
|
|
|
const nsAString& aTag,
|
|
|
|
|
const nsAString& aScope)
|
2015-09-02 20:07:26 +03:00
|
|
|
|
: mPromiseProxy(aProxy), mTag(aTag), mScope(aScope)
|
2015-06-26 04:50:25 +03:00
|
|
|
|
{
|
2015-09-02 20:07:26 +03:00
|
|
|
|
MOZ_ASSERT(mPromiseProxy);
|
2015-06-26 04:50:25 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NS_IMETHOD
|
|
|
|
|
Run() override
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnMainThread();
|
|
|
|
|
nsCOMPtr<nsINotificationStorageCallback> callback =
|
|
|
|
|
new WorkerGetCallback(mPromiseProxy, mScope);
|
|
|
|
|
|
|
|
|
|
AutoJSAPI jsapi;
|
|
|
|
|
jsapi.Init();
|
|
|
|
|
|
|
|
|
|
nsresult rv;
|
|
|
|
|
nsCOMPtr<nsINotificationStorage> notificationStorage =
|
|
|
|
|
do_GetService(NS_NOTIFICATION_STORAGE_CONTRACTID, &rv);
|
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
|
callback->Done(jsapi.cx());
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-02 20:07:26 +03:00
|
|
|
|
MutexAutoLock lock(mPromiseProxy->Lock());
|
|
|
|
|
if (mPromiseProxy->CleanedUp()) {
|
2015-06-26 04:50:25 +03:00
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nsString origin;
|
|
|
|
|
rv =
|
|
|
|
|
Notification::GetOrigin(mPromiseProxy->GetWorkerPrivate()->GetPrincipal(),
|
|
|
|
|
origin);
|
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
|
callback->Done(jsapi.cx());
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rv = notificationStorage->Get(origin, mTag, callback);
|
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
|
callback->Done(jsapi.cx());
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
private:
|
|
|
|
|
~WorkerGetRunnable()
|
|
|
|
|
{}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
already_AddRefed<Promise>
|
|
|
|
|
Notification::WorkerGet(WorkerPrivate* aWorkerPrivate,
|
|
|
|
|
const GetNotificationOptions& aFilter,
|
|
|
|
|
const nsAString& aScope,
|
|
|
|
|
ErrorResult& aRv)
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(aWorkerPrivate);
|
|
|
|
|
aWorkerPrivate->AssertIsOnWorkerThread();
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<Promise> p = Promise::Create(aWorkerPrivate->GlobalScope(), aRv);
|
2015-06-26 04:50:25 +03:00
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<PromiseWorkerProxy> proxy =
|
2015-09-02 20:07:26 +03:00
|
|
|
|
PromiseWorkerProxy::Create(aWorkerPrivate, p);
|
|
|
|
|
if (!proxy) {
|
2015-06-26 04:50:25 +03:00
|
|
|
|
aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<WorkerGetRunnable> r =
|
2015-09-02 20:07:26 +03:00
|
|
|
|
new WorkerGetRunnable(proxy, aFilter.mTag, aScope);
|
|
|
|
|
// Since this is called from script via
|
|
|
|
|
// ServiceWorkerRegistration::GetNotifications, we can assert dispatch.
|
|
|
|
|
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(r)));
|
2015-06-26 04:50:25 +03:00
|
|
|
|
return p.forget();
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-18 17:24:54 +04:00
|
|
|
|
JSObject*
|
Bug 1117172 part 3. Change the wrappercached WrapObject methods to allow passing in aGivenProto. r=peterv
The only manual changes here are to BindingUtils.h, BindingUtils.cpp,
Codegen.py, Element.cpp, IDBFileRequest.cpp, IDBObjectStore.cpp,
dom/workers/Navigator.cpp, WorkerPrivate.cpp, DeviceStorageRequestChild.cpp,
Notification.cpp, nsGlobalWindow.cpp, MessagePort.cpp, nsJSEnvironment.cpp,
Sandbox.cpp, XPCConvert.cpp, ExportHelpers.cpp, and DataStoreService.cpp. The
rest of this diff was generated by running the following commands:
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObject\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(Binding(?:_workers)?::Wrap\((?:aCx|cx|aContext|aCtx|js), [^,)]+)\)/\1, aGivenProto)/g'
2015-03-19 17:13:33 +03:00
|
|
|
|
Notification::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
2013-03-18 17:24:54 +04:00
|
|
|
|
{
|
Bug 1117172 part 3. Change the wrappercached WrapObject methods to allow passing in aGivenProto. r=peterv
The only manual changes here are to BindingUtils.h, BindingUtils.cpp,
Codegen.py, Element.cpp, IDBFileRequest.cpp, IDBObjectStore.cpp,
dom/workers/Navigator.cpp, WorkerPrivate.cpp, DeviceStorageRequestChild.cpp,
Notification.cpp, nsGlobalWindow.cpp, MessagePort.cpp, nsJSEnvironment.cpp,
Sandbox.cpp, XPCConvert.cpp, ExportHelpers.cpp, and DataStoreService.cpp. The
rest of this diff was generated by running the following commands:
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObject\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(Binding(?:_workers)?::Wrap\((?:aCx|cx|aContext|aCtx|js), [^,)]+)\)/\1, aGivenProto)/g'
2015-03-19 17:13:33 +03:00
|
|
|
|
return mozilla::dom::NotificationBinding::Wrap(aCx, this, aGivenProto);
|
2013-03-18 17:24:54 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Notification::Close()
|
|
|
|
|
{
|
2015-06-26 04:53:02 +03:00
|
|
|
|
AssertIsOnTargetThread();
|
|
|
|
|
auto ref = MakeUnique<NotificationRef>(this);
|
2015-06-26 04:53:02 +03:00
|
|
|
|
if (!ref->Initialized()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-06-26 04:53:02 +03:00
|
|
|
|
|
2013-12-06 03:26:04 +04:00
|
|
|
|
nsCOMPtr<nsIRunnable> closeNotificationTask =
|
2015-06-26 04:53:02 +03:00
|
|
|
|
new NotificationTask(Move(ref), NotificationTask::eClose);
|
|
|
|
|
nsresult rv = NS_DispatchToMainThread(closeNotificationTask);
|
|
|
|
|
|
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
|
DispatchTrustedEvent(NS_LITERAL_STRING("error"));
|
|
|
|
|
// If dispatch fails, NotificationTask will release the ref when it goes
|
|
|
|
|
// out of scope at the end of this function.
|
|
|
|
|
}
|
2013-03-18 17:24:54 +04:00
|
|
|
|
}
|
|
|
|
|
|
2013-10-03 05:27:53 +04:00
|
|
|
|
void
|
2013-03-18 17:24:54 +04:00
|
|
|
|
Notification::CloseInternal()
|
|
|
|
|
{
|
2015-06-26 04:50:25 +03:00
|
|
|
|
AssertIsOnMainThread();
|
2015-06-26 04:53:02 +03:00
|
|
|
|
// Transfer ownership (if any) to local scope so we can release it at the end
|
|
|
|
|
// of this function. This is relevant when the call is from
|
|
|
|
|
// NotificationTask::Run().
|
|
|
|
|
UniquePtr<NotificationRef> ownership;
|
|
|
|
|
mozilla::Swap(ownership, mTempRef);
|
|
|
|
|
|
2015-06-26 04:50:25 +03:00
|
|
|
|
SetAlertName();
|
2015-06-26 04:53:02 +03:00
|
|
|
|
UnpersistNotification();
|
2014-09-12 18:50:00 +04:00
|
|
|
|
if (!mIsClosed) {
|
2013-03-18 17:24:54 +04:00
|
|
|
|
nsCOMPtr<nsIAlertsService> alertService =
|
|
|
|
|
do_GetService(NS_ALERTSERVICE_CONTRACTID);
|
|
|
|
|
if (alertService) {
|
2015-06-26 04:50:24 +03:00
|
|
|
|
nsAutoString alertName;
|
|
|
|
|
GetAlertName(alertName);
|
|
|
|
|
alertService->CloseAlert(alertName, GetPrincipal());
|
2013-10-07 22:41:13 +04:00
|
|
|
|
}
|
2013-10-03 05:27:53 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nsresult
|
2015-06-26 04:50:24 +03:00
|
|
|
|
Notification::GetOrigin(nsIPrincipal* aPrincipal, nsString& aOrigin)
|
2013-10-03 05:27:53 +04:00
|
|
|
|
{
|
2015-09-01 22:08:36 +03:00
|
|
|
|
if (!aPrincipal) {
|
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:50:24 +03:00
|
|
|
|
uint16_t appStatus = aPrincipal->GetAppStatus();
|
|
|
|
|
uint32_t appId = aPrincipal->GetAppId();
|
2015-06-26 02:52:40 +03:00
|
|
|
|
|
2015-06-26 04:50:24 +03:00
|
|
|
|
nsresult rv;
|
2013-10-03 05:27:53 +04:00
|
|
|
|
if (appStatus == nsIPrincipal::APP_STATUS_NOT_INSTALLED ||
|
|
|
|
|
appId == nsIScriptSecurityManager::NO_APP_ID ||
|
|
|
|
|
appId == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
|
2015-06-26 04:50:24 +03:00
|
|
|
|
rv = nsContentUtils::GetUTFOrigin(aPrincipal, aOrigin);
|
2013-10-03 05:27:53 +04:00
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
} else {
|
|
|
|
|
// If we are in "app code", use manifest URL as unique origin since
|
|
|
|
|
// multiple apps can share the same origin but not same notifications.
|
|
|
|
|
nsCOMPtr<nsIAppsService> appsService =
|
|
|
|
|
do_GetService("@mozilla.org/AppsService;1", &rv);
|
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
appsService->GetManifestURLByLocalId(appId, aOrigin);
|
|
|
|
|
}
|
2013-10-07 22:41:13 +04:00
|
|
|
|
|
2013-10-03 05:27:53 +04:00
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-21 04:56:12 +04:00
|
|
|
|
void
|
|
|
|
|
Notification::GetData(JSContext* aCx,
|
|
|
|
|
JS::MutableHandle<JS::Value> aRetval)
|
|
|
|
|
{
|
2015-07-30 22:44:14 +03:00
|
|
|
|
if (mData.isNull() && !mDataAsBase64.IsEmpty()) {
|
2014-08-21 04:56:12 +04:00
|
|
|
|
nsresult rv;
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<nsStructuredCloneContainer> container =
|
2015-08-02 12:34:26 +03:00
|
|
|
|
new nsStructuredCloneContainer();
|
2015-07-30 22:44:14 +03:00
|
|
|
|
rv = container->InitFromBase64(mDataAsBase64, JS_STRUCTURED_CLONE_VERSION,
|
|
|
|
|
aCx);
|
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
|
aRetval.setNull();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JS::Rooted<JS::Value> data(aCx);
|
|
|
|
|
rv = container->DeserializeToJsval(aCx, &data);
|
2014-08-21 04:56:12 +04:00
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
|
aRetval.setNull();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-07-30 22:44:14 +03:00
|
|
|
|
|
|
|
|
|
if (data.isGCThing()) {
|
|
|
|
|
mozilla::HoldJSObjects(this);
|
|
|
|
|
}
|
|
|
|
|
mData = data;
|
2014-08-21 04:56:12 +04:00
|
|
|
|
}
|
2015-07-30 22:44:14 +03:00
|
|
|
|
if (mData.isNull()) {
|
2014-08-21 04:56:12 +04:00
|
|
|
|
aRetval.setNull();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-07-30 22:44:14 +03:00
|
|
|
|
|
|
|
|
|
JS::ExposeValueToActiveJS(mData);
|
|
|
|
|
aRetval.set(mData);
|
2014-08-21 04:56:12 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Notification::InitFromJSVal(JSContext* aCx, JS::Handle<JS::Value> aData,
|
|
|
|
|
ErrorResult& aRv)
|
|
|
|
|
{
|
2015-07-30 22:44:14 +03:00
|
|
|
|
if (!mDataAsBase64.IsEmpty() || aData.isNull()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<nsStructuredCloneContainer> dataObjectContainer =
|
2015-08-02 12:34:26 +03:00
|
|
|
|
new nsStructuredCloneContainer();
|
2015-07-30 22:44:14 +03:00
|
|
|
|
aRv = dataObjectContainer->InitFromJSVal(aData, aCx);
|
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
2014-08-21 04:56:12 +04:00
|
|
|
|
return;
|
|
|
|
|
}
|
2015-07-30 22:44:14 +03:00
|
|
|
|
|
|
|
|
|
dataObjectContainer->GetDataAsBase64(mDataAsBase64);
|
2014-08-21 04:56:12 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Notification::InitFromBase64(JSContext* aCx, const nsAString& aData,
|
|
|
|
|
ErrorResult& aRv)
|
|
|
|
|
{
|
2015-07-30 22:44:14 +03:00
|
|
|
|
if (!mDataAsBase64.IsEmpty() || aData.IsEmpty()) {
|
2014-08-21 04:56:12 +04:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-30 22:44:14 +03:00
|
|
|
|
// To and fro to ensure it is valid base64.
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<nsStructuredCloneContainer> container =
|
2015-08-02 12:34:26 +03:00
|
|
|
|
new nsStructuredCloneContainer();
|
2014-08-21 04:56:12 +04:00
|
|
|
|
aRv = container->InitFromBase64(aData, JS_STRUCTURED_CLONE_VERSION,
|
|
|
|
|
aCx);
|
2015-07-30 22:44:14 +03:00
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
container->GetDataAsBase64(mDataAsBase64);
|
2014-08-21 04:56:12 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
bool
|
2015-06-26 04:53:02 +03:00
|
|
|
|
Notification::AddRefObject()
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnTargetThread();
|
2015-06-26 04:53:02 +03:00
|
|
|
|
MOZ_ASSERT_IF(mWorkerPrivate && !mFeature, mTaskCount == 0);
|
2015-06-26 04:53:02 +03:00
|
|
|
|
MOZ_ASSERT_IF(mWorkerPrivate && mFeature, mTaskCount > 0);
|
|
|
|
|
if (mWorkerPrivate && !mFeature) {
|
2015-06-26 04:53:02 +03:00
|
|
|
|
if (!RegisterFeature()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2015-06-26 04:53:02 +03:00
|
|
|
|
}
|
2015-06-26 04:53:02 +03:00
|
|
|
|
AddRef();
|
2015-06-26 04:53:02 +03:00
|
|
|
|
++mTaskCount;
|
2015-06-26 04:53:02 +03:00
|
|
|
|
return true;
|
2015-06-26 04:53:02 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Notification::ReleaseObject()
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnTargetThread();
|
|
|
|
|
MOZ_ASSERT(mTaskCount > 0);
|
2015-06-26 04:53:02 +03:00
|
|
|
|
MOZ_ASSERT_IF(mWorkerPrivate, mFeature);
|
2015-06-26 04:53:02 +03:00
|
|
|
|
|
|
|
|
|
--mTaskCount;
|
2015-06-26 04:53:02 +03:00
|
|
|
|
if (mWorkerPrivate && mTaskCount == 0) {
|
2015-06-26 04:53:02 +03:00
|
|
|
|
UnregisterFeature();
|
|
|
|
|
}
|
|
|
|
|
Release();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NotificationFeature::NotificationFeature(Notification* aNotification)
|
|
|
|
|
: mNotification(aNotification)
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(mNotification->mWorkerPrivate);
|
|
|
|
|
mNotification->mWorkerPrivate->AssertIsOnWorkerThread();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Called from the worker, runs on main thread, blocks worker.
|
|
|
|
|
*
|
|
|
|
|
* We can freely access mNotification here because the feature supplied it and
|
|
|
|
|
* the Notification owns the feature.
|
|
|
|
|
*/
|
|
|
|
|
class CloseNotificationRunnable final
|
|
|
|
|
: public WorkerMainThreadRunnable
|
|
|
|
|
{
|
|
|
|
|
Notification* mNotification;
|
2015-07-24 20:25:00 +03:00
|
|
|
|
bool mHadObserver;
|
2015-06-26 04:53:02 +03:00
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit CloseNotificationRunnable(Notification* aNotification)
|
|
|
|
|
: WorkerMainThreadRunnable(aNotification->mWorkerPrivate)
|
|
|
|
|
, mNotification(aNotification)
|
2015-07-24 20:25:00 +03:00
|
|
|
|
, mHadObserver(false)
|
2015-06-26 04:53:02 +03:00
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
MainThreadRun() override
|
|
|
|
|
{
|
|
|
|
|
if (mNotification->mObserver) {
|
|
|
|
|
// The Notify() take's responsibility of releasing the Notification.
|
|
|
|
|
mNotification->mObserver->ForgetNotification();
|
|
|
|
|
mNotification->mObserver = nullptr;
|
2015-07-24 20:25:00 +03:00
|
|
|
|
mHadObserver = true;
|
2015-06-26 04:53:02 +03:00
|
|
|
|
}
|
|
|
|
|
mNotification->CloseInternal();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2015-07-24 20:25:00 +03:00
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
HadObserver()
|
|
|
|
|
{
|
|
|
|
|
return mHadObserver;
|
|
|
|
|
}
|
2015-06-26 04:53:02 +03:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
NotificationFeature::Notify(JSContext* aCx, Status aStatus)
|
|
|
|
|
{
|
2015-07-24 20:25:00 +03:00
|
|
|
|
if (aStatus >= Canceling) {
|
|
|
|
|
// CloseNotificationRunnable blocks the worker by pushing a sync event loop
|
|
|
|
|
// on the stack. Meanwhile, WorkerControlRunnables dispatched to the worker
|
|
|
|
|
// can still continue running. One of these is
|
|
|
|
|
// ReleaseNotificationControlRunnable that releases the notification,
|
|
|
|
|
// invalidating the notification and this feature. We hold this reference to
|
|
|
|
|
// keep the notification valid until we are done with it.
|
|
|
|
|
//
|
|
|
|
|
// An example of when the control runnable could get dispatched to the
|
|
|
|
|
// worker is if a Notification is created and the worker is immediately
|
|
|
|
|
// closed, but there is no permission to show it so that the main thread
|
|
|
|
|
// immediately drops the NotificationRef. In this case, this function blocks
|
|
|
|
|
// on the main thread, but the main thread dispatches the control runnable,
|
|
|
|
|
// invalidating mNotification.
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<Notification> kungFuDeathGrip = mNotification;
|
2015-07-24 20:25:00 +03:00
|
|
|
|
|
|
|
|
|
// Dispatched to main thread, blocks on closing the Notification.
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<CloseNotificationRunnable> r =
|
2015-07-24 20:25:00 +03:00
|
|
|
|
new CloseNotificationRunnable(mNotification);
|
|
|
|
|
r->Dispatch(aCx);
|
|
|
|
|
|
|
|
|
|
// Only call ReleaseObject() to match the observer's NotificationRef
|
|
|
|
|
// ownership (since CloseNotificationRunnable asked the observer to drop the
|
|
|
|
|
// reference to the notification).
|
|
|
|
|
if (r->HadObserver()) {
|
|
|
|
|
mNotification->ReleaseObject();
|
|
|
|
|
}
|
2015-06-26 04:53:02 +03:00
|
|
|
|
|
2015-07-24 20:25:00 +03:00
|
|
|
|
// From this point we cannot touch properties of this feature because
|
|
|
|
|
// ReleaseObject() may have led to the notification going away and the
|
|
|
|
|
// notification owns this feature!
|
|
|
|
|
}
|
2015-06-26 04:53:02 +03:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:53:02 +03:00
|
|
|
|
bool
|
2015-06-26 04:53:02 +03:00
|
|
|
|
Notification::RegisterFeature()
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(mWorkerPrivate);
|
|
|
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
|
|
|
MOZ_ASSERT(!mFeature);
|
|
|
|
|
mFeature = MakeUnique<NotificationFeature>(this);
|
2015-07-24 20:25:00 +03:00
|
|
|
|
bool added = mWorkerPrivate->AddFeature(mWorkerPrivate->GetJSContext(),
|
|
|
|
|
mFeature.get());
|
|
|
|
|
if (!added) {
|
|
|
|
|
mFeature = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return added;
|
2015-06-26 04:53:02 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Notification::UnregisterFeature()
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(mWorkerPrivate);
|
|
|
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
|
|
|
MOZ_ASSERT(mFeature);
|
|
|
|
|
mWorkerPrivate->RemoveFeature(mWorkerPrivate->GetJSContext(),
|
|
|
|
|
mFeature.get());
|
|
|
|
|
mFeature = nullptr;
|
|
|
|
|
}
|
2015-07-13 18:25:42 +03:00
|
|
|
|
|
2015-06-26 04:50:24 +03:00
|
|
|
|
/*
|
|
|
|
|
* Checks:
|
|
|
|
|
* 1) Is aWorker allowed to show a notification for scope?
|
|
|
|
|
* 2) Is aWorker an active worker?
|
|
|
|
|
*
|
|
|
|
|
* If it is not an active worker, Result() will be NS_ERROR_NOT_AVAILABLE.
|
|
|
|
|
*/
|
|
|
|
|
class CheckLoadRunnable final : public WorkerMainThreadRunnable
|
|
|
|
|
{
|
|
|
|
|
nsresult mRv;
|
|
|
|
|
nsCString mScope;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit CheckLoadRunnable(WorkerPrivate* aWorker, const nsACString& aScope)
|
|
|
|
|
: WorkerMainThreadRunnable(aWorker)
|
|
|
|
|
, mRv(NS_ERROR_DOM_SECURITY_ERR)
|
|
|
|
|
, mScope(aScope)
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
MainThreadRun() override
|
|
|
|
|
{
|
|
|
|
|
nsIPrincipal* principal = mWorkerPrivate->GetPrincipal();
|
|
|
|
|
mRv = CheckScope(principal, mScope);
|
|
|
|
|
|
|
|
|
|
if (NS_FAILED(mRv)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
|
|
|
|
|
RefPtr<ServiceWorkerRegistrationInfo> registration =
|
2015-06-26 04:50:24 +03:00
|
|
|
|
swm->GetRegistration(principal, mScope);
|
|
|
|
|
|
|
|
|
|
// This is coming from a ServiceWorkerRegistrationWorkerThread.
|
|
|
|
|
MOZ_ASSERT(registration);
|
|
|
|
|
|
|
|
|
|
if (!registration->mActiveWorker ||
|
|
|
|
|
registration->mActiveWorker->ID() != mWorkerPrivate->ServiceWorkerID()) {
|
|
|
|
|
mRv = NS_ERROR_NOT_AVAILABLE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
|
Result()
|
|
|
|
|
{
|
|
|
|
|
return mRv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
|
already_AddRefed<Promise>
|
|
|
|
|
Notification::ShowPersistentNotification(nsIGlobalObject *aGlobal,
|
|
|
|
|
const nsAString& aScope,
|
|
|
|
|
const nsAString& aTitle,
|
|
|
|
|
const NotificationOptions& aOptions,
|
|
|
|
|
ErrorResult& aRv)
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(aGlobal);
|
|
|
|
|
|
|
|
|
|
// Validate scope.
|
|
|
|
|
// XXXnsm: This may be slow due to blocking the worker and waiting on the main
|
|
|
|
|
// thread. On calls from content, we can be sure the scope is valid since
|
|
|
|
|
// ServiceWorkerRegistrations have their scope set correctly. Can this be made
|
|
|
|
|
// debug only? The problem is that there would be different semantics in
|
|
|
|
|
// debug and non-debug builds in such a case.
|
|
|
|
|
if (NS_IsMainThread()) {
|
|
|
|
|
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aGlobal);
|
|
|
|
|
if (NS_WARN_IF(!sop)) {
|
|
|
|
|
aRv.Throw(NS_ERROR_UNEXPECTED);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nsIPrincipal* principal = sop->GetPrincipal();
|
|
|
|
|
if (NS_WARN_IF(!principal)) {
|
|
|
|
|
aRv.Throw(NS_ERROR_UNEXPECTED);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
aRv = CheckScope(principal, NS_ConvertUTF16toUTF8(aScope));
|
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
|
|
|
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
|
|
|
|
MOZ_ASSERT(worker);
|
|
|
|
|
worker->AssertIsOnWorkerThread();
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<CheckLoadRunnable> loadChecker =
|
2015-06-26 04:50:24 +03:00
|
|
|
|
new CheckLoadRunnable(worker, NS_ConvertUTF16toUTF8(aScope));
|
|
|
|
|
if (!loadChecker->Dispatch(worker->GetJSContext())) {
|
|
|
|
|
aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (NS_WARN_IF(NS_FAILED(loadChecker->Result()))) {
|
|
|
|
|
if (loadChecker->Result() == NS_ERROR_NOT_AVAILABLE) {
|
2015-08-21 08:18:49 +03:00
|
|
|
|
nsAutoString scope(aScope);
|
2015-10-05 19:38:14 +03:00
|
|
|
|
aRv.ThrowTypeError<MSG_NO_ACTIVE_WORKER>(&scope);
|
2015-06-26 04:50:24 +03:00
|
|
|
|
} else {
|
|
|
|
|
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<Promise> p = Promise::Create(aGlobal, aRv);
|
2015-06-26 04:50:24 +03:00
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We check permission here rather than pass the Promise to NotificationTask
|
|
|
|
|
// which leads to uglier code.
|
|
|
|
|
NotificationPermission permission = GetPermission(aGlobal, aRv);
|
|
|
|
|
|
|
|
|
|
// "If permission for notification’s origin is not "granted", reject promise with a TypeError exception, and terminate these substeps."
|
|
|
|
|
if (NS_WARN_IF(aRv.Failed()) || permission == NotificationPermission::Denied) {
|
|
|
|
|
ErrorResult result;
|
2015-10-05 19:38:14 +03:00
|
|
|
|
result.ThrowTypeError<MSG_NOTIFICATION_PERMISSION_DENIED>();
|
2015-06-26 04:50:24 +03:00
|
|
|
|
p->MaybeReject(result);
|
|
|
|
|
return p.forget();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// "Otherwise, resolve promise with undefined."
|
|
|
|
|
// The Notification may still not be shown due to other errors, but the spec
|
|
|
|
|
// is not concerned with those.
|
|
|
|
|
p->MaybeResolve(JS::UndefinedHandleValue);
|
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<Notification> notification =
|
2015-06-26 04:50:25 +03:00
|
|
|
|
CreateAndShow(aGlobal, aTitle, aOptions, aScope, aRv);
|
2015-06-26 04:50:24 +03:00
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return p.forget();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* static */ already_AddRefed<Notification>
|
|
|
|
|
Notification::CreateAndShow(nsIGlobalObject* aGlobal,
|
|
|
|
|
const nsAString& aTitle,
|
|
|
|
|
const NotificationOptions& aOptions,
|
2015-06-26 04:50:25 +03:00
|
|
|
|
const nsAString& aScope,
|
2015-06-26 04:50:24 +03:00
|
|
|
|
ErrorResult& aRv)
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(aGlobal);
|
|
|
|
|
|
|
|
|
|
AutoJSAPI jsapi;
|
|
|
|
|
jsapi.Init(aGlobal);
|
|
|
|
|
JSContext* cx = jsapi.cx();
|
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<Notification> notification = CreateInternal(aGlobal, EmptyString(),
|
2015-06-26 04:50:25 +03:00
|
|
|
|
aTitle, aOptions);
|
2015-06-26 04:50:24 +03:00
|
|
|
|
|
|
|
|
|
// Make a structured clone of the aOptions.mData object
|
|
|
|
|
JS::Rooted<JS::Value> data(cx, aOptions.mData);
|
|
|
|
|
notification->InitFromJSVal(cx, data, aRv);
|
2015-07-24 20:25:00 +03:00
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
2015-06-26 04:50:24 +03:00
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 04:50:25 +03:00
|
|
|
|
notification->SetScope(aScope);
|
|
|
|
|
|
2015-06-26 04:50:24 +03:00
|
|
|
|
auto ref = MakeUnique<NotificationRef>(notification);
|
2015-07-24 20:25:00 +03:00
|
|
|
|
if (NS_WARN_IF(!ref->Initialized())) {
|
2015-06-26 04:50:24 +03:00
|
|
|
|
aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Queue a task to show the notification.
|
|
|
|
|
nsCOMPtr<nsIRunnable> showNotificationTask =
|
|
|
|
|
new NotificationTask(Move(ref), NotificationTask::eShow);
|
|
|
|
|
nsresult rv = NS_DispatchToMainThread(showNotificationTask);
|
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
|
notification->DispatchTrustedEvent(NS_LITERAL_STRING("error"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return notification.forget();
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-23 00:10:14 +03:00
|
|
|
|
/* static */ nsresult
|
|
|
|
|
Notification::RemovePermission(nsIPrincipal* aPrincipal)
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(XRE_IsParentProcess());
|
|
|
|
|
nsCOMPtr<nsIPermissionManager> permissionManager =
|
|
|
|
|
mozilla::services::GetPermissionManager();
|
|
|
|
|
if (!permissionManager) {
|
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
permissionManager->RemoveFromPrincipal(aPrincipal, "desktop-notification");
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-23 00:20:51 +03:00
|
|
|
|
/* static */ nsresult
|
|
|
|
|
Notification::OpenSettings(nsIPrincipal* aPrincipal)
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(XRE_IsParentProcess());
|
|
|
|
|
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
|
|
|
|
if (!obs) {
|
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
// Notify other observers so they can show settings UI.
|
|
|
|
|
obs->NotifyObservers(aPrincipal, "notifications-open-settings", nullptr);
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-18 17:24:54 +04:00
|
|
|
|
} // namespace dom
|
|
|
|
|
} // namespace mozilla
|
|
|
|
|
|