/* -*- 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/. */
// Allow serialization and deserialization of TouchEventsOverride over IPC template <> struct ParamTraits<mozilla::dom::TouchEventsOverride>
: public mozilla::dom::WebIDLEnumSerializer<
mozilla::dom::TouchEventsOverride> {};
template <> struct ParamTraits<mozilla::dom::EmbedderColorSchemes> { using paramType = mozilla::dom::EmbedderColorSchemes;
// Explicit specialization of the `Transaction` type. Required by the `extern // template class` declaration in the header. templateclass syncedcontext::Transaction<BrowsingContext>;
// All BrowsingContexts indexed by Id static StaticAutoPtr<BrowsingContextMap> sBrowsingContexts; // Top-level Content BrowsingContexts only, indexed by BrowserId instead of Id static StaticAutoPtr<BrowsingContextMap> sCurrentTopByBrowserId;
// Avoids an extra lookup auto browserIdEntry =
sCurrentTopByBrowserId->Lookup(aBrowsingContext->BrowserId()); if (browserIdEntry && browserIdEntry.Data() == aBrowsingContext) {
browserIdEntry.Remove();
}
}
bool BrowsingContext::SameOriginWithTop() {
MOZ_ASSERT(IsInProcess()); // If the top BrowsingContext is not same-process to us, it is cross-origin if (!Top()->IsInProcess()) { returnfalse;
}
nsIDocShell* docShell = GetDocShell(); if (!docShell) { returnfalse;
}
Document* doc = docShell->GetDocument(); if (!doc) { returnfalse;
}
nsIPrincipal* principal = doc->NodePrincipal();
// Determine which BrowsingContextGroup this context should be created in.
RefPtr<BrowsingContextGroup> group = aSpecificGroup; if (aType == Type::Chrome) {
MOZ_DIAGNOSTIC_ASSERT(!group);
group = BrowsingContextGroup::GetChromeGroup();
} elseif (!group) {
group = BrowsingContextGroup::Select(parentWC, aOpener);
}
if (aOpener) {
MOZ_DIAGNOSTIC_ASSERT(!aParent, "new BC with both initial opener and parent");
MOZ_DIAGNOSTIC_ASSERT(aOpener->Group() == group);
MOZ_DIAGNOSTIC_ASSERT(aOpener->mType == aType);
fields.Get<IDX_OpenerId>() = aOpener->Id();
fields.Get<IDX_HadOriginalOpener>() = true;
if (aType == Type::Chrome && !aParent) { // See SetOpener for why we do this inheritance.
fields.Get<IDX_PrefersColorSchemeOverride>() =
aOpener->Top()->GetPrefersColorSchemeOverride();
}
}
if (aParent) {
MOZ_DIAGNOSTIC_ASSERT(parentBC->Group() == group);
MOZ_DIAGNOSTIC_ASSERT(parentBC->mType == aType);
fields.Get<IDX_EmbedderInnerWindowId>() = aParent->WindowID(); // Non-toplevel content documents are always embededed within content.
fields.Get<IDX_EmbeddedInContentDocument>() =
parentBC->mType == Type::Content;
// XXX(farre): Can/Should we check aParent->IsLoading() here? (Bug // 1608448) Check if the parent was itself loading already auto readystate = aParent->GetDocument()->GetReadyStateEnum();
fields.Get<IDX_AncestorLoading>() =
parentBC->GetAncestorLoading() ||
readystate == Document::ReadyState::READYSTATE_LOADING ||
readystate == Document::ReadyState::READYSTATE_INTERACTIVE;
}
fields.Get<IDX_OpenerPolicy>() = nsILoadInfo::OPENER_POLICY_UNSAFE_NONE; if (aOpener && aOpener->SameOriginWithTop()) { // We inherit the opener policy if there is a creator and if the creator's // origin is same origin with the creator's top-level origin. // If it is cross origin we should not inherit the CrossOriginOpenerPolicy
fields.Get<IDX_OpenerPolicy>() = aOpener->Top()->GetOpenerPolicy();
// If we inherit a policy which is potentially cross-origin isolated, we // must be in a potentially cross-origin isolated BCG. bool isPotentiallyCrossOriginIsolated =
fields.Get<IDX_OpenerPolicy>() ==
nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP;
MOZ_RELEASE_ASSERT(isPotentiallyCrossOriginIsolated ==
group->IsPotentiallyCrossOriginIsolated());
} elseif (aOpener) { // They are not same origin auto topPolicy = aOpener->Top()->GetOpenerPolicy();
MOZ_RELEASE_ASSERT(
topPolicy == nsILoadInfo::OPENER_POLICY_UNSAFE_NONE ||
topPolicy == nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_ALLOW_POPUPS ||
aOptions.isForPrinting); if (aOptions.isForPrinting) { // Ensure our opener policy is consistent for printing for our top.
fields.Get<IDX_OpenerPolicy>() = topPolicy;
}
} elseif (!aParent && group->IsPotentiallyCrossOriginIsolated()) { // If we're creating a brand-new toplevel BC in a potentially cross-origin // isolated group, it should start out with a strict opener policy.
fields.Get<IDX_OpenerPolicy>() =
nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP;
}
fields.Get<IDX_HistoryID>() = nsID::GenerateUUID();
fields.Get<IDX_ExplicitActive>() = [&] { if (parentBC || aType == Type::Content) { // Non-root browsing-contexts inherit their status from its parent. // Top-content either gets managed by the top chrome, or gets manually // managed by the front-end (see ManuallyManagesActiveness). In any case // we want to start off as inactive. return ExplicitActiveStatus::None;
} // Chrome starts as active. return ExplicitActiveStatus::Active;
}();
// Assume top allows fullscreen for its children unless otherwise stated. // Subframes start with it false unless otherwise noted in SetEmbedderElement.
fields.Get<IDX_FullscreenAllowedByOwner>() = !aParent;
already_AddRefed<BrowsingContext> BrowsingContext::CreateIndependent(
Type aType, bool aWindowless) {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess(), "BCs created in the content process must be related to " "some BrowserChild");
RefPtr<BrowsingContext> bc(
CreateDetached(nullptr, nullptr, nullptr, u""_ns, aType, {}));
bc->mWindowless = aWindowless;
bc->mEmbeddedByThisProcess = true;
bc->EnsureAttached(); return bc.forget();
}
void BrowsingContext::EnsureAttached() { if (!mEverAttached) { Register(this);
// Attach the browsing context to the tree.
Attach(/* aFromIPC */ false, /* aOriginProcess */ nullptr);
}
}
RefPtr<BrowsingContext> context; if (XRE_IsParentProcess()) { // If the new BrowsingContext has a parent, it is a sub-frame embedded in // whatever process sent the message. If it doesn't, and is not windowless, // it is a new window or tab, and will be embedded in the parent process.
uint64_t embedderProcessId = (aInit.mWindowless || parent) ? originId : 0;
context = new CanonicalBrowsingContext(parent, aGroup, aInit.mId, originId,
embedderProcessId, Type::Content,
std::move(aInit.mFields));
} else {
context = new BrowsingContext(parent, aGroup, aInit.mId, Type::Content,
std::move(aInit.mFields));
}
// NOTE: Call through the `Set` methods for these values to ensure that any // relevant process-local state is also updated.
context->SetOriginAttributes(aInit.mOriginAttributes);
context->SetRemoteTabs(aInit.mUseRemoteTabs);
context->SetRemoteSubframes(aInit.mUseRemoteSubframes);
context->mRequestContextId = aInit.mRequestContextId; // NOTE: Private browsing ID is set by `SetOriginAttributes`.
if (constchar* failure =
context->BrowsingContextCoherencyChecks(aOriginProcess)) {
mozilla::ipc::IProtocol* actor = aOriginProcess; if (!actor) {
actor = ContentChild::GetSingleton();
} return IPC_FAIL_UNSAFE_PRINTF(actor, "Incoherent BrowsingContext: %s",
failure);
}
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.
MOZ_DIAGNOSTIC_ASSERT(mEverAttached);
MOZ_RELEASE_ASSERT(aDocShell->GetBrowsingContext() == this);
mDocShell = aDocShell;
mDanglingRemoteOuterProxies = !mIsInProcess;
mIsInProcess = true; if (mChildSessionHistory) {
mChildSessionHistory->SetIsInProcess(true);
}
// 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) {}
bool BrowsingContext::IsActive() const { const BrowsingContext* current = this; do { auto explicit_ = current->GetExplicitActive(); if (explicit_ != ExplicitActiveStatus::None) { return explicit_ == ExplicitActiveStatus::Active;
} if (mParentWindow && !mParentWindow->IsCurrent()) { returnfalse;
}
} while ((current = current->GetParent()));
returnfalse;
}
bool BrowsingContext::GetIsActiveBrowserWindow() { if (!XRE_IsParentProcess()) { return Top()->GetIsActiveBrowserWindowInternal();
}
// chrome:// urls loaded in the parent won't receive // their own activation so we defer to the top chrome // Browsing Context when in the parent process. return Canonical()
->TopCrossChromeBoundary()
->GetIsActiveBrowserWindowInternal();
}
// Update embedder-element-specific fields in a shared transaction. // Don't do this when clearing our embedder, as we're being destroyed either // way. if (aEmbedder) {
Transaction txn;
txn.SetEmbedderElementType(Some(aEmbedder->LocalName()));
txn.SetEmbeddedInContentDocument(
aEmbedder->OwnerDoc()->IsContentDocument()); if (nsCOMPtr<nsPIDOMWindowInner> inner =
do_QueryInterface(aEmbedder->GetOwnerGlobal())) {
txn.SetEmbedderInnerWindowId(inner->WindowID());
}
txn.SetFullscreenAllowedByOwner(OwnerAllowsFullscreen(*aEmbedder)); if (XRE_IsParentProcess() && aEmbedder->IsXULElement() && IsTopContent()) {
nsAutoString messageManagerGroup;
aEmbedder->GetAttr(nsGkAtoms::messagemanagergroup, messageManagerGroup);
txn.SetMessageManagerGroup(messageManagerGroup);
txn.SetUseGlobalHistory(
!aEmbedder->HasAttr(nsGkAtoms::disableglobalhistory)); if (!aEmbedder->HasAttr(nsGkAtoms::manualactiveness)) { // We're active iff the parent cross-chrome-boundary is active. Note we // can't just use this->Canonical()->GetParentCrossChromeBoundary here, // since mEmbedderElement is still null at this point.
RefPtr bc = aEmbedder->OwnerDoc()->GetBrowsingContext(); constbool isActive = bc && bc->IsActive();
txn.SetExplicitActive(isActive ? ExplicitActiveStatus::Active
: ExplicitActiveStatus::Inactive); if (auto* bp = Canonical()->GetBrowserParent()) {
bp->SetRenderLayers(isActive);
}
}
}
MOZ_ALWAYS_SUCCEEDS(txn.Commit(this));
}
if (XRE_IsParentProcess() && IsTopContent()) {
Canonical()->MaybeSetPermanentKey(aEmbedder);
}
mEmbedderElement = aEmbedder;
if (mEmbedderElement) { if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
obs->NotifyWhenScriptSafe(ToSupports(this), "browsing-context-did-set-embedder", nullptr);
}
if (IsEmbedderTypeObjectOrEmbed()) {
Unused << SetIsSyntheticDocumentContainer(true);
}
}
}
bool BrowsingContext::IsEmbedderTypeObjectOrEmbed() { if (const Maybe<nsString>& type = GetEmbedderElementType()) { return nsGkAtoms::object->Equals(*type) || nsGkAtoms::embed->Equals(*type);
} returnfalse;
}
// LoadContext should generally match our opener or parent. if (IsContent()) { if (RefPtr<BrowsingContext> opener = GetOpener()) {
COHERENCY_ASSERT(opener->mType == mType);
COHERENCY_ASSERT(opener->mGroup == mGroup);
COHERENCY_ASSERT(opener->mUseRemoteTabs == mUseRemoteTabs);
COHERENCY_ASSERT(opener->mUseRemoteSubframes == mUseRemoteSubframes);
COHERENCY_ASSERT(opener->mPrivateBrowsingId == mPrivateBrowsingId);
COHERENCY_ASSERT(
opener->mOriginAttributes.EqualsIgnoringFPD(mOriginAttributes));
}
} if (RefPtr<BrowsingContext> parent = GetParent()) {
COHERENCY_ASSERT(parent->mType == mType);
COHERENCY_ASSERT(parent->mGroup == mGroup);
COHERENCY_ASSERT(parent->mUseRemoteTabs == mUseRemoteTabs);
COHERENCY_ASSERT(parent->mUseRemoteSubframes == mUseRemoteSubframes);
COHERENCY_ASSERT(parent->mPrivateBrowsingId == mPrivateBrowsingId);
COHERENCY_ASSERT(
parent->mOriginAttributes.EqualsIgnoringFPD(mOriginAttributes));
}
// UseRemoteSubframes and UseRemoteTabs must match. if (mUseRemoteSubframes && !mUseRemoteTabs) { return"Cannot set useRemoteSubframes without also setting useRemoteTabs";
}
// Double-check OriginAttributes/Private Browsing // Chrome browsing contexts must not have a private browsing OriginAttribute // Content browsing contexts must maintain the equality: // mOriginAttributes.mPrivateBrowsingId == mPrivateBrowsingId if (IsChrome()) {
COHERENCY_ASSERT(mOriginAttributes.mPrivateBrowsingId == 0);
} else {
COHERENCY_ASSERT(mOriginAttributes.mPrivateBrowsingId ==
mPrivateBrowsingId);
} #undef COHERENCY_ASSERT
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED // We'll already have checked this if `aFromIPC` is set before calling this // function. if (!aFromIPC) { if (constchar* failure = BrowsingContextCoherencyChecks(aOriginProcess)) {
MOZ_CRASH_UNSAFE_PRINTF("Incoherent BrowsingContext: %s", failure);
}
} #endif
// Add ourselves either to our parent or BrowsingContextGroup's child list. // Important: We shouldn't return IPC_FAIL after this point, since the // BrowsingContext will have already been added to the tree. if (mParentWindow) { if (!aFromIPC) {
MOZ_DIAGNOSTIC_ASSERT(!mParentWindow->IsDiscarded(), "local attach in discarded window");
MOZ_DIAGNOSTIC_ASSERT(!GetParent()->IsDiscarded(), "local attach call in discarded bc");
MOZ_DIAGNOSTIC_ASSERT(mParentWindow->GetWindowGlobalChild(), "local attach call with oop parent window");
MOZ_DIAGNOSTIC_ASSERT(mParentWindow->GetWindowGlobalChild()->CanSend(), "local attach call with dead parent window");
}
mChildOffset =
mCreatedDynamically ? -1 : mParentWindow->Children().Length();
mParentWindow->AppendChildBrowsingContext(this);
RecomputeCanExecuteScripts();
} else {
mGroup->Toplevels().AppendElement(this);
}
if (GetIsPopupSpam()) {
PopupBlocker::RegisterOpenPopupSpam();
}
if (IsTop() && GetHasSessionHistory() && !mChildSessionHistory) {
CreateChildSHistory();
}
// Why the context is being attached. This will always be "attach" in the // content process, but may be "replace" if it's known the context being // replaced in the parent process. const char16_t* why = u"attach";
if (XRE_IsContentProcess() && !aFromIPC) { // Send attach to our parent if we need to.
ContentChild::GetSingleton()->SendCreateBrowsingContext(
mGroup->Id(), GetIPCInitializer());
} elseif (XRE_IsParentProcess()) { // If this window was created as a subframe by a content process, it must be // being hosted within the same BrowserParent as its mParentWindow. // Toplevel BrowsingContexts created by content have their BrowserParent // configured during `RecvConstructPopupBrowser`. if (mParentWindow && aOriginProcess) {
MOZ_DIAGNOSTIC_ASSERT(
mParentWindow->Canonical()->GetContentParent() == aOriginProcess, "Creator process isn't the same as our embedder?");
Canonical()->SetCurrentBrowserParent(
mParentWindow->Canonical()->GetBrowserParent());
}
mGroup->EachOtherParent(aOriginProcess, [&](ContentParent* aParent) {
MOZ_DIAGNOSTIC_ASSERT(IsContent(), "chrome BCG cannot be synced to content process"); if (!Canonical()->IsEmbeddedInProcess(aParent->ChildID())) {
Unused << aParent->SendCreateBrowsingContext(mGroup->Id(),
GetIPCInitializer());
}
});
// We want to create a BrowsingContextWebProgress for all content // BrowsingContexts. if (IsContent() && !Canonical()->mWebProgress) {
Canonical()->mWebProgress = new BrowsingContextWebProgress(Canonical());
}
}
if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
obs->NotifyWhenScriptSafe(ToSupports(this), "browsing-context-attached",
why);
}
if (XRE_IsParentProcess()) {
Canonical()->CanonicalAttach();
}
}
if (XRE_IsParentProcess()) {
Canonical()->AddPendingDiscard();
} auto callListeners =
MakeScopeExit([&, listeners = std::move(mDiscardListeners), id = Id()] { for (constauto& listener : listeners) {
listener(id);
} if (XRE_IsParentProcess()) {
Canonical()->RemovePendingDiscard();
}
});
nsCOMPtr<nsIRequestContextService> rcsvc =
net::RequestContextService::GetOrCreate(); if (rcsvc) {
rcsvc->RemoveRequestContext(GetRequestContextId());
}
// This will only ever be null if the cycle-collector has unlinked us. Don't // try to detach ourselves in that case. if (NS_WARN_IF(!mGroup)) {
MOZ_ASSERT_UNREACHABLE(); return;
}
if (mParentWindow) {
mParentWindow->RemoveChildBrowsingContext(this);
} else {
mGroup->Toplevels().RemoveElement(this);
}
if (XRE_IsParentProcess()) {
RefPtr<CanonicalBrowsingContext> self{Canonical()};
Group()->EachParent([&](ContentParent* aParent) { // Only the embedder process is allowed to initiate a BrowsingContext // detach, so if we've gotten here, the host process already knows we've // been detached, and there's no need to tell it again. // // If the owner process is not the same as the embedder process, its // BrowsingContext will be detached when its nsWebBrowser instance is // destroyed. bool doDiscard = !Canonical()->IsEmbeddedInProcess(aParent->ChildID()) &&
!Canonical()->IsOwnedByProcess(aParent->ChildID());
// Hold a strong reference to ourself, and keep our BrowsingContextGroup // alive, until the responses comes back to ensure we don't die while // messages relating to this context are in-flight. // // When the callback is called, the keepalive on our group will be // destroyed, and the reference to the BrowsingContext will be dropped, // which may cause it to be fully destroyed.
mGroup->AddKeepAlive();
self->AddPendingDiscard(); auto callback = [self](auto) {
self->mGroup->RemoveKeepAlive();
self->RemovePendingDiscard();
};
aParent->SendDiscardBrowsingContext(this, doDiscard, callback, callback);
});
} else { // Hold a strong reference to ourself until the responses come back to // ensure the BrowsingContext isn't cleaned up before the parent process // acknowledges the discard request. auto callback = [self = RefPtr{this}](auto) {};
ContentChild::GetSingleton()->SendDiscardBrowsingContext( this, !aFromIPC, callback, callback);
}
if (XRE_IsParentProcess()) {
nsFocusManager* fm = nsFocusManager::GetFocusManager(); if (fm) {
fm->BrowsingContextDetached(this);
}
}
if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) { // Why the context is being discarded. This will always be "discard" in the // content process, but may be "replace" if it's known the context being // replaced in the parent process. const char16_t* why = u"discard"; if (XRE_IsParentProcess() && IsTop() && !Canonical()->GetWebProgress()) {
why = u"replace";
}
obs->NotifyObservers(ToSupports(this), "browsing-context-discarded", why);
}
// NOTE: Doesn't use SetClosed, as it will be set in all processes // automatically by calls to Detach()
mFields.SetWithoutSyncing<IDX_Closed>(true);
if (GetIsPopupSpam()) {
PopupBlocker::UnregisterOpenPopupSpam(); // NOTE: Doesn't use SetIsPopupSpam, as it will be set all processes // automatically.
mFields.SetWithoutSyncing<IDX_IsPopupSpam>(false);
}
AssertOriginAttributesMatchPrivateBrowsing();
if (XRE_IsParentProcess()) {
Canonical()->CanonicalDiscard();
}
}
// 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; if (mChildSessionHistory) { // This can be removed once session history is stored exclusively in the // parent process.
mChildSessionHistory->SetIsInProcess(false);
}
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);
}
if (IsChrome() && IsTop() && aOpener) { // Inherit color scheme overrides from parent window. This is to inherit the // color scheme of dark themed PBM windows in dialogs opened by such // windows. auto openerOverride = aOpener->Top()->PrefersColorSchemeOverride(); if (openerOverride != PrefersColorSchemeOverride()) {
MOZ_ALWAYS_SUCCEEDS(SetPrefersColorSchemeOverride(openerOverride));
}
}
}
// If the newly registered WindowContext is for our current inner window ID, // re-run the `DidSet` handler to re-establish the relationship. if (aWindow->InnerWindowId() == GetCurrentInnerWindowId()) {
DidSet(FieldIndex<IDX_CurrentInnerWindowId>());
MOZ_DIAGNOSTIC_ASSERT(mCurrentWindowContext == aWindow);
}
}
void BrowsingContext::UnregisterWindowContext(WindowContext* aWindow) {
MOZ_ASSERT(mWindowContexts.Contains(aWindow), "WindowContext not registered!");
mWindowContexts.RemoveElement(aWindow);
// If our currently active window was unregistered, clear our reference to it. if (aWindow == mCurrentWindowContext) { // Re-read our `CurrentInnerWindowId` value and use it to set // `mCurrentWindowContext`. As `aWindow` is now unregistered and discarded, // we won't find it, and the value will be cleared back to `nullptr`.
DidSet(FieldIndex<IDX_CurrentInnerWindowId>());
MOZ_DIAGNOSTIC_ASSERT(mCurrentWindowContext == nullptr);
}
}
BrowsingContext* BrowsingContext::FindChildWithName( const nsAString& aName, WindowGlobalChild& aRequestingWindow) { if (aName.IsEmpty()) { // You can't find a browsing context with the empty name. return nullptr;
}
for (BrowsingContext* child : NonSyntheticChildren()) { if (child->NameEquals(aName) && aRequestingWindow.CanNavigate(child) &&
child->IsTargetable()) { return child;
}
}
return nullptr;
}
BrowsingContext* BrowsingContext::FindWithSpecialName( const nsAString& aName, WindowGlobalChild& aRequestingWindow) { // 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")) { returnthis;
}
if (aName.LowerCaseEqualsLiteral("_parent")) { if (BrowsingContext* parent = GetParent()) { return aRequestingWindow.CanNavigate(parent) ? parent : nullptr;
} returnthis;
}
if (aName.LowerCaseEqualsLiteral("_top")) {
BrowsingContext* top = Top();
return aRequestingWindow.CanNavigate(top) ? top : nullptr;
}
for (BrowsingContext* child : NonSyntheticChildren()) { if (BrowsingContext* found =
child->FindWithNameInSubtree(aName, aRequestingWindow)) { return found;
}
}
return nullptr;
}
bool BrowsingContext::IsSandboxedFrom(BrowsingContext* aTarget) { // If no target then not sandboxed. if (!aTarget) { returnfalse;
}
// We cannot be sandboxed from ourselves. if (aTarget == this) { returnfalse;
}
// Default the sandbox flags to our flags, so that if we can't retrieve the // active document, we will still enforce our own.
uint32_t sandboxFlags = GetSandboxFlags(); if (mDocShell) { if (RefPtr<Document> doc = mDocShell->GetExtantDocument()) {
sandboxFlags = doc->GetSandboxFlags();
}
}
// If no flags, we are not sandboxed at all. if (!sandboxFlags) { returnfalse;
}
// If aTarget has an ancestor, it is not top level. if (RefPtr<BrowsingContext> ancestorOfTarget = aTarget->GetParent()) { do { // We are not sandboxed if we are an ancestor of target. if (ancestorOfTarget == this) { returnfalse;
}
ancestorOfTarget = ancestorOfTarget->GetParent();
} while (ancestorOfTarget);
// Otherwise, we are sandboxed from aTarget. returntrue;
}
// aTarget is top level, are we the "one permitted sandboxed // navigator", i.e. did we open aTarget? if (aTarget->GetOnePermittedSandboxedNavigatorId() == Id()) { returnfalse;
}
// If SANDBOXED_TOPLEVEL_NAVIGATION flag is not on, we are not sandboxed // from our top. if (!(sandboxFlags & SANDBOXED_TOPLEVEL_NAVIGATION) && aTarget == Top()) { returnfalse;
}
// If SANDBOXED_TOPLEVEL_NAVIGATION_USER_ACTIVATION flag is not on, we are not // sandboxed from our top if we have user interaction. We assume there is a // valid transient user gesture interaction if this check happens in the // target process given that we have checked in the triggering process // already. if (!(sandboxFlags & SANDBOXED_TOPLEVEL_NAVIGATION_USER_ACTIVATION) &&
mCurrentWindowContext &&
(!mCurrentWindowContext->IsInProcess() ||
mCurrentWindowContext->HasValidTransientUserGestureActivation()) &&
aTarget == Top()) { returnfalse;
}
// Otherwise, we are sandboxed from aTarget. returntrue;
}
RefPtr<SessionStorageManager> BrowsingContext::GetSessionStorageManager() {
RefPtr<SessionStorageManager>& manager = Top()->mSessionStorageManager; if (!manager) {
manager = new SessionStorageManager(this);
} return manager;
}
nsIPrincipal* BrowsingContext::GetSavedPrincipal(
Maybe<PrincipalWithLoadIdentifierTuple> aPrincipalTuple) { if (aPrincipalTuple) {
nsCOMPtr<nsIPrincipal> principal;
uint64_t loadIdentifier;
std::tie(principal, loadIdentifier) = *aPrincipalTuple; // We want to return a principal only if the load identifier for it // matches the current one for this BC. if (auto current = GetCurrentLoadIdentifier();
current && *current == loadIdentifier) { return principal;
}
} return nullptr;
}
if (sBrowsingContexts) {
AutoTArray<RefPtr<BrowsingContext>, 8> toDiscard; for (constauto& data : sBrowsingContexts->Values()) { auto* bc = data->Canonical(); if (!bc->IsDiscarded() && bc->IsEmbeddedInProcess(aCP->ChildID())) {
toDiscard.AppendElement(bc);
}
}
for (BrowsingContext* bc : toDiscard) {
bc->Detach(/* aFromIPC */ true);
}
}
}
// 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_CRASH( "We shouldn't be trying to decode a BrowsingContext " "on a background thread."); return nullptr;
}
JS::Rooted<JS::Value> 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();
}
bool BrowsingContext::CanSetOriginAttributes() { // A discarded BrowsingContext has already been destroyed, and cannot modify // its OriginAttributes. if (NS_WARN_IF(IsDiscarded())) { returnfalse;
}
// Before attaching is the safest time to set OriginAttributes, and the only // allowed time for content BrowsingContexts. if (!EverAttached()) { returntrue;
}
// Attached content BrowsingContexts may have been synced to other processes. if (NS_WARN_IF(IsContent())) {
MOZ_CRASH(); returnfalse;
}
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
// Cannot set OriginAttributes after we've created our child BrowsingContext. if (NS_WARN_IF(!Children().IsEmpty())) { returnfalse;
}
// Only allow setting OriginAttributes if we have no associated document, or // the document is still `about:blank`. // TODO: Bug 1273058 - should have no document when setting origin attributes. if (WindowGlobalParent* window = Canonical()->GetCurrentWindowGlobal()) { if (nsIURI* uri = window->GetDocumentURI()) {
MOZ_ASSERT(NS_IsAboutBlank(uri)); return NS_IsAboutBlank(uri);
}
} returntrue;
}
Nullable<WindowProxyHolder> BrowsingContext::GetAssociatedWindow() { // nsILoadContext usually only returns same-process windows, // so we intentionally return nullptr if this BC is out of // process. if (IsInProcess()) { return WindowProxyHolder(this);
} return nullptr;
}
NS_IMETHODIMP BrowsingContext::SetUsePrivateBrowsing(bool aUsePrivateBrowsing) { if (!CanSetOriginAttributes()) { bool changed = aUsePrivateBrowsing != (mPrivateBrowsingId > 0); if (changed) {
NS_WARNING("SetUsePrivateBrowsing when !CanSetOriginAttributes()");
} return changed ? NS_ERROR_FAILURE : NS_OK;
}
return SetPrivateBrowsing(aUsePrivateBrowsing);
}
NS_IMETHODIMP BrowsingContext::SetPrivateBrowsing(bool aPrivateBrowsing) { if (!CanSetOriginAttributes()) {
NS_WARNING("Attempt to set PrivateBrowsing when !CanSetOriginAttributes"); return NS_ERROR_FAILURE;
}
NS_IMETHODIMP BrowsingContext::SetRemoteTabs(bool aUseRemoteTabs) { if (!CanSetOriginAttributes()) {
NS_WARNING("Attempt to set RemoteTabs when !CanSetOriginAttributes"); return NS_ERROR_FAILURE;
}
if (aUseRemoteTabs && !gIPCEnabledAnnotation) {
gIPCEnabledAnnotation = true;
}
// Don't allow non-remote tabs with remote subframes. if (NS_WARN_IF(!aUseRemoteTabs && mUseRemoteSubframes)) { return NS_ERROR_UNEXPECTED;
}
NS_IMETHODIMP BrowsingContext::SetRemoteSubframes(bool aUseRemoteSubframes) { if (!CanSetOriginAttributes()) {
NS_WARNING("Attempt to set RemoteSubframes when !CanSetOriginAttributes"); return NS_ERROR_FAILURE;
}
if (aUseRemoteSubframes && !gFissionEnabledAnnotation) {
gFissionEnabledAnnotation = true;
}
// Don't allow non-remote tabs with remote subframes. if (NS_WARN_IF(aUseRemoteSubframes && !mUseRemoteTabs)) { return NS_ERROR_UNEXPECTED;
}
nsresult BrowsingContext::SetOriginAttributes(const OriginAttributes& aAttrs) { if (!CanSetOriginAttributes()) {
NS_WARNING("Attempt to set OriginAttributes when !CanSetOriginAttributes"); return NS_ERROR_FAILURE;
}
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BrowsingContext) if (sBrowsingContexts) {
sBrowsingContexts->Remove(tmp->Id());
}
UnregisterBrowserId(tmp);
if (tmp->GetIsPopupSpam()) {
PopupBlocker::UnregisterOpenPopupSpam(); // NOTE: Doesn't use SetIsPopupSpam, as it will be set all processes // automatically.
tmp->mFields.SetWithoutSyncing<IDX_IsPopupSpam>(false);
}
// Give RemoteLocationProxy 2 reserved slots, like the other wrappers, // so JSObject::swap can swap it with CrossCompartmentWrappers without requiring // malloc. template <> const JSClass RemoteLocationProxy::Base::sClass =
PROXY_CLASS_DEF("Proxy", JSCLASS_HAS_RESERVED_SLOTS(2));
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.