Bug 1353867 - Add cross-process proxies for WindowProxy. r=bzbarsky

Differential Revision: https://phabricator.services.mozilla.com/D12656

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Peter Van der Beken 2019-01-02 13:29:18 +00:00
parent 43adb531b7
commit 066d891adb
38 changed files with 1513 additions and 189 deletions

View File

@ -10,6 +10,9 @@
#include "mozilla/dom/BrowsingContextBinding.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/Location.h"
#include "mozilla/dom/LocationBinding.h"
#include "mozilla/dom/WindowBinding.h"
#include "mozilla/Assertions.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/HashTable.h"
@ -17,7 +20,9 @@
#include "mozilla/StaticPtr.h"
#include "nsDocShell.h"
#include "nsGlobalWindowOuter.h"
#include "nsContentUtils.h"
#include "nsScriptError.h"
#include "nsThreadUtils.h"
namespace mozilla {
@ -50,14 +55,12 @@ static void Sync(BrowsingContext* aBrowsingContext) {
auto cc = ContentChild::GetSingleton();
MOZ_DIAGNOSTIC_ASSERT(cc);
nsAutoString name;
aBrowsingContext->GetName(name);
RefPtr<BrowsingContext> parent = aBrowsingContext->GetParent();
BrowsingContext* opener = aBrowsingContext->GetOpener();
cc->SendAttachBrowsingContext(BrowsingContextId(parent ? parent->Id() : 0),
BrowsingContextId(opener ? opener->Id() : 0),
BrowsingContextId(aBrowsingContext->Id()),
name);
aBrowsingContext->Name());
}
/* static */ void BrowsingContext::Init() {
@ -151,7 +154,8 @@ BrowsingContext::BrowsingContext(BrowsingContext* aParent,
mBrowsingContextId(aBrowsingContextId),
mParent(aParent),
mOpener(aOpener),
mName(aName) {
mName(aName),
mClosed(false) {
if (mParent) {
mBrowsingContextGroup = mParent->mBrowsingContextGroup;
} else if (mOpener) {
@ -325,5 +329,137 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(BrowsingContext)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(BrowsingContext, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(BrowsingContext, Release)
void BrowsingContext::Location(JSContext* aCx,
JS::MutableHandle<JSObject*> aLocation,
OOMReporter& aError) {}
void BrowsingContext::Close(CallerType aCallerType, ErrorResult& aError) {
// FIXME We need to set mClosed, but only once we're sending the
// DOMWindowClose event (which happens in the process where the
// document for this browsing context is loaded).
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1516343.
ContentChild* cc = ContentChild::GetSingleton();
cc->SendWindowClose(BrowsingContextId(mBrowsingContextId),
aCallerType == CallerType::System);
}
void BrowsingContext::Focus(ErrorResult& aError) {
ContentChild* cc = ContentChild::GetSingleton();
cc->SendWindowFocus(BrowsingContextId(mBrowsingContextId));
}
void BrowsingContext::Blur(ErrorResult& aError) {
ContentChild* cc = ContentChild::GetSingleton();
cc->SendWindowBlur(BrowsingContextId(mBrowsingContextId));
}
Nullable<WindowProxyHolder> BrowsingContext::GetTop(ErrorResult& aError) {
// We never return null or throw an error, but the implementation in
// nsGlobalWindow does and we need to use the same signature.
BrowsingContext* bc = this;
BrowsingContext* parent;
while ((parent = bc->mParent)) {
bc = parent;
}
return WindowProxyHolder(bc);
}
void BrowsingContext::GetOpener(JSContext* aCx,
JS::MutableHandle<JS::Value> aOpener,
ErrorResult& aError) const {
auto* opener = GetOpener();
if (!opener) {
aOpener.setNull();
return;
}
if (!ToJSValue(aCx, WindowProxyHolder(opener), aOpener)) {
aError.NoteJSContextException(aCx);
}
}
Nullable<WindowProxyHolder> BrowsingContext::GetParent(
ErrorResult& aError) const {
// We never throw an error, but the implementation in nsGlobalWindow does and
// we need to use the same signature.
if (!mParent) {
return nullptr;
}
return WindowProxyHolder(mParent.get());
}
void BrowsingContext::PostMessageMoz(JSContext* aCx,
JS::Handle<JS::Value> aMessage,
const nsAString& aTargetOrigin,
const Sequence<JSObject*>& aTransfer,
nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) {
RefPtr<BrowsingContext> sourceBc;
PostMessageData data;
data.targetOrigin() = aTargetOrigin;
data.subjectPrincipal() = &aSubjectPrincipal;
RefPtr<nsGlobalWindowInner> callerInnerWindow;
if (!nsGlobalWindowOuter::GatherPostMessageData(
aCx, aTargetOrigin, getter_AddRefs(sourceBc), data.origin(),
getter_AddRefs(data.targetOriginURI()),
getter_AddRefs(data.callerPrincipal()),
getter_AddRefs(callerInnerWindow),
getter_AddRefs(data.callerDocumentURI()), aError)) {
return;
}
data.source() = BrowsingContextId(sourceBc->Id());
data.isFromPrivateWindow() =
callerInnerWindow &&
nsScriptErrorBase::ComputeIsFromPrivateWindow(callerInnerWindow);
JS::Rooted<JS::Value> transferArray(aCx);
aError = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransfer,
&transferArray);
if (NS_WARN_IF(aError.Failed())) {
return;
}
ipc::StructuredCloneData message;
message.Write(aCx, aMessage, transferArray, aError);
if (NS_WARN_IF(aError.Failed())) {
return;
}
ContentChild* cc = ContentChild::GetSingleton();
ClonedMessageData messageData;
if (!message.BuildClonedMessageDataForChild(cc, messageData)) {
aError.Throw(NS_ERROR_FAILURE);
return;
}
cc->SendWindowPostMessage(BrowsingContextId(mBrowsingContextId), messageData,
data);
}
void BrowsingContext::PostMessageMoz(JSContext* aCx,
JS::Handle<JS::Value> aMessage,
const WindowPostMessageOptions& aOptions,
nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) {
PostMessageMoz(aCx, aMessage, aOptions.mTargetOrigin, aOptions.mTransfer,
aSubjectPrincipal, aError);
}
already_AddRefed<BrowsingContext> BrowsingContext::FindChildWithName(
const nsAString& aName) {
// FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=1515646 will reimplement
// this on top of the BC tree.
MOZ_ASSERT(mDocShell);
nsCOMPtr<nsIDocShellTreeItem> child;
mDocShell->FindChildWithName(aName, false, true, nullptr, nullptr,
getter_AddRefs(child));
nsCOMPtr<nsIDocShell> childDS = do_QueryInterface(child);
RefPtr<BrowsingContext> bc;
if (childDS) {
childDS->GetBrowsingContext(getter_AddRefs(bc));
}
return bc.forget();
}
} // namespace dom
} // namespace mozilla

View File

@ -10,6 +10,7 @@
#include "mozilla/LinkedList.h"
#include "mozilla/RefPtr.h"
#include "mozilla/WeakPtr.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIDocShell.h"
@ -22,12 +23,20 @@ class nsOuterWindowProxy;
namespace mozilla {
class ErrorResult;
class LogModule;
class OOMReporter;
namespace dom {
class BrowsingContext;
class ContentParent;
template <typename>
struct Nullable;
template <typename T>
class Sequence;
struct WindowPostMessageOptions;
class WindowProxyHolder;
// List of top-level or auxiliary BrowsingContexts
class BrowsingContextGroup : public nsTArray<WeakPtr<BrowsingContext>> {
@ -109,7 +118,7 @@ class BrowsingContext : public nsWrapperCache,
// TODO(farre): We should sync changes from SetName to the parent
// process. [Bug 1490303]
void SetName(const nsAString& aName) { mName = aName; }
void GetName(nsAString& aName) { aName = mName; }
const nsString& Name() const { return mName; }
bool NameEquals(const nsAString& aName) { return mName.Equals(aName); }
bool IsContent() const { return mType == Type::Content; }
@ -120,7 +129,7 @@ class BrowsingContext : public nsWrapperCache,
void GetChildren(nsTArray<RefPtr<BrowsingContext>>& aChildren);
BrowsingContext* GetOpener() { return mOpener; }
BrowsingContext* GetOpener() const { return mOpener; }
void SetOpener(BrowsingContext* aOpener);
@ -143,6 +152,34 @@ class BrowsingContext : public nsWrapperCache,
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(BrowsingContext)
using Children = nsTArray<RefPtr<BrowsingContext>>;
const Children& GetChildren() { return mChildren; }
// Window APIs that are cross-origin-accessible (from the HTML spec).
BrowsingContext* Window() { return Self(); }
BrowsingContext* Self() { return this; }
void Location(JSContext* aCx, JS::MutableHandle<JSObject*> aLocation,
OOMReporter& aError);
void Close(CallerType aCallerType, ErrorResult& aError);
bool GetClosed(ErrorResult&) { return mClosed; }
void Focus(ErrorResult& aError);
void Blur(ErrorResult& aError);
BrowsingContext* GetFrames(ErrorResult& aError) { return Self(); }
int32_t Length() const { return mChildren.Length(); }
Nullable<WindowProxyHolder> GetTop(ErrorResult& aError);
void GetOpener(JSContext* aCx, JS::MutableHandle<JS::Value> aOpener,
ErrorResult& aError) const;
Nullable<WindowProxyHolder> GetParent(ErrorResult& aError) const;
void PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const nsAString& aTargetOrigin,
const Sequence<JSObject*>& aTransfer,
nsIPrincipal& aSubjectPrincipal, ErrorResult& aError);
void PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const WindowPostMessageOptions& aOptions,
nsIPrincipal& aSubjectPrincipal, ErrorResult& aError);
already_AddRefed<BrowsingContext> FindChildWithName(const nsAString& aName);
JSObject* WrapObject(JSContext* aCx);
protected:
virtual ~BrowsingContext();
@ -184,8 +221,21 @@ class BrowsingContext : public nsWrapperCache,
// nsOuterWindowProxy handler, which will update the pointer from its
// objectMoved hook and clear it from its finalize hook.
JS::Heap<JSObject*> mWindowProxy;
bool mClosed;
};
/**
* Gets a WindowProxy object for a BrowsingContext that lives in a different
* process (creating the object if it doesn't already exist). The WindowProxy
* object will be in the compartment that aCx is currently in. This should only
* be called if aContext doesn't hold a docshell, otherwise the BrowsingContext
* lives in this process, and a same-process WindowProxy should be used (see
* nsGlobalWindowOuter). This should only be called by bindings code, ToJSValue
* is the right API to get a WindowProxy for a BrowsingContext.
*/
extern bool GetRemoteOuterWindowProxy(JSContext* aCx, BrowsingContext* aContext,
JS::MutableHandle<JSObject*> aRetVal);
} // namespace dom
} // namespace mozilla

View File

@ -34,6 +34,7 @@ class ChromeBrowsingContext final : public BrowsingContext {
bool IsOwnedByProcess(uint64_t aProcessId) const {
return mProcessId == aProcessId;
}
uint64_t OwnerProcessId() const { return mProcessId; }
void GetWindowGlobals(nsTArray<RefPtr<WindowGlobalParent>>& aWindows);

View File

@ -103,6 +103,7 @@ FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'/docshell/shistory',
'/dom/base',
'/dom/bindings',
'/layout/base',
'/layout/generic',
'/layout/style',

View File

@ -2309,7 +2309,7 @@ nsDocShell::NotifyScrollObservers() {
NS_IMETHODIMP
nsDocShell::GetName(nsAString& aName) {
mBrowsingContext->GetName(aName);
aName = mBrowsingContext->Name();
return NS_OK;
}

View File

@ -9,6 +9,7 @@
#include "js/TypeDecls.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/BrowsingContext.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIWeakReferenceUtils.h"
#include "nsPIDOMWindow.h"
@ -28,6 +29,8 @@ namespace dom {
class Location final : public nsISupports, public nsWrapperCache {
public:
typedef Location RemoteProxy;
Location(nsPIDOMWindowInner* aWindow, nsIDocShell* aDocShell);
NS_DECL_CYCLE_COLLECTING_ISUPPORTS

View File

@ -21,9 +21,11 @@
#include "nsContentUtils.h"
#include "nsDocShell.h"
#include "nsGlobalWindow.h"
#include "nsIConsoleService.h"
#include "nsIPresShell.h"
#include "nsIPrincipal.h"
#include "nsIScriptError.h"
#include "nsNetUtil.h"
#include "nsPresContext.h"
#include "nsQueryObject.h"
@ -34,18 +36,17 @@ PostMessageEvent::PostMessageEvent(BrowsingContext* aSource,
const nsAString& aCallerOrigin,
nsGlobalWindowOuter* aTargetWindow,
nsIPrincipal* aProvidedPrincipal,
uint64_t aCallerWindowID,
nsIURI* aCallerDocumentURI)
const Maybe<uint64_t>& aCallerWindowID,
nsIURI* aCallerDocumentURI,
bool aIsFromPrivateWindow)
: Runnable("dom::PostMessageEvent"),
mSource(aSource),
mCallerOrigin(aCallerOrigin),
mTargetWindow(aTargetWindow),
mProvidedPrincipal(aProvidedPrincipal),
mHolder(StructuredCloneHolder::CloningSupported,
StructuredCloneHolder::TransferringSupported,
JS::StructuredCloneScope::SameProcessSameThread),
mCallerWindowID(aCallerWindowID),
mCallerDocumentURI(aCallerDocumentURI) {}
mCallerDocumentURI(aCallerDocumentURI),
mIsFromPrivateWindow(aIsFromPrivateWindow) {}
PostMessageEvent::~PostMessageEvent() {}
@ -122,11 +123,31 @@ PostMessageEvent::Run() {
nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
"TargetPrincipalDoesNotMatch",
params, errorText);
nsContentUtils::ReportToConsoleByWindowID(
errorText, nsIScriptError::errorFlag,
NS_LITERAL_CSTRING("DOM Window"), mCallerWindowID, callerDocumentURI);
return NS_OK;
nsCOMPtr<nsIScriptError> errorObject =
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
if (mCallerWindowID.isSome()) {
rv = errorObject->InitWithSourceURI(
errorText, callerDocumentURI, EmptyString(), 0, 0,
nsIScriptError::errorFlag, "DOM Window", mCallerWindowID.value());
} else {
nsString uriSpec;
rv = NS_GetSanitizedURIStringFromURI(callerDocumentURI, uriSpec);
NS_ENSURE_SUCCESS(rv, rv);
rv = errorObject->Init(errorText, uriSpec, EmptyString(), 0, 0,
nsIScriptError::errorFlag, "DOM Window",
mIsFromPrivateWindow);
}
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIConsoleService> consoleService =
do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
return consoleService->LogMessage(errorObject);
}
}
@ -135,7 +156,16 @@ PostMessageEvent::Run() {
nsCOMPtr<mozilla::dom::EventTarget> eventTarget =
do_QueryObject(targetWindow);
mHolder.Read(targetWindow->AsInner(), cx, &messageData, rv);
StructuredCloneHolder* holder;
if (mHolder.constructed<StructuredCloneHolder>()) {
mHolder.ref<StructuredCloneHolder>().Read(targetWindow->AsInner(), cx,
&messageData, rv);
holder = &mHolder.ref<StructuredCloneHolder>();
} else {
MOZ_ASSERT(mHolder.constructed<ipc::StructuredCloneData>());
mHolder.ref<ipc::StructuredCloneData>().Read(cx, &messageData, rv);
holder = &mHolder.ref<ipc::StructuredCloneData>();
}
if (NS_WARN_IF(rv.Failed())) {
DispatchError(cx, targetWindow, eventTarget);
return NS_OK;
@ -150,7 +180,7 @@ PostMessageEvent::Run() {
}
Sequence<OwningNonNull<MessagePort>> ports;
if (!mHolder.TakeTransferredPortsAsSequence(ports)) {
if (!holder->TakeTransferredPortsAsSequence(ports)) {
DispatchError(cx, targetWindow, eventTarget);
return NS_OK;
}

View File

@ -8,8 +8,10 @@
#define mozilla_dom_PostMessageEvent_h
#include "mozilla/dom/Event.h"
#include "mozilla/dom/ipc/StructuredCloneData.h"
#include "mozilla/dom/StructuredCloneHolder.h"
#include "nsCOMPtr.h"
#include "mozilla/MaybeOneOf.h"
#include "mozilla/RefPtr.h"
#include "nsTArray.h"
#include "nsThreadUtils.h"
@ -32,17 +34,48 @@ class PostMessageEvent final : public Runnable {
public:
NS_DECL_NSIRUNNABLE
// aCallerWindowID should not be 0.
PostMessageEvent(BrowsingContext* aSource, const nsAString& aCallerOrigin,
nsGlobalWindowOuter* aTargetWindow,
nsIPrincipal* aProvidedPrincipal, uint64_t aCallerWindowID,
nsIURI* aCallerDocumentURI);
nsIURI* aCallerDocumentURI)
: PostMessageEvent(aSource, aCallerOrigin, aTargetWindow,
aProvidedPrincipal, Some(aCallerWindowID),
aCallerDocumentURI, false) {}
// To be used if there is no WindowID for the PostMessage caller's window (for
// example because it lives in a different process).
PostMessageEvent(BrowsingContext* aSource, const nsAString& aCallerOrigin,
nsGlobalWindowOuter* aTargetWindow,
nsIPrincipal* aProvidedPrincipal, nsIURI* aCallerDocumentURI,
bool aIsFromPrivateWindow)
: PostMessageEvent(aSource, aCallerOrigin, aTargetWindow,
aProvidedPrincipal, Nothing(), aCallerDocumentURI,
aIsFromPrivateWindow) {}
void Write(JSContext* aCx, JS::Handle<JS::Value> aMessage,
JS::Handle<JS::Value> aTransfer, ErrorResult& aError) {
mHolder.Write(aCx, aMessage, aTransfer, JS::CloneDataPolicy(), aError);
mHolder.construct<StructuredCloneHolder>(
StructuredCloneHolder::CloningSupported,
StructuredCloneHolder::TransferringSupported,
JS::StructuredCloneScope::SameProcessSameThread);
mHolder.ref<StructuredCloneHolder>().Write(aCx, aMessage, aTransfer,
JS::CloneDataPolicy(), aError);
}
void UnpackFrom(const ClonedMessageData& aMessageData) {
mHolder.construct<ipc::StructuredCloneData>();
// FIXME Want to steal!
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1516349.
mHolder.ref<ipc::StructuredCloneData>().CopyFromClonedMessageDataForChild(
aMessageData);
}
private:
PostMessageEvent(BrowsingContext* aSource, const nsAString& aCallerOrigin,
nsGlobalWindowOuter* aTargetWindow,
nsIPrincipal* aProvidedPrincipal,
const Maybe<uint64_t>& aCallerWindowID,
nsIURI* aCallerDocumentURI, bool aIsFromPrivateWindow);
~PostMessageEvent();
void Dispatch(nsGlobalWindowInner* aTargetWindow, Event* aEvent);
@ -54,9 +87,15 @@ class PostMessageEvent final : public Runnable {
nsString mCallerOrigin;
RefPtr<nsGlobalWindowOuter> mTargetWindow;
nsCOMPtr<nsIPrincipal> mProvidedPrincipal;
StructuredCloneHolder mHolder;
uint64_t mCallerWindowID;
// If the postMessage call was made on a WindowProxy whose Window lives in a
// separate process then mHolder will contain a StructuredCloneData, else
// it'll contain a StructuredCloneHolder.
MaybeOneOf<StructuredCloneHolder, ipc::StructuredCloneData> mHolder;
Maybe<uint64_t> mCallerWindowID;
nsCOMPtr<nsIURI> mCallerDocumentURI;
// This is only set to a relevant value if mCallerWindowID doesn't contain a
// value.
bool mIsFromPrivateWindow;
};
} // namespace dom

View File

@ -0,0 +1,194 @@
/* -*- 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 {
namespace 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.
* However, RemoteOuterWindowProxy only holds BrowsingContexts that don't have a
* reference to a docshell, so there's no need to declare the edge from
* RemoteOuterWindowProxy to its BrowsingContext to the cycle collector.
*
* FIXME Verify that this is correct:
* https://bugzilla.mozilla.org/show_bug.cgi?id=1516350.
*/
class RemoteOuterWindowProxy
: public RemoteObjectProxy<BrowsingContext,
Window_Binding::sCrossOriginAttributes,
Window_Binding::sCrossOriginMethods> {
public:
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::AutoIdVector& aProps) const final;
// SpiderMonkey extensions
bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::AutoIdVector& props) const final;
void finalize(JSFreeOp* aFop, JSObject* aProxy) const final;
const char* className(JSContext* aCx,
JS::Handle<JSObject*> aProxy) const final;
};
static const RemoteOuterWindowProxy sSingleton;
// Give RemoteOuterWindowProxyClass 2 reserved slots, like the other wrappers,
// so JSObject::swap can swap it with CrossCompartmentWrappers without requiring
// malloc.
const js::Class RemoteOuterWindowProxyClass =
PROXY_CLASS_DEF("Proxy", JSCLASS_HAS_RESERVED_SLOTS(2));
bool GetRemoteOuterWindowProxy(JSContext* aCx, BrowsingContext* aContext,
JS::MutableHandle<JSObject*> aRetVal) {
MOZ_ASSERT(!aContext->GetDocShell(),
"Why are we creating a RemoteOuterWindowProxy?");
xpc::CompartmentPrivate* priv =
xpc::CompartmentPrivate::Get(JS::CurrentGlobalOrNull(aCx));
xpc::CompartmentPrivate::RemoteProxyMap& map = priv->GetRemoteProxyMap();
auto result = map.lookupForAdd(aContext);
if (result) {
aRetVal.set(result->value());
return true;
}
JS::Rooted<JSObject*> obj(
aCx, sSingleton.CreateProxyObject(aCx, aContext,
&RemoteOuterWindowProxyClass));
if (!obj) {
return false;
}
NS_ADDREF(aContext);
if (!map.add(result, aContext, obj)) {
JS_ReportOutOfMemory(aCx);
return false;
}
aRetVal.set(obj);
return true;
}
static 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.object().set(aProxy);
aDesc.setDataDescriptor(v, attrs);
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)) {
const BrowsingContext::Children& children = bc->GetChildren();
if (index < children.Length()) {
return WrapResult(aCx, aProxy, children[index],
JSPROP_READONLY | JSPROP_ENUMERATE, aDesc);
}
return ReportCrossOriginDenial(aCx, aId, NS_LITERAL_CSTRING("access"));
}
bool ok = RemoteObjectProxy::getOwnPropertyDescriptorInternal(aCx, aProxy,
aId, aDesc);
if (!ok || aDesc.object()) {
return ok;
}
if (JSID_IS_STRING(aId)) {
nsAutoJSString str;
if (!str.init(aCx, JSID_TO_STRING(aId))) {
return false;
}
for (BrowsingContext* child : bc->GetChildren()) {
if (child->NameEquals(str)) {
return WrapResult(aCx, aProxy, child, JSPROP_READONLY, aDesc);
}
}
}
return getOwnPropertyDescriptorTail(aCx, aProxy, aId, aDesc);
}
bool AppendIndexedPropertyNames(JSContext* aCx, BrowsingContext* aContext,
JS::AutoIdVector& aIndexedProps) {
int32_t length = aContext->GetChildren().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::AutoIdVector& 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::AutoIdVector& aProps) const {
return AppendIndexedPropertyNames(aCx, GetBrowsingContext(aProxy), aProps);
}
void RemoteOuterWindowProxy::finalize(JSFreeOp* aFop, JSObject* aProxy) const {
BrowsingContext* bc = GetBrowsingContext(aProxy);
RefPtr<BrowsingContext> self(dont_AddRef(bc));
}
const char* RemoteOuterWindowProxy::className(
JSContext* aCx, JS::Handle<JSObject*> aProxy) const {
MOZ_ASSERT(js::IsProxy(aProxy));
return "Object";
}
} // namespace dom
} // namespace mozilla

View File

@ -9,6 +9,14 @@
#include "mozilla/dom/BrowsingContext.h"
struct JSContext;
class JSObject;
namespace JS {
template <typename T>
class MutableHandle;
} // namespace JS
namespace mozilla {
namespace dom {
@ -61,6 +69,9 @@ inline void ImplCycleCollectionUnlink(WindowProxyHolder& aProxy) {
aProxy.mBrowsingContext = nullptr;
}
extern bool GetRemoteOuterWindowProxy(JSContext* aCx, BrowsingContext* aContext,
JS::MutableHandle<JSObject*> aValue);
} // namespace dom
} // namespace mozilla

View File

@ -211,6 +211,7 @@ EXPORTS.mozilla.dom += [
'PlacesWeakCallbackWrapper.h',
'PopupBlocker.h',
'Pose.h',
'PostMessageEvent.h',
'ProcessMessageManager.h',
'ResponsiveImageSelector.h',
'SameProcessMessageQueue.h',
@ -369,6 +370,7 @@ UNIFIED_SOURCES += [
'Pose.cpp',
'PostMessageEvent.cpp',
'ProcessMessageManager.cpp',
'RemoteOuterWindowProxy.cpp',
'ResponsiveImageSelector.cpp',
'SameProcessMessageQueue.cpp',
'ScreenLuminance.cpp',

View File

@ -5707,9 +5707,7 @@ already_AddRefed<Location> nsIDocument::GetLocation() const {
return nullptr;
}
nsGlobalWindowInner* window = nsGlobalWindowInner::Cast(w);
RefPtr<Location> loc = window->GetLocation();
return loc.forget();
return do_AddRef(w->Location());
}
Element* nsIDocument::GetHtmlElement() const {

View File

@ -299,18 +299,27 @@ using mozilla::dom::cache::CacheStorage;
return outer->method args; \
PR_END_MACRO
static nsGlobalWindowOuter* GetOuterWindowForForwarding(
nsGlobalWindowInner* aInner, ErrorResult& aError) {
nsGlobalWindowOuter* outer = aInner->GetOuterWindowInternal();
if (MOZ_LIKELY(aInner->HasActiveDocument())) {
return outer;
}
if (!outer) {
NS_WARNING("No outer window available!");
aError.Throw(NS_ERROR_NOT_INITIALIZED);
} else {
aError.Throw(NS_ERROR_XPC_SECURITY_MANAGER_VETO);
}
return nullptr;
}
#define FORWARD_TO_OUTER_OR_THROW(method, args, errorresult, err_rval) \
PR_BEGIN_MACRO \
nsGlobalWindowOuter* outer = GetOuterWindowInternal(); \
if (MOZ_LIKELY(HasActiveDocument())) { \
nsGlobalWindowOuter* outer = GetOuterWindowForForwarding(this, errorresult); \
if (MOZ_LIKELY(outer)) { \
return outer->method args; \
} \
if (!outer) { \
NS_WARNING("No outer window available!"); \
errorresult.Throw(NS_ERROR_NOT_INITIALIZED); \
} else { \
errorresult.Throw(NS_ERROR_XPC_SECURITY_MANAGER_VETO); \
} \
return err_rval; \
PR_END_MACRO
@ -2112,9 +2121,9 @@ void nsPIDOMWindowInner::UnmuteAudioContexts() {
}
}
nsGlobalWindowInner* nsGlobalWindowInner::Window() { return this; }
nsGlobalWindowInner* nsGlobalWindowInner::Self() { return this; }
BrowsingContext* nsGlobalWindowInner::Window() {
return mOuterWindow ? mOuterWindow->GetBrowsingContext() : nullptr;
}
Navigator* nsPIDOMWindowInner::Navigator() {
if (!mNavigator) {
@ -3419,7 +3428,7 @@ void nsGlobalWindowInner::Prompt(const nsAString& aMessage,
}
void nsGlobalWindowInner::Focus(ErrorResult& aError) {
FORWARD_TO_OUTER_OR_THROW(FocusOuter, (aError), aError, );
FORWARD_TO_OUTER_OR_THROW(FocusOuter, (), aError, );
}
nsresult nsGlobalWindowInner::Focus() {
@ -3751,8 +3760,8 @@ void nsGlobalWindowInner::PostMessageMoz(
aSubjectPrincipal, aRv);
}
void nsGlobalWindowInner::Close(ErrorResult& aError) {
FORWARD_TO_OUTER_OR_THROW(CloseOuter, (nsContentUtils::IsCallerChrome()),
void nsGlobalWindowInner::Close(CallerType aCallerType, ErrorResult& aError) {
FORWARD_TO_OUTER_OR_THROW(CloseOuter, (aCallerType == CallerType::System),
aError, );
}
@ -3934,7 +3943,7 @@ EventListenerManager* nsGlobalWindowInner::GetExistingListenerManager() const {
// nsGlobalWindowInner::nsPIDOMWindow
//*****************************************************************************
Location* nsGlobalWindowInner::GetLocation() {
Location* nsGlobalWindowInner::Location() {
if (!mLocation) {
mLocation = new dom::Location(this, GetDocShell());
}

View File

@ -214,6 +214,8 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
public nsAPostRefreshObserver,
public mozilla::webgpu::InstanceProvider {
public:
typedef mozilla::dom::BrowsingContext RemoteProxy;
typedef mozilla::TimeStamp TimeStamp;
typedef mozilla::TimeDuration TimeDuration;
@ -599,12 +601,12 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
static JSObject* CreateNamedPropertiesObject(JSContext* aCx,
JS::Handle<JSObject*> aProto);
nsGlobalWindowInner* Window();
nsGlobalWindowInner* Self();
mozilla::dom::BrowsingContext* Window();
mozilla::dom::BrowsingContext* Self() { return Window(); }
nsIDocument* GetDocument() { return GetDoc(); }
void GetName(nsAString& aName, mozilla::ErrorResult& aError);
void SetName(const nsAString& aName, mozilla::ErrorResult& aError);
mozilla::dom::Location* GetLocation() override;
mozilla::dom::Location* Location() override;
nsHistory* GetHistory(mozilla::ErrorResult& aError);
mozilla::dom::CustomElementRegistry* CustomElements() override;
mozilla::dom::BarProp* GetLocationbar(mozilla::ErrorResult& aError);
@ -615,7 +617,8 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
mozilla::dom::BarProp* GetToolbar(mozilla::ErrorResult& aError);
void GetStatus(nsAString& aStatus, mozilla::ErrorResult& aError);
void SetStatus(const nsAString& aStatus, mozilla::ErrorResult& aError);
void Close(mozilla::ErrorResult& aError);
void Close(mozilla::dom::CallerType aCallerType,
mozilla::ErrorResult& aError);
nsresult Close() override;
bool GetClosed(mozilla::ErrorResult& aError);
void Stop(mozilla::ErrorResult& aError);

View File

@ -3582,16 +3582,9 @@ Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetTopOuter() {
already_AddRefed<BrowsingContext> nsGlobalWindowOuter::GetChildWindow(
const nsAString& aName) {
nsCOMPtr<nsIDocShell> docShell(GetDocShell());
NS_ENSURE_TRUE(docShell, nullptr);
NS_ENSURE_TRUE(mBrowsingContext, nullptr);
nsCOMPtr<nsIDocShellTreeItem> child;
docShell->FindChildWithName(aName, false, true, nullptr, nullptr,
getter_AddRefs(child));
return child && child->GetWindow()
? do_AddRef(child->GetWindow()->GetBrowsingContext())
: nullptr;
return mBrowsingContext->FindChildWithName(aName);
}
bool nsGlobalWindowOuter::DispatchCustomEvent(const nsAString& aEventName) {
@ -4487,8 +4480,8 @@ void nsGlobalWindowOuter::PromptOuter(const nsAString& aMessage,
}
}
void nsGlobalWindowOuter::FocusOuter(ErrorResult& aError) {
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
void nsGlobalWindowOuter::FocusOuter() {
nsFocusManager* fm = nsFocusManager::GetFocusManager();
if (!fm) {
return;
}
@ -4578,7 +4571,10 @@ void nsGlobalWindowOuter::FocusOuter(ErrorResult& aError) {
if (frame) {
uint32_t flags = nsIFocusManager::FLAG_NOSCROLL;
if (canFocus) flags |= nsIFocusManager::FLAG_RAISE;
aError = fm->SetFocus(frame, flags);
DebugOnly<nsresult> rv = fm->SetFocus(frame, flags);
MOZ_ASSERT(NS_SUCCEEDED(rv),
"SetFocus only fails if the first argument is null, "
"but we pass an element");
}
return;
}
@ -4587,7 +4583,10 @@ void nsGlobalWindowOuter::FocusOuter(ErrorResult& aError) {
// if there is no parent, this must be a toplevel window, so raise the
// window if canFocus is true. If this is a child process, the raise
// window request will get forwarded to the parent by the puppet widget.
aError = fm->SetActiveWindow(this);
DebugOnly<nsresult> rv = fm->SetActiveWindow(this);
MOZ_ASSERT(NS_SUCCEEDED(rv),
"SetActiveWindow only fails if passed null or a non-toplevel "
"window, which is not the case here.");
}
}
@ -5369,6 +5368,7 @@ BrowsingContext* nsGlobalWindowOuter::GetFramesOuter() {
return mBrowsingContext;
}
/* static */
nsGlobalWindowInner* nsGlobalWindowOuter::CallerInnerWindow(JSContext* aCx) {
nsIGlobalObject* global = GetIncumbentGlobal();
NS_ENSURE_TRUE(global, nullptr);
@ -5404,7 +5404,7 @@ nsGlobalWindowInner* nsGlobalWindowOuter::CallerInnerWindow(JSContext* aCx) {
bool nsGlobalWindowOuter::GatherPostMessageData(
JSContext* aCx, const nsAString& aTargetOrigin, BrowsingContext** aSource,
nsAString& aOrigin, nsIURI** aTargetOriginURI,
nsIPrincipal** aCallerPrincipal, uint64_t* aCallerInnerWindowID,
nsIPrincipal** aCallerPrincipal, nsGlobalWindowInner** aCallerInnerWindow,
nsIURI** aCallerDocumentURI, ErrorResult& aError) {
//
// Window.postMessage is an intentional subversion of the same-origin policy.
@ -5422,7 +5422,6 @@ bool nsGlobalWindowOuter::GatherPostMessageData(
if (!doc) {
return false;
}
*aCallerInnerWindowID = doc->InnerWindowID();
NS_IF_ADDREF(*aCallerDocumentURI = doc->GetDocumentURI());
// Compute the caller's origin either from its principal or, in the case the
@ -5433,8 +5432,6 @@ bool nsGlobalWindowOuter::GatherPostMessageData(
// might have changed due to intervening navigations).
callerPrin = callerInnerWin->GetPrincipal();
} else {
*aCallerInnerWindowID = 0;
// In case the global is not a window, it can be a sandbox, and the
// sandbox's principal can be used for the security check.
nsIGlobalObject* global = GetIncumbentGlobal();
@ -5493,6 +5490,8 @@ bool nsGlobalWindowOuter::GatherPostMessageData(
*aSource = nullptr;
}
callerInnerWin.forget(aCallerInnerWindow);
return true;
}
@ -5595,12 +5594,13 @@ void nsGlobalWindowOuter::PostMessageMozOuter(JSContext* aCx,
nsAutoString origin;
nsCOMPtr<nsIURI> targetOriginURI;
nsCOMPtr<nsIPrincipal> callerPrincipal;
uint64_t callerInnerWindowID;
RefPtr<nsGlobalWindowInner> callerInnerWindow;
nsCOMPtr<nsIURI> callerDocumentURI;
if (!GatherPostMessageData(
aCx, aTargetOrigin, getter_AddRefs(sourceBc), origin,
getter_AddRefs(targetOriginURI), getter_AddRefs(callerPrincipal),
&callerInnerWindowID, getter_AddRefs(callerDocumentURI), aError)) {
if (!GatherPostMessageData(aCx, aTargetOrigin, getter_AddRefs(sourceBc),
origin, getter_AddRefs(targetOriginURI),
getter_AddRefs(callerPrincipal),
getter_AddRefs(callerInnerWindow),
getter_AddRefs(callerDocumentURI), aError)) {
return;
}
@ -5613,9 +5613,9 @@ void nsGlobalWindowOuter::PostMessageMozOuter(JSContext* aCx,
// Create and asynchronously dispatch a runnable which will handle actual DOM
// event creation and dispatch.
RefPtr<PostMessageEvent> event =
new PostMessageEvent(sourceBc, origin, this, providedPrincipal,
callerInnerWindowID, callerDocumentURI);
RefPtr<PostMessageEvent> event = new PostMessageEvent(
sourceBc, origin, this, providedPrincipal,
callerInnerWindow ? callerInnerWindow->WindowID() : 0, callerDocumentURI);
event->Write(aCx, aMessage, aTransfer, aError);
if (NS_WARN_IF(aError.Failed())) {
@ -6247,7 +6247,7 @@ nsPIDOMWindowOuter* nsGlobalWindowOuter::GetPrivateRoot() {
// This has a caller in Windows-only code (nsNativeAppSupportWin).
Location* nsGlobalWindowOuter::GetLocation() {
// This method can be called on the outer window as well.
FORWARD_TO_INNER(GetLocation, (), nullptr);
FORWARD_TO_INNER(Location, (), nullptr);
}
void nsGlobalWindowOuter::ActivateOrDeactivate(bool aActivate) {

View File

@ -527,7 +527,7 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget,
bool GetClosedOuter();
bool Closed() override;
void StopOuter(mozilla::ErrorResult& aError);
void FocusOuter(mozilla::ErrorResult& aError);
void FocusOuter();
nsresult Focus() override;
void BlurOuter();
mozilla::dom::BrowsingContext* GetFramesOuter();
@ -968,42 +968,7 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget,
nsIPrincipal& aSubjectPrincipal,
mozilla::ErrorResult& aError);
private:
/**
* Gather the necessary data from the caller for a postMessage call.
*
* @param aCx The JSContext.
*
* @param aTargetOrigin The value passed as the targetOrigin argument to the
* postMessage call.
*
* @param aSource [out] The browsing context for the incumbent global.
*
* @param aOrigin [out] The value to use for the origin property of the
* MessageEvent object.
*
* @param aTargetOriginURI [out] The origin of the URI contained in
* aTargetOrigin, null if aTargetOrigin is "/" or "*".
*
* @param aCallerPrincipal [out] The principal of the incumbent global of the
* postMessage call.
*
* @param aCallerInnerWindowID [out] Inner window ID of the caller of
* postMessage, or 0 if the incumbent global is not a Window.
*
* @param aCallerDocumentURI [out] The URI of the document of the incumbent
* global if it's a Window, null otherwise.
*
* @param aError [out] The error, if any.
*
* @return Whether the postMessage call should continue or return now.
*/
static bool GatherPostMessageData(
JSContext* aCx, const nsAString& aTargetOrigin,
mozilla::dom::BrowsingContext** aSource, nsAString& aOrigin,
nsIURI** aTargetOriginURI, nsIPrincipal** aCallerPrincipal,
uint64_t* aCallerInnerWindowID, nsIURI** aCallerDocumentURI,
mozilla::ErrorResult& aError);
public:
/**
* Compute the principal to use for checking against the target principal in a
* postMessage call.
@ -1030,6 +995,43 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget,
nsIPrincipal& aSubjectPrincipal,
nsIPrincipal** aProvidedPrincipal);
private:
/**
* Gather the necessary data from the caller for a postMessage call.
*
* @param aCx The JSContext.
*
* @param aTargetOrigin The value passed as the targetOrigin argument to the
* postMessage call.
*
* @param aSource [out] The browsing context for the incumbent global.
*
* @param aOrigin [out] The value to use for the origin property of the
* MessageEvent object.
*
* @param aTargetOriginURI [out] The origin of the URI contained in
* aTargetOrigin, null if aTargetOrigin is "/" or "*".
*
* @param aCallerPrincipal [out] The principal of the incumbent global of the
* postMessage call.
*
* @param aCallerInnerWindow [out] Inner window of the caller of
* postMessage, or null if the incumbent global is not a Window.
*
* @param aCallerDocumentURI [out] The URI of the document of the incumbent
* global if it's a Window, null otherwise.
*
* @param aError [out] The error, if any.
*
* @return Whether the postMessage call should continue or return now.
*/
static bool GatherPostMessageData(
JSContext* aCx, const nsAString& aTargetOrigin,
mozilla::dom::BrowsingContext** aSource, nsAString& aOrigin,
nsIURI** aTargetOriginURI, nsIPrincipal** aCallerPrincipal,
nsGlobalWindowInner** aCallerInnerWindow, nsIURI** aCallerDocumentURI,
mozilla::ErrorResult& aError);
// Ask the user if further dialogs should be blocked, if dialogs are currently
// being abused. This is used in the cases where we have no modifiable UI to
// show, in that case we show a separate dialog to ask this question.

View File

@ -48,6 +48,7 @@
#include "nsExpirationTracker.h"
#include "nsClassHashtable.h"
#include "mozilla/CORSMode.h"
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/ContentBlockingLog.h"
#include "mozilla/dom/DispatcherTrait.h"
#include "mozilla/dom/DocumentOrShadowRoot.h"

View File

@ -539,7 +539,7 @@ class nsPIDOMWindowInner : public mozIDOMWindow {
uint32_t GetMarkedCCGeneration() { return mMarkedCCGeneration; }
mozilla::dom::Navigator* Navigator();
virtual mozilla::dom::Location* GetLocation() = 0;
virtual mozilla::dom::Location* Location() = 0;
virtual nsresult GetControllers(nsIControllers** aControllers) = 0;

View File

@ -2803,6 +2803,18 @@ namespace binding_detail {
* getter/setter/method, unwrap it. Otherwise just
* return the given object.
*
* UnwrapThisObject: Takes a MutableHandle for a JSObject which contains the
* this object (which the caller probably got from
* MaybeUnwrapThisObject). It will try to get the right native
* out of aObj. In some cases there are 2 possible types for
* the native (which is why aSelf is a reference to a void*).
* The ThisPolicy user should use the this JSObject* to
* determine what C++ class aSelf contains. aObj is used to
* keep the reflector object alive while self is being used,
* so its value before and after the UnwrapThisObject call
* could be different (if aObj was wrapped). The return value
* is an nsresult, which will signal if an error occurred.
*
* HandleInvalidThis: If the |this| is not valid (wrong type of value, wrong
* object, etc), decide what to do about it. Returns a
* boolean to return from the JSNative (false for failure,
@ -2830,6 +2842,14 @@ struct NormalThisPolicy {
return aObj;
}
static MOZ_ALWAYS_INLINE nsresult
UnwrapThisObject(JS::MutableHandle<JSObject*> aObj, void*& aSelf,
prototypes::ID aProtoID, uint32_t aProtoDepth) {
binding_detail::MutableObjectHandleWrapper wrapper(aObj);
return binding_detail::UnwrapObjectInternal<void, true>(
wrapper, aSelf, aProtoID, aProtoDepth);
}
static bool HandleInvalidThis(JSContext* aCx, JS::CallArgs& aArgs,
bool aSecurityError, prototypes::ID aProtoId) {
return ThrowInvalidThis(aCx, aArgs, aSecurityError, aProtoId);
@ -2886,11 +2906,50 @@ struct CrossOriginThisPolicy : public MaybeGlobalThisPolicy {
return js::UncheckedUnwrap(aObj);
}
// Else just return aObj; our UnwrapObjectInternal call will try to
// CheckedUnwrap it, and eitehr succeed or get a security error as needed.
// Else just return aObj; our UnwrapThisObject call will try to
// CheckedUnwrap it, and either succeed or get a security error as needed.
return aObj;
}
// After calling UnwrapThisObject aSelf can contain one of 2 types, depending
// on whether aObj is a proxy with a RemoteObjectProxy handler or a (maybe
// wrapped) normal WebIDL reflector. The generated binding code relies on this
// and uses IsRemoteObjectProxy to determine what type aSelf points to.
static MOZ_ALWAYS_INLINE nsresult
UnwrapThisObject(JS::MutableHandle<JSObject*> aObj, void*& aSelf,
prototypes::ID aProtoID, uint32_t aProtoDepth) {
binding_detail::MutableObjectHandleWrapper wrapper(aObj);
// We need to pass false here, because if aObj doesn't have a DOMJSClass
// it might be a remote proxy object, and we don't want to throw in that
// case (even though unwrapping would fail).
nsresult rv = binding_detail::UnwrapObjectInternal<void, false>(
wrapper, aSelf, aProtoID, aProtoDepth);
if (NS_SUCCEEDED(rv)) {
return rv;
}
if (js::IsWrapper(wrapper)) {
JSObject* unwrappedObj =
js::CheckedUnwrap(wrapper, /* stopAtWindowProxy = */ false);
if (!unwrappedObj) {
return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
}
// At this point we want to keep "unwrappedObj" alive, because we don't
// hold a strong reference in "aSelf".
wrapper = unwrappedObj;
return binding_detail::UnwrapObjectInternal<void, false>(
wrapper, aSelf, aProtoID, aProtoDepth);
}
if (!IsRemoteObjectProxy(wrapper, aProtoID)) {
return NS_ERROR_XPC_BAD_CONVERT_JS;
}
aSelf = RemoteObjectProxyBase::GetNative(wrapper);
return NS_OK;
}
// We want the HandleInvalidThis of MaybeGlobalThisPolicy.
};
@ -2946,9 +3005,8 @@ bool GenericGetter(JSContext* cx, unsigned argc, JS::Value* vp) {
JS::Rooted<JSObject*> rootSelf(cx, ThisPolicy::MaybeUnwrapThisObject(obj));
void* self;
{
binding_detail::MutableObjectHandleWrapper wrapper(&rootSelf);
nsresult rv = binding_detail::UnwrapObjectInternal<void, true>(
wrapper, self, protoID, info->depth);
nsresult rv =
ThisPolicy::UnwrapThisObject(&rootSelf, self, protoID, info->depth);
if (NS_FAILED(rv)) {
bool ok = ThisPolicy::HandleInvalidThis(
cx, args, rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO, protoID);
@ -3003,9 +3061,8 @@ bool GenericSetter(JSContext* cx, unsigned argc, JS::Value* vp) {
JS::Rooted<JSObject*> rootSelf(cx, ThisPolicy::MaybeUnwrapThisObject(obj));
void* self;
{
binding_detail::MutableObjectHandleWrapper wrapper(&rootSelf);
nsresult rv = binding_detail::UnwrapObjectInternal<void, true>(
wrapper, self, protoID, info->depth);
nsresult rv =
ThisPolicy::UnwrapThisObject(&rootSelf, self, protoID, info->depth);
if (NS_FAILED(rv)) {
return ThisPolicy::HandleInvalidThis(
cx, args, rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO, protoID);
@ -3053,9 +3110,8 @@ bool GenericMethod(JSContext* cx, unsigned argc, JS::Value* vp) {
JS::Rooted<JSObject*> rootSelf(cx, ThisPolicy::MaybeUnwrapThisObject(obj));
void* self;
{
binding_detail::MutableObjectHandleWrapper wrapper(&rootSelf);
nsresult rv = binding_detail::UnwrapObjectInternal<void, true>(
wrapper, self, protoID, info->depth);
nsresult rv =
ThisPolicy::UnwrapThisObject(&rootSelf, self, protoID, info->depth);
if (NS_FAILED(rv)) {
bool ok = ThisPolicy::HandleInvalidThis(
cx, args, rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO, protoID);
@ -3230,6 +3286,12 @@ nsresult UnwrapArgImpl(JSContext* cx, JS::Handle<JSObject*> src,
nsresult UnwrapWindowProxyArg(JSContext* cx, JS::Handle<JSObject*> src,
WindowProxyHolder& ppArg) {
if (IsRemoteObjectProxy(src, prototypes::id::Window)) {
ppArg =
static_cast<BrowsingContext*>(RemoteObjectProxyBase::GetNative(src));
return NS_OK;
}
nsCOMPtr<nsPIDOMWindowInner> inner;
nsresult rv = UnwrapArg<nsPIDOMWindowInner>(cx, src, getter_AddRefs(inner));
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -7694,6 +7694,10 @@ class CGPerSignatureCall(CGThing):
The idlNode parameter can be either a method or an attr. We can query
|idlNode.identifier| in both cases, so we can be agnostic between the two.
dontSetSlot should be set to True if the value should not be cached in a
slot (even if the attribute is marked as StoreInSlot or Cached in the
WebIDL).
"""
# XXXbz For now each entry in the argument list is either an
# IDLArgument or a FakeArgument, but longer-term we may want to
@ -7703,7 +7707,8 @@ class CGPerSignatureCall(CGThing):
def __init__(self, returnType, arguments, nativeMethodName, static,
descriptor, idlNode, argConversionStartsAt=0, getter=False,
setter=False, isConstructor=False, useCounterName=None,
resultVar=None, objectName="obj"):
resultVar=None, objectName="obj", dontSetSlot=False,
extendedAttributes=None):
assert idlNode.isMethod() == (not getter and not setter)
assert idlNode.isAttr() == (getter or setter)
# Constructors are always static
@ -7713,12 +7718,15 @@ class CGPerSignatureCall(CGThing):
self.returnType = returnType
self.descriptor = descriptor
self.idlNode = idlNode
self.extendedAttributes = descriptor.getExtendedAttributes(idlNode,
if extendedAttributes is None:
extendedAttributes = descriptor.getExtendedAttributes(idlNode,
getter=getter,
setter=setter)
self.extendedAttributes = extendedAttributes
self.arguments = arguments
self.argCount = len(arguments)
self.isConstructor = isConstructor
self.setSlot = not dontSetSlot and idlNode.isAttr() and idlNode.slotIndices is not None
cgThings = []
deprecated = (idlNode.getExtendedAttribute("Deprecated") or
@ -7961,8 +7969,7 @@ class CGPerSignatureCall(CGThing):
"NewObject implies that we need to keep the object alive with a strong reference.");
""")
setSlot = self.idlNode.isAttr() and self.idlNode.slotIndices is not None
if setSlot:
if self.setSlot:
# For attributes in slots, we want to do some
# post-processing once we've wrapped them.
successCode = "break;\n"
@ -7979,7 +7986,7 @@ class CGPerSignatureCall(CGThing):
# trying to do the to-JS conversion in. We're going to put that
# thing in a variable named "conversionScope" if setSlot is true.
# Otherwise, just use "obj" for lack of anything better.
'obj': "conversionScope" if setSlot else "obj"
'obj': "conversionScope" if self.setSlot else "obj"
}
try:
wrapCode += wrapForType(self.returnType, self.descriptor, resultTemplateValues)
@ -7989,7 +7996,7 @@ class CGPerSignatureCall(CGThing):
(err.typename,
self.descriptor.interface.identifier.name,
self.idlNode.identifier.name))
if setSlot:
if self.setSlot:
if self.idlNode.isStatic():
raise TypeError(
"Attribute %s.%s is static, so we don't have a useful slot "
@ -8590,7 +8597,8 @@ class CGGetterCall(CGPerSignatureCall):
A class to generate a native object getter call for a particular IDL
getter.
"""
def __init__(self, returnType, nativeMethodName, descriptor, attr):
def __init__(self, returnType, nativeMethodName, descriptor, attr, dontSetSlot=False,
extendedAttributes=None):
if attr.getExtendedAttribute("UseCounter"):
useCounterName = "%s_%s_getter" % (descriptor.interface.identifier.name,
attr.identifier.name)
@ -8600,7 +8608,9 @@ class CGGetterCall(CGPerSignatureCall):
nativeMethodName = "%s::%s" % (descriptor.nativeType, nativeMethodName)
CGPerSignatureCall.__init__(self, returnType, [], nativeMethodName,
attr.isStatic(), descriptor, attr,
getter=True, useCounterName=useCounterName)
getter=True, useCounterName=useCounterName,
dontSetSlot=dontSetSlot,
extendedAttributes=extendedAttributes)
class CGNavigatorGetterCall(CGPerSignatureCall):
@ -8608,10 +8618,12 @@ class CGNavigatorGetterCall(CGPerSignatureCall):
A class to generate a native object getter call for an IDL getter for a
property generated by NavigatorProperty.
"""
def __init__(self, returnType, _, descriptor, attr):
def __init__(self, returnType, _, descriptor, attr,
dontSetSlot=False):
nativeMethodName = "%s::ConstructNavigatorObject" % (toBindingNamespace(returnType.inner.identifier.name))
CGPerSignatureCall.__init__(self, returnType, [], nativeMethodName,
True, descriptor, attr, getter=True)
True, descriptor, attr, getter=True,
dontSetSlot=dontSetSlot)
def getArguments(self):
# The navigator object should be associated with the global of
@ -8791,9 +8803,13 @@ class CGSpecializedMethod(CGAbstractStaticMethod):
def __init__(self, descriptor, method):
self.method = method
name = CppKeywords.checkMethodName(IDLToCIdentifier(method.identifier.name))
if method.getExtendedAttribute("CrossOriginCallable"):
selfArg = Argument('void*', 'void_self')
else:
selfArg = Argument('%s*' % descriptor.nativeType, 'self')
args = [Argument('JSContext*', 'cx'),
Argument('JS::Handle<JSObject*>', 'obj'),
Argument('%s*' % descriptor.nativeType, 'self'),
selfArg,
Argument('const JSJitMethodCallArgs&', 'args')]
CGAbstractStaticMethod.__init__(self, descriptor, name, 'bool', args,
canRunScript=True)
@ -8801,8 +8817,34 @@ class CGSpecializedMethod(CGAbstractStaticMethod):
def definition_body(self):
nativeName = CGSpecializedMethod.makeNativeName(self.descriptor,
self.method)
return CGMethodCall(nativeName, self.method.isStatic(), self.descriptor,
call = CGMethodCall(nativeName, self.method.isStatic(), self.descriptor,
self.method).define()
if self.method.getExtendedAttribute("CrossOriginCallable"):
for signature in self.method.signatures():
# non-void signatures would require us to deal with remote proxies for the
# return value here.
if not signature[0].isVoid():
raise TypeError("We don't support a method marked as CrossOriginCallable "
"with non-void return type")
prototypeID, _ = PrototypeIDAndDepth(self.descriptor)
return fill("""
// CrossOriginThisPolicy::UnwrapThisObject stores a ${nativeType}::RemoteProxy in void_self
// if obj is a proxy with a RemoteObjectProxy handler for the right type, or else it stores
// a ${nativeType}. If we get here from the JIT (without going through UnwrapThisObject) we
// know void_self contains a ${nativeType}; we don't have special cases in the JIT to deal
// with remote object proxies.
if (IsRemoteObjectProxy(obj, ${prototypeID})) {
${nativeType}::RemoteProxy* self = static_cast<${nativeType}::RemoteProxy*>(void_self);
$*{call}
}
${nativeType}* self = static_cast<${nativeType}*>(void_self);
$*{call}
""",
prototypeID=prototypeID,
ifaceName=self.descriptor.name,
nativeType=self.descriptor.nativeType,
call=call)
return call
def auto_profiler_label(self):
interface_name = self.descriptor.interface.identifier.name
@ -9094,10 +9136,14 @@ class CGSpecializedGetter(CGAbstractStaticMethod):
def __init__(self, descriptor, attr):
self.attr = attr
name = 'get_' + IDLToCIdentifier(attr.identifier.name)
if attr.getExtendedAttribute("CrossOriginReadable"):
selfArg = Argument('void*', 'void_self')
else:
selfArg = Argument('%s*' % descriptor.nativeType, 'self')
args = [
Argument('JSContext*', 'cx'),
Argument('JS::Handle<JSObject*>', 'obj'),
Argument('%s*' % descriptor.nativeType, 'self'),
selfArg,
Argument('JSJitGetterCallArgs', 'args')
]
# StoreInSlot attributes have their getters called from Wrap(). We
@ -9117,6 +9163,30 @@ class CGSpecializedGetter(CGAbstractStaticMethod):
return getMaplikeOrSetlikeSizeGetterBody(self.descriptor, self.attr)
nativeName = CGSpecializedGetter.makeNativeName(self.descriptor,
self.attr)
prefix = ""
type = self.attr.type
if self.attr.getExtendedAttribute("CrossOriginReadable"):
remoteType = type
extendedAttributes = self.descriptor.getExtendedAttributes(self.attr, getter=True)
if remoteType.isGeckoInterface() and not remoteType.unroll().inner.isExternal():
# We'll use a JSObject. It might make more sense to use remoteType's
# RemoteProxy, but it's not easy to construct a type for that from here.
remoteType = BuiltinTypes[IDLBuiltinType.Types.object]
extendedAttributes.append('canOOM')
extendedAttributes.remove('infallible')
prototypeID, _ = PrototypeIDAndDepth(self.descriptor)
prefix = fill("""
if (IsRemoteObjectProxy(obj, ${prototypeID})) {
${nativeType}::RemoteProxy* self = static_cast<${nativeType}::RemoteProxy*>(void_self);
$*{call}
}
${nativeType}* self = static_cast<${nativeType}*>(void_self);
""",
prototypeID=prototypeID,
ifaceName=self.descriptor.name,
nativeType=self.descriptor.nativeType,
call=CGGetterCall(remoteType, nativeName, self.descriptor, self.attr, dontSetSlot=True,
extendedAttributes=extendedAttributes).define())
if self.attr.slotIndices is not None:
# We're going to store this return value in a slot on some object,
# to cache it. The question is, which object? For dictionary and
@ -9137,7 +9207,7 @@ class CGSpecializedGetter(CGAbstractStaticMethod):
# we know that in the interface type case the returned object is
# wrappercached. So creating Xrays to it is reasonable.
if mayUseXrayExpandoSlots(self.descriptor, self.attr):
prefix = fill(
prefix += fill(
"""
// Have to either root across the getter call or reget after.
bool isXray;
@ -9151,7 +9221,7 @@ class CGSpecializedGetter(CGAbstractStaticMethod):
self.descriptor),
slotIndex=memberReservedSlot(self.attr, self.descriptor))
else:
prefix = fill(
prefix += fill(
"""
// Have to either root across the getter call or reget after.
JS::Rooted<JSObject*> slotStorage(cx, js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false));
@ -9176,15 +9246,13 @@ class CGSpecializedGetter(CGAbstractStaticMethod):
""",
maybeWrap=getMaybeWrapValueFuncForType(self.attr.type))
else:
prefix = ""
if self.attr.navigatorObjectGetter:
cgGetterCall = CGNavigatorGetterCall
else:
cgGetterCall = CGGetterCall
return (prefix +
cgGetterCall(self.attr.type, nativeName,
cgGetterCall(type, nativeName,
self.descriptor, self.attr).define())
def auto_profiler_label(self):
@ -9280,9 +9348,13 @@ class CGSpecializedSetter(CGAbstractStaticMethod):
def __init__(self, descriptor, attr):
self.attr = attr
name = 'set_' + IDLToCIdentifier(attr.identifier.name)
if attr.getExtendedAttribute("CrossOriginWritable"):
selfArg = Argument('void*', 'void_self')
else:
selfArg = Argument('%s*' % descriptor.nativeType, 'self')
args = [Argument('JSContext*', 'cx'),
Argument('JS::Handle<JSObject*>', 'obj'),
Argument('%s*' % descriptor.nativeType, 'self'),
selfArg,
Argument('JSJitSetterCallArgs', 'args')]
CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args,
canRunScript=True)
@ -9290,8 +9362,29 @@ class CGSpecializedSetter(CGAbstractStaticMethod):
def definition_body(self):
nativeName = CGSpecializedSetter.makeNativeName(self.descriptor,
self.attr)
return CGSetterCall(self.attr.type, nativeName, self.descriptor,
self.attr).define()
type = self.attr.type
call = CGSetterCall(type, nativeName, self.descriptor, self.attr).define()
if self.attr.getExtendedAttribute("CrossOriginWritable"):
if type.isGeckoInterface() and not type.unroll().inner.isExternal():
# a setter taking a Gecko interface would require us to deal with remote
# proxies for the value here.
raise TypeError("We don't support the setter of %s marked as "
"CrossOriginWritable because it takes a Gecko interface "
"as the value", attr.identifier.name)
prototypeID, _ = PrototypeIDAndDepth(self.descriptor)
return fill("""
if (IsRemoteObjectProxy(obj, ${prototypeID})) {
${nativeType}::RemoteProxy* self = static_cast<${nativeType}::RemoteProxy*>(void_self);
$*{call}
}
${nativeType}* self = static_cast<${nativeType}*>(void_self);
$*{call}
""",
prototypeID=prototypeID,
ifaceName=self.descriptor.name,
nativeType=self.descriptor.nativeType,
call=call)
return call
def auto_profiler_label(self):
interface_name = self.descriptor.interface.identifier.name
@ -14090,6 +14183,7 @@ class CGBindingRoot(CGThing):
return any(hasCrossOriginProperty(m) for m in desc.interface.members)
bindingDeclareHeaders["mozilla/dom/RemoteObjectProxy.h"] = any(descriptorHasCrossOriginProperties(d) for d in descriptors)
bindingDeclareHeaders["jsapi.h"] = any(descriptorHasCrossOriginProperties(d) for d in descriptors)
bindingDeclareHeaders["jspubtd.h"] = not bindingDeclareHeaders["jsapi.h"]
bindingDeclareHeaders["js/RootingAPI.h"] = not bindingDeclareHeaders["jsapi.h"]

View File

@ -0,0 +1,240 @@
/* -*- 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"
namespace mozilla {
namespace dom {
// Give RemoteObjectProxy 2 reserved slots, like the other wrappers, so
// JSObject::swap can swap it with CrossCompartmentWrappers without requiring
// malloc.
const js::Class RemoteObjectProxyClass =
PROXY_CLASS_DEF("Proxy", JSCLASS_HAS_RESERVED_SLOTS(2));
bool RemoteObjectProxyBase::getOwnPropertyDescriptor(
JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
JS::MutableHandle<JS::PropertyDescriptor> aDesc) const {
bool ok = getOwnPropertyDescriptorInternal(aCx, aProxy, aId, aDesc);
if (!ok || aDesc.object()) {
return ok;
}
return getOwnPropertyDescriptorTail(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, NS_LITERAL_CSTRING("define"));
}
bool RemoteObjectProxyBase::ownPropertyKeys(JSContext* aCx,
JS::Handle<JSObject*> aProxy,
JS::AutoIdVector& 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, NS_LITERAL_CSTRING("delete"));
}
bool RemoteObjectProxyBase::getPrototype(
JSContext* aCx, JS::Handle<JSObject*> aProxy,
JS::MutableHandle<JSObject*> aProtop) const {
// https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-getprototypeof
// step 3 and
// https://html.spec.whatwg.org/multipage/browsers.html#location-getprototypeof
// step 2
aProtop.set(nullptr);
return true;
}
bool RemoteObjectProxyBase::setPrototype(JSContext* aCx,
JS::Handle<JSObject*> aProxy,
JS::Handle<JSObject*> aProto,
JS::ObjectOpResult& aResult) const {
// https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-setprototypeof
// and
// https://html.spec.whatwg.org/multipage/browsers.html#location-setprototypeof
// say to call SetImmutablePrototype, which does nothing and just returns
// whether the passed-in value equals the current prototype. Our current
// prototype is always null, so this just comes down to returning whether null
// was passed in.
//
// In terms of ObjectOpResult that means calling one of the fail*() things on
// it if non-null was passed, and it's got one that does just what we want.
if (!aProto) {
return aResult.succeed();
}
return aResult.failCantSetProto();
}
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;
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 {
Rooted<PropertyDescriptor> desc(aCx);
if (!getOwnPropertyDescriptor(aCx, aProxy, aId, &desc)) {
return false;
}
MOZ_ASSERT(desc.object());
if (desc.isDataDescriptor()) {
aVp.set(desc.value());
return true;
}
JS::Rooted<JSObject*> getter(aCx);
if (!desc.hasGetterObject() || !(getter = desc.getterObject())) {
return ReportCrossOriginDenial(aCx, aId, NS_LITERAL_CSTRING("get"));
}
return JS::Call(aCx, aReceiver, getter, JS::HandleValueArray::empty(), 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 {
Rooted<PropertyDescriptor> desc(aCx);
if (!getOwnPropertyDescriptor(aCx, aProxy, aId, &desc)) {
return false;
}
MOZ_ASSERT(desc.object());
JS::Rooted<JSObject*> setter(aCx);
if (!desc.hasSetterObject() || !(setter = desc.setterObject())) {
return ReportCrossOriginDenial(aCx, aId, NS_LITERAL_CSTRING("set"));
}
JS::Rooted<JS::Value> rv(aCx);
return JS::Call(aCx, aReceiver, setter, JS::HandleValueArray(aValue), &rv) &&
aResult.succeed();
}
bool RemoteObjectProxyBase::hasOwn(JSContext* aCx, JS::Handle<JSObject*> aProxy,
JS::Handle<jsid> aId, bool* aBp) const {
JS::Rooted<JSObject*> holder(aCx);
if (!EnsureHolder(aCx, aProxy, &holder) ||
!JS_AlreadyHasOwnPropertyById(aCx, holder, aId, aBp)) {
return false;
}
if (!*aBp) {
*aBp = xpc::IsCrossOriginWhitelistedProp(aCx, aId);
}
return true;
}
bool RemoteObjectProxyBase::getOwnEnumerablePropertyKeys(
JSContext* aCx, JS::Handle<JSObject*> aProxy,
JS::AutoIdVector& aProps) const {
return true;
}
JSObject* RemoteObjectProxyBase::CreateProxyObject(
JSContext* aCx, void* aNative, const js::Class* aClasp) const {
js::ProxyOptions options;
options.setClass(aClasp);
JS::Rooted<JS::Value> native(aCx, JS::PrivateValue(aNative));
return js::NewProxyObject(aCx, this, native, nullptr, options);
}
/* static */
bool RemoteObjectProxyBase::getOwnPropertyDescriptorTail(
JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
JS::MutableHandle<JS::PropertyDescriptor> aDesc) {
if (xpc::IsCrossOriginWhitelistedProp(aCx, aId)) {
// https://html.spec.whatwg.org/multipage/browsers.html#crossorigingetownpropertyhelper-(-o,-p-)
// step 3 says to return PropertyDescriptor {
// [[Value]]: undefined, [[Writable]]: false, [[Enumerable]]: false,
// [[Configurable]]: true
// }.
//
aDesc.setDataDescriptor(JS::UndefinedHandleValue, JSPROP_READONLY);
aDesc.object().set(aProxy);
return true;
}
return ReportCrossOriginDenial(aCx, aId, NS_LITERAL_CSTRING("access"));
}
/* static */
bool RemoteObjectProxyBase::ReportCrossOriginDenial(
JSContext* aCx, JS::Handle<jsid> aId, const nsACString& aAccessType) {
xpc::AccessCheck::reportCrossOriginDenial(aCx, aId, aAccessType);
return false;
}
const char RemoteObjectProxyBase::sCrossOriginProxyFamily = 0;
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,200 @@
/* -*- 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/. */
#ifndef mozilla_dom_RemoteObjectProxy_h
#define mozilla_dom_RemoteObjectProxy_h
#include "js/Proxy.h"
#include "mozilla/dom/PrototypeList.h"
#include "xpcpublic.h"
namespace mozilla {
namespace dom {
/**
* Base class for RemoteObjectProxy. Implements the pieces of the handler that
* don't depend on properties/methods of the specific WebIDL interface that this
* proxy implements.
*/
class RemoteObjectProxyBase : public js::BaseProxyHandler {
protected:
explicit constexpr RemoteObjectProxyBase(prototypes::ID aPrototypeID)
: BaseProxyHandler(&sCrossOriginProxyFamily, false),
mPrototypeID(aPrototypeID) {}
public:
bool finalizeInBackground(const JS::Value& priv) const final { return false; }
// Standard internal methods
bool getOwnPropertyDescriptor(
JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
JS::MutableHandle<JS::PropertyDescriptor> aDesc) const override;
bool ownPropertyKeys(JSContext* aCx, JS::Handle<JSObject*> aProxy,
JS::AutoIdVector& aProps) const override;
bool defineProperty(JSContext* aCx, JS::Handle<JSObject*> aProxy,
JS::Handle<jsid> aId,
JS::Handle<JS::PropertyDescriptor> aDesc,
JS::ObjectOpResult& result) const final;
bool delete_(JSContext* aCx, JS::Handle<JSObject*> aProxy,
JS::Handle<jsid> aId, JS::ObjectOpResult& aResult) const final;
bool getPrototype(JSContext* aCx, JS::Handle<JSObject*> aProxy,
JS::MutableHandle<JSObject*> aProtop) const final;
bool setPrototype(JSContext* aCx, JS::Handle<JSObject*> aProxy,
JS::Handle<JSObject*> aProto,
JS::ObjectOpResult& aResult) const final;
bool getPrototypeIfOrdinary(JSContext* aCx, JS::Handle<JSObject*> aProxy,
bool* aIsOrdinary,
JS::MutableHandle<JSObject*> aProtop) const final;
bool preventExtensions(JSContext* aCx, JS::Handle<JSObject*> aProxy,
JS::ObjectOpResult& aResult) const final;
bool isExtensible(JSContext* aCx, JS::Handle<JSObject*> aProxy,
bool* aExtensible) const final;
bool get(JSContext* cx, JS::Handle<JSObject*> aProxy,
JS::Handle<JS::Value> aReceiver, JS::Handle<jsid> aId,
JS::MutableHandle<JS::Value> aVp) const final;
bool set(JSContext* cx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
JS::Handle<JS::Value> aValue, JS::Handle<JS::Value> aReceiver,
JS::ObjectOpResult& aResult) const final;
// SpiderMonkey extensions
bool hasOwn(JSContext* aCx, JS::Handle<JSObject*> aProxy,
JS::Handle<jsid> aId, bool* aBp) const override;
bool getOwnEnumerablePropertyKeys(JSContext* aCx,
JS::Handle<JSObject*> aProxy,
JS::AutoIdVector& aProps) const override;
bool isCallable(JSObject* aObj) const final { return false; }
bool isConstructor(JSObject* aObj) const final { return false; }
static void* GetNative(JSObject* aProxy) {
return js::GetProxyPrivate(aProxy).toPrivate();
}
/**
* Returns true if aProxy represents an object implementing the WebIDL
* interface for aProtoID. aProxy should be a proxy object.
*/
static inline bool IsRemoteObjectProxy(JSObject* aProxy,
prototypes::ID aProtoID) {
const js::BaseProxyHandler* handler = js::GetProxyHandler(aProxy);
return handler->family() == &sCrossOriginProxyFamily &&
static_cast<const RemoteObjectProxyBase*>(handler)->mPrototypeID ==
aProtoID;
}
protected:
bool getOwnPropertyDescriptorInternal(
JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
JS::MutableHandle<JS::PropertyDescriptor> aDesc) const {
JS::Rooted<JSObject*> holder(aCx);
if (!EnsureHolder(aCx, aProxy, &holder) ||
!JS_GetOwnPropertyDescriptorById(aCx, holder, aId, aDesc)) {
return false;
}
if (aDesc.object()) {
aDesc.object().set(aProxy);
}
return true;
}
JSObject* CreateProxyObject(JSContext* aCx, void* aNative,
const js::Class* aClasp) const;
/**
* Implements the tail of getOwnPropertyDescriptor, dealing in particular with
* properties that are whitelisted by xpc::IsCrossOriginWhitelistedProp.
*/
static bool getOwnPropertyDescriptorTail(
JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
JS::MutableHandle<JS::PropertyDescriptor> aDesc);
static bool ReportCrossOriginDenial(JSContext* aCx, JS::Handle<jsid> aId,
const nsACString& aAccessType);
/**
* This gets a cached, or creates and caches, a holder object that contains
* the WebIDL properties for this proxy.
*/
bool EnsureHolder(JSContext* aCx, JS::Handle<JSObject*> aProxy,
JS::MutableHandle<JSObject*> aHolder) const {
// FIXME Need to have a holder per realm, should store a weakmap in the
// reserved slot.
JS::Value v = js::GetProxyReservedSlot(aProxy, 0);
if (v.isObject()) {
aHolder.set(&v.toObject());
return true;
}
aHolder.set(JS_NewObjectWithGivenProto(aCx, nullptr, nullptr));
if (!aHolder || !DefinePropertiesAndFunctions(aCx, aHolder)) {
return false;
}
js::SetProxyReservedSlot(aProxy, 0, JS::ObjectValue(*aHolder));
return true;
}
virtual bool DefinePropertiesAndFunctions(
JSContext* aCx, JS::Handle<JSObject*> aHolder) const = 0;
const prototypes::ID mPrototypeID;
static const char sCrossOriginProxyFamily;
};
/**
* Proxy handler for proxy objects that represent an object implementing a
* WebIDL interface that has cross-origin accessible properties/methods, and
* which lives in a different process. The WebIDL code generator will create
* arrays of cross-origin accessible properties/methods that can be used as
* arguments to this template.
*
* The properties and methods can be cached on a holder JSObject, stored in a
* reserved slot on the proxy object.
*
* The proxy objects that use a handler derived from this one are stored in a
* hash map in the JS compartment's private (@see
* xpc::CompartmentPrivate::GetRemoteProxyMap).
*/
template <class Native, JSPropertySpec* P, JSFunctionSpec* F>
class RemoteObjectProxy : public RemoteObjectProxyBase {
public:
JSObject* CreateProxyObject(JSContext* aCx, Native* aNative,
const js::Class* aClasp) const {
return RemoteObjectProxyBase::CreateProxyObject(aCx, aNative, aClasp);
}
protected:
using RemoteObjectProxyBase::RemoteObjectProxyBase;
private:
bool DefinePropertiesAndFunctions(
JSContext* aCx, JS::Handle<JSObject*> aHolder) const final {
return JS_DefineProperties(aCx, aHolder, P) &&
JS_DefineFunctions(aCx, aHolder, F);
}
};
/**
* Returns true if aObj is a proxy object that represents an object implementing
* the WebIDL interface for aProtoID.
*/
static inline bool IsRemoteObjectProxy(JSObject* aObj,
prototypes::ID aProtoID) {
if (!js::IsProxy(aObj)) {
return false;
}
return RemoteObjectProxyBase::IsRemoteObjectProxy(aObj, aProtoID);
}
} // namespace dom
} // namespace mozilla
#endif /* mozilla_dom_RemoteObjectProxy_h */

View File

@ -68,7 +68,9 @@ bool ToJSValue(JSContext* aCx, const WindowProxyHolder& aArgument,
aValue.setNull();
return true;
}
JS::Rooted<JSObject*> windowProxy(aCx, bc->GetWindowProxy());
JS::Rooted<JSObject*> windowProxy(aCx);
if (bc->GetDocShell()) {
windowProxy = bc->GetWindowProxy();
if (!windowProxy) {
nsPIDOMWindowOuter* window = bc->GetDOMWindow();
if (!window->EnsureInnerWindow()) {
@ -79,5 +81,12 @@ bool ToJSValue(JSContext* aCx, const WindowProxyHolder& aArgument,
return ToJSValue(aCx, windowProxy, aValue);
}
if (!GetRemoteOuterWindowProxy(aCx, bc, &windowProxy)) {
return false;
}
aValue.setObjectOrNull(windowProxy);
return true;
}
} // namespace dom
} // namespace mozilla

View File

@ -49,6 +49,7 @@ EXPORTS.mozilla.dom += [
'PrimitiveConversions.h',
'ReadableStream.h',
'Record.h',
'RemoteObjectProxy.h',
'RootedDictionary.h',
'SimpleGlobalObject.h',
'SpiderMonkeyInterface.h',
@ -113,6 +114,7 @@ UNIFIED_SOURCES += [
'IterableIterator.cpp',
'nsScriptError.cpp',
'nsScriptErrorWithStack.cpp',
'RemoteObjectProxy.cpp',
'SimpleGlobalObject.cpp',
'ToJSValue.cpp',
'WebIDLGlobalNameHash.cpp',

View File

@ -62,16 +62,7 @@ void nsScriptErrorBase::InitializeOnMainThread() {
nsPIDOMWindowOuter* outer = window->GetOuterWindow();
if (outer) mOuterWindowID = outer->WindowID();
nsIDocShell* docShell = window->GetDocShell();
nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
if (loadContext) {
// Never mark exceptions from chrome windows as having come from
// private windows, since we always want them to be reported.
nsIPrincipal* winPrincipal = window->GetPrincipal();
mIsFromPrivateWindow = loadContext->UsePrivateBrowsing() &&
!nsContentUtils::IsSystemPrincipal(winPrincipal);
}
mIsFromPrivateWindow = ComputeIsFromPrivateWindow(window);
}
}
@ -389,6 +380,15 @@ nsScriptErrorBase::GetNotes(nsIArray** aNotes) {
return NS_OK;
}
/* static */ bool nsScriptErrorBase::ComputeIsFromPrivateWindow(
nsGlobalWindowInner* aWindow) {
// Never mark exceptions from chrome windows as having come from private
// windows, since we always want them to be reported.
nsIPrincipal* winPrincipal = aWindow->GetPrincipal();
return aWindow->IsPrivateBrowsing() &&
!nsContentUtils::IsSystemPrincipal(winPrincipal);
}
NS_IMPL_ISUPPORTS(nsScriptError, nsIConsoleMessage, nsIScriptError)
nsScriptErrorNote::nsScriptErrorNote()

View File

@ -19,6 +19,8 @@
#include "nsIScriptError.h"
#include "nsString.h"
class nsGlobalWindowInner;
class nsScriptErrorNote final : public nsIScriptErrorNote {
public:
nsScriptErrorNote();
@ -49,6 +51,8 @@ class nsScriptErrorBase : public nsIScriptError {
void AddNote(nsIScriptErrorNote* note);
static bool ComputeIsFromPrivateWindow(nsGlobalWindowInner* aWindow);
protected:
virtual ~nsScriptErrorBase();

View File

@ -13,6 +13,7 @@
#include "mozilla/dom/UIEventBinding.h"
#include "mozilla/dom/WindowProxyHolder.h"
#include "nsDeviceContext.h"
#include "nsDocShell.h"
#include "nsLayoutUtils.h"
#include "nsPresContext.h"

View File

@ -45,6 +45,7 @@
#include "mozilla/dom/LSObject.h"
#include "mozilla/dom/MemoryReportRequest.h"
#include "mozilla/dom/PLoginReputationChild.h"
#include "mozilla/dom/PostMessageEvent.h"
#include "mozilla/dom/PushNotifier.h"
#include "mozilla/dom/RemoteWorkerService.h"
#include "mozilla/dom/ServiceWorkerManager.h"
@ -3483,6 +3484,95 @@ PContentChild::Result ContentChild::OnMessageReceived(const Message& aMsg,
return result;
}
mozilla::ipc::IPCResult ContentChild::RecvWindowClose(
const BrowsingContextId& aContextId, const bool& aTrustedCaller) {
RefPtr<BrowsingContext> bc = BrowsingContext::Get(aContextId);
if (!bc) {
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
("ChildIPC: Trying to send a message to dead or detached context "
"0x%08" PRIx64,
(uint64_t)aContextId));
return IPC_OK();
}
nsCOMPtr<nsPIDOMWindowOuter> window = bc->GetDOMWindow();
nsGlobalWindowOuter::Cast(window)->CloseOuter(aTrustedCaller);
return IPC_OK();
}
mozilla::ipc::IPCResult ContentChild::RecvWindowFocus(
const BrowsingContextId& aContextId) {
RefPtr<BrowsingContext> bc = BrowsingContext::Get(aContextId);
if (!bc) {
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
("ChildIPC: Trying to send a message to dead or detached context "
"0x%08" PRIx64,
(uint64_t)aContextId));
return IPC_OK();
}
nsCOMPtr<nsPIDOMWindowOuter> window = bc->GetDOMWindow();
nsGlobalWindowOuter::Cast(window)->FocusOuter();
return IPC_OK();
}
mozilla::ipc::IPCResult ContentChild::RecvWindowBlur(
const BrowsingContextId& aContextId) {
RefPtr<BrowsingContext> bc = BrowsingContext::Get(aContextId);
if (!bc) {
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
("ChildIPC: Trying to send a message to dead or detached context "
"0x%08" PRIx64,
(uint64_t)aContextId));
return IPC_OK();
}
nsCOMPtr<nsPIDOMWindowOuter> window = bc->GetDOMWindow();
nsGlobalWindowOuter::Cast(window)->BlurOuter();
return IPC_OK();
}
mozilla::ipc::IPCResult ContentChild::RecvWindowPostMessage(
const BrowsingContextId& aContextId, const ClonedMessageData& aMessage,
const PostMessageData& aData) {
RefPtr<BrowsingContext> bc = BrowsingContext::Get(aContextId);
if (!bc) {
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
("ChildIPC: Trying to send a message to dead or detached context "
"0x%08" PRIx64,
(uint64_t)aContextId));
return IPC_OK();
}
RefPtr<nsGlobalWindowOuter> window =
nsGlobalWindowOuter::Cast(bc->GetDOMWindow());
nsCOMPtr<nsIPrincipal> providedPrincipal;
if (!window->GetPrincipalForPostMessage(
aData.targetOrigin(), aData.targetOriginURI(),
aData.callerPrincipal(), *aData.subjectPrincipal(),
getter_AddRefs(providedPrincipal))) {
return IPC_OK();
}
RefPtr<BrowsingContext> sourceBc = BrowsingContext::Get(aData.source());
if (!sourceBc) {
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
("ChildIPC: Trying to use a dead or detached context 0x%08" PRIx64,
(uint64_t)aData.source()));
return IPC_OK();
}
// Create and asynchronously dispatch a runnable which will handle actual DOM
// event creation and dispatch.
RefPtr<PostMessageEvent> event = new PostMessageEvent(
sourceBc, aData.origin(), window, providedPrincipal,
aData.callerDocumentURI(), aData.isFromPrivateWindow());
event->UnpackFrom(aMessage);
window->Dispatch(TaskCategory::Other, event.forget());
return IPC_OK();
}
} // namespace dom
#if defined(__OpenBSD__) && defined(MOZ_CONTENT_SANDBOX)

View File

@ -726,6 +726,16 @@ class ContentChild final : public PContentChild,
virtual void OnChannelReceivedMessage(const Message& aMsg) override;
virtual mozilla::ipc::IPCResult RecvWindowClose(
const BrowsingContextId& aContextId, const bool& aTrustedCaller) override;
virtual mozilla::ipc::IPCResult RecvWindowFocus(
const BrowsingContextId& aContextId) override;
virtual mozilla::ipc::IPCResult RecvWindowBlur(
const BrowsingContextId& aContextId) override;
virtual mozilla::ipc::IPCResult RecvWindowPostMessage(
const BrowsingContextId& aContextId, const ClonedMessageData& aMessage,
const PostMessageData& aData) override;
#ifdef NIGHTLY_BUILD
virtual PContentChild::Result OnMessageReceived(const Message& aMsg) override;
#else

View File

@ -5127,19 +5127,6 @@ mozilla::ipc::IPCResult ContentParent::RecvA11yHandlerControl(
#endif
}
} // namespace dom
} // namespace mozilla
NS_IMPL_ISUPPORTS(ParentIdleListener, nsIObserver)
NS_IMETHODIMP
ParentIdleListener::Observe(nsISupports*, const char* aTopic,
const char16_t* aData) {
mozilla::Unused << mParent->SendNotifyIdleObserver(
mObserver, nsDependentCString(aTopic), nsDependentString(aData));
return NS_OK;
}
bool ContentParent::HandleWindowsMessages(const Message& aMsg) const {
MOZ_ASSERT(aMsg.is_sync());
@ -5777,3 +5764,100 @@ void ContentParent::UnregisterRemoveWorkerActor() {
&ContentParent::ShutDownProcess, SEND_SHUTDOWN_MESSAGE));
}
}
mozilla::ipc::IPCResult ContentParent::RecvWindowClose(
const BrowsingContextId& aContextId, const bool& aTrustedCaller) {
RefPtr<ChromeBrowsingContext> bc = ChromeBrowsingContext::Get(aContextId);
if (!bc) {
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
("ParentIPC: Trying to send a message to dead or detached context "
"0x%08" PRIx64,
(uint64_t)aContextId));
return IPC_OK();
}
// FIXME Need to check that the sending process has access to the unit of
// related
// browsing contexts of bc.
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
ContentParent* cp =
cpm->GetContentProcessById(ContentParentId(bc->OwnerProcessId()));
Unused << cp->SendWindowClose(aContextId, aTrustedCaller);
return IPC_OK();
}
mozilla::ipc::IPCResult ContentParent::RecvWindowFocus(
const BrowsingContextId& aContextId) {
RefPtr<ChromeBrowsingContext> bc = ChromeBrowsingContext::Get(aContextId);
if (!bc) {
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
("ParentIPC: Trying to send a message to dead or detached context "
"0x%08" PRIx64,
(uint64_t)aContextId));
return IPC_OK();
}
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
ContentParent* cp =
cpm->GetContentProcessById(ContentParentId(bc->OwnerProcessId()));
Unused << cp->SendWindowFocus(aContextId);
return IPC_OK();
}
mozilla::ipc::IPCResult ContentParent::RecvWindowBlur(
const BrowsingContextId& aContextId) {
RefPtr<ChromeBrowsingContext> bc = ChromeBrowsingContext::Get(aContextId);
if (!bc) {
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
("ParentIPC: Trying to send a message to dead or detached context "
"0x%08" PRIx64,
(uint64_t)aContextId));
return IPC_OK();
}
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
ContentParent* cp =
cpm->GetContentProcessById(ContentParentId(bc->OwnerProcessId()));
Unused << cp->SendWindowBlur(aContextId);
return IPC_OK();
}
mozilla::ipc::IPCResult ContentParent::RecvWindowPostMessage(
const BrowsingContextId& aContextId, const ClonedMessageData& aMessage,
const PostMessageData& aData) {
RefPtr<ChromeBrowsingContext> bc = ChromeBrowsingContext::Get(aContextId);
if (!bc) {
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
("ParentIPC: Trying to send a message to dead or detached context "
"0x%08" PRIx64,
(uint64_t)aContextId));
return IPC_OK();
}
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
ContentParent* cp =
cpm->GetContentProcessById(ContentParentId(bc->OwnerProcessId()));
StructuredCloneData messageFromChild;
UnpackClonedMessageDataForParent(aMessage, messageFromChild);
ClonedMessageData message;
if (!BuildClonedMessageDataForParent(cp, messageFromChild, message)) {
// FIXME Logging?
return IPC_OK();
}
Unused << cp->SendWindowPostMessage(aContextId, message, aData);
return IPC_OK();
}
} // namespace dom
} // namespace mozilla
NS_IMPL_ISUPPORTS(ParentIdleListener, nsIObserver)
NS_IMETHODIMP
ParentIdleListener::Observe(nsISupports*, const char* aTopic,
const char16_t* aData) {
mozilla::Unused << mParent->SendNotifyIdleObserver(
mObserver, nsDependentCString(aTopic), nsDependentString(aData));
return NS_OK;
}

View File

@ -637,6 +637,16 @@ class ContentParent final : public PContentParent,
const BrowsingContextId& aContextId,
const BrowsingContextId& aOpenerContextId) override;
virtual mozilla::ipc::IPCResult RecvWindowClose(
const BrowsingContextId& aContextId, const bool& aTrustedCaller) override;
virtual mozilla::ipc::IPCResult RecvWindowFocus(
const BrowsingContextId& aContextId) override;
virtual mozilla::ipc::IPCResult RecvWindowBlur(
const BrowsingContextId& aContextId) override;
virtual mozilla::ipc::IPCResult RecvWindowPostMessage(
const BrowsingContextId& aContextId, const ClonedMessageData& aMessage,
const PostMessageData& aData) override;
protected:
void OnChannelConnected(int32_t pid) override;

View File

@ -322,6 +322,18 @@ struct NotificationEventData
nsString behavior;
};
struct PostMessageData
{
BrowsingContextId source;
nsString origin;
nsString targetOrigin;
nsIURI targetOriginURI;
nsIPrincipal callerPrincipal;
nsIPrincipal subjectPrincipal;
nsIURI callerDocumentURI;
bool isFromPrivateWindow;
};
/**
* The PContent protocol is a top-level protocol between the UI process
* and a content process. There is exactly one PContentParent/PContentChild pair
@ -1257,6 +1269,13 @@ both:
*/
async NotifyPushSubscriptionModifiedObservers(nsCString scope,
Principal principal);
async WindowClose(BrowsingContextId aContextId,
bool aTrustedCaller);
async WindowFocus(BrowsingContextId aContextId);
async WindowBlur(BrowsingContextId aContextId);
async WindowPostMessage(BrowsingContextId aContextId, ClonedMessageData aMessage,
PostMessageData aData);
};
}

View File

@ -7,6 +7,7 @@
#ifndef mozilla_dom_TimeEvent_h_
#define mozilla_dom_TimeEvent_h_
#include "nsDocShell.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/TimeEventBinding.h"
#include "mozilla/dom/Nullable.h"

View File

@ -30,13 +30,13 @@ typedef OfflineResourceList ApplicationCache;
/*sealed*/ interface Window : EventTarget {
// the current browsing context
[Unforgeable, Constant, StoreInSlot,
CrossOriginReadable] readonly attribute Window window;
CrossOriginReadable] readonly attribute WindowProxy window;
[Replaceable, Constant, StoreInSlot,
CrossOriginReadable] readonly attribute Window self;
CrossOriginReadable] readonly attribute WindowProxy self;
[Unforgeable, StoreInSlot, Pure] readonly attribute Document? document;
[Throws] attribute DOMString name;
[PutForwards=href, Unforgeable, BinaryName="getLocation",
CrossOriginReadable, CrossOriginWritable] readonly attribute Location location;
[PutForwards=href, Unforgeable, CrossOriginReadable,
CrossOriginWritable] readonly attribute Location location;
[Throws] readonly attribute History history;
readonly attribute CustomElementRegistry customElements;
[Replaceable, Throws] readonly attribute BarProp locationbar;
@ -46,7 +46,7 @@ typedef OfflineResourceList ApplicationCache;
[Replaceable, Throws] readonly attribute BarProp statusbar;
[Replaceable, Throws] readonly attribute BarProp toolbar;
[Throws] attribute DOMString status;
[Throws, CrossOriginCallable] void close();
[Throws, CrossOriginCallable, NeedsCallerType] void close();
[Throws, CrossOriginReadable] readonly attribute boolean closed;
[Throws] void stop();
[Throws, CrossOriginCallable] void focus();

View File

@ -969,6 +969,7 @@ void XPCJSRuntime::CustomGCCallback(JSGCStatus status) {
}
void CompartmentPrivate::UpdateWeakPointersAfterGC() {
mRemoteProxies.sweep();
mWrappedJSMap->UpdateWeakPointersAfterGC();
}

View File

@ -2758,8 +2758,25 @@ class CompartmentPrivate {
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
struct SweepPolicy {
static bool needsSweep(const void* /* unused */,
JS::Heap<JSObject*>* value) {
return JS::GCPolicy<JS::Heap<JSObject*>>::needsSweep(value);
}
};
typedef JS::GCHashMap<const void*, JS::Heap<JSObject*>,
mozilla::PointerHasher<const void*>,
js::SystemAllocPolicy, SweepPolicy>
RemoteProxyMap;
RemoteProxyMap& GetRemoteProxyMap() { return mRemoteProxies; }
private:
JSObject2WrappedJSMap* mWrappedJSMap;
// Cache holding proxy objects for Window objects (and their Location oject)
// that are loaded in a different process.
RemoteProxyMap mRemoteProxies;
};
bool IsUniversalXPConnectEnabled(JS::Compartment* compartment);

View File

@ -423,13 +423,12 @@ nsresult PeerConnectionImpl::Initialize(PeerConnectionObserver& aObserver,
nsAutoCString locationCStr;
if (RefPtr<Location> location = mWindow->GetLocation()) {
RefPtr<Location> location = mWindow->Location();
nsAutoString locationAStr;
res = location->ToString(locationAStr);
NS_ENSURE_SUCCESS(res, res);
CopyUTF16toUTF8(locationAStr, locationCStr);
}
SprintfLiteral(temp, "%" PRIu64 " (id=%" PRIu64 " url=%s)",
static_cast<uint64_t>(timestamp),

View File

@ -33,6 +33,7 @@
#include "nsWindowWatcher.h"
#include "mozilla/BrowserElementParent.h"
#include "mozilla/NullPrincipal.h"
#include "nsDocShell.h"
#include "nsDocShellLoadState.h"
#include "nsIScriptObjectPrincipal.h"