diff options
Diffstat (limited to 'dom/base/RemoteOuterWindowProxy.cpp')
-rw-r--r-- | dom/base/RemoteOuterWindowProxy.cpp | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/dom/base/RemoteOuterWindowProxy.cpp b/dom/base/RemoteOuterWindowProxy.cpp new file mode 100644 index 0000000000..c0d7f81d1e --- /dev/null +++ b/dom/base/RemoteOuterWindowProxy.cpp @@ -0,0 +1,166 @@ +/* -*- 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 "AccessCheck.h" +#include "js/Proxy.h" +#include "mozilla/dom/BrowsingContext.h" +#include "mozilla/dom/RemoteObjectProxy.h" +#include "mozilla/dom/WindowBinding.h" +#include "xpcprivate.h" + +namespace mozilla::dom { + +/** + * RemoteOuterWindowProxy is the proxy handler for the WindowProxy objects for + * Window objects that live in a different process. + * + * RemoteOuterWindowProxy holds a BrowsingContext, which is cycle collected. + * This reference is declared to the cycle collector via NoteChildren(). + */ + +class RemoteOuterWindowProxy + : public RemoteObjectProxy<BrowsingContext, + Window_Binding::sCrossOriginProperties> { + public: + typedef RemoteObjectProxy Base; + + constexpr RemoteOuterWindowProxy() + : RemoteObjectProxy(prototypes::id::Window) {} + + // Standard internal methods + bool getOwnPropertyDescriptor( + JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId, + JS::MutableHandle<JS::PropertyDescriptor> aDesc) const final; + bool ownPropertyKeys(JSContext* aCx, JS::Handle<JSObject*> aProxy, + JS::MutableHandleVector<jsid> aProps) const final; + + // SpiderMonkey extensions + bool getOwnEnumerablePropertyKeys( + JSContext* cx, JS::Handle<JSObject*> proxy, + JS::MutableHandleVector<jsid> props) const final; + + void NoteChildren(JSObject* aProxy, + nsCycleCollectionTraversalCallback& aCb) const override { + CycleCollectionNoteChild(aCb, + static_cast<BrowsingContext*>(GetNative(aProxy)), + "JS::GetPrivate(obj)"); + } +}; + +static const RemoteOuterWindowProxy sSingleton; + +// Give RemoteOuterWindowProxy 2 reserved slots, like the other wrappers, +// so JSObject::swap can swap it with CrossCompartmentWrappers without requiring +// malloc. +template <> +const JSClass RemoteOuterWindowProxy::Base::sClass = + PROXY_CLASS_DEF("Proxy", JSCLASS_HAS_RESERVED_SLOTS(2)); + +bool GetRemoteOuterWindowProxy(JSContext* aCx, BrowsingContext* aContext, + JS::Handle<JSObject*> aTransplantTo, + JS::MutableHandle<JSObject*> aRetVal) { + MOZ_ASSERT(!aContext->GetDocShell(), + "Why are we creating a RemoteOuterWindowProxy?"); + + sSingleton.GetProxyObject(aCx, aContext, aTransplantTo, aRetVal); + return !!aRetVal; +} + +BrowsingContext* GetBrowsingContext(JSObject* aProxy) { + MOZ_ASSERT(IsRemoteObjectProxy(aProxy, prototypes::id::Window)); + return static_cast<BrowsingContext*>( + RemoteObjectProxyBase::GetNative(aProxy)); +} + +bool WrapResult(JSContext* aCx, JS::Handle<JSObject*> aProxy, + BrowsingContext* aResult, unsigned attrs, + JS::MutableHandle<JS::PropertyDescriptor> aDesc) { + JS::Rooted<JS::Value> v(aCx); + if (!ToJSValue(aCx, WindowProxyHolder(aResult), &v)) { + return false; + } + aDesc.setDataDescriptor(v, attrs); + aDesc.object().set(aProxy); + return true; +} + +bool RemoteOuterWindowProxy::getOwnPropertyDescriptor( + JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId, + JS::MutableHandle<JS::PropertyDescriptor> aDesc) const { + BrowsingContext* bc = GetBrowsingContext(aProxy); + uint32_t index = GetArrayIndexFromId(aId); + if (IsArrayIndex(index)) { + Span<RefPtr<BrowsingContext>> children = bc->Children(); + if (index < children.Length()) { + return WrapResult(aCx, aProxy, children[index], + JSPROP_READONLY | JSPROP_ENUMERATE, aDesc); + } + return ReportCrossOriginDenial(aCx, aId, "access"_ns); + } + + bool ok = CrossOriginGetOwnPropertyHelper(aCx, aProxy, aId, aDesc); + if (!ok || aDesc.object()) { + return ok; + } + + // We don't need the "print" hack that nsOuterWindowProxy has, because pdf + // documents are placed in a process based on their principal before the PDF + // viewer changes principals around, so are always same-process with things + // that are same-origin with their original principal and won't reach this + // code in the cases when "print" should be accessible. + + if (JSID_IS_STRING(aId)) { + nsAutoJSString str; + if (!str.init(aCx, JSID_TO_STRING(aId))) { + return false; + } + + for (BrowsingContext* child : bc->Children()) { + if (child->NameEquals(str)) { + return WrapResult(aCx, aProxy, child, JSPROP_READONLY, aDesc); + } + } + } + + return CrossOriginPropertyFallback(aCx, aProxy, aId, aDesc); +} + +bool AppendIndexedPropertyNames(JSContext* aCx, BrowsingContext* aContext, + JS::MutableHandleVector<jsid> aIndexedProps) { + int32_t length = aContext->Children().Length(); + if (!aIndexedProps.reserve(aIndexedProps.length() + length)) { + return false; + } + + for (int32_t i = 0; i < length; ++i) { + aIndexedProps.infallibleAppend(INT_TO_JSID(i)); + } + return true; +} + +bool RemoteOuterWindowProxy::ownPropertyKeys( + JSContext* aCx, JS::Handle<JSObject*> aProxy, + JS::MutableHandleVector<jsid> aProps) const { + BrowsingContext* bc = GetBrowsingContext(aProxy); + + // https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-ownpropertykeys:crossoriginownpropertykeys-(-o-) + // step 3 to 5 + if (!AppendIndexedPropertyNames(aCx, bc, aProps)) { + return false; + } + + // https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-ownpropertykeys:crossoriginownpropertykeys-(-o-) + // step 7 + return RemoteObjectProxy::ownPropertyKeys(aCx, aProxy, aProps); +} + +bool RemoteOuterWindowProxy::getOwnEnumerablePropertyKeys( + JSContext* aCx, JS::Handle<JSObject*> aProxy, + JS::MutableHandleVector<jsid> aProps) const { + return AppendIndexedPropertyNames(aCx, GetBrowsingContext(aProxy), aProps); +} + +} // namespace mozilla::dom |