diff options
Diffstat (limited to 'docshell/base/WindowContext.h')
-rw-r--r-- | docshell/base/WindowContext.h | 392 |
1 files changed, 392 insertions, 0 deletions
diff --git a/docshell/base/WindowContext.h b/docshell/base/WindowContext.h new file mode 100644 index 0000000000..359737ce69 --- /dev/null +++ b/docshell/base/WindowContext.h @@ -0,0 +1,392 @@ +/* -*- 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_WindowContext_h +#define mozilla_dom_WindowContext_h + +#include "mozilla/PermissionDelegateHandler.h" +#include "mozilla/WeakPtr.h" +#include "mozilla/Span.h" +#include "mozilla/dom/MaybeDiscarded.h" +#include "mozilla/dom/SyncedContext.h" +#include "mozilla/dom/UserActivation.h" +#include "nsDOMNavigationTiming.h" +#include "nsILoadInfo.h" +#include "nsWrapperCache.h" + +class nsIGlobalObject; + +class nsGlobalWindowInner; + +namespace mozilla { +class LogModule; + +namespace dom { + +class WindowGlobalChild; +class WindowGlobalParent; +class WindowGlobalInit; +class BrowsingContext; +class BrowsingContextGroup; + +#define MOZ_EACH_WC_FIELD(FIELD) \ + /* Whether the SHEntry associated with the current top-level \ + * window has already seen user interaction. \ + * As such, this will be reset to false when a new SHEntry is \ + * created without changing the WC (e.g. when using pushState or \ + * sub-frame navigation) \ + * This flag is set for optimization purposes, to avoid \ + * having to get the top SHEntry and update it on every \ + * user interaction. \ + * This is only meaningful on the top-level WC. */ \ + FIELD(SHEntryHasUserInteraction, bool) \ + FIELD(CookieBehavior, Maybe<uint32_t>) \ + FIELD(IsOnContentBlockingAllowList, bool) \ + /* Whether the given window hierarchy is third party. See \ + * ThirdPartyUtil::IsThirdPartyWindow for details */ \ + FIELD(IsThirdPartyWindow, bool) \ + /* Whether this window's channel has been marked as a third-party \ + * tracking resource */ \ + FIELD(IsThirdPartyTrackingResourceWindow, bool) \ + FIELD(IsSecureContext, bool) \ + FIELD(IsOriginalFrameSource, bool) \ + /* Mixed-Content: If the corresponding documentURI is https, \ + * then this flag is true. */ \ + FIELD(IsSecure, bool) \ + /* Whether the user has overriden the mixed content blocker to allow \ + * mixed content loads to happen */ \ + FIELD(AllowMixedContent, bool) \ + /* Whether this window has registered a "beforeunload" event \ + * handler */ \ + FIELD(HasBeforeUnload, bool) \ + /* Controls whether the WindowContext is currently considered to be \ + * activated by a gesture */ \ + FIELD(UserActivationState, UserActivation::State) \ + FIELD(EmbedderPolicy, nsILoadInfo::CrossOriginEmbedderPolicy) \ + /* True if this document tree contained at least a HTMLMediaElement. \ + * This should only be set on top level context. */ \ + FIELD(DocTreeHadMedia, bool) \ + FIELD(AutoplayPermission, uint32_t) \ + FIELD(ShortcutsPermission, uint32_t) \ + /* Store the Id of the browsing context where active media session \ + * exists on the top level window context */ \ + FIELD(ActiveMediaSessionContextId, Maybe<uint64_t>) \ + /* ALLOW_ACTION if it is allowed to open popups for the sub-tree \ + * starting and including the current WindowContext */ \ + FIELD(PopupPermission, uint32_t) \ + FIELD(DelegatedPermissions, \ + PermissionDelegateHandler::DelegatedPermissionList) \ + FIELD(DelegatedExactHostMatchPermissions, \ + PermissionDelegateHandler::DelegatedPermissionList) \ + FIELD(HasReportedShadowDOMUsage, bool) \ + /* Whether the principal of this window is for a local \ + * IP address */ \ + FIELD(IsLocalIP, bool) \ + /* Whether any of the windows in the subtree rooted at this window has \ + * active peer connections or not (only set on the top window). */ \ + FIELD(HasActivePeerConnections, bool) \ + /* Whether we can execute scripts in this WindowContext. Has no effect \ + * unless scripts are also allowed in the BrowsingContext. */ \ + FIELD(AllowJavascript, bool) \ + /* If this field is `true`, it means that this WindowContext's \ + * WindowState was saved to be stored in the legacy (non-SHIP) BFCache \ + * implementation. Always false for SHIP */ \ + FIELD(WindowStateSaved, bool) + +class WindowContext : public nsISupports, public nsWrapperCache { + MOZ_DECL_SYNCED_CONTEXT(WindowContext, MOZ_EACH_WC_FIELD) + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(WindowContext) + + public: + static already_AddRefed<WindowContext> GetById(uint64_t aInnerWindowId); + static LogModule* GetLog(); + static LogModule* GetSyncLog(); + + BrowsingContext* GetBrowsingContext() const { return mBrowsingContext; } + BrowsingContextGroup* Group() const; + uint64_t Id() const { return InnerWindowId(); } + uint64_t InnerWindowId() const { return mInnerWindowId; } + uint64_t OuterWindowId() const { return mOuterWindowId; } + bool IsDiscarded() const { return mIsDiscarded; } + + // Returns `true` if this WindowContext is the current WindowContext in its + // BrowsingContext. + bool IsCurrent() const; + + // Returns `true` if this WindowContext is currently in the BFCache. + bool IsInBFCache(); + + bool IsInProcess() const { return mIsInProcess; } + + bool HasBeforeUnload() const { return GetHasBeforeUnload(); } + + bool IsLocalIP() const { return GetIsLocalIP(); } + + nsGlobalWindowInner* GetInnerWindow() const; + Document* GetDocument() const; + Document* GetExtantDoc() const; + + WindowGlobalChild* GetWindowGlobalChild() const; + + // Get the parent WindowContext of this WindowContext, taking the BFCache into + // account. This will not cross chrome/content <browser> boundaries. + WindowContext* GetParentWindowContext(); + WindowContext* TopWindowContext(); + + bool SameOriginWithTop() const; + + bool IsTop() const; + + Span<RefPtr<BrowsingContext>> Children() { return mChildren; } + + // The filtered version of `Children()`, which contains no browsing contexts + // for synthetic documents as created by object loading content. + Span<RefPtr<BrowsingContext>> NonSyntheticChildren() { + return mNonSyntheticChildren; + } + + // Cast this object to it's parent-process canonical form. + WindowGlobalParent* Canonical(); + + nsIGlobalObject* GetParentObject() const; + JSObject* WrapObject(JSContext* cx, + JS::Handle<JSObject*> aGivenProto) override; + + void Discard(); + + struct IPCInitializer { + uint64_t mInnerWindowId; + uint64_t mOuterWindowId; + uint64_t mBrowsingContextId; + + FieldValues mFields; + }; + IPCInitializer GetIPCInitializer(); + + static void CreateFromIPC(IPCInitializer&& aInit); + + // Add new security state flags. + // These should be some of the nsIWebProgressListener 'HTTPS_ONLY_MODE' or + // 'MIXED' state flags, and should only be called on the top window context. + void AddSecurityState(uint32_t aStateFlags); + + // This function would be called when its corresponding window is activated + // by user gesture. + void NotifyUserGestureActivation(); + + // This function would be called when we want to reset the user gesture + // activation flag. + void NotifyResetUserGestureActivation(); + + // Return true if its corresponding window has been activated by user + // gesture. + bool HasBeenUserGestureActivated(); + + // Return true if its corresponding window has transient user gesture + // activation and the transient user gesture activation haven't yet timed + // out. + bool HasValidTransientUserGestureActivation(); + + // See `mUserGestureStart`. + const TimeStamp& GetUserGestureStart() const; + + // Return true if the corresponding window has valid transient user gesture + // activation and the transient user gesture activation had been consumed + // successfully. + bool ConsumeTransientUserGestureActivation(); + + bool CanShowPopup(); + + bool AllowJavascript() const { return GetAllowJavascript(); } + bool CanExecuteScripts() const { return mCanExecuteScripts; } + + void TransientSetHasActivePeerConnections(); + + protected: + WindowContext(BrowsingContext* aBrowsingContext, uint64_t aInnerWindowId, + uint64_t aOuterWindowId, FieldValues&& aFields); + virtual ~WindowContext(); + + virtual void Init(); + + private: + friend class BrowsingContext; + friend class WindowGlobalChild; + friend class WindowGlobalActor; + + void AppendChildBrowsingContext(BrowsingContext* aBrowsingContext); + void RemoveChildBrowsingContext(BrowsingContext* aBrowsingContext); + + // Update non-synthetic children based on whether `aBrowsingContext` + // is synthetic or not. Regardless the synthetic of `aBrowsingContext`, it is + // kept in this WindowContext's all children list. + void UpdateChildSynthetic(BrowsingContext* aBrowsingContext, + bool aIsSynthetic); + + // 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); + + bool CheckOnlyOwningProcessCanSet(ContentParent* aSource); + + // Overload `CanSet` to get notifications for a particular field being set. + bool CanSet(FieldIndex<IDX_IsSecure>, const bool& aIsSecure, + ContentParent* aSource); + bool CanSet(FieldIndex<IDX_AllowMixedContent>, const bool& aAllowMixedContent, + ContentParent* aSource); + + bool CanSet(FieldIndex<IDX_HasBeforeUnload>, const bool& aHasBeforeUnload, + ContentParent* aSource); + + bool CanSet(FieldIndex<IDX_CookieBehavior>, const Maybe<uint32_t>& aValue, + ContentParent* aSource); + + bool CanSet(FieldIndex<IDX_IsOnContentBlockingAllowList>, const bool& aValue, + ContentParent* aSource); + + bool CanSet(FieldIndex<IDX_EmbedderPolicy>, const bool& aValue, + ContentParent* aSource) { + return true; + } + + bool CanSet(FieldIndex<IDX_IsThirdPartyWindow>, + const bool& IsThirdPartyWindow, ContentParent* aSource); + bool CanSet(FieldIndex<IDX_IsThirdPartyTrackingResourceWindow>, + const bool& aIsThirdPartyTrackingResourceWindow, + ContentParent* aSource); + bool CanSet(FieldIndex<IDX_IsSecureContext>, const bool& aIsSecureContext, + ContentParent* aSource); + bool CanSet(FieldIndex<IDX_IsOriginalFrameSource>, + const bool& aIsOriginalFrameSource, ContentParent* aSource); + bool CanSet(FieldIndex<IDX_DocTreeHadMedia>, const bool& aValue, + ContentParent* aSource); + bool CanSet(FieldIndex<IDX_AutoplayPermission>, const uint32_t& aValue, + ContentParent* aSource); + bool CanSet(FieldIndex<IDX_ShortcutsPermission>, const uint32_t& aValue, + ContentParent* aSource); + bool CanSet(FieldIndex<IDX_ActiveMediaSessionContextId>, + const Maybe<uint64_t>& aValue, ContentParent* aSource); + bool CanSet(FieldIndex<IDX_PopupPermission>, const uint32_t&, + ContentParent* aSource); + bool CanSet(FieldIndex<IDX_SHEntryHasUserInteraction>, + const bool& aSHEntryHasUserInteraction, ContentParent* aSource) { + return true; + } + bool CanSet(FieldIndex<IDX_DelegatedPermissions>, + const PermissionDelegateHandler::DelegatedPermissionList& aValue, + ContentParent* aSource); + bool CanSet(FieldIndex<IDX_DelegatedExactHostMatchPermissions>, + const PermissionDelegateHandler::DelegatedPermissionList& aValue, + ContentParent* aSource); + bool CanSet(FieldIndex<IDX_UserActivationState>, + const UserActivation::State& aUserActivationState, + ContentParent* aSource) { + return true; + } + + bool CanSet(FieldIndex<IDX_HasReportedShadowDOMUsage>, const bool& aValue, + ContentParent* aSource) { + return true; + } + + bool CanSet(FieldIndex<IDX_IsLocalIP>, const bool& aValue, + ContentParent* aSource); + + bool CanSet(FieldIndex<IDX_AllowJavascript>, bool aValue, + ContentParent* aSource); + void DidSet(FieldIndex<IDX_AllowJavascript>, bool aOldValue); + + bool CanSet(FieldIndex<IDX_HasActivePeerConnections>, bool, ContentParent*); + + void DidSet(FieldIndex<IDX_HasReportedShadowDOMUsage>, bool aOldValue); + + void DidSet(FieldIndex<IDX_SHEntryHasUserInteraction>, bool aOldValue); + + bool CanSet(FieldIndex<IDX_WindowStateSaved>, bool aValue, + ContentParent* aSource); + + // 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 <size_t I> + void DidSet(FieldIndex<I>) {} + template <size_t I, typename T> + void DidSet(FieldIndex<I>, T&& aOldValue) {} + void DidSet(FieldIndex<IDX_UserActivationState>); + + // Recomputes whether we can execute scripts in this WindowContext based on + // the value of AllowJavascript() and whether scripts are allowed in the + // BrowsingContext. + void RecomputeCanExecuteScripts(bool aApplyChanges = true); + + const uint64_t mInnerWindowId; + const uint64_t mOuterWindowId; + RefPtr<BrowsingContext> mBrowsingContext; + WeakPtr<WindowGlobalChild> mWindowGlobalChild; + + // --- NEVER CHANGE `mChildren` DIRECTLY! --- + // Changes to this list need to be synchronized to the list within our + // `mBrowsingContext`, and should only be performed through the + // `AppendChildBrowsingContext` and `RemoveChildBrowsingContext` methods. + nsTArray<RefPtr<BrowsingContext>> mChildren; + + // --- NEVER CHANGE `mNonSyntheticChildren` DIRECTLY! --- + // Same reason as for mChildren. + // mNonSyntheticChildren contains the same browsing contexts except browsing + // contexts created by the synthetic document for object loading contents + // loading images. This is used to discern browsing contexts created when + // loading images in <object> or <embed> elements, so that they can be hidden + // from named targeting, `Window.frames` etc. + nsTArray<RefPtr<BrowsingContext>> mNonSyntheticChildren; + + bool mIsDiscarded = false; + bool mIsInProcess = false; + + // Determines if we can execute scripts in this WindowContext. True if + // AllowJavascript() is true and script execution is allowed in the + // BrowsingContext. + bool mCanExecuteScripts = true; + + // The start time of user gesture, this is only available if the window + // context is in process. + TimeStamp mUserGestureStart; +}; + +using WindowContextTransaction = WindowContext::BaseTransaction; +using WindowContextInitializer = WindowContext::IPCInitializer; +using MaybeDiscardedWindowContext = MaybeDiscarded<WindowContext>; + +// Don't specialize the `Transaction` object for every translation unit it's +// used in. This should help keep code size down. +extern template class syncedcontext::Transaction<WindowContext>; + +} // namespace dom + +namespace ipc { +template <> +struct IPDLParamTraits<dom::MaybeDiscarded<dom::WindowContext>> { + static void Write(IPC::MessageWriter* aWriter, IProtocol* aActor, + const dom::MaybeDiscarded<dom::WindowContext>& aParam); + static bool Read(IPC::MessageReader* aReader, IProtocol* aActor, + dom::MaybeDiscarded<dom::WindowContext>* aResult); +}; + +template <> +struct IPDLParamTraits<dom::WindowContext::IPCInitializer> { + static void Write(IPC::MessageWriter* aWriter, IProtocol* aActor, + const dom::WindowContext::IPCInitializer& aInitializer); + + static bool Read(IPC::MessageReader* aReader, IProtocol* aActor, + dom::WindowContext::IPCInitializer* aInitializer); +}; +} // namespace ipc +} // namespace mozilla + +#endif // !defined(mozilla_dom_WindowContext_h) |