forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			187 lines
		
	
	
	
		
			7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			187 lines
		
	
	
	
		
			7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #include "RemoteObjectProxy.h"
 | |
| #include "AccessCheck.h"
 | |
| #include "jsfriendapi.h"
 | |
| #include "js/Object.h"  // JS::GetClass
 | |
| #include "xpcprivate.h"
 | |
| 
 | |
| namespace mozilla::dom {
 | |
| 
 | |
| bool RemoteObjectProxyBase::getOwnPropertyDescriptor(
 | |
|     JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
 | |
|     JS::MutableHandle<Maybe<JS::PropertyDescriptor>> aDesc) const {
 | |
|   bool ok = CrossOriginGetOwnPropertyHelper(aCx, aProxy, aId, aDesc);
 | |
|   if (!ok || aDesc.isSome()) {
 | |
|     return ok;
 | |
|   }
 | |
| 
 | |
|   return CrossOriginPropertyFallback(aCx, aProxy, aId, aDesc);
 | |
| }
 | |
| 
 | |
| bool RemoteObjectProxyBase::defineProperty(
 | |
|     JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
 | |
|     JS::Handle<JS::PropertyDescriptor> aDesc,
 | |
|     JS::ObjectOpResult& aResult) const {
 | |
|   // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-defineownproperty
 | |
|   // step 3 and
 | |
|   // https://html.spec.whatwg.org/multipage/browsers.html#location-defineownproperty
 | |
|   // step 2
 | |
|   return ReportCrossOriginDenial(aCx, aId, "define"_ns);
 | |
| }
 | |
| 
 | |
| bool RemoteObjectProxyBase::ownPropertyKeys(
 | |
|     JSContext* aCx, JS::Handle<JSObject*> aProxy,
 | |
|     JS::MutableHandleVector<jsid> aProps) const {
 | |
|   // https://html.spec.whatwg.org/multipage/browsers.html#crossoriginownpropertykeys-(-o-)
 | |
|   // step 2 and
 | |
|   // https://html.spec.whatwg.org/multipage/browsers.html#crossoriginproperties-(-o-)
 | |
|   JS::Rooted<JSObject*> holder(aCx);
 | |
|   if (!EnsureHolder(aCx, aProxy, &holder) ||
 | |
|       !js::GetPropertyKeys(aCx, holder,
 | |
|                            JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS,
 | |
|                            aProps)) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   // https://html.spec.whatwg.org/multipage/browsers.html#crossoriginownpropertykeys-(-o-)
 | |
|   // step 3 and 4
 | |
|   return xpc::AppendCrossOriginWhitelistedPropNames(aCx, aProps);
 | |
| }
 | |
| 
 | |
| bool RemoteObjectProxyBase::delete_(JSContext* aCx,
 | |
|                                     JS::Handle<JSObject*> aProxy,
 | |
|                                     JS::Handle<jsid> aId,
 | |
|                                     JS::ObjectOpResult& aResult) const {
 | |
|   // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-delete
 | |
|   // step 3 and
 | |
|   // https://html.spec.whatwg.org/multipage/browsers.html#location-delete step 2
 | |
|   return ReportCrossOriginDenial(aCx, aId, "delete"_ns);
 | |
| }
 | |
| 
 | |
| bool RemoteObjectProxyBase::getPrototypeIfOrdinary(
 | |
|     JSContext* aCx, JS::Handle<JSObject*> aProxy, bool* aIsOrdinary,
 | |
|     JS::MutableHandle<JSObject*> aProtop) const {
 | |
|   // WindowProxy's and Location's [[GetPrototypeOf]] traps aren't the ordinary
 | |
|   // definition:
 | |
|   //
 | |
|   //   https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-getprototypeof
 | |
|   //   https://html.spec.whatwg.org/multipage/browsers.html#location-getprototypeof
 | |
|   //
 | |
|   // We nonetheless can implement it with a static [[Prototype]], because the
 | |
|   // [[GetPrototypeOf]] trap should always return null.
 | |
|   *aIsOrdinary = true;
 | |
|   aProtop.set(nullptr);
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool RemoteObjectProxyBase::preventExtensions(
 | |
|     JSContext* aCx, JS::Handle<JSObject*> aProxy,
 | |
|     JS::ObjectOpResult& aResult) const {
 | |
|   // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-preventextensions
 | |
|   // and
 | |
|   // https://html.spec.whatwg.org/multipage/browsers.html#location-preventextensions
 | |
|   return aResult.failCantPreventExtensions();
 | |
| }
 | |
| 
 | |
| bool RemoteObjectProxyBase::isExtensible(JSContext* aCx,
 | |
|                                          JS::Handle<JSObject*> aProxy,
 | |
|                                          bool* aExtensible) const {
 | |
|   // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-isextensible
 | |
|   // and
 | |
|   // https://html.spec.whatwg.org/multipage/browsers.html#location-isextensible
 | |
|   *aExtensible = true;
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool RemoteObjectProxyBase::get(JSContext* aCx, JS::Handle<JSObject*> aProxy,
 | |
|                                 JS::Handle<JS::Value> aReceiver,
 | |
|                                 JS::Handle<jsid> aId,
 | |
|                                 JS::MutableHandle<JS::Value> aVp) const {
 | |
|   return CrossOriginGet(aCx, aProxy, aReceiver, aId, aVp);
 | |
| }
 | |
| 
 | |
| bool RemoteObjectProxyBase::set(JSContext* aCx, JS::Handle<JSObject*> aProxy,
 | |
|                                 JS::Handle<jsid> aId,
 | |
|                                 JS::Handle<JS::Value> aValue,
 | |
|                                 JS::Handle<JS::Value> aReceiver,
 | |
|                                 JS::ObjectOpResult& aResult) const {
 | |
|   return CrossOriginSet(aCx, aProxy, aId, aValue, aReceiver, aResult);
 | |
| }
 | |
| 
 | |
| bool RemoteObjectProxyBase::getOwnEnumerablePropertyKeys(
 | |
|     JSContext* aCx, JS::Handle<JSObject*> aProxy,
 | |
|     JS::MutableHandleVector<jsid> aProps) const {
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| const char* RemoteObjectProxyBase::className(
 | |
|     JSContext* aCx, JS::Handle<JSObject*> aProxy) const {
 | |
|   MOZ_ASSERT(js::IsProxy(aProxy));
 | |
| 
 | |
|   return "Object";
 | |
| }
 | |
| 
 | |
| void RemoteObjectProxyBase::GetOrCreateProxyObject(
 | |
|     JSContext* aCx, void* aNative, const JSClass* aClasp,
 | |
|     JS::Handle<JSObject*> aTransplantTo, JS::MutableHandle<JSObject*> aProxy,
 | |
|     bool& aNewObjectCreated) const {
 | |
|   xpc::CompartmentPrivate* priv =
 | |
|       xpc::CompartmentPrivate::Get(JS::CurrentGlobalOrNull(aCx));
 | |
|   xpc::CompartmentPrivate::RemoteProxyMap& map = priv->GetRemoteProxyMap();
 | |
|   if (auto result = map.lookup(aNative)) {
 | |
|     MOZ_RELEASE_ASSERT(!aTransplantTo,
 | |
|                        "GOCPO failed by finding an existing value");
 | |
| 
 | |
|     aProxy.set(result->value());
 | |
| 
 | |
|     // During a transplant, we put an object that is temporarily not a
 | |
|     // proxy object into the map. Make sure that we don't return one of
 | |
|     // these objects in the middle of a transplant.
 | |
|     MOZ_RELEASE_ASSERT(JS::GetClass(aProxy) == aClasp);
 | |
| 
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   js::ProxyOptions options;
 | |
|   options.setClass(aClasp);
 | |
|   JS::Rooted<JS::Value> native(aCx, JS::PrivateValue(aNative));
 | |
|   JS::Rooted<JSObject*> obj(
 | |
|       aCx, js::NewProxyObject(aCx, this, native, nullptr, options));
 | |
|   if (!obj) {
 | |
|     MOZ_RELEASE_ASSERT(!aTransplantTo, "GOCPO failed at NewProxyObject");
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   bool success;
 | |
|   if (!JS_SetImmutablePrototype(aCx, obj, &success)) {
 | |
|     MOZ_RELEASE_ASSERT(!aTransplantTo,
 | |
|                        "GOCPO failed at JS_SetImmutablePrototype");
 | |
|     return;
 | |
|   }
 | |
|   MOZ_ASSERT(success);
 | |
| 
 | |
|   aNewObjectCreated = true;
 | |
| 
 | |
|   // If we're transplanting onto an object, we want to make sure that it does
 | |
|   // not have the same class as aClasp to ensure that the release assert earlier
 | |
|   // in this function will actually fire if we try to return a proxy object in
 | |
|   // the middle of a transplant.
 | |
|   MOZ_RELEASE_ASSERT(!aTransplantTo || (JS::GetClass(aTransplantTo) != aClasp),
 | |
|                      "GOCPO failed by not changing the class");
 | |
| 
 | |
|   if (!map.put(aNative, aTransplantTo ? aTransplantTo : obj)) {
 | |
|     MOZ_RELEASE_ASSERT(!aTransplantTo, "GOCPO failed at map.put");
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   aProxy.set(obj);
 | |
| }
 | |
| 
 | |
| const char RemoteObjectProxyBase::sCrossOriginProxyFamily = 0;
 | |
| 
 | |
| }  // namespace mozilla::dom
 | 
