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/. */
7 #include "AccessCheck.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"
17 namespace mozilla::dom
{
20 * RemoteOuterWindowProxy is the proxy handler for the WindowProxy objects for
21 * Window objects that live in a different process.
23 * RemoteOuterWindowProxy holds a BrowsingContext, which is cycle collected.
24 * This reference is declared to the cycle collector via NoteChildren().
27 class RemoteOuterWindowProxy
28 : public RemoteObjectProxy
<BrowsingContext
,
29 Window_Binding::sCrossOriginProperties
> {
31 using Base
= RemoteObjectProxy
;
33 constexpr RemoteOuterWindowProxy()
34 : RemoteObjectProxy(prototypes::id::Window
) {}
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
;
43 // SpiderMonkey extensions
44 bool getOwnEnumerablePropertyKeys(
45 JSContext
* cx
, JS::Handle
<JSObject
*> proxy
,
46 JS::MutableHandleVector
<jsid
> props
) const final
;
48 void NoteChildren(JSObject
* aProxy
,
49 nsCycleCollectionTraversalCallback
& aCb
) const override
{
50 CycleCollectionNoteChild(aCb
,
51 static_cast<BrowsingContext
*>(GetNative(aProxy
)),
52 "JS::GetPrivate(obj)");
56 static const RemoteOuterWindowProxy sSingleton
;
58 // Give RemoteOuterWindowProxy 2 reserved slots, like the other wrappers,
59 // so JSObject::swap can swap it with CrossCompartmentWrappers without requiring
62 const JSClass
RemoteOuterWindowProxy::Base::sClass
=
63 PROXY_CLASS_DEF("Proxy", JSCLASS_HAS_RESERVED_SLOTS(2));
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?");
71 sSingleton
.GetProxyObject(aCx
, aContext
, aTransplantTo
, aRetVal
);
75 BrowsingContext
* GetBrowsingContext(JSObject
* aProxy
) {
76 MOZ_ASSERT(IsRemoteObjectProxy(aProxy
, prototypes::id::Window
));
77 return static_cast<BrowsingContext
*>(
78 RemoteObjectProxyBase::GetNative(aProxy
));
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
)) {
89 aDesc
.set(Some(JS::PropertyDescriptor::Data(v
, attrs
)));
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
},
106 return ReportCrossOriginDenial(aCx
, aId
, "access"_ns
);
109 bool ok
= CrossOriginGetOwnPropertyHelper(aCx
, aProxy
, aId
, aDesc
);
110 if (!ok
|| aDesc
.isSome()) {
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.
120 if (aId
.isString()) {
122 if (!str
.init(aCx
, aId
.toString())) {
126 for (BrowsingContext
* child
: bc
->Children()) {
127 if (child
->NameEquals(str
)) {
128 return WrapResult(aCx
, aProxy
, child
,
129 {JS::PropertyAttribute::Configurable
}, aDesc
);
134 return CrossOriginPropertyFallback(aCx
, aProxy
, aId
, aDesc
);
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
)) {
144 for (int32_t i
= 0; i
< length
; ++i
) {
145 aIndexedProps
.infallibleAppend(JS::PropertyKey::Int(i
));
150 bool RemoteOuterWindowProxy::ownPropertyKeys(
151 JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
,
152 JS::MutableHandleVector
<jsid
> aProps
) const {
153 BrowsingContext
* bc
= GetBrowsingContext(aProxy
);
155 // https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-ownpropertykeys:crossoriginownpropertykeys-(-o-)
157 if (!AppendIndexedPropertyNames(aCx
, bc
, aProps
)) {
161 // https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-ownpropertykeys:crossoriginownpropertykeys-(-o-)
163 return RemoteObjectProxy::ownPropertyKeys(aCx
, aProxy
, aProps
);
166 bool RemoteOuterWindowProxy::getOwnEnumerablePropertyKeys(
167 JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
,
168 JS::MutableHandleVector
<jsid
> aProps
) const {
169 return AppendIndexedPropertyNames(aCx
, GetBrowsingContext(aProxy
), aProps
);
172 } // namespace mozilla::dom