Bug 898559 - Add metadata API for add-on globals. r=bholley

This commit is contained in:
Mike Hordecki 2013-09-11 09:50:15 -04:00
parent b8058c2b43
commit 7d44f15b4a
6 changed files with 172 additions and 2 deletions

View File

@ -120,7 +120,7 @@ interface ScheduledGCCallback : nsISupports
/**
* interface of Components.utils
*/
[scriptable, uuid(35d5b0e5-9b29-48de-9f79-d2534b497435)]
[scriptable, uuid(c9ccec7a-726c-4479-9438-6f51f6ef4170)]
interface nsIXPCComponents_Utils : nsISupports
{
@ -172,6 +172,32 @@ interface nsIXPCComponents_Utils : nsISupports
[optional] in jsval filename,
[optional] in long lineNo);
/*
* getSandboxMetadata is designed to be called from JavaScript only.
*
* getSandboxMetadata retrieves the metadata associated with
* a sandbox object. It will return undefined if there
* is no metadata attached to the sandbox.
*
* var s = C.u.Sandbox(..., { metadata: "metadata" });
* var metadata = C.u.getSandboxMetadata(s);
*/
[implicit_jscontext]
jsval getSandboxMetadata(in jsval sandbox);
/*
* setSandboxMetadata is designed to be called from JavaScript only.
*
* setSandboxMetadata sets the metadata associated with
* a sandbox object.
*
* Note that the metadata object will be copied before being used.
* The copy will be performed using the structured clone algorithm.
* Note that this algorithm does not support reflectors and
* it will throw if it encounters them.
*/
[implicit_jscontext]
void setSandboxMetadata(in jsval sandbox, in jsval metadata);
/*
* import is designed to be called from JavaScript only.

View File

@ -585,9 +585,11 @@ sandbox_convert(JSContext *cx, HandleObject obj, JSType type, MutableHandleValue
return JS_ConvertStub(cx, obj, type, vp);
}
#define XPCONNECT_SANDBOX_CLASS_METADATA_SLOT (XPCONNECT_GLOBAL_EXTRA_SLOT_OFFSET)
static JSClass SandboxClass = {
"Sandbox",
XPCONNECT_GLOBAL_FLAGS,
XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(1),
JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
sandbox_enumerate, sandbox_resolve, sandbox_convert, sandbox_finalize,
NULL, NULL, NULL, NULL, TraceXPCGlobal
@ -1041,6 +1043,8 @@ xpc::CreateSandboxObject(JSContext *cx, jsval *vp, nsISupports *prinOrSop, Sandb
// about:memory may use that information
xpc::SetLocationForGlobal(sandbox, options.sandboxName);
xpc::SetSandboxMetadata(cx, sandbox, options.metadata);
JS_FireOnNewGlobalObject(cx, sandbox);
return NS_OK;
@ -1338,6 +1342,10 @@ ParseOptionsObject(JSContext *cx, jsval from, SandboxOptions &options)
NS_ENSURE_SUCCESS(rv, rv);
rv = GetDOMConstructorsFromOptions(cx, optionsObject, options);
bool found;
rv = GetPropFromOptions(cx, optionsObject,
"metadata", &options.metadata, &found);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
@ -1650,3 +1658,40 @@ xpc::NewFunctionForwarder(JSContext *cx, HandleId id, HandleObject callable, boo
vp.setObject(*funobj);
return true;
}
nsresult
xpc::GetSandboxMetadata(JSContext *cx, HandleObject sandbox, MutableHandleValue rval)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(IsSandbox(sandbox));
RootedValue metadata(cx);
{
JSAutoCompartment ac(cx, sandbox);
metadata = JS_GetReservedSlot(sandbox, XPCONNECT_SANDBOX_CLASS_METADATA_SLOT);
}
if (!JS_WrapValue(cx, metadata.address()))
return NS_ERROR_UNEXPECTED;
rval.set(metadata);
return NS_OK;
}
nsresult
xpc::SetSandboxMetadata(JSContext *cx, HandleObject sandbox, HandleValue metadataArg)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(IsSandbox(sandbox));
RootedValue metadata(cx);
JSAutoCompartment ac(cx, sandbox);
if (!JS_StructuredClone(cx, metadataArg, metadata.address(), NULL, NULL))
return NS_ERROR_UNEXPECTED;
JS_SetReservedSlot(sandbox, XPCONNECT_SANDBOX_CLASS_METADATA_SLOT, metadata);
return NS_OK;
}

View File

@ -2830,6 +2830,46 @@ nsXPCComponents_Utils::EvalInSandbox(const nsAString& source,
return NS_OK;
}
NS_IMETHODIMP
nsXPCComponents_Utils::GetSandboxMetadata(const JS::Value &sandboxVal,
JSContext *cx, JS::Value *rval)
{
if (!sandboxVal.isObject())
return NS_ERROR_INVALID_ARG;
RootedObject sandbox(cx, &sandboxVal.toObject());
sandbox = js::CheckedUnwrap(sandbox);
if (!sandbox || !xpc::IsSandbox(sandbox))
return NS_ERROR_INVALID_ARG;
RootedValue metadata(cx);
nsresult rv = xpc::GetSandboxMetadata(cx, sandbox, &metadata);
NS_ENSURE_SUCCESS(rv, rv);
*rval = metadata;
return NS_OK;
}
NS_IMETHODIMP
nsXPCComponents_Utils::SetSandboxMetadata(const JS::Value &sandboxVal,
const JS::Value &metadataVal,
JSContext *cx)
{
if (!sandboxVal.isObject())
return NS_ERROR_INVALID_ARG;
RootedObject sandbox(cx, &sandboxVal.toObject());
sandbox = js::CheckedUnwrap(sandbox);
if (!sandbox || !xpc::IsSandbox(sandbox))
return NS_ERROR_INVALID_ARG;
RootedValue metadata(cx, metadataVal);
nsresult rv = xpc::SetSandboxMetadata(cx, sandbox, metadata);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
/* JSObject import (in AUTF8String registryLocation,
* [optional] in JSObject targetObj);
*/

View File

@ -3604,6 +3604,7 @@ struct SandboxOptions {
, wantExportHelpers(false)
, proto(xpc_GetSafeJSContext())
, sameZoneAs(xpc_GetSafeJSContext())
, metadata(xpc_GetSafeJSContext())
{ }
bool wantXrays;
@ -3613,6 +3614,7 @@ struct SandboxOptions {
nsCString sandboxName;
JS::RootedObject sameZoneAs;
DOMConstructors DOMConstructors;
JS::RootedValue metadata;
};
JSObject *
@ -3647,8 +3649,19 @@ EvalInSandbox(JSContext *cx, JS::HandleObject sandbox, const nsAString& source,
JSVersion jsVersion, bool returnStringOnly,
JS::MutableHandleValue rval);
// Helper for retrieving metadata stored in a reserved slot. The metadata
// is set during the sandbox creation using the "metadata" option.
nsresult
GetSandboxMetadata(JSContext *cx, JS::HandleObject sandboxArg,
JS::MutableHandleValue rval);
nsresult
SetSandboxMetadata(JSContext *cx, JS::HandleObject sandboxArg,
JS::HandleValue metadata);
} /* namespace xpc */
/***************************************************************************/
// Inlined utilities.

View File

@ -0,0 +1,45 @@
/* 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/. */
/* See https://bugzilla.mozilla.org/show_bug.cgi?id=898559 */
function run_test()
{
let sandbox = Components.utils.Sandbox("http://www.blah.com", {
metadata: "test metadata"
});
do_check_eq(Components.utils.getSandboxMetadata(sandbox), "test metadata");
let sandbox = Components.utils.Sandbox("http://www.blah.com", {
metadata: { foopy: { bar: 2 }, baz: "hi" }
});
let metadata = Components.utils.getSandboxMetadata(sandbox);
do_check_eq(metadata.baz, "hi");
do_check_eq(metadata.foopy.bar, 2);
metadata.baz = "foo";
metadata = Components.utils.getSandboxMetadata(sandbox);
do_check_eq(metadata.baz, "foo");
metadata = { foo: "bar" };
Components.utils.setSandboxMetadata(sandbox, metadata);
metadata.foo = "baz";
metadata = Components.utils.getSandboxMetadata(sandbox);
do_check_eq(metadata.foo, "bar");
let thrown = false;
let reflector = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Components.interfaces.nsIXMLHttpRequest);
try {
Components.utils.setSandboxMetadata(sandbox, { foo: reflector });
} catch(e) {
thrown = true;
}
do_check_eq(thrown, true);
}

View File

@ -51,6 +51,7 @@ fail-if = os == "android"
[test_allowedDomains.js]
[test_allowedDomainsXHR.js]
[test_nuke_sandbox.js]
[test_sandbox_metadata.js]
[test_exportFunction.js]
[test_textDecoder.js]
[test_watchdog_enable.js]