RemoteOuterWindowProxy.cpp (6346B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "AccessCheck.h" 8 #include "js/Proxy.h" 9 #include "mozilla/Maybe.h" 10 #include "mozilla/dom/BrowsingContext.h" 11 #include "mozilla/dom/ProxyHandlerUtils.h" 12 #include "mozilla/dom/RemoteObjectProxy.h" 13 #include "mozilla/dom/WindowBinding.h" 14 #include "mozilla/dom/WindowProxyHolder.h" 15 #include "xpcprivate.h" 16 17 namespace mozilla::dom { 18 19 /** 20 * RemoteOuterWindowProxy is the proxy handler for the WindowProxy objects for 21 * Window objects that live in a different process. 22 * 23 * RemoteOuterWindowProxy holds a BrowsingContext, which is cycle collected. 24 * This reference is declared to the cycle collector via NoteChildren(). 25 */ 26 27 class RemoteOuterWindowProxy 28 : public RemoteObjectProxy<BrowsingContext, 29 Window_Binding::sCrossOriginProperties> { 30 public: 31 using Base = RemoteObjectProxy; 32 33 constexpr RemoteOuterWindowProxy() 34 : RemoteObjectProxy(prototypes::id::Window) {} 35 36 // Standard internal methods 37 bool getOwnPropertyDescriptor( 38 JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId, 39 JS::MutableHandle<Maybe<JS::PropertyDescriptor>> aDesc) const final; 40 bool ownPropertyKeys(JSContext* aCx, JS::Handle<JSObject*> aProxy, 41 JS::MutableHandleVector<jsid> aProps) const final; 42 43 // SpiderMonkey extensions 44 bool getOwnEnumerablePropertyKeys( 45 JSContext* cx, JS::Handle<JSObject*> proxy, 46 JS::MutableHandleVector<jsid> props) const final; 47 48 void NoteChildren(JSObject* aProxy, 49 nsCycleCollectionTraversalCallback& aCb) const override { 50 CycleCollectionNoteChild(aCb, 51 static_cast<BrowsingContext*>(GetNative(aProxy)), 52 "JS::GetPrivate(obj)"); 53 } 54 }; 55 56 static const RemoteOuterWindowProxy sSingleton; 57 58 // Give RemoteOuterWindowProxy 2 reserved slots, like the other wrappers, 59 // so JSObject::swap can swap it with CrossCompartmentWrappers without requiring 60 // malloc. 61 template <> 62 const JSClass RemoteOuterWindowProxy::Base::sClass = 63 PROXY_CLASS_DEF("Proxy", JSCLASS_HAS_RESERVED_SLOTS(2)); 64 65 bool GetRemoteOuterWindowProxy(JSContext* aCx, BrowsingContext* aContext, 66 JS::Handle<JSObject*> aTransplantTo, 67 JS::MutableHandle<JSObject*> aRetVal) { 68 MOZ_ASSERT(!aContext->GetDocShell(), 69 "Why are we creating a RemoteOuterWindowProxy?"); 70 71 sSingleton.GetProxyObject(aCx, aContext, aTransplantTo, aRetVal); 72 return !!aRetVal; 73 } 74 75 BrowsingContext* GetBrowsingContext(JSObject* aProxy) { 76 MOZ_ASSERT(IsRemoteObjectProxy(aProxy, prototypes::id::Window)); 77 return static_cast<BrowsingContext*>( 78 RemoteObjectProxyBase::GetNative(aProxy)); 79 } 80 81 static bool WrapResult(JSContext* aCx, JS::Handle<JSObject*> aProxy, 82 BrowsingContext* aResult, JS::PropertyAttributes attrs, 83 JS::MutableHandle<Maybe<JS::PropertyDescriptor>> aDesc) { 84 JS::Rooted<JS::Value> v(aCx); 85 if (!ToJSValue(aCx, WindowProxyHolder(aResult), &v)) { 86 return false; 87 } 88 89 aDesc.set(Some(JS::PropertyDescriptor::Data(v, attrs))); 90 return true; 91 } 92 93 bool RemoteOuterWindowProxy::getOwnPropertyDescriptor( 94 JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId, 95 JS::MutableHandle<Maybe<JS::PropertyDescriptor>> aDesc) const { 96 BrowsingContext* bc = GetBrowsingContext(aProxy); 97 uint32_t index = GetArrayIndexFromId(aId); 98 if (IsArrayIndex(index)) { 99 Span<RefPtr<BrowsingContext>> children = bc->Children(); 100 if (index < children.Length()) { 101 return WrapResult(aCx, aProxy, children[index], 102 {JS::PropertyAttribute::Configurable, 103 JS::PropertyAttribute::Enumerable}, 104 aDesc); 105 } 106 return ReportCrossOriginDenial(aCx, aId, "access"_ns); 107 } 108 109 bool ok = CrossOriginGetOwnPropertyHelper(aCx, aProxy, aId, aDesc); 110 if (!ok || aDesc.isSome()) { 111 return ok; 112 } 113 114 // We don't need the "print" hack that nsOuterWindowProxy has, because pdf 115 // documents are placed in a process based on their principal before the PDF 116 // viewer changes principals around, so are always same-process with things 117 // that are same-origin with their original principal and won't reach this 118 // code in the cases when "print" should be accessible. 119 120 if (aId.isString()) { 121 nsAutoJSString str; 122 if (!str.init(aCx, aId.toString())) { 123 return false; 124 } 125 126 for (BrowsingContext* child : bc->Children()) { 127 if (child->NameEquals(str)) { 128 return WrapResult(aCx, aProxy, child, 129 {JS::PropertyAttribute::Configurable}, aDesc); 130 } 131 } 132 } 133 134 return CrossOriginPropertyFallback(aCx, aProxy, aId, aDesc); 135 } 136 137 bool AppendIndexedPropertyNames(JSContext* aCx, BrowsingContext* aContext, 138 JS::MutableHandleVector<jsid> aIndexedProps) { 139 int32_t length = aContext->Children().Length(); 140 if (!aIndexedProps.reserve(aIndexedProps.length() + length)) { 141 return false; 142 } 143 144 for (int32_t i = 0; i < length; ++i) { 145 aIndexedProps.infallibleAppend(JS::PropertyKey::Int(i)); 146 } 147 return true; 148 } 149 150 bool RemoteOuterWindowProxy::ownPropertyKeys( 151 JSContext* aCx, JS::Handle<JSObject*> aProxy, 152 JS::MutableHandleVector<jsid> aProps) const { 153 BrowsingContext* bc = GetBrowsingContext(aProxy); 154 155 // https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-ownpropertykeys:crossoriginownpropertykeys-(-o-) 156 // step 3 to 5 157 if (!AppendIndexedPropertyNames(aCx, bc, aProps)) { 158 return false; 159 } 160 161 // https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-ownpropertykeys:crossoriginownpropertykeys-(-o-) 162 // step 7 163 return RemoteObjectProxy::ownPropertyKeys(aCx, aProxy, aProps); 164 } 165 166 bool RemoteOuterWindowProxy::getOwnEnumerablePropertyKeys( 167 JSContext* aCx, JS::Handle<JSObject*> aProxy, 168 JS::MutableHandleVector<jsid> aProps) const { 169 return AppendIndexedPropertyNames(aCx, GetBrowsingContext(aProxy), aProps); 170 } 171 172 } // namespace mozilla::dom