--- a/dom/base/nsContentPermissionHelper.cpp
+++ b/dom/base/nsContentPermissionHelper.cpp
@@ -13,16 +13,17 @@
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/PContentPermission.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#include "mozilla/dom/PContentPermissionRequestParent.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/TabChild.h"
#include "mozilla/dom/TabParent.h"
+#include "mozilla/EventStateManager.h"
#include "mozilla/Unused.h"
#include "nsComponentManagerUtils.h"
#include "nsArrayUtils.h"
#include "nsIMutableArray.h"
#include "nsContentPermissionHelper.h"
#include "nsJSUtils.h"
#include "nsISupportsPrimitives.h"
#include "nsServiceManagerUtils.h"
@@ -123,43 +124,47 @@ VisibilityChangeListener::GetCallback()
namespace mozilla {
namespace dom {
class ContentPermissionRequestParent : public PContentPermissionRequestParent
{
public:
ContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
- Element* element,
- const IPC::Principal& principal);
+ Element* aElement,
+ const IPC::Principal& aPrincipal,
+ const bool aIsHandlingUserInput);
virtual ~ContentPermissionRequestParent();
bool IsBeingDestroyed();
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<Element> mElement;
+ bool mIsHandlingUserInput;
RefPtr<nsContentPermissionRequestProxy> mProxy;
nsTArray<PermissionRequest> mRequests;
private:
virtual mozilla::ipc::IPCResult Recvprompt();
virtual mozilla::ipc::IPCResult RecvNotifyVisibility(const bool& aIsVisible);
virtual mozilla::ipc::IPCResult RecvDestroy();
virtual void ActorDestroy(ActorDestroyReason why);
};
ContentPermissionRequestParent::ContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
Element* aElement,
- const IPC::Principal& aPrincipal)
+ const IPC::Principal& aPrincipal,
+ const bool aIsHandlingUserInput)
{
MOZ_COUNT_CTOR(ContentPermissionRequestParent);
mPrincipal = aPrincipal;
mElement = aElement;
mRequests = aRequests;
+ mIsHandlingUserInput = aIsHandlingUserInput;
}
ContentPermissionRequestParent::~ContentPermissionRequestParent()
{
MOZ_COUNT_DTOR(ContentPermissionRequestParent);
}
mozilla::ipc::IPCResult
@@ -344,22 +349,23 @@ nsContentPermissionUtils::CreatePermissi
types->AppendElement(permType);
types.forget(aTypesArray);
return NS_OK;
}
/* static */ PContentPermissionRequestParent*
nsContentPermissionUtils::CreateContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
- Element* element,
- const IPC::Principal& principal,
+ Element* aElement,
+ const IPC::Principal& aPrincipal,
+ const bool aIsHandlingUserInput,
const TabId& aTabId)
{
PContentPermissionRequestParent* parent =
- new ContentPermissionRequestParent(aRequests, element, principal);
+ new ContentPermissionRequestParent(aRequests, aElement, aPrincipal, aIsHandlingUserInput);
ContentPermissionRequestParentMap()[parent] = aTabId;
return parent;
}
/* static */ nsresult
nsContentPermissionUtils::AskPermission(nsIContentPermissionRequest* aRequest,
nsPIDOMWindowInner* aWindow)
@@ -383,24 +389,29 @@ nsContentPermissionUtils::AskPermission(
nsTArray<PermissionRequest> permArray;
ConvertArrayToPermissionRequest(typeArray, permArray);
nsCOMPtr<nsIPrincipal> principal;
rv = aRequest->GetPrincipal(getter_AddRefs(principal));
NS_ENSURE_SUCCESS(rv, rv);
+ bool isHandlingUserInput;
+ rv = aRequest->GetIsHandlingUserInput(&isHandlingUserInput);
+ NS_ENSURE_SUCCESS(rv, rv);
+
ContentChild::GetSingleton()->SetEventTargetForActor(
req, aWindow->EventTargetFor(TaskCategory::Other));
req->IPDLAddRef();
ContentChild::GetSingleton()->SendPContentPermissionRequestConstructor(
req,
permArray,
IPC::Principal(principal),
+ isHandlingUserInput,
child->GetTabId());
ContentPermissionRequestChildMap()[req.get()] = child->GetTabId();
req->Sendprompt();
return NS_OK;
}
// for chrome process
@@ -645,16 +656,27 @@ nsContentPermissionRequestProxy::GetElem
}
nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(mParent->mElement);
elem.forget(aRequestingElement);
return NS_OK;
}
NS_IMETHODIMP
+nsContentPermissionRequestProxy::GetIsHandlingUserInput(bool* aIsHandlingUserInput)
+{
+ NS_ENSURE_ARG_POINTER(aIsHandlingUserInput);
+ if (mParent == nullptr) {
+ return NS_ERROR_FAILURE;
+ }
+ *aIsHandlingUserInput = mParent->mIsHandlingUserInput;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
nsContentPermissionRequestProxy::Cancel()
{
if (mParent == nullptr) {
return NS_ERROR_FAILURE;
}
// Don't send out the delete message when the managing protocol (PBrowser) is
// being destroyed and PContentPermissionRequest will soon be.
--- a/dom/base/nsContentPermissionHelper.h
+++ b/dom/base/nsContentPermissionHelper.h
@@ -73,18 +73,19 @@ public:
static nsresult
CreatePermissionArray(const nsACString& aType,
const nsACString& aAccess,
const nsTArray<nsString>& aOptions,
nsIArray** aTypesArray);
static PContentPermissionRequestParent*
CreateContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
- Element* element,
- const IPC::Principal& principal,
+ Element* aElement,
+ const IPC::Principal& aPrincipal,
+ const bool aIsHandlingUserInput,
const TabId& aTabId);
static nsresult
AskPermission(nsIContentPermissionRequest* aRequest,
nsPIDOMWindowInner* aWindow);
static nsTArray<PContentPermissionRequestParent*>
GetContentPermissionRequestParentById(const TabId& aTabId);
--- a/dom/base/test/chrome/chrome.ini
+++ b/dom/base/test/chrome/chrome.ini
@@ -64,15 +64,17 @@ support-files = ../file_bug357450.js
[test_bug1346936.html]
[test_cpows.xul]
[test_getElementsWithGrid.html]
[test_registerElement_content.xul]
[test_registerElement_ep.xul]
[test_domparsing.xul]
[test_fileconstructor.xul]
[test_nsITextInputProcessor.xul]
+[test_permission_isHandlingUserInput.xul]
+support-files = ../dummy.html
[test_range_getClientRectsAndTexts.html]
[test_title.xul]
support-files = file_title.xul
[test_windowroot.xul]
[test_swapFrameLoaders.xul]
[test_groupedSHistory.xul]
[test_bug1339722.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/chrome/test_permission_isHandlingUserInput.xul
@@ -0,0 +1,90 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+<!--
+ Tests that the isHandlingUserInput attribute on permission requests is set correctly.
+-->
+<window title="isHandlingUserInput test" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <iframe id="frame" src="https://example.com/chrome/dom/base/test/chrome/dummy.html" />
+ </body>
+
+ <script type="application/javascript">
+ <![CDATA[
+ let Cu = Components.utils;
+
+ Cu.import("resource://gre/modules/Integration.jsm");
+ Cu.import("resource:///modules/E10SUtils.jsm");
+
+ SimpleTest.waitForExplicitFinish();
+
+ let frame = document.getElementById("frame");
+
+ function checkPermissionRequest(permission, isHandlingUserInput) {
+ return new Promise(function(resolve) {
+ let TestIntegration = (base) => ({
+ __proto__: base,
+ createPermissionPrompt(type, request) {
+ is(type, permission, `Has correct permission type ${permission}.`);
+ is(request.isHandlingUserInput, isHandlingUserInput,
+ "The isHandlingUserInput attribute is set correctly.");
+ Integration.contentPermission.unregister(TestIntegration);
+ resolve();
+ return { prompt() {} };
+ },
+ });
+ Integration.contentPermission.register(TestIntegration);
+ });
+ }
+
+ async function runTest() {
+ // Test programmatic request for persistent storage.
+ let request = checkPermissionRequest("persistent-storage", false);
+ navigator.storage.persist();
+ await request;
+
+ // Test user-initiated request for persistent storage.
+ request = checkPermissionRequest("persistent-storage", true);
+ E10SUtils.wrapHandlingUserInput(content, true, function() {
+ navigator.storage.persist();
+ });
+ await request;
+
+ // Test programmatic request for geolocation.
+ request = checkPermissionRequest("geolocation", false);
+ navigator.geolocation.getCurrentPosition(() => {});
+ await request;
+
+ // Test user-initiated request for geolocation.
+ request = checkPermissionRequest("geolocation", true);
+ E10SUtils.wrapHandlingUserInput(content, true, function() {
+ navigator.geolocation.getCurrentPosition(() => {});
+ });
+ await request;
+
+ // Notifications need to be tested in an HTTPS frame, because
+ // chrome:// URLs are whitelisted.
+ let frameWin = frame.contentWindow;
+
+ // Test programmatic request for notifications.
+ request = checkPermissionRequest("desktop-notification", false);
+ frameWin.Notification.requestPermission();
+ await request;
+
+ // Test user-initiated request for notifications.
+ request = checkPermissionRequest("desktop-notification", true);
+ E10SUtils.wrapHandlingUserInput(content, true, function() {
+ frameWin.Notification.requestPermission();
+ });
+ await request;
+ }
+
+ frame.addEventListener("load", function() {
+ runTest().then(() => SimpleTest.finish());
+ });
+ ]]>
+ </script>
+</window>
--- a/dom/geolocation/nsGeolocation.cpp
+++ b/dom/geolocation/nsGeolocation.cpp
@@ -10,16 +10,17 @@
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/Telemetry.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Unused.h"
#include "mozilla/WeakPtr.h"
+#include "mozilla/EventStateManager.h"
#include "nsComponentManagerUtils.h"
#include "nsContentPermissionHelper.h"
#include "nsContentUtils.h"
#include "nsDOMClassInfoID.h"
#include "nsGlobalWindow.h"
#include "nsIDocument.h"
#include "nsINamed.h"
#include "nsIObserverService.h"
@@ -73,16 +74,17 @@ class nsGeolocationRequest final
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsGeolocationRequest, nsIContentPermissionRequest)
nsGeolocationRequest(Geolocation* aLocator,
GeoPositionCallback aCallback,
GeoPositionErrorCallback aErrorCallback,
UniquePtr<PositionOptions>&& aOptions,
uint8_t aProtocolType,
bool aWatchPositionRequest = false,
+ bool aIsHandlingUserInput = false,
int32_t aWatchId = 0);
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(nsGeolocationRequest)
void Shutdown();
void SendLocation(nsIDOMGeoPosition* aLocation);
bool WantsHighAccuracy() {return !mShutdown && mOptions && mOptions->mEnableHighAccuracy;}
@@ -121,16 +123,17 @@ class nsGeolocationRequest final
void Notify();
bool mIsWatchPositionRequest;
nsCOMPtr<nsITimer> mTimeoutTimer;
GeoPositionCallback mCallback;
GeoPositionErrorCallback mErrorCallback;
UniquePtr<PositionOptions> mOptions;
+ bool mIsHandlingUserInput;
RefPtr<Geolocation> mLocator;
int32_t mWatchId;
bool mShutdown;
nsCOMPtr<nsIContentPermissionRequester> mRequester;
uint8_t mProtocolType;
};
@@ -300,21 +303,23 @@ PositionError::NotifyCallback(const GeoP
////////////////////////////////////////////////////
nsGeolocationRequest::nsGeolocationRequest(Geolocation* aLocator,
GeoPositionCallback aCallback,
GeoPositionErrorCallback aErrorCallback,
UniquePtr<PositionOptions>&& aOptions,
uint8_t aProtocolType,
bool aWatchPositionRequest,
+ bool aIsHandlingUserInput,
int32_t aWatchId)
: mIsWatchPositionRequest(aWatchPositionRequest),
mCallback(Move(aCallback)),
mErrorCallback(Move(aErrorCallback)),
mOptions(Move(aOptions)),
+ mIsHandlingUserInput(aIsHandlingUserInput),
mLocator(aLocator),
mWatchId(aWatchId),
mShutdown(false),
mProtocolType(aProtocolType)
{
if (nsCOMPtr<nsPIDOMWindowInner> win =
do_QueryReferent(mLocator->GetOwner())) {
mRequester = new nsContentPermissionRequester(win);
@@ -391,16 +396,23 @@ NS_IMETHODIMP
nsGeolocationRequest::GetElement(nsIDOMElement * *aRequestingElement)
{
NS_ENSURE_ARG_POINTER(aRequestingElement);
*aRequestingElement = nullptr;
return NS_OK;
}
NS_IMETHODIMP
+nsGeolocationRequest::GetIsHandlingUserInput(bool* aIsHandlingUserInput)
+{
+ *aIsHandlingUserInput = mIsHandlingUserInput;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
nsGeolocationRequest::Cancel()
{
if (mRequester) {
// Record the number of denied requests for regular web content.
// This method is only called when the user explicitly denies the request,
// and is not called when the page is simply unloaded, or similar.
Telemetry::Accumulate(Telemetry::GEOLOCATION_REQUEST_GRANTED, mProtocolType);
}
@@ -551,23 +563,23 @@ nsGeolocationRequest::SendLocation(nsIDO
const uint32_t maximumAge_ms = mOptions->mMaximumAge;
const bool isTooOld =
DOMTimeStamp(PR_Now() / PR_USEC_PER_MSEC - maximumAge_ms) > positionTime_ms;
if (isTooOld) {
return;
}
}
- RefPtr<Position> wrapped;
+ RefPtr<mozilla::dom::Position> wrapped;
if (aPosition) {
nsCOMPtr<nsIDOMGeoPositionCoords> coords;
aPosition->GetCoords(getter_AddRefs(coords));
if (coords) {
- wrapped = new Position(ToSupports(mLocator), aPosition);
+ wrapped = new mozilla::dom::Position(ToSupports(mLocator), aPosition);
}
}
if (!wrapped) {
NotifyError(nsIDOMGeoPositionError::POSITION_UNAVAILABLE);
return;
}
@@ -1249,17 +1261,17 @@ Geolocation::GetCurrentPosition(GeoPosit
// Count the number of requests per protocol/scheme.
Telemetry::Accumulate(Telemetry::GEOLOCATION_GETCURRENTPOSITION_SECURE_ORIGIN,
static_cast<uint8_t>(mProtocolType));
RefPtr<nsGeolocationRequest> request =
new nsGeolocationRequest(this, Move(callback), Move(errorCallback),
Move(options), static_cast<uint8_t>(mProtocolType),
- false);
+ false, EventStateManager::IsHandlingUserInput());
if (!sGeoEnabled || ShouldBlockInsecureRequests() ||
nsContentUtils::ResistFingerprinting(aCallerType)) {
nsCOMPtr<nsIRunnable> ev = new RequestAllowEvent(false, request);
NS_DispatchToMainThread(ev);
return NS_OK;
}
@@ -1336,17 +1348,18 @@ Geolocation::WatchPosition(GeoPositionCa
static_cast<uint8_t>(mProtocolType));
// The watch ID:
*aRv = mLastWatchId++;
RefPtr<nsGeolocationRequest> request =
new nsGeolocationRequest(this, Move(aCallback), Move(aErrorCallback),
Move(aOptions),
- static_cast<uint8_t>(mProtocolType), true, *aRv);
+ static_cast<uint8_t>(mProtocolType), true,
+ EventStateManager::IsHandlingUserInput(), *aRv);
if (!sGeoEnabled || ShouldBlockInsecureRequests() ||
nsContentUtils::ResistFingerprinting(aCallerType)) {
nsCOMPtr<nsIRunnable> ev = new RequestAllowEvent(false, request);
NS_DispatchToMainThread(ev);
return NS_OK;
}
--- a/dom/interfaces/base/nsIContentPermissionPrompt.idl
+++ b/dom/interfaces/base/nsIContentPermissionPrompt.idl
@@ -82,16 +82,18 @@ interface nsIContentPermissionRequest :
* The window or element that the permission request was
* originated in. Typically the element will be non-null
* in when using out of process content. window or
* element can be null but not both.
*/
readonly attribute mozIDOMWindow window;
readonly attribute nsIDOMElement element;
+ readonly attribute boolean isHandlingUserInput;
+
/**
* The requester to get the required information of
* the window.
*/
readonly attribute nsIContentPermissionRequester requester;
/**
* allow or cancel the request
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -3031,16 +3031,17 @@ ContentChild::RecvUpdateWindow(const uin
MOZ_ASSERT(false, "ContentChild::RecvUpdateWindow calls unexpected on this platform.");
return IPC_FAIL_NO_REASON(this);
#endif
}
PContentPermissionRequestChild*
ContentChild::AllocPContentPermissionRequestChild(const InfallibleTArray<PermissionRequest>& aRequests,
const IPC::Principal& aPrincipal,
+ const bool& aIsHandlingUserInput,
const TabId& aTabId)
{
MOZ_CRASH("unused");
return nullptr;
}
bool
ContentChild::DeallocPContentPermissionRequestChild(PContentPermissionRequestChild* actor)
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -548,16 +548,17 @@ public:
virtual PWebrtcGlobalChild* AllocPWebrtcGlobalChild() override;
virtual bool DeallocPWebrtcGlobalChild(PWebrtcGlobalChild *aActor) override;
virtual PContentPermissionRequestChild*
AllocPContentPermissionRequestChild(const InfallibleTArray<PermissionRequest>& aRequests,
const IPC::Principal& aPrincipal,
+ const bool& aIsHandlingUserInput,
const TabId& aTabId) override;
virtual bool
DeallocPContentPermissionRequestChild(PContentPermissionRequestChild* actor) override;
// Windows specific - set up audio session
virtual mozilla::ipc::IPCResult
RecvSetAudioSessionData(const nsID& aId,
const nsString& aDisplayName,
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -4426,28 +4426,30 @@ ContentParent::RecvUpdateDropEffect(cons
dragSession->UpdateDragEffect();
}
return IPC_OK();
}
PContentPermissionRequestParent*
ContentParent::AllocPContentPermissionRequestParent(const InfallibleTArray<PermissionRequest>& aRequests,
const IPC::Principal& aPrincipal,
+ const bool& aIsHandlingUserInput,
const TabId& aTabId)
{
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
RefPtr<TabParent> tp =
cpm->GetTopLevelTabParentByProcessAndTabId(this->ChildID(), aTabId);
if (!tp) {
return nullptr;
}
return nsContentPermissionUtils::CreateContentPermissionRequestParent(aRequests,
tp->GetOwnerElement(),
aPrincipal,
+ aIsHandlingUserInput,
aTabId);
}
bool
ContentParent::DeallocPContentPermissionRequestParent(PContentPermissionRequestParent* actor)
{
nsContentPermissionUtils::NotifyRemoveContentPermissionRequestParent(actor);
delete actor;
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -512,16 +512,17 @@ public:
virtual mozilla::ipc::IPCResult RecvFinishShutdown() override;
void MaybeInvokeDragSession(TabParent* aParent);
virtual PContentPermissionRequestParent*
AllocPContentPermissionRequestParent(const InfallibleTArray<PermissionRequest>& aRequests,
const IPC::Principal& aPrincipal,
+ const bool& aIsTrusted,
const TabId& aTabId) override;
virtual bool
DeallocPContentPermissionRequestParent(PContentPermissionRequestParent* actor) override;
virtual bool HandleWindowsMessages(const Message& aMsg) const override;
void ForkNewProcess(bool aBlocking);
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -987,17 +987,17 @@ parent:
* @param tabId
* To identify which tab issues this request.
*
* NOTE: The principal is untrusted in the parent process. Only
* principals that can live in the content process should
* provided.
*/
async PContentPermissionRequest(PermissionRequest[] aRequests, Principal aPrincipal,
- TabId tabId);
+ bool aIsHandlingUserInput, TabId tabId);
async ShutdownProfile(nsCString aProfile);
/**
* Request graphics initialization information from the parent.
*/
sync GetGraphicsDeviceInitData()
returns (ContentDeviceData aData);
--- a/dom/notification/DesktopNotification.cpp
+++ b/dom/notification/DesktopNotification.cpp
@@ -2,16 +2,17 @@
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/DesktopNotification.h"
#include "mozilla/dom/DesktopNotificationBinding.h"
#include "mozilla/dom/AppNotificationServiceOptionsBinding.h"
#include "mozilla/dom/ToJSValue.h"
+#include "mozilla/EventStateManager.h"
#include "nsComponentManagerUtils.h"
#include "nsContentPermissionHelper.h"
#include "nsXULAppAPI.h"
#include "mozilla/dom/PBrowserChild.h"
#include "mozilla/Preferences.h"
#include "nsGlobalWindow.h"
#include "nsIScriptSecurityManager.h"
#include "nsServiceManagerUtils.h"
@@ -107,22 +108,24 @@ DesktopNotification::PostDesktopNotifica
NS_ENSURE_SUCCESS(rv, rv);
return alerts->ShowAlert(alert, mObserver);
}
DesktopNotification::DesktopNotification(const nsAString & title,
const nsAString & description,
const nsAString & iconURL,
nsPIDOMWindowInner* aWindow,
+ bool aIsHandlingUserInput,
nsIPrincipal* principal)
: DOMEventTargetHelper(aWindow)
, mTitle(title)
, mDescription(description)
, mIconURL(iconURL)
, mPrincipal(principal)
+ , mIsHandlingUserInput(aIsHandlingUserInput)
, mAllow(false)
, mShowHasBeenCalled(false)
{
if (Preferences::GetBool("notification.disabled", false)) {
return;
}
// If we are in testing mode (running mochitests, for example)
@@ -227,16 +230,17 @@ DesktopNotificationCenter::CreateNotific
{
MOZ_ASSERT(mOwner);
RefPtr<DesktopNotification> notification =
new DesktopNotification(aTitle,
aDescription,
aIconURL,
mOwner,
+ EventStateManager::IsHandlingUserInput(),
mPrincipal);
notification->Init();
return notification.forget();
}
JSObject*
DesktopNotificationCenter::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
@@ -276,16 +280,23 @@ NS_IMETHODIMP
DesktopNotificationRequest::GetElement(nsIDOMElement * *aElement)
{
NS_ENSURE_ARG_POINTER(aElement);
*aElement = nullptr;
return NS_OK;
}
NS_IMETHODIMP
+DesktopNotificationRequest::GetIsHandlingUserInput(bool *aIsHandlingUserInput)
+{
+ *aIsHandlingUserInput = mDesktopNotification->mIsHandlingUserInput;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
DesktopNotificationRequest::Cancel()
{
nsresult rv = mDesktopNotification->SetAllow(false);
mDesktopNotification = nullptr;
return rv;
}
NS_IMETHODIMP
--- a/dom/notification/DesktopNotification.h
+++ b/dom/notification/DesktopNotification.h
@@ -87,16 +87,17 @@ class DesktopNotification final : public
friend class DesktopNotificationRequest;
public:
DesktopNotification(const nsAString& aTitle,
const nsAString& aDescription,
const nsAString& aIconURL,
nsPIDOMWindowInner* aWindow,
+ bool aIsHandlingUserInput,
nsIPrincipal* principal);
virtual ~DesktopNotification();
void Init();
/*
* PostDesktopNotification
@@ -130,16 +131,17 @@ public:
protected:
nsString mTitle;
nsString mDescription;
nsString mIconURL;
RefPtr<AlertServiceObserver> mObserver;
nsCOMPtr<nsIPrincipal> mPrincipal;
+ bool mIsHandlingUserInput;
bool mAllow;
bool mShowHasBeenCalled;
static uint32_t sCount;
};
class AlertServiceObserver: public nsIObserver
{
--- a/dom/notification/Notification.cpp
+++ b/dom/notification/Notification.cpp
@@ -2,16 +2,17 @@
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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"
#include "mozilla/Encoding.h"
+#include "mozilla/EventStateManager.h"
#include "mozilla/JSONWriter.h"
#include "mozilla/Move.h"
#include "mozilla/OwningNonNull.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/Telemetry.h"
#include "mozilla/Unused.h"
@@ -231,23 +232,24 @@ class NotificationPermissionRequest : pu
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_NSICONTENTPERMISSIONREQUEST
NS_DECL_NSIRUNNABLE
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(NotificationPermissionRequest,
nsIContentPermissionRequest)
- NotificationPermissionRequest(nsIPrincipal* aPrincipal,
+ NotificationPermissionRequest(nsIPrincipal* aPrincipal, bool aIsHandlingUserInput,
nsPIDOMWindowInner* aWindow, Promise* aPromise,
NotificationPermissionCallback* aCallback)
: mPrincipal(aPrincipal), mWindow(aWindow),
mPermission(NotificationPermission::Default),
mPromise(aPromise),
- mCallback(aCallback)
+ mCallback(aCallback),
+ mIsHandlingUserInput(aIsHandlingUserInput)
{
MOZ_ASSERT(aPromise);
mRequester = new nsContentPermissionRequester(mWindow);
}
NS_IMETHOD GetName(nsACString& aName) override
{
aName.AssignLiteral("NotificationPermissionRequest");
@@ -260,16 +262,17 @@ protected:
nsresult ResolvePromise();
nsresult DispatchResolvePromise();
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<nsPIDOMWindowInner> mWindow;
NotificationPermission mPermission;
RefPtr<Promise> mPromise;
RefPtr<NotificationPermissionCallback> mCallback;
nsCOMPtr<nsIContentPermissionRequester> mRequester;
+ bool mIsHandlingUserInput;
};
namespace {
class ReleaseNotificationControlRunnable final : public MainThreadWorkerControlRunnable
{
Notification* mNotification;
public:
@@ -595,16 +598,23 @@ NS_IMETHODIMP
NotificationPermissionRequest::GetElement(nsIDOMElement** aElement)
{
NS_ENSURE_ARG_POINTER(aElement);
*aElement = nullptr;
return NS_OK;
}
NS_IMETHODIMP
+NotificationPermissionRequest::GetIsHandlingUserInput(bool* aIsHandlingUserInput)
+{
+ *aIsHandlingUserInput = mIsHandlingUserInput;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
NotificationPermissionRequest::Cancel()
{
// `Cancel` is called if the user denied permission or dismissed the
// permission request. To distinguish between the two, we set the
// permission to "default" and query the permission manager in
// `ResolvePromise`.
mPermission = NotificationPermission::Default;
return DispatchResolvePromise();
@@ -1806,18 +1816,19 @@ Notification::RequestPermission(const Gl
RefPtr<Promise> promise = Promise::Create(global, aRv);
if (aRv.Failed()) {
return nullptr;
}
NotificationPermissionCallback* permissionCallback = nullptr;
if (aCallback.WasPassed()) {
permissionCallback = &aCallback.Value();
}
- nsCOMPtr<nsIRunnable> request =
- new NotificationPermissionRequest(principal, window, promise, permissionCallback);
+ bool isHandlingUserInput = EventStateManager::IsHandlingUserInput();
+ nsCOMPtr<nsIRunnable> request = new NotificationPermissionRequest(
+ principal, isHandlingUserInput, window, promise, permissionCallback);
global->Dispatch(TaskCategory::Other, request.forget());
return promise.forget();
}
// static
NotificationPermission
--- a/dom/quota/StorageManager.cpp
+++ b/dom/quota/StorageManager.cpp
@@ -6,16 +6,17 @@
#include "StorageManager.h"
#include "mozilla/dom/PromiseWorkerProxy.h"
#include "mozilla/dom/quota/QuotaManagerService.h"
#include "mozilla/dom/StorageManagerBinding.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/ErrorResult.h"
+#include "mozilla/EventStateManager.h"
#include "mozilla/Telemetry.h"
#include "nsContentPermissionHelper.h"
#include "nsIQuotaCallbacks.h"
#include "nsIQuotaRequests.h"
#include "nsPIDOMWindow.h"
using namespace mozilla::dom::workers;
@@ -162,25 +163,28 @@ public:
* PersistentStoragePermissionRequest
******************************************************************************/
class PersistentStoragePermissionRequest final
: public nsIContentPermissionRequest
{
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<nsPIDOMWindowInner> mWindow;
+ bool mIsHandlingUserInput;
RefPtr<Promise> mPromise;
nsCOMPtr<nsIContentPermissionRequester> mRequester;
public:
PersistentStoragePermissionRequest(nsIPrincipal* aPrincipal,
nsPIDOMWindowInner* aWindow,
+ bool aIsHandlingUserInput,
Promise* aPromise)
: mPrincipal(aPrincipal)
, mWindow(aWindow)
+ , mIsHandlingUserInput(aIsHandlingUserInput)
, mPromise(aPromise)
{
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(aWindow);
MOZ_ASSERT(aPromise);
mRequester = new nsContentPermissionRequester(mWindow);
}
@@ -298,17 +302,20 @@ ExecuteOpOnMainOrWorkerThread(nsIGlobalO
RefPtr<nsIQuotaRequest> request;
aRv = Persisted(principal, resolver, getter_AddRefs(request));
break;
}
case RequestResolver::Type::Persist: {
RefPtr<PersistentStoragePermissionRequest> request =
- new PersistentStoragePermissionRequest(principal, window, promise);
+ new PersistentStoragePermissionRequest(principal,
+ window,
+ EventStateManager::IsHandlingUserInput(),
+ promise);
// In private browsing mode, no permission prompt.
if (nsContentUtils::IsInPrivateBrowsing(doc)) {
aRv = request->Cancel();
} else {
aRv = request->Start();
}
@@ -712,16 +719,23 @@ PersistentStoragePermissionRequest::GetP
MOZ_ASSERT(mPrincipal);
NS_ADDREF(*aPrincipal = mPrincipal);
return NS_OK;
}
NS_IMETHODIMP
+PersistentStoragePermissionRequest::GetIsHandlingUserInput(bool* aIsHandlingUserInput)
+{
+ *aIsHandlingUserInput = mIsHandlingUserInput;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
PersistentStoragePermissionRequest::GetWindow(mozIDOMWindow** aRequestingWindow)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aRequestingWindow);
MOZ_ASSERT(mWindow);
NS_ADDREF(*aRequestingWindow = mWindow);