1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/BrowsingContext.h"
9 #include "ipc/IPCMessageUtils.h"
12 # include "mozilla/a11y/DocAccessibleParent.h"
13 # include "mozilla/a11y/Platform.h"
14 # include "nsAccessibilityService.h"
16 # include "mozilla/a11y/AccessibleWrap.h"
17 # include "mozilla/a11y/Compatibility.h"
18 # include "mozilla/a11y/nsWinUtils.h"
21 #include "mozilla/AppShutdown.h"
22 #include "mozilla/dom/CanonicalBrowsingContext.h"
23 #include "mozilla/dom/BrowserHost.h"
24 #include "mozilla/dom/BrowserChild.h"
25 #include "mozilla/dom/BrowserParent.h"
26 #include "mozilla/dom/BrowsingContextGroup.h"
27 #include "mozilla/dom/BrowsingContextBinding.h"
28 #include "mozilla/dom/ContentChild.h"
29 #include "mozilla/dom/ContentParent.h"
30 #include "mozilla/dom/Document.h"
31 #include "mozilla/dom/Element.h"
32 #include "mozilla/dom/HTMLEmbedElement.h"
33 #include "mozilla/dom/HTMLIFrameElement.h"
34 #include "mozilla/dom/Location.h"
35 #include "mozilla/dom/LocationBinding.h"
36 #include "mozilla/dom/MediaDevices.h"
37 #include "mozilla/dom/PopupBlocker.h"
38 #include "mozilla/dom/ScriptSettings.h"
39 #include "mozilla/dom/SessionStoreChild.h"
40 #include "mozilla/dom/SessionStorageManager.h"
41 #include "mozilla/dom/StructuredCloneTags.h"
42 #include "mozilla/dom/UserActivationIPCUtils.h"
43 #include "mozilla/dom/WindowBinding.h"
44 #include "mozilla/dom/WindowContext.h"
45 #include "mozilla/dom/WindowGlobalChild.h"
46 #include "mozilla/dom/WindowGlobalParent.h"
47 #include "mozilla/dom/WindowProxyHolder.h"
48 #include "mozilla/dom/SyncedContextInlines.h"
49 #include "mozilla/dom/XULFrameElement.h"
50 #include "mozilla/ipc/ProtocolUtils.h"
51 #include "mozilla/net/DocumentLoadListener.h"
52 #include "mozilla/net/RequestContextService.h"
53 #include "mozilla/Assertions.h"
54 #include "mozilla/AsyncEventDispatcher.h"
55 #include "mozilla/ClearOnShutdown.h"
56 #include "mozilla/Components.h"
57 #include "mozilla/HashTable.h"
58 #include "mozilla/Logging.h"
59 #include "mozilla/MediaFeatureChange.h"
60 #include "mozilla/ResultExtensions.h"
61 #include "mozilla/Services.h"
62 #include "mozilla/StaticPrefs_fission.h"
63 #include "mozilla/StaticPrefs_media.h"
64 #include "mozilla/StaticPrefs_page_load.h"
65 #include "mozilla/StaticPtr.h"
66 #include "mozilla/URLQueryStringStripper.h"
67 #include "mozilla/EventStateManager.h"
68 #include "nsIURIFixup.h"
69 #include "nsIXULRuntime.h"
71 #include "nsDocShell.h"
72 #include "nsDocShellLoadState.h"
73 #include "nsFocusManager.h"
74 #include "nsGlobalWindowInner.h"
75 #include "nsGlobalWindowOuter.h"
76 #include "PresShell.h"
77 #include "nsIObserverService.h"
78 #include "nsISHistory.h"
79 #include "nsContentUtils.h"
80 #include "nsQueryObject.h"
81 #include "nsSandboxFlags.h"
82 #include "nsScriptError.h"
83 #include "nsThreadUtils.h"
84 #include "xpcprivate.h"
86 #include "AutoplayPolicy.h"
87 #include "GVAutoplayRequestStatusIPC.h"
89 extern mozilla::LazyLogModule gAutoplayPermissionLog
;
90 extern mozilla::LazyLogModule gTimeoutDeferralLog
;
92 #define AUTOPLAY_LOG(msg, ...) \
93 MOZ_LOG(gAutoplayPermissionLog, LogLevel::Debug, (msg, ##__VA_ARGS__))
96 // Allow serialization and deserialization of OrientationType over IPC
98 struct ParamTraits
<mozilla::dom::OrientationType
>
99 : public ContiguousEnumSerializer
<
100 mozilla::dom::OrientationType
,
101 mozilla::dom::OrientationType::Portrait_primary
,
102 mozilla::dom::OrientationType::EndGuard_
> {};
105 struct ParamTraits
<mozilla::dom::DisplayMode
>
106 : public ContiguousEnumSerializer
<mozilla::dom::DisplayMode
,
107 mozilla::dom::DisplayMode::Browser
,
108 mozilla::dom::DisplayMode::EndGuard_
> {};
111 struct ParamTraits
<mozilla::dom::PrefersColorSchemeOverride
>
112 : public ContiguousEnumSerializer
<
113 mozilla::dom::PrefersColorSchemeOverride
,
114 mozilla::dom::PrefersColorSchemeOverride::None
,
115 mozilla::dom::PrefersColorSchemeOverride::EndGuard_
> {};
118 struct ParamTraits
<mozilla::dom::ExplicitActiveStatus
>
119 : public ContiguousEnumSerializer
<
120 mozilla::dom::ExplicitActiveStatus
,
121 mozilla::dom::ExplicitActiveStatus::None
,
122 mozilla::dom::ExplicitActiveStatus::EndGuard_
> {};
124 // Allow serialization and deserialization of TouchEventsOverride over IPC
126 struct ParamTraits
<mozilla::dom::TouchEventsOverride
>
127 : public ContiguousEnumSerializer
<
128 mozilla::dom::TouchEventsOverride
,
129 mozilla::dom::TouchEventsOverride::Disabled
,
130 mozilla::dom::TouchEventsOverride::EndGuard_
> {};
133 struct ParamTraits
<mozilla::dom::EmbedderColorSchemes
> {
134 using paramType
= mozilla::dom::EmbedderColorSchemes
;
136 static void Write(MessageWriter
* aWriter
, const paramType
& aParam
) {
137 WriteParam(aWriter
, aParam
.mUsed
);
138 WriteParam(aWriter
, aParam
.mPreferred
);
141 static bool Read(MessageReader
* aReader
, paramType
* aResult
) {
142 return ReadParam(aReader
, &aResult
->mUsed
) &&
143 ReadParam(aReader
, &aResult
->mPreferred
);
152 // Explicit specialization of the `Transaction` type. Required by the `extern
153 // template class` declaration in the header.
154 template class syncedcontext::Transaction
<BrowsingContext
>;
156 extern mozilla::LazyLogModule gUserInteractionPRLog
;
158 #define USER_ACTIVATION_LOG(msg, ...) \
159 MOZ_LOG(gUserInteractionPRLog, LogLevel::Debug, (msg, ##__VA_ARGS__))
161 static LazyLogModule
gBrowsingContextLog("BrowsingContext");
162 static LazyLogModule
gBrowsingContextSyncLog("BrowsingContextSync");
164 typedef nsTHashMap
<nsUint64HashKey
, BrowsingContext
*> BrowsingContextMap
;
166 // All BrowsingContexts indexed by Id
167 static StaticAutoPtr
<BrowsingContextMap
> sBrowsingContexts
;
168 // Top-level Content BrowsingContexts only, indexed by BrowserId instead of Id
169 static StaticAutoPtr
<BrowsingContextMap
> sCurrentTopByBrowserId
;
171 static void UnregisterBrowserId(BrowsingContext
* aBrowsingContext
) {
172 if (!aBrowsingContext
->IsTopContent() || !sCurrentTopByBrowserId
) {
176 // Avoids an extra lookup
177 auto browserIdEntry
=
178 sCurrentTopByBrowserId
->Lookup(aBrowsingContext
->BrowserId());
179 if (browserIdEntry
&& browserIdEntry
.Data() == aBrowsingContext
) {
180 browserIdEntry
.Remove();
184 static void Register(BrowsingContext
* aBrowsingContext
) {
185 sBrowsingContexts
->InsertOrUpdate(aBrowsingContext
->Id(), aBrowsingContext
);
186 if (aBrowsingContext
->IsTopContent()) {
187 sCurrentTopByBrowserId
->InsertOrUpdate(aBrowsingContext
->BrowserId(),
191 aBrowsingContext
->Group()->Register(aBrowsingContext
);
195 void BrowsingContext::UpdateCurrentTopByBrowserId(
196 BrowsingContext
* aNewBrowsingContext
) {
197 if (aNewBrowsingContext
->IsTopContent()) {
198 sCurrentTopByBrowserId
->InsertOrUpdate(aNewBrowsingContext
->BrowserId(),
199 aNewBrowsingContext
);
203 BrowsingContext
* BrowsingContext::GetParent() const {
204 return mParentWindow
? mParentWindow
->GetBrowsingContext() : nullptr;
207 bool BrowsingContext::IsInSubtreeOf(BrowsingContext
* aContext
) {
208 BrowsingContext
* bc
= this;
210 if (bc
== aContext
) {
213 } while ((bc
= bc
->GetParent()));
217 BrowsingContext
* BrowsingContext::Top() {
218 BrowsingContext
* bc
= this;
219 while (bc
->mParentWindow
) {
220 bc
= bc
->GetParent();
225 const BrowsingContext
* BrowsingContext::Top() const {
226 const BrowsingContext
* bc
= this;
227 while (bc
->mParentWindow
) {
228 bc
= bc
->GetParent();
233 int32_t BrowsingContext::IndexOf(BrowsingContext
* aChild
) {
235 for (BrowsingContext
* child
: Children()) {
237 if (child
== aChild
) {
244 WindowContext
* BrowsingContext::GetTopWindowContext() const {
246 return mParentWindow
->TopWindowContext();
248 return mCurrentWindowContext
;
252 void BrowsingContext::Init() {
253 if (!sBrowsingContexts
) {
254 sBrowsingContexts
= new BrowsingContextMap();
255 sCurrentTopByBrowserId
= new BrowsingContextMap();
256 ClearOnShutdown(&sBrowsingContexts
);
257 ClearOnShutdown(&sCurrentTopByBrowserId
);
262 LogModule
* BrowsingContext::GetLog() { return gBrowsingContextLog
; }
265 LogModule
* BrowsingContext::GetSyncLog() { return gBrowsingContextSyncLog
; }
268 already_AddRefed
<BrowsingContext
> BrowsingContext::Get(uint64_t aId
) {
269 return do_AddRef(sBrowsingContexts
->Get(aId
));
273 already_AddRefed
<BrowsingContext
> BrowsingContext::GetCurrentTopByBrowserId(
274 uint64_t aBrowserId
) {
275 return do_AddRef(sCurrentTopByBrowserId
->Get(aBrowserId
));
279 already_AddRefed
<BrowsingContext
> BrowsingContext::GetFromWindow(
280 WindowProxyHolder
& aProxy
) {
281 return do_AddRef(aProxy
.get());
284 CanonicalBrowsingContext
* BrowsingContext::Canonical() {
285 return CanonicalBrowsingContext::Cast(this);
288 bool BrowsingContext::IsOwnedByProcess() const {
289 return mIsInProcess
&& mDocShell
&&
290 !nsDocShell::Cast(mDocShell
)->WillChangeProcess();
293 bool BrowsingContext::SameOriginWithTop() {
294 MOZ_ASSERT(IsInProcess());
295 // If the top BrowsingContext is not same-process to us, it is cross-origin
296 if (!Top()->IsInProcess()) {
300 nsIDocShell
* docShell
= GetDocShell();
304 Document
* doc
= docShell
->GetDocument();
308 nsIPrincipal
* principal
= doc
->NodePrincipal();
310 nsIDocShell
* topDocShell
= Top()->GetDocShell();
314 Document
* topDoc
= topDocShell
->GetDocument();
318 nsIPrincipal
* topPrincipal
= topDoc
->NodePrincipal();
320 return principal
->Equals(topPrincipal
);
324 already_AddRefed
<BrowsingContext
> BrowsingContext::CreateDetached(
325 nsGlobalWindowInner
* aParent
, BrowsingContext
* aOpener
,
326 BrowsingContextGroup
* aSpecificGroup
, const nsAString
& aName
, Type aType
,
327 bool aIsPopupRequested
, bool aCreatedDynamically
) {
329 MOZ_DIAGNOSTIC_ASSERT(aParent
->GetWindowContext());
330 MOZ_DIAGNOSTIC_ASSERT(aParent
->GetBrowsingContext()->mType
== aType
);
331 MOZ_DIAGNOSTIC_ASSERT(aParent
->GetBrowsingContext()->GetBrowserId() != 0);
334 MOZ_DIAGNOSTIC_ASSERT(aType
!= Type::Chrome
|| XRE_IsParentProcess());
336 uint64_t id
= nsContentUtils::GenerateBrowsingContextId();
338 MOZ_LOG(GetLog(), LogLevel::Debug
,
339 ("Creating 0x%08" PRIx64
" in %s", id
,
340 XRE_IsParentProcess() ? "Parent" : "Child"));
342 RefPtr
<BrowsingContext
> parentBC
=
343 aParent
? aParent
->GetBrowsingContext() : nullptr;
344 RefPtr
<WindowContext
> parentWC
=
345 aParent
? aParent
->GetWindowContext() : nullptr;
346 BrowsingContext
* inherit
= parentBC
? parentBC
.get() : aOpener
;
348 // Determine which BrowsingContextGroup this context should be created in.
349 RefPtr
<BrowsingContextGroup
> group
= aSpecificGroup
;
350 if (aType
== Type::Chrome
) {
351 MOZ_DIAGNOSTIC_ASSERT(!group
);
352 group
= BrowsingContextGroup::GetChromeGroup();
354 group
= BrowsingContextGroup::Select(parentWC
, aOpener
);
357 // Configure initial values for synced fields.
359 fields
.Get
<IDX_Name
>() = aName
;
362 MOZ_DIAGNOSTIC_ASSERT(!aParent
,
363 "new BC with both initial opener and parent");
364 MOZ_DIAGNOSTIC_ASSERT(aOpener
->Group() == group
);
365 MOZ_DIAGNOSTIC_ASSERT(aOpener
->mType
== aType
);
366 fields
.Get
<IDX_OpenerId
>() = aOpener
->Id();
367 fields
.Get
<IDX_HadOriginalOpener
>() = true;
369 if (aType
== Type::Chrome
&& !aParent
) {
370 // See SetOpener for why we do this inheritance.
371 fields
.Get
<IDX_PrefersColorSchemeOverride
>() =
372 aOpener
->Top()->GetPrefersColorSchemeOverride();
377 MOZ_DIAGNOSTIC_ASSERT(parentBC
->Group() == group
);
378 MOZ_DIAGNOSTIC_ASSERT(parentBC
->mType
== aType
);
379 fields
.Get
<IDX_EmbedderInnerWindowId
>() = aParent
->WindowID();
380 // Non-toplevel content documents are always embededed within content.
381 fields
.Get
<IDX_EmbeddedInContentDocument
>() =
382 parentBC
->mType
== Type::Content
;
384 // XXX(farre): Can/Should we check aParent->IsLoading() here? (Bug
385 // 1608448) Check if the parent was itself loading already
386 auto readystate
= aParent
->GetDocument()->GetReadyStateEnum();
387 fields
.Get
<IDX_AncestorLoading
>() =
388 parentBC
->GetAncestorLoading() ||
389 readystate
== Document::ReadyState::READYSTATE_LOADING
||
390 readystate
== Document::ReadyState::READYSTATE_INTERACTIVE
;
393 fields
.Get
<IDX_BrowserId
>() =
394 parentBC
? parentBC
->GetBrowserId() : nsContentUtils::GenerateBrowserId();
396 fields
.Get
<IDX_OpenerPolicy
>() = nsILoadInfo::OPENER_POLICY_UNSAFE_NONE
;
397 if (aOpener
&& aOpener
->SameOriginWithTop()) {
398 // We inherit the opener policy if there is a creator and if the creator's
399 // origin is same origin with the creator's top-level origin.
400 // If it is cross origin we should not inherit the CrossOriginOpenerPolicy
401 fields
.Get
<IDX_OpenerPolicy
>() = aOpener
->Top()->GetOpenerPolicy();
403 // If we inherit a policy which is potentially cross-origin isolated, we
404 // must be in a potentially cross-origin isolated BCG.
405 bool isPotentiallyCrossOriginIsolated
=
406 fields
.Get
<IDX_OpenerPolicy
>() ==
407 nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP
;
408 MOZ_RELEASE_ASSERT(isPotentiallyCrossOriginIsolated
==
409 group
->IsPotentiallyCrossOriginIsolated());
410 } else if (aOpener
) {
411 // They are not same origin
412 auto topPolicy
= aOpener
->Top()->GetOpenerPolicy();
413 MOZ_RELEASE_ASSERT(topPolicy
== nsILoadInfo::OPENER_POLICY_UNSAFE_NONE
||
415 nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_ALLOW_POPUPS
);
416 } else if (!aParent
&& group
->IsPotentiallyCrossOriginIsolated()) {
417 // If we're creating a brand-new toplevel BC in a potentially cross-origin
418 // isolated group, it should start out with a strict opener policy.
419 fields
.Get
<IDX_OpenerPolicy
>() =
420 nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP
;
423 fields
.Get
<IDX_HistoryID
>() = nsID::GenerateUUID();
424 fields
.Get
<IDX_ExplicitActive
>() = [&] {
426 // Non-root browsing-contexts inherit their status from its parent.
427 return ExplicitActiveStatus::None
;
429 if (aType
== Type::Content
) {
430 // Content gets managed by the chrome front-end / embedder element and
431 // starts as inactive.
432 return ExplicitActiveStatus::Inactive
;
434 // Chrome starts as active.
435 return ExplicitActiveStatus::Active
;
438 fields
.Get
<IDX_FullZoom
>() = parentBC
? parentBC
->FullZoom() : 1.0f
;
439 fields
.Get
<IDX_TextZoom
>() = parentBC
? parentBC
->TextZoom() : 1.0f
;
441 bool allowContentRetargeting
=
442 inherit
? inherit
->GetAllowContentRetargetingOnChildren() : true;
443 fields
.Get
<IDX_AllowContentRetargeting
>() = allowContentRetargeting
;
444 fields
.Get
<IDX_AllowContentRetargetingOnChildren
>() = allowContentRetargeting
;
446 // Assume top allows fullscreen for its children unless otherwise stated.
447 // Subframes start with it false unless otherwise noted in SetEmbedderElement.
448 fields
.Get
<IDX_FullscreenAllowedByOwner
>() = !aParent
;
450 fields
.Get
<IDX_AllowPlugins
>() = inherit
? inherit
->GetAllowPlugins() : true;
452 fields
.Get
<IDX_DefaultLoadFlags
>() =
453 inherit
? inherit
->GetDefaultLoadFlags() : nsIRequest::LOAD_NORMAL
;
455 fields
.Get
<IDX_OrientationLock
>() = mozilla::hal::ScreenOrientation::None
;
457 fields
.Get
<IDX_UseGlobalHistory
>() =
458 inherit
? inherit
->GetUseGlobalHistory() : false;
460 fields
.Get
<IDX_UseErrorPages
>() = true;
462 fields
.Get
<IDX_TouchEventsOverrideInternal
>() = TouchEventsOverride::None
;
464 fields
.Get
<IDX_AllowJavascript
>() =
465 inherit
? inherit
->GetAllowJavascript() : true;
467 fields
.Get
<IDX_IsPopupRequested
>() = aIsPopupRequested
;
470 fields
.Get
<IDX_ShouldDelayMediaFromStart
>() =
471 StaticPrefs::media_block_autoplay_until_in_foreground();
474 RefPtr
<BrowsingContext
> context
;
475 if (XRE_IsParentProcess()) {
476 context
= new CanonicalBrowsingContext(parentWC
, group
, id
,
477 /* aOwnerProcessId */ 0,
478 /* aEmbedderProcessId */ 0, aType
,
482 new BrowsingContext(parentWC
, group
, id
, aType
, std::move(fields
));
485 context
->mEmbeddedByThisProcess
= XRE_IsParentProcess() || aParent
;
486 context
->mCreatedDynamically
= aCreatedDynamically
;
488 context
->mPrivateBrowsingId
= inherit
->mPrivateBrowsingId
;
489 context
->mUseRemoteTabs
= inherit
->mUseRemoteTabs
;
490 context
->mUseRemoteSubframes
= inherit
->mUseRemoteSubframes
;
491 context
->mOriginAttributes
= inherit
->mOriginAttributes
;
494 nsCOMPtr
<nsIRequestContextService
> rcsvc
=
495 net::RequestContextService::GetOrCreate();
497 nsCOMPtr
<nsIRequestContext
> requestContext
;
498 nsresult rv
= rcsvc
->NewRequestContext(getter_AddRefs(requestContext
));
499 if (NS_SUCCEEDED(rv
) && requestContext
) {
500 context
->mRequestContextId
= requestContext
->GetID();
504 return context
.forget();
507 already_AddRefed
<BrowsingContext
> BrowsingContext::CreateIndependent(
509 MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess(),
510 "BCs created in the content process must be related to "
511 "some BrowserChild");
512 RefPtr
<BrowsingContext
> bc(
513 CreateDetached(nullptr, nullptr, nullptr, u
""_ns
, aType
, false));
514 bc
->mWindowless
= bc
->IsContent();
515 bc
->mEmbeddedByThisProcess
= true;
516 bc
->EnsureAttached();
520 void BrowsingContext::EnsureAttached() {
521 if (!mEverAttached
) {
524 // Attach the browsing context to the tree.
525 Attach(/* aFromIPC */ false, /* aOriginProcess */ nullptr);
530 mozilla::ipc::IPCResult
BrowsingContext::CreateFromIPC(
531 BrowsingContext::IPCInitializer
&& aInit
, BrowsingContextGroup
* aGroup
,
532 ContentParent
* aOriginProcess
) {
533 MOZ_DIAGNOSTIC_ASSERT(aOriginProcess
|| XRE_IsContentProcess());
534 MOZ_DIAGNOSTIC_ASSERT(aGroup
);
536 uint64_t originId
= 0;
537 if (aOriginProcess
) {
538 originId
= aOriginProcess
->ChildID();
539 aGroup
->EnsureHostProcess(aOriginProcess
);
542 MOZ_LOG(GetLog(), LogLevel::Debug
,
543 ("Creating 0x%08" PRIx64
" from IPC (origin=0x%08" PRIx64
")",
544 aInit
.mId
, originId
));
546 RefPtr
<WindowContext
> parent
= aInit
.GetParent();
548 RefPtr
<BrowsingContext
> context
;
549 if (XRE_IsParentProcess()) {
550 // If the new BrowsingContext has a parent, it is a sub-frame embedded in
551 // whatever process sent the message. If it doesn't, and is not windowless,
552 // it is a new window or tab, and will be embedded in the parent process.
553 uint64_t embedderProcessId
= (aInit
.mWindowless
|| parent
) ? originId
: 0;
554 context
= new CanonicalBrowsingContext(parent
, aGroup
, aInit
.mId
, originId
,
555 embedderProcessId
, Type::Content
,
556 std::move(aInit
.mFields
));
558 context
= new BrowsingContext(parent
, aGroup
, aInit
.mId
, Type::Content
,
559 std::move(aInit
.mFields
));
562 context
->mWindowless
= aInit
.mWindowless
;
563 context
->mCreatedDynamically
= aInit
.mCreatedDynamically
;
564 context
->mChildOffset
= aInit
.mChildOffset
;
565 if (context
->GetHasSessionHistory()) {
566 context
->CreateChildSHistory();
567 if (mozilla::SessionHistoryInParent()) {
568 context
->GetChildSessionHistory()->SetIndexAndLength(
569 aInit
.mSessionHistoryIndex
, aInit
.mSessionHistoryCount
, nsID());
573 // NOTE: Call through the `Set` methods for these values to ensure that any
574 // relevant process-local state is also updated.
575 context
->SetOriginAttributes(aInit
.mOriginAttributes
);
576 context
->SetRemoteTabs(aInit
.mUseRemoteTabs
);
577 context
->SetRemoteSubframes(aInit
.mUseRemoteSubframes
);
578 context
->mRequestContextId
= aInit
.mRequestContextId
;
579 // NOTE: Private browsing ID is set by `SetOriginAttributes`.
583 return context
->Attach(/* aFromIPC */ true, aOriginProcess
);
586 BrowsingContext::BrowsingContext(WindowContext
* aParentWindow
,
587 BrowsingContextGroup
* aGroup
,
588 uint64_t aBrowsingContextId
, Type aType
,
590 : mFields(std::move(aInit
)),
592 mBrowsingContextId(aBrowsingContextId
),
594 mParentWindow(aParentWindow
),
595 mPrivateBrowsingId(0),
596 mEverAttached(false),
600 mDanglingRemoteOuterProxies(false),
601 mEmbeddedByThisProcess(false),
602 mUseRemoteTabs(false),
603 mUseRemoteSubframes(false),
604 mCreatedDynamically(false),
606 mCanExecuteScripts(true),
608 MOZ_RELEASE_ASSERT(!mParentWindow
|| mParentWindow
->Group() == mGroup
);
609 MOZ_RELEASE_ASSERT(mBrowsingContextId
!= 0);
610 MOZ_RELEASE_ASSERT(mGroup
);
613 void BrowsingContext::SetDocShell(nsIDocShell
* aDocShell
) {
614 // XXX(nika): We should communicate that we are now an active BrowsingContext
615 // process to the parent & do other validation here.
616 MOZ_DIAGNOSTIC_ASSERT(mEverAttached
);
617 MOZ_RELEASE_ASSERT(aDocShell
->GetBrowsingContext() == this);
618 mDocShell
= aDocShell
;
619 mDanglingRemoteOuterProxies
= !mIsInProcess
;
621 if (mChildSessionHistory
) {
622 mChildSessionHistory
->SetIsInProcess(true);
625 RecomputeCanExecuteScripts();
626 ClearCachedValuesOfLocations();
629 // This class implements a callback that will return the remote window proxy for
630 // mBrowsingContext in that compartment, if it has one. It also removes the
631 // proxy from the map, because the object will be transplanted into another kind
633 class MOZ_STACK_CLASS CompartmentRemoteProxyTransplantCallback
634 : public js::CompartmentTransplantCallback
{
636 explicit CompartmentRemoteProxyTransplantCallback(
637 BrowsingContext
* aBrowsingContext
)
638 : mBrowsingContext(aBrowsingContext
) {}
640 virtual JSObject
* getObjectToTransplant(
641 JS::Compartment
* compartment
) override
{
642 auto* priv
= xpc::CompartmentPrivate::Get(compartment
);
647 auto& map
= priv
->GetRemoteProxyMap();
648 auto result
= map
.lookup(mBrowsingContext
);
652 JSObject
* resultObject
= result
->value();
659 BrowsingContext
* mBrowsingContext
;
662 void BrowsingContext::CleanUpDanglingRemoteOuterWindowProxies(
663 JSContext
* aCx
, JS::MutableHandle
<JSObject
*> aOuter
) {
664 if (!mDanglingRemoteOuterProxies
) {
667 mDanglingRemoteOuterProxies
= false;
669 CompartmentRemoteProxyTransplantCallback
cb(this);
670 js::RemapRemoteWindowProxies(aCx
, &cb
, aOuter
);
673 bool BrowsingContext::IsActive() const {
674 const BrowsingContext
* current
= this;
676 auto explicit_
= current
->GetExplicitActive();
677 if (explicit_
!= ExplicitActiveStatus::None
) {
678 return explicit_
== ExplicitActiveStatus::Active
;
680 if (mParentWindow
&& !mParentWindow
->IsCurrent()) {
683 } while ((current
= current
->GetParent()));
688 bool BrowsingContext::GetIsActiveBrowserWindow() {
689 if (!XRE_IsParentProcess()) {
690 return Top()->GetIsActiveBrowserWindowInternal();
693 // chrome:// urls loaded in the parent won't receive
694 // their own activation so we defer to the top chrome
695 // Browsing Context when in the parent process.
696 RefPtr
<CanonicalBrowsingContext
> chromeTop
=
697 Canonical()->TopCrossChromeBoundary();
698 return chromeTop
->GetIsActiveBrowserWindowInternal();
701 void BrowsingContext::SetIsActiveBrowserWindow(bool aActive
) {
702 Unused
<< SetIsActiveBrowserWindowInternal(aActive
);
705 bool BrowsingContext::FullscreenAllowed() const {
706 for (auto* current
= this; current
; current
= current
->GetParent()) {
707 if (!current
->GetFullscreenAllowedByOwner()) {
714 static bool OwnerAllowsFullscreen(const Element
& aEmbedder
) {
715 if (aEmbedder
.IsXULElement()) {
716 return !aEmbedder
.HasAttr(nsGkAtoms::disablefullscreen
);
718 if (aEmbedder
.IsHTMLElement(nsGkAtoms::iframe
)) {
719 // This is controlled by feature policy.
722 if (const auto* embed
= HTMLEmbedElement::FromNode(aEmbedder
)) {
723 return embed
->AllowFullscreen();
728 void BrowsingContext::SetEmbedderElement(Element
* aEmbedder
) {
729 mEmbeddedByThisProcess
= true;
731 // Update embedder-element-specific fields in a shared transaction.
732 // Don't do this when clearing our embedder, as we're being destroyed either
736 txn
.SetEmbedderElementType(Some(aEmbedder
->LocalName()));
737 txn
.SetEmbeddedInContentDocument(
738 aEmbedder
->OwnerDoc()->IsContentDocument());
739 if (nsCOMPtr
<nsPIDOMWindowInner
> inner
=
740 do_QueryInterface(aEmbedder
->GetOwnerGlobal())) {
741 txn
.SetEmbedderInnerWindowId(inner
->WindowID());
743 txn
.SetFullscreenAllowedByOwner(OwnerAllowsFullscreen(*aEmbedder
));
744 if (XRE_IsParentProcess() && IsTopContent()) {
745 nsAutoString messageManagerGroup
;
746 if (aEmbedder
->IsXULElement()) {
747 aEmbedder
->GetAttr(nsGkAtoms::messagemanagergroup
, messageManagerGroup
);
748 if (!aEmbedder
->AttrValueIs(kNameSpaceID_None
,
749 nsGkAtoms::initiallyactive
,
750 nsGkAtoms::_false
, eIgnoreCase
)) {
751 txn
.SetExplicitActive(ExplicitActiveStatus::Active
);
754 txn
.SetMessageManagerGroup(messageManagerGroup
);
756 bool useGlobalHistory
=
757 !aEmbedder
->HasAttr(nsGkAtoms::disableglobalhistory
);
758 txn
.SetUseGlobalHistory(useGlobalHistory
);
761 MOZ_ALWAYS_SUCCEEDS(txn
.Commit(this));
764 if (XRE_IsParentProcess() && IsTopContent()) {
765 Canonical()->MaybeSetPermanentKey(aEmbedder
);
768 mEmbedderElement
= aEmbedder
;
770 if (mEmbedderElement
) {
771 if (nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService()) {
772 obs
->NotifyWhenScriptSafe(ToSupports(this),
773 "browsing-context-did-set-embedder", nullptr);
776 if (nsContentUtils::ShouldHideObjectOrEmbedImageDocument() &&
777 IsEmbedderTypeObjectOrEmbed()) {
778 Unused
<< SetSyntheticDocumentContainer(true);
783 bool BrowsingContext::IsEmbedderTypeObjectOrEmbed() {
784 if (const Maybe
<nsString
>& type
= GetEmbedderElementType()) {
785 return nsGkAtoms::object
->Equals(*type
) || nsGkAtoms::embed
->Equals(*type
);
790 void BrowsingContext::Embed() {
791 if (auto* frame
= HTMLIFrameElement::FromNode(mEmbedderElement
)) {
792 frame
->BindToBrowsingContext(this);
796 mozilla::ipc::IPCResult
BrowsingContext::Attach(bool aFromIPC
,
797 ContentParent
* aOriginProcess
) {
798 MOZ_DIAGNOSTIC_ASSERT(!mEverAttached
);
799 MOZ_DIAGNOSTIC_ASSERT_IF(aFromIPC
, aOriginProcess
|| XRE_IsContentProcess());
800 mEverAttached
= true;
802 if (MOZ_LOG_TEST(GetLog(), LogLevel::Debug
)) {
803 nsAutoCString suffix
;
804 mOriginAttributes
.CreateSuffix(suffix
);
805 MOZ_LOG(GetLog(), LogLevel::Debug
,
806 ("%s: Connecting 0x%08" PRIx64
" to 0x%08" PRIx64
807 " (private=%d, remote=%d, fission=%d, oa=%s)",
808 XRE_IsParentProcess() ? "Parent" : "Child", Id(),
809 GetParent() ? GetParent()->Id() : 0, (int)mPrivateBrowsingId
,
810 (int)mUseRemoteTabs
, (int)mUseRemoteSubframes
, suffix
.get()));
813 MOZ_DIAGNOSTIC_ASSERT(mGroup
);
814 MOZ_DIAGNOSTIC_ASSERT(!mIsDiscarded
);
816 if (mGroup
->IsPotentiallyCrossOriginIsolated() !=
817 (Top()->GetOpenerPolicy() ==
818 nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP
)) {
819 MOZ_DIAGNOSTIC_ASSERT(aFromIPC
);
821 auto* actor
= aOriginProcess
822 ? static_cast<mozilla::ipc::IProtocol
*>(aOriginProcess
)
823 : static_cast<mozilla::ipc::IProtocol
*>(
824 ContentChild::GetSingleton());
827 "Invalid CrossOriginIsolated state in BrowsingContext::Attach call");
830 "Invalid CrossOriginIsolated state in BrowsingContext::Attach call");
834 AssertCoherentLoadContext();
836 // Add ourselves either to our parent or BrowsingContextGroup's child list.
837 // Important: We shouldn't return IPC_FAIL after this point, since the
838 // BrowsingContext will have already been added to the tree.
841 MOZ_DIAGNOSTIC_ASSERT(!mParentWindow
->IsDiscarded(),
842 "local attach in discarded window");
843 MOZ_DIAGNOSTIC_ASSERT(!GetParent()->IsDiscarded(),
844 "local attach call in discarded bc");
845 MOZ_DIAGNOSTIC_ASSERT(mParentWindow
->GetWindowGlobalChild(),
846 "local attach call with oop parent window");
847 MOZ_DIAGNOSTIC_ASSERT(mParentWindow
->GetWindowGlobalChild()->CanSend(),
848 "local attach call with dead parent window");
851 mCreatedDynamically
? -1 : mParentWindow
->Children().Length();
852 mParentWindow
->AppendChildBrowsingContext(this);
853 RecomputeCanExecuteScripts();
855 mGroup
->Toplevels().AppendElement(this);
858 if (GetIsPopupSpam()) {
859 PopupBlocker::RegisterOpenPopupSpam();
862 if (IsTop() && GetHasSessionHistory() && !mChildSessionHistory
) {
863 CreateChildSHistory();
866 // Why the context is being attached. This will always be "attach" in the
867 // content process, but may be "replace" if it's known the context being
868 // replaced in the parent process.
869 const char16_t
* why
= u
"attach";
871 if (XRE_IsContentProcess() && !aFromIPC
) {
872 // Send attach to our parent if we need to.
873 ContentChild::GetSingleton()->SendCreateBrowsingContext(
874 mGroup
->Id(), GetIPCInitializer());
875 } else if (XRE_IsParentProcess()) {
876 // If this window was created as a subframe by a content process, it must be
877 // being hosted within the same BrowserParent as its mParentWindow.
878 // Toplevel BrowsingContexts created by content have their BrowserParent
879 // configured during `RecvConstructPopupBrowser`.
880 if (mParentWindow
&& aOriginProcess
) {
881 MOZ_DIAGNOSTIC_ASSERT(
882 mParentWindow
->Canonical()->GetContentParent() == aOriginProcess
,
883 "Creator process isn't the same as our embedder?");
884 Canonical()->SetCurrentBrowserParent(
885 mParentWindow
->Canonical()->GetBrowserParent());
888 mGroup
->EachOtherParent(aOriginProcess
, [&](ContentParent
* aParent
) {
889 MOZ_DIAGNOSTIC_ASSERT(IsContent(),
890 "chrome BCG cannot be synced to content process");
891 if (!Canonical()->IsEmbeddedInProcess(aParent
->ChildID())) {
892 Unused
<< aParent
->SendCreateBrowsingContext(mGroup
->Id(),
893 GetIPCInitializer());
897 if (IsTop() && IsContent() && Canonical()->GetWebProgress()) {
901 // We want to create a BrowsingContextWebProgress for all content
903 if (IsContent() && !Canonical()->mWebProgress
) {
904 Canonical()->mWebProgress
= new BrowsingContextWebProgress(Canonical());
908 if (nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService()) {
909 obs
->NotifyWhenScriptSafe(ToSupports(this), "browsing-context-attached",
913 if (XRE_IsParentProcess()) {
914 Canonical()->CanonicalAttach();
919 void BrowsingContext::Detach(bool aFromIPC
) {
920 MOZ_LOG(GetLog(), LogLevel::Debug
,
921 ("%s: Detaching 0x%08" PRIx64
" from 0x%08" PRIx64
,
922 XRE_IsParentProcess() ? "Parent" : "Child", Id(),
923 GetParent() ? GetParent()->Id() : 0));
925 MOZ_DIAGNOSTIC_ASSERT(mEverAttached
);
926 MOZ_DIAGNOSTIC_ASSERT(!mIsDiscarded
);
928 if (XRE_IsParentProcess()) {
929 Canonical()->AddPendingDiscard();
932 MakeScopeExit([&, listeners
= std::move(mDiscardListeners
), id
= Id()] {
933 for (const auto& listener
: listeners
) {
936 if (XRE_IsParentProcess()) {
937 Canonical()->RemovePendingDiscard();
941 nsCOMPtr
<nsIRequestContextService
> rcsvc
=
942 net::RequestContextService::GetOrCreate();
944 rcsvc
->RemoveRequestContext(GetRequestContextId());
947 // This will only ever be null if the cycle-collector has unlinked us. Don't
948 // try to detach ourselves in that case.
949 if (NS_WARN_IF(!mGroup
)) {
950 MOZ_ASSERT_UNREACHABLE();
955 mParentWindow
->RemoveChildBrowsingContext(this);
957 mGroup
->Toplevels().RemoveElement(this);
960 if (XRE_IsParentProcess()) {
961 RefPtr
<CanonicalBrowsingContext
> self
{Canonical()};
962 Group()->EachParent([&](ContentParent
* aParent
) {
963 // Only the embedder process is allowed to initiate a BrowsingContext
964 // detach, so if we've gotten here, the host process already knows we've
965 // been detached, and there's no need to tell it again.
967 // If the owner process is not the same as the embedder process, its
968 // BrowsingContext will be detached when its nsWebBrowser instance is
970 bool doDiscard
= !Canonical()->IsEmbeddedInProcess(aParent
->ChildID()) &&
971 !Canonical()->IsOwnedByProcess(aParent
->ChildID());
973 // Hold a strong reference to ourself, and keep our BrowsingContextGroup
974 // alive, until the responses comes back to ensure we don't die while
975 // messages relating to this context are in-flight.
977 // When the callback is called, the keepalive on our group will be
978 // destroyed, and the reference to the BrowsingContext will be dropped,
979 // which may cause it to be fully destroyed.
980 mGroup
->AddKeepAlive();
981 self
->AddPendingDiscard();
982 auto callback
= [self
](auto) {
983 self
->mGroup
->RemoveKeepAlive();
984 self
->RemovePendingDiscard();
987 aParent
->SendDiscardBrowsingContext(this, doDiscard
, callback
, callback
);
990 // Hold a strong reference to ourself until the responses come back to
991 // ensure the BrowsingContext isn't cleaned up before the parent process
992 // acknowledges the discard request.
993 auto callback
= [self
= RefPtr
{this}](auto) {};
994 ContentChild::GetSingleton()->SendDiscardBrowsingContext(
995 this, !aFromIPC
, callback
, callback
);
998 mGroup
->Unregister(this);
999 UnregisterBrowserId(this);
1000 mIsDiscarded
= true;
1002 if (XRE_IsParentProcess()) {
1003 nsFocusManager
* fm
= nsFocusManager::GetFocusManager();
1005 fm
->BrowsingContextDetached(this);
1009 if (nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService()) {
1010 // Why the context is being discarded. This will always be "discard" in the
1011 // content process, but may be "replace" if it's known the context being
1012 // replaced in the parent process.
1013 const char16_t
* why
= u
"discard";
1014 if (XRE_IsParentProcess() && IsTop() && !Canonical()->GetWebProgress()) {
1017 obs
->NotifyObservers(ToSupports(this), "browsing-context-discarded", why
);
1020 // NOTE: Doesn't use SetClosed, as it will be set in all processes
1021 // automatically by calls to Detach()
1022 mFields
.SetWithoutSyncing
<IDX_Closed
>(true);
1024 if (GetIsPopupSpam()) {
1025 PopupBlocker::UnregisterOpenPopupSpam();
1026 // NOTE: Doesn't use SetIsPopupSpam, as it will be set all processes
1028 mFields
.SetWithoutSyncing
<IDX_IsPopupSpam
>(false);
1031 AssertOriginAttributesMatchPrivateBrowsing();
1033 if (XRE_IsParentProcess()) {
1034 Canonical()->CanonicalDiscard();
1038 void BrowsingContext::AddDiscardListener(
1039 std::function
<void(uint64_t)>&& aListener
) {
1044 mDiscardListeners
.AppendElement(std::move(aListener
));
1047 void BrowsingContext::PrepareForProcessChange() {
1048 MOZ_LOG(GetLog(), LogLevel::Debug
,
1049 ("%s: Preparing 0x%08" PRIx64
" for a process change",
1050 XRE_IsParentProcess() ? "Parent" : "Child", Id()));
1052 MOZ_ASSERT(mIsInProcess
, "Must currently be an in-process frame");
1053 MOZ_ASSERT(!mIsDiscarded
, "We're already closed?");
1055 mIsInProcess
= false;
1056 mUserGestureStart
= TimeStamp();
1058 ClearCachedValuesOfLocations();
1060 // NOTE: For now, clear our nsDocShell reference, as we're primarily in a
1061 // different process now. This may need to change in the future with
1062 // Cross-Process BFCache.
1063 mDocShell
= nullptr;
1064 if (mChildSessionHistory
) {
1065 // This can be removed once session history is stored exclusively in the
1067 mChildSessionHistory
->SetIsInProcess(false);
1070 if (!mWindowProxy
) {
1074 // We have to go through mWindowProxy rather than calling GetDOMWindow() on
1075 // mDocShell because the mDocshell reference gets cleared immediately after
1076 // the window is closed.
1077 nsGlobalWindowOuter::PrepareForProcessChange(mWindowProxy
);
1078 MOZ_ASSERT(!mWindowProxy
);
1081 bool BrowsingContext::IsTargetable() const {
1082 return !GetClosed() && AncestorsAreCurrent();
1085 void BrowsingContext::SetOpener(BrowsingContext
* aOpener
) {
1086 MOZ_DIAGNOSTIC_ASSERT(!aOpener
|| aOpener
->Group() == Group());
1087 MOZ_DIAGNOSTIC_ASSERT(!aOpener
|| aOpener
->mType
== mType
);
1089 MOZ_ALWAYS_SUCCEEDS(SetOpenerId(aOpener
? aOpener
->Id() : 0));
1091 if (IsChrome() && IsTop() && aOpener
) {
1092 // Inherit color scheme overrides from parent window. This is to inherit the
1093 // color scheme of dark themed PBM windows in dialogs opened by such
1095 auto openerOverride
= aOpener
->Top()->PrefersColorSchemeOverride();
1096 if (openerOverride
!= PrefersColorSchemeOverride()) {
1097 MOZ_ALWAYS_SUCCEEDS(SetPrefersColorSchemeOverride(openerOverride
));
1102 bool BrowsingContext::HasOpener() const {
1103 return sBrowsingContexts
->Contains(GetOpenerId());
1106 bool BrowsingContext::AncestorsAreCurrent() const {
1107 const BrowsingContext
* bc
= this;
1109 if (bc
->IsDiscarded()) {
1113 if (WindowContext
* wc
= bc
->GetParentWindowContext()) {
1114 if (!wc
->IsCurrent() || wc
->IsDiscarded()) {
1118 bc
= wc
->GetBrowsingContext();
1125 bool BrowsingContext::IsInBFCache() const {
1126 if (mozilla::SessionHistoryInParent()) {
1127 return mIsInBFCache
;
1129 return mParentWindow
&&
1130 mParentWindow
->TopWindowContext()->GetWindowStateSaved();
1133 Span
<RefPtr
<BrowsingContext
>> BrowsingContext::Children() const {
1134 if (WindowContext
* current
= mCurrentWindowContext
) {
1135 return current
->Children();
1137 return Span
<RefPtr
<BrowsingContext
>>();
1140 void BrowsingContext::GetChildren(
1141 nsTArray
<RefPtr
<BrowsingContext
>>& aChildren
) {
1142 aChildren
.AppendElements(Children());
1145 Span
<RefPtr
<BrowsingContext
>> BrowsingContext::NonSyntheticChildren() const {
1146 if (WindowContext
* current
= mCurrentWindowContext
) {
1147 return current
->NonSyntheticChildren();
1149 return Span
<RefPtr
<BrowsingContext
>>();
1152 void BrowsingContext::GetWindowContexts(
1153 nsTArray
<RefPtr
<WindowContext
>>& aWindows
) {
1154 aWindows
.AppendElements(mWindowContexts
);
1157 void BrowsingContext::RegisterWindowContext(WindowContext
* aWindow
) {
1158 MOZ_ASSERT(!mWindowContexts
.Contains(aWindow
),
1159 "WindowContext already registered!");
1160 MOZ_ASSERT(aWindow
->GetBrowsingContext() == this);
1162 mWindowContexts
.AppendElement(aWindow
);
1164 // If the newly registered WindowContext is for our current inner window ID,
1165 // re-run the `DidSet` handler to re-establish the relationship.
1166 if (aWindow
->InnerWindowId() == GetCurrentInnerWindowId()) {
1167 DidSet(FieldIndex
<IDX_CurrentInnerWindowId
>());
1168 MOZ_DIAGNOSTIC_ASSERT(mCurrentWindowContext
== aWindow
);
1172 void BrowsingContext::UnregisterWindowContext(WindowContext
* aWindow
) {
1173 MOZ_ASSERT(mWindowContexts
.Contains(aWindow
),
1174 "WindowContext not registered!");
1175 mWindowContexts
.RemoveElement(aWindow
);
1177 // If our currently active window was unregistered, clear our reference to it.
1178 if (aWindow
== mCurrentWindowContext
) {
1179 // Re-read our `CurrentInnerWindowId` value and use it to set
1180 // `mCurrentWindowContext`. As `aWindow` is now unregistered and discarded,
1181 // we won't find it, and the value will be cleared back to `nullptr`.
1182 DidSet(FieldIndex
<IDX_CurrentInnerWindowId
>());
1183 MOZ_DIAGNOSTIC_ASSERT(mCurrentWindowContext
== nullptr);
1187 void BrowsingContext::PreOrderWalkVoid(
1188 const std::function
<void(BrowsingContext
*)>& aCallback
) {
1191 AutoTArray
<RefPtr
<BrowsingContext
>, 8> children
;
1192 children
.AppendElements(Children());
1194 for (auto& child
: children
) {
1195 child
->PreOrderWalkVoid(aCallback
);
1199 BrowsingContext::WalkFlag
BrowsingContext::PreOrderWalkFlag(
1200 const std::function
<WalkFlag(BrowsingContext
*)>& aCallback
) {
1201 switch (aCallback(this)) {
1202 case WalkFlag::Skip
:
1203 return WalkFlag::Next
;
1204 case WalkFlag::Stop
:
1205 return WalkFlag::Stop
;
1206 case WalkFlag::Next
:
1211 AutoTArray
<RefPtr
<BrowsingContext
>, 8> children
;
1212 children
.AppendElements(Children());
1214 for (auto& child
: children
) {
1215 switch (child
->PreOrderWalkFlag(aCallback
)) {
1216 case WalkFlag::Stop
:
1217 return WalkFlag::Stop
;
1223 return WalkFlag::Next
;
1226 void BrowsingContext::PostOrderWalk(
1227 const std::function
<void(BrowsingContext
*)>& aCallback
) {
1228 AutoTArray
<RefPtr
<BrowsingContext
>, 8> children
;
1229 children
.AppendElements(Children());
1231 for (auto& child
: children
) {
1232 child
->PostOrderWalk(aCallback
);
1238 void BrowsingContext::GetAllBrowsingContextsInSubtree(
1239 nsTArray
<RefPtr
<BrowsingContext
>>& aBrowsingContexts
) {
1240 PreOrderWalk([&](BrowsingContext
* aContext
) {
1241 aBrowsingContexts
.AppendElement(aContext
);
1245 BrowsingContext
* BrowsingContext::FindChildWithName(
1246 const nsAString
& aName
, WindowGlobalChild
& aRequestingWindow
) {
1247 if (aName
.IsEmpty()) {
1248 // You can't find a browsing context with the empty name.
1252 for (BrowsingContext
* child
: NonSyntheticChildren()) {
1253 if (child
->NameEquals(aName
) && aRequestingWindow
.CanNavigate(child
) &&
1254 child
->IsTargetable()) {
1262 BrowsingContext
* BrowsingContext::FindWithSpecialName(
1263 const nsAString
& aName
, WindowGlobalChild
& aRequestingWindow
) {
1264 // TODO(farre): Neither BrowsingContext nor nsDocShell checks if the
1265 // browsing context pointed to by a special name is active. Should
1266 // it be? See Bug 1527913.
1267 if (aName
.LowerCaseEqualsLiteral("_self")) {
1271 if (aName
.LowerCaseEqualsLiteral("_parent")) {
1272 if (BrowsingContext
* parent
= GetParent()) {
1273 return aRequestingWindow
.CanNavigate(parent
) ? parent
: nullptr;
1278 if (aName
.LowerCaseEqualsLiteral("_top")) {
1279 BrowsingContext
* top
= Top();
1281 return aRequestingWindow
.CanNavigate(top
) ? top
: nullptr;
1287 BrowsingContext
* BrowsingContext::FindWithNameInSubtree(
1288 const nsAString
& aName
, WindowGlobalChild
* aRequestingWindow
) {
1289 MOZ_DIAGNOSTIC_ASSERT(!aName
.IsEmpty());
1291 if (NameEquals(aName
) &&
1292 (!aRequestingWindow
|| aRequestingWindow
->CanNavigate(this)) &&
1297 for (BrowsingContext
* child
: NonSyntheticChildren()) {
1298 if (BrowsingContext
* found
=
1299 child
->FindWithNameInSubtree(aName
, aRequestingWindow
)) {
1307 bool BrowsingContext::IsSandboxedFrom(BrowsingContext
* aTarget
) {
1308 // If no target then not sandboxed.
1313 // We cannot be sandboxed from ourselves.
1314 if (aTarget
== this) {
1318 // Default the sandbox flags to our flags, so that if we can't retrieve the
1319 // active document, we will still enforce our own.
1320 uint32_t sandboxFlags
= GetSandboxFlags();
1322 if (RefPtr
<Document
> doc
= mDocShell
->GetExtantDocument()) {
1323 sandboxFlags
= doc
->GetSandboxFlags();
1327 // If no flags, we are not sandboxed at all.
1328 if (!sandboxFlags
) {
1332 // If aTarget has an ancestor, it is not top level.
1333 if (RefPtr
<BrowsingContext
> ancestorOfTarget
= aTarget
->GetParent()) {
1335 // We are not sandboxed if we are an ancestor of target.
1336 if (ancestorOfTarget
== this) {
1339 ancestorOfTarget
= ancestorOfTarget
->GetParent();
1340 } while (ancestorOfTarget
);
1342 // Otherwise, we are sandboxed from aTarget.
1346 // aTarget is top level, are we the "one permitted sandboxed
1347 // navigator", i.e. did we open aTarget?
1348 if (aTarget
->GetOnePermittedSandboxedNavigatorId() == Id()) {
1352 // If SANDBOXED_TOPLEVEL_NAVIGATION flag is not on, we are not sandboxed
1354 if (!(sandboxFlags
& SANDBOXED_TOPLEVEL_NAVIGATION
) && aTarget
== Top()) {
1358 // If SANDBOXED_TOPLEVEL_NAVIGATION_USER_ACTIVATION flag is not on, we are not
1359 // sandboxed from our top if we have user interaction. We assume there is a
1360 // valid transient user gesture interaction if this check happens in the
1361 // target process given that we have checked in the triggering process
1363 if (!(sandboxFlags
& SANDBOXED_TOPLEVEL_NAVIGATION_USER_ACTIVATION
) &&
1364 mCurrentWindowContext
&&
1365 (!mCurrentWindowContext
->IsInProcess() ||
1366 mCurrentWindowContext
->HasValidTransientUserGestureActivation()) &&
1371 // Otherwise, we are sandboxed from aTarget.
1375 RefPtr
<SessionStorageManager
> BrowsingContext::GetSessionStorageManager() {
1376 RefPtr
<SessionStorageManager
>& manager
= Top()->mSessionStorageManager
;
1378 manager
= new SessionStorageManager(this);
1383 bool BrowsingContext::CrossOriginIsolated() {
1384 MOZ_ASSERT(NS_IsMainThread());
1386 return StaticPrefs::
1387 dom_postMessage_sharedArrayBuffer_withCOOP_COEP_AtStartup() &&
1388 Top()->GetOpenerPolicy() ==
1390 OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP
&&
1391 XRE_IsContentProcess() &&
1392 StringBeginsWith(ContentChild::GetSingleton()->GetRemoteType(),
1393 WITH_COOP_COEP_REMOTE_TYPE_PREFIX
);
1396 void BrowsingContext::SetTriggeringAndInheritPrincipals(
1397 nsIPrincipal
* aTriggeringPrincipal
, nsIPrincipal
* aPrincipalToInherit
,
1398 uint64_t aLoadIdentifier
) {
1399 mTriggeringPrincipal
= Some(
1400 PrincipalWithLoadIdentifierTuple(aTriggeringPrincipal
, aLoadIdentifier
));
1401 if (aPrincipalToInherit
) {
1402 mPrincipalToInherit
= Some(
1403 PrincipalWithLoadIdentifierTuple(aPrincipalToInherit
, aLoadIdentifier
));
1407 std::tuple
<nsCOMPtr
<nsIPrincipal
>, nsCOMPtr
<nsIPrincipal
>>
1408 BrowsingContext::GetTriggeringAndInheritPrincipalsForCurrentLoad() {
1409 nsCOMPtr
<nsIPrincipal
> triggeringPrincipal
=
1410 GetSavedPrincipal(mTriggeringPrincipal
);
1411 nsCOMPtr
<nsIPrincipal
> principalToInherit
=
1412 GetSavedPrincipal(mPrincipalToInherit
);
1413 return std::make_tuple(triggeringPrincipal
, principalToInherit
);
1416 nsIPrincipal
* BrowsingContext::GetSavedPrincipal(
1417 Maybe
<PrincipalWithLoadIdentifierTuple
> aPrincipalTuple
) {
1418 if (aPrincipalTuple
) {
1419 nsCOMPtr
<nsIPrincipal
> principal
;
1420 uint64_t loadIdentifier
;
1421 std::tie(principal
, loadIdentifier
) = *aPrincipalTuple
;
1422 // We want to return a principal only if the load identifier for it
1423 // matches the current one for this BC.
1424 if (auto current
= GetCurrentLoadIdentifier();
1425 current
&& *current
== loadIdentifier
) {
1432 BrowsingContext::~BrowsingContext() {
1433 MOZ_DIAGNOSTIC_ASSERT(!mParentWindow
||
1434 !mParentWindow
->mChildren
.Contains(this));
1435 MOZ_DIAGNOSTIC_ASSERT(!mGroup
|| !mGroup
->Toplevels().Contains(this));
1437 mDeprioritizedLoadRunner
.clear();
1439 if (sBrowsingContexts
) {
1440 sBrowsingContexts
->Remove(Id());
1442 UnregisterBrowserId(this);
1444 ClearCachedValuesOfLocations();
1449 void BrowsingContext::DiscardFromContentParent(ContentParent
* aCP
) {
1450 MOZ_ASSERT(XRE_IsParentProcess());
1452 if (sBrowsingContexts
) {
1453 AutoTArray
<RefPtr
<BrowsingContext
>, 8> toDiscard
;
1454 for (const auto& data
: sBrowsingContexts
->Values()) {
1455 auto* bc
= data
->Canonical();
1456 if (!bc
->IsDiscarded() && bc
->IsEmbeddedInProcess(aCP
->ChildID())) {
1457 toDiscard
.AppendElement(bc
);
1461 for (BrowsingContext
* bc
: toDiscard
) {
1462 bc
->Detach(/* aFromIPC */ true);
1467 nsISupports
* BrowsingContext::GetParentObject() const {
1468 return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
1471 JSObject
* BrowsingContext::WrapObject(JSContext
* aCx
,
1472 JS::Handle
<JSObject
*> aGivenProto
) {
1473 return BrowsingContext_Binding::Wrap(aCx
, this, aGivenProto
);
1476 bool BrowsingContext::WriteStructuredClone(JSContext
* aCx
,
1477 JSStructuredCloneWriter
* aWriter
,
1478 StructuredCloneHolder
* aHolder
) {
1479 MOZ_DIAGNOSTIC_ASSERT(mEverAttached
);
1480 return (JS_WriteUint32Pair(aWriter
, SCTAG_DOM_BROWSING_CONTEXT
, 0) &&
1481 JS_WriteUint32Pair(aWriter
, uint32_t(Id()), uint32_t(Id() >> 32)));
1485 JSObject
* BrowsingContext::ReadStructuredClone(JSContext
* aCx
,
1486 JSStructuredCloneReader
* aReader
,
1487 StructuredCloneHolder
* aHolder
) {
1489 uint32_t idHigh
= 0;
1490 if (!JS_ReadUint32Pair(aReader
, &idLow
, &idHigh
)) {
1493 uint64_t id
= uint64_t(idHigh
) << 32 | idLow
;
1495 // Note: Do this check after reading our ID data. Returning null will abort
1496 // the decode operation anyway, but we should at least be as safe as possible.
1497 if (NS_WARN_IF(!NS_IsMainThread())) {
1498 MOZ_DIAGNOSTIC_ASSERT(false,
1499 "We shouldn't be trying to decode a BrowsingContext "
1500 "on a background thread.");
1504 JS::Rooted
<JS::Value
> val(aCx
, JS::NullValue());
1505 // We'll get rooting hazard errors from the RefPtr destructor if it isn't
1506 // destroyed before we try to return a raw JSObject*, so create it in its own
1508 if (RefPtr
<BrowsingContext
> context
= Get(id
)) {
1509 if (!GetOrCreateDOMReflector(aCx
, context
, &val
) || !val
.isObject()) {
1513 return val
.toObjectOrNull();
1516 bool BrowsingContext::CanSetOriginAttributes() {
1517 // A discarded BrowsingContext has already been destroyed, and cannot modify
1518 // its OriginAttributes.
1519 if (NS_WARN_IF(IsDiscarded())) {
1523 // Before attaching is the safest time to set OriginAttributes, and the only
1524 // allowed time for content BrowsingContexts.
1525 if (!EverAttached()) {
1529 // Attached content BrowsingContexts may have been synced to other processes.
1530 if (NS_WARN_IF(IsContent())) {
1534 MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
1536 // Cannot set OriginAttributes after we've created our child BrowsingContext.
1537 if (NS_WARN_IF(!Children().IsEmpty())) {
1541 // Only allow setting OriginAttributes if we have no associated document, or
1542 // the document is still `about:blank`.
1543 // TODO: Bug 1273058 - should have no document when setting origin attributes.
1544 if (WindowGlobalParent
* window
= Canonical()->GetCurrentWindowGlobal()) {
1545 if (nsIURI
* uri
= window
->GetDocumentURI()) {
1546 MOZ_ASSERT(NS_IsAboutBlank(uri
));
1547 return NS_IsAboutBlank(uri
);
1553 Nullable
<WindowProxyHolder
> BrowsingContext::GetAssociatedWindow() {
1554 // nsILoadContext usually only returns same-process windows,
1555 // so we intentionally return nullptr if this BC is out of
1557 if (IsInProcess()) {
1558 return WindowProxyHolder(this);
1563 Nullable
<WindowProxyHolder
> BrowsingContext::GetTopWindow() {
1564 return Top()->GetAssociatedWindow();
1567 Element
* BrowsingContext::GetTopFrameElement() {
1568 return Top()->GetEmbedderElement();
1571 void BrowsingContext::SetUsePrivateBrowsing(bool aUsePrivateBrowsing
,
1572 ErrorResult
& aError
) {
1573 nsresult rv
= SetUsePrivateBrowsing(aUsePrivateBrowsing
);
1574 if (NS_FAILED(rv
)) {
1579 void BrowsingContext::SetUseTrackingProtectionWebIDL(
1580 bool aUseTrackingProtection
, ErrorResult
& aRv
) {
1581 SetForceEnableTrackingProtection(aUseTrackingProtection
, aRv
);
1584 void BrowsingContext::GetOriginAttributes(JSContext
* aCx
,
1585 JS::MutableHandle
<JS::Value
> aVal
,
1586 ErrorResult
& aError
) {
1587 AssertOriginAttributesMatchPrivateBrowsing();
1589 if (!ToJSValue(aCx
, mOriginAttributes
, aVal
)) {
1590 aError
.NoteJSContextException(aCx
);
1594 NS_IMETHODIMP
BrowsingContext::GetAssociatedWindow(
1595 mozIDOMWindowProxy
** aAssociatedWindow
) {
1596 nsCOMPtr
<mozIDOMWindowProxy
> win
= GetDOMWindow();
1597 win
.forget(aAssociatedWindow
);
1601 NS_IMETHODIMP
BrowsingContext::GetTopWindow(mozIDOMWindowProxy
** aTopWindow
) {
1602 return Top()->GetAssociatedWindow(aTopWindow
);
1605 NS_IMETHODIMP
BrowsingContext::GetTopFrameElement(Element
** aTopFrameElement
) {
1606 RefPtr
<Element
> topFrameElement
= GetTopFrameElement();
1607 topFrameElement
.forget(aTopFrameElement
);
1611 NS_IMETHODIMP
BrowsingContext::GetIsContent(bool* aIsContent
) {
1612 *aIsContent
= IsContent();
1616 NS_IMETHODIMP
BrowsingContext::GetUsePrivateBrowsing(
1617 bool* aUsePrivateBrowsing
) {
1618 *aUsePrivateBrowsing
= mPrivateBrowsingId
> 0;
1622 NS_IMETHODIMP
BrowsingContext::SetUsePrivateBrowsing(bool aUsePrivateBrowsing
) {
1623 if (!CanSetOriginAttributes()) {
1624 bool changed
= aUsePrivateBrowsing
!= (mPrivateBrowsingId
> 0);
1626 NS_WARNING("SetUsePrivateBrowsing when !CanSetOriginAttributes()");
1628 return changed
? NS_ERROR_FAILURE
: NS_OK
;
1631 return SetPrivateBrowsing(aUsePrivateBrowsing
);
1634 NS_IMETHODIMP
BrowsingContext::SetPrivateBrowsing(bool aPrivateBrowsing
) {
1635 if (!CanSetOriginAttributes()) {
1636 NS_WARNING("Attempt to set PrivateBrowsing when !CanSetOriginAttributes");
1637 return NS_ERROR_FAILURE
;
1640 bool changed
= aPrivateBrowsing
!= (mPrivateBrowsingId
> 0);
1642 mPrivateBrowsingId
= aPrivateBrowsing
? 1 : 0;
1644 mOriginAttributes
.SyncAttributesWithPrivateBrowsing(aPrivateBrowsing
);
1647 if (XRE_IsParentProcess()) {
1648 Canonical()->AdjustPrivateBrowsingCount(aPrivateBrowsing
);
1651 AssertOriginAttributesMatchPrivateBrowsing();
1653 if (changed
&& mDocShell
) {
1654 nsDocShell::Cast(mDocShell
)->NotifyPrivateBrowsingChanged();
1659 NS_IMETHODIMP
BrowsingContext::GetUseRemoteTabs(bool* aUseRemoteTabs
) {
1660 *aUseRemoteTabs
= mUseRemoteTabs
;
1664 NS_IMETHODIMP
BrowsingContext::SetRemoteTabs(bool aUseRemoteTabs
) {
1665 if (!CanSetOriginAttributes()) {
1666 NS_WARNING("Attempt to set RemoteTabs when !CanSetOriginAttributes");
1667 return NS_ERROR_FAILURE
;
1670 static bool annotated
= false;
1671 if (aUseRemoteTabs
&& !annotated
) {
1673 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::DOMIPCEnabled
,
1677 // Don't allow non-remote tabs with remote subframes.
1678 if (NS_WARN_IF(!aUseRemoteTabs
&& mUseRemoteSubframes
)) {
1679 return NS_ERROR_UNEXPECTED
;
1682 mUseRemoteTabs
= aUseRemoteTabs
;
1686 NS_IMETHODIMP
BrowsingContext::GetUseRemoteSubframes(
1687 bool* aUseRemoteSubframes
) {
1688 *aUseRemoteSubframes
= mUseRemoteSubframes
;
1692 NS_IMETHODIMP
BrowsingContext::SetRemoteSubframes(bool aUseRemoteSubframes
) {
1693 if (!CanSetOriginAttributes()) {
1694 NS_WARNING("Attempt to set RemoteSubframes when !CanSetOriginAttributes");
1695 return NS_ERROR_FAILURE
;
1698 static bool annotated
= false;
1699 if (aUseRemoteSubframes
&& !annotated
) {
1701 CrashReporter::AnnotateCrashReport(
1702 CrashReporter::Annotation::DOMFissionEnabled
, true);
1705 // Don't allow non-remote tabs with remote subframes.
1706 if (NS_WARN_IF(aUseRemoteSubframes
&& !mUseRemoteTabs
)) {
1707 return NS_ERROR_UNEXPECTED
;
1710 mUseRemoteSubframes
= aUseRemoteSubframes
;
1714 NS_IMETHODIMP
BrowsingContext::GetUseTrackingProtection(
1715 bool* aUseTrackingProtection
) {
1716 *aUseTrackingProtection
= false;
1718 if (GetForceEnableTrackingProtection() ||
1719 StaticPrefs::privacy_trackingprotection_enabled() ||
1720 (UsePrivateBrowsing() &&
1721 StaticPrefs::privacy_trackingprotection_pbmode_enabled())) {
1722 *aUseTrackingProtection
= true;
1727 return GetParent()->GetUseTrackingProtection(aUseTrackingProtection
);
1733 NS_IMETHODIMP
BrowsingContext::SetUseTrackingProtection(
1734 bool aUseTrackingProtection
) {
1735 return SetForceEnableTrackingProtection(aUseTrackingProtection
);
1738 NS_IMETHODIMP
BrowsingContext::GetScriptableOriginAttributes(
1739 JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aVal
) {
1740 AssertOriginAttributesMatchPrivateBrowsing();
1742 bool ok
= ToJSValue(aCx
, mOriginAttributes
, aVal
);
1743 NS_ENSURE_TRUE(ok
, NS_ERROR_FAILURE
);
1747 NS_IMETHODIMP_(void)
1748 BrowsingContext::GetOriginAttributes(OriginAttributes
& aAttrs
) {
1749 aAttrs
= mOriginAttributes
;
1750 AssertOriginAttributesMatchPrivateBrowsing();
1753 nsresult
BrowsingContext::SetOriginAttributes(const OriginAttributes
& aAttrs
) {
1754 if (!CanSetOriginAttributes()) {
1755 NS_WARNING("Attempt to set OriginAttributes when !CanSetOriginAttributes");
1756 return NS_ERROR_FAILURE
;
1759 AssertOriginAttributesMatchPrivateBrowsing();
1760 mOriginAttributes
= aAttrs
;
1762 bool isPrivate
= mOriginAttributes
.mPrivateBrowsingId
!=
1763 nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID
;
1764 // Chrome Browsing Context can not contain OriginAttributes.mPrivateBrowsingId
1765 if (IsChrome() && isPrivate
) {
1766 mOriginAttributes
.mPrivateBrowsingId
=
1767 nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID
;
1769 SetPrivateBrowsing(isPrivate
);
1770 AssertOriginAttributesMatchPrivateBrowsing();
1775 void BrowsingContext::AssertCoherentLoadContext() {
1776 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1777 // LoadContext should generally match our opener or parent.
1779 if (RefPtr
<BrowsingContext
> opener
= GetOpener()) {
1780 MOZ_DIAGNOSTIC_ASSERT(opener
->mType
== mType
);
1781 MOZ_DIAGNOSTIC_ASSERT(opener
->mGroup
== mGroup
);
1782 MOZ_DIAGNOSTIC_ASSERT(opener
->mUseRemoteTabs
== mUseRemoteTabs
);
1783 MOZ_DIAGNOSTIC_ASSERT(opener
->mUseRemoteSubframes
== mUseRemoteSubframes
);
1784 MOZ_DIAGNOSTIC_ASSERT(opener
->mPrivateBrowsingId
== mPrivateBrowsingId
);
1785 MOZ_DIAGNOSTIC_ASSERT(
1786 opener
->mOriginAttributes
.EqualsIgnoringFPD(mOriginAttributes
));
1789 if (RefPtr
<BrowsingContext
> parent
= GetParent()) {
1790 MOZ_DIAGNOSTIC_ASSERT(parent
->mType
== mType
);
1791 MOZ_DIAGNOSTIC_ASSERT(parent
->mGroup
== mGroup
);
1792 MOZ_DIAGNOSTIC_ASSERT(parent
->mUseRemoteTabs
== mUseRemoteTabs
);
1793 MOZ_DIAGNOSTIC_ASSERT(parent
->mUseRemoteSubframes
== mUseRemoteSubframes
);
1794 MOZ_DIAGNOSTIC_ASSERT(parent
->mPrivateBrowsingId
== mPrivateBrowsingId
);
1795 MOZ_DIAGNOSTIC_ASSERT(
1796 parent
->mOriginAttributes
.EqualsIgnoringFPD(mOriginAttributes
));
1799 // UseRemoteSubframes and UseRemoteTabs must match.
1800 MOZ_DIAGNOSTIC_ASSERT(
1801 !mUseRemoteSubframes
|| mUseRemoteTabs
,
1802 "Cannot set useRemoteSubframes without also setting useRemoteTabs");
1804 // Double-check OriginAttributes/Private Browsing
1805 AssertOriginAttributesMatchPrivateBrowsing();
1809 void BrowsingContext::AssertOriginAttributesMatchPrivateBrowsing() {
1810 // Chrome browsing contexts must not have a private browsing OriginAttribute
1811 // Content browsing contexts must maintain the equality:
1812 // mOriginAttributes.mPrivateBrowsingId == mPrivateBrowsingId
1814 MOZ_DIAGNOSTIC_ASSERT(mOriginAttributes
.mPrivateBrowsingId
== 0);
1816 MOZ_DIAGNOSTIC_ASSERT(mOriginAttributes
.mPrivateBrowsingId
==
1817 mPrivateBrowsingId
);
1821 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BrowsingContext
)
1822 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
1823 NS_INTERFACE_MAP_ENTRY(nsILoadContext
)
1824 NS_INTERFACE_MAP_ENTRY(nsISupports
)
1825 NS_INTERFACE_MAP_END
1827 NS_IMPL_CYCLE_COLLECTION_CLASS(BrowsingContext
)
1829 NS_IMPL_CYCLE_COLLECTING_ADDREF(BrowsingContext
)
1830 NS_IMPL_CYCLE_COLLECTING_RELEASE(BrowsingContext
)
1832 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(BrowsingContext
)
1833 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
1834 NS_IMPL_CYCLE_COLLECTION_TRACE_END
1836 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BrowsingContext
)
1837 if (sBrowsingContexts
) {
1838 sBrowsingContexts
->Remove(tmp
->Id());
1840 UnregisterBrowserId(tmp
);
1842 if (tmp
->GetIsPopupSpam()) {
1843 PopupBlocker::UnregisterOpenPopupSpam();
1844 // NOTE: Doesn't use SetIsPopupSpam, as it will be set all processes
1846 tmp
->mFields
.SetWithoutSyncing
<IDX_IsPopupSpam
>(false);
1849 NS_IMPL_CYCLE_COLLECTION_UNLINK(
1850 mDocShell
, mParentWindow
, mGroup
, mEmbedderElement
, mWindowContexts
,
1851 mCurrentWindowContext
, mSessionStorageManager
, mChildSessionHistory
)
1852 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
1853 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1855 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(BrowsingContext
)
1856 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(
1857 mDocShell
, mParentWindow
, mGroup
, mEmbedderElement
, mWindowContexts
,
1858 mCurrentWindowContext
, mSessionStorageManager
, mChildSessionHistory
)
1859 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1861 static bool IsCertainlyAliveForCC(BrowsingContext
* aContext
) {
1862 return aContext
->HasKnownLiveWrapper() ||
1863 (AppShutdown::GetCurrentShutdownPhase() ==
1864 ShutdownPhase::NotInShutdown
&&
1865 aContext
->EverAttached() && !aContext
->IsDiscarded());
1868 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(BrowsingContext
)
1869 if (IsCertainlyAliveForCC(tmp
)) {
1870 if (tmp
->PreservingWrapper()) {
1871 tmp
->MarkWrapperLive();
1875 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
1877 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(BrowsingContext
)
1878 return IsCertainlyAliveForCC(tmp
) && tmp
->HasNothingToTrace(tmp
);
1879 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
1881 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(BrowsingContext
)
1882 return IsCertainlyAliveForCC(tmp
);
1883 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
1885 class RemoteLocationProxy
1886 : public RemoteObjectProxy
<BrowsingContext::LocationProxy
,
1887 Location_Binding::sCrossOriginProperties
> {
1889 typedef RemoteObjectProxy Base
;
1891 constexpr RemoteLocationProxy()
1892 : RemoteObjectProxy(prototypes::id::Location
) {}
1894 void NoteChildren(JSObject
* aProxy
,
1895 nsCycleCollectionTraversalCallback
& aCb
) const override
{
1897 static_cast<BrowsingContext::LocationProxy
*>(GetNative(aProxy
));
1898 CycleCollectionNoteChild(aCb
, location
->GetBrowsingContext(),
1899 "JS::GetPrivate(obj)->GetBrowsingContext()");
1903 static const RemoteLocationProxy sSingleton
;
1905 // Give RemoteLocationProxy 2 reserved slots, like the other wrappers,
1906 // so JSObject::swap can swap it with CrossCompartmentWrappers without requiring
1909 const JSClass
RemoteLocationProxy::Base::sClass
=
1910 PROXY_CLASS_DEF("Proxy", JSCLASS_HAS_RESERVED_SLOTS(2));
1912 void BrowsingContext::Location(JSContext
* aCx
,
1913 JS::MutableHandle
<JSObject
*> aLocation
,
1914 ErrorResult
& aError
) {
1915 aError
.MightThrowJSException();
1916 sSingleton
.GetProxyObject(aCx
, &mLocation
, /* aTransplantTo = */ nullptr,
1919 aError
.StealExceptionFromJSContext(aCx
);
1923 bool BrowsingContext::RemoveRootFromBFCacheSync() {
1924 if (WindowContext
* wc
= GetParentWindowContext()) {
1925 if (RefPtr
<Document
> doc
= wc
->TopWindowContext()->GetDocument()) {
1926 return doc
->RemoveFromBFCacheSync();
1932 nsresult
BrowsingContext::CheckSandboxFlags(nsDocShellLoadState
* aLoadState
) {
1933 const auto& sourceBC
= aLoadState
->SourceBrowsingContext();
1934 if (sourceBC
.IsNull()) {
1938 // We might be called after the source BC has been discarded, but before we've
1939 // destroyed our in-process instance of the BrowsingContext object in some
1940 // situations (e.g. after creating a new pop-up with window.open while the
1941 // window is being closed). In these situations we want to still perform the
1942 // sandboxing check against our in-process copy. If we've forgotten about the
1943 // context already, assume it is sanboxed. (bug 1643450)
1944 BrowsingContext
* bc
= sourceBC
.GetMaybeDiscarded();
1945 if (!bc
|| bc
->IsSandboxedFrom(this)) {
1946 return NS_ERROR_DOM_SECURITY_ERR
;
1951 nsresult
BrowsingContext::LoadURI(nsDocShellLoadState
* aLoadState
,
1952 bool aSetNavigating
) {
1953 // Per spec, most load attempts are silently ignored when a BrowsingContext is
1954 // null (which in our code corresponds to discarded), so we simply fail
1955 // silently in those cases. Regardless, we cannot trigger loads in/from
1956 // discarded BrowsingContexts via IPC, so we need to abort in any case.
1957 if (IsDiscarded()) {
1961 MOZ_DIAGNOSTIC_ASSERT(aLoadState
->TargetBrowsingContext().IsNull(),
1962 "Targeting occurs in InternalLoad");
1963 aLoadState
->AssertProcessCouldTriggerLoadIfSystem();
1966 nsCOMPtr
<nsIDocShell
> docShell
= mDocShell
;
1967 return docShell
->LoadURI(aLoadState
, aSetNavigating
);
1970 // Note: We do this check both here and in `nsDocShell::InternalLoad`, since
1971 // document-specific sandbox flags are only available in the process
1972 // triggering the load, and we don't want the target process to have to trust
1973 // the triggering process to do the appropriate checks for the
1974 // BrowsingContext's sandbox flags.
1975 MOZ_TRY(CheckSandboxFlags(aLoadState
));
1976 SetTriggeringAndInheritPrincipals(aLoadState
->TriggeringPrincipal(),
1977 aLoadState
->PrincipalToInherit(),
1978 aLoadState
->GetLoadIdentifier());
1980 const auto& sourceBC
= aLoadState
->SourceBrowsingContext();
1982 if (net::SchemeIsJavascript(aLoadState
->URI())) {
1983 if (!XRE_IsParentProcess()) {
1984 // Web content should only be able to load javascript: URIs into documents
1985 // whose principals the caller principal subsumes, which by definition
1986 // excludes any document in a cross-process BrowsingContext.
1987 return NS_ERROR_DOM_BAD_CROSS_ORIGIN_URI
;
1989 MOZ_DIAGNOSTIC_ASSERT(!sourceBC
,
1990 "Should never see a cross-process javascript: load "
1991 "triggered from content");
1994 MOZ_DIAGNOSTIC_ASSERT(!sourceBC
|| sourceBC
->Group() == Group());
1995 if (sourceBC
&& sourceBC
->IsInProcess()) {
1996 nsCOMPtr
<nsPIDOMWindowOuter
> win(sourceBC
->GetDOMWindow());
1997 if (WindowGlobalChild
* wgc
=
1998 win
->GetCurrentInnerWindow()->GetWindowGlobalChild()) {
1999 if (!wgc
->CanNavigate(this)) {
2000 return NS_ERROR_DOM_PROP_ACCESS_DENIED
;
2002 wgc
->SendLoadURI(this, mozilla::WrapNotNull(aLoadState
), aSetNavigating
);
2004 } else if (XRE_IsParentProcess()) {
2005 if (Canonical()->LoadInParent(aLoadState
, aSetNavigating
)) {
2009 if (ContentParent
* cp
= Canonical()->GetContentParent()) {
2010 // Attempt to initiate this load immediately in the parent, if it succeeds
2011 // it'll return a unique identifier so that we can find it later.
2012 uint64_t loadIdentifier
= 0;
2013 if (Canonical()->AttemptSpeculativeLoadInParent(aLoadState
)) {
2014 MOZ_DIAGNOSTIC_ASSERT(GetCurrentLoadIdentifier().isSome());
2015 loadIdentifier
= GetCurrentLoadIdentifier().value();
2016 aLoadState
->SetChannelInitialized(true);
2019 cp
->TransmitBlobDataIfBlobURL(aLoadState
->URI());
2021 // Setup a confirmation callback once the content process receives this
2022 // load. Normally we'd expect a PDocumentChannel actor to have been
2023 // created to claim the load identifier by that time. If not, then it
2024 // won't be coming, so make sure we clean up and deregister.
2025 cp
->SendLoadURI(this, mozilla::WrapNotNull(aLoadState
), aSetNavigating
)
2026 ->Then(GetMainThreadSerialEventTarget(), __func__
,
2028 const PContentParent::LoadURIPromise::ResolveOrRejectValue
&
2030 if (loadIdentifier
) {
2031 net::DocumentLoadListener::CleanupParentLoadAttempt(
2037 MOZ_DIAGNOSTIC_ASSERT(sourceBC
);
2039 return NS_ERROR_UNEXPECTED
;
2041 // If we're in a content process and the source BC is no longer in-process,
2042 // just fail silently.
2047 nsresult
BrowsingContext::InternalLoad(nsDocShellLoadState
* aLoadState
) {
2048 if (IsDiscarded()) {
2051 SetTriggeringAndInheritPrincipals(aLoadState
->TriggeringPrincipal(),
2052 aLoadState
->PrincipalToInherit(),
2053 aLoadState
->GetLoadIdentifier());
2055 MOZ_DIAGNOSTIC_ASSERT(aLoadState
->Target().IsEmpty(),
2056 "should already have retargeted");
2057 MOZ_DIAGNOSTIC_ASSERT(!aLoadState
->TargetBrowsingContext().IsNull(),
2058 "should have target bc set");
2059 MOZ_DIAGNOSTIC_ASSERT(aLoadState
->TargetBrowsingContext() == this,
2060 "must be targeting this BrowsingContext");
2061 aLoadState
->AssertProcessCouldTriggerLoadIfSystem();
2064 RefPtr
<nsDocShell
> docShell
= nsDocShell::Cast(mDocShell
);
2065 return docShell
->InternalLoad(aLoadState
);
2068 // Note: We do this check both here and in `nsDocShell::InternalLoad`, since
2069 // document-specific sandbox flags are only available in the process
2070 // triggering the load, and we don't want the target process to have to trust
2071 // the triggering process to do the appropriate checks for the
2072 // BrowsingContext's sandbox flags.
2073 MOZ_TRY(CheckSandboxFlags(aLoadState
));
2075 const auto& sourceBC
= aLoadState
->SourceBrowsingContext();
2077 if (net::SchemeIsJavascript(aLoadState
->URI())) {
2078 if (!XRE_IsParentProcess()) {
2079 // Web content should only be able to load javascript: URIs into documents
2080 // whose principals the caller principal subsumes, which by definition
2081 // excludes any document in a cross-process BrowsingContext.
2082 return NS_ERROR_DOM_BAD_CROSS_ORIGIN_URI
;
2084 MOZ_DIAGNOSTIC_ASSERT(!sourceBC
,
2085 "Should never see a cross-process javascript: load "
2086 "triggered from content");
2089 if (XRE_IsParentProcess()) {
2090 ContentParent
* cp
= Canonical()->GetContentParent();
2091 if (!cp
|| !cp
->CanSend()) {
2092 return NS_ERROR_FAILURE
;
2095 MOZ_ALWAYS_SUCCEEDS(
2096 SetCurrentLoadIdentifier(Some(aLoadState
->GetLoadIdentifier())));
2097 Unused
<< cp
->SendInternalLoad(mozilla::WrapNotNull(aLoadState
));
2099 MOZ_DIAGNOSTIC_ASSERT(sourceBC
);
2100 MOZ_DIAGNOSTIC_ASSERT(sourceBC
->Group() == Group());
2102 nsCOMPtr
<nsPIDOMWindowOuter
> win(sourceBC
->GetDOMWindow());
2103 WindowGlobalChild
* wgc
=
2104 win
->GetCurrentInnerWindow()->GetWindowGlobalChild();
2105 if (!wgc
|| !wgc
->CanSend()) {
2106 return NS_ERROR_FAILURE
;
2108 if (!wgc
->CanNavigate(this)) {
2109 return NS_ERROR_DOM_PROP_ACCESS_DENIED
;
2112 MOZ_ALWAYS_SUCCEEDS(
2113 SetCurrentLoadIdentifier(Some(aLoadState
->GetLoadIdentifier())));
2114 wgc
->SendInternalLoad(mozilla::WrapNotNull(aLoadState
));
2120 void BrowsingContext::DisplayLoadError(const nsAString
& aURI
) {
2121 MOZ_LOG(GetLog(), LogLevel::Debug
, ("DisplayLoadError"));
2122 MOZ_DIAGNOSTIC_ASSERT(!IsDiscarded());
2123 MOZ_DIAGNOSTIC_ASSERT(mDocShell
|| XRE_IsParentProcess());
2126 bool didDisplayLoadError
= false;
2127 nsCOMPtr
<nsIDocShell
> docShell
= mDocShell
;
2128 docShell
->DisplayLoadError(NS_ERROR_MALFORMED_URI
, nullptr,
2129 PromiseFlatString(aURI
).get(), nullptr,
2130 &didDisplayLoadError
);
2132 if (ContentParent
* cp
= Canonical()->GetContentParent()) {
2133 Unused
<< cp
->SendDisplayLoadError(this, PromiseFlatString(aURI
));
2138 WindowProxyHolder
BrowsingContext::Window() {
2139 return WindowProxyHolder(Self());
2142 WindowProxyHolder
BrowsingContext::GetFrames(ErrorResult
& aError
) {
2146 void BrowsingContext::Close(CallerType aCallerType
, ErrorResult
& aError
) {
2152 // .close() on frames is a no-op.
2156 if (GetDOMWindow()) {
2157 nsGlobalWindowOuter::Cast(GetDOMWindow())
2158 ->CloseOuter(aCallerType
== CallerType::System
);
2162 // This is a bit of a hack for webcompat. Content needs to see an updated
2163 // |window.closed| value as early as possible, so we set this before we
2164 // actually send the DOMWindowClose event, which happens in the process where
2165 // the document for this browsing context is loaded.
2166 MOZ_ALWAYS_SUCCEEDS(SetClosed(true));
2168 if (ContentChild
* cc
= ContentChild::GetSingleton()) {
2169 cc
->SendWindowClose(this, aCallerType
== CallerType::System
);
2170 } else if (ContentParent
* cp
= Canonical()->GetContentParent()) {
2171 Unused
<< cp
->SendWindowClose(this, aCallerType
== CallerType::System
);
2176 * Examine the current document state to see if we're in a way that is
2177 * typically abused by web designers. The window.open code uses this
2178 * routine to determine whether to allow the new window.
2179 * Returns a value from the PopupControlState enum.
2181 PopupBlocker::PopupControlState
BrowsingContext::RevisePopupAbuseLevel(
2182 PopupBlocker::PopupControlState aControl
) {
2184 return PopupBlocker::openAllowed
;
2187 RefPtr
<Document
> doc
= GetExtantDocument();
2188 PopupBlocker::PopupControlState abuse
= aControl
;
2190 case PopupBlocker::openControlled
:
2191 case PopupBlocker::openBlocked
:
2192 case PopupBlocker::openOverridden
:
2193 if (IsPopupAllowed()) {
2194 abuse
= PopupBlocker::PopupControlState(abuse
- 1);
2197 case PopupBlocker::openAbused
:
2198 if (IsPopupAllowed() ||
2199 (doc
&& doc
->HasValidTransientUserGestureActivation())) {
2200 // Skip PopupBlocker::openBlocked
2201 abuse
= PopupBlocker::openControlled
;
2204 case PopupBlocker::openAllowed
:
2207 NS_WARNING("Strange PopupControlState!");
2210 // limit the number of simultaneously open popups
2211 if (abuse
== PopupBlocker::openAbused
|| abuse
== PopupBlocker::openBlocked
||
2212 abuse
== PopupBlocker::openControlled
) {
2213 int32_t popupMax
= StaticPrefs::dom_popup_maximum();
2214 if (popupMax
>= 0 &&
2215 PopupBlocker::GetOpenPopupSpamCount() >= (uint32_t)popupMax
) {
2216 abuse
= PopupBlocker::openOverridden
;
2220 // If we're currently in-process, attempt to consume transient user gesture
2223 // HACK: Some pages using bogus library + UA sniffing call window.open()
2224 // from a blank iframe, only on Firefox, see bug 1685056.
2226 // This is a hack-around to preserve behavior in that particular and
2227 // specific case, by consuming activation on the parent document, so we
2228 // don't care about the InProcessParent bits not being fission-safe or what
2230 auto ConsumeTransientUserActivationForMultiplePopupBlocking
=
2232 if (doc
->ConsumeTransientUserGestureActivation()) {
2235 if (!doc
->IsInitialDocument()) {
2238 Document
* parentDoc
= doc
->GetInProcessParentDocument();
2240 !parentDoc
->NodePrincipal()->Equals(doc
->NodePrincipal())) {
2243 return parentDoc
->ConsumeTransientUserGestureActivation();
2246 // If this popup is allowed, let's block any other for this event, forcing
2247 // PopupBlocker::openBlocked state.
2248 if ((abuse
== PopupBlocker::openAllowed
||
2249 abuse
== PopupBlocker::openControlled
) &&
2250 StaticPrefs::dom_block_multiple_popups() && !IsPopupAllowed() &&
2251 !ConsumeTransientUserActivationForMultiplePopupBlocking()) {
2252 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag
, "DOM"_ns
,
2253 doc
, nsContentUtils::eDOM_PROPERTIES
,
2254 "MultiplePopupsBlockedNoUserActivation");
2255 abuse
= PopupBlocker::openBlocked
;
2262 void BrowsingContext::IncrementHistoryEntryCountForBrowsingContext() {
2263 Unused
<< SetHistoryEntryCount(GetHistoryEntryCount() + 1);
2266 std::tuple
<bool, bool> BrowsingContext::CanFocusCheck(CallerType aCallerType
) {
2267 nsFocusManager
* fm
= nsFocusManager::GetFocusManager();
2269 return {false, false};
2272 nsCOMPtr
<nsPIDOMWindowInner
> caller
= do_QueryInterface(GetEntryGlobal());
2273 BrowsingContext
* callerBC
= caller
? caller
->GetBrowsingContext() : nullptr;
2274 RefPtr
<BrowsingContext
> openerBC
= GetOpener();
2275 MOZ_DIAGNOSTIC_ASSERT(!openerBC
|| openerBC
->Group() == Group());
2277 // Enforce dom.disable_window_flip (for non-chrome), but still allow the
2278 // window which opened us to raise us at times when popups are allowed
2279 // (bugs 355482 and 369306).
2280 bool canFocus
= aCallerType
== CallerType::System
||
2281 !Preferences::GetBool("dom.disable_window_flip", true);
2282 if (!canFocus
&& openerBC
== callerBC
) {
2284 (callerBC
? callerBC
: this)
2285 ->RevisePopupAbuseLevel(PopupBlocker::GetPopupControlState()) <
2286 PopupBlocker::openBlocked
;
2289 bool isActive
= false;
2290 if (XRE_IsParentProcess()) {
2291 RefPtr
<CanonicalBrowsingContext
> chromeTop
=
2292 Canonical()->TopCrossChromeBoundary();
2293 nsCOMPtr
<nsPIDOMWindowOuter
> activeWindow
= fm
->GetActiveWindow();
2294 isActive
= (activeWindow
== chromeTop
->GetDOMWindow());
2296 isActive
= (fm
->GetActiveBrowsingContext() == Top());
2299 return {canFocus
, isActive
};
2302 void BrowsingContext::Focus(CallerType aCallerType
, ErrorResult
& aError
) {
2303 // These checks need to happen before the RequestFrameFocus call, which
2304 // is why they are done in an untrusted process. If we wanted to enforce
2305 // these in the parent, we'd need to do the checks there _also_.
2306 // These should be kept in sync with nsGlobalWindowOuter::FocusOuter.
2308 auto [canFocus
, isActive
] = CanFocusCheck(aCallerType
);
2310 if (!(canFocus
|| isActive
)) {
2314 // Permission check passed
2316 if (mEmbedderElement
) {
2317 // Make the activeElement in this process update synchronously.
2318 nsContentUtils::RequestFrameFocus(*mEmbedderElement
, true, aCallerType
);
2320 uint64_t actionId
= nsFocusManager::GenerateFocusActionId();
2321 if (ContentChild
* cc
= ContentChild::GetSingleton()) {
2322 cc
->SendWindowFocus(this, aCallerType
, actionId
);
2323 } else if (ContentParent
* cp
= Canonical()->GetContentParent()) {
2324 Unused
<< cp
->SendWindowFocus(this, aCallerType
, actionId
);
2328 bool BrowsingContext::CanBlurCheck(CallerType aCallerType
) {
2329 // If dom.disable_window_flip == true, then content should not be allowed
2330 // to do blur (this would allow popunders, bug 369306)
2331 return aCallerType
== CallerType::System
||
2332 !Preferences::GetBool("dom.disable_window_flip", true);
2335 void BrowsingContext::Blur(CallerType aCallerType
, ErrorResult
& aError
) {
2336 if (!CanBlurCheck(aCallerType
)) {
2340 if (ContentChild
* cc
= ContentChild::GetSingleton()) {
2341 cc
->SendWindowBlur(this, aCallerType
);
2342 } else if (ContentParent
* cp
= Canonical()->GetContentParent()) {
2343 Unused
<< cp
->SendWindowBlur(this, aCallerType
);
2347 Nullable
<WindowProxyHolder
> BrowsingContext::GetWindow() {
2348 if (XRE_IsParentProcess() && !IsInProcess()) {
2351 return WindowProxyHolder(this);
2354 Nullable
<WindowProxyHolder
> BrowsingContext::GetTop(ErrorResult
& aError
) {
2359 // We never return null or throw an error, but the implementation in
2360 // nsGlobalWindow does and we need to use the same signature.
2361 return WindowProxyHolder(Top());
2364 void BrowsingContext::GetOpener(JSContext
* aCx
,
2365 JS::MutableHandle
<JS::Value
> aOpener
,
2366 ErrorResult
& aError
) const {
2367 RefPtr
<BrowsingContext
> opener
= GetOpener();
2373 if (!ToJSValue(aCx
, WindowProxyHolder(opener
), aOpener
)) {
2374 aError
.NoteJSContextException(aCx
);
2378 // We never throw an error, but the implementation in nsGlobalWindow does and
2379 // we need to use the same signature.
2380 Nullable
<WindowProxyHolder
> BrowsingContext::GetParent(ErrorResult
& aError
) {
2386 return WindowProxyHolder(GetParent());
2388 return WindowProxyHolder(this);
2391 void BrowsingContext::PostMessageMoz(JSContext
* aCx
,
2392 JS::Handle
<JS::Value
> aMessage
,
2393 const nsAString
& aTargetOrigin
,
2394 const Sequence
<JSObject
*>& aTransfer
,
2395 nsIPrincipal
& aSubjectPrincipal
,
2396 ErrorResult
& aError
) {
2401 RefPtr
<BrowsingContext
> sourceBc
;
2402 PostMessageData data
;
2403 data
.targetOrigin() = aTargetOrigin
;
2404 data
.subjectPrincipal() = &aSubjectPrincipal
;
2405 RefPtr
<nsGlobalWindowInner
> callerInnerWindow
;
2406 nsAutoCString scriptLocation
;
2407 // We don't need to get the caller's agentClusterId since that is used for
2408 // checking whether it's okay to sharing memory (and it's not allowed to share
2409 // memory cross processes)
2410 if (!nsGlobalWindowOuter::GatherPostMessageData(
2411 aCx
, aTargetOrigin
, getter_AddRefs(sourceBc
), data
.origin(),
2412 getter_AddRefs(data
.targetOriginURI()),
2413 getter_AddRefs(data
.callerPrincipal()),
2414 getter_AddRefs(callerInnerWindow
), getter_AddRefs(data
.callerURI()),
2415 /* aCallerAgentClusterId */ nullptr, &scriptLocation
, aError
)) {
2418 if (sourceBc
&& sourceBc
->IsDiscarded()) {
2421 data
.source() = sourceBc
;
2422 data
.isFromPrivateWindow() =
2423 callerInnerWindow
&&
2424 nsScriptErrorBase::ComputeIsFromPrivateWindow(callerInnerWindow
);
2425 data
.innerWindowId() = callerInnerWindow
? callerInnerWindow
->WindowID() : 0;
2426 data
.scriptLocation() = scriptLocation
;
2427 JS::Rooted
<JS::Value
> transferArray(aCx
);
2428 aError
= nsContentUtils::CreateJSValueFromSequenceOfObject(aCx
, aTransfer
,
2430 if (NS_WARN_IF(aError
.Failed())) {
2434 JS::CloneDataPolicy clonePolicy
;
2435 if (callerInnerWindow
&& callerInnerWindow
->IsSharedMemoryAllowed()) {
2436 clonePolicy
.allowSharedMemoryObjects();
2439 // We will see if the message is required to be in the same process or it can
2440 // be in the different process after Write().
2441 ipc::StructuredCloneData message
= ipc::StructuredCloneData(
2442 StructuredCloneHolder::StructuredCloneScope::UnknownDestination
,
2443 StructuredCloneHolder::TransferringSupported
);
2444 message
.Write(aCx
, aMessage
, transferArray
, clonePolicy
, aError
);
2445 if (NS_WARN_IF(aError
.Failed())) {
2449 ClonedOrErrorMessageData messageData
;
2450 if (ContentChild
* cc
= ContentChild::GetSingleton()) {
2451 // The clone scope gets set when we write the message data based on the
2452 // requirements of that data that we're writing.
2453 // If the message data contains a shared memory object, then CloneScope
2454 // would return SameProcess. Otherwise, it returns DifferentProcess.
2455 if (message
.CloneScope() ==
2456 StructuredCloneHolder::StructuredCloneScope::DifferentProcess
) {
2457 ClonedMessageData clonedMessageData
;
2458 if (!message
.BuildClonedMessageData(clonedMessageData
)) {
2459 aError
.Throw(NS_ERROR_FAILURE
);
2463 messageData
= std::move(clonedMessageData
);
2465 MOZ_ASSERT(message
.CloneScope() ==
2466 StructuredCloneHolder::StructuredCloneScope::SameProcess
);
2468 messageData
= ErrorMessageData();
2470 nsContentUtils::ReportToConsole(
2471 nsIScriptError::warningFlag
, "DOM Window"_ns
,
2472 callerInnerWindow
? callerInnerWindow
->GetDocument() : nullptr,
2473 nsContentUtils::eDOM_PROPERTIES
,
2474 "PostMessageSharedMemoryObjectToCrossOriginWarning");
2477 cc
->SendWindowPostMessage(this, messageData
, data
);
2478 } else if (ContentParent
* cp
= Canonical()->GetContentParent()) {
2479 if (message
.CloneScope() ==
2480 StructuredCloneHolder::StructuredCloneScope::DifferentProcess
) {
2481 ClonedMessageData clonedMessageData
;
2482 if (!message
.BuildClonedMessageData(clonedMessageData
)) {
2483 aError
.Throw(NS_ERROR_FAILURE
);
2487 messageData
= std::move(clonedMessageData
);
2489 MOZ_ASSERT(message
.CloneScope() ==
2490 StructuredCloneHolder::StructuredCloneScope::SameProcess
);
2492 messageData
= ErrorMessageData();
2494 nsContentUtils::ReportToConsole(
2495 nsIScriptError::warningFlag
, "DOM Window"_ns
,
2496 callerInnerWindow
? callerInnerWindow
->GetDocument() : nullptr,
2497 nsContentUtils::eDOM_PROPERTIES
,
2498 "PostMessageSharedMemoryObjectToCrossOriginWarning");
2501 Unused
<< cp
->SendWindowPostMessage(this, messageData
, data
);
2505 void BrowsingContext::PostMessageMoz(JSContext
* aCx
,
2506 JS::Handle
<JS::Value
> aMessage
,
2507 const WindowPostMessageOptions
& aOptions
,
2508 nsIPrincipal
& aSubjectPrincipal
,
2509 ErrorResult
& aError
) {
2510 PostMessageMoz(aCx
, aMessage
, aOptions
.mTargetOrigin
, aOptions
.mTransfer
,
2511 aSubjectPrincipal
, aError
);
2514 void BrowsingContext::SendCommitTransaction(ContentParent
* aParent
,
2515 const BaseTransaction
& aTxn
,
2517 Unused
<< aParent
->SendCommitBrowsingContextTransaction(this, aTxn
, aEpoch
);
2520 void BrowsingContext::SendCommitTransaction(ContentChild
* aChild
,
2521 const BaseTransaction
& aTxn
,
2523 aChild
->SendCommitBrowsingContextTransaction(this, aTxn
, aEpoch
);
2526 BrowsingContext::IPCInitializer
BrowsingContext::GetIPCInitializer() {
2527 MOZ_DIAGNOSTIC_ASSERT(mEverAttached
);
2528 MOZ_DIAGNOSTIC_ASSERT(mType
== Type::Content
);
2530 IPCInitializer init
;
2532 init
.mParentId
= mParentWindow
? mParentWindow
->Id() : 0;
2533 init
.mWindowless
= mWindowless
;
2534 init
.mUseRemoteTabs
= mUseRemoteTabs
;
2535 init
.mUseRemoteSubframes
= mUseRemoteSubframes
;
2536 init
.mCreatedDynamically
= mCreatedDynamically
;
2537 init
.mChildOffset
= mChildOffset
;
2538 init
.mOriginAttributes
= mOriginAttributes
;
2539 if (mChildSessionHistory
&& mozilla::SessionHistoryInParent()) {
2540 init
.mSessionHistoryIndex
= mChildSessionHistory
->Index();
2541 init
.mSessionHistoryCount
= mChildSessionHistory
->Count();
2543 init
.mRequestContextId
= mRequestContextId
;
2544 init
.mFields
= mFields
.RawValues();
2548 already_AddRefed
<WindowContext
> BrowsingContext::IPCInitializer::GetParent() {
2549 RefPtr
<WindowContext
> parent
;
2550 if (mParentId
!= 0) {
2551 parent
= WindowContext::GetById(mParentId
);
2552 MOZ_RELEASE_ASSERT(parent
);
2554 return parent
.forget();
2557 already_AddRefed
<BrowsingContext
> BrowsingContext::IPCInitializer::GetOpener() {
2558 RefPtr
<BrowsingContext
> opener
;
2559 if (GetOpenerId() != 0) {
2560 opener
= BrowsingContext::Get(GetOpenerId());
2561 MOZ_RELEASE_ASSERT(opener
);
2563 return opener
.forget();
2566 void BrowsingContext::StartDelayedAutoplayMediaComponents() {
2570 AUTOPLAY_LOG("%s : StartDelayedAutoplayMediaComponents for bc 0x%08" PRIx64
,
2571 XRE_IsParentProcess() ? "Parent" : "Child", Id());
2572 mDocShell
->StartDelayedAutoplayMediaComponents();
2575 nsresult
BrowsingContext::ResetGVAutoplayRequestStatus() {
2577 "Should only set GVAudibleAutoplayRequestStatus in the top-level "
2578 "browsing context");
2581 txn
.SetGVAudibleAutoplayRequestStatus(GVAutoplayRequestStatus::eUNKNOWN
);
2582 txn
.SetGVInaudibleAutoplayRequestStatus(GVAutoplayRequestStatus::eUNKNOWN
);
2583 return txn
.Commit(this);
2586 template <typename Callback
>
2587 void BrowsingContext::WalkPresContexts(Callback
&& aCallback
) {
2588 PreOrderWalk([&](BrowsingContext
* aContext
) {
2589 if (nsIDocShell
* shell
= aContext
->GetDocShell()) {
2590 if (RefPtr pc
= shell
->GetPresContext()) {
2591 aCallback(pc
.get());
2597 void BrowsingContext::PresContextAffectingFieldChanged() {
2598 WalkPresContexts([&](nsPresContext
* aPc
) {
2599 aPc
->RecomputeBrowsingContextDependentData();
2603 void BrowsingContext::DidSet(FieldIndex
<IDX_SessionStoreEpoch
>,
2604 uint32_t aOldValue
) {
2605 if (!mCurrentWindowContext
) {
2608 SessionStoreChild
* sessionStoreChild
=
2609 SessionStoreChild::From(mCurrentWindowContext
->GetWindowGlobalChild());
2610 if (!sessionStoreChild
) {
2614 sessionStoreChild
->SetEpoch(GetSessionStoreEpoch());
2617 void BrowsingContext::DidSet(FieldIndex
<IDX_GVAudibleAutoplayRequestStatus
>) {
2619 "Should only set GVAudibleAutoplayRequestStatus in the top-level "
2620 "browsing context");
2623 void BrowsingContext::DidSet(FieldIndex
<IDX_GVInaudibleAutoplayRequestStatus
>) {
2625 "Should only set GVAudibleAutoplayRequestStatus in the top-level "
2626 "browsing context");
2629 void BrowsingContext::DidSet(FieldIndex
<IDX_ExplicitActive
>,
2630 ExplicitActiveStatus aOldValue
) {
2631 const bool isActive
= IsActive();
2632 const bool wasActive
= [&] {
2633 if (aOldValue
!= ExplicitActiveStatus::None
) {
2634 return aOldValue
== ExplicitActiveStatus::Active
;
2636 return GetParent() && GetParent()->IsActive();
2639 if (isActive
== wasActive
) {
2644 Group()->UpdateToplevelsSuspendedIfNeeded();
2646 if (XRE_IsParentProcess()) {
2647 auto* bc
= Canonical();
2648 if (BrowserParent
* bp
= bc
->GetBrowserParent()) {
2649 bp
->RecomputeProcessPriority();
2650 #if defined(XP_WIN) && defined(ACCESSIBILITY)
2651 if (a11y::Compatibility::IsDolphin()) {
2652 // update active accessible documents on windows
2653 if (a11y::DocAccessibleParent
* tabDoc
=
2654 bp
->GetTopLevelDocAccessible()) {
2655 HWND window
= tabDoc
->GetEmulatedWindowHandle();
2659 a11y::nsWinUtils::ShowNativeWindow(window
);
2661 a11y::nsWinUtils::HideNativeWindow(window
);
2671 PreOrderWalk([&](BrowsingContext
* aContext
) {
2672 if (nsCOMPtr
<nsIDocShell
> ds
= aContext
->GetDocShell()) {
2673 nsDocShell::Cast(ds
)->ActivenessMaybeChanged();
2678 void BrowsingContext::DidSet(FieldIndex
<IDX_InRDMPane
>, bool aOldValue
) {
2680 "Should only set InRDMPane in the top-level browsing context");
2681 if (GetInRDMPane() == aOldValue
) {
2684 PresContextAffectingFieldChanged();
2687 bool BrowsingContext::CanSet(FieldIndex
<IDX_PageAwakeRequestCount
>,
2688 uint32_t aNewValue
, ContentParent
* aSource
) {
2689 return IsTop() && XRE_IsParentProcess() && !aSource
;
2692 void BrowsingContext::DidSet(FieldIndex
<IDX_PageAwakeRequestCount
>,
2693 uint32_t aOldValue
) {
2694 if (!IsTop() || aOldValue
== GetPageAwakeRequestCount()) {
2697 Group()->UpdateToplevelsSuspendedIfNeeded();
2700 auto BrowsingContext::CanSet(FieldIndex
<IDX_AllowJavascript
>, bool aValue
,
2701 ContentParent
* aSource
) -> CanSetResult
{
2702 if (mozilla::SessionHistoryInParent()) {
2703 return XRE_IsParentProcess() && !aSource
? CanSetResult::Allow
2704 : CanSetResult::Deny
;
2707 // Without Session History in Parent, session restore code still needs to set
2708 // this from content processes.
2709 return LegacyRevertIfNotOwningOrParentProcess(aSource
);
2712 void BrowsingContext::DidSet(FieldIndex
<IDX_AllowJavascript
>, bool aOldValue
) {
2713 RecomputeCanExecuteScripts();
2716 void BrowsingContext::RecomputeCanExecuteScripts() {
2717 const bool old
= mCanExecuteScripts
;
2718 if (!AllowJavascript()) {
2719 // Scripting has been explicitly disabled on our BrowsingContext.
2720 mCanExecuteScripts
= false;
2721 } else if (GetParentWindowContext()) {
2722 // Otherwise, inherit parent.
2723 mCanExecuteScripts
= GetParentWindowContext()->CanExecuteScripts();
2725 // Otherwise, we're the root of the tree, and we haven't explicitly disabled
2727 mCanExecuteScripts
= true;
2730 if (old
!= mCanExecuteScripts
) {
2731 for (WindowContext
* wc
: GetWindowContexts()) {
2732 wc
->RecomputeCanExecuteScripts();
2737 bool BrowsingContext::InactiveForSuspend() const {
2738 if (!StaticPrefs::dom_suspend_inactive_enabled()) {
2741 // We should suspend a page only when it's inactive and doesn't have any awake
2742 // request that is used to prevent page from being suspended because web page
2743 // might still need to run their script. Eg. waiting for media keys to resume
2744 // media, playing web audio, waiting in a video call conference room.
2745 return !IsActive() && GetPageAwakeRequestCount() == 0;
2748 bool BrowsingContext::CanSet(FieldIndex
<IDX_TouchEventsOverrideInternal
>,
2749 dom::TouchEventsOverride
, ContentParent
* aSource
) {
2750 return XRE_IsParentProcess() && !aSource
;
2753 void BrowsingContext::DidSet(FieldIndex
<IDX_TouchEventsOverrideInternal
>,
2754 dom::TouchEventsOverride
&& aOldValue
) {
2755 if (GetTouchEventsOverrideInternal() == aOldValue
) {
2758 WalkPresContexts([&](nsPresContext
* aPc
) {
2759 aPc
->MediaFeatureValuesChanged(
2760 {MediaFeatureChangeReason::SystemMetricsChange
},
2761 // We're already iterating through sub documents, so we don't need to
2762 // propagate the change again.
2763 MediaFeatureChangePropagation::JustThisDocument
);
2767 void BrowsingContext::DidSet(FieldIndex
<IDX_EmbedderColorSchemes
>,
2768 EmbedderColorSchemes
&& aOldValue
) {
2769 if (GetEmbedderColorSchemes() == aOldValue
) {
2772 PresContextAffectingFieldChanged();
2775 void BrowsingContext::DidSet(FieldIndex
<IDX_PrefersColorSchemeOverride
>,
2776 dom::PrefersColorSchemeOverride aOldValue
) {
2777 MOZ_ASSERT(IsTop());
2778 if (PrefersColorSchemeOverride() == aOldValue
) {
2781 PresContextAffectingFieldChanged();
2784 void BrowsingContext::DidSet(FieldIndex
<IDX_MediumOverride
>,
2785 nsString
&& aOldValue
) {
2786 MOZ_ASSERT(IsTop());
2787 if (GetMediumOverride() == aOldValue
) {
2790 PresContextAffectingFieldChanged();
2793 void BrowsingContext::DidSet(FieldIndex
<IDX_DisplayMode
>,
2794 enum DisplayMode aOldValue
) {
2795 MOZ_ASSERT(IsTop());
2797 if (GetDisplayMode() == aOldValue
) {
2801 WalkPresContexts([&](nsPresContext
* aPc
) {
2802 aPc
->MediaFeatureValuesChanged(
2803 {MediaFeatureChangeReason::DisplayModeChange
},
2804 // We're already iterating through sub documents, so we don't need
2805 // to propagate the change again.
2807 // Images and other resources don't change their display-mode
2808 // evaluation, display-mode is a property of the browsing context.
2809 MediaFeatureChangePropagation::JustThisDocument
);
2813 void BrowsingContext::DidSet(FieldIndex
<IDX_Muted
>) {
2814 MOZ_ASSERT(IsTop(), "Set muted flag on non top-level context!");
2815 USER_ACTIVATION_LOG("Set audio muted %d for %s browsing context 0x%08" PRIx64
,
2816 GetMuted(), XRE_IsParentProcess() ? "Parent" : "Child",
2818 PreOrderWalk([&](BrowsingContext
* aContext
) {
2819 nsPIDOMWindowOuter
* win
= aContext
->GetDOMWindow();
2821 win
->RefreshMediaElementsVolume();
2826 bool BrowsingContext::CanSet(FieldIndex
<IDX_IsAppTab
>, const bool& aValue
,
2827 ContentParent
* aSource
) {
2828 return XRE_IsParentProcess() && !aSource
&& IsTop();
2831 bool BrowsingContext::CanSet(FieldIndex
<IDX_HasSiblings
>, const bool& aValue
,
2832 ContentParent
* aSource
) {
2833 return XRE_IsParentProcess() && !aSource
&& IsTop();
2836 bool BrowsingContext::CanSet(FieldIndex
<IDX_ShouldDelayMediaFromStart
>,
2837 const bool& aValue
, ContentParent
* aSource
) {
2841 void BrowsingContext::DidSet(FieldIndex
<IDX_ShouldDelayMediaFromStart
>,
2843 MOZ_ASSERT(IsTop(), "Set attribute on non top-level context!");
2844 if (aOldValue
== GetShouldDelayMediaFromStart()) {
2847 if (!GetShouldDelayMediaFromStart()) {
2848 PreOrderWalk([&](BrowsingContext
* aContext
) {
2849 if (nsPIDOMWindowOuter
* win
= aContext
->GetDOMWindow()) {
2850 win
->ActivateMediaComponents();
2856 bool BrowsingContext::CanSet(FieldIndex
<IDX_OverrideDPPX
>, const float& aValue
,
2857 ContentParent
* aSource
) {
2858 return XRE_IsParentProcess() && !aSource
&& IsTop();
2861 void BrowsingContext::DidSet(FieldIndex
<IDX_OverrideDPPX
>, float aOldValue
) {
2862 MOZ_ASSERT(IsTop());
2863 if (GetOverrideDPPX() == aOldValue
) {
2866 PresContextAffectingFieldChanged();
2869 void BrowsingContext::SetCustomUserAgent(const nsAString
& aUserAgent
,
2871 Top()->SetUserAgentOverride(aUserAgent
, aRv
);
2874 nsresult
BrowsingContext::SetCustomUserAgent(const nsAString
& aUserAgent
) {
2875 return Top()->SetUserAgentOverride(aUserAgent
);
2878 void BrowsingContext::DidSet(FieldIndex
<IDX_UserAgentOverride
>) {
2879 MOZ_ASSERT(IsTop());
2881 PreOrderWalk([&](BrowsingContext
* aContext
) {
2882 nsIDocShell
* shell
= aContext
->GetDocShell();
2884 shell
->ClearCachedUserAgent();
2889 bool BrowsingContext::CanSet(FieldIndex
<IDX_IsInBFCache
>, bool,
2890 ContentParent
* aSource
) {
2891 return IsTop() && !aSource
&& mozilla::BFCacheInParent();
2894 void BrowsingContext::DidSet(FieldIndex
<IDX_IsInBFCache
>) {
2895 MOZ_RELEASE_ASSERT(mozilla::BFCacheInParent());
2896 MOZ_DIAGNOSTIC_ASSERT(IsTop());
2898 const bool isInBFCache
= GetIsInBFCache();
2900 UpdateCurrentTopByBrowserId(this);
2901 PreOrderWalk([&](BrowsingContext
* aContext
) {
2902 aContext
->mIsInBFCache
= false;
2903 nsCOMPtr
<nsIDocShell
> shell
= aContext
->GetDocShell();
2905 nsDocShell::Cast(shell
)->ThawFreezeNonRecursive(true);
2910 if (isInBFCache
&& XRE_IsContentProcess() && mDocShell
) {
2911 nsDocShell::Cast(mDocShell
)->MaybeDisconnectChildListenersOnPageHide();
2915 PreOrderWalk([&](BrowsingContext
* aContext
) {
2916 nsCOMPtr
<nsIDocShell
> shell
= aContext
->GetDocShell();
2918 nsDocShell::Cast(shell
)->FirePageHideShowNonRecursive(false);
2922 PostOrderWalk([&](BrowsingContext
* aContext
) {
2923 nsCOMPtr
<nsIDocShell
> shell
= aContext
->GetDocShell();
2925 nsDocShell::Cast(shell
)->FirePageHideShowNonRecursive(true);
2931 PreOrderWalk([&](BrowsingContext
* aContext
) {
2932 nsCOMPtr
<nsIDocShell
> shell
= aContext
->GetDocShell();
2934 nsDocShell::Cast(shell
)->ThawFreezeNonRecursive(false);
2935 if (nsPresContext
* pc
= shell
->GetPresContext()) {
2936 pc
->EventStateManager()->ResetHoverState();
2939 aContext
->mIsInBFCache
= true;
2940 Document
* doc
= aContext
->GetDocument();
2942 // Notifying needs to happen after mIsInBFCache is set to true.
2943 doc
->NotifyActivityChanged();
2947 if (XRE_IsParentProcess()) {
2948 if (mCurrentWindowContext
&&
2949 mCurrentWindowContext
->Canonical()->Fullscreen()) {
2950 mCurrentWindowContext
->Canonical()->ExitTopChromeDocumentFullscreen();
2956 void BrowsingContext::DidSet(FieldIndex
<IDX_SyntheticDocumentContainer
>) {
2957 if (WindowContext
* parentWindowContext
= GetParentWindowContext()) {
2958 parentWindowContext
->UpdateChildSynthetic(this,
2959 GetSyntheticDocumentContainer());
2963 void BrowsingContext::SetCustomPlatform(const nsAString
& aPlatform
,
2965 Top()->SetPlatformOverride(aPlatform
, aRv
);
2968 void BrowsingContext::DidSet(FieldIndex
<IDX_PlatformOverride
>) {
2969 MOZ_ASSERT(IsTop());
2971 PreOrderWalk([&](BrowsingContext
* aContext
) {
2972 nsIDocShell
* shell
= aContext
->GetDocShell();
2974 shell
->ClearCachedPlatform();
2979 auto BrowsingContext::LegacyRevertIfNotOwningOrParentProcess(
2980 ContentParent
* aSource
) -> CanSetResult
{
2982 MOZ_ASSERT(XRE_IsParentProcess());
2984 if (!Canonical()->IsOwnedByProcess(aSource
->ChildID())) {
2985 return CanSetResult::Revert
;
2987 } else if (!IsInProcess() && !XRE_IsParentProcess()) {
2988 // Don't allow this to be set from content processes that
2989 // don't own the BrowsingContext.
2990 return CanSetResult::Deny
;
2993 return CanSetResult::Allow
;
2996 bool BrowsingContext::CanSet(FieldIndex
<IDX_IsActiveBrowserWindowInternal
>,
2997 const bool& aValue
, ContentParent
* aSource
) {
2998 // Should only be set in the parent process.
2999 return XRE_IsParentProcess() && !aSource
&& IsTop();
3002 void BrowsingContext::DidSet(FieldIndex
<IDX_IsActiveBrowserWindowInternal
>,
3004 bool isActivateEvent
= GetIsActiveBrowserWindowInternal();
3005 // The browser window containing this context has changed
3006 // activation state so update window inactive document states
3007 // for all in-process documents.
3008 PreOrderWalk([isActivateEvent
](BrowsingContext
* aContext
) {
3009 if (RefPtr
<Document
> doc
= aContext
->GetExtantDocument()) {
3010 doc
->UpdateDocumentStates(DocumentState::WINDOW_INACTIVE
, true);
3012 RefPtr
<nsPIDOMWindowInner
> win
= doc
->GetInnerWindow();
3014 RefPtr
<MediaDevices
> devices
;
3015 if (isActivateEvent
&& (devices
= win
->GetExtantMediaDevices())) {
3016 devices
->BrowserWindowBecameActive();
3019 if (XRE_IsContentProcess() &&
3020 (!aContext
->GetParent() || !aContext
->GetParent()->IsInProcess())) {
3021 // Send the inner window an activate/deactivate event if
3022 // the context is the top of a sub-tree of in-process
3024 nsContentUtils::DispatchEventOnlyToChrome(
3025 doc
, nsGlobalWindowInner::Cast(win
),
3026 isActivateEvent
? u
"activate"_ns
: u
"deactivate"_ns
,
3027 CanBubble::eYes
, Cancelable::eYes
, nullptr);
3034 bool BrowsingContext::CanSet(FieldIndex
<IDX_OpenerPolicy
>,
3035 nsILoadInfo::CrossOriginOpenerPolicy aPolicy
,
3036 ContentParent
* aSource
) {
3037 // A potentially cross-origin isolated BC can't change opener policy, nor can
3038 // a BC become potentially cross-origin isolated. An unchanged policy is
3040 return GetOpenerPolicy() == aPolicy
||
3041 (GetOpenerPolicy() !=
3043 OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP
&&
3046 OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP
);
3049 auto BrowsingContext::CanSet(FieldIndex
<IDX_AllowContentRetargeting
>,
3050 const bool& aAllowContentRetargeting
,
3051 ContentParent
* aSource
) -> CanSetResult
{
3052 return LegacyRevertIfNotOwningOrParentProcess(aSource
);
3055 auto BrowsingContext::CanSet(FieldIndex
<IDX_AllowContentRetargetingOnChildren
>,
3056 const bool& aAllowContentRetargetingOnChildren
,
3057 ContentParent
* aSource
) -> CanSetResult
{
3058 return LegacyRevertIfNotOwningOrParentProcess(aSource
);
3061 auto BrowsingContext::CanSet(FieldIndex
<IDX_AllowPlugins
>,
3062 const bool& aAllowPlugins
, ContentParent
* aSource
)
3064 return LegacyRevertIfNotOwningOrParentProcess(aSource
);
3067 bool BrowsingContext::CanSet(FieldIndex
<IDX_FullscreenAllowedByOwner
>,
3068 const bool& aAllowed
, ContentParent
* aSource
) {
3069 return CheckOnlyEmbedderCanSet(aSource
);
3072 bool BrowsingContext::CanSet(FieldIndex
<IDX_UseErrorPages
>,
3073 const bool& aUseErrorPages
,
3074 ContentParent
* aSource
) {
3075 return CheckOnlyEmbedderCanSet(aSource
);
3078 TouchEventsOverride
BrowsingContext::TouchEventsOverride() const {
3079 for (const auto* bc
= this; bc
; bc
= bc
->GetParent()) {
3080 auto tev
= bc
->GetTouchEventsOverrideInternal();
3081 if (tev
!= dom::TouchEventsOverride::None
) {
3085 return dom::TouchEventsOverride::None
;
3088 bool BrowsingContext::TargetTopLevelLinkClicksToBlank() const {
3089 return Top()->GetTargetTopLevelLinkClicksToBlankInternal();
3092 // We map `watchedByDevTools` WebIDL attribute to `watchedByDevToolsInternal`
3093 // BC field. And we map it to the top level BrowsingContext.
3094 bool BrowsingContext::WatchedByDevTools() {
3095 return Top()->GetWatchedByDevToolsInternal();
3098 // Enforce that the watchedByDevTools BC field can only be set on the top level
3099 // Browsing Context.
3100 bool BrowsingContext::CanSet(FieldIndex
<IDX_WatchedByDevToolsInternal
>,
3101 const bool& aWatchedByDevTools
,
3102 ContentParent
* aSource
) {
3105 void BrowsingContext::SetWatchedByDevTools(bool aWatchedByDevTools
,
3108 aRv
.ThrowInvalidModificationError(
3109 "watchedByDevTools can only be set on top BrowsingContext");
3112 SetWatchedByDevToolsInternal(aWatchedByDevTools
, aRv
);
3115 auto BrowsingContext::CanSet(FieldIndex
<IDX_DefaultLoadFlags
>,
3116 const uint32_t& aDefaultLoadFlags
,
3117 ContentParent
* aSource
) -> CanSetResult
{
3118 // Bug 1623565 - Are these flags only used by the debugger, which makes it
3119 // possible that this field can only be settable by the parent process?
3120 return LegacyRevertIfNotOwningOrParentProcess(aSource
);
3123 void BrowsingContext::DidSet(FieldIndex
<IDX_DefaultLoadFlags
>) {
3124 auto loadFlags
= GetDefaultLoadFlags();
3125 if (GetDocShell()) {
3126 nsDocShell::Cast(GetDocShell())->SetLoadGroupDefaultLoadFlags(loadFlags
);
3129 if (XRE_IsParentProcess()) {
3130 PreOrderWalk([&](BrowsingContext
* aContext
) {
3131 if (aContext
!= this) {
3132 // Setting load flags on a discarded context has no effect.
3133 Unused
<< aContext
->SetDefaultLoadFlags(loadFlags
);
3139 bool BrowsingContext::CanSet(FieldIndex
<IDX_UseGlobalHistory
>,
3140 const bool& aUseGlobalHistory
,
3141 ContentParent
* aSource
) {
3142 // Should only be set in the parent process.
3143 // return XRE_IsParentProcess() && !aSource;
3147 auto BrowsingContext::CanSet(FieldIndex
<IDX_UserAgentOverride
>,
3148 const nsString
& aUserAgent
, ContentParent
* aSource
)
3151 return CanSetResult::Deny
;
3154 return LegacyRevertIfNotOwningOrParentProcess(aSource
);
3157 auto BrowsingContext::CanSet(FieldIndex
<IDX_PlatformOverride
>,
3158 const nsString
& aPlatform
, ContentParent
* aSource
)
3161 return CanSetResult::Deny
;
3164 return LegacyRevertIfNotOwningOrParentProcess(aSource
);
3167 bool BrowsingContext::CheckOnlyEmbedderCanSet(ContentParent
* aSource
) {
3168 if (XRE_IsParentProcess()) {
3169 uint64_t childId
= aSource
? aSource
->ChildID() : 0;
3170 return Canonical()->IsEmbeddedInProcess(childId
);
3172 return mEmbeddedByThisProcess
;
3175 bool BrowsingContext::CanSet(FieldIndex
<IDX_EmbedderInnerWindowId
>,
3176 const uint64_t& aValue
, ContentParent
* aSource
) {
3177 // If we have a parent window, our embedder inner window ID must match it.
3178 if (mParentWindow
) {
3179 return mParentWindow
->Id() == aValue
;
3182 // For toplevel BrowsingContext instances, this value may only be set by the
3183 // parent process, or initialized to `0`.
3184 return CheckOnlyEmbedderCanSet(aSource
);
3187 bool BrowsingContext::CanSet(FieldIndex
<IDX_EmbedderElementType
>,
3188 const Maybe
<nsString
>&, ContentParent
* aSource
) {
3189 return CheckOnlyEmbedderCanSet(aSource
);
3192 auto BrowsingContext::CanSet(FieldIndex
<IDX_CurrentInnerWindowId
>,
3193 const uint64_t& aValue
, ContentParent
* aSource
)
3195 // Generally allow clearing this. We may want to be more precise about this
3196 // check in the future.
3198 return CanSetResult::Allow
;
3201 // We must have access to the specified context.
3202 RefPtr
<WindowContext
> window
= WindowContext::GetById(aValue
);
3203 if (!window
|| window
->GetBrowsingContext() != this) {
3204 return CanSetResult::Deny
;
3208 // If the sending process is no longer the current owner, revert
3209 MOZ_ASSERT(XRE_IsParentProcess());
3210 if (!Canonical()->IsOwnedByProcess(aSource
->ChildID())) {
3211 return CanSetResult::Revert
;
3213 } else if (XRE_IsContentProcess() && !IsOwnedByProcess()) {
3214 return CanSetResult::Deny
;
3217 return CanSetResult::Allow
;
3220 bool BrowsingContext::CanSet(FieldIndex
<IDX_ParentInitiatedNavigationEpoch
>,
3221 const uint64_t& aValue
, ContentParent
* aSource
) {
3222 return XRE_IsParentProcess() && !aSource
;
3225 void BrowsingContext::DidSet(FieldIndex
<IDX_CurrentInnerWindowId
>) {
3226 RefPtr
<WindowContext
> prevWindowContext
= mCurrentWindowContext
.forget();
3227 mCurrentWindowContext
= WindowContext::GetById(GetCurrentInnerWindowId());
3229 !mCurrentWindowContext
|| mWindowContexts
.Contains(mCurrentWindowContext
),
3230 "WindowContext not registered?");
3232 // Clear our cached `children` value, to ensure that JS sees the up-to-date
3234 BrowsingContext_Binding::ClearCachedChildrenValue(this);
3236 if (XRE_IsParentProcess()) {
3237 if (prevWindowContext
!= mCurrentWindowContext
) {
3238 if (prevWindowContext
) {
3239 prevWindowContext
->Canonical()->DidBecomeCurrentWindowGlobal(false);
3241 if (mCurrentWindowContext
) {
3242 // We set a timer when we set the current inner window. This
3243 // will then flush the session storage to session store to
3244 // make sure that we don't miss to store session storage to
3245 // session store that is a result of navigation. This is due
3246 // to Bug 1700623. We wish to fix this in Bug 1711886, where
3247 // making sure to store everything would make this timer
3249 Canonical()->MaybeScheduleSessionStoreUpdate();
3250 mCurrentWindowContext
->Canonical()->DidBecomeCurrentWindowGlobal(true);
3253 BrowserParent::UpdateFocusFromBrowsingContext();
3257 bool BrowsingContext::CanSet(FieldIndex
<IDX_IsPopupSpam
>, const bool& aValue
,
3258 ContentParent
* aSource
) {
3259 // Ensure that we only mark a browsing context as popup spam once and never
3261 return aValue
&& !GetIsPopupSpam();
3264 void BrowsingContext::DidSet(FieldIndex
<IDX_IsPopupSpam
>) {
3265 if (GetIsPopupSpam()) {
3266 PopupBlocker::RegisterOpenPopupSpam();
3270 bool BrowsingContext::CanSet(FieldIndex
<IDX_MessageManagerGroup
>,
3271 const nsString
& aMessageManagerGroup
,
3272 ContentParent
* aSource
) {
3273 // Should only be set in the parent process on toplevel.
3274 return XRE_IsParentProcess() && !aSource
&& IsTopContent();
3277 bool BrowsingContext::CanSet(
3278 FieldIndex
<IDX_OrientationLock
>,
3279 const mozilla::hal::ScreenOrientation
& aOrientationLock
,
3280 ContentParent
* aSource
) {
3284 bool BrowsingContext::IsLoading() {
3289 // If we're in the same process as the page, we're possibly just
3290 // updating the flag.
3291 nsIDocShell
* shell
= GetDocShell();
3293 Document
* doc
= shell
->GetDocument();
3294 return doc
&& doc
->GetReadyStateEnum() < Document::READYSTATE_COMPLETE
;
3300 void BrowsingContext::DidSet(FieldIndex
<IDX_Loading
>) {
3301 if (mFields
.Get
<IDX_Loading
>()) {
3305 while (!mDeprioritizedLoadRunner
.isEmpty()) {
3306 nsCOMPtr
<nsIRunnable
> runner
= mDeprioritizedLoadRunner
.popFirst();
3307 NS_DispatchToCurrentThread(runner
.forget());
3310 if (StaticPrefs::dom_separate_event_queue_for_post_message_enabled() &&
3312 Group()->FlushPostMessageEvents();
3316 // Inform the Document for this context of the (potential) change in
3318 void BrowsingContext::DidSet(FieldIndex
<IDX_AncestorLoading
>) {
3319 nsPIDOMWindowOuter
* outer
= GetDOMWindow();
3321 MOZ_LOG(gTimeoutDeferralLog
, mozilla::LogLevel::Debug
,
3322 ("DidSetAncestorLoading BC: %p -- No outer window", (void*)this));
3325 Document
* document
= nsGlobalWindowOuter::Cast(outer
)->GetExtantDoc();
3327 MOZ_LOG(gTimeoutDeferralLog
, mozilla::LogLevel::Debug
,
3328 ("DidSetAncestorLoading BC: %p -- NotifyLoading(%d, %d, %d)",
3329 (void*)this, GetAncestorLoading(), document
->GetReadyStateEnum(),
3330 document
->GetReadyStateEnum()));
3331 document
->NotifyLoading(GetAncestorLoading(), document
->GetReadyStateEnum(),
3332 document
->GetReadyStateEnum());
3336 void BrowsingContext::DidSet(FieldIndex
<IDX_AuthorStyleDisabledDefault
>) {
3338 "Should only set AuthorStyleDisabledDefault in the top "
3339 "browsing context");
3341 // We don't need to handle changes to this field, since PageStyleChild.sys.mjs
3342 // will respond to the PageStyle:Disable message in all content processes.
3344 // But we store the state here on the top BrowsingContext so that the
3345 // docshell has somewhere to look for the current author style disabling
3346 // state when new iframes are inserted.
3349 void BrowsingContext::DidSet(FieldIndex
<IDX_TextZoom
>, float aOldValue
) {
3350 if (GetTextZoom() == aOldValue
) {
3354 if (IsInProcess()) {
3355 if (nsIDocShell
* shell
= GetDocShell()) {
3356 if (nsPresContext
* pc
= shell
->GetPresContext()) {
3357 pc
->RecomputeBrowsingContextDependentData();
3361 for (BrowsingContext
* child
: Children()) {
3362 // Setting text zoom on a discarded context has no effect.
3363 Unused
<< child
->SetTextZoom(GetTextZoom());
3367 if (IsTop() && XRE_IsParentProcess()) {
3368 if (Element
* element
= GetEmbedderElement()) {
3369 AsyncEventDispatcher::RunDOMEventWhenSafe(*element
, u
"TextZoomChange"_ns
,
3371 ChromeOnlyDispatch::eYes
);
3376 // TODO(emilio): It'd be potentially nicer and cheaper to allow to set this only
3377 // on the Top() browsing context, but there are a lot of tests that rely on
3378 // zooming a subframe so...
3379 void BrowsingContext::DidSet(FieldIndex
<IDX_FullZoom
>, float aOldValue
) {
3380 if (GetFullZoom() == aOldValue
) {
3384 if (IsInProcess()) {
3385 if (nsIDocShell
* shell
= GetDocShell()) {
3386 if (nsPresContext
* pc
= shell
->GetPresContext()) {
3387 pc
->RecomputeBrowsingContextDependentData();
3391 for (BrowsingContext
* child
: Children()) {
3392 // Setting full zoom on a discarded context has no effect.
3393 Unused
<< child
->SetFullZoom(GetFullZoom());
3397 if (IsTop() && XRE_IsParentProcess()) {
3398 if (Element
* element
= GetEmbedderElement()) {
3399 AsyncEventDispatcher::RunDOMEventWhenSafe(*element
, u
"FullZoomChange"_ns
,
3401 ChromeOnlyDispatch::eYes
);
3406 void BrowsingContext::AddDeprioritizedLoadRunner(nsIRunnable
* aRunner
) {
3407 MOZ_ASSERT(IsLoading());
3408 MOZ_ASSERT(Top() == this);
3410 RefPtr
<DeprioritizedLoadRunner
> runner
= new DeprioritizedLoadRunner(aRunner
);
3411 mDeprioritizedLoadRunner
.insertBack(runner
);
3412 NS_DispatchToCurrentThreadQueue(
3413 runner
.forget(), StaticPrefs::page_load_deprioritization_period(),
3414 EventQueuePriority::Idle
);
3417 bool BrowsingContext::IsDynamic() const {
3418 const BrowsingContext
* current
= this;
3420 if (current
->CreatedDynamically()) {
3423 } while ((current
= current
->GetParent()));
3428 bool BrowsingContext::GetOffsetPath(nsTArray
<uint32_t>& aPath
) const {
3429 for (const BrowsingContext
* current
= this; current
&& current
->GetParent();
3430 current
= current
->GetParent()) {
3431 if (current
->CreatedDynamically()) {
3434 aPath
.AppendElement(current
->ChildOffset());
3439 void BrowsingContext::GetHistoryID(JSContext
* aCx
,
3440 JS::MutableHandle
<JS::Value
> aVal
,
3441 ErrorResult
& aError
) {
3442 if (!xpc::ID2JSValue(aCx
, GetHistoryID(), aVal
)) {
3443 aError
.Throw(NS_ERROR_OUT_OF_MEMORY
);
3447 void BrowsingContext::InitSessionHistory() {
3448 MOZ_ASSERT(!IsDiscarded());
3449 MOZ_ASSERT(IsTop());
3450 MOZ_ASSERT(EverAttached());
3452 if (!GetHasSessionHistory()) {
3453 MOZ_ALWAYS_SUCCEEDS(SetHasSessionHistory(true));
3457 ChildSHistory
* BrowsingContext::GetChildSessionHistory() {
3458 if (!mozilla::SessionHistoryInParent()) {
3459 // For now we're checking that the session history object for the child
3460 // process is available before returning the ChildSHistory object, because
3461 // it is the actual implementation that ChildSHistory forwards to. This can
3462 // be removed once session history is stored exclusively in the parent
3464 return mChildSessionHistory
&& mChildSessionHistory
->IsInProcess()
3465 ? mChildSessionHistory
.get()
3469 return mChildSessionHistory
;
3472 void BrowsingContext::CreateChildSHistory() {
3473 MOZ_ASSERT(IsTop());
3474 MOZ_ASSERT(GetHasSessionHistory());
3475 MOZ_ASSERT(!mChildSessionHistory
);
3477 // Because session history is global in a browsing context tree, every process
3478 // that has access to a browsing context tree needs access to its session
3479 // history. That is why we create the ChildSHistory object in every process
3480 // where we have access to this browsing context (which is the top one).
3481 mChildSessionHistory
= new ChildSHistory(this);
3483 // If the top browsing context (this one) is loaded in this process then we
3484 // also create the session history implementation for the child process.
3485 // This can be removed once session history is stored exclusively in the
3487 mChildSessionHistory
->SetIsInProcess(IsInProcess());
3490 void BrowsingContext::DidSet(FieldIndex
<IDX_HasSessionHistory
>,
3492 MOZ_ASSERT(GetHasSessionHistory() || !aOldValue
,
3493 "We don't support turning off session history.");
3495 if (GetHasSessionHistory() && !aOldValue
) {
3496 CreateChildSHistory();
3500 bool BrowsingContext::CanSet(
3501 FieldIndex
<IDX_TargetTopLevelLinkClicksToBlankInternal
>,
3502 const bool& aTargetTopLevelLinkClicksToBlankInternal
,
3503 ContentParent
* aSource
) {
3504 return XRE_IsParentProcess() && !aSource
&& IsTop();
3507 bool BrowsingContext::CanSet(FieldIndex
<IDX_BrowserId
>, const uint32_t& aValue
,
3508 ContentParent
* aSource
) {
3509 // We should only be able to set this for toplevel contexts which don't have
3511 return GetBrowserId() == 0 && IsTop() && Children().IsEmpty();
3514 bool BrowsingContext::CanSet(FieldIndex
<IDX_PendingInitialization
>,
3515 bool aNewValue
, ContentParent
* aSource
) {
3516 // Can only be cleared from `true` to `false`, and should only ever be set on
3517 // the toplevel BrowsingContext.
3518 return IsTop() && GetPendingInitialization() && !aNewValue
;
3521 bool BrowsingContext::CanSet(FieldIndex
<IDX_HasRestoreData
>, bool aNewValue
,
3522 ContentParent
* aSource
) {
3526 bool BrowsingContext::CanSet(FieldIndex
<IDX_IsUnderHiddenEmbedderElement
>,
3527 const bool& aIsUnderHiddenEmbedderElement
,
3528 ContentParent
* aSource
) {
3532 bool BrowsingContext::CanSet(FieldIndex
<IDX_ForceOffline
>, bool aNewValue
,
3533 ContentParent
* aSource
) {
3534 return XRE_IsParentProcess() && !aSource
;
3537 void BrowsingContext::DidSet(FieldIndex
<IDX_IsUnderHiddenEmbedderElement
>,
3539 nsIDocShell
* shell
= GetDocShell();
3543 const bool newValue
= IsUnderHiddenEmbedderElement();
3544 if (NS_WARN_IF(aOldValue
== newValue
)) {
3548 if (auto* bc
= BrowserChild::GetFrom(shell
)) {
3549 bc
->UpdateVisibility();
3552 if (PresShell
* presShell
= shell
->GetPresShell()) {
3553 presShell
->SetIsUnderHiddenEmbedderElement(newValue
);
3556 // Propagate to children.
3557 for (BrowsingContext
* child
: Children()) {
3558 Element
* embedderElement
= child
->GetEmbedderElement();
3559 if (!embedderElement
) {
3560 // TODO: We shouldn't need to null check here since `child` and the
3561 // element returned by `child->GetEmbedderElement()` are in our
3562 // process (the actual browsing context represented by `child` may not
3563 // be, but that doesn't matter). However, there are currently a very
3564 // small number of crashes due to `embedderElement` being null, somehow
3565 // - see bug 1551241. For now we wallpaper the crash.
3569 bool embedderFrameIsHidden
= true;
3570 if (auto* embedderFrame
= embedderElement
->GetPrimaryFrame()) {
3571 embedderFrameIsHidden
= !embedderFrame
->StyleVisibility()->IsVisible();
3574 bool hidden
= IsUnderHiddenEmbedderElement() || embedderFrameIsHidden
;
3575 if (child
->IsUnderHiddenEmbedderElement() != hidden
) {
3576 Unused
<< child
->SetIsUnderHiddenEmbedderElement(hidden
);
3581 bool BrowsingContext::IsPopupAllowed() {
3582 for (auto* context
= GetCurrentWindowContext(); context
;
3583 context
= context
->GetParentWindowContext()) {
3584 if (context
->CanShowPopup()) {
3593 bool BrowsingContext::ShouldAddEntryForRefresh(
3594 nsIURI
* aPreviousURI
, const SessionHistoryInfo
& aInfo
) {
3595 return ShouldAddEntryForRefresh(aPreviousURI
, aInfo
.GetURI(),
3596 aInfo
.HasPostData());
3600 bool BrowsingContext::ShouldAddEntryForRefresh(nsIURI
* aPreviousURI
,
3602 bool aHasPostData
) {
3607 bool equalsURI
= false;
3609 aPreviousURI
->Equals(aNewURI
, &equalsURI
);
3614 void BrowsingContext::SessionHistoryCommit(
3615 const LoadingSessionHistoryInfo
& aInfo
, uint32_t aLoadType
,
3616 nsIURI
* aPreviousURI
, SessionHistoryInfo
* aPreviousActiveEntry
,
3617 bool aPersist
, bool aCloneEntryChildren
, bool aChannelExpired
,
3618 uint32_t aCacheKey
) {
3620 if (XRE_IsContentProcess()) {
3621 RefPtr
<ChildSHistory
> rootSH
= Top()->GetChildSessionHistory();
3623 if (!aInfo
.mLoadIsFromSessionHistory
) {
3624 // We try to mimic as closely as possible what will happen in
3625 // CanonicalBrowsingContext::SessionHistoryCommit. We'll be
3626 // incrementing the session history length if we're not replacing,
3627 // this is a top-level load or it's not the initial load in an iframe,
3628 // ShouldUpdateSessionHistory(loadType) returns true and it's not a
3629 // refresh for which ShouldAddEntryForRefresh returns false.
3630 // It is possible that this leads to wrong length temporarily, but
3631 // so would not having the check for replace.
3632 // Note that nsSHistory::AddEntry does a replace load if the current
3633 // entry is not marked as a persisted entry. The child process does
3634 // not have access to the current entry, so we use the previous active
3635 // entry as the best approximation. When that's not the current entry
3636 // then the length might be wrong briefly, until the parent process
3637 // commits the actual length.
3638 if (!LOAD_TYPE_HAS_FLAGS(
3639 aLoadType
, nsIWebNavigation::LOAD_FLAGS_REPLACE_HISTORY
) &&
3641 ? (!aPreviousActiveEntry
|| aPreviousActiveEntry
->GetPersist())
3642 : !!aPreviousActiveEntry
) &&
3643 ShouldUpdateSessionHistory(aLoadType
) &&
3644 (!LOAD_TYPE_HAS_FLAGS(aLoadType
,
3645 nsIWebNavigation::LOAD_FLAGS_IS_REFRESH
) ||
3646 ShouldAddEntryForRefresh(aPreviousURI
, aInfo
.mInfo
))) {
3647 changeID
= rootSH
->AddPendingHistoryChange();
3650 // History load doesn't change the length, only index.
3651 changeID
= rootSH
->AddPendingHistoryChange(aInfo
.mOffset
, 0);
3654 ContentChild
* cc
= ContentChild::GetSingleton();
3655 mozilla::Unused
<< cc
->SendHistoryCommit(
3656 this, aInfo
.mLoadId
, changeID
, aLoadType
, aPersist
, aCloneEntryChildren
,
3657 aChannelExpired
, aCacheKey
);
3659 Canonical()->SessionHistoryCommit(aInfo
.mLoadId
, changeID
, aLoadType
,
3660 aPersist
, aCloneEntryChildren
,
3661 aChannelExpired
, aCacheKey
);
3665 void BrowsingContext::SetActiveSessionHistoryEntry(
3666 const Maybe
<nsPoint
>& aPreviousScrollPos
, SessionHistoryInfo
* aInfo
,
3667 uint32_t aLoadType
, uint32_t aUpdatedCacheKey
, bool aUpdateLength
) {
3668 if (XRE_IsContentProcess()) {
3669 // XXX Why we update cache key only in content process case?
3670 if (aUpdatedCacheKey
!= 0) {
3671 aInfo
->SetCacheKey(aUpdatedCacheKey
);
3675 if (aUpdateLength
) {
3676 RefPtr
<ChildSHistory
> shistory
= Top()->GetChildSessionHistory();
3678 changeID
= shistory
->AddPendingHistoryChange();
3681 ContentChild::GetSingleton()->SendSetActiveSessionHistoryEntry(
3682 this, aPreviousScrollPos
, *aInfo
, aLoadType
, aUpdatedCacheKey
,
3685 Canonical()->SetActiveSessionHistoryEntry(
3686 aPreviousScrollPos
, aInfo
, aLoadType
, aUpdatedCacheKey
, nsID());
3690 void BrowsingContext::ReplaceActiveSessionHistoryEntry(
3691 SessionHistoryInfo
* aInfo
) {
3692 if (XRE_IsContentProcess()) {
3693 ContentChild::GetSingleton()->SendReplaceActiveSessionHistoryEntry(this,
3696 Canonical()->ReplaceActiveSessionHistoryEntry(aInfo
);
3700 void BrowsingContext::RemoveDynEntriesFromActiveSessionHistoryEntry() {
3701 if (XRE_IsContentProcess()) {
3702 ContentChild::GetSingleton()
3703 ->SendRemoveDynEntriesFromActiveSessionHistoryEntry(this);
3705 Canonical()->RemoveDynEntriesFromActiveSessionHistoryEntry();
3709 void BrowsingContext::RemoveFromSessionHistory(const nsID
& aChangeID
) {
3710 if (XRE_IsContentProcess()) {
3711 ContentChild::GetSingleton()->SendRemoveFromSessionHistory(this, aChangeID
);
3713 Canonical()->RemoveFromSessionHistory(aChangeID
);
3717 void BrowsingContext::HistoryGo(
3718 int32_t aOffset
, uint64_t aHistoryEpoch
, bool aRequireUserInteraction
,
3719 bool aUserActivation
, std::function
<void(Maybe
<int32_t>&&)>&& aResolver
) {
3720 if (XRE_IsContentProcess()) {
3721 ContentChild::GetSingleton()->SendHistoryGo(
3722 this, aOffset
, aHistoryEpoch
, aRequireUserInteraction
, aUserActivation
,
3723 std::move(aResolver
),
3725 ResponseRejectReason
) { /* FIXME Is ignoring this fine? */ });
3727 RefPtr
<CanonicalBrowsingContext
> self
= Canonical();
3728 aResolver(self
->HistoryGo(
3729 aOffset
, aHistoryEpoch
, aRequireUserInteraction
, aUserActivation
,
3730 Canonical()->GetContentParent()
3731 ? Some(Canonical()->GetContentParent()->ChildID())
3736 void BrowsingContext::SetChildSHistory(ChildSHistory
* aChildSHistory
) {
3737 mChildSessionHistory
= aChildSHistory
;
3738 mChildSessionHistory
->SetBrowsingContext(this);
3739 mFields
.SetWithoutSyncing
<IDX_HasSessionHistory
>(true);
3742 bool BrowsingContext::ShouldUpdateSessionHistory(uint32_t aLoadType
) {
3743 // We don't update session history on reload unless we're loading
3744 // an iframe in shift-reload case.
3745 return nsDocShell::ShouldUpdateGlobalHistory(aLoadType
) &&
3746 (!(aLoadType
& nsIDocShell::LOAD_CMD_RELOAD
) ||
3747 (IsForceReloadType(aLoadType
) && IsSubframe()));
3750 nsresult
BrowsingContext::CheckLocationChangeRateLimit(CallerType aCallerType
) {
3751 // We only rate limit non system callers
3752 if (aCallerType
== CallerType::System
) {
3756 // Fetch rate limiting preferences
3757 uint32_t limitCount
=
3758 StaticPrefs::dom_navigation_locationChangeRateLimit_count();
3759 uint32_t timeSpanSeconds
=
3760 StaticPrefs::dom_navigation_locationChangeRateLimit_timespan();
3762 // Disable throttling if either of the preferences is set to 0.
3763 if (limitCount
== 0 || timeSpanSeconds
== 0) {
3767 TimeDuration throttleSpan
= TimeDuration::FromSeconds(timeSpanSeconds
);
3769 if (mLocationChangeRateLimitSpanStart
.IsNull() ||
3770 ((TimeStamp::Now() - mLocationChangeRateLimitSpanStart
) > throttleSpan
)) {
3771 // Initial call or timespan exceeded, reset counter and timespan.
3772 mLocationChangeRateLimitSpanStart
= TimeStamp::Now();
3773 mLocationChangeRateLimitCount
= 1;
3777 if (mLocationChangeRateLimitCount
>= limitCount
) {
3778 // Rate limit reached
3780 Document
* doc
= GetDocument();
3782 nsContentUtils::ReportToConsole(nsIScriptError::errorFlag
, "DOM"_ns
, doc
,
3783 nsContentUtils::eDOM_PROPERTIES
,
3784 "LocChangeFloodingPrevented");
3787 return NS_ERROR_DOM_SECURITY_ERR
;
3790 mLocationChangeRateLimitCount
++;
3794 void BrowsingContext::ResetLocationChangeRateLimit() {
3795 // Resetting the timestamp object will cause the check function to
3796 // init again and reset the rate limit.
3797 mLocationChangeRateLimitSpanStart
= TimeStamp();
3800 void BrowsingContext::LocationCreated(dom::Location
* aLocation
) {
3801 MOZ_ASSERT(!aLocation
->isInList());
3802 mLocations
.insertBack(aLocation
);
3805 void BrowsingContext::ClearCachedValuesOfLocations() {
3806 for (dom::Location
* loc
= mLocations
.getFirst(); loc
; loc
= loc
->getNext()) {
3807 loc
->ClearCachedValues();
3815 void IPDLParamTraits
<dom::MaybeDiscarded
<dom::BrowsingContext
>>::Write(
3816 IPC::MessageWriter
* aWriter
, IProtocol
* aActor
,
3817 const dom::MaybeDiscarded
<dom::BrowsingContext
>& aParam
) {
3818 MOZ_DIAGNOSTIC_ASSERT(!aParam
.GetMaybeDiscarded() ||
3819 aParam
.GetMaybeDiscarded()->EverAttached());
3820 uint64_t id
= aParam
.ContextId();
3821 WriteIPDLParam(aWriter
, aActor
, id
);
3824 bool IPDLParamTraits
<dom::MaybeDiscarded
<dom::BrowsingContext
>>::Read(
3825 IPC::MessageReader
* aReader
, IProtocol
* aActor
,
3826 dom::MaybeDiscarded
<dom::BrowsingContext
>* aResult
) {
3828 if (!ReadIPDLParam(aReader
, aActor
, &id
)) {
3834 } else if (RefPtr
<dom::BrowsingContext
> bc
= dom::BrowsingContext::Get(id
)) {
3835 *aResult
= std::move(bc
);
3837 aResult
->SetDiscarded(id
);
3842 void IPDLParamTraits
<dom::BrowsingContext::IPCInitializer
>::Write(
3843 IPC::MessageWriter
* aWriter
, IProtocol
* aActor
,
3844 const dom::BrowsingContext::IPCInitializer
& aInit
) {
3845 // Write actor ID parameters.
3846 WriteIPDLParam(aWriter
, aActor
, aInit
.mId
);
3847 WriteIPDLParam(aWriter
, aActor
, aInit
.mParentId
);
3848 WriteIPDLParam(aWriter
, aActor
, aInit
.mWindowless
);
3849 WriteIPDLParam(aWriter
, aActor
, aInit
.mUseRemoteTabs
);
3850 WriteIPDLParam(aWriter
, aActor
, aInit
.mUseRemoteSubframes
);
3851 WriteIPDLParam(aWriter
, aActor
, aInit
.mCreatedDynamically
);
3852 WriteIPDLParam(aWriter
, aActor
, aInit
.mChildOffset
);
3853 WriteIPDLParam(aWriter
, aActor
, aInit
.mOriginAttributes
);
3854 WriteIPDLParam(aWriter
, aActor
, aInit
.mRequestContextId
);
3855 WriteIPDLParam(aWriter
, aActor
, aInit
.mSessionHistoryIndex
);
3856 WriteIPDLParam(aWriter
, aActor
, aInit
.mSessionHistoryCount
);
3857 WriteIPDLParam(aWriter
, aActor
, aInit
.mFields
);
3860 bool IPDLParamTraits
<dom::BrowsingContext::IPCInitializer
>::Read(
3861 IPC::MessageReader
* aReader
, IProtocol
* aActor
,
3862 dom::BrowsingContext::IPCInitializer
* aInit
) {
3863 // Read actor ID parameters.
3864 if (!ReadIPDLParam(aReader
, aActor
, &aInit
->mId
) ||
3865 !ReadIPDLParam(aReader
, aActor
, &aInit
->mParentId
) ||
3866 !ReadIPDLParam(aReader
, aActor
, &aInit
->mWindowless
) ||
3867 !ReadIPDLParam(aReader
, aActor
, &aInit
->mUseRemoteTabs
) ||
3868 !ReadIPDLParam(aReader
, aActor
, &aInit
->mUseRemoteSubframes
) ||
3869 !ReadIPDLParam(aReader
, aActor
, &aInit
->mCreatedDynamically
) ||
3870 !ReadIPDLParam(aReader
, aActor
, &aInit
->mChildOffset
) ||
3871 !ReadIPDLParam(aReader
, aActor
, &aInit
->mOriginAttributes
) ||
3872 !ReadIPDLParam(aReader
, aActor
, &aInit
->mRequestContextId
) ||
3873 !ReadIPDLParam(aReader
, aActor
, &aInit
->mSessionHistoryIndex
) ||
3874 !ReadIPDLParam(aReader
, aActor
, &aInit
->mSessionHistoryCount
) ||
3875 !ReadIPDLParam(aReader
, aActor
, &aInit
->mFields
)) {
3881 template struct IPDLParamTraits
<dom::BrowsingContext::BaseTransaction
>;
3884 } // namespace mozilla