summaryrefslogtreecommitdiffstats
path: root/dom/base/nsFrameLoader.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/base/nsFrameLoader.h')
-rw-r--r--dom/base/nsFrameLoader.h579
1 files changed, 579 insertions, 0 deletions
diff --git a/dom/base/nsFrameLoader.h b/dom/base/nsFrameLoader.h
new file mode 100644
index 0000000000..159e3865a6
--- /dev/null
+++ b/dom/base/nsFrameLoader.h
@@ -0,0 +1,579 @@
+/* -*- 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/. */
+
+/*
+ * Class for managing loading of a subframe (creation of the docshell,
+ * handling of loads in it, recursion-checking).
+ */
+
+#ifndef nsFrameLoader_h_
+#define nsFrameLoader_h_
+
+#include <cstdint>
+#include "ErrorList.h"
+#include "Units.h"
+#include "js/RootingAPI.h"
+#include "mozilla/AlreadyAddRefed.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/LinkedList.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/dom/BrowsingContext.h"
+#include "mozilla/dom/Nullable.h"
+#include "mozilla/dom/Promise.h"
+#include "mozilla/dom/ReferrerPolicyBinding.h"
+#include "mozilla/dom/WindowProxyHolder.h"
+#include "mozilla/dom/ipc/IdType.h"
+#include "mozilla/layers/LayersTypes.h"
+#include "nsCOMPtr.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsDocShell.h"
+#include "mozilla/dom/MessageManagerCallback.h"
+#include "nsID.h"
+#include "nsIFrame.h"
+#include "nsIMutationObserver.h"
+#include "nsISupports.h"
+#include "nsRect.h"
+#include "nsStringFwd.h"
+#include "nsStubMutationObserver.h"
+#include "nsWrapperCache.h"
+
+class nsIURI;
+class nsSubDocumentFrame;
+class AutoResetInShow;
+class AutoResetInFrameSwap;
+class nsFrameLoaderOwner;
+class nsIRemoteTab;
+class nsIDocShellTreeItem;
+class nsIDocShellTreeOwner;
+class nsILoadContext;
+class nsIPrintSettings;
+class nsIWebBrowserPersistDocumentReceiver;
+class nsIWebProgressListener;
+class nsIOpenWindowInfo;
+
+namespace mozilla {
+
+class OriginAttributes;
+
+namespace dom {
+class ChromeMessageSender;
+class ContentParent;
+class Document;
+class Element;
+class InProcessBrowserChildMessageManager;
+class MessageSender;
+class ProcessMessageManager;
+class BrowserParent;
+class MutableTabContext;
+class BrowserBridgeChild;
+class RemoteBrowser;
+struct RemotenessOptions;
+struct NavigationIsolationOptions;
+class SessionStoreChild;
+class SessionStoreParent;
+
+struct LazyLoadFrameResumptionState {
+ RefPtr<nsIURI> mBaseURI;
+ ReferrerPolicy mReferrerPolicy = ReferrerPolicy::_empty;
+
+ void Clear() {
+ mBaseURI = nullptr;
+ mReferrerPolicy = ReferrerPolicy::_empty;
+ }
+};
+
+namespace ipc {
+class StructuredCloneData;
+} // namespace ipc
+
+} // namespace dom
+
+namespace ipc {
+class MessageChannel;
+} // namespace ipc
+} // namespace mozilla
+
+#if defined(MOZ_WIDGET_GTK)
+typedef struct _GtkWidget GtkWidget;
+#endif
+
+// IID for nsFrameLoader, because some places want to QI to it.
+#define NS_FRAMELOADER_IID \
+ { \
+ 0x297fd0ea, 0x1b4a, 0x4c9a, { \
+ 0xa4, 0x04, 0xe5, 0x8b, 0xe8, 0x95, 0x10, 0x50 \
+ } \
+ }
+
+class nsFrameLoader final : public nsStubMutationObserver,
+ public mozilla::dom::ipc::MessageManagerCallback,
+ public nsWrapperCache,
+ public mozilla::LinkedListElement<nsFrameLoader> {
+ friend class AutoResetInShow;
+ friend class AutoResetInFrameSwap;
+ friend class nsFrameLoaderOwner;
+ using Document = mozilla::dom::Document;
+ using Element = mozilla::dom::Element;
+ using BrowserParent = mozilla::dom::BrowserParent;
+ using BrowserBridgeChild = mozilla::dom::BrowserBridgeChild;
+ using BrowsingContext = mozilla::dom::BrowsingContext;
+ using BrowsingContextGroup = mozilla::dom::BrowsingContextGroup;
+ using Promise = mozilla::dom::Promise;
+
+ public:
+ // Called by Frame Elements to create a new FrameLoader.
+ static already_AddRefed<nsFrameLoader> Create(
+ Element* aOwner, bool aNetworkCreated,
+ nsIOpenWindowInfo* aOpenWindowInfo = nullptr);
+
+ // Called by nsFrameLoaderOwner::ChangeRemoteness when switching out
+ // FrameLoaders.
+ static already_AddRefed<nsFrameLoader> Recreate(
+ Element* aOwner, BrowsingContext* aContext, BrowsingContextGroup* aGroup,
+ const mozilla::dom::NavigationIsolationOptions& aRemotenessOptions,
+ bool aIsRemote, bool aNetworkCreated, bool aPreserveContext);
+
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_FRAMELOADER_IID)
+
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(nsFrameLoader)
+
+ NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
+ nsresult CheckForRecursiveLoad(nsIURI* aURI);
+ nsresult ReallyStartLoading();
+ void StartDestroy(bool aForProcessSwitch);
+ void DestroyDocShell();
+ void DestroyComplete();
+ nsDocShell* GetExistingDocShell() const { return mDocShell; }
+ mozilla::dom::InProcessBrowserChildMessageManager*
+ GetBrowserChildMessageManager() const {
+ return mChildMessageManager;
+ }
+ nsresult UpdatePositionAndSize(nsSubDocumentFrame* aIFrame);
+ void PropagateIsUnderHiddenEmbedderElement(
+ bool aIsUnderHiddenEmbedderElement);
+
+ void UpdateRemoteStyle(mozilla::StyleImageRendering aImageRendering);
+
+ // When creating a nsFrameLoaderOwner which is a static clone, a
+ // `nsFrameLoader` is not immediately attached to it. Instead, it is added to
+ // the static clone document's `PendingFrameStaticClones` list.
+ //
+ // After the parent document has been fully cloned, a new frameloader will be
+ // created for the cloned iframe, and `FinishStaticClone` will be called on
+ // it, which will clone the inner document of the source nsFrameLoader.
+ nsresult FinishStaticClone(nsFrameLoader* aStaticCloneOf,
+ nsIPrintSettings* aPrintSettings,
+ bool* aOutHasInProcessPrintCallbacks);
+
+ nsresult DoRemoteStaticClone(nsFrameLoader* aStaticCloneOf,
+ nsIPrintSettings* aPrintSettings);
+
+ // WebIDL methods
+
+ nsDocShell* GetDocShell(mozilla::ErrorResult& aRv);
+
+ already_AddRefed<nsIRemoteTab> GetRemoteTab();
+
+ already_AddRefed<nsILoadContext> GetLoadContext();
+
+ mozilla::dom::BrowsingContext* GetBrowsingContext();
+ mozilla::dom::BrowsingContext* GetExtantBrowsingContext();
+ mozilla::dom::BrowsingContext* GetMaybePendingBrowsingContext() {
+ return mPendingBrowsingContext;
+ }
+
+ /**
+ * Start loading the frame. This method figures out what to load
+ * from the owner content in the frame loader.
+ */
+ void LoadFrame(bool aOriginalSrc);
+
+ /**
+ * Loads the specified URI in this frame. Behaves identically to loadFrame,
+ * except that this method allows specifying the URI to load.
+ *
+ * @param aURI The URI to load.
+ * @param aTriggeringPrincipal The triggering principal for the load. May be
+ * null, in which case the node principal of the owner content will be
+ * used.
+ * @param aCsp The CSP to be used for the load. That is not the CSP to be
+ * applied to subresources within the frame, but to the iframe load
+ * itself. E.g. if the CSP holds upgrade-insecure-requests the the
+ * frame load is upgraded from http to https.
+ */
+ nsresult LoadURI(nsIURI* aURI, nsIPrincipal* aTriggeringPrincipal,
+ nsIContentSecurityPolicy* aCsp, bool aOriginalSrc);
+
+ /**
+ * Resume a redirected load within this frame.
+ *
+ * @param aPendingSwitchID ID of a process-switching load to be reusmed
+ * within this frame.
+ */
+ void ResumeLoad(uint64_t aPendingSwitchID);
+
+ /**
+ * Destroy the frame loader and everything inside it. This will
+ * clear the weak owner content reference.
+ */
+ void Destroy(bool aForProcessSwitch = false);
+
+ void AsyncDestroy() {
+ mNeedsAsyncDestroy = true;
+ Destroy();
+ }
+
+ void RequestUpdatePosition(mozilla::ErrorResult& aRv);
+
+ already_AddRefed<Promise> RequestTabStateFlush(mozilla::ErrorResult& aRv);
+
+ void RequestEpochUpdate(uint32_t aEpoch);
+
+ void RequestSHistoryUpdate();
+
+ MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> PrintPreview(
+ nsIPrintSettings* aPrintSettings, BrowsingContext* aSourceBC,
+ mozilla::ErrorResult& aRv);
+
+ void ExitPrintPreview();
+
+ void StartPersistence(BrowsingContext* aContext,
+ nsIWebBrowserPersistDocumentReceiver* aRecv,
+ mozilla::ErrorResult& aRv);
+
+ // WebIDL getters
+
+ already_AddRefed<mozilla::dom::MessageSender> GetMessageManager();
+
+ already_AddRefed<Element> GetOwnerElement();
+
+ uint32_t LazyWidth() const;
+
+ uint32_t LazyHeight() const;
+
+ uint64_t ChildID() const { return mChildID; }
+
+ bool DepthTooGreat() const { return mDepthTooGreat; }
+
+ bool IsDead() const { return mDestroyCalled; }
+
+ bool IsNetworkCreated() const { return mNetworkCreated; }
+
+ /**
+ * Is this a frame loader for a bona fide <iframe mozbrowser>?
+ * <xul:browser> is not a mozbrowser, so this is false for that case.
+ */
+ bool OwnerIsMozBrowserFrame();
+
+ nsIContent* GetParentObject() const;
+
+ /**
+ * MessageManagerCallback methods that we override.
+ */
+ virtual bool DoLoadMessageManagerScript(const nsAString& aURL,
+ bool aRunInGlobalScope) override;
+ virtual nsresult DoSendAsyncMessage(
+ const nsAString& aMessage,
+ mozilla::dom::ipc::StructuredCloneData& aData) override;
+
+ /**
+ * Called from the layout frame associated with this frame loader;
+ * this notifies us to hook up with the widget and view.
+ */
+ MOZ_CAN_RUN_SCRIPT_BOUNDARY bool Show(nsSubDocumentFrame*);
+
+ void MaybeShowFrame();
+
+ /**
+ * Called when the margin properties of the containing frame are changed.
+ */
+ void MarginsChanged();
+
+ /**
+ * Called from the layout frame associated with this frame loader, when
+ * the frame is being torn down; this notifies us that out widget and view
+ * are going away and we should unhook from them.
+ */
+ void Hide();
+
+ // Used when content is causing a FrameLoader to be created, and
+ // needs to try forcing layout to flush in order to get accurate
+ // dimensions for the content area.
+ MOZ_CAN_RUN_SCRIPT_BOUNDARY void ForceLayoutIfNecessary();
+
+ // The guts of an nsFrameLoaderOwner::SwapFrameLoader implementation. A
+ // frame loader owner needs to call this, and pass in the two references to
+ // nsRefPtrs for frame loaders that need to be swapped.
+ nsresult SwapWithOtherLoader(nsFrameLoader* aOther,
+ nsFrameLoaderOwner* aThisOwner,
+ nsFrameLoaderOwner* aOtherOwner);
+
+ nsresult SwapWithOtherRemoteLoader(nsFrameLoader* aOther,
+ nsFrameLoaderOwner* aThisOwner,
+ nsFrameLoaderOwner* aOtherOwner);
+
+ /**
+ * Return the primary frame for our owning content, or null if it
+ * can't be found.
+ */
+ nsIFrame* GetPrimaryFrameOfOwningContent() const;
+
+ /**
+ * Return the document that owns this, or null if we don't have
+ * an owner.
+ */
+ Document* GetOwnerDoc() const;
+
+ /**
+ * Returns whether this frame is a remote frame.
+ *
+ * This is true for either a top-level remote browser in the parent process,
+ * or a remote subframe in the child process.
+ */
+ bool IsRemoteFrame();
+
+ mozilla::dom::RemoteBrowser* GetRemoteBrowser() const;
+
+ /**
+ * Returns the IPDL actor used if this is a top-level remote browser, or null
+ * otherwise.
+ */
+ BrowserParent* GetBrowserParent() const;
+
+ /**
+ * Returns the IPDL actor used if this is an out-of-process iframe, or null
+ * otherwise.
+ */
+ BrowserBridgeChild* GetBrowserBridgeChild() const;
+
+ /**
+ * Returns the layers ID that this remote frame is using to render.
+ *
+ * This must only be called if this is a remote frame.
+ */
+ mozilla::layers::LayersId GetLayersId() const;
+
+ mozilla::dom::ChromeMessageSender* GetFrameMessageManager() {
+ return mMessageManager;
+ }
+
+ mozilla::dom::Element* GetOwnerContent() { return mOwnerContent; }
+
+ /**
+ * Stashes a detached nsIFrame on the frame loader. We do this when we're
+ * destroying the nsSubDocumentFrame. If the nsSubdocumentFrame is
+ * being reframed we'll restore the detached nsIFrame when it's recreated,
+ * otherwise we'll discard the old presentation and set the detached
+ * subdoc nsIFrame to null.
+ */
+ void SetDetachedSubdocFrame(nsIFrame* aDetachedFrame);
+
+ /**
+ * Retrieves the detached nsIFrame as set by SetDetachedSubdocFrame().
+ */
+ nsIFrame* GetDetachedSubdocFrame(bool* aOutIsSet = nullptr) const;
+
+ /**
+ * Applies a new set of sandbox flags. These are merged with the sandbox
+ * flags from our owning content's owning document with a logical OR, this
+ * ensures that we can only add restrictions and never remove them.
+ */
+ void ApplySandboxFlags(uint32_t sandboxFlags);
+
+ void GetURL(nsString& aURL, nsIPrincipal** aTriggeringPrincipal,
+ nsIContentSecurityPolicy** aCsp);
+
+ // Properly retrieves documentSize of any subdocument type.
+ nsresult GetWindowDimensions(nsIntRect& aRect);
+
+ virtual mozilla::dom::ProcessMessageManager* GetProcessMessageManager()
+ const override;
+
+ // public because a callback needs these.
+ RefPtr<mozilla::dom::ChromeMessageSender> mMessageManager;
+ RefPtr<mozilla::dom::InProcessBrowserChildMessageManager>
+ mChildMessageManager;
+
+ virtual JSObject* WrapObject(JSContext* cx,
+ JS::Handle<JSObject*> aGivenProto) override;
+
+ void SetWillChangeProcess();
+
+ // Configure which remote process should be used to host the remote browser
+ // created in `TryRemoteBrowser`. This method _must_ be called before
+ // `TryRemoteBrowser`, and a script blocker must be on the stack.
+ //
+ // |aContentParent|, if set, must have the remote type |aRemoteType|.
+ void ConfigRemoteProcess(const nsACString& aRemoteType,
+ mozilla::dom::ContentParent* aContentParent);
+
+ // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
+ MOZ_CAN_RUN_SCRIPT_BOUNDARY void MaybeNotifyCrashed(
+ mozilla::dom::BrowsingContext* aBrowsingContext,
+ mozilla::dom::ContentParentId aChildID,
+ mozilla::ipc::MessageChannel* aChannel);
+
+ void FireErrorEvent();
+
+ mozilla::dom::SessionStoreChild* GetSessionStoreChild() {
+ return mSessionStoreChild;
+ }
+
+ mozilla::dom::SessionStoreParent* GetSessionStoreParent();
+
+ private:
+ nsFrameLoader(mozilla::dom::Element* aOwner,
+ mozilla::dom::BrowsingContext* aBrowsingContext, bool aIsRemote,
+ bool aNetworkCreated);
+ ~nsFrameLoader();
+
+ void SetOwnerContent(mozilla::dom::Element* aContent);
+
+ /**
+ * Get our owning element's app manifest URL, or return the empty string if
+ * our owning element doesn't have an app manifest URL.
+ */
+ void GetOwnerAppManifestURL(nsAString& aOut);
+
+ /**
+ * If we are an IPC frame, set mRemoteFrame. Otherwise, create and
+ * initialize mDocShell.
+ */
+ nsresult MaybeCreateDocShell();
+ nsresult EnsureMessageManager();
+ nsresult ReallyLoadFrameScripts();
+ nsDocShell* GetDocShell() const { return mDocShell; }
+
+ void AssertSafeToInit();
+
+ // Updates the subdocument position and size. This gets called only
+ // when we have our own in-process DocShell.
+ void UpdateBaseWindowPositionAndSize(nsSubDocumentFrame* aIFrame);
+
+ /**
+ * Checks whether a load of the given URI should be allowed, and returns an
+ * error result if it should not.
+ *
+ * @param aURI The URI to check.
+ * @param aTriggeringPrincipal The triggering principal for the load. May be
+ * null, in which case the node principal of the owner content is used.
+ */
+ nsresult CheckURILoad(nsIURI* aURI, nsIPrincipal* aTriggeringPrincipal);
+ nsresult ReallyStartLoadingInternal();
+
+ // Returns true if we have a remote browser or else attempts to create a
+ // remote browser and returns true if successful.
+ bool EnsureRemoteBrowser();
+
+ // Return true if remote browser created; nothing else to do
+ bool TryRemoteBrowser();
+ bool TryRemoteBrowserInternal();
+
+ // Tell the remote browser that it's now "virtually visible"
+ bool ShowRemoteFrame(const mozilla::ScreenIntSize& size,
+ nsSubDocumentFrame* aFrame = nullptr);
+
+ void AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem,
+ nsIDocShellTreeOwner* aOwner);
+
+ void InitializeBrowserAPI();
+ void DestroyBrowserFrameScripts();
+
+ nsresult GetNewTabContext(mozilla::dom::MutableTabContext* aTabContext,
+ nsIURI* aURI = nullptr);
+
+ enum BrowserParentChange { eBrowserParentRemoved, eBrowserParentChanged };
+ void MaybeUpdatePrimaryBrowserParent(BrowserParentChange aChange);
+
+ nsresult PopulateOriginContextIdsFromAttributes(
+ mozilla::OriginAttributes& aAttr);
+
+ bool EnsureBrowsingContextAttached();
+
+ // Invoke the callback from nsOpenWindowInfo to indicate that a
+ // browsing context for a newly opened tab/window is ready.
+ void InvokeBrowsingContextReadyCallback();
+
+ void RequestFinalTabStateFlush();
+
+ const mozilla::dom::LazyLoadFrameResumptionState&
+ GetLazyLoadFrameResumptionState();
+
+ RefPtr<mozilla::dom::BrowsingContext> mPendingBrowsingContext;
+ nsCOMPtr<nsIURI> mURIToLoad;
+ nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
+ nsCOMPtr<nsIContentSecurityPolicy> mCsp;
+ nsCOMPtr<nsIOpenWindowInfo> mOpenWindowInfo;
+ mozilla::dom::Element* mOwnerContent; // WEAK
+
+ // After the frameloader has been removed from the DOM but before all of the
+ // messages from the frame have been received, we keep a strong reference to
+ // our <browser> element.
+ RefPtr<mozilla::dom::Element> mOwnerContentStrong;
+
+ // Stores the root frame of the subdocument while the subdocument is being
+ // reframed. Used to restore the presentation after reframing.
+ WeakFrame mDetachedSubdocFrame;
+
+ // When performing a process switch, this value is used rather than mURIToLoad
+ // to identify the process-switching load which should be resumed in the
+ // target process.
+ uint64_t mPendingSwitchID;
+
+ uint64_t mChildID;
+ RefPtr<mozilla::dom::RemoteBrowser> mRemoteBrowser;
+ RefPtr<nsDocShell> mDocShell;
+
+ // Holds the last known size of the frame.
+ mozilla::ScreenIntSize mLazySize;
+
+ // Actor for collecting session store data from content children. This will be
+ // cleared and set to null eagerly when taking down the frameloader to break
+ // refcounted cycles early.
+ RefPtr<mozilla::dom::SessionStoreChild> mSessionStoreChild;
+
+ nsCString mRemoteType;
+
+ bool mInitialized : 1;
+ bool mDepthTooGreat : 1;
+ bool mIsTopLevelContent : 1;
+ bool mDestroyCalled : 1;
+ bool mNeedsAsyncDestroy : 1;
+ bool mInSwap : 1;
+ bool mInShow : 1;
+ bool mHideCalled : 1;
+ // True when the object is created for an element which the parser has
+ // created using NS_FROM_PARSER_NETWORK flag. If the element is modified,
+ // it may lose the flag.
+ bool mNetworkCreated : 1;
+
+ // True if a pending load corresponds to the original src (or srcdoc)
+ // attribute of the frame element.
+ bool mLoadingOriginalSrc : 1;
+
+ bool mRemoteBrowserShown : 1;
+ bool mIsRemoteFrame : 1;
+ // If true, the FrameLoader will be re-created with the same BrowsingContext,
+ // but for a different process, after it is destroyed.
+ bool mWillChangeProcess : 1;
+ bool mObservingOwnerContent : 1;
+ // Whether we had a (possibly dead now) mDetachedSubdocFrame.
+ bool mHadDetachedFrame : 1;
+
+ // When an out-of-process nsFrameLoader crashes, an event is fired on the
+ // frame. To ensure this is only fired once, this bit is checked.
+ bool mTabProcessCrashFired : 1;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsFrameLoader, NS_FRAMELOADER_IID)
+
+inline nsISupports* ToSupports(nsFrameLoader* aFrameLoader) {
+ return aFrameLoader;
+}
+
+#endif