/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_dom_BrowsingContext_h #define mozilla_dom_BrowsingContext_h #include #include "GVAutoplayRequestUtils.h" #include "mozilla/ErrorResult.h" #include "mozilla/HalScreenConfiguration.h" #include "mozilla/LinkedList.h" #include "mozilla/Maybe.h" #include "mozilla/RefPtr.h" #include "mozilla/Span.h" #include "mozilla/Tuple.h" #include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/LocationBase.h" #include "mozilla/dom/MaybeDiscarded.h" #include "mozilla/dom/PopupBlocker.h" #include "mozilla/dom/UserActivation.h" #include "mozilla/dom/BrowsingContextBinding.h" #include "mozilla/dom/ScreenOrientationBinding.h" #include "mozilla/dom/SyncedContext.h" #include "nsCOMPtr.h" #include "nsCycleCollectionParticipant.h" #include "nsIDocShell.h" #include "nsTArray.h" #include "nsWrapperCache.h" #include "nsILoadInfo.h" #include "nsILoadContext.h" #include "nsThreadUtils.h" class nsDocShellLoadState; class nsGlobalWindowInner; class nsGlobalWindowOuter; class nsIPrincipal; class nsOuterWindowProxy; struct nsPoint; class PickleIterator; namespace IPC { class Message; } // namespace IPC namespace mozilla { class ErrorResult; class LogModule; namespace ipc { class IProtocol; template struct IPDLParamTraits; } // namespace ipc namespace dom { class BrowsingContent; class BrowsingContextGroup; class CanonicalBrowsingContext; class ChildSHistory; class ContentParent; class Element; struct LoadingSessionHistoryInfo; template struct Nullable; template class Sequence; class SessionHistoryInfo; class SessionStorageManager; class StructuredCloneHolder; class WindowContext; struct WindowPostMessageOptions; class WindowProxyHolder; enum class ExplicitActiveStatus : uint8_t { None, Active, Inactive, EndGuard_, }; // Fields are, by default, settable by any process and readable by any process. // Racy sets will be resolved as-if they occurred in the order the parent // process finds out about them. // // The `DidSet` and `CanSet` methods may be overloaded to provide different // behavior for a specific field. // * `DidSet` is called to run code in every process whenever the value is // updated (This currently occurs even if the value didn't change, though // this may change in the future). // * `CanSet` is called before attempting to set the value, in both the process // which calls `Set`, and the parent process, and will kill the misbehaving // process if it fails. #define MOZ_EACH_BC_FIELD(FIELD) \ FIELD(Name, nsString) \ FIELD(Closed, bool) \ FIELD(ExplicitActive, ExplicitActiveStatus) \ /* Top()-only. If true, new-playing media will be suspended when in an \ * inactive browsing context. */ \ FIELD(SuspendMediaWhenInactive, bool) \ /* If true, we're within the nested event loop in window.open, and this \ * context may not be used as the target of a load */ \ FIELD(PendingInitialization, bool) \ /* Indicates if the browser window is active for the purpose of the \ * :-moz-window-inactive pseudoclass. Only read from or set on the \ * top BrowsingContext. */ \ FIELD(IsActiveBrowserWindowInternal, bool) \ FIELD(OpenerPolicy, nsILoadInfo::CrossOriginOpenerPolicy) \ /* Current opener for the BrowsingContext. Weak reference */ \ FIELD(OpenerId, uint64_t) \ FIELD(OnePermittedSandboxedNavigatorId, uint64_t) \ /* WindowID of the inner window which embeds this BC */ \ FIELD(EmbedderInnerWindowId, uint64_t) \ FIELD(CurrentInnerWindowId, uint64_t) \ FIELD(HadOriginalOpener, bool) \ FIELD(IsPopupSpam, bool) \ /* Hold the audio muted state and should be used on top level browsing \ * contexts only */ \ FIELD(Muted, bool) \ /* See nsSandboxFlags.h for the possible flags. */ \ FIELD(SandboxFlags, uint32_t) \ FIELD(InitialSandboxFlags, uint32_t) \ /* A non-zero unique identifier for the browser element that is hosting \ * this \ * BrowsingContext tree. Every BrowsingContext in the element's tree will \ * return the same ID in all processes and it will remain stable \ * regardless of process changes. When a browser element's frameloader is \ * switched to another browser element this ID will remain the same but \ * hosted under the under the new browser element. */ \ FIELD(BrowserId, uint64_t) \ FIELD(HistoryID, nsID) \ FIELD(InRDMPane, bool) \ FIELD(Loading, bool) \ /* A field only set on top browsing contexts, which indicates that either: \ * \ * * This is a browsing context created explicitly for printing or print \ * preview (thus hosting static documents). \ * \ * * This is a browsing context where something in this tree is calling \ * window.print() (and thus showing a modal dialog). \ * \ * We use it exclusively to block navigation for both of these cases. */ \ FIELD(IsPrinting, bool) \ FIELD(AncestorLoading, bool) \ FIELD(AllowPlugins, bool) \ FIELD(AllowContentRetargeting, bool) \ FIELD(AllowContentRetargetingOnChildren, bool) \ FIELD(ForceEnableTrackingProtection, bool) \ FIELD(UseGlobalHistory, bool) \ FIELD(FullscreenAllowedByOwner, bool) \ /* These field are used to store the states of autoplay media request on \ * GeckoView only, and it would only be modified on the top level browsing \ * context. */ \ FIELD(GVAudibleAutoplayRequestStatus, GVAutoplayRequestStatus) \ FIELD(GVInaudibleAutoplayRequestStatus, GVAutoplayRequestStatus) \ /* ScreenOrientation-related APIs */ \ FIELD(CurrentOrientationAngle, float) \ FIELD(CurrentOrientationType, mozilla::dom::OrientationType) \ FIELD(OrientationLock, mozilla::hal::ScreenOrientation) \ FIELD(UserAgentOverride, nsString) \ FIELD(TouchEventsOverrideInternal, mozilla::dom::TouchEventsOverride) \ FIELD(EmbedderElementType, Maybe) \ FIELD(MessageManagerGroup, nsString) \ FIELD(MaxTouchPointsOverride, uint8_t) \ FIELD(FullZoom, float) \ FIELD(WatchedByDevToolsInternal, bool) \ FIELD(TextZoom, float) \ /* The current in-progress load. */ \ FIELD(CurrentLoadIdentifier, Maybe) \ /* See nsIRequest for possible flags. */ \ FIELD(DefaultLoadFlags, uint32_t) \ /* Signals that session history is enabled for this browsing context tree. \ * This is only ever set to true on the top BC, so consumers need to get \ * the value from the top BC! */ \ FIELD(HasSessionHistory, bool) \ /* Tracks if this context is the only top-level document in the session \ * history of the context. */ \ FIELD(IsSingleToplevelInHistory, bool) \ FIELD(UseErrorPages, bool) \ FIELD(PlatformOverride, nsString) \ FIELD(HasLoadedNonInitialDocument, bool) \ FIELD(CreatedDynamically, bool) \ /* Default value for nsIContentViewer::authorStyleDisabled in any new \ * browsing contexts created as a descendant of this one. Valid only for \ * top BCs. */ \ FIELD(AuthorStyleDisabledDefault, bool) \ FIELD(DisplayMode, mozilla::dom::DisplayMode) \ /* True if the top level browsing context owns a main media controller */ \ FIELD(HasMainMediaController, bool) // BrowsingContext, in this context, is the cross process replicated // environment in which information about documents is stored. In // particular the tree structure of nested browsing contexts is // represented by the tree of BrowsingContexts. // // The tree of BrowsingContexts is created in step with its // corresponding nsDocShell, and when nsDocShells are connected // through a parent/child relationship, so are BrowsingContexts. The // major difference is that BrowsingContexts are replicated (synced) // to the parent process, making it possible to traverse the // BrowsingContext tree for a tab, in both the parent and the child // process. // // Trees of BrowsingContexts should only ever contain nodes of the // same BrowsingContext::Type. This is enforced by asserts in the // BrowsingContext::Create* methods. class BrowsingContext : public nsILoadContext, public nsWrapperCache { MOZ_DECL_SYNCED_CONTEXT(BrowsingContext, MOZ_EACH_BC_FIELD) public: enum class Type { Chrome, Content }; static void Init(); static LogModule* GetLog(); // Look up a BrowsingContext in the current process by ID. static already_AddRefed Get(uint64_t aId); static already_AddRefed Get(GlobalObject&, uint64_t aId) { return Get(aId); } // Look up the top-level BrowsingContext by BrowserID. static already_AddRefed GetCurrentTopByBrowserId( uint64_t aBrowserId); static already_AddRefed GetFromWindow( WindowProxyHolder& aProxy); static already_AddRefed GetFromWindow( GlobalObject&, WindowProxyHolder& aProxy) { return GetFromWindow(aProxy); } static void DiscardFromContentParent(ContentParent* aCP); // Create a brand-new toplevel BrowsingContext with no relationships to other // BrowsingContexts, and which is not embedded within any or frame // element. // // This BrowsingContext is immediately attached, and cannot have LoadContext // flags customized unless it is of `Type::Chrome`. // // The process which created this BrowsingContext is responsible for detaching // it. static already_AddRefed CreateIndependent(Type aType); // Create a brand-new BrowsingContext object, but does not immediately attach // it. State such as OriginAttributes and PrivateBrowsingId may be customized // to configure the BrowsingContext before it is attached. // // `EnsureAttached()` must be called before the BrowsingContext is used for a // DocShell, BrowserParent, or BrowserBridgeChild. static already_AddRefed CreateDetached( nsGlobalWindowInner* aParent, BrowsingContext* aOpener, BrowsingContextGroup* aSpecificGroup, const nsAString& aName, Type aType, bool aCreatedDynamically = false); void EnsureAttached(); bool EverAttached() const { return mEverAttached; } // Cast this object to a canonical browsing context, and return it. CanonicalBrowsingContext* Canonical(); // Is the most recent Document in this BrowsingContext loaded within this // process? This may be true with a null mDocShell after the Window has been // closed. bool IsInProcess() const { return mIsInProcess; } bool IsOwnedByProcess() const; bool CanHaveRemoteOuterProxies() const { return !mIsInProcess || mDanglingRemoteOuterProxies; } // Has this BrowsingContext been discarded. A discarded browsing context has // been destroyed, and may not be available on the other side of an IPC // message. bool IsDiscarded() const { return mIsDiscarded; } // Returns true if none of the BrowsingContext's ancestor BrowsingContexts or // WindowContexts are discarded or cached. bool AncestorsAreCurrent() const; bool Windowless() const { return mWindowless; } // Get the DocShell for this BrowsingContext if it is in-process, or // null if it's not. nsIDocShell* GetDocShell() const { return mDocShell; } void SetDocShell(nsIDocShell* aDocShell); void ClearDocShell() { mDocShell = nullptr; } // Get the Document for this BrowsingContext if it is in-process, or // null if it's not. Document* GetDocument() const { return mDocShell ? mDocShell->GetDocument() : nullptr; } Document* GetExtantDocument() const { return mDocShell ? mDocShell->GetExtantDocument() : nullptr; } // This cleans up remote outer window proxies that might have been left behind // when the browsing context went from being remote to local. It does this by // turning them into cross-compartment wrappers to aOuter. If there is already // a remote proxy in the compartment of aOuter, then aOuter will get swapped // to it and the value of aOuter will be set to the object that used to be the // remote proxy and is now an OuterWindowProxy. void CleanUpDanglingRemoteOuterWindowProxies( JSContext* aCx, JS::MutableHandle aOuter); // Get the embedder element for this BrowsingContext if the embedder is // in-process, or null if it's not. Element* GetEmbedderElement() const { return mEmbedderElement; } void SetEmbedderElement(Element* aEmbedder); // Called after the BrowingContext has been embedded in a FrameLoader. This // happens after `SetEmbedderElement` is called on the BrowsingContext and // after the BrowsingContext has been set on the FrameLoader. void Embed(); // Get the outer window object for this BrowsingContext if it is in-process // and still has a docshell, or null otherwise. nsPIDOMWindowOuter* GetDOMWindow() const { return mDocShell ? mDocShell->GetWindow() : nullptr; } uint64_t GetRequestContextId() const { return mRequestContextId; } // Detach the current BrowsingContext from its parent, in both the // child and the parent process. void Detach(bool aFromIPC = false); // Prepare this BrowsingContext to leave the current process. void PrepareForProcessChange(); // Triggers a load in the process which currently owns this BrowsingContext. nsresult LoadURI(nsDocShellLoadState* aLoadState, bool aSetNavigating = false); nsresult InternalLoad(nsDocShellLoadState* aLoadState); // Removes the root document for this BrowsingContext tree from the BFCache, // if it is cached, and returns true if it was. bool RemoveRootFromBFCacheSync(); // If the load state includes a source BrowsingContext has been passed, check // to see if we are sandboxed from it as the result of an iframe or CSP // sandbox. nsresult CheckSandboxFlags(nsDocShellLoadState* aLoadState); void DisplayLoadError(const nsAString& aURI); // Determine if the current BrowsingContext is in the BFCache. bool IsCached() const; // Check that this browsing context is targetable for navigations (i.e. that // it is neither closed, cached, nor discarded). bool IsTargetable() const; // True if this browsing context is inactive and is able to be suspended. bool InactiveForSuspend() const; const nsString& Name() const { return GetName(); } void GetName(nsAString& aName) { aName = GetName(); } bool NameEquals(const nsAString& aName) { return GetName().Equals(aName); } Type GetType() const { return mType; } bool IsContent() const { return mType == Type::Content; } bool IsChrome() const { return !IsContent(); } bool IsTop() const { return !GetParent(); } bool IsFrame() const { return !IsTop(); } bool IsTopContent() const { return IsContent() && IsTop(); } bool IsInSubtreeOf(BrowsingContext* aContext); bool IsContentSubframe() const { return IsContent() && IsFrame(); } // non-zero uint64_t Id() const { return mBrowsingContextId; } BrowsingContext* GetParent() const; BrowsingContext* Top(); int32_t IndexOf(BrowsingContext* aChild); // NOTE: Unlike `GetEmbedderWindowGlobal`, `GetParentWindowContext` does not // cross toplevel content browser boundaries. WindowContext* GetParentWindowContext() const { return mParentWindow; } WindowContext* GetTopWindowContext(); already_AddRefed GetOpener() const { RefPtr opener(Get(GetOpenerId())); if (!mIsDiscarded && opener && !opener->mIsDiscarded) { MOZ_DIAGNOSTIC_ASSERT(opener->mType == mType); return opener.forget(); } return nullptr; } void SetOpener(BrowsingContext* aOpener) { MOZ_DIAGNOSTIC_ASSERT(!aOpener || aOpener->Group() == Group()); MOZ_DIAGNOSTIC_ASSERT(!aOpener || aOpener->mType == mType); MOZ_ALWAYS_SUCCEEDS(SetOpenerId(aOpener ? aOpener->Id() : 0)); } bool HasOpener() const; bool HadOriginalOpener() const { return GetHadOriginalOpener(); } // Returns true if the browsing context and top context are same origin bool SameOriginWithTop(); /** * When a new browsing context is opened by a sandboxed document, it needs to * keep track of the browsing context that opened it, so that it can be * navigated by it. This is the "one permitted sandboxed navigator". */ already_AddRefed GetOnePermittedSandboxedNavigator() const { return Get(GetOnePermittedSandboxedNavigatorId()); } [[nodiscard]] nsresult SetOnePermittedSandboxedNavigator( BrowsingContext* aNavigator) { if (GetOnePermittedSandboxedNavigatorId()) { MOZ_ASSERT(false, "One Permitted Sandboxed Navigator should only be set once."); return NS_ERROR_FAILURE; } else { return SetOnePermittedSandboxedNavigatorId(aNavigator ? aNavigator->Id() : 0); } } uint32_t SandboxFlags() { return GetSandboxFlags(); } Span> Children() const; void GetChildren(nsTArray>& aChildren); const nsTArray>& GetWindowContexts() { return mWindowContexts; } void GetWindowContexts(nsTArray>& aWindows); void RegisterWindowContext(WindowContext* aWindow); void UnregisterWindowContext(WindowContext* aWindow); WindowContext* GetCurrentWindowContext() const { return mCurrentWindowContext; } // Helpers to traverse this BrowsingContext subtree. Note that these will only // traverse active contexts, and will ignore ones in the BFCache. void PreOrderWalk(const std::function& aCallback); void PostOrderWalk(const std::function& aCallback); void GetAllBrowsingContextsInSubtree( nsTArray>& aBrowsingContexts); BrowsingContextGroup* Group() { return mGroup; } // WebIDL bindings for nsILoadContext Nullable GetAssociatedWindow(); Nullable GetTopWindow(); Element* GetTopFrameElement(); bool GetIsContent() { return IsContent(); } void SetUsePrivateBrowsing(bool aUsePrivateBrowsing, ErrorResult& aError); // Needs a different name to disambiguate from the xpidl method with // the same signature but different return value. void SetUseTrackingProtectionWebIDL(bool aUseTrackingProtection, ErrorResult& aRv); bool UseTrackingProtectionWebIDL() { return UseTrackingProtection(); } void GetOriginAttributes(JSContext* aCx, JS::MutableHandle aVal, ErrorResult& aError); bool InRDMPane() const { return GetInRDMPane(); } bool WatchedByDevTools(); void SetWatchedByDevTools(bool aWatchedByDevTools, ErrorResult& aRv); mozilla::dom::TouchEventsOverride TouchEventsOverride() const; void SetTouchEventsOverride( const enum TouchEventsOverride aTouchEventsOverride, ErrorResult& aRv); MOZ_MUST_USE nsresult SetTouchEventsOverride(const enum TouchEventsOverride aTouchEventsOverride); bool FullscreenAllowed() const; float FullZoom() const { return GetFullZoom(); } float TextZoom() const { return GetTextZoom(); } bool SuspendMediaWhenInactive() const { return GetSuspendMediaWhenInactive(); } bool IsActive() const; void SetIsActive(bool aIsActive, mozilla::ErrorResult& aRv) { SetExplicitActive(aIsActive ? ExplicitActiveStatus::Active : ExplicitActiveStatus::Inactive, aRv); } bool AuthorStyleDisabledDefault() const { return GetAuthorStyleDisabledDefault(); } bool UseGlobalHistory() const { return GetUseGlobalHistory(); } bool GetIsActiveBrowserWindow(); void SetIsActiveBrowserWindow(bool aActive); uint64_t BrowserId() const { return GetBrowserId(); } bool IsLoading(); void GetEmbedderElementType(nsString& aElementType) { if (GetEmbedderElementType().isSome()) { aElementType = GetEmbedderElementType().value(); } } bool IsLoadingIdentifier(uint64_t aLoadIdentifer) { if (GetCurrentLoadIdentifier() && *GetCurrentLoadIdentifier() == aLoadIdentifer) { return true; } return false; } // ScreenOrientation related APIs [[nodiscard]] nsresult SetCurrentOrientation(OrientationType aType, float aAngle) { Transaction txn; txn.SetCurrentOrientationType(aType); txn.SetCurrentOrientationAngle(aAngle); return txn.Commit(this); } void SetRDMPaneOrientation(OrientationType aType, float aAngle, ErrorResult& aRv) { if (InRDMPane()) { if (NS_FAILED(SetCurrentOrientation(aType, aAngle))) { aRv.ThrowInvalidStateError("Browsing context is discarded"); } } } void SetRDMPaneMaxTouchPoints(uint8_t aMaxTouchPoints, ErrorResult& aRv) { if (InRDMPane()) { SetMaxTouchPointsOverride(aMaxTouchPoints, aRv); } } // Using the rules for choosing a browsing context we try to find // the browsing context with the given name in the set of // transitively reachable browsing contexts. Performs access control // checks with regard to this. // See // https://html.spec.whatwg.org/multipage/browsers.html#the-rules-for-choosing-a-browsing-context-given-a-browsing-context-name. // // BrowsingContext::FindWithName(const nsAString&) is equivalent to // calling nsIDocShellTreeItem::FindItemWithName(aName, nullptr, // nullptr, false, ). BrowsingContext* FindWithName(const nsAString& aName, bool aUseEntryGlobalForAccessCheck = true); // Find a browsing context in this context's list of // children. Doesn't consider the special names, '_self', '_parent', // '_top', or '_blank'. Performs access control checks with regard to // 'this'. BrowsingContext* FindChildWithName(const nsAString& aName, BrowsingContext& aRequestingContext); // Find a browsing context in the subtree rooted at 'this' Doesn't // consider the special names, '_self', '_parent', '_top', or // '_blank'. Performs access control checks with regard to // 'aRequestingContext'. BrowsingContext* FindWithNameInSubtree(const nsAString& aName, BrowsingContext& aRequestingContext); nsISupports* GetParentObject() const; JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; // Return the window proxy object that corresponds to this browsing context. inline JSObject* GetWindowProxy() const { return mWindowProxy; } inline JSObject* GetUnbarrieredWindowProxy() const { return mWindowProxy.unbarrieredGet(); } // Set the window proxy object that corresponds to this browsing context. void SetWindowProxy(JS::Handle aWindowProxy) { mWindowProxy = aWindowProxy; } Nullable GetWindow(); NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(BrowsingContext) NS_DECL_NSILOADCONTEXT // Window APIs that are cross-origin-accessible (from the HTML spec). WindowProxyHolder Window(); BrowsingContext* GetBrowsingContext() { return this; }; BrowsingContext* Self() { return this; } void Location(JSContext* aCx, JS::MutableHandle aLocation, ErrorResult& aError); void Close(CallerType aCallerType, ErrorResult& aError); bool GetClosed(ErrorResult&) { return GetClosed(); } void Focus(CallerType aCallerType, ErrorResult& aError); void Blur(ErrorResult& aError); WindowProxyHolder GetFrames(ErrorResult& aError); int32_t Length() const { return Children().Length(); } Nullable GetTop(ErrorResult& aError); void GetOpener(JSContext* aCx, JS::MutableHandle aOpener, ErrorResult& aError) const; Nullable GetParent(ErrorResult& aError); void PostMessageMoz(JSContext* aCx, JS::Handle aMessage, const nsAString& aTargetOrigin, const Sequence& aTransfer, nsIPrincipal& aSubjectPrincipal, ErrorResult& aError); void PostMessageMoz(JSContext* aCx, JS::Handle aMessage, const WindowPostMessageOptions& aOptions, nsIPrincipal& aSubjectPrincipal, ErrorResult& aError); void GetCustomUserAgent(nsAString& aUserAgent) { aUserAgent = Top()->GetUserAgentOverride(); } nsresult SetCustomUserAgent(const nsAString& aUserAgent); void SetCustomUserAgent(const nsAString& aUserAgent, ErrorResult& aRv); void GetCustomPlatform(nsAString& aPlatform) { aPlatform = Top()->GetPlatformOverride(); } void SetCustomPlatform(const nsAString& aPlatform, ErrorResult& aRv); JSObject* WrapObject(JSContext* aCx); static JSObject* ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader* aReader, StructuredCloneHolder* aHolder); bool WriteStructuredClone(JSContext* aCx, JSStructuredCloneWriter* aWriter, StructuredCloneHolder* aHolder); void StartDelayedAutoplayMediaComponents(); [[nodiscard]] nsresult ResetGVAutoplayRequestStatus(); /** * Information required to initialize a BrowsingContext in another process. * This object may be serialized over IPC. */ struct IPCInitializer { uint64_t mId = 0; // IDs are used for Parent and Opener to allow for this object to be // deserialized before other BrowsingContext in the BrowsingContextGroup // have been initialized. uint64_t mParentId = 0; already_AddRefed GetParent(); already_AddRefed GetOpener(); uint64_t GetOpenerId() const { return mFields.mOpenerId; } bool mWindowless = false; bool mUseRemoteTabs = false; bool mUseRemoteSubframes = false; bool mCreatedDynamically = false; int32_t mSessionHistoryIndex = -1; int32_t mSessionHistoryCount = 0; OriginAttributes mOriginAttributes; uint64_t mRequestContextId = 0; FieldValues mFields; }; // Create an IPCInitializer object for this BrowsingContext. IPCInitializer GetIPCInitializer(); // Create a BrowsingContext object from over IPC. static void CreateFromIPC(IPCInitializer&& aInitializer, BrowsingContextGroup* aGroup, ContentParent* aOriginProcess); // Performs access control to check that 'this' can access 'aTarget'. bool CanAccess(BrowsingContext* aTarget, bool aConsiderOpener = true); bool IsSandboxedFrom(BrowsingContext* aTarget); // The runnable will be called once there is idle time, or the top level // page has been loaded or if a timeout has fired. // Must be called only on the top level BrowsingContext. void AddDeprioritizedLoadRunner(nsIRunnable* aRunner); RefPtr GetSessionStorageManager(); // Set PendingInitialization on this BrowsingContext before the context has // been attached. void InitPendingInitialization(bool aPendingInitialization) { MOZ_ASSERT(!EverAttached()); mFields.SetWithoutSyncing( aPendingInitialization); } bool CreatedDynamically() const { return mCreatedDynamically; } const OriginAttributes& OriginAttributesRef() { return mOriginAttributes; } nsresult SetOriginAttributes(const OriginAttributes& aAttrs); void GetHistoryID(JSContext* aCx, JS::MutableHandle aVal, ErrorResult& aError); // This should only be called on the top browsing context. void InitSessionHistory(); // This will only ever return a non-null value if called on the top browsing // context. ChildSHistory* GetChildSessionHistory(); bool CrossOriginIsolated(); void SessionHistoryChanged(int32_t aIndexDelta, int32_t aLengthDelta); // Check if it is allowed to open a popup from the current browsing // context or any of its ancestors. bool IsPopupAllowed(); void SessionHistoryCommit(const LoadingSessionHistoryInfo& aInfo, uint32_t aLoadType, bool aHadActiveEntry, bool aPersist, bool aCloneEntryChildren); // Set a new active entry on this browsing context. This is used for // implementing history.pushState/replaceState and same document navigations. // The new active entry will be linked to the current active entry through // its shared state. // aPreviousScrollPos is the scroll position that needs to be saved on the // previous active entry. // aUpdatedCacheKey is the cache key to set on the new active entry. If // aUpdatedCacheKey is 0 then it will be ignored. void SetActiveSessionHistoryEntry(const Maybe& aPreviousScrollPos, SessionHistoryInfo* aInfo, uint32_t aLoadType, uint32_t aUpdatedCacheKey); // Replace the active entry for this browsing context. This is used for // implementing history.replaceState and same document navigations. void ReplaceActiveSessionHistoryEntry(SessionHistoryInfo* aInfo); // Removes dynamic child entries of the active entry. void RemoveDynEntriesFromActiveSessionHistoryEntry(); // Removes entries corresponding to this BrowsingContext from session history. void RemoveFromSessionHistory(); void SetTriggeringAndInheritPrincipals(nsIPrincipal* aTriggeringPrincipal, nsIPrincipal* aPrincipalToInherit, uint64_t aLoadIdentifier); // Return mTriggeringPrincipal and mPrincipalToInherit if the load id // saved with the principal matches the current load identifier of this BC. Tuple, nsCOMPtr> GetTriggeringAndInheritPrincipalsForCurrentLoad(); void HistoryGo(int32_t aOffset, uint64_t aHistoryEpoch, bool aRequireUserInteraction, std::function&& aResolver); bool ShouldUpdateSessionHistory(uint32_t aLoadType); // Checks if we reached the rate limit for calls to Location and History API. // The rate limit is controlled by the // "dom.navigation.locationChangeRateLimit" prefs. // Rate limit applies per BrowsingContext. // Returns NS_OK if we are below the rate limit and increments the counter. // Returns NS_ERROR_DOM_SECURITY_ERR if limit is reached. nsresult CheckLocationChangeRateLimit(CallerType aCallerType); void ResetLocationChangeRateLimit(); mozilla::dom::DisplayMode DisplayMode() { return Top()->GetDisplayMode(); } // Returns canFocus, isActive std::tuple CanFocusCheck(CallerType aCallerType); PopupBlocker::PopupControlState RevisePopupAbuseLevel( PopupBlocker::PopupControlState aControl); protected: virtual ~BrowsingContext(); BrowsingContext(WindowContext* aParentWindow, BrowsingContextGroup* aGroup, uint64_t aBrowsingContextId, Type aType, FieldValues&& aInit); void SetChildSHistory(ChildSHistory* aChildSHistory); already_AddRefed ForgetChildSHistory() { // FIXME Do we need to unset mHasSessionHistory? return mChildSessionHistory.forget(); } private: void Attach(bool aFromIPC, ContentParent* aOriginProcess); // Find the special browsing context if aName is '_self', '_parent', // '_top', but not '_blank'. The latter is handled in FindWithName BrowsingContext* FindWithSpecialName(const nsAString& aName, BrowsingContext& aRequestingContext); // Is it early enough in the BrowsingContext's lifecycle that it is still // OK to set OriginAttributes? bool CanSetOriginAttributes(); void AssertOriginAttributesMatchPrivateBrowsing(); // Assert that the BrowsingContext's LoadContext flags appear coherent // relative to related BrowsingContexts. void AssertCoherentLoadContext(); friend class ::nsOuterWindowProxy; friend class ::nsGlobalWindowOuter; friend class WindowContext; // Update the window proxy object that corresponds to this browsing context. // This should be called from the window proxy object's objectMoved hook, if // the object mWindowProxy points to was moved by the JS GC. void UpdateWindowProxy(JSObject* obj, JSObject* old) { if (mWindowProxy) { MOZ_ASSERT(mWindowProxy == old); mWindowProxy = obj; } } // Clear the window proxy object that corresponds to this browsing context. // This should be called if the window proxy object is finalized, or it can't // reach its browsing context anymore. void ClearWindowProxy() { mWindowProxy = nullptr; } friend class Location; friend class RemoteLocationProxy; /** * LocationProxy is the class for the native object stored as a private in a * RemoteLocationProxy proxy representing a Location object in a different * process. It forwards all operations to its BrowsingContext and aggregates * its refcount to that BrowsingContext. */ class LocationProxy final : public LocationBase { public: MozExternalRefCountType AddRef() { return GetBrowsingContext()->AddRef(); } MozExternalRefCountType Release() { return GetBrowsingContext()->Release(); } protected: friend class RemoteLocationProxy; BrowsingContext* GetBrowsingContext() override { return reinterpret_cast( uintptr_t(this) - offsetof(BrowsingContext, mLocation)); } already_AddRefed GetDocShell() override { return nullptr; } }; // Send a given `BaseTransaction` object to the correct remote. void SendCommitTransaction(ContentParent* aParent, const BaseTransaction& aTxn, uint64_t aEpoch); void SendCommitTransaction(ContentChild* aChild, const BaseTransaction& aTxn, uint64_t aEpoch); // Ensure that opener is in the same BrowsingContextGroup. bool CanSet(FieldIndex, const uint64_t& aValue, ContentParent* aSource) { if (aValue != 0) { RefPtr opener = Get(aValue); return opener && opener->Group() == Group(); } return true; } bool CanSet(FieldIndex, bool, ContentParent*) { return IsTop(); } bool CanSet(FieldIndex, const enum TouchEventsOverride& aTouchEventsOverride, ContentParent* aSource); bool CanSet(FieldIndex, const enum DisplayMode& aDisplayMode, ContentParent* aSource); void DidSet(FieldIndex, enum DisplayMode aOldValue); void DidSet(FieldIndex, ExplicitActiveStatus aOldValue); bool CanSet(FieldIndex, const bool& aValue, ContentParent* aSource); void DidSet(FieldIndex, bool aOldValue); // Ensure that we only set the flag on the top level browsingContext. // And then, we do a pre-order walk in the tree to refresh the // volume of all media elements. void DidSet(FieldIndex); bool CanSet(FieldIndex, const uint64_t& aValue, ContentParent* aSource); bool CanSet(FieldIndex, const uint64_t& aValue, ContentParent* aSource); void DidSet(FieldIndex); bool CanSet(FieldIndex, const bool& aValue, ContentParent* aSource); void DidSet(FieldIndex); void DidSet(FieldIndex); void DidSet(FieldIndex); void DidSet(FieldIndex); void DidSet(FieldIndex); void DidSet(FieldIndex); bool CanSet(FieldIndex, const nsString& aPlatformOverride, ContentParent* aSource); void DidSet(FieldIndex); bool CanSet(FieldIndex, const nsString& aUserAgent, ContentParent* aSource); bool CanSet(FieldIndex, const mozilla::hal::ScreenOrientation& aOrientationLock, ContentParent* aSource); bool CanSet(FieldIndex, const Maybe& aInitiatorType, ContentParent* aSource); bool CanSet(FieldIndex, const nsString& aMessageManagerGroup, ContentParent* aSource); bool CanSet(FieldIndex, const bool& aAllowContentRetargeting, ContentParent* aSource); bool CanSet(FieldIndex, const bool& aAllowContentRetargetingOnChildren, ContentParent* aSource); bool CanSet(FieldIndex, const bool& aAllowPlugins, ContentParent* aSource); bool CanSet(FieldIndex, const bool&, ContentParent*); bool CanSet(FieldIndex, const bool& aWatchedByDevToolsInternal, ContentParent* aSource); bool CanSet(FieldIndex, const uint32_t& aDefaultLoadFlags, ContentParent* aSource); void DidSet(FieldIndex); bool CanSet(FieldIndex, const bool& aUseGlobalHistory, ContentParent* aSource); void DidSet(FieldIndex, bool aOldValue); bool CanSet(FieldIndex, const uint32_t& aValue, ContentParent* aSource); bool CanSet(FieldIndex, const bool& aUseErrorPages, ContentParent* aSource); bool CanSet(FieldIndex, bool aNewValue, ContentParent* aSource); bool CanSet(FieldIndex, bool aNewValue, ContentParent* aSource); void DidSet(FieldIndex, bool aOldValue); template bool CanSet(FieldIndex, const T&, ContentParent*) { return true; } // Overload `DidSet` to get notifications for a particular field being set. // // You can also overload the variant that gets the old value if you need it. template void DidSet(FieldIndex) {} template void DidSet(FieldIndex, T&& aOldValue) {} void DidSet(FieldIndex, float aOldValue); void DidSet(FieldIndex, float aOldValue); void DidSet(FieldIndex); // True if the process attemping to set field is the same as the owning // process. bool CheckOnlyOwningProcessCanSet(ContentParent* aSource); // True if the process attempting to set field is the same as the embedder's // process. bool CheckOnlyEmbedderCanSet(ContentParent* aSource); void CreateChildSHistory(); using PrincipalWithLoadIdentifierTuple = Tuple, uint64_t>; nsIPrincipal* GetSavedPrincipal( Maybe aPrincipalTuple); // Type of BrowsingContent const Type mType; // Unique id identifying BrowsingContext const uint64_t mBrowsingContextId; RefPtr mGroup; RefPtr mParentWindow; nsCOMPtr mDocShell; RefPtr mEmbedderElement; nsTArray> mWindowContexts; RefPtr mCurrentWindowContext; // This is not a strong reference, but using a JS::Heap for that should be // fine. The JSObject stored in here should be a proxy with a // nsOuterWindowProxy handler, which will update the pointer from its // objectMoved hook and clear it from its finalize hook. JS::Heap mWindowProxy; LocationProxy mLocation; // OriginAttributes for this BrowsingContext. May not be changed after this // BrowsingContext is attached. OriginAttributes mOriginAttributes; // The network request context id, representing the nsIRequestContext // associated with this BrowsingContext, and LoadGroups created for it. uint64_t mRequestContextId = 0; // Determines if private browsing should be used. May not be changed after // this BrowsingContext is attached. This field matches mOriginAttributes in // content Browsing Contexts. Currently treated as a binary value: 1 - in // private mode, 0 - not private mode. uint32_t mPrivateBrowsingId; // True if Attach() has been called on this BrowsingContext already. bool mEverAttached : 1; // Is the most recent Document in this BrowsingContext loaded within this // process? This may be true with a null mDocShell after the Window has been // closed. bool mIsInProcess : 1; // Has this browsing context been discarded? BrowsingContexts should // only be discarded once. bool mIsDiscarded : 1; // True if this BrowsingContext has no associated visible window, and is owned // by whichever process created it, even if top-level. bool mWindowless : 1; // This is true if the BrowsingContext was out of process, but is now in // process, and might have remote window proxies that need to be cleaned up. bool mDanglingRemoteOuterProxies : 1; // True if this BrowsingContext has been embedded in a element in this // process. bool mEmbeddedByThisProcess : 1; // Determines if remote (out-of-process) tabs should be used. May not be // changed after this BrowsingContext is attached. bool mUseRemoteTabs : 1; // Determines if out-of-process iframes should be used. May not be changed // after this BrowsingContext is attached. bool mUseRemoteSubframes : 1; // True if this BrowsingContext is for a frame that was added dynamically. bool mCreatedDynamically : 1; // The start time of user gesture, this is only available if the browsing // context is in process. TimeStamp mUserGestureStart; // Triggering principal and principal to inherit need to point to original // principal instances if the document is loaded in the same process as the // process that initiated the load. When the load starts we save the // principals along with the current load id. // These principals correspond to the most recent load that took place within // the process of this browsing context. Maybe mTriggeringPrincipal; Maybe mPrincipalToInherit; class DeprioritizedLoadRunner : public mozilla::Runnable, public mozilla::LinkedListElement { public: explicit DeprioritizedLoadRunner(nsIRunnable* aInner) : Runnable("DeprioritizedLoadRunner"), mInner(aInner) {} NS_IMETHOD Run() override { if (mInner) { RefPtr inner = std::move(mInner); inner->Run(); } return NS_OK; } private: RefPtr mInner; }; mozilla::LinkedList mDeprioritizedLoadRunner; RefPtr mSessionStorageManager; RefPtr mChildSessionHistory; // Counter and time span for rate limiting Location and History API calls. // Used by CheckLocationChangeRateLimit. Do not apply cross-process. uint32_t mLocationChangeRateLimitCount; mozilla::TimeStamp mLocationChangeRateLimitSpanStart; }; /** * Gets a WindowProxy object for a BrowsingContext that lives in a different * process (creating the object if it doesn't already exist). The WindowProxy * object will be in the compartment that aCx is currently in. This should only * be called if aContext doesn't hold a docshell, otherwise the BrowsingContext * lives in this process, and a same-process WindowProxy should be used (see * nsGlobalWindowOuter). This should only be called by bindings code, ToJSValue * is the right API to get a WindowProxy for a BrowsingContext. * * If aTransplantTo is non-null, then the WindowProxy object will eventually be * transplanted onto it. Therefore it should be used as the value in the remote * proxy map. */ extern bool GetRemoteOuterWindowProxy(JSContext* aCx, BrowsingContext* aContext, JS::Handle aTransplantTo, JS::MutableHandle aRetVal); using BrowsingContextTransaction = BrowsingContext::BaseTransaction; using BrowsingContextInitializer = BrowsingContext::IPCInitializer; using MaybeDiscardedBrowsingContext = MaybeDiscarded; // Specialize the transaction object for every translation unit it's used in. extern template class syncedcontext::Transaction; } // namespace dom // Allow sending BrowsingContext objects over IPC. namespace ipc { template <> struct IPDLParamTraits> { static void Write(IPC::Message* aMsg, IProtocol* aActor, const dom::MaybeDiscarded& aParam); static bool Read(const IPC::Message* aMsg, PickleIterator* aIter, IProtocol* aActor, dom::MaybeDiscarded* aResult); }; template <> struct IPDLParamTraits { static void Write(IPC::Message* aMessage, IProtocol* aActor, const dom::BrowsingContext::IPCInitializer& aInitializer); static bool Read(const IPC::Message* aMessage, PickleIterator* aIterator, IProtocol* aActor, dom::BrowsingContext::IPCInitializer* aInitializer); }; } // namespace ipc } // namespace mozilla #endif // !defined(mozilla_dom_BrowsingContext_h)