示例#1
0
bool
InterposeProperty(JSContext* cx, HandleObject target, const nsIID* iid, HandleId id,
                  MutableHandle<JSPropertyDescriptor> descriptor)
{
    // We only want to do interpostion on DOM instances and
    // wrapped natives.
    RootedObject unwrapped(cx, UncheckedUnwrap(target));
    const js::Class* clasp = js::GetObjectClass(unwrapped);
    if (!mozilla::dom::IsDOMClass(clasp) &&
        !IS_WN_CLASS(clasp) &&
        !IS_PROTO_CLASS(clasp) &&
        clasp != &OuterWindowProxyClass) {
        return true;
    }

    XPCWrappedNativeScope* scope = ObjectScope(CurrentGlobalOrNull(cx));
    MOZ_ASSERT(scope->HasInterposition());

    nsCOMPtr<nsIAddonInterposition> interp = scope->GetInterposition();
    JSAddonId* addonId = AddonIdOfObject(target);
    RootedValue addonIdValue(cx, StringValue(StringOfAddonId(addonId)));
    RootedValue prop(cx, IdToValue(id));
    RootedValue targetValue(cx, ObjectValue(*target));
    RootedValue descriptorVal(cx);
    nsresult rv = interp->InterposeProperty(addonIdValue, targetValue,
                                            iid, prop, &descriptorVal);
    if (NS_FAILED(rv)) {
        xpc::Throw(cx, rv);
        return false;
    }

    if (!descriptorVal.isObject())
        return true;

    // We need to be careful parsing descriptorVal. |cx| is in the compartment
    // of the add-on and the descriptor is in the compartment of the
    // interposition. We could wrap the descriptor in the add-on's compartment
    // and then parse it. However, parsing the descriptor fetches properties
    // from it, and we would try to interpose on those property accesses. So
    // instead we parse in the interposition's compartment and then wrap the
    // descriptor.

    {
        JSAutoCompartment ac(cx, &descriptorVal.toObject());
        if (!JS::ObjectToCompletePropertyDescriptor(cx, target, descriptorVal, descriptor))
            return false;
    }

    // Always make the property non-configurable regardless of what the
    // interposition wants.
    descriptor.setAttributes(descriptor.attributes() | JSPROP_PERMANENT);

    if (!JS_WrapPropertyDescriptor(cx, descriptor))
        return false;

    return true;
}
示例#2
0
static JSBool
DefineGetterOrSetter(JSContext *cx, uintN argc, JSBool wantGetter, jsval *vp)
{
    uintN attrs;
    JSBool found;
    JSPropertyOp getter, setter;
    JSObject *obj2;
    jsval v;
    jsid interned_id;

    XPC_QS_ASSERT_CONTEXT_OK(cx);
    JSObject *obj = JS_THIS_OBJECT(cx, vp);
    if (!obj)
        return JS_FALSE;
    JSFastNative forward = wantGetter ? js_obj_defineGetter : js_obj_defineSetter;
    jsval id = (argc >= 1) ? JS_ARGV(cx, vp)[0] : JSVAL_VOID;
    if(!JSVAL_IS_STRING(id))
        return forward(cx, argc, vp);
    JSString *str = JSVAL_TO_STRING(id);

    const char *name = JS_GetStringBytes(str);
    if(!JS_ValueToId(cx, id, &interned_id) ||
       !JS_LookupPropertyWithFlagsById(cx, obj, interned_id,
                                       JSRESOLVE_QUALIFIED, &obj2, &v) ||
       (obj2 &&
        !JS_GetPropertyAttrsGetterAndSetterById(cx, obj2, interned_id, &attrs,
                                                &found, &getter, &setter)))
        return JS_FALSE;

    // The property didn't exist, already has a getter or setter, or is not
    // our property, then just forward now.
    if(!obj2 ||
       (attrs & (JSPROP_GETTER | JSPROP_SETTER)) ||
       !(getter || setter) ||
       !IS_PROTO_CLASS(STOBJ_GET_CLASS(obj2)))
        return forward(cx, argc, vp);

    // Reify the getter and setter...
    if(!ReifyPropertyOps(cx, obj, id, interned_id, name, getter, setter,
                         nsnull, nsnull))
        return JS_FALSE;

    return forward(cx, argc, vp);
}
示例#3
0
static JSBool
LookupGetterOrSetter(JSContext *cx, JSBool wantGetter, uintN argc, jsval *vp)
{
    uintN attrs;
    JSBool found;
    JSPropertyOp getter, setter;
    JSObject *obj2;
    jsid interned_id;
    jsval v;

    XPC_QS_ASSERT_CONTEXT_OK(cx);

    if(argc == 0)
    {
        JS_SET_RVAL(cx, vp, JSVAL_VOID);
        return JS_TRUE;
    }

    JSObject *obj = JS_THIS_OBJECT(cx, vp);
    if (!obj)
        return JS_FALSE;
    jsval idval = JS_ARGV(cx, vp)[0];

    const char *name = JSVAL_IS_STRING(idval)
                       ? JS_GetStringBytes(JSVAL_TO_STRING(idval))
                       : nsnull;
    if(!JS_ValueToId(cx, idval, &interned_id) ||
       !JS_LookupPropertyWithFlagsById(cx, obj, interned_id,
                                       JSRESOLVE_QUALIFIED, &obj2, &v) ||
       (obj2 &&
        !JS_GetPropertyAttrsGetterAndSetterById(cx, obj2, interned_id, &attrs,
                                                &found, &getter, &setter)))
        return JS_FALSE;

    // No property at all means no getters or setters possible.
    if(!obj2 || !found)
    {
        JS_SET_RVAL(cx, vp, JSVAL_VOID);
        return JS_TRUE;
    }

    // Inline obj_lookup[GS]etter here.
    if(wantGetter)
    {
        if(attrs & JSPROP_GETTER)
        {
            JS_SET_RVAL(cx, vp,
                        OBJECT_TO_JSVAL(JS_FUNC_TO_DATA_PTR(JSObject *, getter)));
            return JS_TRUE;
        }
    }
    else
    {
        if(attrs & JSPROP_SETTER)
        {
            JS_SET_RVAL(cx, vp,
                        OBJECT_TO_JSVAL(JS_FUNC_TO_DATA_PTR(JSObject *, setter)));
            return JS_TRUE;
        }
    }

    // Since XPConnect doesn't use JSPropertyOps in any other contexts,
    // ensuring that we have an XPConnect prototype object ensures that
    // we are only going to expose quickstubbed properties to script.
    // Also be careful not to overwrite existing properties!
    if(!name ||
       !IS_PROTO_CLASS(STOBJ_GET_CLASS(obj2)) ||
       (attrs & (JSPROP_GETTER | JSPROP_SETTER)) ||
       !(getter || setter))
    {
        JS_SET_RVAL(cx, vp, JSVAL_VOID);
        return JS_TRUE;
    }

    JSObject *getterobj, *setterobj;
    if(!ReifyPropertyOps(cx, obj, idval, interned_id, name, getter, setter,
                         &getterobj, &setterobj))
        return JS_FALSE;

    JSObject *wantedobj = wantGetter ? getterobj : setterobj;
    v = wantedobj ? OBJECT_TO_JSVAL(wantedobj) : JSVAL_VOID;
    JS_SET_RVAL(cx, vp, v);
    return JS_TRUE;
}