2018-07-26 10:31:00 +03:00
|
|
|
/* -*- 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/. */
|
|
|
|
|
2018-10-20 01:00:59 +03:00
|
|
|
#include "mozilla/dom/BrowsingContext.h"
|
2018-07-26 10:31:00 +03:00
|
|
|
|
2019-02-21 23:14:28 +03:00
|
|
|
#include "ipc/IPCMessageUtils.h"
|
|
|
|
|
2019-01-29 20:32:28 +03:00
|
|
|
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
2019-01-30 19:07:21 +03:00
|
|
|
#include "mozilla/dom/BrowsingContextGroup.h"
|
2018-08-29 05:00:00 +03:00
|
|
|
#include "mozilla/dom/BrowsingContextBinding.h"
|
2018-07-26 10:31:00 +03:00
|
|
|
#include "mozilla/dom/ContentChild.h"
|
2018-11-05 15:43:10 +03:00
|
|
|
#include "mozilla/dom/ContentParent.h"
|
2019-12-01 00:13:54 +03:00
|
|
|
#include "mozilla/dom/Document.h"
|
2019-04-17 03:51:36 +03:00
|
|
|
#include "mozilla/dom/Element.h"
|
2020-01-24 22:03:10 +03:00
|
|
|
#include "mozilla/dom/HTMLIFrameElement.h"
|
2019-01-02 16:29:18 +03:00
|
|
|
#include "mozilla/dom/Location.h"
|
|
|
|
#include "mozilla/dom/LocationBinding.h"
|
2019-10-18 06:04:55 +03:00
|
|
|
#include "mozilla/dom/PopupBlocker.h"
|
2019-10-24 17:53:07 +03:00
|
|
|
#include "mozilla/dom/ScriptSettings.h"
|
2019-12-10 15:12:25 +03:00
|
|
|
#include "mozilla/dom/SessionStorageManager.h"
|
2019-07-02 01:24:09 +03:00
|
|
|
#include "mozilla/dom/StructuredCloneTags.h"
|
2019-09-20 14:10:13 +03:00
|
|
|
#include "mozilla/dom/UserActivationIPCUtils.h"
|
2019-01-02 16:29:18 +03:00
|
|
|
#include "mozilla/dom/WindowBinding.h"
|
2019-04-17 03:51:36 +03:00
|
|
|
#include "mozilla/dom/WindowGlobalChild.h"
|
|
|
|
#include "mozilla/dom/WindowGlobalParent.h"
|
2019-01-03 10:11:00 +03:00
|
|
|
#include "mozilla/dom/WindowProxyHolder.h"
|
2020-01-20 17:57:47 +03:00
|
|
|
#include "mozilla/dom/SyncedContextInlines.h"
|
2018-07-26 10:31:00 +03:00
|
|
|
#include "mozilla/Assertions.h"
|
|
|
|
#include "mozilla/ClearOnShutdown.h"
|
2019-10-11 05:27:14 +03:00
|
|
|
#include "mozilla/Components.h"
|
2018-12-17 13:45:37 +03:00
|
|
|
#include "mozilla/HashTable.h"
|
2018-07-26 10:31:00 +03:00
|
|
|
#include "mozilla/Logging.h"
|
2019-10-29 20:15:29 +03:00
|
|
|
#include "mozilla/Services.h"
|
2019-12-01 00:13:24 +03:00
|
|
|
#include "mozilla/StaticPrefs_page_load.h"
|
2018-07-26 10:31:00 +03:00
|
|
|
#include "mozilla/StaticPtr.h"
|
2019-10-11 05:27:14 +03:00
|
|
|
#include "nsIURIFixup.h"
|
2018-07-26 10:31:00 +03:00
|
|
|
|
2018-11-05 15:43:10 +03:00
|
|
|
#include "nsDocShell.h"
|
2019-11-13 00:52:18 +03:00
|
|
|
#include "nsFocusManager.h"
|
2019-01-02 16:29:18 +03:00
|
|
|
#include "nsGlobalWindowOuter.h"
|
2019-10-29 20:15:29 +03:00
|
|
|
#include "nsIObserverService.h"
|
2018-07-26 10:31:00 +03:00
|
|
|
#include "nsContentUtils.h"
|
2019-01-02 16:29:18 +03:00
|
|
|
#include "nsScriptError.h"
|
2018-06-29 02:41:00 +03:00
|
|
|
#include "nsThreadUtils.h"
|
2019-02-28 21:23:15 +03:00
|
|
|
#include "xpcprivate.h"
|
2018-07-26 10:31:00 +03:00
|
|
|
|
2019-03-20 06:15:36 +03:00
|
|
|
#include "AutoplayPolicy.h"
|
2019-11-25 14:00:13 +03:00
|
|
|
#include "GVAutoplayRequestStatusIPC.h"
|
2019-03-20 06:15:36 +03:00
|
|
|
|
|
|
|
extern mozilla::LazyLogModule gAutoplayPermissionLog;
|
2019-12-13 20:09:33 +03:00
|
|
|
extern mozilla::LazyLogModule gTimeoutDeferralLog;
|
2019-03-20 06:15:36 +03:00
|
|
|
|
|
|
|
#define AUTOPLAY_LOG(msg, ...) \
|
|
|
|
MOZ_LOG(gAutoplayPermissionLog, LogLevel::Debug, (msg, ##__VA_ARGS__))
|
|
|
|
|
2019-12-04 03:44:27 +03:00
|
|
|
namespace IPC {
|
|
|
|
// Allow serialization and deserialization of OrientationType over IPC
|
|
|
|
template <>
|
|
|
|
struct ParamTraits<mozilla::dom::OrientationType>
|
|
|
|
: public ContiguousEnumSerializerInclusive<
|
|
|
|
mozilla::dom::OrientationType,
|
|
|
|
mozilla::dom::OrientationType::Portrait_primary,
|
|
|
|
mozilla::dom::OrientationType::Landscape_secondary> {};
|
|
|
|
|
|
|
|
} // namespace IPC
|
|
|
|
|
2018-07-26 10:31:00 +03:00
|
|
|
namespace mozilla {
|
|
|
|
namespace dom {
|
|
|
|
|
2020-01-20 17:57:47 +03:00
|
|
|
// Explicit specialization of the `Transaction` type. Required by the `extern
|
|
|
|
// template class` declaration in the header.
|
|
|
|
template class syncedcontext::Transaction<BrowsingContext>;
|
|
|
|
|
2019-01-15 02:09:42 +03:00
|
|
|
extern mozilla::LazyLogModule gUserInteractionPRLog;
|
|
|
|
|
|
|
|
#define USER_ACTIVATION_LOG(msg, ...) \
|
|
|
|
MOZ_LOG(gUserInteractionPRLog, LogLevel::Debug, (msg, ##__VA_ARGS__))
|
|
|
|
|
2018-07-26 10:31:00 +03:00
|
|
|
static LazyLogModule gBrowsingContextLog("BrowsingContext");
|
|
|
|
|
2019-05-24 23:15:53 +03:00
|
|
|
typedef nsDataHashtable<nsUint64HashKey, BrowsingContext*> BrowsingContextMap;
|
2018-12-17 13:45:37 +03:00
|
|
|
|
2019-05-24 23:15:53 +03:00
|
|
|
static StaticAutoPtr<BrowsingContextMap> sBrowsingContexts;
|
2018-07-26 10:31:00 +03:00
|
|
|
|
2018-11-05 15:43:10 +03:00
|
|
|
static void Register(BrowsingContext* aBrowsingContext) {
|
2019-05-24 23:15:53 +03:00
|
|
|
sBrowsingContexts->Put(aBrowsingContext->Id(), aBrowsingContext);
|
2019-01-30 19:07:21 +03:00
|
|
|
|
|
|
|
aBrowsingContext->Group()->Register(aBrowsingContext);
|
2018-11-05 15:43:10 +03:00
|
|
|
}
|
|
|
|
|
2019-04-09 09:19:24 +03:00
|
|
|
BrowsingContext* BrowsingContext::Top() {
|
2019-01-15 02:09:42 +03:00
|
|
|
BrowsingContext* bc = this;
|
|
|
|
while (bc->mParent) {
|
|
|
|
bc = bc->mParent;
|
|
|
|
}
|
|
|
|
return bc;
|
|
|
|
}
|
|
|
|
|
2019-02-26 01:04:59 +03:00
|
|
|
/* static */
|
|
|
|
void BrowsingContext::Init() {
|
2018-07-26 10:31:00 +03:00
|
|
|
if (!sBrowsingContexts) {
|
2019-05-24 23:15:53 +03:00
|
|
|
sBrowsingContexts = new BrowsingContextMap();
|
2018-07-26 10:31:00 +03:00
|
|
|
ClearOnShutdown(&sBrowsingContexts);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-26 01:04:59 +03:00
|
|
|
/* static */
|
|
|
|
LogModule* BrowsingContext::GetLog() { return gBrowsingContextLog; }
|
2018-07-26 10:31:00 +03:00
|
|
|
|
2019-02-26 01:04:59 +03:00
|
|
|
/* static */
|
|
|
|
already_AddRefed<BrowsingContext> BrowsingContext::Get(uint64_t aId) {
|
2019-05-24 23:15:53 +03:00
|
|
|
return do_AddRef(sBrowsingContexts->Get(aId));
|
2018-07-26 10:31:00 +03:00
|
|
|
}
|
|
|
|
|
2019-06-19 23:06:32 +03:00
|
|
|
/* static */
|
|
|
|
already_AddRefed<BrowsingContext> BrowsingContext::GetFromWindow(
|
|
|
|
WindowProxyHolder& aProxy) {
|
|
|
|
return do_AddRef(aProxy.get());
|
|
|
|
}
|
|
|
|
|
2019-02-14 00:02:55 +03:00
|
|
|
CanonicalBrowsingContext* BrowsingContext::Canonical() {
|
|
|
|
return CanonicalBrowsingContext::Cast(this);
|
|
|
|
}
|
|
|
|
|
2019-02-26 01:04:59 +03:00
|
|
|
/* static */
|
|
|
|
already_AddRefed<BrowsingContext> BrowsingContext::Create(
|
2018-11-05 15:43:10 +03:00
|
|
|
BrowsingContext* aParent, BrowsingContext* aOpener, const nsAString& aName,
|
|
|
|
Type aType) {
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!aParent || aParent->mType == aType);
|
|
|
|
|
2019-09-20 07:43:46 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(aType != Type::Chrome || XRE_IsParentProcess());
|
|
|
|
|
2018-11-05 15:43:10 +03:00
|
|
|
uint64_t id = nsContentUtils::GenerateBrowsingContextId();
|
|
|
|
|
|
|
|
MOZ_LOG(GetLog(), LogLevel::Debug,
|
|
|
|
("Creating 0x%08" PRIx64 " in %s", id,
|
|
|
|
XRE_IsParentProcess() ? "Parent" : "Child"));
|
|
|
|
|
2019-03-14 21:51:09 +03:00
|
|
|
// Determine which BrowsingContextGroup this context should be created in.
|
|
|
|
RefPtr<BrowsingContextGroup> group =
|
2019-10-24 17:53:07 +03:00
|
|
|
(aType == Type::Chrome)
|
|
|
|
? do_AddRef(BrowsingContextGroup::GetChromeGroup())
|
|
|
|
: BrowsingContextGroup::Select(aParent, aOpener);
|
2019-03-14 21:51:09 +03:00
|
|
|
|
2018-09-14 17:57:18 +03:00
|
|
|
RefPtr<BrowsingContext> context;
|
|
|
|
if (XRE_IsParentProcess()) {
|
2019-03-14 21:51:09 +03:00
|
|
|
context = new CanonicalBrowsingContext(aParent, group, id,
|
2020-01-20 17:57:47 +03:00
|
|
|
/* aProcessId */ 0, aType, {});
|
2018-09-14 17:57:18 +03:00
|
|
|
} else {
|
2020-01-20 17:57:47 +03:00
|
|
|
context = new BrowsingContext(aParent, group, id, aType, {});
|
2019-03-14 21:51:09 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// The name and opener fields need to be explicitly initialized. Don't bother
|
|
|
|
// using transactions to set them, as we haven't been attached yet.
|
2020-01-20 17:57:47 +03:00
|
|
|
context->mFields.SetWithoutSyncing<IDX_Name>(aName);
|
2019-08-28 21:07:31 +03:00
|
|
|
if (aOpener) {
|
2019-09-20 07:43:39 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(aOpener->Group() == context->Group());
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(aOpener->mType == context->mType);
|
2020-01-20 17:57:47 +03:00
|
|
|
context->mFields.SetWithoutSyncing<IDX_OpenerId>(aOpener->Id());
|
|
|
|
context->mFields.SetWithoutSyncing<IDX_HadOriginalOpener>(true);
|
2019-08-28 21:07:31 +03:00
|
|
|
}
|
2020-01-20 17:57:47 +03:00
|
|
|
context->mFields.SetWithoutSyncing<IDX_EmbedderPolicy>(
|
|
|
|
nsILoadInfo::EMBEDDER_POLICY_NULL);
|
2019-03-14 21:51:09 +03:00
|
|
|
|
2019-04-09 23:10:13 +03:00
|
|
|
BrowsingContext* inherit = aParent ? aParent : aOpener;
|
|
|
|
if (inherit) {
|
2020-01-20 17:57:47 +03:00
|
|
|
context->mFields.SetWithoutSyncing<IDX_OpenerPolicy>(
|
|
|
|
inherit->Top()->GetOpenerPolicy());
|
2019-08-08 21:56:30 +03:00
|
|
|
// CORPP 3.1.3 https://mikewest.github.io/corpp/#integration-html
|
2020-01-20 17:57:47 +03:00
|
|
|
context->mFields.SetWithoutSyncing<IDX_EmbedderPolicy>(
|
|
|
|
inherit->GetEmbedderPolicy());
|
2019-12-13 20:09:33 +03:00
|
|
|
// if our parent has a parent that's loading, we need it too
|
2020-01-20 17:57:47 +03:00
|
|
|
bool ancestorLoading = aParent ? aParent->GetAncestorLoading() : false;
|
|
|
|
if (!ancestorLoading && aParent) {
|
2020-01-23 21:14:42 +03:00
|
|
|
// XXX(farre): Can/Should we check aParent->IsLoading() here? (Bug
|
|
|
|
// 1608448) Check if the parent was itself loading already
|
2019-12-13 20:09:33 +03:00
|
|
|
nsPIDOMWindowOuter* outer = aParent->GetDOMWindow();
|
|
|
|
if (outer) {
|
|
|
|
Document* document = nsGlobalWindowOuter::Cast(outer)->GetDocument();
|
|
|
|
auto readystate = document->GetReadyStateEnum();
|
|
|
|
if (readystate == Document::ReadyState::READYSTATE_LOADING ||
|
|
|
|
readystate == Document::ReadyState::READYSTATE_INTERACTIVE) {
|
2020-01-20 17:57:47 +03:00
|
|
|
ancestorLoading = true;
|
2019-12-13 20:09:33 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-01-20 17:57:47 +03:00
|
|
|
context->mFields.SetWithoutSyncing<IDX_AncestorLoading>(ancestorLoading);
|
2018-09-14 17:57:18 +03:00
|
|
|
}
|
|
|
|
|
2020-01-20 17:57:47 +03:00
|
|
|
nsContentUtils::GenerateUUIDInPlace(
|
|
|
|
context->mFields.GetNonSyncingReference<IDX_HistoryID>());
|
|
|
|
|
|
|
|
context->mFields.SetWithoutSyncing<IDX_IsActive>(true);
|
2019-03-05 12:33:42 +03:00
|
|
|
|
2018-11-05 15:43:10 +03:00
|
|
|
Register(context);
|
|
|
|
|
|
|
|
// Attach the browsing context to the tree.
|
|
|
|
context->Attach();
|
|
|
|
|
2018-09-14 17:57:18 +03:00
|
|
|
return context.forget();
|
|
|
|
}
|
|
|
|
|
2019-02-26 01:04:59 +03:00
|
|
|
/* static */
|
|
|
|
already_AddRefed<BrowsingContext> BrowsingContext::CreateFromIPC(
|
2019-03-14 21:51:09 +03:00
|
|
|
BrowsingContext::IPCInitializer&& aInit, BrowsingContextGroup* aGroup,
|
|
|
|
ContentParent* aOriginProcess) {
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(aOriginProcess || XRE_IsContentProcess());
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(aGroup);
|
|
|
|
|
2019-05-02 11:50:12 +03:00
|
|
|
uint64_t originId = 0;
|
|
|
|
if (aOriginProcess) {
|
|
|
|
originId = aOriginProcess->ChildID();
|
|
|
|
aGroup->EnsureSubscribed(aOriginProcess);
|
|
|
|
}
|
2018-11-05 15:43:10 +03:00
|
|
|
|
|
|
|
MOZ_LOG(GetLog(), LogLevel::Debug,
|
2019-03-14 21:51:09 +03:00
|
|
|
("Creating 0x%08" PRIx64 " from IPC (origin=0x%08" PRIx64 ")",
|
|
|
|
aInit.mId, originId));
|
|
|
|
|
|
|
|
RefPtr<BrowsingContext> parent = aInit.GetParent();
|
2018-11-05 15:43:10 +03:00
|
|
|
|
|
|
|
RefPtr<BrowsingContext> context;
|
|
|
|
if (XRE_IsParentProcess()) {
|
2020-01-20 17:57:47 +03:00
|
|
|
context =
|
|
|
|
new CanonicalBrowsingContext(parent, aGroup, aInit.mId, originId,
|
|
|
|
Type::Content, std::move(aInit.mFields));
|
2018-11-05 15:43:10 +03:00
|
|
|
} else {
|
2020-01-20 17:57:47 +03:00
|
|
|
context = new BrowsingContext(parent, aGroup, aInit.mId, Type::Content,
|
|
|
|
std::move(aInit.mFields));
|
2018-11-05 15:43:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
Register(context);
|
|
|
|
|
2019-03-14 21:50:38 +03:00
|
|
|
// Caller handles attaching us to the tree.
|
2018-11-05 15:43:10 +03:00
|
|
|
|
|
|
|
return context.forget();
|
2018-07-26 10:31:00 +03:00
|
|
|
}
|
|
|
|
|
2018-11-05 15:43:10 +03:00
|
|
|
BrowsingContext::BrowsingContext(BrowsingContext* aParent,
|
2019-03-14 21:51:09 +03:00
|
|
|
BrowsingContextGroup* aGroup,
|
2020-01-20 17:57:47 +03:00
|
|
|
uint64_t aBrowsingContextId, Type aType,
|
|
|
|
FieldTuple&& aFields)
|
|
|
|
: mFields(std::move(aFields)),
|
|
|
|
mType(aType),
|
2018-11-05 15:43:10 +03:00
|
|
|
mBrowsingContextId(aBrowsingContextId),
|
2019-03-14 21:51:09 +03:00
|
|
|
mGroup(aGroup),
|
2019-03-06 00:11:48 +03:00
|
|
|
mParent(aParent),
|
2019-07-02 23:48:13 +03:00
|
|
|
mIsInProcess(false),
|
Bug 1559489, part 4 - Remote-to-local window transplanting. r=tcampbell,bzbarsky
This patch cleans up remote outer window proxies when we navigate back
into the process.
It adds a flag to mDanglingRemoteOuterProxies that is set in between
BrowsingContext::SetDocShell(), where we can tell that the browsing
context is going from being remote to being local, to
nsGlobalWindowOuter::SetNewDocument(), where the local outer window
proxy is actually created. Once the outer window is created, the
remote window proxies can be cleaned up in
CleanUpDanglingRemoteOuterWindowProxies().
The clean up is done by a process that is similar to object
transplanting, except that instead of looking in the cross-compartment
wrapper table for each compartment to find objects to be turned into
CCWs to the new object, it looks in the remote proxy map for each
compartment. SpiderMonkey doesn't know about the proxy maps, so this
has to be done by a new callback object CompartmentTransplantCallback.
Now that this cleanup is being done, it shouldn't be possible to wrap
a remote outer window proxy when the browsing context is local, so
MaybeWrapWindowProxy() can be simplified. I had to drop the assert
here that the browsing context has a window proxy because during clean
up we call wrap on a local outer window proxy before the BC gets the
window proxy set on it. I had the assert because my original plan was
to implicitly fix remote proxies during wrapping, but that is no
longer necessary.
Differential Revision: https://phabricator.services.mozilla.com/D38343
--HG--
extra : moz-landing-system : lando
2019-08-13 22:09:59 +03:00
|
|
|
mIsDiscarded(false),
|
2019-12-20 01:05:19 +03:00
|
|
|
mDanglingRemoteOuterProxies(false),
|
|
|
|
mPendingInitialization(false) {
|
2019-03-14 21:51:09 +03:00
|
|
|
MOZ_RELEASE_ASSERT(!mParent || mParent->Group() == mGroup);
|
|
|
|
MOZ_RELEASE_ASSERT(mBrowsingContextId != 0);
|
|
|
|
MOZ_RELEASE_ASSERT(mGroup);
|
2018-12-17 13:45:37 +03:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-11-05 15:43:10 +03:00
|
|
|
void BrowsingContext::SetDocShell(nsIDocShell* aDocShell) {
|
|
|
|
// XXX(nika): We should communicate that we are now an active BrowsingContext
|
|
|
|
// process to the parent & do other validation here.
|
2019-08-07 19:59:30 +03:00
|
|
|
MOZ_RELEASE_ASSERT(aDocShell->GetBrowsingContext() == this);
|
2018-11-05 15:43:10 +03:00
|
|
|
mDocShell = aDocShell;
|
Bug 1559489, part 4 - Remote-to-local window transplanting. r=tcampbell,bzbarsky
This patch cleans up remote outer window proxies when we navigate back
into the process.
It adds a flag to mDanglingRemoteOuterProxies that is set in between
BrowsingContext::SetDocShell(), where we can tell that the browsing
context is going from being remote to being local, to
nsGlobalWindowOuter::SetNewDocument(), where the local outer window
proxy is actually created. Once the outer window is created, the
remote window proxies can be cleaned up in
CleanUpDanglingRemoteOuterWindowProxies().
The clean up is done by a process that is similar to object
transplanting, except that instead of looking in the cross-compartment
wrapper table for each compartment to find objects to be turned into
CCWs to the new object, it looks in the remote proxy map for each
compartment. SpiderMonkey doesn't know about the proxy maps, so this
has to be done by a new callback object CompartmentTransplantCallback.
Now that this cleanup is being done, it shouldn't be possible to wrap
a remote outer window proxy when the browsing context is local, so
MaybeWrapWindowProxy() can be simplified. I had to drop the assert
here that the browsing context has a window proxy because during clean
up we call wrap on a local outer window proxy before the BC gets the
window proxy set on it. I had the assert because my original plan was
to implicitly fix remote proxies during wrapping, but that is no
longer necessary.
Differential Revision: https://phabricator.services.mozilla.com/D38343
--HG--
extra : moz-landing-system : lando
2019-08-13 22:09:59 +03:00
|
|
|
mDanglingRemoteOuterProxies = !mIsInProcess;
|
Bug 1529684 - Part 6: Store a mIsInProcess flag to preserve WindowProxy behaviour, r=farre
Currently when we have an in-process WindowProxy object, we will attempt
to either use the cached mWindowProxy value, or fetch the
nsGlobalWindowOuter object from through the nsDocShell. Unfortunately,
when the BrowsingContext is detached, we will fail to get the
nsGlobalWindowOuter object. This happens to be OK for our test cases, as
the cached mWindowProxy value doesn't have the chance to go away, but
isn't acceptable long-term.
These patches exascerbated that issue by causing the nsDocShell pointer
itself to be cleared when it is destroyed, which caused the Remote
WindowProxy logic to be triggered. To deal with that case, this patch
adds a new mIsInProcess flag to continue to act like the old code-path.
In the future, we will need to also handle ensuring that the
nsGlobalWindowOuter lives for long enough, however that is not being
done in this patch in order to land it sooner rather than later.
Depends on D22763
Differential Revision: https://phabricator.services.mozilla.com/D22764
--HG--
extra : moz-landing-system : lando
2019-03-14 21:50:54 +03:00
|
|
|
mIsInProcess = true;
|
2018-11-05 15:43:10 +03:00
|
|
|
}
|
|
|
|
|
Bug 1559489, part 4 - Remote-to-local window transplanting. r=tcampbell,bzbarsky
This patch cleans up remote outer window proxies when we navigate back
into the process.
It adds a flag to mDanglingRemoteOuterProxies that is set in between
BrowsingContext::SetDocShell(), where we can tell that the browsing
context is going from being remote to being local, to
nsGlobalWindowOuter::SetNewDocument(), where the local outer window
proxy is actually created. Once the outer window is created, the
remote window proxies can be cleaned up in
CleanUpDanglingRemoteOuterWindowProxies().
The clean up is done by a process that is similar to object
transplanting, except that instead of looking in the cross-compartment
wrapper table for each compartment to find objects to be turned into
CCWs to the new object, it looks in the remote proxy map for each
compartment. SpiderMonkey doesn't know about the proxy maps, so this
has to be done by a new callback object CompartmentTransplantCallback.
Now that this cleanup is being done, it shouldn't be possible to wrap
a remote outer window proxy when the browsing context is local, so
MaybeWrapWindowProxy() can be simplified. I had to drop the assert
here that the browsing context has a window proxy because during clean
up we call wrap on a local outer window proxy before the BC gets the
window proxy set on it. I had the assert because my original plan was
to implicitly fix remote proxies during wrapping, but that is no
longer necessary.
Differential Revision: https://phabricator.services.mozilla.com/D38343
--HG--
extra : moz-landing-system : lando
2019-08-13 22:09:59 +03:00
|
|
|
// This class implements a callback that will return the remote window proxy for
|
|
|
|
// mBrowsingContext in that compartment, if it has one. It also removes the
|
|
|
|
// proxy from the map, because the object will be transplanted into another kind
|
|
|
|
// of object.
|
|
|
|
class MOZ_STACK_CLASS CompartmentRemoteProxyTransplantCallback
|
|
|
|
: public js::CompartmentTransplantCallback {
|
|
|
|
public:
|
|
|
|
explicit CompartmentRemoteProxyTransplantCallback(
|
|
|
|
BrowsingContext* aBrowsingContext)
|
|
|
|
: mBrowsingContext(aBrowsingContext) {}
|
|
|
|
|
|
|
|
virtual JSObject* getObjectToTransplant(
|
|
|
|
JS::Compartment* compartment) override {
|
|
|
|
auto* priv = xpc::CompartmentPrivate::Get(compartment);
|
|
|
|
if (!priv) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto& map = priv->GetRemoteProxyMap();
|
|
|
|
auto result = map.lookup(mBrowsingContext);
|
|
|
|
if (!result) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
JSObject* resultObject = result->value();
|
|
|
|
map.remove(result);
|
|
|
|
|
|
|
|
return resultObject;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
BrowsingContext* mBrowsingContext;
|
|
|
|
};
|
|
|
|
|
|
|
|
void BrowsingContext::CleanUpDanglingRemoteOuterWindowProxies(
|
|
|
|
JSContext* aCx, JS::MutableHandle<JSObject*> aOuter) {
|
|
|
|
if (!mDanglingRemoteOuterProxies) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mDanglingRemoteOuterProxies = false;
|
|
|
|
|
|
|
|
CompartmentRemoteProxyTransplantCallback cb(this);
|
|
|
|
js::RemapRemoteWindowProxies(aCx, &cb, aOuter);
|
|
|
|
}
|
|
|
|
|
2019-04-17 03:51:36 +03:00
|
|
|
void BrowsingContext::SetEmbedderElement(Element* aEmbedder) {
|
|
|
|
// Notify the parent process of the embedding status. We don't need to do
|
|
|
|
// this when clearing our embedder, as we're being destroyed either way.
|
2019-04-17 03:53:24 +03:00
|
|
|
if (aEmbedder) {
|
2019-10-01 11:48:25 +03:00
|
|
|
if (nsCOMPtr<nsPIDOMWindowInner> inner =
|
|
|
|
do_QueryInterface(aEmbedder->GetOwnerGlobal())) {
|
|
|
|
SetEmbedderInnerWindowId(inner->WindowID());
|
|
|
|
}
|
2019-04-17 03:51:36 +03:00
|
|
|
}
|
2019-04-17 03:53:24 +03:00
|
|
|
|
|
|
|
mEmbedderElement = aEmbedder;
|
2019-04-17 03:51:36 +03:00
|
|
|
}
|
|
|
|
|
2020-01-24 22:03:10 +03:00
|
|
|
void BrowsingContext::Embed() {
|
|
|
|
if (auto* frame = HTMLIFrameElement::FromNode(mEmbedderElement)) {
|
|
|
|
frame->BindToBrowsingContext(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-14 21:50:38 +03:00
|
|
|
void BrowsingContext::Attach(bool aFromIPC) {
|
2018-07-26 10:31:00 +03:00
|
|
|
MOZ_LOG(GetLog(), LogLevel::Debug,
|
2019-04-29 14:38:45 +03:00
|
|
|
("%s: Connecting 0x%08" PRIx64 " to 0x%08" PRIx64,
|
|
|
|
XRE_IsParentProcess() ? "Parent" : "Child", Id(),
|
|
|
|
mParent ? mParent->Id() : 0));
|
2018-12-17 13:45:37 +03:00
|
|
|
|
2019-07-02 23:48:13 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(mGroup);
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!mGroup->IsContextCached(this));
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!mIsDiscarded);
|
2018-07-26 10:31:00 +03:00
|
|
|
|
2019-01-30 19:07:21 +03:00
|
|
|
auto* children = mParent ? &mParent->mChildren : &mGroup->Toplevels();
|
2018-12-17 13:45:37 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!children->Contains(this));
|
|
|
|
|
|
|
|
children->AppendElement(this);
|
2018-07-26 10:31:00 +03:00
|
|
|
|
2020-01-20 17:57:47 +03:00
|
|
|
if (GetIsPopupSpam()) {
|
2019-10-18 06:04:55 +03:00
|
|
|
PopupBlocker::RegisterOpenPopupSpam();
|
|
|
|
}
|
|
|
|
|
2019-04-04 19:17:47 +03:00
|
|
|
if (!aFromIPC) {
|
|
|
|
// Send attach to our parent if we need to.
|
|
|
|
if (XRE_IsContentProcess()) {
|
|
|
|
ContentChild::GetSingleton()->SendAttachBrowsingContext(
|
|
|
|
GetIPCInitializer());
|
|
|
|
} else if (IsContent()) {
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
|
2019-07-02 23:48:13 +03:00
|
|
|
mGroup->EachParent([&](ContentParent* aParent) {
|
2019-04-30 11:45:41 +03:00
|
|
|
Unused << aParent->SendAttachBrowsingContext(GetIPCInitializer());
|
|
|
|
});
|
2019-04-04 19:17:47 +03:00
|
|
|
}
|
2019-03-14 21:50:38 +03:00
|
|
|
}
|
2018-07-26 10:31:00 +03:00
|
|
|
}
|
|
|
|
|
2019-03-14 21:50:38 +03:00
|
|
|
void BrowsingContext::Detach(bool aFromIPC) {
|
2018-07-26 10:31:00 +03:00
|
|
|
MOZ_LOG(GetLog(), LogLevel::Debug,
|
|
|
|
("%s: Detaching 0x%08" PRIx64 " from 0x%08" PRIx64,
|
|
|
|
XRE_IsParentProcess() ? "Parent" : "Child", Id(),
|
|
|
|
mParent ? mParent->Id() : 0));
|
|
|
|
|
2019-07-02 23:48:13 +03:00
|
|
|
// Unlinking might remove our group before Detach gets called.
|
|
|
|
if (NS_WARN_IF(!mGroup)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-07-15 23:44:50 +03:00
|
|
|
RefPtr<BrowsingContext> self(this);
|
2018-12-17 13:45:37 +03:00
|
|
|
|
2019-07-02 23:48:13 +03:00
|
|
|
if (!mGroup->EvictCachedContext(this)) {
|
2019-03-14 21:51:13 +03:00
|
|
|
Children* children = nullptr;
|
|
|
|
if (mParent) {
|
|
|
|
children = &mParent->mChildren;
|
2019-07-02 23:48:13 +03:00
|
|
|
} else {
|
2019-03-14 21:51:13 +03:00
|
|
|
children = &mGroup->Toplevels();
|
|
|
|
}
|
|
|
|
|
2019-07-02 23:48:13 +03:00
|
|
|
children->RemoveElement(this);
|
2019-03-14 21:51:13 +03:00
|
|
|
}
|
2019-03-14 21:50:45 +03:00
|
|
|
|
2019-09-10 18:37:54 +03:00
|
|
|
if (!mChildren.IsEmpty()) {
|
|
|
|
mGroup->CacheContexts(mChildren);
|
|
|
|
mChildren.Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
mGroup->Unregister(this);
|
|
|
|
mIsDiscarded = true;
|
|
|
|
|
2019-10-29 20:15:29 +03:00
|
|
|
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
|
|
|
if (obs) {
|
|
|
|
obs->NotifyObservers(ToSupports(this), "browsing-context-discarded",
|
|
|
|
nullptr);
|
|
|
|
}
|
|
|
|
|
2019-09-10 18:37:54 +03:00
|
|
|
// NOTE: Doesn't use SetClosed, as it will be set in all processes
|
|
|
|
// automatically by calls to Detach()
|
2020-01-20 17:57:47 +03:00
|
|
|
mFields.SetWithoutSyncing<IDX_Closed>(true);
|
Bug 1529684 - Part 6: Store a mIsInProcess flag to preserve WindowProxy behaviour, r=farre
Currently when we have an in-process WindowProxy object, we will attempt
to either use the cached mWindowProxy value, or fetch the
nsGlobalWindowOuter object from through the nsDocShell. Unfortunately,
when the BrowsingContext is detached, we will fail to get the
nsGlobalWindowOuter object. This happens to be OK for our test cases, as
the cached mWindowProxy value doesn't have the chance to go away, but
isn't acceptable long-term.
These patches exascerbated that issue by causing the nsDocShell pointer
itself to be cleared when it is destroyed, which caused the Remote
WindowProxy logic to be triggered. To deal with that case, this patch
adds a new mIsInProcess flag to continue to act like the old code-path.
In the future, we will need to also handle ensuring that the
nsGlobalWindowOuter lives for long enough, however that is not being
done in this patch in order to land it sooner rather than later.
Depends on D22763
Differential Revision: https://phabricator.services.mozilla.com/D22764
--HG--
extra : moz-landing-system : lando
2019-03-14 21:50:54 +03:00
|
|
|
|
2020-01-20 17:57:47 +03:00
|
|
|
if (GetIsPopupSpam()) {
|
2019-10-18 06:04:55 +03:00
|
|
|
PopupBlocker::UnregisterOpenPopupSpam();
|
|
|
|
// NOTE: Doesn't use SetIsPopupSpam, as it will be set all processes
|
|
|
|
// automatically.
|
2020-01-20 17:57:47 +03:00
|
|
|
mFields.SetWithoutSyncing<IDX_IsPopupSpam>(false);
|
2019-10-18 06:04:55 +03:00
|
|
|
}
|
|
|
|
|
2020-01-16 21:05:14 +03:00
|
|
|
if (XRE_IsParentProcess()) {
|
|
|
|
Canonical()->CanonicalDiscard();
|
|
|
|
}
|
|
|
|
|
2019-03-14 21:50:38 +03:00
|
|
|
if (!aFromIPC && XRE_IsContentProcess()) {
|
|
|
|
auto cc = ContentChild::GetSingleton();
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(cc);
|
2019-07-15 23:44:50 +03:00
|
|
|
// Tell our parent that the BrowsingContext has been detached. A strong
|
|
|
|
// reference to this is held until the promise is resolved to ensure it
|
|
|
|
// doesn't die before the parent receives the message.
|
|
|
|
auto resolve = [self](bool) {};
|
|
|
|
auto reject = [self](mozilla::ipc::ResponseRejectReason) {};
|
|
|
|
cc->SendDetachBrowsingContext(Id(), resolve, reject);
|
2018-07-26 10:31:00 +03:00
|
|
|
}
|
2018-06-28 05:40:00 +03:00
|
|
|
}
|
|
|
|
|
2019-06-06 17:57:18 +03:00
|
|
|
void BrowsingContext::PrepareForProcessChange() {
|
|
|
|
MOZ_LOG(GetLog(), LogLevel::Debug,
|
|
|
|
("%s: Preparing 0x%08" PRIx64 " for a process change",
|
|
|
|
XRE_IsParentProcess() ? "Parent" : "Child", Id()));
|
|
|
|
|
|
|
|
MOZ_ASSERT(mIsInProcess, "Must currently be an in-process frame");
|
2019-07-08 20:27:27 +03:00
|
|
|
MOZ_ASSERT(!mIsDiscarded, "We're already closed?");
|
2019-06-06 17:57:18 +03:00
|
|
|
|
|
|
|
mIsInProcess = false;
|
2019-09-07 22:12:20 +03:00
|
|
|
mUserGestureStart = TimeStamp();
|
2019-06-06 17:57:18 +03:00
|
|
|
|
|
|
|
// NOTE: For now, clear our nsDocShell reference, as we're primarily in a
|
|
|
|
// different process now. This may need to change in the future with
|
|
|
|
// Cross-Process BFCache.
|
|
|
|
mDocShell = nullptr;
|
Bug 1510760, part 5 - Support local-to-remote window proxy transplanting. r=tcampbell,peterv
When a BrowsingContext changes from being local to remote, we have to
change all window proxies from being local to remote, using
transplanting. The actual window proxy becomes a remote window
proxy. Cross compartment wrappers (CCWs) to the window proxy also
become remote window proxies in their respective compartments, rather
than CCWs to a remote proxy in the old compartment of the window
proxy, because the window is no longer actually in that
compartment. This also avoids having to figure out what Xray behavior
for remote window proxies should be.
This patch uses the transplanting support I added to
GetRemoteOuterWindowProxy() in the previous patch to ensure that the
remote proxy map holds the correct value after transplanting finishes.
It drops the requirement that both arguments to JS_TransplantObject
have the same class, because we need to transplant a window proxy with
a remote window proxy. It also deals with this by not adding origobj
to the wrapper map unless it is a CCW, to handle transplanting to a
remote proxy.
The core design here, with the remote window proxies in every
compartment, is taken from a patch by peterv.
Differential Revision: https://phabricator.services.mozilla.com/D35730
--HG--
extra : moz-landing-system : lando
2019-07-18 22:36:19 +03:00
|
|
|
|
|
|
|
if (!mWindowProxy) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We have to go through mWindowProxy rather than calling GetDOMWindow() on
|
|
|
|
// mDocShell because the mDocshell reference gets cleared immediately after
|
|
|
|
// the window is closed.
|
|
|
|
nsGlobalWindowOuter::PrepareForProcessChange(mWindowProxy);
|
|
|
|
MOZ_ASSERT(!mWindowProxy);
|
2019-06-06 17:57:18 +03:00
|
|
|
}
|
|
|
|
|
2019-03-14 21:50:38 +03:00
|
|
|
void BrowsingContext::CacheChildren(bool aFromIPC) {
|
2018-06-28 05:40:00 +03:00
|
|
|
MOZ_LOG(GetLog(), LogLevel::Debug,
|
|
|
|
("%s: Caching children of 0x%08" PRIx64 "",
|
|
|
|
XRE_IsParentProcess() ? "Parent" : "Child", Id()));
|
|
|
|
|
2019-07-02 23:48:13 +03:00
|
|
|
mGroup->CacheContexts(mChildren);
|
2018-12-17 13:45:37 +03:00
|
|
|
mChildren.Clear();
|
2018-06-28 05:40:00 +03:00
|
|
|
|
2019-03-14 21:50:38 +03:00
|
|
|
if (!aFromIPC && XRE_IsContentProcess()) {
|
|
|
|
auto cc = ContentChild::GetSingleton();
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(cc);
|
2019-04-29 14:38:45 +03:00
|
|
|
cc->SendCacheBrowsingContextChildren(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BrowsingContext::RestoreChildren(Children&& aChildren, bool aFromIPC) {
|
|
|
|
MOZ_LOG(GetLog(), LogLevel::Debug,
|
|
|
|
("%s: Restoring children of 0x%08" PRIx64 "",
|
|
|
|
XRE_IsParentProcess() ? "Parent" : "Child", Id()));
|
|
|
|
|
2019-04-30 19:11:03 +03:00
|
|
|
for (BrowsingContext* child : aChildren) {
|
2019-04-29 14:38:45 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(child->GetParent() == this);
|
2019-07-02 23:48:13 +03:00
|
|
|
Unused << mGroup->EvictCachedContext(child);
|
2019-04-29 14:38:45 +03:00
|
|
|
}
|
|
|
|
|
2019-05-06 19:14:40 +03:00
|
|
|
mChildren.AppendElements(aChildren);
|
2019-04-29 14:38:45 +03:00
|
|
|
|
|
|
|
if (!aFromIPC && XRE_IsContentProcess()) {
|
|
|
|
auto cc = ContentChild::GetSingleton();
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(cc);
|
2019-05-28 10:40:00 +03:00
|
|
|
cc->SendRestoreBrowsingContextChildren(this, aChildren);
|
2018-06-28 05:40:00 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-02 23:48:13 +03:00
|
|
|
bool BrowsingContext::IsCached() { return mGroup->IsContextCached(this); }
|
2018-07-26 10:31:00 +03:00
|
|
|
|
2019-07-17 18:35:04 +03:00
|
|
|
bool BrowsingContext::IsTargetable() {
|
2020-01-20 17:57:47 +03:00
|
|
|
return !GetClosed() && !mIsDiscarded && !IsCached();
|
2019-07-17 18:35:04 +03:00
|
|
|
}
|
|
|
|
|
2019-04-15 18:14:54 +03:00
|
|
|
bool BrowsingContext::HasOpener() const {
|
2020-01-20 17:57:47 +03:00
|
|
|
return sBrowsingContexts->Contains(GetOpenerId());
|
2019-04-15 18:14:54 +03:00
|
|
|
}
|
|
|
|
|
2019-04-29 14:38:45 +03:00
|
|
|
void BrowsingContext::GetChildren(Children& aChildren) {
|
2018-12-17 13:45:37 +03:00
|
|
|
MOZ_ALWAYS_TRUE(aChildren.AppendElements(mChildren));
|
2018-08-29 05:00:00 +03:00
|
|
|
}
|
|
|
|
|
2020-01-20 17:58:52 +03:00
|
|
|
void BrowsingContext::GetWindowContexts(
|
|
|
|
nsTArray<RefPtr<WindowContext>>& aWindows) {
|
|
|
|
aWindows.AppendElements(mWindowContexts);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BrowsingContext::RegisterWindowContext(WindowContext* aWindow) {
|
|
|
|
MOZ_ASSERT(!mWindowContexts.Contains(aWindow),
|
|
|
|
"WindowContext already registered!");
|
|
|
|
mWindowContexts.AppendElement(aWindow);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BrowsingContext::UnregisterWindowContext(WindowContext* aWindow) {
|
|
|
|
MOZ_ASSERT(mWindowContexts.Contains(aWindow),
|
|
|
|
"WindowContext not registered!");
|
|
|
|
mWindowContexts.RemoveElement(aWindow);
|
|
|
|
|
|
|
|
// Our current window global should be in our mWindowGlobals set. If it's not
|
|
|
|
// anymore, clear that reference.
|
|
|
|
// FIXME: There are probably situations where this is wrong. We should
|
|
|
|
// double-check.
|
|
|
|
if (aWindow == mCurrentWindowContext) {
|
|
|
|
mCurrentWindowContext = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-15 12:59:21 +03:00
|
|
|
// FindWithName follows the rules for choosing a browsing context,
|
|
|
|
// with the exception of sandboxing for iframes. The implementation
|
|
|
|
// for arbitrarily choosing between two browsing contexts with the
|
|
|
|
// same name is as follows:
|
|
|
|
//
|
|
|
|
// 1) The start browsing context, i.e. 'this'
|
|
|
|
// 2) Descendants in insertion order
|
|
|
|
// 3) The parent
|
|
|
|
// 4) Siblings and their children, both in insertion order
|
|
|
|
// 5) After this we iteratively follow the parent chain, repeating 3
|
|
|
|
// and 4 until
|
|
|
|
// 6) If there is no parent, consider all other top level browsing
|
|
|
|
// contexts and their children, both in insertion order
|
|
|
|
//
|
|
|
|
// See
|
|
|
|
// https://html.spec.whatwg.org/multipage/browsers.html#the-rules-for-choosing-a-browsing-context-given-a-browsing-context-name
|
2019-10-25 18:34:30 +03:00
|
|
|
BrowsingContext* BrowsingContext::FindWithName(
|
|
|
|
const nsAString& aName, bool aUseEntryGlobalForAccessCheck) {
|
2019-10-24 17:53:07 +03:00
|
|
|
RefPtr<BrowsingContext> requestingContext = this;
|
2019-10-25 18:34:30 +03:00
|
|
|
if (aUseEntryGlobalForAccessCheck) {
|
|
|
|
if (nsCOMPtr<nsIDocShell> caller = do_GetInterface(GetEntryGlobal())) {
|
|
|
|
if (caller->GetBrowsingContext()) {
|
|
|
|
requestingContext = caller->GetBrowsingContext();
|
|
|
|
}
|
2019-10-24 17:53:07 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-15 12:59:21 +03:00
|
|
|
BrowsingContext* found = nullptr;
|
|
|
|
if (aName.IsEmpty()) {
|
|
|
|
// You can't find a browsing context with an empty name.
|
|
|
|
found = nullptr;
|
|
|
|
} else if (aName.LowerCaseEqualsLiteral("_blank")) {
|
|
|
|
// Just return null. Caller must handle creating a new window with
|
|
|
|
// a blank name.
|
|
|
|
found = nullptr;
|
2019-10-24 17:53:07 +03:00
|
|
|
} else if (nsContentUtils::IsSpecialName(aName)) {
|
2019-10-24 17:53:07 +03:00
|
|
|
found = FindWithSpecialName(aName, *requestingContext);
|
2019-07-31 03:30:55 +03:00
|
|
|
} else if (BrowsingContext* child =
|
2019-10-24 17:53:07 +03:00
|
|
|
FindWithNameInSubtree(aName, *requestingContext)) {
|
2019-02-15 12:59:21 +03:00
|
|
|
found = child;
|
|
|
|
} else {
|
|
|
|
BrowsingContext* current = this;
|
|
|
|
|
|
|
|
do {
|
|
|
|
Children* siblings;
|
|
|
|
BrowsingContext* parent = current->mParent;
|
|
|
|
|
|
|
|
if (!parent) {
|
|
|
|
// We've reached the root of the tree, consider browsing
|
|
|
|
// contexts in the same browsing context group.
|
|
|
|
siblings = &mGroup->Toplevels();
|
2019-07-31 03:30:55 +03:00
|
|
|
} else if (parent->NameEquals(aName) &&
|
2019-10-24 17:53:07 +03:00
|
|
|
requestingContext->CanAccess(parent) &&
|
2019-07-17 18:31:04 +03:00
|
|
|
parent->IsTargetable()) {
|
2019-02-15 12:59:21 +03:00
|
|
|
found = parent;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
siblings = &parent->mChildren;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (BrowsingContext* sibling : *siblings) {
|
|
|
|
if (sibling == current) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (BrowsingContext* relative =
|
2019-10-24 17:53:07 +03:00
|
|
|
sibling->FindWithNameInSubtree(aName, *requestingContext)) {
|
2019-02-15 12:59:21 +03:00
|
|
|
found = relative;
|
|
|
|
// Breaks the outer loop
|
|
|
|
parent = nullptr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
current = parent;
|
|
|
|
} while (current);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Helpers should perform access control checks, which means that we
|
|
|
|
// only need to assert that we can access found.
|
2019-10-24 17:53:07 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!found || requestingContext->CanAccess(found));
|
2019-02-15 12:59:21 +03:00
|
|
|
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
2019-07-31 03:30:55 +03:00
|
|
|
BrowsingContext* BrowsingContext::FindChildWithName(
|
|
|
|
const nsAString& aName, BrowsingContext& aRequestingContext) {
|
2019-02-15 12:59:21 +03:00
|
|
|
if (aName.IsEmpty()) {
|
|
|
|
// You can't find a browsing context with the empty name.
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (BrowsingContext* child : mChildren) {
|
2019-07-31 03:30:55 +03:00
|
|
|
if (child->NameEquals(aName) && aRequestingContext.CanAccess(child) &&
|
|
|
|
child->IsTargetable()) {
|
2019-02-15 12:59:21 +03:00
|
|
|
return child;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2019-07-31 03:30:55 +03:00
|
|
|
BrowsingContext* BrowsingContext::FindWithSpecialName(
|
|
|
|
const nsAString& aName, BrowsingContext& aRequestingContext) {
|
2019-02-15 12:59:21 +03:00
|
|
|
// TODO(farre): Neither BrowsingContext nor nsDocShell checks if the
|
|
|
|
// browsing context pointed to by a special name is active. Should
|
|
|
|
// it be? See Bug 1527913.
|
|
|
|
if (aName.LowerCaseEqualsLiteral("_self")) {
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aName.LowerCaseEqualsLiteral("_parent")) {
|
2019-08-02 04:45:47 +03:00
|
|
|
if (mParent) {
|
|
|
|
return aRequestingContext.CanAccess(mParent) ? mParent.get() : nullptr;
|
|
|
|
}
|
|
|
|
return this;
|
2019-02-15 12:59:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (aName.LowerCaseEqualsLiteral("_top")) {
|
2019-04-09 09:19:24 +03:00
|
|
|
BrowsingContext* top = Top();
|
2019-02-15 12:59:21 +03:00
|
|
|
|
2019-07-31 03:30:55 +03:00
|
|
|
return aRequestingContext.CanAccess(top) ? top : nullptr;
|
2019-02-15 12:59:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
BrowsingContext* BrowsingContext::FindWithNameInSubtree(
|
2019-07-31 03:30:55 +03:00
|
|
|
const nsAString& aName, BrowsingContext& aRequestingContext) {
|
2019-02-15 12:59:21 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!aName.IsEmpty());
|
|
|
|
|
2019-07-31 03:30:55 +03:00
|
|
|
if (NameEquals(aName) && aRequestingContext.CanAccess(this) &&
|
2019-07-17 18:31:04 +03:00
|
|
|
IsTargetable()) {
|
2019-02-15 12:59:21 +03:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (BrowsingContext* child : mChildren) {
|
|
|
|
if (BrowsingContext* found =
|
|
|
|
child->FindWithNameInSubtree(aName, aRequestingContext)) {
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2019-07-31 21:40:39 +03:00
|
|
|
// For historical context, see:
|
|
|
|
//
|
|
|
|
// Bug 13871: Prevent frameset spoofing
|
|
|
|
// Bug 103638: Targets with same name in different windows open in wrong
|
|
|
|
// window with javascript
|
|
|
|
// Bug 408052: Adopt "ancestor" frame navigation policy
|
|
|
|
// Bug 1570207: Refactor logic to rely on BrowsingContextGroups to enforce
|
|
|
|
// origin attribute isolation.
|
|
|
|
bool BrowsingContext::CanAccess(BrowsingContext* aTarget,
|
|
|
|
bool aConsiderOpener) {
|
|
|
|
MOZ_ASSERT(
|
|
|
|
mDocShell,
|
|
|
|
"CanAccess() may only be called in the process of the accessing window");
|
|
|
|
MOZ_ASSERT(aTarget, "Must have a target");
|
|
|
|
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(
|
|
|
|
Group() == aTarget->Group(),
|
|
|
|
"A BrowsingContext should never see a context from a different group");
|
|
|
|
|
|
|
|
// A frame can navigate itself and its own root.
|
|
|
|
if (aTarget == this || aTarget == Top()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// A frame can navigate any frame with a same-origin ancestor.
|
|
|
|
for (BrowsingContext* bc = aTarget; bc; bc = bc->GetParent()) {
|
2020-01-23 21:14:42 +03:00
|
|
|
if (bc->mDocShell && nsDocShell::ValidateOrigin(this, bc)) {
|
2019-07-31 21:40:39 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the target is a top-level document, a frame can navigate it if it can
|
|
|
|
// navigate its opener.
|
|
|
|
if (aConsiderOpener && !aTarget->GetParent()) {
|
|
|
|
if (RefPtr<BrowsingContext> opener = aTarget->GetOpener()) {
|
|
|
|
return CanAccess(opener, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2019-02-15 12:59:21 +03:00
|
|
|
}
|
|
|
|
|
2019-12-10 15:12:25 +03:00
|
|
|
RefPtr<SessionStorageManager> BrowsingContext::GetSessionStorageManager() {
|
|
|
|
RefPtr<SessionStorageManager>& manager = Top()->mSessionStorageManager;
|
|
|
|
if (!manager) {
|
2019-12-10 15:12:32 +03:00
|
|
|
manager = new SessionStorageManager(this);
|
2019-12-10 15:12:25 +03:00
|
|
|
}
|
|
|
|
return manager;
|
|
|
|
}
|
|
|
|
|
2018-07-26 10:31:00 +03:00
|
|
|
BrowsingContext::~BrowsingContext() {
|
2018-12-17 13:45:37 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!mParent || !mParent->mChildren.Contains(this));
|
2019-01-30 19:07:21 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!mGroup || !mGroup->Toplevels().Contains(this));
|
2019-04-29 10:01:50 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!mGroup || !mGroup->IsContextCached(this));
|
2018-07-26 10:31:00 +03:00
|
|
|
|
2019-12-01 00:13:24 +03:00
|
|
|
mDeprioritizedLoadRunner.clear();
|
|
|
|
|
2018-07-26 10:31:00 +03:00
|
|
|
if (sBrowsingContexts) {
|
2019-05-24 23:15:53 +03:00
|
|
|
sBrowsingContexts->Remove(Id());
|
2018-07-26 10:31:00 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-29 05:00:00 +03:00
|
|
|
nsISupports* BrowsingContext::GetParentObject() const {
|
|
|
|
return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
|
|
|
|
}
|
|
|
|
|
|
|
|
JSObject* BrowsingContext::WrapObject(JSContext* aCx,
|
|
|
|
JS::Handle<JSObject*> aGivenProto) {
|
|
|
|
return BrowsingContext_Binding::Wrap(aCx, this, aGivenProto);
|
|
|
|
}
|
|
|
|
|
2019-07-02 01:24:09 +03:00
|
|
|
bool BrowsingContext::WriteStructuredClone(JSContext* aCx,
|
|
|
|
JSStructuredCloneWriter* aWriter,
|
|
|
|
StructuredCloneHolder* aHolder) {
|
|
|
|
return (JS_WriteUint32Pair(aWriter, SCTAG_DOM_BROWSING_CONTEXT, 0) &&
|
|
|
|
JS_WriteUint32Pair(aWriter, uint32_t(Id()), uint32_t(Id() >> 32)));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
JSObject* BrowsingContext::ReadStructuredClone(JSContext* aCx,
|
|
|
|
JSStructuredCloneReader* aReader,
|
|
|
|
StructuredCloneHolder* aHolder) {
|
|
|
|
uint32_t idLow = 0;
|
|
|
|
uint32_t idHigh = 0;
|
|
|
|
if (!JS_ReadUint32Pair(aReader, &idLow, &idHigh)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
uint64_t id = uint64_t(idHigh) << 32 | idLow;
|
|
|
|
|
|
|
|
// Note: Do this check after reading our ID data. Returning null will abort
|
|
|
|
// the decode operation anyway, but we should at least be as safe as possible.
|
|
|
|
if (NS_WARN_IF(!NS_IsMainThread())) {
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(false,
|
|
|
|
"We shouldn't be trying to decode a BrowsingContext "
|
|
|
|
"on a background thread.");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::RootedValue val(aCx, JS::NullValue());
|
|
|
|
// We'll get rooting hazard errors from the RefPtr destructor if it isn't
|
|
|
|
// destroyed before we try to return a raw JSObject*, so create it in its own
|
|
|
|
// scope.
|
|
|
|
if (RefPtr<BrowsingContext> context = Get(id)) {
|
|
|
|
if (!GetOrCreateDOMReflector(aCx, context, &val) || !val.isObject()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return val.toObjectOrNull();
|
|
|
|
}
|
|
|
|
|
2019-01-15 02:09:42 +03:00
|
|
|
void BrowsingContext::NotifyUserGestureActivation() {
|
2019-09-20 14:10:13 +03:00
|
|
|
SetUserActivationState(UserActivation::State::FullActivated);
|
2019-01-15 02:09:42 +03:00
|
|
|
}
|
|
|
|
|
2019-01-15 02:21:05 +03:00
|
|
|
void BrowsingContext::NotifyResetUserGestureActivation() {
|
2019-09-20 14:10:13 +03:00
|
|
|
SetUserActivationState(UserActivation::State::None);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool BrowsingContext::HasBeenUserGestureActivated() {
|
2020-01-20 17:57:47 +03:00
|
|
|
return GetUserActivationState() != UserActivation::State::None;
|
2019-09-07 22:12:20 +03:00
|
|
|
}
|
2019-01-15 02:09:42 +03:00
|
|
|
|
2019-09-07 22:12:20 +03:00
|
|
|
bool BrowsingContext::HasValidTransientUserGestureActivation() {
|
|
|
|
MOZ_ASSERT(mIsInProcess);
|
|
|
|
|
2020-01-20 17:57:47 +03:00
|
|
|
if (GetUserActivationState() != UserActivation::State::FullActivated) {
|
2019-09-07 22:12:20 +03:00
|
|
|
MOZ_ASSERT(mUserGestureStart.IsNull(),
|
|
|
|
"mUserGestureStart should be null if the document hasn't ever "
|
|
|
|
"been activated by user gesture");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(!mUserGestureStart.IsNull(),
|
|
|
|
"mUserGestureStart shouldn't be null if the document has ever "
|
|
|
|
"been activated by user gesture");
|
|
|
|
TimeDuration timeout = TimeDuration::FromMilliseconds(
|
|
|
|
StaticPrefs::dom_user_activation_transient_timeout());
|
|
|
|
|
|
|
|
return timeout <= TimeDuration() ||
|
|
|
|
(TimeStamp::Now() - mUserGestureStart) <= timeout;
|
2019-01-15 02:21:05 +03:00
|
|
|
}
|
|
|
|
|
2019-09-20 14:10:13 +03:00
|
|
|
bool BrowsingContext::ConsumeTransientUserGestureActivation() {
|
|
|
|
MOZ_ASSERT(mIsInProcess);
|
|
|
|
|
|
|
|
if (!HasValidTransientUserGestureActivation()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
BrowsingContext* top = Top();
|
|
|
|
top->PreOrderWalk([&](BrowsingContext* aContext) {
|
|
|
|
if (aContext->GetUserActivationState() ==
|
|
|
|
UserActivation::State::FullActivated) {
|
|
|
|
aContext->SetUserActivationState(UserActivation::State::HasBeenActivated);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-10-18 21:58:30 +03:00
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BrowsingContext)
|
|
|
|
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
|
|
NS_INTERFACE_MAP_END
|
|
|
|
|
2018-09-14 17:57:18 +03:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(BrowsingContext)
|
|
|
|
|
2019-10-18 21:58:30 +03:00
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(BrowsingContext)
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(BrowsingContext)
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(BrowsingContext)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
|
|
|
|
2018-09-14 17:57:18 +03:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BrowsingContext)
|
2019-05-24 23:15:53 +03:00
|
|
|
if (sBrowsingContexts) {
|
|
|
|
sBrowsingContexts->Remove(tmp->Id());
|
|
|
|
}
|
|
|
|
|
2020-01-20 17:57:47 +03:00
|
|
|
if (tmp->GetIsPopupSpam()) {
|
2019-10-18 06:04:55 +03:00
|
|
|
PopupBlocker::UnregisterOpenPopupSpam();
|
|
|
|
// NOTE: Doesn't use SetIsPopupSpam, as it will be set all processes
|
|
|
|
// automatically.
|
2020-01-20 17:57:47 +03:00
|
|
|
tmp->mFields.SetWithoutSyncing<IDX_IsPopupSpam>(false);
|
2019-10-18 06:04:55 +03:00
|
|
|
}
|
|
|
|
|
2019-04-17 03:51:36 +03:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell, mChildren, mParent, mGroup,
|
2020-01-20 17:58:52 +03:00
|
|
|
mEmbedderElement, mWindowContexts,
|
|
|
|
mCurrentWindowContext, mSessionStorageManager)
|
2018-09-14 17:57:18 +03:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(BrowsingContext)
|
2020-01-20 17:58:52 +03:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(
|
|
|
|
mDocShell, mChildren, mParent, mGroup, mEmbedderElement, mWindowContexts,
|
|
|
|
mCurrentWindowContext, mSessionStorageManager)
|
2018-09-14 17:57:18 +03:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
|
2019-02-28 21:23:15 +03:00
|
|
|
class RemoteLocationProxy
|
|
|
|
: public RemoteObjectProxy<BrowsingContext::LocationProxy,
|
|
|
|
Location_Binding::sCrossOriginAttributes,
|
|
|
|
Location_Binding::sCrossOriginMethods> {
|
|
|
|
public:
|
|
|
|
typedef RemoteObjectProxy Base;
|
|
|
|
|
|
|
|
constexpr RemoteLocationProxy()
|
|
|
|
: RemoteObjectProxy(prototypes::id::Location) {}
|
2019-02-28 22:34:02 +03:00
|
|
|
|
|
|
|
void NoteChildren(JSObject* aProxy,
|
|
|
|
nsCycleCollectionTraversalCallback& aCb) const override {
|
|
|
|
auto location =
|
|
|
|
static_cast<BrowsingContext::LocationProxy*>(GetNative(aProxy));
|
|
|
|
CycleCollectionNoteChild(aCb, location->GetBrowsingContext(),
|
|
|
|
"js::GetObjectPrivate(obj)->GetBrowsingContext()");
|
|
|
|
}
|
2019-02-28 21:23:15 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
static const RemoteLocationProxy sSingleton;
|
|
|
|
|
|
|
|
// Give RemoteLocationProxy 2 reserved slots, like the other wrappers,
|
|
|
|
// so JSObject::swap can swap it with CrossCompartmentWrappers without requiring
|
|
|
|
// malloc.
|
|
|
|
template <>
|
2019-08-14 20:15:15 +03:00
|
|
|
const JSClass RemoteLocationProxy::Base::sClass =
|
2019-02-28 21:23:15 +03:00
|
|
|
PROXY_CLASS_DEF("Proxy", JSCLASS_HAS_RESERVED_SLOTS(2));
|
|
|
|
|
2019-01-02 16:29:18 +03:00
|
|
|
void BrowsingContext::Location(JSContext* aCx,
|
|
|
|
JS::MutableHandle<JSObject*> aLocation,
|
2019-02-28 21:23:15 +03:00
|
|
|
ErrorResult& aError) {
|
|
|
|
aError.MightThrowJSException();
|
2019-07-18 22:36:17 +03:00
|
|
|
sSingleton.GetProxyObject(aCx, &mLocation, /* aTransplantTo = */ nullptr,
|
|
|
|
aLocation);
|
2019-02-28 21:23:15 +03:00
|
|
|
if (!aLocation) {
|
|
|
|
aError.StealExceptionFromJSContext(aCx);
|
|
|
|
}
|
|
|
|
}
|
2019-01-02 16:29:18 +03:00
|
|
|
|
2019-08-24 01:26:51 +03:00
|
|
|
nsresult BrowsingContext::LoadURI(BrowsingContext* aAccessor,
|
2019-10-11 05:27:05 +03:00
|
|
|
nsDocShellLoadState* aLoadState,
|
|
|
|
bool aSetNavigating) {
|
2019-09-12 14:37:01 +03:00
|
|
|
// Per spec, most load attempts are silently ignored when a BrowsingContext is
|
|
|
|
// null (which in our code corresponds to discarded), so we simply fail
|
|
|
|
// silently in those cases. Regardless, we cannot trigger loads in/from
|
|
|
|
// discarded BrowsingContexts via IPC, so we need to abort in any case.
|
|
|
|
if (IsDiscarded() || (aAccessor && aAccessor->IsDiscarded())) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2019-08-02 04:00:32 +03:00
|
|
|
|
|
|
|
if (mDocShell) {
|
2019-10-11 05:27:05 +03:00
|
|
|
return mDocShell->LoadURI(aLoadState, aSetNavigating);
|
2019-08-24 01:26:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!aAccessor && XRE_IsParentProcess()) {
|
2019-12-12 05:32:00 +03:00
|
|
|
if (ContentParent* cp = Canonical()->GetContentParent()) {
|
|
|
|
Unused << cp->SendLoadURI(this, aLoadState, aSetNavigating);
|
|
|
|
}
|
2019-08-02 04:00:32 +03:00
|
|
|
} else {
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(aAccessor);
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(aAccessor->Group() == Group());
|
|
|
|
|
Bug 1586926 - Add necessary caller access checks for cross-process Location navigations. r=nika
We attempt to enforce the same (approximate) access checks to Location-based
navigation that we use for loads that use named targeting (e.g., via
window.open), so that a frame that can't be navigated via, e.g., window.open,
also can't be navigated via, e.g., window.parent[1].location = url. For the
in-process case, this is handled by a somewhat hidden call to
CheckLoadingPermissions() in nsDocShell::InternalLoad, where the former checks
whether the principal of whatever JS context happens to be on the stack
subsumes the principal of the target DocShell or any of its ancestors, and
blocks the load if it doesn't.
Since there is no JS context on the stack when we call into the DocShell
loading code in the cross-process case, the check is simply ignored.
So we need to instead do the check in BrowsingContext::LoadURI, where we
already have an explicit accessor, and can simply use the standard access
checks that we use elsewhere.
Differential Revision: https://phabricator.services.mozilla.com/D48443
--HG--
extra : moz-landing-system : lando
2019-10-10 22:36:23 +03:00
|
|
|
if (!aAccessor->CanAccess(this)) {
|
|
|
|
return NS_ERROR_DOM_PROP_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
|
2019-08-02 04:00:32 +03:00
|
|
|
nsCOMPtr<nsPIDOMWindowOuter> win(aAccessor->GetDOMWindow());
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(win);
|
|
|
|
if (WindowGlobalChild* wgc =
|
|
|
|
win->GetCurrentInnerWindow()->GetWindowGlobalChild()) {
|
2019-10-11 05:27:05 +03:00
|
|
|
wgc->SendLoadURI(this, aLoadState, aSetNavigating);
|
2019-08-02 04:00:32 +03:00
|
|
|
}
|
|
|
|
}
|
2019-08-24 01:26:51 +03:00
|
|
|
return NS_OK;
|
2019-08-02 04:00:32 +03:00
|
|
|
}
|
|
|
|
|
2019-11-13 00:52:18 +03:00
|
|
|
nsresult BrowsingContext::InternalLoad(BrowsingContext* aAccessor,
|
|
|
|
nsDocShellLoadState* aLoadState,
|
|
|
|
nsIDocShell** aDocShell,
|
|
|
|
nsIRequest** aRequest) {
|
|
|
|
if (IsDiscarded() || (aAccessor && aAccessor->IsDiscarded())) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isActive =
|
2020-01-20 17:57:47 +03:00
|
|
|
aAccessor && aAccessor->GetIsActive() && !GetIsActive() &&
|
2019-11-13 00:52:18 +03:00
|
|
|
!Preferences::GetBool("browser.tabs.loadDivertedInBackground", false);
|
|
|
|
if (mDocShell) {
|
|
|
|
nsresult rv = nsDocShell::Cast(mDocShell)->InternalLoad(
|
|
|
|
aLoadState, aDocShell, aRequest);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// Switch to target tab if we're currently focused window.
|
|
|
|
// Take loadDivertedInBackground into account so the behavior would be
|
|
|
|
// the same as how the tab first opened.
|
|
|
|
nsCOMPtr<nsPIDOMWindowOuter> domWin = GetDOMWindow();
|
|
|
|
if (isActive && domWin) {
|
2020-01-16 17:38:40 +03:00
|
|
|
nsFocusManager::FocusWindow(domWin, CallerType::System);
|
2019-11-13 00:52:18 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Else we ran out of memory, or were a popup and got blocked,
|
|
|
|
// or something.
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2019-12-12 05:32:00 +03:00
|
|
|
if (XRE_IsParentProcess()) {
|
|
|
|
if (ContentParent* cp = Canonical()->GetContentParent()) {
|
|
|
|
Unused << cp->SendInternalLoad(this, aLoadState, isActive);
|
|
|
|
}
|
2019-11-13 00:52:18 +03:00
|
|
|
} else {
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(aAccessor);
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(aAccessor->Group() == Group());
|
|
|
|
|
|
|
|
if (!aAccessor->CanAccess(this)) {
|
|
|
|
return NS_ERROR_DOM_PROP_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsPIDOMWindowOuter> win(aAccessor->GetDOMWindow());
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(win);
|
|
|
|
if (WindowGlobalChild* wgc =
|
|
|
|
win->GetCurrentInnerWindow()->GetWindowGlobalChild()) {
|
|
|
|
wgc->SendInternalLoad(this, aLoadState);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2019-10-11 05:27:07 +03:00
|
|
|
void BrowsingContext::DisplayLoadError(const nsAString& aURI) {
|
|
|
|
MOZ_LOG(GetLog(), LogLevel::Debug, ("DisplayLoadError"));
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsDiscarded());
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(mDocShell || XRE_IsParentProcess());
|
|
|
|
|
|
|
|
if (mDocShell) {
|
|
|
|
bool didDisplayLoadError = false;
|
|
|
|
mDocShell->DisplayLoadError(NS_ERROR_MALFORMED_URI, nullptr,
|
|
|
|
PromiseFlatString(aURI).get(), nullptr,
|
|
|
|
&didDisplayLoadError);
|
|
|
|
} else {
|
2019-12-12 05:32:00 +03:00
|
|
|
if (ContentParent* cp = Canonical()->GetContentParent()) {
|
|
|
|
Unused << cp->SendDisplayLoadError(this, PromiseFlatString(aURI));
|
|
|
|
}
|
2019-10-11 05:27:07 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-11 22:32:09 +03:00
|
|
|
WindowProxyHolder BrowsingContext::Window() {
|
|
|
|
return WindowProxyHolder(Self());
|
|
|
|
}
|
|
|
|
|
|
|
|
WindowProxyHolder BrowsingContext::GetFrames(ErrorResult& aError) {
|
|
|
|
return Window();
|
|
|
|
}
|
|
|
|
|
2019-01-02 16:29:18 +03:00
|
|
|
void BrowsingContext::Close(CallerType aCallerType, ErrorResult& aError) {
|
2019-12-12 05:31:55 +03:00
|
|
|
if (mIsDiscarded) {
|
|
|
|
return;
|
|
|
|
}
|
2020-01-20 17:57:47 +03:00
|
|
|
// FIXME We need to set the Closed field, but only once we're sending the
|
2019-01-02 16:29:18 +03:00
|
|
|
// 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.
|
2019-11-08 07:35:05 +03:00
|
|
|
if (GetDOMWindow()) {
|
|
|
|
nsGlobalWindowOuter::Cast(GetDOMWindow())
|
|
|
|
->CloseOuter(aCallerType == CallerType::System);
|
|
|
|
} else if (ContentChild* cc = ContentChild::GetSingleton()) {
|
2019-03-14 21:50:52 +03:00
|
|
|
cc->SendWindowClose(this, aCallerType == CallerType::System);
|
|
|
|
} else if (ContentParent* cp = Canonical()->GetContentParent()) {
|
|
|
|
Unused << cp->SendWindowClose(this, aCallerType == CallerType::System);
|
|
|
|
}
|
2019-01-02 16:29:18 +03:00
|
|
|
}
|
|
|
|
|
2020-01-16 17:38:40 +03:00
|
|
|
void BrowsingContext::Focus(CallerType aCallerType, ErrorResult& aError) {
|
2019-03-14 21:50:52 +03:00
|
|
|
if (ContentChild* cc = ContentChild::GetSingleton()) {
|
2020-01-16 17:38:40 +03:00
|
|
|
cc->SendWindowFocus(this, aCallerType);
|
2019-03-14 21:50:52 +03:00
|
|
|
} else if (ContentParent* cp = Canonical()->GetContentParent()) {
|
2020-01-16 17:38:40 +03:00
|
|
|
Unused << cp->SendWindowFocus(this, aCallerType);
|
2019-03-14 21:50:52 +03:00
|
|
|
}
|
2019-01-02 16:29:18 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void BrowsingContext::Blur(ErrorResult& aError) {
|
2019-03-14 21:50:52 +03:00
|
|
|
if (ContentChild* cc = ContentChild::GetSingleton()) {
|
|
|
|
cc->SendWindowBlur(this);
|
|
|
|
} else if (ContentParent* cp = Canonical()->GetContentParent()) {
|
|
|
|
Unused << cp->SendWindowBlur(this);
|
|
|
|
}
|
2019-01-02 16:29:18 +03:00
|
|
|
}
|
|
|
|
|
2019-10-05 00:50:34 +03:00
|
|
|
Nullable<WindowProxyHolder> BrowsingContext::GetWindow() {
|
|
|
|
if (XRE_IsParentProcess() && !IsInProcess()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return WindowProxyHolder(this);
|
|
|
|
}
|
|
|
|
|
2019-01-02 16:29:18 +03:00
|
|
|
Nullable<WindowProxyHolder> BrowsingContext::GetTop(ErrorResult& aError) {
|
2019-07-02 23:48:13 +03:00
|
|
|
if (mIsDiscarded) {
|
2019-04-17 03:53:09 +03:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2019-01-02 16:29:18 +03:00
|
|
|
// We never return null or throw an error, but the implementation in
|
|
|
|
// nsGlobalWindow does and we need to use the same signature.
|
2019-04-09 09:19:24 +03:00
|
|
|
return WindowProxyHolder(Top());
|
2019-01-02 16:29:18 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void BrowsingContext::GetOpener(JSContext* aCx,
|
|
|
|
JS::MutableHandle<JS::Value> aOpener,
|
|
|
|
ErrorResult& aError) const {
|
2019-03-14 21:51:11 +03:00
|
|
|
RefPtr<BrowsingContext> opener = GetOpener();
|
2019-01-02 16:29:18 +03:00
|
|
|
if (!opener) {
|
|
|
|
aOpener.setNull();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ToJSValue(aCx, WindowProxyHolder(opener), aOpener)) {
|
|
|
|
aError.NoteJSContextException(aCx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-17 03:53:05 +03:00
|
|
|
Nullable<WindowProxyHolder> BrowsingContext::GetParent(ErrorResult& aError) {
|
2019-07-02 23:48:13 +03:00
|
|
|
if (mIsDiscarded) {
|
2019-04-17 03:53:05 +03:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2019-01-02 16:29:18 +03:00
|
|
|
// We never throw an error, but the implementation in nsGlobalWindow does and
|
|
|
|
// we need to use the same signature.
|
|
|
|
if (!mParent) {
|
2019-04-17 03:53:05 +03:00
|
|
|
return WindowProxyHolder(this);
|
2019-01-02 16:29:18 +03:00
|
|
|
}
|
|
|
|
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) {
|
2019-10-09 17:20:23 +03:00
|
|
|
if (mIsDiscarded) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-01-02 16:29:18 +03:00
|
|
|
RefPtr<BrowsingContext> sourceBc;
|
|
|
|
PostMessageData data;
|
|
|
|
data.targetOrigin() = aTargetOrigin;
|
|
|
|
data.subjectPrincipal() = &aSubjectPrincipal;
|
|
|
|
RefPtr<nsGlobalWindowInner> callerInnerWindow;
|
2020-01-15 23:20:31 +03:00
|
|
|
nsAutoCString scriptLocation;
|
2019-10-23 10:19:48 +03:00
|
|
|
// We don't need to get the caller's agentClusterId since that is used for
|
2019-12-12 16:42:47 +03:00
|
|
|
// checking whether it's okay to sharing memory (and it's not allowed to share
|
2019-10-23 10:19:48 +03:00
|
|
|
// memory cross processes)
|
2019-01-02 16:29:18 +03:00
|
|
|
if (!nsGlobalWindowOuter::GatherPostMessageData(
|
|
|
|
aCx, aTargetOrigin, getter_AddRefs(sourceBc), data.origin(),
|
|
|
|
getter_AddRefs(data.targetOriginURI()),
|
|
|
|
getter_AddRefs(data.callerPrincipal()),
|
2020-01-15 23:20:31 +03:00
|
|
|
getter_AddRefs(callerInnerWindow), getter_AddRefs(data.callerURI()),
|
|
|
|
/* aCallerAgentClusterId */ nullptr, &scriptLocation, aError)) {
|
2019-01-02 16:29:18 +03:00
|
|
|
return;
|
|
|
|
}
|
2019-12-12 16:42:47 +03:00
|
|
|
if (sourceBc && sourceBc->IsDiscarded()) {
|
|
|
|
return;
|
|
|
|
}
|
2019-02-14 00:02:55 +03:00
|
|
|
data.source() = sourceBc;
|
2019-01-02 16:29:18 +03:00
|
|
|
data.isFromPrivateWindow() =
|
|
|
|
callerInnerWindow &&
|
|
|
|
nsScriptErrorBase::ComputeIsFromPrivateWindow(callerInnerWindow);
|
2020-01-15 23:20:31 +03:00
|
|
|
data.innerWindowId() = callerInnerWindow ? callerInnerWindow->WindowID() : 0;
|
|
|
|
data.scriptLocation() = scriptLocation;
|
2019-01-02 16:29:18 +03:00
|
|
|
JS::Rooted<JS::Value> transferArray(aCx);
|
|
|
|
aError = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransfer,
|
|
|
|
&transferArray);
|
|
|
|
if (NS_WARN_IF(aError.Failed())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ipc::StructuredCloneData message;
|
2020-02-06 16:46:25 +03:00
|
|
|
message.Write(aCx, aMessage, transferArray, JS::CloneDataPolicy(), aError);
|
2019-01-02 16:29:18 +03:00
|
|
|
if (NS_WARN_IF(aError.Failed())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ClonedMessageData messageData;
|
2019-03-14 21:50:52 +03:00
|
|
|
if (ContentChild* cc = ContentChild::GetSingleton()) {
|
|
|
|
if (!message.BuildClonedMessageDataForChild(cc, messageData)) {
|
|
|
|
aError.Throw(NS_ERROR_FAILURE);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cc->SendWindowPostMessage(this, messageData, data);
|
|
|
|
} else if (ContentParent* cp = Canonical()->GetContentParent()) {
|
|
|
|
if (!message.BuildClonedMessageDataForParent(cp, messageData)) {
|
|
|
|
aError.Throw(NS_ERROR_FAILURE);
|
|
|
|
return;
|
|
|
|
}
|
2019-01-02 16:29:18 +03:00
|
|
|
|
2019-03-14 21:50:52 +03:00
|
|
|
Unused << cp->SendWindowPostMessage(this, messageData, data);
|
|
|
|
}
|
2019-01-02 16:29:18 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2020-01-20 17:57:47 +03:00
|
|
|
void BrowsingContext::SendCommitTransaction(ContentParent* aParent,
|
|
|
|
const BaseTransaction& aTxn,
|
|
|
|
uint64_t aEpoch) {
|
|
|
|
Unused << aParent->SendCommitBrowsingContextTransaction(this, aTxn, aEpoch);
|
2019-08-09 17:51:30 +03:00
|
|
|
}
|
|
|
|
|
2020-01-20 17:57:47 +03:00
|
|
|
void BrowsingContext::SendCommitTransaction(ContentChild* aChild,
|
|
|
|
const BaseTransaction& aTxn,
|
|
|
|
uint64_t aEpoch) {
|
|
|
|
aChild->SendCommitBrowsingContextTransaction(this, aTxn, aEpoch);
|
2019-02-21 23:14:28 +03:00
|
|
|
}
|
|
|
|
|
2019-05-09 22:24:10 +03:00
|
|
|
BrowsingContext::IPCInitializer BrowsingContext::GetIPCInitializer() {
|
2019-09-20 07:43:46 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(mType == Type::Content);
|
2019-05-09 22:24:10 +03:00
|
|
|
|
|
|
|
IPCInitializer init;
|
|
|
|
init.mId = Id();
|
|
|
|
init.mParentId = mParent ? mParent->Id() : 0;
|
|
|
|
init.mCached = IsCached();
|
2020-01-20 17:57:47 +03:00
|
|
|
init.mFields = mFields.Fields();
|
2019-05-09 22:24:10 +03:00
|
|
|
return init;
|
|
|
|
}
|
|
|
|
|
2019-03-14 21:51:09 +03:00
|
|
|
already_AddRefed<BrowsingContext> BrowsingContext::IPCInitializer::GetParent() {
|
|
|
|
RefPtr<BrowsingContext> parent;
|
|
|
|
if (mParentId != 0) {
|
|
|
|
parent = BrowsingContext::Get(mParentId);
|
|
|
|
MOZ_RELEASE_ASSERT(parent);
|
|
|
|
}
|
|
|
|
return parent.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<BrowsingContext> BrowsingContext::IPCInitializer::GetOpener() {
|
|
|
|
RefPtr<BrowsingContext> opener;
|
2020-01-20 17:57:47 +03:00
|
|
|
if (GetOpenerId() != 0) {
|
|
|
|
opener = BrowsingContext::Get(GetOpenerId());
|
2019-03-14 21:51:09 +03:00
|
|
|
MOZ_RELEASE_ASSERT(opener);
|
|
|
|
}
|
|
|
|
return opener.forget();
|
|
|
|
}
|
|
|
|
|
2019-03-20 06:15:36 +03:00
|
|
|
void BrowsingContext::StartDelayedAutoplayMediaComponents() {
|
|
|
|
if (!mDocShell) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
AUTOPLAY_LOG("%s : StartDelayedAutoplayMediaComponents for bc 0x%08" PRIx64,
|
|
|
|
XRE_IsParentProcess() ? "Parent" : "Child", Id());
|
|
|
|
mDocShell->StartDelayedAutoplayMediaComponents();
|
|
|
|
}
|
|
|
|
|
2019-11-25 14:00:13 +03:00
|
|
|
void BrowsingContext::ResetGVAutoplayRequestStatus() {
|
2020-01-06 22:13:38 +03:00
|
|
|
MOZ_ASSERT(IsTop(),
|
2019-11-25 14:00:13 +03:00
|
|
|
"Should only set GVAudibleAutoplayRequestStatus in the top-level "
|
|
|
|
"browsing context");
|
|
|
|
SetGVAudibleAutoplayRequestStatus(GVAutoplayRequestStatus::eUNKNOWN);
|
|
|
|
SetGVInaudibleAutoplayRequestStatus(GVAutoplayRequestStatus::eUNKNOWN);
|
|
|
|
}
|
|
|
|
|
2020-01-20 17:57:47 +03:00
|
|
|
void BrowsingContext::DidSet(FieldIndex<IDX_GVAudibleAutoplayRequestStatus>) {
|
2020-01-06 22:13:38 +03:00
|
|
|
MOZ_ASSERT(IsTop(),
|
2019-11-25 14:00:13 +03:00
|
|
|
"Should only set GVAudibleAutoplayRequestStatus in the top-level "
|
|
|
|
"browsing context");
|
|
|
|
}
|
|
|
|
|
2020-01-20 17:57:47 +03:00
|
|
|
void BrowsingContext::DidSet(FieldIndex<IDX_GVInaudibleAutoplayRequestStatus>) {
|
2020-01-06 22:13:38 +03:00
|
|
|
MOZ_ASSERT(IsTop(),
|
2019-11-25 14:00:13 +03:00
|
|
|
"Should only set GVAudibleAutoplayRequestStatus in the top-level "
|
|
|
|
"browsing context");
|
|
|
|
}
|
|
|
|
|
2020-01-20 17:57:47 +03:00
|
|
|
void BrowsingContext::DidSet(FieldIndex<IDX_UserActivationState>) {
|
2019-09-07 22:12:20 +03:00
|
|
|
MOZ_ASSERT_IF(!mIsInProcess, mUserGestureStart.IsNull());
|
2019-09-20 14:10:13 +03:00
|
|
|
USER_ACTIVATION_LOG("Set user gesture activation %" PRIu8
|
|
|
|
" for %s browsing context 0x%08" PRIx64,
|
2020-01-20 17:57:47 +03:00
|
|
|
static_cast<uint8_t>(GetUserActivationState()),
|
2019-09-20 14:10:13 +03:00
|
|
|
XRE_IsParentProcess() ? "Parent" : "Child", Id());
|
2019-09-07 22:12:20 +03:00
|
|
|
if (mIsInProcess) {
|
|
|
|
USER_ACTIVATION_LOG(
|
|
|
|
"Set user gesture start time for %s browsing context 0x%08" PRIx64,
|
|
|
|
XRE_IsParentProcess() ? "Parent" : "Child", Id());
|
|
|
|
mUserGestureStart =
|
2020-01-20 17:57:47 +03:00
|
|
|
(GetUserActivationState() == UserActivation::State::FullActivated)
|
2019-09-20 14:10:13 +03:00
|
|
|
? TimeStamp::Now()
|
|
|
|
: TimeStamp();
|
2019-09-07 22:12:20 +03:00
|
|
|
}
|
2019-03-20 06:15:36 +03:00
|
|
|
}
|
|
|
|
|
2020-01-20 17:57:47 +03:00
|
|
|
void BrowsingContext::DidSet(FieldIndex<IDX_Muted>) {
|
2019-08-20 00:17:21 +03:00
|
|
|
MOZ_ASSERT(!mParent, "Set muted flag on non top-level context!");
|
|
|
|
USER_ACTIVATION_LOG("Set audio muted %d for %s browsing context 0x%08" PRIx64,
|
2020-01-20 17:57:47 +03:00
|
|
|
GetMuted(), XRE_IsParentProcess() ? "Parent" : "Child",
|
|
|
|
Id());
|
2019-08-20 00:17:21 +03:00
|
|
|
PreOrderWalk([&](BrowsingContext* aContext) {
|
|
|
|
nsPIDOMWindowOuter* win = aContext->GetDOMWindow();
|
|
|
|
if (win) {
|
|
|
|
win->RefreshMediaElementsVolume();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-01-20 17:57:47 +03:00
|
|
|
bool BrowsingContext::CanSet(FieldIndex<IDX_EmbedderInnerWindowId>,
|
|
|
|
const uint64_t& aValue, ContentParent* aSource) {
|
2019-09-26 19:16:32 +03:00
|
|
|
// Generally allow clearing this. We may want to be more precise about this
|
|
|
|
// check in the future.
|
|
|
|
if (aValue == 0) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we don't have a specified source, we're the setting process. The window
|
|
|
|
// which we're setting this to must be in-process.
|
|
|
|
RefPtr<BrowsingContext> impliedParent;
|
|
|
|
if (!aSource) {
|
|
|
|
nsGlobalWindowInner* innerWindow =
|
|
|
|
nsGlobalWindowInner::GetInnerWindowWithId(aValue);
|
|
|
|
if (NS_WARN_IF(!innerWindow)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
impliedParent = innerWindow->GetBrowsingContext();
|
|
|
|
}
|
|
|
|
|
|
|
|
// If in the parent process, double-check ownership and WindowGlobalParent as
|
|
|
|
// well.
|
|
|
|
if (XRE_IsParentProcess()) {
|
|
|
|
RefPtr<WindowGlobalParent> wgp =
|
|
|
|
WindowGlobalParent::GetByInnerWindowId(aValue);
|
|
|
|
if (NS_WARN_IF(!wgp)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Deduce the implied parent from the WindowGlobalParent actor.
|
|
|
|
if (impliedParent) {
|
|
|
|
MOZ_ASSERT(impliedParent == wgp->BrowsingContext());
|
|
|
|
}
|
|
|
|
impliedParent = wgp->BrowsingContext();
|
|
|
|
|
|
|
|
// Double-check ownership if we aren't the setter.
|
|
|
|
if (aSource &&
|
|
|
|
!impliedParent->Canonical()->IsOwnedByProcess(aSource->ChildID()) &&
|
|
|
|
aSource->ChildID() !=
|
|
|
|
impliedParent->Canonical()->GetInFlightProcessId()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we would have an invalid implied parent, something has gone wrong.
|
|
|
|
MOZ_ASSERT(impliedParent);
|
|
|
|
if (NS_WARN_IF(mParent && mParent != impliedParent)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-01-20 17:58:52 +03:00
|
|
|
bool BrowsingContext::CanSet(FieldIndex<IDX_CurrentInnerWindowId>,
|
|
|
|
const uint64_t& aValue, ContentParent* aSource) {
|
|
|
|
// Generally allow clearing this. We may want to be more precise about this
|
|
|
|
// check in the future.
|
|
|
|
if (aValue == 0) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aSource) {
|
|
|
|
MOZ_ASSERT(XRE_IsParentProcess());
|
|
|
|
|
|
|
|
// If in the parent process, double-check ownership and WindowGlobalParent
|
|
|
|
// as well.
|
|
|
|
RefPtr<WindowGlobalParent> wgp =
|
|
|
|
WindowGlobalParent::GetByInnerWindowId(aValue);
|
|
|
|
if (NS_WARN_IF(!wgp) || NS_WARN_IF(wgp->BrowsingContext() != this)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Double-check ownership if we aren't the setter.
|
|
|
|
if (!Canonical()->IsOwnedByProcess(aSource->ChildID()) &&
|
|
|
|
aSource->ChildID() != Canonical()->GetInFlightProcessId()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// We must have access to the specified context.
|
|
|
|
RefPtr<WindowContext> window = WindowContext::GetById(aValue);
|
|
|
|
return window && window->GetBrowsingContext() == this;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BrowsingContext::DidSet(FieldIndex<IDX_CurrentInnerWindowId>) {
|
|
|
|
mCurrentWindowContext = WindowContext::GetById(GetCurrentInnerWindowId());
|
|
|
|
}
|
|
|
|
|
2020-01-20 17:57:47 +03:00
|
|
|
bool BrowsingContext::CanSet(FieldIndex<IDX_IsPopupSpam>, const bool& aValue,
|
|
|
|
ContentParent* aSource) {
|
2019-10-18 06:04:55 +03:00
|
|
|
// Ensure that we only mark a browsing context as popup spam once and never
|
|
|
|
// unmark it.
|
2020-01-20 17:57:47 +03:00
|
|
|
return aValue && !GetIsPopupSpam();
|
2019-10-18 06:04:55 +03:00
|
|
|
}
|
|
|
|
|
2020-01-20 17:57:47 +03:00
|
|
|
void BrowsingContext::DidSet(FieldIndex<IDX_IsPopupSpam>) {
|
|
|
|
if (GetIsPopupSpam()) {
|
2019-10-18 06:04:55 +03:00
|
|
|
PopupBlocker::RegisterOpenPopupSpam();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-01 00:13:54 +03:00
|
|
|
bool BrowsingContext::IsLoading() {
|
|
|
|
if (GetLoading()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we're in the same process as the page, we're possibly just
|
|
|
|
// updating the flag.
|
|
|
|
nsIDocShell* shell = GetDocShell();
|
|
|
|
if (shell) {
|
|
|
|
Document* doc = shell->GetDocument();
|
|
|
|
return doc && doc->GetReadyStateEnum() < Document::READYSTATE_COMPLETE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-01-20 17:57:47 +03:00
|
|
|
void BrowsingContext::DidSet(FieldIndex<IDX_Loading>) {
|
|
|
|
if (mFields.Get<IDX_Loading>()) {
|
2019-12-01 00:13:54 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (!mDeprioritizedLoadRunner.isEmpty()) {
|
|
|
|
nsCOMPtr<nsIRunnable> runner = mDeprioritizedLoadRunner.popFirst();
|
|
|
|
NS_DispatchToCurrentThread(runner.forget());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (StaticPrefs::dom_separate_event_queue_for_post_message_enabled() &&
|
|
|
|
Top() == this) {
|
|
|
|
Group()->FlushPostMessageEvents();
|
2019-12-01 00:13:24 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-20 17:57:47 +03:00
|
|
|
// Inform the Document for this context of the (potential) change in
|
|
|
|
// loading state
|
|
|
|
void BrowsingContext::DidSet(FieldIndex<IDX_AncestorLoading>) {
|
|
|
|
nsPIDOMWindowOuter* outer = GetDOMWindow();
|
|
|
|
if (!outer) {
|
|
|
|
MOZ_LOG(gTimeoutDeferralLog, mozilla::LogLevel::Debug,
|
|
|
|
("DidSetAncestorLoading BC: %p -- No outer window", (void*)this));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Document* document = nsGlobalWindowOuter::Cast(outer)->GetExtantDoc();
|
|
|
|
if (document) {
|
|
|
|
MOZ_LOG(gTimeoutDeferralLog, mozilla::LogLevel::Debug,
|
|
|
|
("DidSetAncestorLoading BC: %p -- NotifyLoading(%d, %d, %d)",
|
|
|
|
(void*)this, GetAncestorLoading(), document->GetReadyStateEnum(),
|
|
|
|
document->GetReadyStateEnum()));
|
|
|
|
document->NotifyLoading(GetAncestorLoading(), document->GetReadyStateEnum(),
|
|
|
|
document->GetReadyStateEnum());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-01 00:13:24 +03:00
|
|
|
void BrowsingContext::AddDeprioritizedLoadRunner(nsIRunnable* aRunner) {
|
2019-12-01 00:13:54 +03:00
|
|
|
MOZ_ASSERT(IsLoading());
|
2019-12-01 00:13:24 +03:00
|
|
|
MOZ_ASSERT(Top() == this);
|
|
|
|
|
|
|
|
RefPtr<DeprioritizedLoadRunner> runner = new DeprioritizedLoadRunner(aRunner);
|
|
|
|
mDeprioritizedLoadRunner.insertBack(runner);
|
|
|
|
NS_DispatchToCurrentThreadQueue(
|
|
|
|
runner.forget(), StaticPrefs::page_load_deprioritization_period(),
|
|
|
|
EventQueuePriority::Idle);
|
|
|
|
}
|
|
|
|
|
2018-07-26 10:31:00 +03:00
|
|
|
} // namespace dom
|
2019-02-14 00:02:53 +03:00
|
|
|
|
|
|
|
namespace ipc {
|
|
|
|
|
2019-05-21 20:04:39 +03:00
|
|
|
void IPDLParamTraits<dom::BrowsingContext*>::Write(
|
2019-02-14 00:02:53 +03:00
|
|
|
IPC::Message* aMsg, IProtocol* aActor, dom::BrowsingContext* aParam) {
|
|
|
|
uint64_t id = aParam ? aParam->Id() : 0;
|
|
|
|
WriteIPDLParam(aMsg, aActor, id);
|
2019-07-15 23:44:57 +03:00
|
|
|
if (!aParam) {
|
|
|
|
return;
|
|
|
|
}
|
2019-02-14 00:02:53 +03:00
|
|
|
|
2019-07-15 23:44:57 +03:00
|
|
|
// Make sure that the other side will still have our BrowsingContext around
|
|
|
|
// when it tries to perform deserialization.
|
|
|
|
if (aActor->GetIPCChannel()->IsCrossProcess()) {
|
|
|
|
// If we're sending the message between processes, we only know the other
|
|
|
|
// side will still have a copy if we've not been discarded yet. As
|
|
|
|
// serialization cannot fail softly, fail loudly by crashing.
|
|
|
|
MOZ_RELEASE_ASSERT(
|
|
|
|
!aParam->IsDiscarded(),
|
|
|
|
"Cannot send discarded BrowsingContext between processes!");
|
|
|
|
} else {
|
|
|
|
// If we're in-process, we can take an extra reference to ensure it lives
|
|
|
|
// long enough to make it to the other side. This reference is freed in
|
|
|
|
// `::Read()`.
|
|
|
|
aParam->AddRef();
|
2019-02-14 00:02:53 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-21 20:04:39 +03:00
|
|
|
bool IPDLParamTraits<dom::BrowsingContext*>::Read(
|
2019-02-14 00:02:53 +03:00
|
|
|
const IPC::Message* aMsg, PickleIterator* aIter, IProtocol* aActor,
|
|
|
|
RefPtr<dom::BrowsingContext>* aResult) {
|
|
|
|
uint64_t id = 0;
|
|
|
|
if (!ReadIPDLParam(aMsg, aIter, aActor, &id)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (id == 0) {
|
2019-04-15 17:52:11 +03:00
|
|
|
*aResult = nullptr;
|
2019-02-14 00:02:53 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-07-15 23:44:57 +03:00
|
|
|
RefPtr<dom::BrowsingContext> browsingContext = dom::BrowsingContext::Get(id);
|
|
|
|
if (!browsingContext) {
|
2020-01-07 21:58:06 +03:00
|
|
|
#ifndef FUZZING
|
2019-07-15 23:44:57 +03:00
|
|
|
// NOTE: We could fail softly by returning `false` if the `BrowsingContext`
|
|
|
|
// isn't present, but doing so will cause a crash anyway. Let's improve
|
|
|
|
// diagnostics by reliably crashing here.
|
|
|
|
//
|
|
|
|
// If we can recover from failures to deserialize in the future, this crash
|
|
|
|
// should be removed or modified.
|
|
|
|
MOZ_CRASH("Attempt to deserialize absent BrowsingContext");
|
2020-01-07 21:58:06 +03:00
|
|
|
#endif
|
2019-07-15 23:44:57 +03:00
|
|
|
*aResult = nullptr;
|
|
|
|
return false;
|
|
|
|
}
|
2019-02-14 00:02:53 +03:00
|
|
|
|
|
|
|
if (!aActor->GetIPCChannel()->IsCrossProcess()) {
|
2019-07-15 23:44:57 +03:00
|
|
|
// Release the reference taken in `::Write()` for in-process actors.
|
|
|
|
browsingContext.get()->Release();
|
2019-02-14 00:02:53 +03:00
|
|
|
}
|
|
|
|
|
2019-07-15 23:44:57 +03:00
|
|
|
*aResult = browsingContext.forget();
|
|
|
|
return true;
|
2019-02-14 00:02:53 +03:00
|
|
|
}
|
|
|
|
|
2019-03-14 21:51:09 +03:00
|
|
|
void IPDLParamTraits<dom::BrowsingContext::IPCInitializer>::Write(
|
|
|
|
IPC::Message* aMessage, IProtocol* aActor,
|
|
|
|
const dom::BrowsingContext::IPCInitializer& aInit) {
|
|
|
|
// Write actor ID parameters.
|
|
|
|
WriteIPDLParam(aMessage, aActor, aInit.mId);
|
|
|
|
WriteIPDLParam(aMessage, aActor, aInit.mParentId);
|
2019-04-29 10:01:50 +03:00
|
|
|
WriteIPDLParam(aMessage, aActor, aInit.mCached);
|
2020-01-20 17:57:47 +03:00
|
|
|
WriteIPDLParam(aMessage, aActor, aInit.mFields);
|
2019-03-14 21:51:09 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
bool IPDLParamTraits<dom::BrowsingContext::IPCInitializer>::Read(
|
|
|
|
const IPC::Message* aMessage, PickleIterator* aIterator, IProtocol* aActor,
|
|
|
|
dom::BrowsingContext::IPCInitializer* aInit) {
|
|
|
|
// Read actor ID parameters.
|
|
|
|
if (!ReadIPDLParam(aMessage, aIterator, aActor, &aInit->mId) ||
|
2020-01-20 17:57:47 +03:00
|
|
|
!ReadIPDLParam(aMessage, aIterator, aActor, &aInit->mParentId) ||
|
|
|
|
!ReadIPDLParam(aMessage, aIterator, aActor, &aInit->mCached) ||
|
|
|
|
!ReadIPDLParam(aMessage, aIterator, aActor, &aInit->mFields)) {
|
2019-04-29 10:01:50 +03:00
|
|
|
return false;
|
|
|
|
}
|
2019-03-14 21:51:09 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-01-20 17:57:47 +03:00
|
|
|
template struct IPDLParamTraits<dom::BrowsingContext::BaseTransaction>;
|
|
|
|
|
2019-02-14 00:02:53 +03:00
|
|
|
} // namespace ipc
|
2018-07-26 10:31:00 +03:00
|
|
|
} // namespace mozilla
|