mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Bug 1092102 - Implement WorkerDebuggerGlobalScope.createSandbox;r=khuey
This commit is contained in:
parent
066aa9747b
commit
0c47b481d2
@ -7,6 +7,11 @@
|
||||
interface WorkerDebuggerGlobalScope : EventTarget {
|
||||
readonly attribute object global;
|
||||
|
||||
object createSandbox(DOMString name, object prototype);
|
||||
|
||||
[Throws]
|
||||
void loadSubScript(DOMString url, optional object sandbox);
|
||||
|
||||
void enterEventLoop();
|
||||
|
||||
void leaveEventLoop();
|
||||
|
@ -873,14 +873,14 @@ JSObject*
|
||||
Wrap(JSContext *cx, JS::HandleObject existing, JS::HandleObject obj)
|
||||
{
|
||||
JSObject* targetGlobal = JS::CurrentGlobalOrNull(cx);
|
||||
if (!IsDebuggerGlobal(targetGlobal)) {
|
||||
if (!IsDebuggerGlobal(targetGlobal) && !IsDebuggerSandbox(targetGlobal)) {
|
||||
MOZ_CRASH("There should be no edges from the debuggee to the debugger.");
|
||||
}
|
||||
|
||||
JSObject* originGlobal = js::GetGlobalForObjectCrossCompartment(obj);
|
||||
|
||||
const js::Wrapper* wrapper = nullptr;
|
||||
if (IsDebuggerGlobal(originGlobal)) {
|
||||
if (IsDebuggerGlobal(originGlobal) || IsDebuggerSandbox(originGlobal)) {
|
||||
wrapper = &js::CrossCompartmentWrapper::singleton;
|
||||
} else {
|
||||
if (obj != originGlobal) {
|
||||
|
@ -981,7 +981,8 @@ LoadMainScript(JSContext* aCx, const nsAString& aScriptURL,
|
||||
|
||||
void
|
||||
Load(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
||||
const Sequence<nsString>& aScriptURLs, ErrorResult& aRv)
|
||||
const nsTArray<nsString>& aScriptURLs, WorkerScriptType aWorkerScriptType,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
const uint32_t urlCount = aScriptURLs.Length();
|
||||
|
||||
@ -1001,7 +1002,7 @@ Load(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
||||
loadInfos[index].mURL = aScriptURLs[index];
|
||||
}
|
||||
|
||||
if (!LoadAllScripts(aCx, aWorkerPrivate, loadInfos, false, WorkerScript)) {
|
||||
if (!LoadAllScripts(aCx, aWorkerPrivate, loadInfos, false, aWorkerScriptType)) {
|
||||
// LoadAllScripts can fail if we're shutting down.
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
}
|
||||
|
@ -58,7 +58,8 @@ bool LoadMainScript(JSContext* aCx, const nsAString& aScriptURL,
|
||||
|
||||
void Load(JSContext* aCx,
|
||||
WorkerPrivate* aWorkerPrivate,
|
||||
const mozilla::dom::Sequence<nsString>& aScriptURLs,
|
||||
const nsTArray<nsString>& aScriptURLs,
|
||||
WorkerScriptType aWorkerScriptType,
|
||||
mozilla::ErrorResult& aRv);
|
||||
|
||||
} // namespace scriptloader
|
||||
|
@ -1511,15 +1511,16 @@ public:
|
||||
if (!globalScope) {
|
||||
WorkerDebuggerGlobalScope* globalScope = nullptr;
|
||||
UNWRAP_OBJECT(WorkerDebuggerGlobalScope, global, globalScope);
|
||||
MOZ_ASSERT(globalScope);
|
||||
MOZ_ASSERT(global == globalScope->GetWrapperPreserveColor());
|
||||
|
||||
MOZ_ASSERT_IF(globalScope, globalScope->GetWrapperPreserveColor() == global);
|
||||
MOZ_ASSERT_IF(!globalScope, IsDebuggerSandbox(global));
|
||||
|
||||
aWorkerPrivate->ReportErrorToDebugger(aFilename, aLineNumber,
|
||||
aMessage);
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(global == globalScope->GetWrapperPreserveColor());
|
||||
MOZ_ASSERT(globalScope->GetWrapperPreserveColor() == global);
|
||||
nsIDOMEventTarget* target = static_cast<nsIDOMEventTarget*>(globalScope);
|
||||
|
||||
nsRefPtr<ErrorEvent> event =
|
||||
|
@ -208,7 +208,7 @@ WorkerGlobalScope::ImportScripts(JSContext* aCx,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
scriptloader::Load(aCx, mWorkerPrivate, aScriptURLs, aRv);
|
||||
scriptloader::Load(aCx, mWorkerPrivate, aScriptURLs, WorkerScript, aRv);
|
||||
}
|
||||
|
||||
int32_t
|
||||
@ -513,6 +513,184 @@ WorkerDebuggerGlobalScope::GetGlobal(JSContext* aCx,
|
||||
aGlobal.set(mWorkerPrivate->GetOrCreateGlobalScope(aCx)->GetWrapper());
|
||||
}
|
||||
|
||||
class WorkerDebuggerSandboxPrivate : public nsIGlobalObject,
|
||||
public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
WorkerDebuggerSandboxPrivate(JSObject *global)
|
||||
{
|
||||
SetWrapper(global);
|
||||
}
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(WorkerDebuggerSandboxPrivate,
|
||||
nsIGlobalObject)
|
||||
|
||||
JSObject *GetGlobalJSObject()
|
||||
{
|
||||
return GetWrapper();
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* cx,
|
||||
JS::Handle<JSObject*> aGivenProto) override
|
||||
{
|
||||
MOZ_CRASH("WorkerDebuggerSandboxPrivate doesn't use DOM bindings!");
|
||||
}
|
||||
|
||||
private:
|
||||
virtual ~WorkerDebuggerSandboxPrivate()
|
||||
{
|
||||
ClearWrapper();
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WorkerDebuggerSandboxPrivate)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(WorkerDebuggerSandboxPrivate)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(WorkerDebuggerSandboxPrivate)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WorkerDebuggerSandboxPrivate)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
static bool
|
||||
workerdebuggersandbox_enumerate(JSContext *cx, JS::Handle<JSObject *> obj)
|
||||
{
|
||||
return JS_EnumerateStandardClasses(cx, obj);
|
||||
}
|
||||
|
||||
static bool
|
||||
workerdebuggersandbox_resolve(JSContext *cx, JS::Handle<JSObject *> obj,
|
||||
JS::Handle<jsid> id, bool *resolvedp)
|
||||
{
|
||||
return JS_ResolveStandardClass(cx, obj, id, resolvedp);
|
||||
}
|
||||
|
||||
static bool
|
||||
workerdebuggersandbox_convert(JSContext *cx, JS::Handle<JSObject *> obj,
|
||||
JSType type, JS::MutableHandle<JS::Value> vp)
|
||||
{
|
||||
if (type == JSTYPE_OBJECT) {
|
||||
vp.set(OBJECT_TO_JSVAL(obj));
|
||||
return true;
|
||||
}
|
||||
|
||||
return JS::OrdinaryToPrimitive(cx, obj, type, vp);
|
||||
}
|
||||
|
||||
static void
|
||||
workerdebuggersandbox_finalize(js::FreeOp *fop, JSObject *obj)
|
||||
{
|
||||
nsIGlobalObject *globalObject =
|
||||
static_cast<nsIGlobalObject *>(JS_GetPrivate(obj));
|
||||
NS_RELEASE(globalObject);
|
||||
}
|
||||
|
||||
static void
|
||||
workerdebuggersandbox_moved(JSObject *obj, const JSObject *old)
|
||||
{
|
||||
}
|
||||
|
||||
const js::Class workerdebuggersandbox_class = {
|
||||
"workerdebuggersandbox",
|
||||
JSCLASS_GLOBAL_FLAGS | JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
workerdebuggersandbox_enumerate,
|
||||
workerdebuggersandbox_resolve,
|
||||
workerdebuggersandbox_convert,
|
||||
workerdebuggersandbox_finalize,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
JS_GlobalObjectTraceHook,
|
||||
JS_NULL_CLASS_SPEC, {
|
||||
nullptr,
|
||||
nullptr,
|
||||
false,
|
||||
nullptr,
|
||||
workerdebuggersandbox_moved
|
||||
}, JS_NULL_OBJECT_OPS
|
||||
};
|
||||
|
||||
void
|
||||
WorkerDebuggerGlobalScope::CreateSandbox(JSContext* aCx, const nsAString& aName,
|
||||
JS::Handle<JSObject*> aPrototype,
|
||||
JS::MutableHandle<JSObject*> aResult)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
JS::CompartmentOptions options;
|
||||
options.setInvisibleToDebugger(true);
|
||||
|
||||
JS::Rooted<JSObject*> sandbox(aCx,
|
||||
JS_NewGlobalObject(aCx, js::Jsvalify(&workerdebuggersandbox_class), nullptr,
|
||||
JS::DontFireOnNewGlobalHook, options));
|
||||
if (!sandbox) {
|
||||
JS_ReportError(aCx, "Can't create sandbox!");
|
||||
aResult.set(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
JSAutoCompartment ac(aCx, sandbox);
|
||||
|
||||
JS::Rooted<JSObject*> prototype(aCx, aPrototype);
|
||||
if (!JS_WrapObject(aCx, &prototype)) {
|
||||
JS_ReportError(aCx, "Can't wrap sandbox prototype!");
|
||||
aResult.set(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!JS_SetPrototype(aCx, sandbox, prototype)) {
|
||||
JS_ReportError(aCx, "Can't set sandbox prototype!");
|
||||
aResult.set(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> globalObject =
|
||||
new WorkerDebuggerSandboxPrivate(sandbox);
|
||||
|
||||
// Pass on ownership of globalObject to |sandbox|.
|
||||
JS_SetPrivate(sandbox, globalObject.forget().take());
|
||||
}
|
||||
|
||||
JS_FireOnNewGlobalObject(aCx, sandbox);
|
||||
|
||||
if (!JS_WrapObject(aCx, &sandbox)) {
|
||||
JS_ReportError(aCx, "Can't wrap sandbox!");
|
||||
aResult.set(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
aResult.set(sandbox);
|
||||
}
|
||||
|
||||
void
|
||||
WorkerDebuggerGlobalScope::LoadSubScript(JSContext* aCx,
|
||||
const nsAString& aURL,
|
||||
const Optional<JS::Handle<JSObject*>>& aSandbox,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
Maybe<JSAutoCompartment> ac;
|
||||
if (aSandbox.WasPassed()) {
|
||||
JS::Rooted<JSObject*> sandbox(aCx, js::CheckedUnwrap(aSandbox.Value()));
|
||||
if (!IsDebuggerSandbox(sandbox)) {
|
||||
aRv.Throw(NS_ERROR_INVALID_ARG);
|
||||
return;
|
||||
}
|
||||
|
||||
ac.emplace(aCx, sandbox);
|
||||
}
|
||||
|
||||
nsTArray<nsString> urls;
|
||||
urls.AppendElement(aURL);
|
||||
scriptloader::Load(aCx, mWorkerPrivate, urls, DebuggerScript, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
WorkerDebuggerGlobalScope::EnterEventLoop()
|
||||
{
|
||||
@ -561,10 +739,18 @@ GetGlobalObjectForGlobal(JSObject* global)
|
||||
{
|
||||
nsIGlobalObject* globalObject = nullptr;
|
||||
UNWRAP_WORKER_OBJECT(WorkerGlobalScope, global, globalObject);
|
||||
|
||||
if (!globalObject) {
|
||||
UNWRAP_OBJECT(WorkerDebuggerGlobalScope, global, globalObject);
|
||||
MOZ_ASSERT(globalObject);
|
||||
|
||||
if (!globalObject) {
|
||||
MOZ_ASSERT(IsDebuggerSandbox(global));
|
||||
globalObject = static_cast<nsIGlobalObject *>(JS_GetPrivate(global));
|
||||
|
||||
MOZ_ASSERT(globalObject);
|
||||
}
|
||||
}
|
||||
|
||||
return globalObject;
|
||||
}
|
||||
|
||||
@ -584,6 +770,12 @@ IsDebuggerGlobal(JSObject* object)
|
||||
globalObject)) && !!globalObject;
|
||||
}
|
||||
|
||||
bool
|
||||
IsDebuggerSandbox(JSObject* object)
|
||||
{
|
||||
return js::GetObjectClass(object) == &workerdebuggersandbox_class;
|
||||
}
|
||||
|
||||
bool
|
||||
GetterOnlyJSNative(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
|
||||
{
|
||||
|
@ -264,6 +264,16 @@ public:
|
||||
void
|
||||
GetGlobal(JSContext* aCx, JS::MutableHandle<JSObject*> aGlobal);
|
||||
|
||||
void
|
||||
CreateSandbox(JSContext* aCx, const nsAString& aName,
|
||||
JS::Handle<JSObject*> aPrototype,
|
||||
JS::MutableHandle<JSObject*> aResult);
|
||||
|
||||
void
|
||||
LoadSubScript(JSContext* aCx, const nsAString& aURL,
|
||||
const Optional<JS::Handle<JSObject*>>& aSandbox,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
EnterEventLoop();
|
||||
|
||||
|
@ -339,6 +339,9 @@ IsWorkerGlobal(JSObject* global);
|
||||
bool
|
||||
IsDebuggerGlobal(JSObject* global);
|
||||
|
||||
bool
|
||||
IsDebuggerSandbox(JSObject* object);
|
||||
|
||||
// Throws the JSMSG_GETTER_ONLY exception. This shouldn't be used going
|
||||
// forward -- getter-only properties should just use JS_PSG for the setter
|
||||
// (implying no setter at all), which will not throw when set in non-strict
|
||||
|
@ -0,0 +1,9 @@
|
||||
"use strict";
|
||||
|
||||
const SANDBOX_URL = "WorkerDebuggerGlobalScope.createSandbox_sandbox.js";
|
||||
|
||||
let prototype = {
|
||||
self: this,
|
||||
};
|
||||
let sandbox = createSandbox(SANDBOX_URL, prototype);
|
||||
loadSubScript(SANDBOX_URL, sandbox);
|
@ -0,0 +1,9 @@
|
||||
"use strict";
|
||||
|
||||
self.addEventListener("message", function(event) {
|
||||
switch (event.data) {
|
||||
case "ping":
|
||||
self.postMessage("pong");
|
||||
break;
|
||||
}
|
||||
});
|
@ -0,0 +1,3 @@
|
||||
"use strict";
|
||||
|
||||
self.onmessage = function () {};
|
@ -7,6 +7,9 @@ support-files =
|
||||
WorkerDebugger.postMessage_childWorker.js
|
||||
WorkerDebugger.postMessage_debugger.js
|
||||
WorkerDebugger.postMessage_worker.js
|
||||
WorkerDebuggerGlobalScope.createSandbox_debugger.js
|
||||
WorkerDebuggerGlobalScope.createSandbox_sandbox.js
|
||||
WorkerDebuggerGlobalScope.createSandbox_worker.js
|
||||
WorkerDebuggerGlobalScope.enterEventLoop_childWorker.js
|
||||
WorkerDebuggerGlobalScope.enterEventLoop_debugger.js
|
||||
WorkerDebuggerGlobalScope.enterEventLoop_worker.js
|
||||
@ -45,6 +48,7 @@ support-files =
|
||||
[test_WorkerDebugger.xul]
|
||||
[test_WorkerDebugger.initialize.xul]
|
||||
[test_WorkerDebugger.postMessage.xul]
|
||||
[test_WorkerDebuggerGlobalScope.createSandbox.xul]
|
||||
[test_WorkerDebuggerGlobalScope.enterEventLoop.xul]
|
||||
[test_WorkerDebuggerGlobalScope.reportError.xul]
|
||||
[test_WorkerDebuggerGlobalScope.setImmediate.xul]
|
||||
|
@ -0,0 +1,52 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<window title="Test for WorkerDebuggerGlobalScope.createSandbox"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="test();">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
<script type="application/javascript" src="dom_worker_helper.js"/>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
const WORKER_URL = "WorkerDebuggerGlobalScope.createSandbox_worker.js";
|
||||
const DEBUGGER_URL = BASE_URL + "WorkerDebuggerGlobalScope.createSandbox_debugger.js";
|
||||
|
||||
function test() {
|
||||
Task.spawn(function* () {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
info("Create a worker, wait for its debugger to be registered, and " +
|
||||
"initialize it.");
|
||||
let promise = waitForRegister(WORKER_URL, DEBUGGER_URL);
|
||||
let worker = new Worker(WORKER_URL);
|
||||
let dbg = yield promise;
|
||||
|
||||
info("Send a request to the worker debugger. This should cause the " +
|
||||
"worker debugger to send a response from within a sandbox.");
|
||||
promise = waitForDebuggerMessage(dbg, "pong");
|
||||
dbg.postMessage("ping");
|
||||
yield promise;
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display:none;"></div>
|
||||
<pre id="test"></pre>
|
||||
</body>
|
||||
<label id="test-result"/>
|
||||
</window>
|
||||
|
Loading…
Reference in New Issue
Block a user