Bug 522621 - Use namespaces in the wrapper code and generally clean up the internal interfaces between the wrappers. r=jst

This commit is contained in:
Blake Kaplan 2009-10-20 17:21:39 -07:00
parent 44e1ce7702
commit 2e37e51b5b
13 changed files with 1193 additions and 1139 deletions

View File

@ -244,7 +244,11 @@ XPC_COW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly);
static JSObject * static JSObject *
XPC_COW_WrappedObject(JSContext *cx, JSObject *obj); XPC_COW_WrappedObject(JSContext *cx, JSObject *obj);
JSExtendedClass sXPC_COW_JSClass = { using namespace XPCWrapper;
namespace ChromeObjectWrapper {
JSExtendedClass COWClass = {
// JSClass (JSExtendedClass.base) initialization // JSClass (JSExtendedClass.base) initialization
{ "ChromeObjectWrapper", { "ChromeObjectWrapper",
JSCLASS_NEW_RESOLVE | JSCLASS_IS_EXTENDED | JSCLASS_NEW_RESOLVE | JSCLASS_IS_EXTENDED |
@ -268,11 +272,43 @@ JSExtendedClass sXPC_COW_JSClass = {
JSCLASS_NO_RESERVED_MEMBERS JSCLASS_NO_RESERVED_MEMBERS
}; };
JSBool
WrapObject(JSContext *cx, JSObject *parent, jsval v, jsval *vp)
{
JSObject *wrapperObj =
JS_NewObjectWithGivenProto(cx, &COWClass.base, NULL, parent);
if (!wrapperObj) {
return JS_FALSE;
}
*vp = OBJECT_TO_JSVAL(wrapperObj);
jsval exposedProps = JSVAL_VOID;
JSAutoTempValueRooter tvr(cx, 1, &exposedProps);
if (!GetExposedProperties(cx, JSVAL_TO_OBJECT(v), &exposedProps)) {
return JS_FALSE;
}
if (!JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sWrappedObjSlot, v) ||
!JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sFlagsSlot,
JSVAL_ZERO) ||
!JS_SetReservedSlot(cx, wrapperObj, sExposedPropsSlot, exposedProps)) {
return JS_FALSE;
}
return JS_TRUE;
}
} // namespace ChromeObjectWrapper
using namespace ChromeObjectWrapper;
// Throws an exception on context |cx|. // Throws an exception on context |cx|.
static inline JSBool static inline JSBool
ThrowException(nsresult rv, JSContext *cx) ThrowException(nsresult rv, JSContext *cx)
{ {
return XPCWrapper::ThrowException(rv, cx); return XPCWrapper::DoThrowException(rv, cx);
} }
// Like GetWrappedObject, but works on other types of wrappers, too. // Like GetWrappedObject, but works on other types of wrappers, too.
@ -305,7 +341,7 @@ static inline
JSObject * JSObject *
GetWrapper(JSObject *obj) GetWrapper(JSObject *obj)
{ {
while (STOBJ_GET_CLASS(obj) != &sXPC_COW_JSClass.base) { while (STOBJ_GET_CLASS(obj) != &COWClass.base) {
obj = STOBJ_GET_PROTO(obj); obj = STOBJ_GET_PROTO(obj);
if (!obj) { if (!obj) {
break; break;
@ -320,7 +356,7 @@ static inline
JSObject * JSObject *
GetWrappedObject(JSContext *cx, JSObject *wrapper) GetWrappedObject(JSContext *cx, JSObject *wrapper)
{ {
return XPCWrapper::UnwrapGeneric(cx, &sXPC_COW_JSClass, wrapper); return XPCWrapper::UnwrapGeneric(cx, &COWClass, wrapper);
} }
// Forward declaration for the function wrapper. // Forward declaration for the function wrapper.
@ -423,7 +459,7 @@ XPC_COW_RewrapForChrome(JSContext *cx, JSObject *wrapperObj, jsval *vp)
return XPCNativeWrapper::CreateExplicitWrapper(cx, wn, JS_TRUE, vp); return XPCNativeWrapper::CreateExplicitWrapper(cx, wn, JS_TRUE, vp);
} }
return XPC_SJOW_Construct(cx, obj, 1, vp, vp); return XPCSafeJSObjectWrapper::WrapObject(cx, obj, *vp, vp);
} }
JSBool JSBool
@ -444,8 +480,7 @@ XPC_COW_RewrapForContent(JSContext *cx, JSObject *wrapperObj, jsval *vp)
return XPC_COW_WrapFunction(cx, wrapperObj, obj, vp); return XPC_COW_WrapFunction(cx, wrapperObj, obj, vp);
} }
return XPC_COW_WrapObject(cx, JS_GetScopeChain(cx), OBJECT_TO_JSVAL(obj), return WrapObject(cx, JS_GetScopeChain(cx), OBJECT_TO_JSVAL(obj), vp);
vp);
} }
static JSBool static JSBool
@ -482,7 +517,7 @@ XPC_COW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
if (desc.attrs & (JSPROP_GETTER | JSPROP_SETTER)) { if (desc.attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
// Only chrome is allowed to add getters or setters to our object. // Only chrome is allowed to add getters or setters to our object.
if (!AllowedToAct(cx, id)) { if (!SystemOnlyWrapper::AllowedToAct(cx, id)) {
return JS_FALSE; return JS_FALSE;
} }
} }
@ -714,7 +749,7 @@ XPC_COW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly)
return nsnull; return nsnull;
} }
JSObject *wrapperIter = JS_NewObject(cx, &sXPC_COW_JSClass.base, nsnull, JSObject *wrapperIter = JS_NewObject(cx, &COWClass.base, nsnull,
JS_GetGlobalForObject(cx, obj)); JS_GetGlobalForObject(cx, obj));
if (!wrapperIter) { if (!wrapperIter) {
return nsnull; return nsnull;
@ -739,31 +774,3 @@ XPC_COW_WrappedObject(JSContext *cx, JSObject *obj)
{ {
return GetWrappedObject(cx, obj); return GetWrappedObject(cx, obj);
} }
JSBool
XPC_COW_WrapObject(JSContext *cx, JSObject *parent, jsval v, jsval *vp)
{
JSObject *wrapperObj =
JS_NewObjectWithGivenProto(cx, &sXPC_COW_JSClass.base, NULL, parent);
if (!wrapperObj) {
return JS_FALSE;
}
*vp = OBJECT_TO_JSVAL(wrapperObj);
jsval exposedProps = JSVAL_VOID;
JSAutoTempValueRooter tvr(cx, 1, &exposedProps);
if (!GetExposedProperties(cx, JSVAL_TO_OBJECT(v), &exposedProps)) {
return JS_FALSE;
}
if (!JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sWrappedObjSlot, v) ||
!JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sFlagsSlot,
JSVAL_ZERO) ||
!JS_SetReservedSlot(cx, wrapperObj, sExposedPropsSlot, exposedProps)) {
return JS_FALSE;
}
return JS_TRUE;
}

View File

@ -96,7 +96,63 @@ XPC_XOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly);
static JSObject * static JSObject *
XPC_XOW_WrappedObject(JSContext *cx, JSObject *obj); XPC_XOW_WrappedObject(JSContext *cx, JSObject *obj);
JSExtendedClass sXPC_XOW_JSClass = { // The slot that we stick our scope into.
// This is used in the finalizer to see if we actually need to remove
// ourselves from our scope's map. Because we cannot outlive our scope
// (the parent link ensures this), we know that, when we're being
// finalized, either our scope is still alive (i.e. we became garbage
// due to no more references) or it is being garbage collected right now.
// Therefore, we can look in gDyingScopes, and if our scope is there,
// then the map is about to be destroyed anyway, so we don't need to
// do anything.
static const int XPC_XOW_ScopeSlot = XPCWrapper::sNumSlots;
static const int sUXPCObjectSlot = XPCWrapper::sNumSlots + 1;
using namespace XPCWrapper;
// Throws an exception on context |cx|.
static inline
JSBool
ThrowException(nsresult ex, JSContext *cx)
{
XPCWrapper::DoThrowException(ex, cx);
return JS_FALSE;
}
// Get the (possibly non-existant) XOW off of an object
static inline
JSObject *
GetWrapper(JSObject *obj)
{
while (STOBJ_GET_CLASS(obj) != &XPCCrossOriginWrapper::XOWClass.base) {
obj = STOBJ_GET_PROTO(obj);
if (!obj) {
break;
}
}
return obj;
}
static inline
JSObject *
GetWrappedObject(JSContext *cx, JSObject *wrapper)
{
return XPCWrapper::UnwrapGeneric(cx, &XPCCrossOriginWrapper::XOWClass, wrapper);
}
static JSBool
XPC_XOW_FunctionWrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval);
// This flag is set on objects that were created for UniversalXPConnect-
// enabled code.
static const PRUint32 FLAG_IS_UXPC_OBJECT = XPCWrapper::LAST_FLAG << 1;
namespace XPCCrossOriginWrapper {
JSExtendedClass XOWClass = {
// JSClass (JSExtendedClass.base) initialization // JSClass (JSExtendedClass.base) initialization
{ "XPCCrossOriginWrapper", { "XPCCrossOriginWrapper",
JSCLASS_NEW_RESOLVE | JSCLASS_IS_EXTENDED | JSCLASS_NEW_RESOLVE | JSCLASS_IS_EXTENDED |
@ -120,56 +176,8 @@ JSExtendedClass sXPC_XOW_JSClass = {
JSCLASS_NO_RESERVED_MEMBERS JSCLASS_NO_RESERVED_MEMBERS
}; };
// The slot that we stick our scope into.
// This is used in the finalizer to see if we actually need to remove
// ourselves from our scope's map. Because we cannot outlive our scope
// (the parent link ensures this), we know that, when we're being
// finalized, either our scope is still alive (i.e. we became garbage
// due to no more references) or it is being garbage collected right now.
// Therefore, we can look in gDyingScopes, and if our scope is there,
// then the map is about to be destroyed anyway, so we don't need to
// do anything.
static const int XPC_XOW_ScopeSlot = XPCWrapper::sNumSlots;
static const int sUXPCObjectSlot = XPCWrapper::sNumSlots + 1;
static JSBool
XPC_XOW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval);
// Throws an exception on context |cx|.
static inline
JSBool JSBool
ThrowException(nsresult ex, JSContext *cx) WrapperMoved(JSContext *cx, XPCWrappedNative *innerObj,
{
XPCThrower::Throw(ex, cx);
return JS_FALSE;
}
// Get the (possibly non-existant) XOW off of an object
static inline
JSObject *
GetWrapper(JSObject *obj)
{
while (STOBJ_GET_CLASS(obj) != &sXPC_XOW_JSClass.base) {
obj = STOBJ_GET_PROTO(obj);
if (!obj) {
break;
}
}
return obj;
}
static inline
JSObject *
GetWrappedObject(JSContext *cx, JSObject *wrapper)
{
return XPCWrapper::UnwrapGeneric(cx, &sXPC_XOW_JSClass, wrapper);
}
JSBool
XPC_XOW_WrapperMoved(JSContext *cx, XPCWrappedNative *innerObj,
XPCWrappedNativeScope *newScope) XPCWrappedNativeScope *newScope)
{ {
typedef WrappedNative2WrapperMap::Link Link; typedef WrappedNative2WrapperMap::Link Link;
@ -206,36 +214,6 @@ XPC_XOW_WrapperMoved(JSContext *cx, XPCWrappedNative *innerObj,
JS_SetParent(cx, xow, newScope->GetGlobalJSObject()); JS_SetParent(cx, xow, newScope->GetGlobalJSObject());
} }
static JSBool
IsValFrame(JSObject *obj, jsval v, XPCWrappedNative *wn)
{
// Fast path for the common case.
if (STOBJ_GET_CLASS(obj)->name[0] != 'W') {
return JS_FALSE;
}
nsCOMPtr<nsIDOMWindow> domwin(do_QueryWrappedNative(wn));
if (!domwin) {
return JS_FALSE;
}
nsCOMPtr<nsIDOMWindowCollection> col;
domwin->GetFrames(getter_AddRefs(col));
if (!col) {
return JS_FALSE;
}
if (JSVAL_IS_INT(v)) {
col->Item(JSVAL_TO_INT(v), getter_AddRefs(domwin));
} else {
nsAutoString str(reinterpret_cast<PRUnichar *>
(JS_GetStringChars(JSVAL_TO_STRING(v))));
col->NamedItem(str, getter_AddRefs(domwin));
}
return domwin != nsnull;
}
// Returns whether the currently executing code is allowed to access // Returns whether the currently executing code is allowed to access
// the wrapper. Uses nsIPrincipal::Subsumes. // the wrapper. Uses nsIPrincipal::Subsumes.
// |cx| must be the top context on the context stack. // |cx| must be the top context on the context stack.
@ -308,96 +286,8 @@ CanAccessWrapper(JSContext *cx, JSObject *wrappedObj, JSBool *privilegeEnabled)
return rv; return rv;
} }
static JSBool
WrapSameOriginProp(JSContext *cx, JSObject *outerObj, jsval *vp);
static JSBool
XPC_XOW_FunctionWrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
{
JSObject *wrappedObj, *outerObj = obj;
// Allow 'this' to be either an XOW, in which case we unwrap it.
// We disallow invalid XOWs that have no wrapped object. Otherwise,
// if it isn't an XOW, then pass it through as-is.
wrappedObj = GetWrapper(obj);
if (wrappedObj) {
wrappedObj = GetWrappedObject(cx, wrappedObj);
if (!wrappedObj) {
return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx);
}
} else {
wrappedObj = obj;
}
JSObject *funObj = JSVAL_TO_OBJECT(argv[-2]);
jsval funToCall;
if (!JS_GetReservedSlot(cx, funObj, XPCWrapper::eWrappedFunctionSlot,
&funToCall)) {
return JS_FALSE;
}
JSFunction *fun = JS_ValueToFunction(cx, funToCall);
if (!fun) {
return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx);
}
XPCCallContext ccx(JS_CALLER, cx);
if (!ccx.IsValid()) {
return ThrowException(NS_ERROR_FAILURE, cx);
}
nsresult rv = CanAccessWrapper(cx, JSVAL_TO_OBJECT(funToCall), nsnull);
if (NS_FAILED(rv) && rv != NS_ERROR_DOM_PROP_ACCESS_DENIED) {
return ThrowException(rv, cx);
}
#ifdef DEBUG
JSNative native = JS_GetFunctionNative(cx, fun);
NS_ASSERTION(native, "How'd we get here with a scripted function?");
#endif
if (!JS_CallFunctionValue(cx, wrappedObj, funToCall, argc, argv, rval)) {
return JS_FALSE;
}
if (NS_SUCCEEDED(rv)) {
return WrapSameOriginProp(cx, outerObj, rval);
}
return XPC_XOW_RewrapIfNeeded(cx, obj, rval);
}
static JSBool
WrapSameOriginProp(JSContext *cx, JSObject *outerObj, jsval *vp)
{
// Don't call XPC_XOW_RewrapIfNeeded for same origin properties. We only
// need to wrap window, document and location.
if (JSVAL_IS_PRIMITIVE(*vp)) {
return JS_TRUE;
}
JSObject *wrappedObj = JSVAL_TO_OBJECT(*vp);
JSClass *clasp = STOBJ_GET_CLASS(wrappedObj);
if (XPC_XOW_ClassNeedsXOW(clasp->name)) {
return XPC_XOW_WrapObject(cx, JS_GetGlobalForObject(cx, outerObj), vp);
}
// Check if wrappedObj is an XOW. If so, verify that it's from the
// right scope.
if (clasp == &sXPC_XOW_JSClass.base &&
STOBJ_GET_PARENT(wrappedObj) != STOBJ_GET_PARENT(outerObj)) {
*vp = OBJECT_TO_JSVAL(GetWrappedObject(cx, wrappedObj));
return XPC_XOW_WrapObject(cx, STOBJ_GET_PARENT(outerObj), vp);
}
return JS_TRUE;
}
JSBool JSBool
XPC_XOW_WrapFunction(JSContext *cx, JSObject *outerObj, JSObject *funobj, WrapFunction(JSContext *cx, JSObject *outerObj, JSObject *funobj, jsval *rval)
jsval *rval)
{ {
jsval funobjVal = OBJECT_TO_JSVAL(funobj); jsval funobjVal = OBJECT_TO_JSVAL(funobj);
JSFunction *wrappedFun = JSFunction *wrappedFun =
@ -420,10 +310,8 @@ XPC_XOW_WrapFunction(JSContext *cx, JSObject *outerObj, JSObject *funobj,
JSObject *funWrapperObj = JS_GetFunctionObject(funWrapper); JSObject *funWrapperObj = JS_GetFunctionObject(funWrapper);
*rval = OBJECT_TO_JSVAL(funWrapperObj); *rval = OBJECT_TO_JSVAL(funWrapperObj);
if (!JS_SetReservedSlot(cx, funWrapperObj, XPCWrapper::eWrappedFunctionSlot, if (!JS_SetReservedSlot(cx, funWrapperObj, eWrappedFunctionSlot, funobjVal) ||
funobjVal) || !JS_SetReservedSlot(cx, funWrapperObj, eAllAccessSlot, JSVAL_FALSE)) {
!JS_SetReservedSlot(cx, funWrapperObj, XPCWrapper::eAllAccessSlot,
JSVAL_FALSE)) {
return JS_FALSE; return JS_FALSE;
} }
@ -431,7 +319,7 @@ XPC_XOW_WrapFunction(JSContext *cx, JSObject *outerObj, JSObject *funobj,
} }
JSBool JSBool
XPC_XOW_RewrapIfNeeded(JSContext *cx, JSObject *outerObj, jsval *vp) RewrapIfNeeded(JSContext *cx, JSObject *outerObj, jsval *vp)
{ {
// Don't need to wrap primitive values. // Don't need to wrap primitive values.
if (JSVAL_IS_PRIMITIVE(*vp)) { if (JSVAL_IS_PRIMITIVE(*vp)) {
@ -441,23 +329,22 @@ XPC_XOW_RewrapIfNeeded(JSContext *cx, JSObject *outerObj, jsval *vp)
JSObject *obj = JSVAL_TO_OBJECT(*vp); JSObject *obj = JSVAL_TO_OBJECT(*vp);
if (JS_ObjectIsFunction(cx, obj)) { if (JS_ObjectIsFunction(cx, obj)) {
return XPC_XOW_WrapFunction(cx, outerObj, obj, vp); return WrapFunction(cx, outerObj, obj, vp);
} }
XPCWrappedNative *wn = nsnull; XPCWrappedNative *wn = nsnull;
if (STOBJ_GET_CLASS(obj) == &sXPC_XOW_JSClass.base && if (STOBJ_GET_CLASS(obj) == &XOWClass.base &&
STOBJ_GET_PARENT(outerObj) != STOBJ_GET_PARENT(obj)) { STOBJ_GET_PARENT(outerObj) != STOBJ_GET_PARENT(obj)) {
*vp = OBJECT_TO_JSVAL(GetWrappedObject(cx, obj)); *vp = OBJECT_TO_JSVAL(GetWrappedObject(cx, obj));
} else if (!(wn = XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(cx, obj))) { } else if (!(wn = XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(cx, obj))) {
return JS_TRUE; return JS_TRUE;
} }
return XPC_XOW_WrapObject(cx, JS_GetGlobalForObject(cx, outerObj), vp, wn); return WrapObject(cx, JS_GetGlobalForObject(cx, outerObj), vp, wn);
} }
JSBool JSBool
XPC_XOW_WrapObject(JSContext *cx, JSObject *parent, jsval *vp, WrapObject(JSContext *cx, JSObject *parent, jsval *vp, XPCWrappedNative* wn)
XPCWrappedNative* wn)
{ {
NS_ASSERTION(XPCPerThreadData::IsMainThread(cx), NS_ASSERTION(XPCPerThreadData::IsMainThread(cx),
"Can't do this off the main thread!"); "Can't do this off the main thread!");
@ -467,7 +354,7 @@ XPC_XOW_WrapObject(JSContext *cx, JSObject *parent, jsval *vp,
JSObject *wrappedObj; JSObject *wrappedObj;
if (!JSVAL_IS_OBJECT(*vp) || if (!JSVAL_IS_OBJECT(*vp) ||
!(wrappedObj = JSVAL_TO_OBJECT(*vp)) || !(wrappedObj = JSVAL_TO_OBJECT(*vp)) ||
STOBJ_GET_CLASS(wrappedObj) == &sXPC_XOW_JSClass.base) { STOBJ_GET_CLASS(wrappedObj) == &XOWClass.base) {
return JS_TRUE; return JS_TRUE;
} }
@ -506,7 +393,7 @@ XPC_XOW_WrapObject(JSContext *cx, JSObject *parent, jsval *vp,
outerObj = map->Find(wrappedObj); outerObj = map->Find(wrappedObj);
if (outerObj) { if (outerObj) {
NS_ASSERTION(STOBJ_GET_CLASS(outerObj) == &sXPC_XOW_JSClass.base, NS_ASSERTION(STOBJ_GET_CLASS(outerObj) == &XOWClass.base,
"What crazy object are we getting here?"); "What crazy object are we getting here?");
#ifdef DEBUG_mrbkap_off #ifdef DEBUG_mrbkap_off
printf("But found a wrapper in the map %p!\n", (void *)outerObj); printf("But found a wrapper in the map %p!\n", (void *)outerObj);
@ -515,15 +402,14 @@ XPC_XOW_WrapObject(JSContext *cx, JSObject *parent, jsval *vp,
return JS_TRUE; return JS_TRUE;
} }
outerObj = JS_NewObjectWithGivenProto(cx, &sXPC_XOW_JSClass.base, nsnull, outerObj = JS_NewObjectWithGivenProto(cx, &XOWClass.base, nsnull,
parent); parent);
if (!outerObj) { if (!outerObj) {
return JS_FALSE; return JS_FALSE;
} }
if (!JS_SetReservedSlot(cx, outerObj, XPCWrapper::sWrappedObjSlot, *vp) || if (!JS_SetReservedSlot(cx, outerObj, sWrappedObjSlot, *vp) ||
!JS_SetReservedSlot(cx, outerObj, XPCWrapper::sFlagsSlot, !JS_SetReservedSlot(cx, outerObj, sFlagsSlot, JSVAL_ZERO) ||
JSVAL_ZERO) ||
!JS_SetReservedSlot(cx, outerObj, XPC_XOW_ScopeSlot, !JS_SetReservedSlot(cx, outerObj, XPC_XOW_ScopeSlot,
PRIVATE_TO_JSVAL(parentScope))) { PRIVATE_TO_JSVAL(parentScope))) {
return JS_FALSE; return JS_FALSE;
@ -536,6 +422,130 @@ XPC_XOW_WrapObject(JSContext *cx, JSObject *parent, jsval *vp,
return JS_TRUE; return JS_TRUE;
} }
} // namespace XPCCrossOriginWrapper
using namespace XPCCrossOriginWrapper;
static JSBool
XPC_XOW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval);
static JSBool
IsValFrame(JSObject *obj, jsval v, XPCWrappedNative *wn)
{
// Fast path for the common case.
if (STOBJ_GET_CLASS(obj)->name[0] != 'W') {
return JS_FALSE;
}
nsCOMPtr<nsIDOMWindow> domwin(do_QueryWrappedNative(wn));
if (!domwin) {
return JS_FALSE;
}
nsCOMPtr<nsIDOMWindowCollection> col;
domwin->GetFrames(getter_AddRefs(col));
if (!col) {
return JS_FALSE;
}
if (JSVAL_IS_INT(v)) {
col->Item(JSVAL_TO_INT(v), getter_AddRefs(domwin));
} else {
nsAutoString str(reinterpret_cast<PRUnichar *>
(JS_GetStringChars(JSVAL_TO_STRING(v))));
col->NamedItem(str, getter_AddRefs(domwin));
}
return domwin != nsnull;
}
static JSBool
WrapSameOriginProp(JSContext *cx, JSObject *outerObj, jsval *vp);
static JSBool
XPC_XOW_FunctionWrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
{
JSObject *wrappedObj, *outerObj = obj;
// Allow 'this' to be either an XOW, in which case we unwrap it.
// We disallow invalid XOWs that have no wrapped object. Otherwise,
// if it isn't an XOW, then pass it through as-is.
wrappedObj = GetWrapper(obj);
if (wrappedObj) {
wrappedObj = GetWrappedObject(cx, wrappedObj);
if (!wrappedObj) {
return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx);
}
} else {
wrappedObj = obj;
}
JSObject *funObj = JSVAL_TO_OBJECT(argv[-2]);
jsval funToCall;
if (!JS_GetReservedSlot(cx, funObj, eWrappedFunctionSlot, &funToCall)) {
return JS_FALSE;
}
JSFunction *fun = JS_ValueToFunction(cx, funToCall);
if (!fun) {
return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx);
}
XPCCallContext ccx(JS_CALLER, cx);
if (!ccx.IsValid()) {
return ThrowException(NS_ERROR_FAILURE, cx);
}
nsresult rv = CanAccessWrapper(cx, JSVAL_TO_OBJECT(funToCall), nsnull);
if (NS_FAILED(rv) && rv != NS_ERROR_DOM_PROP_ACCESS_DENIED) {
return ThrowException(rv, cx);
}
#ifdef DEBUG
JSNative native = JS_GetFunctionNative(cx, fun);
NS_ASSERTION(native, "How'd we get here with a scripted function?");
#endif
if (!JS_CallFunctionValue(cx, wrappedObj, funToCall, argc, argv, rval)) {
return JS_FALSE;
}
if (NS_SUCCEEDED(rv)) {
return WrapSameOriginProp(cx, outerObj, rval);
}
return RewrapIfNeeded(cx, obj, rval);
}
static JSBool
WrapSameOriginProp(JSContext *cx, JSObject *outerObj, jsval *vp)
{
// Don't call RewrapIfNeeded for same origin properties. We only
// need to wrap window, document and location.
if (JSVAL_IS_PRIMITIVE(*vp)) {
return JS_TRUE;
}
JSObject *wrappedObj = JSVAL_TO_OBJECT(*vp);
JSClass *clasp = STOBJ_GET_CLASS(wrappedObj);
if (ClassNeedsXOW(clasp->name)) {
return WrapObject(cx, JS_GetGlobalForObject(cx, outerObj), vp);
}
// Check if wrappedObj is an XOW. If so, verify that it's from the
// right scope.
if (clasp == &XOWClass.base &&
STOBJ_GET_PARENT(wrappedObj) != STOBJ_GET_PARENT(outerObj)) {
*vp = OBJECT_TO_JSVAL(GetWrappedObject(cx, wrappedObj));
return WrapObject(cx, STOBJ_GET_PARENT(outerObj), vp);
}
return JS_TRUE;
}
static JSBool static JSBool
XPC_XOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) XPC_XOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{ {
@ -544,7 +554,7 @@ XPC_XOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
obj = GetWrapper(obj); obj = GetWrapper(obj);
jsval resolving; jsval resolving;
if (!JS_GetReservedSlot(cx, obj, XPCWrapper::sFlagsSlot, &resolving)) { if (!JS_GetReservedSlot(cx, obj, sFlagsSlot, &resolving)) {
return JS_FALSE; return JS_FALSE;
} }
@ -574,7 +584,7 @@ XPC_XOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
} }
// Same origin, pass this request along. // Same origin, pass this request along.
return XPCWrapper::AddProperty(cx, obj, JS_TRUE, wrappedObj, id, vp); return AddProperty(cx, obj, JS_TRUE, wrappedObj, id, vp);
} }
static JSBool static JSBool
@ -600,7 +610,7 @@ XPC_XOW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
} }
// Same origin, pass this request along. // Same origin, pass this request along.
return XPCWrapper::DelProperty(cx, wrappedObj, id, vp); return DelProperty(cx, wrappedObj, id, vp);
} }
static JSBool static JSBool
@ -656,22 +666,21 @@ XPC_XOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp,
XPCWrappedNative::GetWrappedNativeOfJSObject(cx, wrappedObj); XPCWrappedNative::GetWrappedNativeOfJSObject(cx, wrappedObj);
NS_ASSERTION(wn, "How did we wrap a non-WrappedNative?"); NS_ASSERTION(wn, "How did we wrap a non-WrappedNative?");
if (!IsValFrame(wrappedObj, id, wn)) { if (!IsValFrame(wrappedObj, id, wn)) {
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); nsIScriptSecurityManager *ssm = GetSecurityManager();
if (!ssm) { if (!ssm) {
return ThrowException(NS_ERROR_NOT_INITIALIZED, cx); return ThrowException(NS_ERROR_NOT_INITIALIZED, cx);
} }
rv = ssm->CheckPropertyAccess(cx, wrappedObj, rv = ssm->CheckPropertyAccess(cx, wrappedObj,
STOBJ_GET_CLASS(wrappedObj)->name, STOBJ_GET_CLASS(wrappedObj)->name,
id, isSet ? XPCWrapper::sSecMgrSetProp id, isSet ? sSecMgrSetProp
: XPCWrapper::sSecMgrGetProp); : sSecMgrGetProp);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
// The security manager threw an exception for us. // The security manager threw an exception for us.
return JS_FALSE; return JS_FALSE;
} }
} }
return XPCWrapper::GetOrSetNativeProperty(cx, obj, wn, id, vp, isSet, return GetOrSetNativeProperty(cx, obj, wn, id, vp, isSet, JS_FALSE);
JS_FALSE);
} }
JSObject *proto = nsnull; // Initialize this to quiet GCC. JSObject *proto = nsnull; // Initialize this to quiet GCC.
@ -764,7 +773,7 @@ XPC_XOW_Enumerate(JSContext *cx, JSObject *obj)
return JS_FALSE; return JS_FALSE;
} }
return XPCWrapper::Enumerate(cx, obj, wrappedObj); return Enumerate(cx, obj, wrappedObj);
} }
// Because of the drastically different ways that same- and cross-origin XOWs // Because of the drastically different ways that same- and cross-origin XOWs
@ -785,10 +794,10 @@ XPC_XOW_Enumerate(JSContext *cx, JSObject *obj)
static JSObject * static JSObject *
GetUXPCObject(JSContext *cx, JSObject *obj) GetUXPCObject(JSContext *cx, JSObject *obj)
{ {
NS_ASSERTION(STOBJ_GET_CLASS(obj) == &sXPC_XOW_JSClass.base, "wrong object"); NS_ASSERTION(STOBJ_GET_CLASS(obj) == &XOWClass.base, "wrong object");
jsval v; jsval v;
if (!JS_GetReservedSlot(cx, obj, XPCWrapper::sFlagsSlot, &v)) { if (!JS_GetReservedSlot(cx, obj, sFlagsSlot, &v)) {
return nsnull; return nsnull;
} }
@ -805,7 +814,7 @@ GetUXPCObject(JSContext *cx, JSObject *obj)
} }
JSObject *uxpco = JSObject *uxpco =
JS_NewObjectWithGivenProto(cx, &sXPC_XOW_JSClass.base, nsnull, JS_NewObjectWithGivenProto(cx, &XOWClass.base, nsnull,
STOBJ_GET_PARENT(obj)); STOBJ_GET_PARENT(obj));
if (!uxpco) { if (!uxpco) {
return nsnull; return nsnull;
@ -814,13 +823,13 @@ GetUXPCObject(JSContext *cx, JSObject *obj)
JSAutoTempValueRooter tvr(cx, uxpco); JSAutoTempValueRooter tvr(cx, uxpco);
jsval wrappedObj, parentScope; jsval wrappedObj, parentScope;
if (!JS_GetReservedSlot(cx, obj, XPCWrapper::sWrappedObjSlot, &wrappedObj) || if (!JS_GetReservedSlot(cx, obj, sWrappedObjSlot, &wrappedObj) ||
!JS_GetReservedSlot(cx, obj, XPC_XOW_ScopeSlot, &parentScope)) { !JS_GetReservedSlot(cx, obj, XPC_XOW_ScopeSlot, &parentScope)) {
return nsnull; return nsnull;
} }
if (!JS_SetReservedSlot(cx, uxpco, XPCWrapper::sWrappedObjSlot, wrappedObj) || if (!JS_SetReservedSlot(cx, uxpco, sWrappedObjSlot, wrappedObj) ||
!JS_SetReservedSlot(cx, uxpco, XPCWrapper::sFlagsSlot, !JS_SetReservedSlot(cx, uxpco, sFlagsSlot,
INT_TO_JSVAL(FLAG_IS_UXPC_OBJECT)) || INT_TO_JSVAL(FLAG_IS_UXPC_OBJECT)) ||
!JS_SetReservedSlot(cx, uxpco, XPC_XOW_ScopeSlot, parentScope)) { !JS_SetReservedSlot(cx, uxpco, XPC_XOW_ScopeSlot, parentScope)) {
return nsnull; return nsnull;
@ -867,14 +876,14 @@ XPC_XOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
XPCWrappedNative::GetWrappedNativeOfJSObject(cx, wrappedObj); XPCWrappedNative::GetWrappedNativeOfJSObject(cx, wrappedObj);
NS_ASSERTION(wn, "How did we wrap a non-WrappedNative?"); NS_ASSERTION(wn, "How did we wrap a non-WrappedNative?");
if (!IsValFrame(wrappedObj, id, wn)) { if (!IsValFrame(wrappedObj, id, wn)) {
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); nsIScriptSecurityManager *ssm = GetSecurityManager();
if (!ssm) { if (!ssm) {
return ThrowException(NS_ERROR_NOT_INITIALIZED, cx); return ThrowException(NS_ERROR_NOT_INITIALIZED, cx);
} }
PRUint32 action = (flags & JSRESOLVE_ASSIGNING) PRUint32 action = (flags & JSRESOLVE_ASSIGNING)
? XPCWrapper::sSecMgrSetProp ? sSecMgrSetProp
: XPCWrapper::sSecMgrGetProp; : sSecMgrGetProp;
rv = ssm->CheckPropertyAccess(cx, wrappedObj, rv = ssm->CheckPropertyAccess(cx, wrappedObj,
STOBJ_GET_CLASS(wrappedObj)->name, STOBJ_GET_CLASS(wrappedObj)->name,
id, action); id, action);
@ -885,8 +894,8 @@ XPC_XOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
} }
// We're out! We're allowed to resolve this property. // We're out! We're allowed to resolve this property.
return XPCWrapper::ResolveNativeProperty(cx, obj, wrappedObj, wn, id, return ResolveNativeProperty(cx, obj, wrappedObj, wn, id,
flags, objp, JS_FALSE); flags, objp, JS_FALSE);
} }
@ -896,8 +905,8 @@ XPC_XOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
if (id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) { if (id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) {
jsval oldSlotVal; jsval oldSlotVal;
if (!JS_GetReservedSlot(cx, obj, XPCWrapper::sFlagsSlot, &oldSlotVal) || if (!JS_GetReservedSlot(cx, obj, sFlagsSlot, &oldSlotVal) ||
!JS_SetReservedSlot(cx, obj, XPCWrapper::sFlagsSlot, !JS_SetReservedSlot(cx, obj, sFlagsSlot,
INT_TO_JSVAL(JSVAL_TO_INT(oldSlotVal) | INT_TO_JSVAL(JSVAL_TO_INT(oldSlotVal) |
FLAG_RESOLVING))) { FLAG_RESOLVING))) {
return JS_FALSE; return JS_FALSE;
@ -906,7 +915,7 @@ XPC_XOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
JSBool ok = JS_DefineFunction(cx, obj, "toString", JSBool ok = JS_DefineFunction(cx, obj, "toString",
XPC_XOW_toString, 0, 0) != nsnull; XPC_XOW_toString, 0, 0) != nsnull;
JS_SetReservedSlot(cx, obj, XPCWrapper::sFlagsSlot, oldSlotVal); JS_SetReservedSlot(cx, obj, sFlagsSlot, oldSlotVal);
if (ok) { if (ok) {
*objp = obj; *objp = obj;
@ -915,7 +924,7 @@ XPC_XOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
return ok; return ok;
} }
return XPCWrapper::NewResolve(cx, obj, JS_TRUE, wrappedObj, id, flags, objp); return NewResolve(cx, obj, JS_TRUE, wrappedObj, id, flags, objp);
} }
static JSBool static JSBool
@ -962,7 +971,7 @@ XPC_XOW_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
return NS_SUCCEEDED(rv) return NS_SUCCEEDED(rv)
? WrapSameOriginProp(cx, obj, vp) ? WrapSameOriginProp(cx, obj, vp)
: XPC_XOW_RewrapIfNeeded(cx, obj, vp); : RewrapIfNeeded(cx, obj, vp);
} }
static void static void
@ -1037,7 +1046,7 @@ XPC_XOW_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
return JS_FALSE; return JS_FALSE;
} }
return XPC_XOW_RewrapIfNeeded(cx, callee, rval); return RewrapIfNeeded(cx, callee, rval);
} }
static JSBool static JSBool
@ -1070,7 +1079,7 @@ XPC_XOW_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
return JS_FALSE; return JS_FALSE;
} }
return XPC_XOW_RewrapIfNeeded(cx, wrappedObj, rval); return RewrapIfNeeded(cx, wrappedObj, rval);
} }
static JSBool static JSBool
@ -1123,8 +1132,8 @@ XPC_XOW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
} }
JSObject *test = JSVAL_TO_OBJECT(v); JSObject *test = JSVAL_TO_OBJECT(v);
if (STOBJ_GET_CLASS(test) == &sXPC_XOW_JSClass.base) { if (STOBJ_GET_CLASS(test) == &XOWClass.base) {
if (!JS_GetReservedSlot(cx, test, XPCWrapper::sWrappedObjSlot, &v)) { if (!JS_GetReservedSlot(cx, test, sWrappedObjSlot, &v)) {
return JS_FALSE; return JS_FALSE;
} }
@ -1181,7 +1190,7 @@ XPC_XOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly)
return nsnull; return nsnull;
} }
JSObject *wrapperIter = JS_NewObject(cx, &sXPC_XOW_JSClass.base, nsnull, JSObject *wrapperIter = JS_NewObject(cx, &XOWClass.base, nsnull,
JS_GetGlobalForObject(cx, obj)); JS_GetGlobalForObject(cx, obj));
if (!wrapperIter) { if (!wrapperIter) {
return nsnull; return nsnull;
@ -1191,16 +1200,14 @@ XPC_XOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly)
// Initialize our XOW. // Initialize our XOW.
jsval v = OBJECT_TO_JSVAL(wrappedObj); jsval v = OBJECT_TO_JSVAL(wrappedObj);
if (!JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sWrappedObjSlot, v) || if (!JS_SetReservedSlot(cx, wrapperIter, sWrappedObjSlot, v) ||
!JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sFlagsSlot, !JS_SetReservedSlot(cx, wrapperIter, sFlagsSlot, JSVAL_ZERO) ||
JSVAL_ZERO) ||
!JS_SetReservedSlot(cx, wrapperIter, XPC_XOW_ScopeSlot, !JS_SetReservedSlot(cx, wrapperIter, XPC_XOW_ScopeSlot,
PRIVATE_TO_JSVAL(nsnull))) { PRIVATE_TO_JSVAL(nsnull))) {
return nsnull; return nsnull;
} }
return XPCWrapper::CreateIteratorObj(cx, wrapperIter, obj, wrappedObj, return CreateIteratorObj(cx, wrapperIter, obj, wrappedObj, keysonly);
keysonly);
} }
static JSObject * static JSObject *
@ -1238,7 +1245,7 @@ XPC_XOW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
nsresult rv = CanAccessWrapper(cx, wrappedObj, nsnull); nsresult rv = CanAccessWrapper(cx, wrappedObj, nsnull);
if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) { if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) {
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); nsIScriptSecurityManager *ssm = GetSecurityManager();
if (!ssm) { if (!ssm) {
return ThrowException(NS_ERROR_NOT_INITIALIZED, cx); return ThrowException(NS_ERROR_NOT_INITIALIZED, cx);
} }
@ -1253,5 +1260,5 @@ XPC_XOW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
XPCWrappedNative *wn = XPCWrappedNative *wn =
XPCWrappedNative::GetWrappedNativeOfJSObject(cx, wrappedObj); XPCWrappedNative::GetWrappedNativeOfJSObject(cx, wrappedObj);
return XPCWrapper::NativeToString(cx, wn, argc, argv, rval, JS_FALSE); return NativeToString(cx, wn, argc, argv, rval, JS_FALSE);
} }

View File

@ -96,10 +96,23 @@ static JSBool
XPC_NW_FunctionWrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, XPC_NW_FunctionWrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval); jsval *rval);
using namespace XPCWrapper;
// Whether this XPCNativeWrapper should be a deep wrapper.
static const PRUint32 FLAG_DEEP = XPCWrapper::LAST_FLAG << 1;
// If this flag is set, then this XPCNativeWrapper is *not* the implicit
// wrapper stored in XPCWrappedNative::mWrapperWord. These wrappers may
// be exposed to content script and because they are not shared, they do
// not have expando properties set on implicit native wrappers.
static const PRUint32 FLAG_EXPLICIT = XPCWrapper::LAST_FLAG << 2;
namespace XPCNativeWrapper { namespace internal {
// JS class for XPCNativeWrapper (and this doubles as the constructor // JS class for XPCNativeWrapper (and this doubles as the constructor
// for XPCNativeWrapper for the moment too...) // for XPCNativeWrapper for the moment too...)
JSExtendedClass XPCNativeWrapper::sXPC_NW_JSClass = { JSExtendedClass NWClass = {
// JSClass (JSExtendedClass.base) initialization // JSClass (JSExtendedClass.base) initialization
{ "XPCNativeWrapper", { "XPCNativeWrapper",
JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS | JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS |
@ -125,6 +138,163 @@ JSExtendedClass XPCNativeWrapper::sXPC_NW_JSClass = {
JSCLASS_NO_RESERVED_MEMBERS JSCLASS_NO_RESERVED_MEMBERS
}; };
} // namespace internal
JSBool
GetWrappedNative(JSContext *cx, JSObject *obj,
XPCWrappedNative **aWrappedNative)
{
XPCWrappedNative *wn = static_cast<XPCWrappedNative *>(xpc_GetJSPrivate(obj));
*aWrappedNative = wn;
if (!wn) {
return JS_TRUE;
}
nsIScriptSecurityManager *ssm = GetSecurityManager();
if (!ssm) {
return JS_TRUE;
}
nsIPrincipal *subjectPrincipal = ssm->GetCxSubjectPrincipal(cx);
if (!subjectPrincipal) {
return JS_TRUE;
}
XPCWrappedNativeScope *scope = wn->GetScope();
nsIPrincipal *objectPrincipal = scope->GetPrincipal();
PRBool subsumes;
nsresult rv = subjectPrincipal->Subsumes(objectPrincipal, &subsumes);
if (NS_FAILED(rv) || !subsumes) {
PRBool isPrivileged;
rv = ssm->IsCapabilityEnabled("UniversalXPConnect", &isPrivileged);
return NS_SUCCEEDED(rv) && isPrivileged;
}
return JS_TRUE;
}
JSBool
WrapFunction(JSContext* cx, JSObject* funobj, jsval *rval)
{
// If funobj is already a wrapped function, just return it.
if (JS_GetFunctionNative(cx,
JS_ValueToFunction(cx, OBJECT_TO_JSVAL(funobj))) ==
XPC_NW_FunctionWrapper) {
*rval = OBJECT_TO_JSVAL(funobj);
return JS_TRUE;
}
// Ensure that we've been called from JS. Native code should extract
// the wrapped native and deal with that directly.
// XXX Can we simply trust |cx| here?
JSStackFrame *iterator = nsnull;
if (!::JS_FrameIterator(cx, &iterator)) {
::JS_ReportError(cx, "XPCNativeWrappers must be used from script");
return JS_FALSE;
}
// Create a new function that'll call our given function. This new
// function's parent will be the original function and that's how we
// get the right thing to call when this function is called.
// Note that we pass nsnull as the nominal parent so that we'll inherit
// our caller's Function.prototype.
JSFunction *funWrapper =
::JS_NewFunction(cx, XPC_NW_FunctionWrapper, 0, 0, nsnull,
"XPCNativeWrapper function wrapper");
if (!funWrapper) {
return JS_FALSE;
}
JSObject* funWrapperObj = ::JS_GetFunctionObject(funWrapper);
::JS_SetParent(cx, funWrapperObj, funobj);
*rval = OBJECT_TO_JSVAL(funWrapperObj);
JS_SetReservedSlot(cx, funWrapperObj, eAllAccessSlot, JSVAL_FALSE);
return JS_TRUE;
}
JSBool
RewrapIfDeepWrapper(JSContext *cx, JSObject *obj, jsval v, jsval *rval)
{
NS_ASSERTION(XPCNativeWrapper::IsNativeWrapper(obj),
"Unexpected object");
JSBool primitive = JSVAL_IS_PRIMITIVE(v);
JSObject* nativeObj = primitive ? nsnull : JSVAL_TO_OBJECT(v);
// We always want to wrap function objects, no matter whether we're deep.
if (!primitive && JS_ObjectIsFunction(cx, nativeObj)) {
return WrapFunction(cx, nativeObj, rval);
}
jsval flags;
::JS_GetReservedSlot(cx, obj, 0, &flags);
// Re-wrap non-primitive values if this is a deep wrapper, i.e.
// if (HAS_FLAGS(flags, FLAG_DEEP).
if (HAS_FLAGS(flags, FLAG_DEEP) && !primitive) {
// Unwrap a cross origin wrapper, since we're more restrictive.
if (STOBJ_GET_CLASS(nativeObj) == &XPCCrossOriginWrapper::XOWClass.base) {
if (!::JS_GetReservedSlot(cx, nativeObj, sWrappedObjSlot,
&v)) {
return JS_FALSE;
}
// If v is primitive, allow nativeObj to remain a cross origin wrapper,
// which will fail below (since it isn't a wrapped native).
if (!JSVAL_IS_PRIMITIVE(v)) {
nativeObj = JSVAL_TO_OBJECT(v);
}
}
XPCWrappedNative* wrappedNative =
XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(cx, nativeObj);
if (!wrappedNative)
return XPCSafeJSObjectWrapper::WrapObject(cx, nsnull, v, rval);
if (HAS_FLAGS(flags, FLAG_EXPLICIT)) {
#ifdef DEBUG_XPCNativeWrapper
printf("Rewrapping for deep explicit wrapper\n");
#endif
if (wrappedNative == XPCNativeWrapper::SafeGetWrappedNative(obj)) {
// Already wrapped, return the wrapper.
*rval = OBJECT_TO_JSVAL(obj);
return JS_TRUE;
}
// |obj| is an explicit deep wrapper. We want to construct another
// explicit deep wrapper for |v|.
return XPCNativeWrapper::CreateExplicitWrapper(cx, wrappedNative,
JS_TRUE, rval);
}
#ifdef DEBUG_XPCNativeWrapper
printf("Rewrapping for deep implicit wrapper\n");
#endif
// Just using GetNewOrUsed on the return value of
// GetWrappedNativeOfJSObject will give the right thing -- the unique deep
// implicit wrapper associated with wrappedNative.
JSObject* wrapperObj = XPCNativeWrapper::GetNewOrUsed(cx, wrappedNative,
nsnull);
if (!wrapperObj) {
return JS_FALSE;
}
*rval = OBJECT_TO_JSVAL(wrapperObj);
} else {
*rval = v;
}
return JS_TRUE;
}
} // namespace XPCNativeWrapper
using namespace XPCNativeWrapper;
// If one of our class hooks is ever called from a non-system script, bypass // If one of our class hooks is ever called from a non-system script, bypass
// the hook by calling the same hook on our wrapped native, with obj reset to // the hook by calling the same hook on our wrapped native, with obj reset to
// the wrapped native's flat JSObject, so the hook and args macro parameters // the wrapped native's flat JSObject, so the hook and args macro parameters
@ -204,7 +374,7 @@ JSBool
EnsureLegalActivity(JSContext *cx, JSObject *obj, EnsureLegalActivity(JSContext *cx, JSObject *obj,
jsval id = JSVAL_VOID, PRUint32 accessType = 0) jsval id = JSVAL_VOID, PRUint32 accessType = 0)
{ {
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); nsIScriptSecurityManager *ssm = GetSecurityManager();
if (!ssm) { if (!ssm) {
// If there's no security manager, then we're not running in a browser // If there's no security manager, then we're not running in a browser
// context: allow access. // context: allow access.
@ -243,8 +413,7 @@ EnsureLegalActivity(JSContext *cx, JSObject *obj,
JSObject* flatObj; JSObject* flatObj;
if (!JSVAL_IS_VOID(id) && if (!JSVAL_IS_VOID(id) &&
(accessType & (XPCWrapper::sSecMgrSetProp | (accessType & (sSecMgrSetProp | sSecMgrGetProp)) &&
XPCWrapper::sSecMgrGetProp)) &&
(flatObj = wn->GetFlatJSObject())) { (flatObj = wn->GetFlatJSObject())) {
rv = ssm->CheckPropertyAccess(cx, flatObj, rv = ssm->CheckPropertyAccess(cx, flatObj,
STOBJ_GET_CLASS(flatObj)->name, STOBJ_GET_CLASS(flatObj)->name,
@ -285,82 +454,6 @@ EnsureLegalActivity(JSContext *cx, JSObject *obj,
return ThrowException(NS_ERROR_XPC_SECURITY_MANAGER_VETO, cx); return ThrowException(NS_ERROR_XPC_SECURITY_MANAGER_VETO, cx);
} }
// static
JSBool
XPCNativeWrapper::GetWrappedNative(JSContext *cx, JSObject *obj,
XPCWrappedNative **aWrappedNative)
{
XPCWrappedNative *wn = static_cast<XPCWrappedNative *>(xpc_GetJSPrivate(obj));
*aWrappedNative = wn;
if (!wn) {
return JS_TRUE;
}
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
if (!ssm) {
return JS_TRUE;
}
nsIPrincipal *subjectPrincipal = ssm->GetCxSubjectPrincipal(cx);
if (!subjectPrincipal) {
return JS_TRUE;
}
XPCWrappedNativeScope *scope = wn->GetScope();
nsIPrincipal *objectPrincipal = scope->GetPrincipal();
PRBool subsumes;
nsresult rv = subjectPrincipal->Subsumes(objectPrincipal, &subsumes);
if (NS_FAILED(rv) || !subsumes) {
PRBool isPrivileged;
rv = ssm->IsCapabilityEnabled("UniversalXPConnect", &isPrivileged);
return NS_SUCCEEDED(rv) && isPrivileged;
}
return JS_TRUE;
}
JSBool
XPC_NW_WrapFunction(JSContext* cx, JSObject* funobj, jsval *rval)
{
// If funobj is already a wrapped function, just return it.
if (JS_GetFunctionNative(cx,
JS_ValueToFunction(cx, OBJECT_TO_JSVAL(funobj))) ==
XPC_NW_FunctionWrapper) {
*rval = OBJECT_TO_JSVAL(funobj);
return JS_TRUE;
}
// Ensure that we've been called from JS. Native code should extract
// the wrapped native and deal with that directly.
// XXX Can we simply trust |cx| here?
JSStackFrame *iterator = nsnull;
if (!::JS_FrameIterator(cx, &iterator)) {
::JS_ReportError(cx, "XPCNativeWrappers must be used from script");
return JS_FALSE;
}
// Create a new function that'll call our given function. This new
// function's parent will be the original function and that's how we
// get the right thing to call when this function is called.
// Note that we pass nsnull as the nominal parent so that we'll inherit
// our caller's Function.prototype.
JSFunction *funWrapper =
::JS_NewFunction(cx, XPC_NW_FunctionWrapper, 0, 0, nsnull,
"XPCNativeWrapper function wrapper");
if (!funWrapper) {
return JS_FALSE;
}
JSObject* funWrapperObj = ::JS_GetFunctionObject(funWrapper);
::JS_SetParent(cx, funWrapperObj, funobj);
*rval = OBJECT_TO_JSVAL(funWrapperObj);
JS_SetReservedSlot(cx, funWrapperObj, XPCWrapper::eAllAccessSlot, JSVAL_FALSE);
return JS_TRUE;
}
static JSBool static JSBool
XPC_NW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) XPC_NW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{ {
@ -390,8 +483,8 @@ XPC_NW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
// Note: no need to protect *vp from GC here, since it's already in the slot // Note: no need to protect *vp from GC here, since it's already in the slot
// on |obj|. // on |obj|.
return EnsureLegalActivity(cx, obj, id, XPCWrapper::sSecMgrSetProp) && return EnsureLegalActivity(cx, obj, id, sSecMgrSetProp) &&
XPC_NW_RewrapIfDeepWrapper(cx, obj, *vp, vp); RewrapIfDeepWrapper(cx, obj, *vp, vp);
} }
static JSBool static JSBool
@ -419,82 +512,6 @@ XPC_NW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
return JS_TRUE; return JS_TRUE;
} }
JSBool
XPC_NW_RewrapIfDeepWrapper(JSContext *cx, JSObject *obj, jsval v, jsval *rval)
{
NS_ASSERTION(XPCNativeWrapper::IsNativeWrapper(obj),
"Unexpected object");
JSBool primitive = JSVAL_IS_PRIMITIVE(v);
JSObject* nativeObj = primitive ? nsnull : JSVAL_TO_OBJECT(v);
// We always want to wrap function objects, no matter whether we're deep.
if (!primitive && JS_ObjectIsFunction(cx, nativeObj)) {
return XPC_NW_WrapFunction(cx, nativeObj, rval);
}
jsval flags;
::JS_GetReservedSlot(cx, obj, 0, &flags);
// Re-wrap non-primitive values if this is a deep wrapper, i.e.
// if (HAS_FLAGS(flags, FLAG_DEEP).
if (HAS_FLAGS(flags, FLAG_DEEP) && !primitive) {
// Unwrap a cross origin wrapper, since we're more restrictive.
if (STOBJ_GET_CLASS(nativeObj) == &sXPC_XOW_JSClass.base) {
if (!::JS_GetReservedSlot(cx, nativeObj, XPCWrapper::sWrappedObjSlot,
&v)) {
return JS_FALSE;
}
// If v is primitive, allow nativeObj to remain a cross origin wrapper,
// which will fail below (since it isn't a wrapped native).
if (!JSVAL_IS_PRIMITIVE(v)) {
nativeObj = JSVAL_TO_OBJECT(v);
}
}
XPCWrappedNative* wrappedNative =
XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(cx, nativeObj);
if (!wrappedNative)
return XPC_SJOW_Construct(cx, nsnull, 1, &v, rval);
if (HAS_FLAGS(flags, FLAG_EXPLICIT)) {
#ifdef DEBUG_XPCNativeWrapper
printf("Rewrapping for deep explicit wrapper\n");
#endif
if (wrappedNative == XPCNativeWrapper::SafeGetWrappedNative(obj)) {
// Already wrapped, return the wrapper.
*rval = OBJECT_TO_JSVAL(obj);
return JS_TRUE;
}
// |obj| is an explicit deep wrapper. We want to construct another
// explicit deep wrapper for |v|.
return XPCNativeWrapper::CreateExplicitWrapper(cx, wrappedNative,
JS_TRUE, rval);
}
#ifdef DEBUG_XPCNativeWrapper
printf("Rewrapping for deep implicit wrapper\n");
#endif
// Just using GetNewOrUsed on the return value of
// GetWrappedNativeOfJSObject will give the right thing -- the unique deep
// implicit wrapper associated with wrappedNative.
JSObject* wrapperObj = XPCNativeWrapper::GetNewOrUsed(cx, wrappedNative,
nsnull);
if (!wrapperObj) {
return JS_FALSE;
}
*rval = OBJECT_TO_JSVAL(wrapperObj);
} else {
*rval = v;
}
return JS_TRUE;
}
static JSBool static JSBool
XPC_NW_FunctionWrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, XPC_NW_FunctionWrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval) jsval *rval)
@ -518,9 +535,7 @@ XPC_NW_FunctionWrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
XPCWrappedNative* wrappedNative = nsnull; XPCWrappedNative* wrappedNative = nsnull;
jsval isAllAccess; jsval isAllAccess;
if (::JS_GetReservedSlot(cx, funObj, if (::JS_GetReservedSlot(cx, funObj, eAllAccessSlot, &isAllAccess) &&
XPCWrapper::eAllAccessSlot,
&isAllAccess) &&
JSVAL_TO_BOOLEAN(isAllAccess)) { JSVAL_TO_BOOLEAN(isAllAccess)) {
wrappedNative = XPCNativeWrapper::SafeGetWrappedNative(obj); wrappedNative = XPCNativeWrapper::SafeGetWrappedNative(obj);
} else if (!XPCNativeWrapper::GetWrappedNative(cx, obj, &wrappedNative)) { } else if (!XPCNativeWrapper::GetWrappedNative(cx, obj, &wrappedNative)) {
@ -543,7 +558,7 @@ XPC_NW_FunctionWrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
// Make sure v doesn't get collected while we're re-wrapping it. // Make sure v doesn't get collected while we're re-wrapping it.
AUTO_MARK_JSVAL(ccx, v); AUTO_MARK_JSVAL(ccx, v);
return XPC_NW_RewrapIfDeepWrapper(cx, obj, v, rval); return RewrapIfDeepWrapper(cx, obj, v, rval);
} }
static JSBool static JSBool
@ -564,8 +579,7 @@ XPC_NW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp,
} }
if (!EnsureLegalActivity(cx, obj, id, if (!EnsureLegalActivity(cx, obj, id,
aIsSet ? XPCWrapper::sSecMgrSetProp aIsSet ? sSecMgrSetProp : sSecMgrGetProp)) {
: XPCWrapper::sSecMgrGetProp)) {
return JS_FALSE; return JS_FALSE;
} }
@ -603,7 +617,7 @@ XPC_NW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp,
jsval nativeVal = OBJECT_TO_JSVAL(nativeObj); jsval nativeVal = OBJECT_TO_JSVAL(nativeObj);
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); nsIScriptSecurityManager *ssm = GetSecurityManager();
nsCOMPtr<nsIPrincipal> prin; nsCOMPtr<nsIPrincipal> prin;
nsresult rv = ssm->GetObjectPrincipal(cx, nativeObj, nsresult rv = ssm->GetObjectPrincipal(cx, nativeObj,
getter_AddRefs(prin)); getter_AddRefs(prin));
@ -617,11 +631,11 @@ XPC_NW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp,
return JS_TRUE; return JS_TRUE;
} }
return XPC_SJOW_Construct(cx, nsnull, 1, &nativeVal, vp); return XPCSafeJSObjectWrapper::WrapObject(cx, nsnull, nativeVal, vp);
} }
return XPCWrapper::GetOrSetNativeProperty(cx, obj, wrappedNative, id, vp, return GetOrSetNativeProperty(cx, obj, wrappedNative, id, vp, aIsSet,
aIsSet, JS_TRUE); JS_TRUE);
} }
static JSBool static JSBool
@ -655,7 +669,7 @@ XPC_NW_Enumerate(JSContext *cx, JSObject *obj)
return JS_TRUE; return JS_TRUE;
} }
return XPCWrapper::Enumerate(cx, obj, wn->GetFlatJSObject()); return Enumerate(cx, obj, wn->GetFlatJSObject());
} }
static JSBool static JSBool
@ -673,7 +687,7 @@ XPC_NW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
if (id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) { if (id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) {
*objp = obj; *objp = obj;
// See the comment in XPC_NW_WrapFunction for why we create this function // See the comment in WrapFunction for why we create this function
// like this. // like this.
JSFunction *fun = JS_NewFunction(cx, XPC_NW_toString, 0, 0, nsnull, JSFunction *fun = JS_NewFunction(cx, XPC_NW_toString, 0, 0, nsnull,
"toString"); "toString");
@ -689,8 +703,7 @@ XPC_NW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
} }
PRUint32 accessType = PRUint32 accessType =
(flags & JSRESOLVE_ASSIGNING) ? XPCWrapper::sSecMgrSetProp (flags & JSRESOLVE_ASSIGNING) ? sSecMgrSetProp : sSecMgrGetProp;
: XPCWrapper::sSecMgrGetProp;
if (!EnsureLegalActivity(cx, obj, id, accessType)) { if (!EnsureLegalActivity(cx, obj, id, accessType)) {
return JS_FALSE; return JS_FALSE;
} }
@ -746,10 +759,8 @@ XPC_NW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
return JS_TRUE; return JS_TRUE;
} }
return XPCWrapper::ResolveNativeProperty(cx, obj, return ResolveNativeProperty(cx, obj, wrappedNative->GetFlatJSObject(),
wrappedNative->GetFlatJSObject(), wrappedNative, id, flags, objp, JS_TRUE);
wrappedNative, id, flags, objp,
JS_TRUE);
} }
static JSBool static JSBool
@ -870,7 +881,7 @@ XPC_NW_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx); return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx);
} }
return XPC_NW_RewrapIfDeepWrapper(cx, obj, *rval, rval); return RewrapIfDeepWrapper(cx, obj, *rval, rval);
} }
static JSBool static JSBool
@ -947,22 +958,11 @@ XPCNativeWrapperCtor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
JSObject *nativeObj = JSVAL_TO_OBJECT(native); JSObject *nativeObj = JSVAL_TO_OBJECT(native);
// Unwrap a cross origin wrapper, since we're more restrictive than it is. // Unwrap a cross origin wrapper, since we're more restrictive than it is.
if (STOBJ_GET_CLASS(nativeObj) == &sXPC_XOW_JSClass.base) { JSObject *wrapper;
jsval v; if ((wrapper = UnwrapGeneric(cx, &XPCCrossOriginWrapper::XOWClass, nativeObj))) {
if (!::JS_GetReservedSlot(cx, nativeObj, XPCWrapper::sWrappedObjSlot, &v)) { nativeObj = wrapper;
return JS_FALSE; } else if ((wrapper = UnwrapGeneric(cx, &XPCSafeJSObjectWrapper::SJOWClass, nativeObj))) {
} nativeObj = wrapper;
// If v is primitive, allow nativeObj to remain a cross origin wrapper,
// which will fail below (since it isn't a wrapped native).
if (!JSVAL_IS_PRIMITIVE(v)) {
nativeObj = JSVAL_TO_OBJECT(v);
}
} else if (STOBJ_GET_CLASS(nativeObj) == &sXPC_SJOW_JSClass.base) {
// Also unwrap SJOWs.
nativeObj = JS_GetParent(cx, nativeObj);
if (!nativeObj) {
return ThrowException(NS_ERROR_XPC_BAD_CONVERT_JS, cx);
}
} }
XPCWrappedNative *wrappedNative; XPCWrappedNative *wrappedNative;
@ -1119,8 +1119,8 @@ XPC_NW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly)
return nsnull; return nsnull;
} }
return XPCWrapper::CreateIteratorObj(cx, wrapperIter, obj, return CreateIteratorObj(cx, wrapperIter, obj, wn->GetFlatJSObject(),
wn->GetFlatJSObject(), keysonly); keysonly);
} }
static JSBool static JSBool
@ -1136,7 +1136,7 @@ XPC_NW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
if (!EnsureLegalActivity(cx, obj, if (!EnsureLegalActivity(cx, obj,
GetRTStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING), GetRTStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING),
XPCWrapper::sSecMgrGetProp)) { sSecMgrGetProp)) {
return JS_FALSE; return JS_FALSE;
} }
@ -1155,8 +1155,7 @@ XPC_NW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
return JS_TRUE; return JS_TRUE;
} }
return XPCWrapper::NativeToString(cx, wrappedNative, argc, argv, rval, return NativeToString(cx, wrappedNative, argc, argv, rval, JS_TRUE);
JS_TRUE);
} }
// static // static
@ -1165,7 +1164,7 @@ XPCNativeWrapper::AttachNewConstructorObject(XPCCallContext &ccx,
JSObject *aGlobalObject) JSObject *aGlobalObject)
{ {
JSObject *class_obj = JSObject *class_obj =
::JS_InitClass(ccx, aGlobalObject, nsnull, &sXPC_NW_JSClass.base, ::JS_InitClass(ccx, aGlobalObject, nsnull, &internal::NWClass.base,
XPCNativeWrapperCtor, 0, nsnull, nsnull, XPCNativeWrapperCtor, 0, nsnull, nsnull,
nsnull, nsnull); nsnull, nsnull);
if (!class_obj) { if (!class_obj) {
@ -1183,7 +1182,7 @@ XPCNativeWrapper::AttachNewConstructorObject(XPCCallContext &ccx,
JSBool found; JSBool found;
return ::JS_SetPropertyAttributes(ccx, aGlobalObject, return ::JS_SetPropertyAttributes(ccx, aGlobalObject,
sXPC_NW_JSClass.base.name, internal::NWClass.base.name,
JSPROP_READONLY | JSPROP_PERMANENT, JSPROP_READONLY | JSPROP_PERMANENT,
&found); &found);
} }
@ -1194,7 +1193,7 @@ XPCNativeWrapper::GetNewOrUsed(JSContext *cx, XPCWrappedNative *wrapper,
nsIPrincipal *aObjectPrincipal) nsIPrincipal *aObjectPrincipal)
{ {
if (aObjectPrincipal) { if (aObjectPrincipal) {
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); nsIScriptSecurityManager *ssm = GetSecurityManager();
PRBool isSystem; PRBool isSystem;
nsresult rv = ssm->IsSystemPrincipal(aObjectPrincipal, &isSystem); nsresult rv = ssm->IsSystemPrincipal(aObjectPrincipal, &isSystem);
@ -1220,7 +1219,7 @@ XPCNativeWrapper::GetNewOrUsed(JSContext *cx, XPCWrappedNative *wrapper,
// Make sure v doesn't get collected while we're re-wrapping it. // Make sure v doesn't get collected while we're re-wrapping it.
AUTO_MARK_JSVAL(ccx, v); AUTO_MARK_JSVAL(ccx, v);
if (XPC_SJOW_Construct(cx, nsnull, 1, &v, &v)) if (XPCSafeJSObjectWrapper::WrapObject(cx, nsnull, v, &v))
return JSVAL_TO_OBJECT(v); return JSVAL_TO_OBJECT(v);
return nsnull; return nsnull;

View File

@ -42,49 +42,50 @@
class nsIPrincipal; class nsIPrincipal;
class XPCNativeWrapper namespace XPCNativeWrapper {
namespace internal { extern JSExtendedClass NWClass; }
PRBool
AttachNewConstructorObject(XPCCallContext &ccx, JSObject *aGlobalObject);
JSObject *
GetNewOrUsed(JSContext *cx, XPCWrappedNative *wrapper,
nsIPrincipal *aObjectPrincipal);
JSBool
CreateExplicitWrapper(JSContext *cx, XPCWrappedNative *wrapper, JSBool deep,
jsval *rval);
inline PRBool
IsNativeWrapperClass(JSClass *clazz)
{ {
public: return clazz == &internal::NWClass.base;
static PRBool AttachNewConstructorObject(XPCCallContext &ccx, }
JSObject *aGlobalObject);
static JSObject *GetNewOrUsed(JSContext *cx, XPCWrappedNative *wrapper, inline PRBool
nsIPrincipal *aObjectPrincipal); IsNativeWrapper(JSObject *obj)
static JSBool CreateExplicitWrapper(JSContext *cx, XPCWrappedNative *wrapper, {
JSBool deep, jsval *rval); return STOBJ_GET_CLASS(obj) == &internal::NWClass.base;
}
static PRBool IsNativeWrapperClass(JSClass *clazz)
{
return clazz == &sXPC_NW_JSClass.base;
}
static PRBool IsNativeWrapper(JSObject *obj)
{
return STOBJ_GET_CLASS(obj) == &sXPC_NW_JSClass.base;
}
static JSBool GetWrappedNative(JSContext *cx, JSObject *obj,
XPCWrappedNative **aWrappedNative);
// NB: Use the following carefully.
static XPCWrappedNative *SafeGetWrappedNative(JSObject *obj)
{
return static_cast<XPCWrappedNative *>(xpc_GetJSPrivate(obj));
}
static JSClass *GetJSClass()
{
return &sXPC_NW_JSClass.base;
}
static void ClearWrappedNativeScopes(JSContext* cx,
XPCWrappedNative* wrapper);
protected:
static JSExtendedClass sXPC_NW_JSClass;
};
JSBool JSBool
XPC_XOW_WrapObject(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, GetWrappedNative(JSContext *cx, JSObject *obj,
jsval *rval); XPCWrappedNative **aWrappedNative);
// NB: Use the following carefully.
inline XPCWrappedNative *
SafeGetWrappedNative(JSObject *obj)
{
return static_cast<XPCWrappedNative *>(xpc_GetJSPrivate(obj));
}
inline JSClass *
GetJSClass()
{
return &internal::NWClass.base;
}
void
ClearWrappedNativeScopes(JSContext* cx, XPCWrappedNative* wrapper);
}

View File

@ -77,7 +77,7 @@ static JSBool
XPC_SJOW_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, XPC_SJOW_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval); jsval *rval);
JSBool static JSBool
XPC_SJOW_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, XPC_SJOW_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval); jsval *rval);
@ -103,6 +103,9 @@ ThrowException(nsresult ex, JSContext *cx)
return JS_FALSE; return JS_FALSE;
} }
using namespace XPCSafeJSObjectWrapper;
using namespace XPCWrapper;
// Find the subject and object principal. The argument // Find the subject and object principal. The argument
// subjectPrincipal can be null if the caller doesn't care about the // subjectPrincipal can be null if the caller doesn't care about the
// subject principal, and secMgr can also be null if the caller // subject principal, and secMgr can also be null if the caller
@ -171,15 +174,10 @@ CanCallerAccess(JSContext *cx, JSObject *unsafeObj)
// Reserved slot indexes on safe wrappers. // Reserved slot indexes on safe wrappers.
// Boolean value, initialized to false on object creation and true
// only while we're resolving a property on the object.
#define XPC_SJOW_SLOT_IS_RESOLVING 0
// Slot for holding on to the principal to use if a principal other // Slot for holding on to the principal to use if a principal other
// than that of the unsafe object is desired for this wrapper // than that of the unsafe object is desired for this wrapper
// (nsIPrincipal, strong reference). // (nsIPrincipal, strong reference).
#define XPC_SJOW_SLOT_PRINCIPAL 1 static const PRUint32 sPrincipalSlot = sNumSlots;
// Returns a weak reference. // Returns a weak reference.
static nsIPrincipal * static nsIPrincipal *
@ -187,7 +185,7 @@ FindObjectPrincipals(JSContext *cx, JSObject *safeObj, JSObject *innerObj)
{ {
// Check if we have a cached principal first. // Check if we have a cached principal first.
jsval v; jsval v;
if (!JS_GetReservedSlot(cx, safeObj, XPC_SJOW_SLOT_PRINCIPAL, &v)) { if (!JS_GetReservedSlot(cx, safeObj, sPrincipalSlot, &v)) {
return nsnull; return nsnull;
} }
@ -203,7 +201,7 @@ FindObjectPrincipals(JSContext *cx, JSObject *safeObj, JSObject *innerObj)
return nsnull; return nsnull;
} }
if (!JS_SetReservedSlot(cx, safeObj, XPC_SJOW_SLOT_PRINCIPAL, if (!JS_SetReservedSlot(cx, safeObj, sPrincipalSlot,
PRIVATE_TO_JSVAL(objPrincipal.get()))) { PRIVATE_TO_JSVAL(objPrincipal.get()))) {
return nsnull; return nsnull;
} }
@ -212,15 +210,34 @@ FindObjectPrincipals(JSContext *cx, JSObject *safeObj, JSObject *innerObj)
return objPrincipal.forget().get(); return objPrincipal.forget().get();
} }
static inline JSObject *
FindSafeObject(JSObject *obj)
{
while (STOBJ_GET_CLASS(obj) != &SJOWClass.base) {
obj = STOBJ_GET_PROTO(obj);
if (!obj) {
break;
}
}
return obj;
}
static JSBool
XPC_SJOW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval);
namespace XPCSafeJSObjectWrapper {
// JS class for XPCSafeJSObjectWrapper (and this doubles as the // JS class for XPCSafeJSObjectWrapper (and this doubles as the
// constructor for XPCSafeJSObjectWrapper for the moment too...) // constructor for XPCSafeJSObjectWrapper for the moment too...)
JSExtendedClass sXPC_SJOW_JSClass = { JSExtendedClass SJOWClass = {
// JSClass (JSExtendedClass.base) initialization // JSClass (JSExtendedClass.base) initialization
{ "XPCSafeJSObjectWrapper", { "XPCSafeJSObjectWrapper",
JSCLASS_NEW_RESOLVE | JSCLASS_IS_EXTENDED | JSCLASS_NEW_RESOLVE | JSCLASS_IS_EXTENDED |
JSCLASS_HAS_RESERVED_SLOTS(XPCWrapper::sNumSlots + 3), JSCLASS_HAS_RESERVED_SLOTS(XPCWrapper::sNumSlots + 1),
XPC_SJOW_AddProperty, XPC_SJOW_DelProperty, XPC_SJOW_AddProperty, XPC_SJOW_DelProperty,
XPC_SJOW_GetProperty, XPC_SJOW_SetProperty, XPC_SJOW_GetProperty, XPC_SJOW_SetProperty,
XPC_SJOW_Enumerate, (JSResolveOp)XPC_SJOW_NewResolve, XPC_SJOW_Enumerate, (JSResolveOp)XPC_SJOW_NewResolve,
@ -239,10 +256,69 @@ JSExtendedClass sXPC_SJOW_JSClass = {
JSCLASS_NO_RESERVED_MEMBERS JSCLASS_NO_RESERVED_MEMBERS
}; };
static JSBool JSBool
XPC_SJOW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, WrapObject(JSContext *cx, JSObject *scope, jsval v, jsval *vp)
jsval *rval); {
*vp = v;
return XPC_SJOW_Construct(cx, scope, 1, vp, vp);
}
PRBool
AttachNewConstructorObject(XPCCallContext &ccx, JSObject *aGlobalObject)
{
// Initialize sEvalNative the first time we attach a constructor.
// NB: This always happens before any cross origin wrappers are
// created, so it's OK to do this here.
if (!XPCWrapper::FindEval(ccx, aGlobalObject)) {
return PR_FALSE;
}
JSObject *class_obj =
::JS_InitClass(ccx, aGlobalObject, nsnull, &SJOWClass.base,
XPC_SJOW_Construct, 0, nsnull, nsnull, nsnull, nsnull);
if (!class_obj) {
NS_WARNING("can't initialize the XPCSafeJSObjectWrapper class");
return PR_FALSE;
}
if (!::JS_DefineFunction(ccx, class_obj, "toString", XPC_SJOW_toString,
0, 0)) {
return PR_FALSE;
}
// Null out the class object's parent to prevent code in this class
// from thinking the class object is a wrapper for the global
// object.
::JS_SetParent(ccx, class_obj, nsnull);
// Make sure our prototype chain is empty and that people can't mess
// with XPCSafeJSObjectWrapper.prototype.
::JS_SetPrototype(ccx, class_obj, nsnull);
if (!::JS_SealObject(ccx, class_obj, JS_FALSE)) {
NS_WARNING("Failed to seal XPCSafeJSObjectWrapper.prototype");
return PR_FALSE;
}
JSBool found;
return ::JS_SetPropertyAttributes(ccx, aGlobalObject,
SJOWClass.base.name,
JSPROP_READONLY | JSPROP_PERMANENT,
&found);
}
JSObject *
GetUnsafeObject(JSObject *obj)
{
obj = FindSafeObject(obj);
if (!obj) {
return nsnull;
}
return STOBJ_GET_PARENT(obj);
}
} // namespace XPCSafeJSObjectWrapper
// Wrap a JS value in a safe wrapper of a function wrapper if // Wrap a JS value in a safe wrapper of a function wrapper if
// needed. Note that rval must point to something rooted when calling // needed. Note that rval must point to something rooted when calling
@ -259,7 +335,7 @@ WrapJSValue(JSContext *cx, JSObject *obj, jsval val, jsval *rval)
// parent we pass in here, the construct hook will ensure we get // parent we pass in here, the construct hook will ensure we get
// the right parent for the wrapper. // the right parent for the wrapper.
JSObject *safeObj = JSObject *safeObj =
::JS_ConstructObjectWithArguments(cx, &sXPC_SJOW_JSClass.base, nsnull, ::JS_ConstructObjectWithArguments(cx, &SJOWClass.base, nsnull,
nsnull, 1, &val); nsnull, 1, &val);
if (!safeObj) { if (!safeObj) {
return JS_FALSE; return JS_FALSE;
@ -315,7 +391,7 @@ WrapJSValue(JSContext *cx, JSObject *obj, jsval val, jsval *rval)
// the principal of the unsafe object to prevent users of the // the principal of the unsafe object to prevent users of the
// new object wrapper from evaluating code through the new // new object wrapper from evaluating code through the new
// wrapper with the principal of the new object. // wrapper with the principal of the new object.
if (!::JS_SetReservedSlot(cx, safeObj, XPC_SJOW_SLOT_PRINCIPAL, if (!::JS_SetReservedSlot(cx, safeObj, sPrincipalSlot,
PRIVATE_TO_JSVAL(srcObjPrincipal.get()))) { PRIVATE_TO_JSVAL(srcObjPrincipal.get()))) {
return JS_FALSE; return JS_FALSE;
} }
@ -331,44 +407,6 @@ WrapJSValue(JSContext *cx, JSObject *obj, jsval val, jsval *rval)
return ok; return ok;
} }
static inline JSObject *
FindSafeObject(JSObject *obj)
{
while (STOBJ_GET_CLASS(obj) != &sXPC_SJOW_JSClass.base) {
obj = STOBJ_GET_PROTO(obj);
if (!obj) {
break;
}
}
return obj;
}
PRBool
IsXPCSafeJSObjectWrapperClass(JSClass *clazz)
{
return clazz == &sXPC_SJOW_JSClass.base;
}
static inline JSObject *
GetUnsafeObject(JSObject *obj)
{
obj = FindSafeObject(obj);
if (!obj) {
return nsnull;
}
return STOBJ_GET_PARENT(obj);
}
JSObject *
XPC_SJOW_GetUnsafeObject(JSObject *obj)
{
return GetUnsafeObject(obj);
}
static jsval static jsval
UnwrapJSValue(jsval val) UnwrapJSValue(jsval val)
{ {
@ -400,8 +438,7 @@ XPC_SJOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
// Do nothing here if we're in the middle of resolving a property on // Do nothing here if we're in the middle of resolving a property on
// this safe wrapper. // this safe wrapper.
jsval isResolving; jsval isResolving;
JSBool ok = ::JS_GetReservedSlot(cx, obj, XPC_SJOW_SLOT_IS_RESOLVING, JSBool ok = ::JS_GetReservedSlot(cx, obj, sFlagsSlot, &isResolving);
&isResolving);
if (!ok || HAS_FLAGS(isResolving, FLAG_RESOLVING)) { if (!ok || HAS_FLAGS(isResolving, FLAG_RESOLVING)) {
return ok; return ok;
} }
@ -619,8 +656,7 @@ XPC_SJOW_Finalize(JSContext *cx, JSObject *obj)
{ {
// Release the reference to the cached principal if we have one. // Release the reference to the cached principal if we have one.
jsval v; jsval v;
if (::JS_GetReservedSlot(cx, obj, XPC_SJOW_SLOT_PRINCIPAL, &v) && if (::JS_GetReservedSlot(cx, obj, sPrincipalSlot, &v) && !JSVAL_IS_VOID(v)) {
!JSVAL_IS_VOID(v)) {
nsIPrincipal *principal = (nsIPrincipal *)JSVAL_TO_PRIVATE(v); nsIPrincipal *principal = (nsIPrincipal *)JSVAL_TO_PRIVATE(v);
NS_RELEASE(principal); NS_RELEASE(principal);
@ -738,7 +774,7 @@ XPC_SJOW_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
return WrapJSValue(cx, obj, *rval, rval); return WrapJSValue(cx, obj, *rval, rval);
} }
JSBool static JSBool
XPC_SJOW_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, XPC_SJOW_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval) jsval *rval)
{ {
@ -796,7 +832,7 @@ XPC_SJOW_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
// Don't use the object the JS engine created for us, it is in most // Don't use the object the JS engine created for us, it is in most
// cases incorectly parented and has a proto from the wrong scope. // cases incorectly parented and has a proto from the wrong scope.
JSObject *wrapperObj = JSObject *wrapperObj =
::JS_NewObjectWithGivenProto(cx, &sXPC_SJOW_JSClass.base, nsnull, ::JS_NewObjectWithGivenProto(cx, &SJOWClass.base, nsnull,
objToWrap); objToWrap);
if (!wrapperObj) { if (!wrapperObj) {
@ -804,8 +840,7 @@ XPC_SJOW_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
return JS_FALSE; return JS_FALSE;
} }
if (!::JS_SetReservedSlot(cx, wrapperObj, XPC_SJOW_SLOT_IS_RESOLVING, if (!::JS_SetReservedSlot(cx, wrapperObj, sFlagsSlot, JSVAL_ZERO)) {
JSVAL_ZERO)) {
return JS_FALSE; return JS_FALSE;
} }
@ -893,7 +928,9 @@ XPC_SJOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly)
return nsnull; return nsnull;
} }
JSObject *tmp = XPCWrapper::UnwrapGeneric(cx, &sXPC_XOW_JSClass, unsafeObj); JSObject *tmp =
XPCWrapper::UnwrapGeneric(cx, &XPCCrossOriginWrapper::XOWClass,
unsafeObj);
if (tmp) { if (tmp) {
unsafeObj = tmp; unsafeObj = tmp;
@ -907,14 +944,13 @@ XPC_SJOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly)
// Create our dummy SJOW. // Create our dummy SJOW.
JSObject *wrapperIter = JSObject *wrapperIter =
::JS_NewObjectWithGivenProto(cx, &sXPC_SJOW_JSClass.base, nsnull, ::JS_NewObjectWithGivenProto(cx, &SJOWClass.base, nsnull,
unsafeObj); unsafeObj);
if (!wrapperIter) { if (!wrapperIter) {
return nsnull; return nsnull;
} }
if (!::JS_SetReservedSlot(cx, wrapperIter, XPC_SJOW_SLOT_IS_RESOLVING, if (!::JS_SetReservedSlot(cx, wrapperIter, sFlagsSlot, JSVAL_ZERO)) {
JSVAL_ZERO)) {
return nsnull; return nsnull;
} }
@ -977,47 +1013,3 @@ XPC_SJOW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
} }
return JS_TRUE; return JS_TRUE;
} }
PRBool
XPC_SJOW_AttachNewConstructorObject(XPCCallContext &ccx,
JSObject *aGlobalObject)
{
// Initialize sEvalNative the first time we attach a constructor.
// NB: This always happens before any cross origin wrappers are
// created, so it's OK to do this here.
if (!XPCWrapper::FindEval(ccx, aGlobalObject)) {
return PR_FALSE;
}
JSObject *class_obj =
::JS_InitClass(ccx, aGlobalObject, nsnull, &sXPC_SJOW_JSClass.base,
XPC_SJOW_Construct, 0, nsnull, nsnull, nsnull, nsnull);
if (!class_obj) {
NS_WARNING("can't initialize the XPCSafeJSObjectWrapper class");
return PR_FALSE;
}
if (!::JS_DefineFunction(ccx, class_obj, "toString", XPC_SJOW_toString,
0, 0)) {
return PR_FALSE;
}
// Null out the class object's parent to prevent code in this class
// from thinking the class object is a wrapper for the global
// object.
::JS_SetParent(ccx, class_obj, nsnull);
// Make sure our prototype chain is empty and that people can't mess
// with XPCSafeJSObjectWrapper.prototype.
::JS_SetPrototype(ccx, class_obj, nsnull);
if (!::JS_SealObject(ccx, class_obj, JS_FALSE)) {
NS_WARNING("Failed to seal XPCSafeJSObjectWrapper.prototype");
return PR_FALSE;
}
JSBool found;
return ::JS_SetPropertyAttributes(ccx, aGlobalObject,
sXPC_SJOW_JSClass.base.name,
JSPROP_READONLY | JSPROP_PERMANENT,
&found);
}

View File

@ -85,7 +85,18 @@ XPC_SOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly);
static JSObject * static JSObject *
XPC_SOW_WrappedObject(JSContext *cx, JSObject *obj); XPC_SOW_WrappedObject(JSContext *cx, JSObject *obj);
JSExtendedClass sXPC_SOW_JSClass = { using namespace XPCWrapper;
// Throws an exception on context |cx|.
static inline JSBool
ThrowException(nsresult rv, JSContext *cx)
{
return DoThrowException(rv, cx);
}
namespace SystemOnlyWrapper {
JSExtendedClass SOWClass = {
// JSClass (JSExtendedClass.base) initialization // JSClass (JSExtendedClass.base) initialization
{ "SystemOnlyWrapper", { "SystemOnlyWrapper",
JSCLASS_NEW_RESOLVE | JSCLASS_IS_EXTENDED | JSCLASS_NEW_RESOLVE | JSCLASS_IS_EXTENDED |
@ -109,55 +120,31 @@ JSExtendedClass sXPC_SOW_JSClass = {
JSCLASS_NO_RESERVED_MEMBERS JSCLASS_NO_RESERVED_MEMBERS
}; };
static JSBool JSBool
XPC_SOW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, WrapObject(JSContext *cx, JSObject *parent, jsval v, jsval *vp)
jsval *rval);
// Throws an exception on context |cx|.
static inline JSBool
ThrowException(nsresult rv, JSContext *cx)
{ {
return XPCWrapper::ThrowException(rv, cx); // Slim wrappers don't expect to be wrapped, so morph them to fat wrappers
} // if we're about to wrap one.
JSObject *innerObj = JSVAL_TO_OBJECT(v);
// Like GetWrappedObject, but works on other types of wrappers, too. if (IS_SLIM_WRAPPER(innerObj) && !MorphSlimWrapper(cx, innerObj)) {
// TODO Move to XPCWrapper? return ThrowException(NS_ERROR_FAILURE, cx);
static inline JSObject *
GetWrappedJSObject(JSContext *cx, JSObject *obj)
{
JSClass *clasp = STOBJ_GET_CLASS(obj);
if (!(clasp->flags & JSCLASS_IS_EXTENDED)) {
return obj;
} }
JSExtendedClass *xclasp = (JSExtendedClass *)clasp; JSObject *wrapperObj =
if (!xclasp->wrappedObject) { JS_NewObjectWithGivenProto(cx, &SOWClass.base, NULL, parent);
return obj; if (!wrapperObj) {
return JS_FALSE;
} }
return xclasp->wrappedObject(cx, obj); *vp = OBJECT_TO_JSVAL(wrapperObj);
} JSAutoTempValueRooter tvr(cx, *vp);
// Get the (possibly non-existant) SOW off of an object if (!JS_SetReservedSlot(cx, wrapperObj, sWrappedObjSlot, v) ||
static inline !JS_SetReservedSlot(cx, wrapperObj, sFlagsSlot, JSVAL_ZERO)) {
JSObject * return JS_FALSE;
GetWrapper(JSObject *obj)
{
while (STOBJ_GET_CLASS(obj) != &sXPC_SOW_JSClass.base) {
obj = STOBJ_GET_PROTO(obj);
if (!obj) {
break;
}
} }
return obj; return JS_TRUE;
}
static inline
JSObject *
GetWrappedObject(JSContext *cx, JSObject *wrapper)
{
return XPCWrapper::UnwrapGeneric(cx, &sXPC_SOW_JSClass, wrapper);
} }
// If you change this code, change also nsContentUtils::CanAccessNativeAnon()! // If you change this code, change also nsContentUtils::CanAccessNativeAnon()!
@ -165,7 +152,7 @@ JSBool
AllowedToAct(JSContext *cx, jsval idval) AllowedToAct(JSContext *cx, jsval idval)
{ {
// TODO bug 508928: Refactor this with the XOW security checking code. // TODO bug 508928: Refactor this with the XOW security checking code.
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); nsIScriptSecurityManager *ssm = GetSecurityManager();
if (!ssm) { if (!ssm) {
return JS_TRUE; return JS_TRUE;
} }
@ -227,6 +214,54 @@ AllowedToAct(JSContext *cx, jsval idval)
return JS_FALSE; return JS_FALSE;
} }
} // namespace SystemOnlyWrapper
using namespace SystemOnlyWrapper;
static JSBool
XPC_SOW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval);
// Like GetWrappedObject, but works on other types of wrappers, too.
// TODO Move to XPCWrapper?
static inline JSObject *
GetWrappedJSObject(JSContext *cx, JSObject *obj)
{
JSClass *clasp = STOBJ_GET_CLASS(obj);
if (!(clasp->flags & JSCLASS_IS_EXTENDED)) {
return obj;
}
JSExtendedClass *xclasp = (JSExtendedClass *)clasp;
if (!xclasp->wrappedObject) {
return obj;
}
return xclasp->wrappedObject(cx, obj);
}
// Get the (possibly non-existant) SOW off of an object
static inline
JSObject *
GetWrapper(JSObject *obj)
{
while (STOBJ_GET_CLASS(obj) != &SOWClass.base) {
obj = STOBJ_GET_PROTO(obj);
if (!obj) {
break;
}
}
return obj;
}
static inline
JSObject *
GetWrappedObject(JSContext *cx, JSObject *wrapper)
{
return UnwrapGeneric(cx, &SOWClass, wrapper);
}
static JSBool static JSBool
XPC_SOW_FunctionWrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, XPC_SOW_FunctionWrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval) jsval *rval)
@ -254,8 +289,7 @@ XPC_SOW_FunctionWrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
JSObject *funObj = JSVAL_TO_OBJECT(argv[-2]); JSObject *funObj = JSVAL_TO_OBJECT(argv[-2]);
jsval funToCall; jsval funToCall;
if (!JS_GetReservedSlot(cx, funObj, XPCWrapper::eWrappedFunctionSlot, if (!JS_GetReservedSlot(cx, funObj, eWrappedFunctionSlot, &funToCall)) {
&funToCall)) {
return JS_FALSE; return JS_FALSE;
} }
@ -288,7 +322,7 @@ XPC_SOW_WrapFunction(JSContext *cx, JSObject *outerObj, JSObject *funobj,
*rval = OBJECT_TO_JSVAL(funWrapperObj); *rval = OBJECT_TO_JSVAL(funWrapperObj);
return JS_SetReservedSlot(cx, funWrapperObj, return JS_SetReservedSlot(cx, funWrapperObj,
XPCWrapper::eWrappedFunctionSlot, eWrappedFunctionSlot,
funobjVal); funobjVal);
} }
@ -321,7 +355,7 @@ XPC_SOW_RewrapValue(JSContext *cx, JSObject *wrapperObj, jsval *vp)
} }
// It isn't ours, rewrap the wrapped function. // It isn't ours, rewrap the wrapped function.
if (!JS_GetReservedSlot(cx, obj, XPCWrapper::eWrappedFunctionSlot, &v)) { if (!JS_GetReservedSlot(cx, obj, eWrappedFunctionSlot, &v)) {
return JS_FALSE; return JS_FALSE;
} }
obj = JSVAL_TO_OBJECT(v); obj = JSVAL_TO_OBJECT(v);
@ -330,7 +364,7 @@ XPC_SOW_RewrapValue(JSContext *cx, JSObject *wrapperObj, jsval *vp)
return XPC_SOW_WrapFunction(cx, wrapperObj, obj, vp); return XPC_SOW_WrapFunction(cx, wrapperObj, obj, vp);
} }
if (STOBJ_GET_CLASS(obj) == &sXPC_SOW_JSClass.base) { if (STOBJ_GET_CLASS(obj) == &SOWClass.base) {
// We are extra careful about content-polluted wrappers here. I don't know // We are extra careful about content-polluted wrappers here. I don't know
// if it's possible to reach them through objects that we wrap, but figuring // if it's possible to reach them through objects that we wrap, but figuring
// that out is more expensive (and harder) than simply checking and // that out is more expensive (and harder) than simply checking and
@ -349,16 +383,16 @@ XPC_SOW_RewrapValue(JSContext *cx, JSObject *wrapperObj, jsval *vp)
v = *vp = OBJECT_TO_JSVAL(obj); v = *vp = OBJECT_TO_JSVAL(obj);
} }
return XPC_SOW_WrapObject(cx, STOBJ_GET_PARENT(wrapperObj), v, vp); return WrapObject(cx, STOBJ_GET_PARENT(wrapperObj), v, vp);
} }
static JSBool static JSBool
XPC_SOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) XPC_SOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{ {
NS_ASSERTION(STOBJ_GET_CLASS(obj) == &sXPC_SOW_JSClass.base, "Wrong object"); NS_ASSERTION(STOBJ_GET_CLASS(obj) == &SOWClass.base, "Wrong object");
jsval resolving; jsval resolving;
if (!JS_GetReservedSlot(cx, obj, XPCWrapper::sFlagsSlot, &resolving)) { if (!JS_GetReservedSlot(cx, obj, sFlagsSlot, &resolving)) {
return JS_FALSE; return JS_FALSE;
} }
@ -376,7 +410,7 @@ XPC_SOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
return JS_TRUE; return JS_TRUE;
} }
return XPCWrapper::AddProperty(cx, obj, JS_TRUE, wrappedObj, id, vp); return AddProperty(cx, obj, JS_TRUE, wrappedObj, id, vp);
} }
static JSBool static JSBool
@ -391,7 +425,7 @@ XPC_SOW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
return JS_FALSE; return JS_FALSE;
} }
return XPCWrapper::DelProperty(cx, wrappedObj, id, vp); return DelProperty(cx, wrappedObj, id, vp);
} }
static JSBool static JSBool
@ -464,7 +498,7 @@ XPC_SOW_Enumerate(JSContext *cx, JSObject *obj)
return JS_FALSE; return JS_FALSE;
} }
return XPCWrapper::Enumerate(cx, obj, wrappedObj); return Enumerate(cx, obj, wrappedObj);
} }
static JSBool static JSBool
@ -486,8 +520,8 @@ XPC_SOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
if (id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) { if (id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) {
jsval oldSlotVal; jsval oldSlotVal;
if (!JS_GetReservedSlot(cx, obj, XPCWrapper::sFlagsSlot, &oldSlotVal) || if (!JS_GetReservedSlot(cx, obj, sFlagsSlot, &oldSlotVal) ||
!JS_SetReservedSlot(cx, obj, XPCWrapper::sFlagsSlot, !JS_SetReservedSlot(cx, obj, sFlagsSlot,
INT_TO_JSVAL(JSVAL_TO_INT(oldSlotVal) | INT_TO_JSVAL(JSVAL_TO_INT(oldSlotVal) |
FLAG_RESOLVING))) { FLAG_RESOLVING))) {
return JS_FALSE; return JS_FALSE;
@ -496,7 +530,7 @@ XPC_SOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
JSBool ok = JS_DefineFunction(cx, obj, "toString", JSBool ok = JS_DefineFunction(cx, obj, "toString",
XPC_SOW_toString, 0, 0) != nsnull; XPC_SOW_toString, 0, 0) != nsnull;
JS_SetReservedSlot(cx, obj, XPCWrapper::sFlagsSlot, oldSlotVal); JS_SetReservedSlot(cx, obj, sFlagsSlot, oldSlotVal);
if (ok) { if (ok) {
*objp = obj; *objp = obj;
@ -505,7 +539,7 @@ XPC_SOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
return ok; return ok;
} }
return XPCWrapper::NewResolve(cx, obj, JS_TRUE, wrappedObj, id, flags, objp); return NewResolve(cx, obj, JS_TRUE, wrappedObj, id, flags, objp);
} }
static JSBool static JSBool
@ -643,7 +677,7 @@ XPC_SOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly)
return nsnull; return nsnull;
} }
JSObject *wrapperIter = JS_NewObject(cx, &sXPC_SOW_JSClass.base, nsnull, JSObject *wrapperIter = JS_NewObject(cx, &SOWClass.base, nsnull,
JS_GetGlobalForObject(cx, obj)); JS_GetGlobalForObject(cx, obj));
if (!wrapperIter) { if (!wrapperIter) {
return nsnull; return nsnull;
@ -653,14 +687,12 @@ XPC_SOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly)
// Initialize our SOW. // Initialize our SOW.
jsval v = OBJECT_TO_JSVAL(wrappedObj); jsval v = OBJECT_TO_JSVAL(wrappedObj);
if (!JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sWrappedObjSlot, v) || if (!JS_SetReservedSlot(cx, wrapperIter, sWrappedObjSlot, v) ||
!JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sFlagsSlot, !JS_SetReservedSlot(cx, wrapperIter, sFlagsSlot, JSVAL_ZERO)) {
JSVAL_ZERO)) {
return nsnull; return nsnull;
} }
return XPCWrapper::CreateIteratorObj(cx, wrapperIter, obj, wrappedObj, return CreateIteratorObj(cx, wrapperIter, obj, wrappedObj, keysonly);
keysonly);
} }
static JSObject * static JSObject *
@ -697,34 +729,5 @@ XPC_SOW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
XPCWrappedNative *wn = XPCWrappedNative *wn =
XPCWrappedNative::GetWrappedNativeOfJSObject(cx, wrappedObj); XPCWrappedNative::GetWrappedNativeOfJSObject(cx, wrappedObj);
return XPCWrapper::NativeToString(cx, wn, argc, argv, rval, JS_FALSE); return NativeToString(cx, wn, argc, argv, rval, JS_FALSE);
}
JSBool
XPC_SOW_WrapObject(JSContext *cx, JSObject *parent, jsval v,
jsval *vp)
{
// Slim wrappers don't expect to be wrapped, so morph them to fat wrappers
// if we're about to wrap one.
JSObject *innerObj = JSVAL_TO_OBJECT(v);
if (IS_SLIM_WRAPPER(innerObj) && !MorphSlimWrapper(cx, innerObj)) {
return ThrowException(NS_ERROR_FAILURE, cx);
}
JSObject *wrapperObj =
JS_NewObjectWithGivenProto(cx, &sXPC_SOW_JSClass.base, NULL, parent);
if (!wrapperObj) {
return JS_FALSE;
}
*vp = OBJECT_TO_JSVAL(wrapperObj);
JSAutoTempValueRooter tvr(cx, *vp);
if (!JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sWrappedObjSlot, v) ||
!JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sFlagsSlot,
JSVAL_ZERO)) {
return JS_FALSE;
}
return JS_TRUE;
} }

View File

@ -43,29 +43,24 @@
#include "XPCWrapper.h" #include "XPCWrapper.h"
#include "XPCNativeWrapper.h" #include "XPCNativeWrapper.h"
const PRUint32 namespace XPCWrapper {
XPCWrapper::sWrappedObjSlot = 1;
const PRUint32 const PRUint32 sWrappedObjSlot = 1;
XPCWrapper::sFlagsSlot = 0; const PRUint32 sFlagsSlot = 0;
const PRUint32 sNumSlots = 2;
JSNative sEvalNative = nsnull;
const PRUint32 const PRUint32 FLAG_RESOLVING = 0x1;
XPCWrapper::sNumSlots = 2; const PRUint32 LAST_FLAG = FLAG_RESOLVING;
JSNative const PRUint32 sSecMgrSetProp = nsIXPCSecurityManager::ACCESS_SET_PROPERTY;
XPCWrapper::sEvalNative = nsnull; const PRUint32 sSecMgrGetProp = nsIXPCSecurityManager::ACCESS_GET_PROPERTY;
const PRUint32
XPCWrapper::sSecMgrSetProp = nsIXPCSecurityManager::ACCESS_SET_PROPERTY;
const PRUint32
XPCWrapper::sSecMgrGetProp = nsIXPCSecurityManager::ACCESS_GET_PROPERTY;
// static
JSObject * JSObject *
XPCWrapper::Unwrap(JSContext *cx, JSObject *wrapper) Unwrap(JSContext *cx, JSObject *wrapper)
{ {
JSClass *clasp = STOBJ_GET_CLASS(wrapper); JSClass *clasp = STOBJ_GET_CLASS(wrapper);
if (clasp == &sXPC_XOW_JSClass.base) { if (clasp == &XPCCrossOriginWrapper::XOWClass.base) {
return UnwrapXOW(cx, wrapper); return UnwrapXOW(cx, wrapper);
} }
@ -79,10 +74,10 @@ XPCWrapper::Unwrap(JSContext *cx, JSObject *wrapper)
return wrappedObj->GetFlatJSObject(); return wrappedObj->GetFlatJSObject();
} }
if (clasp == &sXPC_SJOW_JSClass.base) { if (clasp == &XPCSafeJSObjectWrapper::SJOWClass.base) {
JSObject *wrappedObj = STOBJ_GET_PARENT(wrapper); JSObject *wrappedObj = STOBJ_GET_PARENT(wrapper);
if (NS_FAILED(CanAccessWrapper(cx, wrappedObj, nsnull))) { if (NS_FAILED(XPCCrossOriginWrapper::CanAccessWrapper(cx, wrappedObj, nsnull))) {
JS_ClearPendingException(cx); JS_ClearPendingException(cx);
return nsnull; return nsnull;
@ -91,10 +86,10 @@ XPCWrapper::Unwrap(JSContext *cx, JSObject *wrapper)
return wrappedObj; return wrappedObj;
} }
if (clasp == &sXPC_SOW_JSClass.base) { if (clasp == &SystemOnlyWrapper::SOWClass.base) {
return UnwrapSOW(cx, wrapper); return UnwrapSOW(cx, wrapper);
} }
if (clasp == &sXPC_COW_JSClass.base) { if (clasp == &ChromeObjectWrapper::COWClass.base) {
return UnwrapCOW(cx, wrapper); return UnwrapCOW(cx, wrapper);
} }
@ -180,11 +175,10 @@ static JSClass IteratorClass = {
JSCLASS_NO_OPTIONAL_MEMBERS JSCLASS_NO_OPTIONAL_MEMBERS
}; };
// static
JSObject * JSObject *
XPCWrapper::CreateIteratorObj(JSContext *cx, JSObject *tempWrapper, CreateIteratorObj(JSContext *cx, JSObject *tempWrapper,
JSObject *wrapperObj, JSObject *innerObj, JSObject *wrapperObj, JSObject *innerObj,
JSBool keysonly) JSBool keysonly)
{ {
// This is rather ugly: we want to use the trick seen in Enumerate, // This is rather ugly: we want to use the trick seen in Enumerate,
// where we use our wrapper's resolve hook to determine if we should // where we use our wrapper's resolve hook to determine if we should
@ -251,11 +245,9 @@ XPCWrapper::CreateIteratorObj(JSContext *cx, JSObject *tempWrapper,
return iterObj; return iterObj;
} }
// static
JSBool JSBool
XPCWrapper::AddProperty(JSContext *cx, JSObject *wrapperObj, AddProperty(JSContext *cx, JSObject *wrapperObj, JSBool wantGetterSetter,
JSBool wantGetterSetter, JSObject *innerObj, jsval id, JSObject *innerObj, jsval id, jsval *vp)
jsval *vp)
{ {
jsid interned_id; jsid interned_id;
if (!::JS_ValueToId(cx, id, &interned_id)) { if (!::JS_ValueToId(cx, id, &interned_id)) {
@ -275,9 +267,8 @@ XPCWrapper::AddProperty(JSContext *cx, JSObject *wrapperObj,
desc.getter, desc.setter, desc.attrs); desc.getter, desc.setter, desc.attrs);
} }
// static
JSBool JSBool
XPCWrapper::DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{ {
if (JSVAL_IS_STRING(id)) { if (JSVAL_IS_STRING(id)) {
JSString *str = JSVAL_TO_STRING(id); JSString *str = JSVAL_TO_STRING(id);
@ -288,15 +279,14 @@ XPCWrapper::DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
} }
if (!JSVAL_IS_INT(id)) { if (!JSVAL_IS_INT(id)) {
return ThrowException(NS_ERROR_NOT_IMPLEMENTED, cx); return DoThrowException(NS_ERROR_NOT_IMPLEMENTED, cx);
} }
return ::JS_DeleteElement2(cx, obj, JSVAL_TO_INT(id), vp); return ::JS_DeleteElement2(cx, obj, JSVAL_TO_INT(id), vp);
} }
// static
JSBool JSBool
XPCWrapper::Enumerate(JSContext *cx, JSObject *wrapperObj, JSObject *innerObj) Enumerate(JSContext *cx, JSObject *wrapperObj, JSObject *innerObj)
{ {
// We are being notified of a for-in loop or similar operation on // We are being notified of a for-in loop or similar operation on
// this wrapper. Forward to the correct high-level object hook, // this wrapper. Forward to the correct high-level object hook,
@ -342,11 +332,9 @@ XPCWrapper::Enumerate(JSContext *cx, JSObject *wrapperObj, JSObject *innerObj)
return ok; return ok;
} }
// static
JSBool JSBool
XPCWrapper::NewResolve(JSContext *cx, JSObject *wrapperObj, NewResolve(JSContext *cx, JSObject *wrapperObj, JSBool wantDetails,
JSBool wantDetails, JSObject *innerObj, jsval id, JSObject *innerObj, jsval id, uintN flags, JSObject **objp)
uintN flags, JSObject **objp)
{ {
jsid interned_id; jsid interned_id;
if (!::JS_ValueToId(cx, id, &interned_id)) { if (!::JS_ValueToId(cx, id, &interned_id)) {
@ -385,12 +373,11 @@ XPCWrapper::NewResolve(JSContext *cx, JSObject *wrapperObj,
return ok; return ok;
} }
// static
JSBool JSBool
XPCWrapper::ResolveNativeProperty(JSContext *cx, JSObject *wrapperObj, ResolveNativeProperty(JSContext *cx, JSObject *wrapperObj,
JSObject *innerObj, XPCWrappedNative *wn, JSObject *innerObj, XPCWrappedNative *wn,
jsval id, uintN flags, JSObject **objp, jsval id, uintN flags, JSObject **objp,
JSBool isNativeWrapper) JSBool isNativeWrapper)
{ {
// This will do verification and the method lookup for us. // This will do verification and the method lookup for us.
XPCCallContext ccx(JS_CALLER, cx, innerObj, nsnull, id); XPCCallContext ccx(JS_CALLER, cx, innerObj, nsnull, id);
@ -432,7 +419,7 @@ XPCWrapper::ResolveNativeProperty(JSContext *cx, JSObject *wrapperObj,
} }
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
return ThrowException(rv, cx); return DoThrowException(rv, cx);
} }
if (newObj) { if (newObj) {
@ -457,7 +444,7 @@ XPCWrapper::ResolveNativeProperty(JSContext *cx, JSObject *wrapperObj,
// I suspect that we'd need to redo the security check on the new object // I suspect that we'd need to redo the security check on the new object
// (if it has a different class than the original object) and then call // (if it has a different class than the original object) and then call
// ResolveNativeProperty with *that* as the inner object. // ResolveNativeProperty with *that* as the inner object.
return ThrowException(NS_ERROR_NOT_IMPLEMENTED, cx); return DoThrowException(NS_ERROR_NOT_IMPLEMENTED, cx);
} }
} }
@ -472,7 +459,7 @@ XPCWrapper::ResolveNativeProperty(JSContext *cx, JSObject *wrapperObj,
XPCWrappedNative* wrapper = ccx.GetWrapper(); XPCWrappedNative* wrapper = ccx.GetWrapper();
if (wrapper != wn || !wrapper->IsValid()) { if (wrapper != wn || !wrapper->IsValid()) {
NS_ASSERTION(wrapper == wn, "Uh, how did this happen!"); NS_ASSERTION(wrapper == wn, "Uh, how did this happen!");
return ThrowException(NS_ERROR_XPC_BAD_CONVERT_JS, cx); return DoThrowException(NS_ERROR_XPC_BAD_CONVERT_JS, cx);
} }
// it would be a big surprise if there is a member without an // it would be a big surprise if there is a member without an
@ -494,7 +481,7 @@ XPCWrapper::ResolveNativeProperty(JSContext *cx, JSObject *wrapperObj,
JSString *str = JSVAL_TO_STRING(id); JSString *str = JSVAL_TO_STRING(id);
if (!str) { if (!str) {
return ThrowException(NS_ERROR_UNEXPECTED, cx); return DoThrowException(NS_ERROR_UNEXPECTED, cx);
} }
// Get (and perhaps lazily create) the member's value (commonly a // Get (and perhaps lazily create) the member's value (commonly a
@ -506,7 +493,7 @@ XPCWrapper::ResolveNativeProperty(JSContext *cx, JSObject *wrapperObj,
if (member->IsConstant()) { if (member->IsConstant()) {
if (!member->GetConstantValue(ccx, iface, &v)) { if (!member->GetConstantValue(ccx, iface, &v)) {
return ThrowException(NS_ERROR_XPC_BAD_CONVERT_JS, cx); return DoThrowException(NS_ERROR_XPC_BAD_CONVERT_JS, cx);
} }
} else if (member->IsAttribute()) { } else if (member->IsAttribute()) {
// An attribute is being resolved. Define the property, the value // An attribute is being resolved. Define the property, the value
@ -524,7 +511,7 @@ XPCWrapper::ResolveNativeProperty(JSContext *cx, JSObject *wrapperObj,
jsval funval; jsval funval;
if (!member->NewFunctionObject(ccx, iface, wrapper->GetFlatJSObject(), if (!member->NewFunctionObject(ccx, iface, wrapper->GetFlatJSObject(),
&funval)) { &funval)) {
return ThrowException(NS_ERROR_XPC_BAD_CONVERT_JS, cx); return DoThrowException(NS_ERROR_XPC_BAD_CONVERT_JS, cx);
} }
AUTO_MARK_JSVAL(ccx, funval); AUTO_MARK_JSVAL(ccx, funval);
@ -582,12 +569,11 @@ XPCWrapper::ResolveNativeProperty(JSContext *cx, JSObject *wrapperObj,
return JS_TRUE; return JS_TRUE;
} }
// static
JSBool JSBool
XPCWrapper::GetOrSetNativeProperty(JSContext *cx, JSObject *obj, GetOrSetNativeProperty(JSContext *cx, JSObject *obj,
XPCWrappedNative *wrappedNative, XPCWrappedNative *wrappedNative,
jsval id, jsval *vp, JSBool aIsSet, jsval id, jsval *vp, JSBool aIsSet,
JSBool isNativeWrapper) JSBool isNativeWrapper)
{ {
// This will do verification and the method lookup for us. // This will do verification and the method lookup for us.
JSObject *nativeObj = wrappedNative->GetFlatJSObject(); JSObject *nativeObj = wrappedNative->GetFlatJSObject();
@ -610,7 +596,7 @@ XPCWrapper::GetOrSetNativeProperty(JSContext *cx, JSObject *obj,
} }
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
return ThrowException(rv, cx); return DoThrowException(rv, cx);
} }
if (!retval) { if (!retval) {
return JS_FALSE; return JS_FALSE;
@ -643,7 +629,7 @@ XPCWrapper::GetOrSetNativeProperty(JSContext *cx, JSObject *obj,
XPCWrappedNative* wrapper = ccx.GetWrapper(); XPCWrappedNative* wrapper = ccx.GetWrapper();
if (wrapper != wrappedNative || !wrapper->IsValid()) { if (wrapper != wrappedNative || !wrapper->IsValid()) {
NS_ASSERTION(wrapper == wrappedNative, "Uh, how did this happen!"); NS_ASSERTION(wrapper == wrappedNative, "Uh, how did this happen!");
return ThrowException(NS_ERROR_XPC_BAD_CONVERT_JS, cx); return DoThrowException(NS_ERROR_XPC_BAD_CONVERT_JS, cx);
} }
// it would be a big surprise if there is a member without an // it would be a big surprise if there is a member without an
@ -665,13 +651,13 @@ XPCWrapper::GetOrSetNativeProperty(JSContext *cx, JSObject *obj,
if (member->IsConstant()) { if (member->IsConstant()) {
jsval memberval; jsval memberval;
if (!member->GetConstantValue(ccx, iface, &memberval)) { if (!member->GetConstantValue(ccx, iface, &memberval)) {
return ThrowException(NS_ERROR_XPC_BAD_CONVERT_JS, cx); return DoThrowException(NS_ERROR_XPC_BAD_CONVERT_JS, cx);
} }
// Getting the value of constants is easy, just return the // Getting the value of constants is easy, just return the
// value. Setting is not supported (obviously). // value. Setting is not supported (obviously).
if (aIsSet) { if (aIsSet) {
return ThrowException(NS_ERROR_XPC_BAD_CONVERT_JS, cx); return DoThrowException(NS_ERROR_XPC_BAD_CONVERT_JS, cx);
} }
*vp = memberval; *vp = memberval;
@ -689,7 +675,7 @@ XPCWrapper::GetOrSetNativeProperty(JSContext *cx, JSObject *obj,
jsval funval; jsval funval;
if (!member->NewFunctionObject(ccx, iface, wrapper->GetFlatJSObject(), if (!member->NewFunctionObject(ccx, iface, wrapper->GetFlatJSObject(),
&funval)) { &funval)) {
return ThrowException(NS_ERROR_XPC_BAD_CONVERT_JS, cx); return DoThrowException(NS_ERROR_XPC_BAD_CONVERT_JS, cx);
} }
AUTO_MARK_JSVAL(ccx, funval); AUTO_MARK_JSVAL(ccx, funval);
@ -700,7 +686,7 @@ XPCWrapper::GetOrSetNativeProperty(JSContext *cx, JSObject *obj,
if (aIsSet) { if (aIsSet) {
if (member->IsReadOnlyAttribute()) { if (member->IsReadOnlyAttribute()) {
// Trying to set a property for which there is no setter! // Trying to set a property for which there is no setter!
return ThrowException(NS_ERROR_NOT_AVAILABLE, cx); return DoThrowException(NS_ERROR_NOT_AVAILABLE, cx);
} }
#ifdef DEBUG_XPCNativeWrapper #ifdef DEBUG_XPCNativeWrapper
@ -736,11 +722,10 @@ XPCWrapper::GetOrSetNativeProperty(JSContext *cx, JSObject *obj,
} }
} }
// static
JSBool JSBool
XPCWrapper::NativeToString(JSContext *cx, XPCWrappedNative *wrappedNative, NativeToString(JSContext *cx, XPCWrappedNative *wrappedNative,
uintN argc, jsval *argv, jsval *rval, uintN argc, jsval *argv, jsval *rval,
JSBool isNativeWrapper) JSBool isNativeWrapper)
{ {
// Check whether toString was overridden in any object along // Check whether toString was overridden in any object along
// the wrapped native's object's prototype chain. // the wrapped native's object's prototype chain.
@ -757,7 +742,7 @@ XPCWrapper::NativeToString(JSContext *cx, XPCWrappedNative *wrappedNative,
XPCCallContext ccx(JS_CALLER, cx, wn_obj, nsnull, idAsVal); XPCCallContext ccx(JS_CALLER, cx, wn_obj, nsnull, idAsVal);
if (!ccx.IsValid()) { if (!ccx.IsValid()) {
// Shouldn't really happen. // Shouldn't really happen.
return ThrowException(NS_ERROR_FAILURE, cx); return DoThrowException(NS_ERROR_FAILURE, cx);
} }
XPCNativeInterface *iface = ccx.GetInterface(); XPCNativeInterface *iface = ccx.GetInterface();
@ -827,11 +812,10 @@ XPCWrapper::NativeToString(JSContext *cx, XPCWrappedNative *wrappedNative,
return JS_TRUE; return JS_TRUE;
} }
// static
JSBool JSBool
XPCWrapper::GetPropertyAttrs(JSContext *cx, JSObject *obj, jsid interned_id, GetPropertyAttrs(JSContext *cx, JSObject *obj, jsid interned_id,
uintN flags, JSBool wantDetails, uintN flags, JSBool wantDetails,
JSPropertyDescriptor *desc) JSPropertyDescriptor *desc)
{ {
if (!JS_GetPropertyDescriptorById(cx, obj, interned_id, flags, desc)) { if (!JS_GetPropertyDescriptorById(cx, obj, interned_id, flags, desc)) {
return JS_FALSE; return JS_FALSE;
@ -864,3 +848,5 @@ XPCWrapper::GetPropertyAttrs(JSContext *cx, JSObject *obj, jsid interned_id,
return JS_TRUE; return JS_TRUE;
} }
}

View File

@ -45,51 +45,60 @@
#include "xpcprivate.h" #include "xpcprivate.h"
/* These are used by XPCNativeWrapper polluted code in the common wrapper. */ namespace XPCNativeWrapper {
#define FLAG_DEEP 0x1
#define FLAG_EXPLICIT 0x2
// FLAG_RESOLVING is used to tag an XPCNativeWrapper when while it's calling
// the newResolve hook on the XPCWrappedNative's scriptable info.
#define FLAG_RESOLVING 0x4
// FLAG_IS_UXPC_OBJECT is used to tag a XPCCrossOriginWrapper that we created
// to deal with a cross origin XOW that has UniversalXPConnect privileges.
#define FLAG_IS_UXPC_OBJECT (1 << 29)
#define HAS_FLAGS(_val, _flags) \
((PRUint32(JSVAL_TO_INT(_val)) & (_flags)) != 0)
// Given an XPCWrappedNative pointer and the name of the function on
// XPCNativeScriptableFlags corresponding with a flag, returns 'true'
// if the flag is set.
// XXX Convert to using GetFlags() and not a macro.
#define NATIVE_HAS_FLAG(_wn, _flag) \ #define NATIVE_HAS_FLAG(_wn, _flag) \
((_wn)->GetScriptableInfo() && \ ((_wn)->GetScriptableInfo() && \
(_wn)->GetScriptableInfo()->GetFlags()._flag()) (_wn)->GetScriptableInfo()->GetFlags()._flag())
// Wraps a function in an XPCNativeWrapper function wrapper.
JSBool JSBool
XPC_NW_WrapFunction(JSContext* cx, JSObject* funobj, jsval *rval); WrapFunction(JSContext* cx, JSObject* funobj, jsval *rval);
// Given a value, if the original XPCNativeWrapper is a deep wrapper,
// returns a new XPCNativeWrapper around the value.
JSBool JSBool
XPC_NW_RewrapIfDeepWrapper(JSContext *cx, JSObject *obj, jsval v, RewrapIfDeepWrapper(JSContext *cx, JSObject *obj, jsval v, jsval *rval);
jsval *rval);
/* These are used by XPC_XOW_* polluted code in the common wrapper. */ } // namespace XPCNativeWrapper
namespace XPCCrossOriginWrapper {
// Wraps an object in an XPCCrossOriginWrapper.
JSBool JSBool
XPC_XOW_WrapFunction(JSContext *cx, JSObject *wrapperObj, JSObject *funobj, WrapObject(JSContext *cx, JSObject *parent, jsval *vp,
jsval *rval); XPCWrappedNative *wn = nsnull);
// Wraps a function in an XPCCrossOriginWrapper function wrapper.
JSBool JSBool
XPC_XOW_RewrapIfNeeded(JSContext *cx, JSObject *wrapperObj, jsval *vp); WrapFunction(JSContext *cx, JSObject *wrapperObj, JSObject *funobj,
jsval *rval);
// Wraps a value in a XOW if we need to wrap it (either it's cross-scope
// or ClassNeedsXOW returns true).
JSBool JSBool
XPC_XOW_WrapperMoved(JSContext *cx, XPCWrappedNative *innerObj, RewrapIfNeeded(JSContext *cx, JSObject *wrapperObj, jsval *vp);
XPCWrappedNativeScope *newScope);
// Notify a wrapper's XOWs that the wrapper has been reparented.
JSBool
WrapperMoved(JSContext *cx, XPCWrappedNative *innerObj,
XPCWrappedNativeScope *newScope);
// Returns 'true' if the current context is same-origin to the wrappedObject.
// If we are "same origin" because UniversalXPConnect is enabled and
// privilegeEnabled is non-null, then privilegeEnabled is set to true.
nsresult nsresult
CanAccessWrapper(JSContext *cx, JSObject *wrappedObj, JSBool *privilegeEnabled); CanAccessWrapper(JSContext *cx, JSObject *wrappedObj, JSBool *privilegeEnabled);
// Used by UnwrapSOW below. // Some elements can change their principal or otherwise need XOWs, even
JSBool // if they're same origin. This function returns 'true' if the element's
AllowedToAct(JSContext *cx, jsval idval); // JSClass's name matches one such element.
inline JSBool inline JSBool
XPC_XOW_ClassNeedsXOW(const char *name) ClassNeedsXOW(const char *name)
{ {
switch (*name) { switch (*name) {
case 'W': case 'W':
@ -110,306 +119,377 @@ XPC_XOW_ClassNeedsXOW(const char *name)
return JS_FALSE; return JS_FALSE;
} }
extern JSExtendedClass sXPC_COW_JSClass; } // namespace XPCCrossOriginWrapper
extern JSExtendedClass sXPC_SJOW_JSClass;
extern JSExtendedClass sXPC_SOW_JSClass;
extern JSExtendedClass sXPC_XOW_JSClass;
// This class wraps some common functionality between the three existing namespace ChromeObjectWrapper {
JSBool
WrapObject(JSContext *cx, JSObject *parent, jsval v, jsval *vp);
}
namespace XPCSafeJSObjectWrapper {
JSObject *
GetUnsafeObject(JSObject *obj);
JSBool
WrapObject(JSContext *cx, JSObject *scope, jsval v, jsval *vp);
PRBool
AttachNewConstructorObject(XPCCallContext &ccx, JSObject *aGlobalObject);
}
namespace SystemOnlyWrapper {
JSBool
WrapObject(JSContext *cx, JSObject *parent, jsval v, jsval *vp);
// Used by UnwrapSOW below.
JSBool
AllowedToAct(JSContext *cx, jsval idval);
}
namespace ChromeObjectWrapper { extern JSExtendedClass COWClass; }
namespace XPCSafeJSObjectWrapper { extern JSExtendedClass SJOWClass; }
namespace SystemOnlyWrapper { extern JSExtendedClass SOWClass; }
namespace XPCCrossOriginWrapper { extern JSExtendedClass XOWClass; }
extern nsIScriptSecurityManager *gScriptSecurityManager;
// This namespace wraps some common functionality between the three existing
// wrappers. Its main purpose is to allow XPCCrossOriginWrapper to act both // wrappers. Its main purpose is to allow XPCCrossOriginWrapper to act both
// as an XPCSafeSJSObjectWrapper and as an XPCNativeWrapper when required to // as an XPCSafeJSObjectWrapper and as an XPCNativeWrapper when required to
// do so (the decision is based on the principals of the wrapper and wrapped // do so (the decision is based on the principals of the wrapper and wrapped
// objects). // objects).
class XPCWrapper namespace XPCWrapper {
// FLAG_RESOLVING is used to tag a wrapper when while it's calling
// the newResolve. It tells the addProperty hook to not worry about
// what's being defined.
extern const PRUint32 FLAG_RESOLVING;
// This is used by individual wrappers as a starting point to stick
// per-wrapper flags into the flags slot. This is guaranteed to only
// have one bit set.
extern const PRUint32 LAST_FLAG;
inline JSBool
HAS_FLAGS(jsval v, PRUint32 flags)
{ {
public: return (PRUint32(JSVAL_TO_INT(v)) & flags) != 0;
/** }
* Used by the cross origin and safe wrappers: the slot that the wrapped
* object is held in.
*/
static const PRUint32 sWrappedObjSlot;
/** /**
* Used by all wrappers to store flags about their state. For example, * Used by the cross origin and safe wrappers: the slot that the wrapped
* it is used when resolving a property to tell to the addProperty hook * object is held in.
* that it shouldn't perform any security checks. */
*/ extern const PRUint32 sWrappedObjSlot;
static const PRUint32 sFlagsSlot;
/** /**
* The base number of slots needed by code using the above constants. * Used by all wrappers to store flags about their state. For example,
*/ * it is used when resolving a property to tell to the addProperty hook
static const PRUint32 sNumSlots; * that it shouldn't perform any security checks.
*/
extern const PRUint32 sFlagsSlot;
/** /**
* Cross origin wrappers and safe JSObject wrappers both need to know * The base number of slots needed by code using the above constants.
* which native is 'eval' for various purposes. */
*/ extern const PRUint32 sNumSlots;
static JSNative sEvalNative;
enum FunctionObjectSlot { /**
eWrappedFunctionSlot = 0, * Cross origin wrappers and safe JSObject wrappers both need to know
eAllAccessSlot = 1 * which native is 'eval' for various purposes.
}; */
extern JSNative sEvalNative;
// Helpful for keeping lines short: enum FunctionObjectSlot {
static const PRUint32 sSecMgrSetProp, sSecMgrGetProp; eWrappedFunctionSlot = 0,
eAllAccessSlot = 1
/**
* Given a context and a global object, fill our eval native.
*/
static JSBool FindEval(XPCCallContext &ccx, JSObject *obj) {
if (sEvalNative) {
return JS_TRUE;
}
jsval eval_val;
if (!::JS_GetProperty(ccx, obj, "eval", &eval_val)) {
return ThrowException(NS_ERROR_UNEXPECTED, ccx);
}
if (JSVAL_IS_PRIMITIVE(eval_val) ||
!::JS_ObjectIsFunction(ccx, JSVAL_TO_OBJECT(eval_val))) {
return ThrowException(NS_ERROR_UNEXPECTED, ccx);
}
sEvalNative =
::JS_GetFunctionNative(ccx, ::JS_ValueToFunction(ccx, eval_val));
if (!sEvalNative) {
return ThrowException(NS_ERROR_UNEXPECTED, ccx);
}
return JS_TRUE;
}
/**
* A useful function that throws an exception onto cx.
*/
static JSBool ThrowException(nsresult ex, JSContext *cx) {
XPCThrower::Throw(ex, cx);
return JS_FALSE;
}
/**
* Returns the script security manager used by XPConnect.
*/
static nsIScriptSecurityManager *GetSecurityManager() {
extern nsIScriptSecurityManager *gScriptSecurityManager;
return gScriptSecurityManager;
}
/**
* Used to ensure that an XPCWrappedNative stays alive when its scriptable
* helper defines an "expando" property on it.
*/
static JSBool MaybePreserveWrapper(JSContext *cx, XPCWrappedNative *wn,
uintN flags) {
if ((flags & JSRESOLVE_ASSIGNING) &&
(::JS_GetOptions(cx) & JSOPTION_PRIVATE_IS_NSISUPPORTS)) {
nsCOMPtr<nsIXPCScriptNotify> scriptNotify =
do_QueryInterface(static_cast<nsISupports*>
(JS_GetContextPrivate(cx)));
if (scriptNotify) {
return NS_SUCCEEDED(scriptNotify->PreserveWrapper(wn));
}
}
return JS_TRUE;
}
static JSBool IsSecurityWrapper(JSObject *wrapper)
{
JSClass *clasp = STOBJ_GET_CLASS(wrapper);
return (clasp->flags & JSCLASS_IS_EXTENDED) &&
((JSExtendedClass*)clasp)->wrappedObject;
}
/**
* Given an arbitrary object, Unwrap will return the wrapped object if the
* passed-in object is a wrapper that Unwrap knows about *and* the
* currently running code has permission to access both the wrapper and
* wrapped object.
*
* Since this is meant to be called from functions like
* XPCWrappedNative::GetWrappedNativeOfJSObject, it does not set an
* exception on |cx|.
*/
static JSObject *Unwrap(JSContext *cx, JSObject *wrapper);
/**
* Unwraps objects whose class is |xclasp|.
*/
static JSObject *UnwrapGeneric(JSContext *cx, const JSExtendedClass *xclasp,
JSObject *wrapper)
{
if (STOBJ_GET_CLASS(wrapper) != &xclasp->base) {
return nsnull;
}
jsval v;
if (!JS_GetReservedSlot(cx, wrapper, XPCWrapper::sWrappedObjSlot, &v)) {
JS_ClearPendingException(cx);
return nsnull;
}
if (JSVAL_IS_PRIMITIVE(v)) {
return nsnull;
}
return JSVAL_TO_OBJECT(v);
}
static JSObject *UnwrapSOW(JSContext *cx, JSObject *wrapper) {
wrapper = UnwrapGeneric(cx, &sXPC_SOW_JSClass, wrapper);
if (!wrapper) {
return nsnull;
}
if (!AllowedToAct(cx, JSVAL_VOID)) {
JS_ClearPendingException(cx);
wrapper = nsnull;
}
return wrapper;
}
/**
* Unwraps a XOW into its wrapped native.
*/
static JSObject *UnwrapXOW(JSContext *cx, JSObject *wrapper) {
wrapper = UnwrapGeneric(cx, &sXPC_XOW_JSClass, wrapper);
if (!wrapper) {
return nsnull;
}
nsresult rv = CanAccessWrapper(cx, wrapper, nsnull);
if (NS_FAILED(rv)) {
JS_ClearPendingException(cx);
wrapper = nsnull;
}
return wrapper;
}
static JSObject *UnwrapCOW(JSContext *cx, JSObject *wrapper) {
wrapper = UnwrapGeneric(cx, &sXPC_COW_JSClass, wrapper);
if (!wrapper) {
return nsnull;
}
nsresult rv = CanAccessWrapper(cx, wrapper, nsnull);
if (NS_FAILED(rv)) {
JS_ClearPendingException(cx);
wrapper = nsnull;
}
return wrapper;
}
/**
* Rewraps a property if it needs to be rewrapped. Used by
* GetOrSetNativeProperty to rewrap the return value.
*/
static JSBool RewrapIfDeepWrapper(JSContext *cx, JSObject *obj, jsval v,
jsval *rval, JSBool isNativeWrapper) {
*rval = v;
return isNativeWrapper
? XPC_NW_RewrapIfDeepWrapper(cx, obj, v, rval)
: XPC_XOW_RewrapIfNeeded(cx, obj, rval);
}
/**
* Creates a wrapper around a JSObject function object. Note
* XPCSafeJSObjectWrapper code doesn't have special function wrappers,
* obviating the need for this function. Instead, this is used by
* XPCNativeWrapper and the cross origin wrapper.
*/
static inline JSBool WrapFunction(JSContext *cx, JSObject *wrapperObj,
JSObject *funobj, jsval *v,
JSBool isNativeWrapper) {
return isNativeWrapper
? XPC_NW_WrapFunction(cx, funobj, v)
: XPC_XOW_WrapFunction(cx, wrapperObj, funobj, v);
}
/**
* Creates an iterator object that walks up the prototype of
* wrappedObj. This is suitable for for-in loops over a wrapper. If
* a property is not supposed to be reflected, the resolve hook
* is expected to censor it. tempWrapper must be rooted already.
*/
static JSObject *CreateIteratorObj(JSContext *cx,
JSObject *tempWrapper,
JSObject *wrapperObj,
JSObject *innerObj,
JSBool keysonly);
/**
* Called for the common part of adding a property to obj.
*/
static JSBool AddProperty(JSContext *cx, JSObject *wrapperObj,
JSBool wantGetterSetter, JSObject *innerObj,
jsval id, jsval *vp);
/**
* Called for the common part of deleting a property from obj.
*/
static JSBool DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
/**
* Called to enumerate the properties of |innerObj| onto |wrapperObj|.
*/
static JSBool Enumerate(JSContext *cx, JSObject *wrapperObj,
JSObject *innerObj);
/**
* Resolves a property (that may be) defined on |innerObj| onto
* |wrapperObj|. This will also resolve random, page-defined objects
* and is therefore unsuitable for cross-origin resolution.
*/
static JSBool NewResolve(JSContext *cx, JSObject *wrapperObj,
JSBool preserveVal, JSObject *innerObj,
jsval id, uintN flags, JSObject **objp);
/**
* Resolve a native property named id from innerObj onto wrapperObj. The
* native wrapper will be preserved if necessary. Note that if we resolve
* an attribute here, we don't deal with the value until later.
*/
static JSBool ResolveNativeProperty(JSContext *cx, JSObject *wrapperObj,
JSObject *innerObj, XPCWrappedNative *wn,
jsval id, uintN flags, JSObject **objp,
JSBool isNativeWrapper);
/**
* Gets a native property from obj. This goes directly through XPConnect, it
* does not look at Javascript-defined getters or setters. This ensures that
* the caller gets a real answer.
*/
static JSBool GetOrSetNativeProperty(JSContext *cx, JSObject *obj,
XPCWrappedNative *wrappedNative,
jsval id, jsval *vp, JSBool aIsSet,
JSBool isNativeWrapper);
/**
* Gets a string representation of wrappedNative, going through IDL.
*/
static JSBool NativeToString(JSContext *cx, XPCWrappedNative *wrappedNative,
uintN argc, jsval *argv, jsval *rval,
JSBool isNativeWrapper);
/**
* Looks up a property on obj. If it exists, then the parameters are filled
* in with useful values.
*
* NB: All parameters must be initialized before the call.
*/
static JSBool GetPropertyAttrs(JSContext *cx, JSObject *obj,
jsid interned_id, uintN flags,
JSBool wantDetails,
JSPropertyDescriptor *desc);
}; };
// Helpful for keeping lines short:
extern const PRUint32 sSecMgrSetProp, sSecMgrGetProp;
/**
* A useful function that throws an exception onto cx.
*/
inline JSBool
DoThrowException(nsresult ex, JSContext *cx)
{
XPCThrower::Throw(ex, cx);
return JS_FALSE;
}
/**
* Given a context and a global object, fill our eval native.
*/
inline JSBool
FindEval(XPCCallContext &ccx, JSObject *obj)
{
if (sEvalNative) {
return JS_TRUE;
}
jsval eval_val;
if (!::JS_GetProperty(ccx, obj, "eval", &eval_val)) {
return DoThrowException(NS_ERROR_UNEXPECTED, ccx);
}
if (JSVAL_IS_PRIMITIVE(eval_val) ||
!::JS_ObjectIsFunction(ccx, JSVAL_TO_OBJECT(eval_val))) {
return DoThrowException(NS_ERROR_UNEXPECTED, ccx);
}
sEvalNative =
::JS_GetFunctionNative(ccx, ::JS_ValueToFunction(ccx, eval_val));
if (!sEvalNative) {
return DoThrowException(NS_ERROR_UNEXPECTED, ccx);
}
return JS_TRUE;
}
/**
* Returns the script security manager used by XPConnect.
*/
inline nsIScriptSecurityManager *
GetSecurityManager()
{
return ::gScriptSecurityManager;
}
/**
* Used to ensure that an XPCWrappedNative stays alive when its scriptable
* helper defines an "expando" property on it.
*/
inline JSBool
MaybePreserveWrapper(JSContext *cx, XPCWrappedNative *wn, uintN flags)
{
if ((flags & JSRESOLVE_ASSIGNING) &&
(::JS_GetOptions(cx) & JSOPTION_PRIVATE_IS_NSISUPPORTS)) {
nsCOMPtr<nsIXPCScriptNotify> scriptNotify =
do_QueryInterface(static_cast<nsISupports*>
(JS_GetContextPrivate(cx)));
if (scriptNotify) {
return NS_SUCCEEDED(scriptNotify->PreserveWrapper(wn));
}
}
return JS_TRUE;
}
inline JSBool
IsSecurityWrapper(JSObject *wrapper)
{
JSClass *clasp = STOBJ_GET_CLASS(wrapper);
return (clasp->flags & JSCLASS_IS_EXTENDED) &&
((JSExtendedClass*)clasp)->wrappedObject;
}
/**
* Given an arbitrary object, Unwrap will return the wrapped object if the
* passed-in object is a wrapper that Unwrap knows about *and* the
* currently running code has permission to access both the wrapper and
* wrapped object.
*
* Since this is meant to be called from functions like
* XPCWrappedNative::GetWrappedNativeOfJSObject, it does not set an
* exception on |cx|.
*/
JSObject *
Unwrap(JSContext *cx, JSObject *wrapper);
/**
* Unwraps objects whose class is |xclasp|.
*/
inline JSObject *
UnwrapGeneric(JSContext *cx, const JSExtendedClass *xclasp, JSObject *wrapper)
{
if (STOBJ_GET_CLASS(wrapper) != &xclasp->base) {
return nsnull;
}
jsval v;
if (!JS_GetReservedSlot(cx, wrapper, XPCWrapper::sWrappedObjSlot, &v)) {
JS_ClearPendingException(cx);
return nsnull;
}
if (JSVAL_IS_PRIMITIVE(v)) {
return nsnull;
}
return JSVAL_TO_OBJECT(v);
}
inline JSObject *
UnwrapSOW(JSContext *cx, JSObject *wrapper)
{
wrapper = UnwrapGeneric(cx, &SystemOnlyWrapper::SOWClass, wrapper);
if (!wrapper) {
return nsnull;
}
if (!SystemOnlyWrapper::AllowedToAct(cx, JSVAL_VOID)) {
JS_ClearPendingException(cx);
wrapper = nsnull;
}
return wrapper;
}
/**
* Unwraps a XOW into its wrapped native.
*/
inline JSObject *
UnwrapXOW(JSContext *cx, JSObject *wrapper)
{
wrapper = UnwrapGeneric(cx, &XPCCrossOriginWrapper::XOWClass, wrapper);
if (!wrapper) {
return nsnull;
}
nsresult rv = XPCCrossOriginWrapper::CanAccessWrapper(cx, wrapper, nsnull);
if (NS_FAILED(rv)) {
JS_ClearPendingException(cx);
wrapper = nsnull;
}
return wrapper;
}
inline JSObject *
UnwrapCOW(JSContext *cx, JSObject *wrapper)
{
wrapper = UnwrapGeneric(cx, &ChromeObjectWrapper::COWClass, wrapper);
if (!wrapper) {
return nsnull;
}
nsresult rv = XPCCrossOriginWrapper::CanAccessWrapper(cx, wrapper, nsnull);
if (NS_FAILED(rv)) {
JS_ClearPendingException(cx);
wrapper = nsnull;
}
return wrapper;
}
/**
* Rewraps a property if it needs to be rewrapped. Used by
* GetOrSetNativeProperty to rewrap the return value.
*/
inline JSBool
RewrapIfDeepWrapper(JSContext *cx, JSObject *obj, jsval v, jsval *rval,
JSBool isNativeWrapper)
{
*rval = v;
return isNativeWrapper
? XPCNativeWrapper::RewrapIfDeepWrapper(cx, obj, v, rval)
: XPCCrossOriginWrapper::RewrapIfNeeded(cx, obj, rval);
}
/**
* Creates a wrapper around a JSObject function object. Note
* XPCSafeJSObjectWrapper code doesn't have special function wrappers,
* obviating the need for this function. Instead, this is used by
* XPCNativeWrapper and the cross origin wrapper.
*/
inline JSBool
WrapFunction(JSContext *cx, JSObject *wrapperObj, JSObject *funobj, jsval *v,
JSBool isNativeWrapper)
{
return isNativeWrapper
? XPCNativeWrapper::WrapFunction(cx, funobj, v)
: XPCCrossOriginWrapper::WrapFunction(cx, wrapperObj, funobj, v);
}
/**
* Creates an iterator object that walks up the prototype of
* wrappedObj. This is suitable for for-in loops over a wrapper. If
* a property is not supposed to be reflected, the resolve hook
* is expected to censor it. tempWrapper must be rooted already.
*/
JSObject *
CreateIteratorObj(JSContext *cx, JSObject *tempWrapper,
JSObject *wrapperObj, JSObject *innerObj,
JSBool keysonly);
/**
* Called for the common part of adding a property to obj.
*/
JSBool
AddProperty(JSContext *cx, JSObject *wrapperObj,
JSBool wantGetterSetter, JSObject *innerObj,
jsval id, jsval *vp);
/**
* Called for the common part of deleting a property from obj.
*/
JSBool
DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
/**
* Called to enumerate the properties of |innerObj| onto |wrapperObj|.
*/
JSBool
Enumerate(JSContext *cx, JSObject *wrapperObj, JSObject *innerObj);
/**
* Resolves a property (that may be) defined on |innerObj| onto
* |wrapperObj|. This will also resolve random, page-defined objects
* and is therefore unsuitable for cross-origin resolution.
*/
JSBool
NewResolve(JSContext *cx, JSObject *wrapperObj,
JSBool preserveVal, JSObject *innerObj,
jsval id, uintN flags, JSObject **objp);
/**
* Resolve a native property named id from innerObj onto wrapperObj. The
* native wrapper will be preserved if necessary. Note that if we resolve
* an attribute here, we don't deal with the value until later.
*/
JSBool
ResolveNativeProperty(JSContext *cx, JSObject *wrapperObj,
JSObject *innerObj, XPCWrappedNative *wn,
jsval id, uintN flags, JSObject **objp,
JSBool isNativeWrapper);
/**
* Gets a native property from obj. This goes directly through XPConnect, it
* does not look at Javascript-defined getters or setters. This ensures that
* the caller gets a real answer.
*/
JSBool
GetOrSetNativeProperty(JSContext *cx, JSObject *obj,
XPCWrappedNative *wrappedNative,
jsval id, jsval *vp, JSBool aIsSet,
JSBool isNativeWrapper);
/**
* Gets a string representation of wrappedNative, going through IDL.
*/
JSBool
NativeToString(JSContext *cx, XPCWrappedNative *wrappedNative,
uintN argc, jsval *argv, jsval *rval,
JSBool isNativeWrapper);
/**
* Looks up a property on obj. If it exists, then the parameters are filled
* in with useful values.
*
* NB: All parameters must be initialized before the call.
*/
JSBool
GetPropertyAttrs(JSContext *cx, JSObject *obj, jsid interned_id, uintN flags,
JSBool wantDetails, JSPropertyDescriptor *desc);
} // namespace XPCWrapper
#endif #endif

View File

@ -1068,7 +1068,7 @@ nsXPConnect::InitClasses(JSContext * aJSContext, JSObject * aGlobalJSObj)
if (!XPCNativeWrapper::AttachNewConstructorObject(ccx, aGlobalJSObj)) if (!XPCNativeWrapper::AttachNewConstructorObject(ccx, aGlobalJSObj))
return UnexpectedFailure(NS_ERROR_FAILURE); return UnexpectedFailure(NS_ERROR_FAILURE);
if (!XPC_SJOW_AttachNewConstructorObject(ccx, aGlobalJSObj)) if (!XPCSafeJSObjectWrapper::AttachNewConstructorObject(ccx, aGlobalJSObj))
return UnexpectedFailure(NS_ERROR_FAILURE); return UnexpectedFailure(NS_ERROR_FAILURE);
} }
@ -1206,7 +1206,7 @@ nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext,
if(!XPCNativeWrapper::AttachNewConstructorObject(ccx, globalJSObj)) if(!XPCNativeWrapper::AttachNewConstructorObject(ccx, globalJSObj))
return UnexpectedFailure(NS_ERROR_FAILURE); return UnexpectedFailure(NS_ERROR_FAILURE);
if(!XPC_SJOW_AttachNewConstructorObject(ccx, globalJSObj)) if(!XPCSafeJSObjectWrapper::AttachNewConstructorObject(ccx, globalJSObj))
return UnexpectedFailure(NS_ERROR_FAILURE); return UnexpectedFailure(NS_ERROR_FAILURE);
} }
} }
@ -2049,7 +2049,7 @@ nsXPConnect::GetXOWForObject(JSContext * aJSContext,
jsval * rval) jsval * rval)
{ {
*rval = OBJECT_TO_JSVAL(aWrappedObj); *rval = OBJECT_TO_JSVAL(aWrappedObj);
return XPC_XOW_WrapObject(aJSContext, aParent, rval) return XPCCrossOriginWrapper::WrapObject(aJSContext, aParent, rval)
? NS_OK : NS_ERROR_FAILURE; ? NS_OK : NS_ERROR_FAILURE;
} }
@ -2060,7 +2060,7 @@ nsXPConnect::GetCOWForObject(JSContext * aJSContext,
jsval * rval) jsval * rval)
{ {
*rval = OBJECT_TO_JSVAL(aWrappedObj); *rval = OBJECT_TO_JSVAL(aWrappedObj);
return XPC_COW_WrapObject(aJSContext, aParent, *rval, rval) return ChromeObjectWrapper::WrapObject(aJSContext, aParent, *rval, rval)
? NS_OK : NS_ERROR_FAILURE; ? NS_OK : NS_ERROR_FAILURE;
} }
@ -2458,7 +2458,8 @@ nsXPConnect::GetWrapperForObject(JSContext* aJSContext,
JSBool sameOrigin; JSBool sameOrigin;
JSBool sameScope = xpc_SameScope(objectscope, xpcscope, &sameOrigin); JSBool sameScope = xpc_SameScope(objectscope, xpcscope, &sameOrigin);
JSBool forceXOW = XPC_XOW_ClassNeedsXOW(STOBJ_GET_CLASS(aObject)->name); JSBool forceXOW =
XPCCrossOriginWrapper::ClassNeedsXOW(STOBJ_GET_CLASS(aObject)->name);
// We can do nothing if: // We can do nothing if:
// - We're wrapping a system object // - We're wrapping a system object
@ -2491,7 +2492,7 @@ nsXPConnect::GetWrapperForObject(JSContext* aJSContext,
else if(aFilenameFlags & JSFILENAME_SYSTEM) else if(aFilenameFlags & JSFILENAME_SYSTEM)
{ {
jsval val = OBJECT_TO_JSVAL(aObject); jsval val = OBJECT_TO_JSVAL(aObject);
if(XPC_SJOW_Construct(aJSContext, nsnull, 1, &val, &val)) if(XPCSafeJSObjectWrapper::WrapObject(aJSContext, nsnull, val, &val))
wrappedObj = JSVAL_TO_OBJECT(val); wrappedObj = JSVAL_TO_OBJECT(val);
} }
else else
@ -2502,7 +2503,7 @@ nsXPConnect::GetWrapperForObject(JSContext* aJSContext,
return NS_OK; return NS_OK;
jsval val = OBJECT_TO_JSVAL(aObject); jsval val = OBJECT_TO_JSVAL(aObject);
if(XPC_XOW_WrapObject(aJSContext, aScope, &val, wrapper)) if(XPCCrossOriginWrapper::WrapObject(aJSContext, aScope, &val, wrapper))
wrappedObj = JSVAL_TO_OBJECT(val); wrappedObj = JSVAL_TO_OBJECT(val);
} }
@ -2511,7 +2512,7 @@ nsXPConnect::GetWrapperForObject(JSContext* aJSContext,
*_retval = OBJECT_TO_JSVAL(wrappedObj); *_retval = OBJECT_TO_JSVAL(wrappedObj);
if(wrapper && wrapper->NeedsChromeWrapper() && if(wrapper && wrapper->NeedsChromeWrapper() &&
!XPC_SOW_WrapObject(aJSContext, aScope, *_retval, _retval)) !SystemOnlyWrapper::WrapObject(aJSContext, aScope, *_retval, _retval))
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
return NS_OK; return NS_OK;
} }

View File

@ -1362,7 +1362,7 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx,
"XPCSafeJSObjectWrapper\n"); "XPCSafeJSObjectWrapper\n");
#endif #endif
if(XPC_SJOW_Construct(ccx, nsnull, 1, &v, &v)) if(XPCSafeJSObjectWrapper::WrapObject(ccx, nsnull, v, &v))
destObj = JSVAL_TO_OBJECT(v); destObj = JSVAL_TO_OBJECT(v);
triedWrapping = JS_TRUE; triedWrapping = JS_TRUE;
} }
@ -1370,7 +1370,7 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx,
{ {
// Reaching across scopes from content code. Wrap // Reaching across scopes from content code. Wrap
// the new object in a XOW. // the new object in a XOW.
if (XPC_XOW_WrapObject(ccx, scope, &v)) if (XPCCrossOriginWrapper::WrapObject(ccx, scope, &v))
destObj = JSVAL_TO_OBJECT(v); destObj = JSVAL_TO_OBJECT(v);
triedWrapping = JS_TRUE; triedWrapping = JS_TRUE;
} }
@ -1384,9 +1384,10 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx,
AUTO_MARK_JSVAL(ccx, &wrappedObjVal); AUTO_MARK_JSVAL(ccx, &wrappedObjVal);
if(wrapper->NeedsChromeWrapper()) if(wrapper->NeedsChromeWrapper())
{ {
if(!XPC_SOW_WrapObject(ccx, xpcscope->GetGlobalJSObject(), using SystemOnlyWrapper::WrapObject;
OBJECT_TO_JSVAL(destObj), if(!WrapObject(ccx, xpcscope->GetGlobalJSObject(),
&wrappedObjVal)) OBJECT_TO_JSVAL(destObj),
&wrappedObjVal))
return JS_FALSE; return JS_FALSE;
} }
@ -1400,7 +1401,7 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx,
if(allowNativeWrapper && if(allowNativeWrapper &&
!(flags & JSFILENAME_SYSTEM) && !(flags & JSFILENAME_SYSTEM) &&
!JS_IsSystemObject(ccx, flat) && !JS_IsSystemObject(ccx, flat) &&
XPC_XOW_ClassNeedsXOW(name)) XPCCrossOriginWrapper::ClassNeedsXOW(name))
{ {
// From here on we might create new JSObjects, so we need to // From here on we might create new JSObjects, so we need to
// make sure that wrapper stays alive. // make sure that wrapper stays alive.
@ -1408,10 +1409,10 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx,
strongWrapper = wrapper; strongWrapper = wrapper;
AUTO_MARK_JSVAL(ccx, &v); AUTO_MARK_JSVAL(ccx, &v);
return XPC_XOW_WrapObject(ccx, scope, &v) && return XPCCrossOriginWrapper::WrapObject(ccx, scope, &v) &&
(!wrapper->NeedsChromeWrapper() || (!wrapper->NeedsChromeWrapper() ||
XPC_SOW_WrapObject(ccx, xpcscope->GetGlobalJSObject(), SystemOnlyWrapper::WrapObject(ccx, xpcscope->GetGlobalJSObject(),
v, &v)) && v, &v)) &&
CreateHolderIfNeeded(ccx, JSVAL_TO_OBJECT(v), d, dest); CreateHolderIfNeeded(ccx, JSVAL_TO_OBJECT(v), d, dest);
} }
@ -1419,10 +1420,12 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx,
if(allowNativeWrapper) if(allowNativeWrapper)
{ {
if(wrapper->NeedsChromeWrapper()) if(wrapper->NeedsChromeWrapper())
if(!XPC_SOW_WrapObject(ccx, xpcscope->GetGlobalJSObject(), v, d)) if(!SystemOnlyWrapper::WrapObject(ccx,
xpcscope->GetGlobalJSObject(),
v, d))
return JS_FALSE; return JS_FALSE;
if(wrapper->IsDoubleWrapper()) if(wrapper->IsDoubleWrapper())
if(!XPC_COW_WrapObject(ccx, xpcscope->GetGlobalJSObject(), v, d)) if(!ChromeObjectWrapper::WrapObject(ccx, xpcscope->GetGlobalJSObject(), v, d))
return JS_FALSE; return JS_FALSE;
} }
if(dest) if(dest)

View File

@ -4347,31 +4347,6 @@ xpc_SameScope(XPCWrappedNativeScope *objectscope,
nsISupports * nsISupports *
XPC_GetIdentityObject(JSContext *cx, JSObject *obj); XPC_GetIdentityObject(JSContext *cx, JSObject *obj);
PRBool
IsXPCSafeJSObjectWrapperClass(JSClass *clazz);
JSObject *
XPC_SJOW_GetUnsafeObject(JSObject *obj);
JSBool
XPC_SJOW_Construct(JSContext *cx, JSObject *obj, uintN, jsval *argv,
jsval *rval);
PRBool
XPC_SJOW_AttachNewConstructorObject(XPCCallContext &ccx,
JSObject *aGlobalObject);
JSBool
XPC_XOW_WrapObject(JSContext *cx, JSObject *parent, jsval *vp,
XPCWrappedNative *wn = nsnull);
JSBool
XPC_SOW_WrapObject(JSContext *cx, JSObject *parent, jsval v,
jsval *vp);
JSBool
XPC_COW_WrapObject(JSContext *cx, JSObject *parent, jsval v, jsval *vp);
#ifdef XPC_IDISPATCH_SUPPORT #ifdef XPC_IDISPATCH_SUPPORT
#ifdef WINCE #ifdef WINCE

View File

@ -1523,7 +1523,7 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx,
if(wrapper) if(wrapper)
{ {
if(!XPC_XOW_WrapperMoved(ccx, wrapper, aNewScope)) if(!XPCCrossOriginWrapper::WrapperMoved(ccx, wrapper, aNewScope))
{ {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
@ -1736,7 +1736,7 @@ return_tearoff:
// Protect against infinite recursion through XOWs. // Protect against infinite recursion through XOWs.
JSObject *unsafeObj; JSObject *unsafeObj;
clazz = STOBJ_GET_CLASS(outer); clazz = STOBJ_GET_CLASS(outer);
if(clazz == &sXPC_XOW_JSClass.base && if(clazz == &XPCCrossOriginWrapper::XOWClass.base &&
(unsafeObj = XPCWrapper::UnwrapXOW(cx, outer))) (unsafeObj = XPCWrapper::UnwrapXOW(cx, outer)))
{ {
outer = unsafeObj; outer = unsafeObj;

View File

@ -818,7 +818,7 @@ XPC_GetIdentityObject(JSContext *cx, JSObject *obj)
wrapper = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj); wrapper = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj);
if(!wrapper) { if(!wrapper) {
JSObject *unsafeObj = XPC_SJOW_GetUnsafeObject(obj); JSObject *unsafeObj = XPCSafeJSObjectWrapper::GetUnsafeObject(obj);
if(unsafeObj) if(unsafeObj)
return XPC_GetIdentityObject(cx, unsafeObj); return XPC_GetIdentityObject(cx, unsafeObj);
@ -853,9 +853,9 @@ XPC_WN_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
return Throw(rv, cx); return Throw(rv, cx);
if(!*bp && !JSVAL_IS_PRIMITIVE(v) && if(!*bp && !JSVAL_IS_PRIMITIVE(v) &&
IsXPCSafeJSObjectWrapperClass(STOBJ_GET_CLASS(JSVAL_TO_OBJECT(v)))) STOBJ_GET_CLASS(JSVAL_TO_OBJECT(v)) == &XPCSafeJSObjectWrapper::SJOWClass.base)
{ {
v = OBJECT_TO_JSVAL(XPC_SJOW_GetUnsafeObject(JSVAL_TO_OBJECT(v))); v = OBJECT_TO_JSVAL(XPCSafeJSObjectWrapper::GetUnsafeObject(JSVAL_TO_OBJECT(v)));
rv = si->GetCallback()->Equality(wrapper, cx, obj, v, bp); rv = si->GetCallback()->Equality(wrapper, cx, obj, v, bp);
if(NS_FAILED(rv)) if(NS_FAILED(rv))