From 9f4458505ffe02abcb155b21eabfab522a1404a7 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Wed, 21 Sep 2011 21:30:27 -0400 Subject: [PATCH] Bug 660233 part 2. Move nodePrincipal, baseURIObject, and documentURIObject from classinfo to XrayWrapper and to DOM prototypes in chrome documents. r=mrbkap --- dom/base/nsDOMClassInfo.cpp | 260 ++++++++++------------ dom/base/nsDOMClassInfo.h | 17 +- js/src/xpconnect/src/xpcjsruntime.cpp | 5 +- js/src/xpconnect/src/xpcprivate.h | 3 + js/src/xpconnect/wrappers/XrayWrapper.cpp | 176 +++++++++++++-- 5 files changed, 283 insertions(+), 178 deletions(-) diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index 37a79d1e7808..c166cb20acc6 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -528,9 +528,7 @@ static const char kDOMStringBundleURL[] = #define NODE_SCRIPTABLE_FLAGS \ ((DOM_DEFAULT_SCRIPTABLE_FLAGS | \ nsIXPCScriptable::USE_STUB_EQUALITY_HOOK | \ - nsIXPCScriptable::WANT_GETPROPERTY | \ - nsIXPCScriptable::WANT_ADDPROPERTY | \ - nsIXPCScriptable::WANT_SETPROPERTY) & \ + nsIXPCScriptable::WANT_ADDPROPERTY) & \ ~nsIXPCScriptable::USE_JSSTUB_FOR_ADDPROPERTY) // We need to let JavaScript QI elements to interfaces that are not in @@ -554,8 +552,6 @@ static const char kDOMStringBundleURL[] = #define DOCUMENT_SCRIPTABLE_FLAGS \ (NODE_SCRIPTABLE_FLAGS | \ nsIXPCScriptable::WANT_POSTCREATE | \ - nsIXPCScriptable::WANT_ADDPROPERTY | \ - nsIXPCScriptable::WANT_GETPROPERTY | \ nsIXPCScriptable::WANT_ENUMERATE) #define ARRAY_SCRIPTABLE_FLAGS \ @@ -765,7 +761,8 @@ static nsDOMClassInfoData sClassInfoData[] = { // Misc HTML classes NS_DEFINE_CLASSINFO_DATA(HTMLDocument, nsHTMLDocumentSH, - DOCUMENT_SCRIPTABLE_FLAGS) + DOCUMENT_SCRIPTABLE_FLAGS | + nsIXPCScriptable::WANT_GETPROPERTY) NS_DEFINE_CLASSINFO_DATA(HTMLOptionsCollection, nsHTMLOptionsCollectionSH, ARRAY_SCRIPTABLE_FLAGS | @@ -869,6 +866,7 @@ static nsDOMClassInfoData sClassInfoData[] = { ELEMENT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(HTMLSelectElement, nsHTMLSelectElementSH, ELEMENT_SCRIPTABLE_FLAGS | + nsIXPCScriptable::WANT_SETPROPERTY | nsIXPCScriptable::WANT_GETPROPERTY) NS_DEFINE_CLASSINFO_DATA(HTMLSpanElement, nsElementSH, ELEMENT_SCRIPTABLE_FLAGS) @@ -6385,10 +6383,9 @@ LocationSetterGuts(JSContext *cx, JSObject *obj, jsval *vp) XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj); // The error checks duplicate code in THROW_AND_RETURN_IF_BAD_WRAPPER - NS_ENSURE_TRUE(wrapper, NS_ERROR_XPC_BAD_OP_ON_WN_PROTO); - NS_ENSURE_TRUE(wrapper->IsValid(), NS_ERROR_XPC_HAS_BEEN_SHUTDOWN); + NS_ENSURE_TRUE(!wrapper || wrapper->IsValid(), NS_ERROR_XPC_HAS_BEEN_SHUTDOWN); - nsCOMPtr xpcomObj = do_QueryWrappedNative(wrapper); + nsCOMPtr xpcomObj = do_QueryWrappedNative(wrapper, obj); NS_ENSURE_TRUE(xpcomObj, NS_ERROR_UNEXPECTED); nsCOMPtr location; @@ -7129,6 +7126,79 @@ nsNavigatorSH::PreCreate(nsISupports *nativeObj, JSContext *cx, // DOM Node helper +template +static JSBool +GetterShim(JSContext *cx, JSObject *obj, jsid /* unused */, jsval *vp) +{ + nsresult rv = (*func)(cx, obj, vp); + if (NS_FAILED(rv)) { + if (!::JS_IsExceptionPending(cx)) { + nsDOMClassInfo::ThrowJSException(cx, rv); + } + return JS_FALSE; + } + + return JS_TRUE; +} + +// Can't be static so GetterShim will compile +nsresult +BaseURIObjectGetter(JSContext *cx, JSObject *obj, jsval *vp) +{ + // This function duplicates some of the logic in XPC_WN_HelperGetProperty + XPCWrappedNative *wrapper = + XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj); + + // The error checks duplicate code in THROW_AND_RETURN_IF_BAD_WRAPPER + NS_ENSURE_TRUE(!wrapper || wrapper->IsValid(), NS_ERROR_XPC_HAS_BEEN_SHUTDOWN); + + nsCOMPtr node = do_QueryWrappedNative(wrapper, obj); + NS_ENSURE_TRUE(node, NS_ERROR_UNEXPECTED); + + nsCOMPtr uri = node->GetBaseURI(); + return WrapNative(cx, JS_GetGlobalForScopeChain(cx), uri, + &NS_GET_IID(nsIURI), PR_TRUE, vp); +} + +// Can't be static so GetterShim will compile +nsresult +NodePrincipalGetter(JSContext *cx, JSObject *obj, jsval *vp) +{ + // This function duplicates some of the logic in XPC_WN_HelperGetProperty + XPCWrappedNative *wrapper = + XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj); + + // The error checks duplicate code in THROW_AND_RETURN_IF_BAD_WRAPPER + NS_ENSURE_TRUE(!wrapper || wrapper->IsValid(), NS_ERROR_XPC_HAS_BEEN_SHUTDOWN); + + nsCOMPtr node = do_QueryWrappedNative(wrapper, obj); + NS_ENSURE_TRUE(node, NS_ERROR_UNEXPECTED); + + return WrapNative(cx, JS_GetGlobalForScopeChain(cx), node->NodePrincipal(), + &NS_GET_IID(nsIPrincipal), PR_TRUE, vp); +} + +NS_IMETHODIMP +nsNodeSH::PostCreatePrototype(JSContext * cx, JSObject * proto) +{ + // set up our proto first + nsresult rv = nsDOMGenericSH::PostCreatePrototype(cx, proto); + + if (xpc::AccessCheck::isChrome(proto->compartment())) { + // Stick nodePrincipal and baseURIObject properties on there + JS_DefinePropertyById(cx, proto, sNodePrincipal_id, + JSVAL_VOID, GetterShim, + nsnull, + JSPROP_READONLY | JSPROP_SHARED); + JS_DefinePropertyById(cx, proto, sBaseURIObject_id, + JSVAL_VOID, GetterShim, + nsnull, + JSPROP_READONLY | JSPROP_SHARED); + } + + return rv; +} + PRBool nsNodeSH::IsCapabilityEnabled(const char* aCapability) { @@ -7138,26 +7208,6 @@ nsNodeSH::IsCapabilityEnabled(const char* aCapability) enabled; } -nsresult -nsNodeSH::DefineVoidProp(JSContext* cx, JSObject* obj, jsid id, - JSObject** objp) -{ - NS_ASSERTION(JSID_IS_STRING(id), "id must be a string"); - - // We want this to be as invisible to content script as possible. So - // don't enumerate this, and set is as JSPROP_SHARED so it won't get - // cached on the object. - JSBool ok = ::JS_DefinePropertyById(cx, obj, id, JSVAL_VOID, - nsnull, nsnull, JSPROP_SHARED); - - if (!ok) { - return NS_ERROR_FAILURE; - } - - *objp = obj; - return NS_OK; -} - NS_IMETHODIMP nsNodeSH::PreCreate(nsISupports *nativeObj, JSContext *cx, JSObject *globalObj, JSObject **parentObj) @@ -7305,11 +7355,6 @@ nsNodeSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval) { - if ((id == sBaseURIObject_id || id == sNodePrincipal_id) && - IsPrivilegedScript()) { - return DefineVoidProp(cx, obj, id, objp); - } - if (id == sOnload_id || id == sOnerror_id) { // Make sure that this node can't go away while waiting for a // network load that could fire an event handler. @@ -7324,63 +7369,6 @@ nsNodeSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, _retval); } -NS_IMETHODIMP -nsNodeSH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsid id, jsval *vp, PRBool *_retval) -{ - if (id == sBaseURIObject_id && IsPrivilegedScript()) { - // I wish GetBaseURI lived on nsINode - nsCOMPtr uri; - nsCOMPtr content = do_QueryWrappedNative(wrapper, obj); - if (content) { - uri = content->GetBaseURI(); - NS_ENSURE_TRUE(uri, NS_ERROR_OUT_OF_MEMORY); - } else { - nsCOMPtr doc = do_QueryWrappedNative(wrapper, obj); - NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED); - - uri = doc->GetBaseURI(); - NS_ENSURE_TRUE(uri, NS_ERROR_NOT_AVAILABLE); - } - - nsCOMPtr holder; - nsresult rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), uri, - &NS_GET_IID(nsIURI), PR_TRUE, vp, - getter_AddRefs(holder)); - return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING; - } - - if (id == sNodePrincipal_id && IsPrivilegedScript()) { - nsCOMPtr node = do_QueryWrappedNative(wrapper, obj); - NS_ENSURE_TRUE(node, NS_ERROR_UNEXPECTED); - - nsCOMPtr holder; - nsresult rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), - node->NodePrincipal(), &NS_GET_IID(nsIPrincipal), - PR_TRUE, vp, getter_AddRefs(holder)); - return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING; - } - - // Note: none of our ancestors want GetProperty - return NS_OK; -} - -NS_IMETHODIMP -nsNodeSH::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsid id, jsval *vp, PRBool *_retval) -{ - if ((id == sBaseURIObject_id || id == sNodePrincipal_id) && - IsPrivilegedScript()) { - // We don't want privileged script that can read this property to set it, - // but _do_ want to allow everyone else to set a value they can then read. - // - // XXXbz Is there a better error we could use here? - return NS_ERROR_DOM_NOT_SUPPORTED_ERR; - } - - return NS_OK; -} - NS_IMETHODIMP nsNodeSH::GetFlags(PRUint32 *aFlags) { @@ -8247,6 +8235,41 @@ nsDOMStringMapSH::JSIDToProp(const jsid& aId, nsAString& aResult) return true; } +// Can't be static so GetterShim will compile +nsresult +DocumentURIObjectGetter(JSContext *cx, JSObject *obj, jsval *vp) +{ + // This function duplicates some of the logic in XPC_WN_HelperGetProperty + XPCWrappedNative *wrapper = + XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj); + + // The error checks duplicate code in THROW_AND_RETURN_IF_BAD_WRAPPER + NS_ENSURE_TRUE(!wrapper || wrapper->IsValid(), NS_ERROR_XPC_HAS_BEEN_SHUTDOWN); + + nsCOMPtr doc = do_QueryWrappedNative(wrapper, obj); + NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED); + + return WrapNative(cx, JS_GetGlobalForScopeChain(cx), doc->GetDocumentURI(), + &NS_GET_IID(nsIURI), PR_TRUE, vp); +} + +NS_IMETHODIMP +nsDocumentSH::PostCreatePrototype(JSContext * cx, JSObject * proto) +{ + // set up our proto first + nsresult rv = nsNodeSH::PostCreatePrototype(cx, proto); + + if (xpc::AccessCheck::isChrome(proto->compartment())) { + // Stick a documentURIObject property on there + JS_DefinePropertyById(cx, proto, sDocumentURIObject_id, + JSVAL_VOID, GetterShim, + nsnull, + JSPROP_READONLY | JSPROP_SHARED); + } + + return rv; +} + NS_IMETHODIMP nsDocumentSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, jsid id, PRUint32 flags, @@ -8273,8 +8296,6 @@ nsDocumentSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, getter_AddRefs(holder)); NS_ENSURE_SUCCESS(rv, rv); - JSAutoRequest ar(cx); - JSBool ok = ::JS_DefinePropertyById(cx, obj, id, v, nsnull, LocationSetter, JSPROP_PERMANENT | JSPROP_ENUMERATE); @@ -8288,50 +8309,9 @@ nsDocumentSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, return NS_OK; } - if (id == sDocumentURIObject_id && IsPrivilegedScript()) { - return DefineVoidProp(cx, obj, id, objp); - } - return nsNodeSH::NewResolve(wrapper, cx, obj, id, flags, objp, _retval); } -NS_IMETHODIMP -nsDocumentSH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsid id, jsval *vp, PRBool *_retval) -{ - if (id == sDocumentURIObject_id && IsPrivilegedScript()) { - nsCOMPtr doc = do_QueryWrappedNative(wrapper); - NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED); - - nsIURI* uri = doc->GetDocumentURI(); - NS_ENSURE_TRUE(uri, NS_ERROR_NOT_AVAILABLE); - - nsCOMPtr holder; - nsresult rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), uri, - &NS_GET_IID(nsIURI), PR_TRUE, vp, - getter_AddRefs(holder)); - - return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING; - } - - return nsNodeSH::GetProperty(wrapper, cx, obj, id, vp, _retval); -} - -NS_IMETHODIMP -nsDocumentSH::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsid id, jsval *vp, PRBool *_retval) -{ - if (id == sDocumentURIObject_id && IsPrivilegedScript()) { - // We don't want privileged script that can read this property to set it, - // but _do_ want to allow everyone else to set a value they can then read. - // - // XXXbz Is there a better error we could use here? - return NS_ERROR_DOM_NOT_SUPPORTED_ERR; - } - - return nsNodeSH::SetProperty(wrapper, cx, obj, id, vp, _retval); -} - NS_IMETHODIMP nsDocumentSH::GetFlags(PRUint32* aFlags) { @@ -8997,7 +8977,7 @@ nsHTMLDocumentSH::GetProperty(nsIXPConnectWrappedNative *wrapper, } } - return nsDocumentSH::GetProperty(wrapper, cx, obj, id, vp, _retval); + return NS_OK; } // HTMLFormElement helper @@ -9096,7 +9076,7 @@ nsHTMLFormElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper, } } - return nsElementSH::GetProperty(wrapper, cx, obj, id, vp, _retval);; + return NS_OK; } NS_IMETHODIMP @@ -9230,7 +9210,7 @@ nsHTMLSelectElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper, } } - return nsElementSH::GetProperty(wrapper, cx, obj, id, vp, _retval);; + return NS_OK; } // static @@ -9281,7 +9261,7 @@ nsHTMLSelectElementSH::SetProperty(nsIXPConnectWrappedNative *wrapper, return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING; } - return nsElementSH::SetProperty(wrapper, cx, obj, id, vp, _retval); + return NS_OK; } @@ -9554,7 +9534,7 @@ nsHTMLPluginObjElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper, return *_retval ? NS_SUCCESS_I_DID_SOMETHING : NS_ERROR_FAILURE; } - return nsElementSH::GetProperty(wrapper, cx, obj, id, vp, _retval); + return NS_OK; } NS_IMETHODIMP @@ -9583,7 +9563,7 @@ nsHTMLPluginObjElementSH::SetProperty(nsIXPConnectWrappedNative *wrapper, return *_retval ? NS_SUCCESS_I_DID_SOMETHING : NS_ERROR_FAILURE; } - return nsElementSH::SetProperty(wrapper, cx, obj, id, vp, _retval); + return NS_OK; } NS_IMETHODIMP diff --git a/dom/base/nsDOMClassInfo.h b/dom/base/nsDOMClassInfo.h index 1110df00cc74..896007f0a0e8 100644 --- a/dom/base/nsDOMClassInfo.h +++ b/dom/base/nsDOMClassInfo.h @@ -511,25 +511,15 @@ protected: return IsCapabilityEnabled("UniversalXPConnect"); } - // Helper to define a void property with JSPROP_SHARED; this can do all the - // work so it's safe to just return whatever it returns. |obj| is the object - // we're defining on, |id| is the name of the prop. This must be a string - // jsval. |objp| is the out param if we define successfully. - nsresult DefineVoidProp(JSContext* cx, JSObject* obj, jsid id, - JSObject** objp); - public: NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx, JSObject *globalObj, JSObject **parentObj); + NS_IMETHOD PostCreatePrototype(JSContext * cx, JSObject * proto); NS_IMETHOD AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, jsid id, jsval *vp, PRBool *_retval); NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval); - NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsid id, jsval *vp, PRBool *_retval); - NS_IMETHOD SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsid id, jsval *vp, PRBool *_retval); NS_IMETHOD GetFlags(PRUint32 *aFlags); virtual void PreserveWrapper(nsISupports *aNative); @@ -827,13 +817,10 @@ public: } public: + NS_IMETHOD PostCreatePrototype(JSContext * cx, JSObject * proto); NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval); - NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsid id, jsval *vp, PRBool *_retval); - NS_IMETHOD SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsid id, jsval *vp, PRBool *_retval); NS_IMETHOD GetFlags(PRUint32* aFlags); NS_IMETHOD PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj); diff --git a/js/src/xpconnect/src/xpcjsruntime.cpp b/js/src/xpconnect/src/xpcjsruntime.cpp index 9913cc2f67f7..c0f464299da9 100644 --- a/js/src/xpconnect/src/xpcjsruntime.cpp +++ b/js/src/xpconnect/src/xpcjsruntime.cpp @@ -80,7 +80,10 @@ const char* XPCJSRuntime::mStrings[] = { "__proto__", // IDX_PROTO "__iterator__", // IDX_ITERATOR "__exposedProps__", // IDX_EXPOSEDPROPS - "__scriptOnly__" // IDX_SCRIPTONLY + "__scriptOnly__", // IDX_SCRIPTONLY + "baseURIObject", // IDX_BASEURIOBJECT + "nodePrincipal", // IDX_NODEPRINCIPAL + "documentURIObject" // IDX_DOCUMENTURIOBJECT }; /***************************************************************************/ diff --git a/js/src/xpconnect/src/xpcprivate.h b/js/src/xpconnect/src/xpcprivate.h index cfea27a26044..4939defb1b9e 100644 --- a/js/src/xpconnect/src/xpcprivate.h +++ b/js/src/xpconnect/src/xpcprivate.h @@ -725,6 +725,9 @@ public: IDX_ITERATOR , IDX_EXPOSEDPROPS , IDX_SCRIPTONLY , + IDX_BASEURIOBJECT , + IDX_NODEPRINCIPAL , + IDX_DOCUMENTURIOBJECT , IDX_TOTAL_COUNT // just a count of the above }; diff --git a/js/src/xpconnect/wrappers/XrayWrapper.cpp b/js/src/xpconnect/wrappers/XrayWrapper.cpp index d83bb0d273c7..b604e9daa63d 100644 --- a/js/src/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/src/xpconnect/wrappers/XrayWrapper.cpp @@ -46,6 +46,9 @@ #include "jscntxt.h" #include "jsiter.h" +#include "nsINode.h" +#include "nsIDocument.h" + #include "XPCWrapper.h" #include "xpcprivate.h" @@ -332,11 +335,118 @@ ResolveNativeProperty(JSContext *cx, JSObject *wrapper, JSObject *holder, jsid i static JSBool wrappedJSObject_getter(JSContext *cx, JSObject *wrapper, jsid id, jsval *vp) { + if (!wrapper->isWrapper() || !WrapperFactory::IsXrayWrapper(wrapper)) { + JS_ReportError(cx, "Unexpected object"); + return false; + } + *vp = OBJECT_TO_JSVAL(wrapper); return WrapperFactory::WaiveXrayAndWrap(cx, vp); } +template +static bool +Is(JSObject *wrapper) +{ + JSObject *holder = GetHolder(wrapper); + XPCWrappedNative *wn = GetWrappedNativeFromHolder(holder); + nsCOMPtr native = do_QueryWrappedNative(wn); + return !!native; +} + +static JSBool +WrapURI(JSContext *cx, nsIURI *uri, jsval *vp) +{ + JSObject *scope = JS_GetGlobalForScopeChain(cx); + nsresult rv = + nsXPConnect::FastGetXPConnect()->WrapNativeToJSVal(cx, scope, uri, nsnull, + &NS_GET_IID(nsIURI), PR_TRUE, + vp, nsnull); + if (NS_FAILED(rv)) { + XPCThrower::Throw(rv, cx); + return false; + } + return true; +} + +static JSBool +documentURIObject_getter(JSContext *cx, JSObject *wrapper, jsid id, jsval *vp) +{ + if (!wrapper->isWrapper() || !WrapperFactory::IsXrayWrapper(wrapper)) { + JS_ReportError(cx, "Unexpected object"); + return false; + } + + JSObject *holder = GetHolder(wrapper); + XPCWrappedNative *wn = GetWrappedNativeFromHolder(holder); + nsCOMPtr native = do_QueryWrappedNative(wn); + if (!native) { + JS_ReportError(cx, "Unexpected object"); + return false; + } + + nsCOMPtr uri = native->GetDocumentURI(); + if (!uri) { + JS_ReportOutOfMemory(cx); + return false; + } + + return WrapURI(cx, uri, vp); +} + +static JSBool +baseURIObject_getter(JSContext *cx, JSObject *wrapper, jsid id, jsval *vp) +{ + if (!wrapper->isWrapper() || !WrapperFactory::IsXrayWrapper(wrapper)) { + JS_ReportError(cx, "Unexpected object"); + return false; + } + + JSObject *holder = GetHolder(wrapper); + XPCWrappedNative *wn = GetWrappedNativeFromHolder(holder); + nsCOMPtr native = do_QueryWrappedNative(wn); + if (!native) { + JS_ReportError(cx, "Unexpected object"); + return false; + } + nsCOMPtr uri = native->GetBaseURI(); + if (!uri) { + JS_ReportOutOfMemory(cx); + return false; + } + + return WrapURI(cx, uri, vp); +} + +static JSBool +nodePrincipal_getter(JSContext *cx, JSObject *wrapper, jsid id, jsval *vp) +{ + if (!wrapper->isWrapper() || !WrapperFactory::IsXrayWrapper(wrapper)) { + JS_ReportError(cx, "Unexpected object"); + return false; + } + + JSObject *holder = GetHolder(wrapper); + XPCWrappedNative *wn = GetWrappedNativeFromHolder(holder); + nsCOMPtr node = do_QueryWrappedNative(wn); + if (!node) { + JS_ReportError(cx, "Unexpected object"); + return false; + } + + JSObject *scope = JS_GetGlobalForScopeChain(cx); + nsresult rv = + nsXPConnect::FastGetXPConnect()->WrapNativeToJSVal(cx, scope, node->NodePrincipal(), nsnull, + &NS_GET_IID(nsIPrincipal), PR_TRUE, + vp, nsnull); + if (NS_FAILED(rv)) { + XPCThrower::Throw(rv, cx); + return false; + } + return true; +} + static JSBool XrayToString(JSContext *cx, uintN argc, jsval *vp) { @@ -401,7 +511,22 @@ class AutoLeaveHelper }; static bool -Transparent(JSContext *cx, JSObject *wrapper) +IsPrivilegedScript() +{ + // Redirect access straight to the wrapper if UniversalXPConnect is enabled. + nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); + if (ssm) { + PRBool privileged; + if (NS_SUCCEEDED(ssm->IsCapabilityEnabled("UniversalXPConnect", &privileged)) && privileged) + return true; + } + return false; +} + +namespace XrayUtils { + +bool +IsTransparent(JSContext *cx, JSObject *wrapper) { if (WrapperFactory::HasWaiveXrayFlag(wrapper)) return true; @@ -410,24 +535,12 @@ Transparent(JSContext *cx, JSObject *wrapper) return false; // Redirect access straight to the wrapper if UniversalXPConnect is enabled. - nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); - if (ssm) { - PRBool privileged; - if (NS_SUCCEEDED(ssm->IsCapabilityEnabled("UniversalXPConnect", &privileged)) && privileged) - return true; - } + if (IsPrivilegedScript()) + return true; return AccessCheck::documentDomainMakesSameOrigin(cx, wrapper->unwrap()); } -namespace XrayUtils { - -bool -IsTransparent(JSContext *cx, JSObject *wrapper) -{ - return Transparent(cx, wrapper); -} - } template @@ -437,8 +550,20 @@ XrayWrapper::resolveOwnProperty(JSContext *cx, JSObject *wrapper, jsid id, { // Partially transparent wrappers (which used to be known as XOWs) don't // have a .wrappedJSObject property. + XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance(); if (!WrapperFactory::IsPartiallyTransparent(wrapper) && - id == nsXPConnect::GetRuntimeInstance()->GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT)) { + (id == rt->GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT) || + // Check for baseURIObject and nodePrincipal no nodes and + // documentURIObject on documents, but only from privileged scripts. + // Do the id checks before the QIs and IsPrivilegedScript() checks, + // since they're cheaper and will tend to fail most of the time + // anyway. + (((id == rt->GetStringID(XPCJSRuntime::IDX_BASEURIOBJECT) || + id == rt->GetStringID(XPCJSRuntime::IDX_NODEPRINCIPAL)) && + Is(wrapper)) || + (id == rt->GetStringID(XPCJSRuntime::IDX_DOCUMENTURIOBJECT) && + Is(wrapper))) && + IsPrivilegedScript())) { bool status; JSWrapper::Action action = set ? JSWrapper::SET : JSWrapper::GET; desc->obj = NULL; // default value @@ -449,7 +574,14 @@ XrayWrapper::resolveOwnProperty(JSContext *cx, JSObject *wrapper, jsid id, desc->obj = wrapper; desc->attrs = JSPROP_ENUMERATE|JSPROP_SHARED; - desc->getter = wrappedJSObject_getter; + if (id == rt->GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT)) + desc->getter = wrappedJSObject_getter; + else if (id == rt->GetStringID(XPCJSRuntime::IDX_BASEURIOBJECT)) + desc->getter = baseURIObject_getter; + else if (id == rt->GetStringID(XPCJSRuntime::IDX_DOCUMENTURIOBJECT)) + desc->getter = documentURIObject_getter; + else + desc->getter = nodePrincipal_getter; desc->setter = NULL; desc->shortid = 0; desc->value = JSVAL_VOID; @@ -537,7 +669,7 @@ XrayWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid ResolvingId resolving(holder, id); // Redirect access straight to the wrapper if we should be transparent. - if (Transparent(cx, wrapper)) { + if (XrayUtils::IsTransparent(cx, wrapper)) { JSObject *wnObject = GetWrappedNativeObjectFromHolder(holder); { @@ -607,7 +739,7 @@ XrayWrapper::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, js // NB: Nothing we do here acts on the wrapped native itself, so we don't // enter our policy. // Redirect access straight to the wrapper if we should be transparent. - if (Transparent(cx, wrapper)) { + if (XrayUtils::IsTransparent(cx, wrapper)) { JSObject *wnObject = GetWrappedNativeObjectFromHolder(holder); { @@ -638,7 +770,7 @@ XrayWrapper::defineProperty(JSContext *cx, JSObject *wrapper, jsid id, JSPropertyDescriptor *jsdesc = desc; // Redirect access straight to the wrapper if we should be transparent. - if (Transparent(cx, wrapper)) { + if (XrayUtils::IsTransparent(cx, wrapper)) { JSObject *wnObject = GetWrappedNativeObjectFromHolder(holder); JSAutoEnterCompartment ac; @@ -687,7 +819,7 @@ EnumerateNames(JSContext *cx, JSObject *wrapper, uintN flags, js::AutoIdVector & JSObject *wnObject = GetWrappedNativeObjectFromHolder(holder); // Redirect access straight to the wrapper if we should be transparent. - if (Transparent(cx, wrapper)) { + if (XrayUtils::IsTransparent(cx, wrapper)) { JSAutoEnterCompartment ac; if (!ac.enter(cx, wnObject)) return false; @@ -744,7 +876,7 @@ XrayWrapper::delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp) JSBool b; // Redirect access straight to the wrapper if we should be transparent. - if (Transparent(cx, wrapper)) { + if (XrayUtils::IsTransparent(cx, wrapper)) { JSObject *wnObject = GetWrappedNativeObjectFromHolder(holder); JSAutoEnterCompartment ac;