зеркало из https://github.com/mozilla/pjs.git
Bug 634156 - Come up with a way of creating an API in content that exposes real content objects without using a sandbox. r/sr=jst/mossop/gal
--HG-- extra : rebase_source : c3ca469ff33d099b51e140d0a274113884507a03
This commit is contained in:
Родитель
f7592ec269
Коммит
1ee16408c9
|
@ -95,24 +95,27 @@ ConsoleAPI.prototype = {
|
|||
|
||||
// We need to return an actual content object here, instead of a wrapped
|
||||
// chrome object. This allows things like console.log.bind() to work.
|
||||
let sandbox = Cu.Sandbox(aWindow);
|
||||
let contentObject = Cu.evalInSandbox(
|
||||
"(function(x) {\
|
||||
var bind = Function.bind;\
|
||||
var obj = {\
|
||||
log: bind.call(x.log, x),\
|
||||
info: bind.call(x.info, x),\
|
||||
warn: bind.call(x.warn, x),\
|
||||
error: bind.call(x.error, x),\
|
||||
debug: bind.call(x.debug, x),\
|
||||
trace: bind.call(x.trace, x),\
|
||||
__noSuchMethod__: function() {}\
|
||||
};\
|
||||
Object.defineProperty(obj, '__mozillaConsole__', { value: true });\
|
||||
return obj;\
|
||||
})", sandbox)(chromeObject);
|
||||
let contentObj = Cu.createObjectIn(aWindow);
|
||||
function genPropDesc(fun) {
|
||||
return { enumerable: true, configurable: true, writable: true,
|
||||
value: chromeObject[fun].bind(chromeObject) };
|
||||
}
|
||||
const properties = {
|
||||
log: genPropDesc('log'),
|
||||
info: genPropDesc('info'),
|
||||
warn: genPropDesc('warn'),
|
||||
error: genPropDesc('error'),
|
||||
debug: genPropDesc('debug'),
|
||||
trace: genPropDesc('trace'),
|
||||
__noSuchMethod__: { enumerable: true, configurable: true, writable: true,
|
||||
value: function() {} },
|
||||
__mozillaConsole__: { value: true }
|
||||
};
|
||||
|
||||
return contentObject;
|
||||
Object.defineProperties(contentObj, properties);
|
||||
Cu.makeObjectPropsNormal(contentObj);
|
||||
|
||||
return contentObj;
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -44,6 +44,10 @@
|
|||
#include "nsIComponentManager.idl"
|
||||
#include "nsIScriptableInterfaces.idl"
|
||||
|
||||
%{C++
|
||||
#include "jspubtd.h"
|
||||
%}
|
||||
|
||||
interface xpcIJSWeakReference;
|
||||
|
||||
/**
|
||||
|
@ -123,7 +127,7 @@ interface nsIXPCComponents_utils_Sandbox : nsISupports
|
|||
/**
|
||||
* interface of Components.utils
|
||||
*/
|
||||
[scriptable, uuid(5f0acf45-135a-48d1-976c-082ce3b24ead)]
|
||||
[scriptable, uuid(45857850-a08e-4fe9-a582-77fe03e3676f)]
|
||||
interface nsIXPCComponents_Utils : nsISupports
|
||||
{
|
||||
|
||||
|
@ -237,6 +241,23 @@ interface nsIXPCComponents_Utils : nsISupports
|
|||
* @return the corresponding global.
|
||||
*/
|
||||
void /* JSObject */ getGlobalForObject(/* in JSObject obj */);
|
||||
|
||||
/*
|
||||
* To be called from JS only.
|
||||
*
|
||||
* Returns an object created in |vobj|'s compartment.
|
||||
*/
|
||||
[implicit_jscontext]
|
||||
jsval createObjectIn(in jsval vobj);
|
||||
|
||||
/*
|
||||
* To be called from JS only.
|
||||
*
|
||||
* Ensures that all functions come from vobj's scope (and aren't cross
|
||||
* compartment wrappers).
|
||||
*/
|
||||
[implicit_jscontext]
|
||||
void makeObjectPropsNormal(in jsval vobj);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -3831,6 +3831,106 @@ nsXPCComponents_Utils::GetGlobalForObject()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
/* jsval createObjectIn(in jsval vobj); */
|
||||
NS_IMETHODIMP
|
||||
nsXPCComponents_Utils::CreateObjectIn(const jsval &vobj, JSContext *cx, jsval *rval)
|
||||
{
|
||||
if (!cx)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// first argument must be an object
|
||||
if(JSVAL_IS_PRIMITIVE(vobj))
|
||||
return NS_ERROR_XPC_BAD_CONVERT_JS;
|
||||
|
||||
JSObject *scope = JSVAL_TO_OBJECT(vobj)->unwrap();
|
||||
JSObject *obj;
|
||||
{
|
||||
JSAutoEnterCompartment ac;
|
||||
if(!ac.enter(cx, scope))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
obj = JS_NewObject(cx, nsnull, nsnull, scope);
|
||||
if (!obj)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!JS_WrapObject(cx, &obj))
|
||||
return NS_ERROR_FAILURE;
|
||||
*rval = OBJECT_TO_JSVAL(obj);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JSBool
|
||||
FunctionWrapper(JSContext *cx, uintN argc, jsval *vp)
|
||||
{
|
||||
jsval v;
|
||||
if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)), 0, &v))
|
||||
return JS_FALSE;
|
||||
NS_ASSERTION(JSVAL_IS_OBJECT(v), "weird function");
|
||||
|
||||
return JS_CallFunctionValue(cx, JS_THIS_OBJECT(cx, vp), v,
|
||||
argc, JS_ARGV(cx, vp), vp);
|
||||
}
|
||||
|
||||
JSBool
|
||||
WrapCallable(JSContext *cx, JSObject *obj, jsid id, JSObject *propobj, jsval *vp)
|
||||
{
|
||||
JSFunction *fun = JS_NewFunctionById(cx, FunctionWrapper, 0, 0,
|
||||
JS_GetGlobalForObject(cx, obj), id);
|
||||
if (!fun)
|
||||
return JS_FALSE;
|
||||
|
||||
JSObject *funobj = JS_GetFunctionObject(fun);
|
||||
if (!JS_SetReservedSlot(cx, funobj, 0, OBJECT_TO_JSVAL(propobj)))
|
||||
return JS_FALSE;
|
||||
*vp = OBJECT_TO_JSVAL(funobj);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* void makeObjectPropsNormal(jsval vobj); */
|
||||
NS_IMETHODIMP
|
||||
nsXPCComponents_Utils::MakeObjectPropsNormal(const jsval &vobj, JSContext *cx)
|
||||
{
|
||||
if (!cx)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// first argument must be an object
|
||||
if(JSVAL_IS_PRIMITIVE(vobj))
|
||||
return NS_ERROR_XPC_BAD_CONVERT_JS;
|
||||
|
||||
JSObject *obj = JSVAL_TO_OBJECT(vobj)->unwrap();
|
||||
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(cx, obj))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
js::AutoIdArray ida(cx, JS_Enumerate(cx, obj));
|
||||
if (!ida)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
for (size_t i = 0; i < ida.length(); ++i) {
|
||||
jsid id = ida[i];
|
||||
jsval v;
|
||||
|
||||
if (!JS_GetPropertyById(cx, obj, id, &v))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (JSVAL_IS_PRIMITIVE(v))
|
||||
continue;
|
||||
|
||||
JSObject *propobj = JSVAL_TO_OBJECT(v);
|
||||
// TODO Deal with non-functions.
|
||||
if (!propobj->isWrapper() || !propobj->isCallable())
|
||||
continue;
|
||||
|
||||
if (!WrapCallable(cx, obj, id, propobj, &v) ||
|
||||
!JS_SetPropertyById(cx, obj, id, &v))
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* string canCreateWrapper (in nsIIDPtr iid); */
|
||||
NS_IMETHODIMP
|
||||
nsXPCComponents_Utils::CanCreateWrapper(const nsIID * iid, char **_retval)
|
||||
|
|
|
@ -66,6 +66,7 @@ _CHROME_FILES = \
|
|||
test_bug596580.xul \
|
||||
test_bug654370.xul \
|
||||
test_bug658560.xul \
|
||||
test_APIExposer.xul \
|
||||
$(NULL)
|
||||
|
||||
# Disabled until this test gets updated to test the new proxy based
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=634156
|
||||
-->
|
||||
<window title="Testing API exposing capabilities"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=634156"
|
||||
target="_blank">Mozilla Bug 634156</a>
|
||||
</body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript"><![CDATA[
|
||||
const Cu = Components.utils;
|
||||
|
||||
var sandbox = new Cu.Sandbox("about:blank");
|
||||
sandbox.ok = ok;
|
||||
sandbox.is = is;
|
||||
Cu.evalInSandbox("Object.defineProperty(Object.prototype, 'getProp', { get: function() { throw 'FAIL: called getter' }, set: function() { throw 'FAIL: called setter'; } })", sandbox);
|
||||
|
||||
var obj = Cu.createObjectIn(sandbox);
|
||||
is(Object.getPrototypeOf(obj), Cu.evalInSandbox("Object.prototype", sandbox),
|
||||
"Object is a sandbox object");
|
||||
|
||||
function genPropDesc(value) {
|
||||
return { enumerable: true, configurable: true, writable: true,
|
||||
value: value };
|
||||
}
|
||||
const props = {
|
||||
'getProp': genPropDesc(function() { ok(true, "called prop that shadowed a getter"); }),
|
||||
'argument': genPropDesc(function(arg) { is(arg, 42, "can pass arguments through"); }),
|
||||
'returnval': genPropDesc(function() { return 42; })
|
||||
};
|
||||
Object.defineProperties(obj, props);
|
||||
Cu.makeObjectPropsNormal(obj);
|
||||
|
||||
sandbox.api = obj;
|
||||
Cu.evalInSandbox("ok(Object.getPrototypeOf(api) === Object.prototype, 'we have the object we expected'); \
|
||||
api.getProp(); api.argument(42); is(api.returnval(), 42, 'return value was correct');\
|
||||
ok(typeof api.getProp === 'function', 'functions are functions');\
|
||||
ok(Object.getPrototypeOf(api.getProp) === Function.prototype, 'functions come from our scope');", sandbox);
|
||||
]]></script>
|
||||
</window>
|
|
@ -188,18 +188,22 @@ function createInstallTrigger(window) {
|
|||
}
|
||||
};
|
||||
|
||||
let sandbox = Cu.Sandbox(window);
|
||||
let obj = Cu.evalInSandbox(
|
||||
"(function (x) {\
|
||||
var bind = Function.bind;\
|
||||
return {\
|
||||
enabled: bind.call(x.enabled, x),\
|
||||
updateEnabled: bind.call(x.updateEnabled, x),\
|
||||
install: bind.call(x.install, x),\
|
||||
installChrome: bind.call(x.installChrome, x),\
|
||||
startSoftwareUpdate: bind.call(x.startSoftwareUpdate, x)\
|
||||
};\
|
||||
})", sandbox)(chromeObject);
|
||||
let obj = Cu.createObjectIn(window);
|
||||
function genPropDesc(fun) {
|
||||
return { enumerable: true, configurable: true, writable: true,
|
||||
value: chromeObject[fun].bind(chromeObject) };
|
||||
}
|
||||
const properties = {
|
||||
'enabled': genPropDesc('enabled'),
|
||||
'updateEnabled': genPropDesc('updateEnabled'),
|
||||
'install': genPropDesc('install'),
|
||||
'installChrome': genPropDesc('installChrome'),
|
||||
'startSoftwareUpdate': genPropDesc('startSoftwareUpdate')
|
||||
};
|
||||
|
||||
Object.defineProperties(obj, properties);
|
||||
|
||||
Cu.makeObjectPropsNormal(obj);
|
||||
|
||||
obj.SKIN = chromeObject.SKIN;
|
||||
obj.LOCALE = chromeObject.LOCALE;
|
||||
|
|
Загрузка…
Ссылка в новой задаче