mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
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:
parent
43adb531b7
commit
066d891adb
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -103,6 +103,7 @@ FINAL_LIBRARY = 'xul'
|
||||
LOCAL_INCLUDES += [
|
||||
'/docshell/shistory',
|
||||
'/dom/base',
|
||||
'/dom/bindings',
|
||||
'/layout/base',
|
||||
'/layout/generic',
|
||||
'/layout/style',
|
||||
|
@ -2309,7 +2309,7 @@ nsDocShell::NotifyScrollObservers() {
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::GetName(nsAString& aName) {
|
||||
mBrowsingContext->GetName(aName);
|
||||
aName = mBrowsingContext->Name();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
194
dom/base/RemoteOuterWindowProxy.cpp
Normal file
194
dom/base/RemoteOuterWindowProxy.cpp
Normal 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
|
@ -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
|
||||
|
||||
|
@ -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',
|
||||
|
@ -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 {
|
||||
|
@ -299,19 +299,28 @@ using mozilla::dom::cache::CacheStorage;
|
||||
return outer->method args; \
|
||||
PR_END_MACRO
|
||||
|
||||
#define FORWARD_TO_OUTER_OR_THROW(method, args, errorresult, err_rval) \
|
||||
PR_BEGIN_MACRO \
|
||||
nsGlobalWindowOuter* outer = GetOuterWindowInternal(); \
|
||||
if (MOZ_LIKELY(HasActiveDocument())) { \
|
||||
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; \
|
||||
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 = GetOuterWindowForForwarding(this, errorresult); \
|
||||
if (MOZ_LIKELY(outer)) { \
|
||||
return outer->method args; \
|
||||
} \
|
||||
return err_rval; \
|
||||
PR_END_MACRO
|
||||
|
||||
#define FORWARD_TO_OUTER_VOID(method, args) \
|
||||
@ -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());
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
getter=getter,
|
||||
setter=setter)
|
||||
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"]
|
||||
|
240
dom/bindings/RemoteObjectProxy.cpp
Normal file
240
dom/bindings/RemoteObjectProxy.cpp
Normal 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
|
200
dom/bindings/RemoteObjectProxy.h
Normal file
200
dom/bindings/RemoteObjectProxy.h
Normal 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 */
|
@ -68,15 +68,24 @@ bool ToJSValue(JSContext* aCx, const WindowProxyHolder& aArgument,
|
||||
aValue.setNull();
|
||||
return true;
|
||||
}
|
||||
JS::Rooted<JSObject*> windowProxy(aCx, bc->GetWindowProxy());
|
||||
if (!windowProxy) {
|
||||
nsPIDOMWindowOuter* window = bc->GetDOMWindow();
|
||||
if (!window->EnsureInnerWindow()) {
|
||||
return Throw(aCx, NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
JS::Rooted<JSObject*> windowProxy(aCx);
|
||||
if (bc->GetDocShell()) {
|
||||
windowProxy = bc->GetWindowProxy();
|
||||
if (!windowProxy) {
|
||||
nsPIDOMWindowOuter* window = bc->GetDOMWindow();
|
||||
if (!window->EnsureInnerWindow()) {
|
||||
return Throw(aCx, NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
windowProxy = bc->GetWindowProxy();
|
||||
}
|
||||
return ToJSValue(aCx, windowProxy, aValue);
|
||||
}
|
||||
return ToJSValue(aCx, windowProxy, aValue);
|
||||
|
||||
if (!GetRemoteOuterWindowProxy(aCx, bc, &windowProxy)) {
|
||||
return false;
|
||||
}
|
||||
aValue.setObjectOrNull(windowProxy);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
@ -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',
|
||||
|
@ -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()
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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();
|
||||
|
@ -969,6 +969,7 @@ void XPCJSRuntime::CustomGCCallback(JSGCStatus status) {
|
||||
}
|
||||
|
||||
void CompartmentPrivate::UpdateWeakPointersAfterGC() {
|
||||
mRemoteProxies.sweep();
|
||||
mWrappedJSMap->UpdateWeakPointersAfterGC();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -423,13 +423,12 @@ nsresult PeerConnectionImpl::Initialize(PeerConnectionObserver& aObserver,
|
||||
|
||||
nsAutoCString locationCStr;
|
||||
|
||||
if (RefPtr<Location> location = mWindow->GetLocation()) {
|
||||
nsAutoString locationAStr;
|
||||
res = location->ToString(locationAStr);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
RefPtr<Location> location = mWindow->Location();
|
||||
nsAutoString locationAStr;
|
||||
res = location->ToString(locationAStr);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
CopyUTF16toUTF8(locationAStr, locationCStr);
|
||||
}
|
||||
CopyUTF16toUTF8(locationAStr, locationCStr);
|
||||
|
||||
SprintfLiteral(temp, "%" PRIu64 " (id=%" PRIu64 " url=%s)",
|
||||
static_cast<uint64_t>(timestamp),
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "nsWindowWatcher.h"
|
||||
#include "mozilla/BrowserElementParent.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "nsDocShell.h"
|
||||
#include "nsDocShellLoadState.h"
|
||||
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
|
Loading…
Reference in New Issue
Block a user