зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1151495
- Support permission prompting from workers for IDB, r=bent
This commit is contained in:
Родитель
65f9cd87c9
Коммит
f2ba43b3fd
|
@ -40,6 +40,8 @@
|
||||||
#include "PermissionRequestBase.h"
|
#include "PermissionRequestBase.h"
|
||||||
#include "ProfilerHelpers.h"
|
#include "ProfilerHelpers.h"
|
||||||
#include "ReportInternalError.h"
|
#include "ReportInternalError.h"
|
||||||
|
#include "WorkerPrivate.h"
|
||||||
|
#include "WorkerRunnable.h"
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#include "IndexedDatabaseManager.h"
|
#include "IndexedDatabaseManager.h"
|
||||||
|
@ -57,7 +59,13 @@
|
||||||
#endif // DEBUG || GC_ON_IPC_MESSAGES
|
#endif // DEBUG || GC_ON_IPC_MESSAGES
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
|
using ipc::PrincipalInfo;
|
||||||
|
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
|
using namespace workers;
|
||||||
|
|
||||||
namespace indexedDB {
|
namespace indexedDB {
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
@ -777,6 +785,235 @@ DispatchSuccessEvent(ResultHelper* aResultHelper,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class WorkerPermissionChallenge;
|
||||||
|
|
||||||
|
// This class calles WorkerPermissionChallenge::OperationCompleted() in the
|
||||||
|
// worker thread.
|
||||||
|
class WorkerPermissionOperationCompleted final : public WorkerRunnable
|
||||||
|
{
|
||||||
|
nsRefPtr<WorkerPermissionChallenge> mChallenge;
|
||||||
|
|
||||||
|
public:
|
||||||
|
WorkerPermissionOperationCompleted(WorkerPrivate* aWorkerPrivate,
|
||||||
|
WorkerPermissionChallenge* aChallenge)
|
||||||
|
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
|
||||||
|
, mChallenge(aChallenge)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool
|
||||||
|
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This class used to do prompting in the main thread and main process.
|
||||||
|
class WorkerPermissionRequest final : public PermissionRequestBase
|
||||||
|
{
|
||||||
|
nsRefPtr<WorkerPermissionChallenge> mChallenge;
|
||||||
|
|
||||||
|
public:
|
||||||
|
WorkerPermissionRequest(Element* aElement,
|
||||||
|
nsIPrincipal* aPrincipal,
|
||||||
|
WorkerPermissionChallenge* aChallenge)
|
||||||
|
: PermissionRequestBase(aElement, aPrincipal)
|
||||||
|
, mChallenge(aChallenge)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
MOZ_ASSERT(aChallenge);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
~WorkerPermissionRequest()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
OnPromptComplete(PermissionValue aPermissionValue) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This class is used in the main thread of all child processes.
|
||||||
|
class WorkerPermissionRequestChildProcessActor final
|
||||||
|
: public PIndexedDBPermissionRequestChild
|
||||||
|
{
|
||||||
|
nsRefPtr<WorkerPermissionChallenge> mChallenge;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit WorkerPermissionRequestChildProcessActor(
|
||||||
|
WorkerPermissionChallenge* aChallenge)
|
||||||
|
: mChallenge(aChallenge)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(XRE_GetProcessType() != GeckoProcessType_Default);
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
MOZ_ASSERT(aChallenge);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
~WorkerPermissionRequestChildProcessActor()
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual bool
|
||||||
|
Recv__delete__(const uint32_t& aPermission) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class WorkerPermissionChallenge final : public nsRunnable
|
||||||
|
, public WorkerFeature
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WorkerPermissionChallenge(WorkerPrivate* aWorkerPrivate,
|
||||||
|
BackgroundFactoryRequestChild* aActor,
|
||||||
|
IDBFactory* aFactory,
|
||||||
|
const PrincipalInfo& aPrincipalInfo)
|
||||||
|
: mWorkerPrivate(aWorkerPrivate)
|
||||||
|
, mActor(aActor)
|
||||||
|
, mFactory(aFactory)
|
||||||
|
, mPrincipalInfo(aPrincipalInfo)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mWorkerPrivate);
|
||||||
|
MOZ_ASSERT(aActor);
|
||||||
|
MOZ_ASSERT(aFactory);
|
||||||
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHOD
|
||||||
|
Run() override
|
||||||
|
{
|
||||||
|
bool completed = RunInternal();
|
||||||
|
if (completed) {
|
||||||
|
OperationCompleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool
|
||||||
|
Notify(JSContext* aCx, workers::Status aStatus) override
|
||||||
|
{
|
||||||
|
// We don't care about the notification. We just want to keep the
|
||||||
|
// mWorkerPrivate alive.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
OperationCompleted()
|
||||||
|
{
|
||||||
|
if (NS_IsMainThread()) {
|
||||||
|
nsRefPtr<WorkerPermissionOperationCompleted> runnable =
|
||||||
|
new WorkerPermissionOperationCompleted(mWorkerPrivate, this);
|
||||||
|
|
||||||
|
if (!runnable->Dispatch(nullptr)) {
|
||||||
|
NS_WARNING("Failed to dispatch a runnable to the worker thread.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(mActor);
|
||||||
|
mActor->AssertIsOnOwningThread();
|
||||||
|
|
||||||
|
MaybeCollectGarbageOnIPCMessage();
|
||||||
|
|
||||||
|
nsRefPtr<IDBFactory> factory;
|
||||||
|
mFactory.swap(factory);
|
||||||
|
|
||||||
|
mActor->SendPermissionRetry();
|
||||||
|
mActor = nullptr;
|
||||||
|
|
||||||
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||||
|
JSContext* cx = mWorkerPrivate->GetJSContext();
|
||||||
|
mWorkerPrivate->RemoveFeature(cx, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool
|
||||||
|
RunInternal()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
// Walk up to our containing page
|
||||||
|
WorkerPrivate* wp = mWorkerPrivate;
|
||||||
|
while (wp->GetParent()) {
|
||||||
|
wp = wp->GetParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
nsPIDOMWindow* window = wp->GetWindow();
|
||||||
|
if (!window) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult rv;
|
||||||
|
nsCOMPtr<nsIPrincipal> principal =
|
||||||
|
mozilla::ipc::PrincipalInfoToPrincipal(mPrincipalInfo, &rv);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (XRE_GetProcessType() == GeckoProcessType_Default) {
|
||||||
|
nsCOMPtr<Element> ownerElement =
|
||||||
|
do_QueryInterface(window->GetChromeEventHandler());
|
||||||
|
if (NS_WARN_IF(!ownerElement)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsRefPtr<WorkerPermissionRequest> helper =
|
||||||
|
new WorkerPermissionRequest(ownerElement, principal, this);
|
||||||
|
|
||||||
|
PermissionRequestBase::PermissionValue permission;
|
||||||
|
if (NS_WARN_IF(NS_FAILED(helper->PromptIfNeeded(&permission)))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(permission == PermissionRequestBase::kPermissionAllowed ||
|
||||||
|
permission == PermissionRequestBase::kPermissionDenied ||
|
||||||
|
permission == PermissionRequestBase::kPermissionPrompt);
|
||||||
|
|
||||||
|
return permission != PermissionRequestBase::kPermissionPrompt;
|
||||||
|
}
|
||||||
|
|
||||||
|
TabChild* tabChild = TabChild::GetFrom(window);
|
||||||
|
MOZ_ASSERT(tabChild);
|
||||||
|
|
||||||
|
IPC::Principal ipcPrincipal(principal);
|
||||||
|
|
||||||
|
auto* actor = new WorkerPermissionRequestChildProcessActor(this);
|
||||||
|
tabChild->SendPIndexedDBPermissionRequestConstructor(actor, ipcPrincipal);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
WorkerPrivate* mWorkerPrivate;
|
||||||
|
BackgroundFactoryRequestChild* mActor;
|
||||||
|
nsRefPtr<IDBFactory> mFactory;
|
||||||
|
PrincipalInfo mPrincipalInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
WorkerPermissionRequest::OnPromptComplete(PermissionValue aPermissionValue)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
mChallenge->OperationCompleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
WorkerPermissionOperationCompleted::WorkerRun(JSContext* aCx,
|
||||||
|
WorkerPrivate* aWorkerPrivate)
|
||||||
|
{
|
||||||
|
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||||
|
mChallenge->OperationCompleted();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
WorkerPermissionRequestChildProcessActor::Recv__delete__(
|
||||||
|
const uint32_t& /* aPermission */)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
mChallenge->OperationCompleted();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
@ -1124,7 +1361,23 @@ BackgroundFactoryRequestChild::RecvPermissionChallenge(
|
||||||
MaybeCollectGarbageOnIPCMessage();
|
MaybeCollectGarbageOnIPCMessage();
|
||||||
|
|
||||||
if (!NS_IsMainThread()) {
|
if (!NS_IsMainThread()) {
|
||||||
MOZ_CRASH("Implement me for workers!");
|
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||||
|
MOZ_ASSERT(workerPrivate);
|
||||||
|
workerPrivate->AssertIsOnWorkerThread();
|
||||||
|
|
||||||
|
nsRefPtr<WorkerPermissionChallenge> challenge =
|
||||||
|
new WorkerPermissionChallenge(workerPrivate, this, mFactory,
|
||||||
|
aPrincipalInfo);
|
||||||
|
|
||||||
|
JSContext* cx = workerPrivate->GetJSContext();
|
||||||
|
MOZ_ASSERT(cx);
|
||||||
|
|
||||||
|
if (!workerPrivate->AddFeature(cx, challenge)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(challenge)));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
|
|
|
@ -6,11 +6,16 @@ support-files =
|
||||||
browser_forgetThisSiteGet.html
|
browser_forgetThisSiteGet.html
|
||||||
browserHelpers.js
|
browserHelpers.js
|
||||||
browser_permissionsPrompt.html
|
browser_permissionsPrompt.html
|
||||||
|
browser_permissionsSharedWorker.html
|
||||||
|
browser_permissionsSharedWorker.js
|
||||||
|
browser_permissionsWorker.html
|
||||||
|
browser_permissionsWorker.js
|
||||||
bug839193.js
|
bug839193.js
|
||||||
bug839193.xul
|
bug839193.xul
|
||||||
|
|
||||||
[browser_forgetThisSite.js]
|
[browser_forgetThisSite.js]
|
||||||
[browser_permissionsPromptAllow.js]
|
[browser_permissionsPromptAllow.js]
|
||||||
[browser_permissionsPromptDeny.js]
|
[browser_permissionsPromptDeny.js]
|
||||||
|
[browser_permissionsPromptWorker.js]
|
||||||
[browser_perwindow_privateBrowsing.js]
|
[browser_perwindow_privateBrowsing.js]
|
||||||
[browser_bug839193.js]
|
[browser_bug839193.js]
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
/**
|
||||||
|
* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
*/
|
||||||
|
|
||||||
|
const testWorkerURL = "http://mochi.test:8888/browser/" +
|
||||||
|
"dom/indexedDB/test/browser_permissionsWorker.html";
|
||||||
|
const testSharedWorkerURL = "http://mochi.test:8888/browser/" +
|
||||||
|
"dom/indexedDB/test/browser_permissionsSharedWorker.html";
|
||||||
|
const notificationID = "indexedDB-permissions-prompt";
|
||||||
|
|
||||||
|
function test()
|
||||||
|
{
|
||||||
|
waitForExplicitFinish();
|
||||||
|
executeSoon(test1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test1()
|
||||||
|
{
|
||||||
|
// We want a prompt.
|
||||||
|
removePermission(testWorkerURL, "indexedDB");
|
||||||
|
|
||||||
|
info("creating tab");
|
||||||
|
gBrowser.selectedTab = gBrowser.addTab();
|
||||||
|
|
||||||
|
gBrowser.selectedBrowser.addEventListener("load", function () {
|
||||||
|
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
|
||||||
|
|
||||||
|
setFinishedCallback(function(isIDBDatabase, exception) {
|
||||||
|
ok(isIDBDatabase, "First database creation was successful");
|
||||||
|
ok(!exception, "No exception");
|
||||||
|
is(getPermission(testWorkerURL, "indexedDB"),
|
||||||
|
Components.interfaces.nsIPermissionManager.ALLOW_ACTION,
|
||||||
|
"Correct permission set");
|
||||||
|
gBrowser.removeCurrentTab();
|
||||||
|
executeSoon(test2);
|
||||||
|
});
|
||||||
|
|
||||||
|
registerPopupEventHandler("popupshowing", function () {
|
||||||
|
ok(true, "prompt showing");
|
||||||
|
});
|
||||||
|
registerPopupEventHandler("popupshown", function () {
|
||||||
|
ok(true, "prompt shown");
|
||||||
|
triggerMainCommand(this);
|
||||||
|
});
|
||||||
|
registerPopupEventHandler("popuphidden", function () {
|
||||||
|
ok(true, "prompt hidden");
|
||||||
|
});
|
||||||
|
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
info("loading test page: " + testWorkerURL);
|
||||||
|
content.location = testWorkerURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
function test2()
|
||||||
|
{
|
||||||
|
// We want a prompt.
|
||||||
|
removePermission(testSharedWorkerURL, "indexedDB");
|
||||||
|
|
||||||
|
info("creating tab");
|
||||||
|
gBrowser.selectedTab = gBrowser.addTab();
|
||||||
|
|
||||||
|
gBrowser.selectedBrowser.addEventListener("load", function () {
|
||||||
|
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
|
||||||
|
|
||||||
|
setFinishedCallback(function(isIDBDatabase, exception) {
|
||||||
|
ok(!isIDBDatabase, "First database creation was successful");
|
||||||
|
ok(exception, "No exception");
|
||||||
|
is(getPermission(testSharedWorkerURL, "indexedDB"),
|
||||||
|
Components.interfaces.nsIPermissionManager.UNKNOWN_ACTION,
|
||||||
|
"Correct permission set");
|
||||||
|
gBrowser.removeCurrentTab();
|
||||||
|
executeSoon(finish);
|
||||||
|
});
|
||||||
|
|
||||||
|
registerPopupEventHandler("popupshowing", function () {
|
||||||
|
ok(false, "prompt showing");
|
||||||
|
});
|
||||||
|
registerPopupEventHandler("popupshown", function () {
|
||||||
|
ok(false, "prompt shown");
|
||||||
|
});
|
||||||
|
registerPopupEventHandler("popuphidden", function () {
|
||||||
|
ok(false, "prompt hidden");
|
||||||
|
});
|
||||||
|
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
info("loading test page: " + testSharedWorkerURL);
|
||||||
|
content.location = testSharedWorkerURL;
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
<!--
|
||||||
|
Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
-->
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Indexed Database Test</title>
|
||||||
|
|
||||||
|
<script type="text/javascript;version=1.7">
|
||||||
|
let testIsIDBDatabase;
|
||||||
|
let testException;
|
||||||
|
|
||||||
|
function runTest() {
|
||||||
|
let w = new SharedWorker('browser_permissionsSharedWorker.js');
|
||||||
|
w.port.onmessage = function(e) {
|
||||||
|
if (e.data.status == 'success') {
|
||||||
|
testIsIDBDatabase = e.data.isIDBDatabase;
|
||||||
|
} else {
|
||||||
|
testException = e.data.error;
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(testFinishedCallback, 0, testIsIDBDatabase, testException);
|
||||||
|
}
|
||||||
|
|
||||||
|
const name = window.location.pathname + "_sharedWorker";
|
||||||
|
w.port.postMessage(name);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body onload="runTest();"></body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -0,0 +1,14 @@
|
||||||
|
onconnect = function(e) {
|
||||||
|
e.ports[0].onmessage = function(e) {
|
||||||
|
var request = indexedDB.open(e.data, { version: 1,
|
||||||
|
storage: "persistent" });
|
||||||
|
request.onsuccess = function(event) {
|
||||||
|
e.target.postMessage({ status: 'success',
|
||||||
|
isIDBDatabase: (event.target.result instanceof IDBDatabase) });
|
||||||
|
}
|
||||||
|
|
||||||
|
request.onerror = function(event) {
|
||||||
|
e.target.postMessage({ status: 'error', error: event.target.error.name });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
<!--
|
||||||
|
Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
-->
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Indexed Database Test</title>
|
||||||
|
|
||||||
|
<script type="text/javascript;version=1.7">
|
||||||
|
let testIsIDBDatabase;
|
||||||
|
let testException;
|
||||||
|
|
||||||
|
function runTest() {
|
||||||
|
let w = new Worker('browser_permissionsWorker.js');
|
||||||
|
w.onmessage = function(e) {
|
||||||
|
if (e.data.status == 'success') {
|
||||||
|
testIsIDBDatabase = e.data.isIDBDatabase;
|
||||||
|
} else {
|
||||||
|
testException = e.data.error;
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(testFinishedCallback, 0, testIsIDBDatabase, testException);
|
||||||
|
}
|
||||||
|
|
||||||
|
const name = window.location.pathname;
|
||||||
|
w.postMessage(name);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body onload="runTest();"></body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -0,0 +1,12 @@
|
||||||
|
onmessage = function(e) {
|
||||||
|
var request = indexedDB.open(e.data, { version: 1,
|
||||||
|
storage: "persistent" });
|
||||||
|
request.onsuccess = function(event) {
|
||||||
|
postMessage({ status: 'success',
|
||||||
|
isIDBDatabase: (event.target.result instanceof IDBDatabase) });
|
||||||
|
}
|
||||||
|
|
||||||
|
request.onerror = function(event) {
|
||||||
|
postMessage({ status: 'error', error: event.target.error.name });
|
||||||
|
}
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче