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/. */
8 * Class for managing loading of a subframe (creation of the docshell,
9 * handling of loads in it, recursion-checking).
12 #ifndef nsFrameLoader_h_
13 #define nsFrameLoader_h_
16 #include "ErrorList.h"
18 #include "js/RootingAPI.h"
19 #include "mozilla/AlreadyAddRefed.h"
20 #include "mozilla/Assertions.h"
21 #include "mozilla/Attributes.h"
22 #include "mozilla/LinkedList.h"
23 #include "mozilla/RefPtr.h"
24 #include "mozilla/dom/BrowsingContext.h"
25 #include "mozilla/dom/Nullable.h"
26 #include "mozilla/dom/Promise.h"
27 #include "mozilla/dom/ReferrerPolicyBinding.h"
28 #include "mozilla/dom/WindowProxyHolder.h"
29 #include "mozilla/dom/ipc/IdType.h"
30 #include "mozilla/layers/LayersTypes.h"
32 #include "nsCycleCollectionParticipant.h"
33 #include "nsDocShell.h"
34 #include "mozilla/dom/MessageManagerCallback.h"
37 #include "nsIMutationObserver.h"
38 #include "nsISupports.h"
40 #include "nsStringFwd.h"
41 #include "nsStubMutationObserver.h"
42 #include "nsWrapperCache.h"
45 class nsSubDocumentFrame
;
46 class AutoResetInShow
;
47 class AutoResetInFrameSwap
;
48 class nsFrameLoaderOwner
;
50 class nsIDocShellTreeItem
;
51 class nsIDocShellTreeOwner
;
53 class nsIPrintSettings
;
54 class nsIWebBrowserPersistDocumentReceiver
;
55 class nsIWebProgressListener
;
56 class nsIOpenWindowInfo
;
60 class OriginAttributes
;
63 class ChromeMessageSender
;
67 class InProcessBrowserChildMessageManager
;
69 class ProcessMessageManager
;
71 class MutableTabContext
;
72 class BrowserBridgeChild
;
74 struct RemotenessOptions
;
75 struct NavigationIsolationOptions
;
76 class SessionStoreChild
;
77 class SessionStoreParent
;
79 struct LazyLoadFrameResumptionState
{
80 RefPtr
<nsIURI
> mBaseURI
;
81 ReferrerPolicy mReferrerPolicy
= ReferrerPolicy::_empty
;
85 mReferrerPolicy
= ReferrerPolicy::_empty
;
90 class StructuredCloneData
;
98 } // namespace mozilla
100 #if defined(MOZ_WIDGET_GTK)
101 typedef struct _GtkWidget GtkWidget
;
104 // IID for nsFrameLoader, because some places want to QI to it.
105 #define NS_FRAMELOADER_IID \
107 0x297fd0ea, 0x1b4a, 0x4c9a, { \
108 0xa4, 0x04, 0xe5, 0x8b, 0xe8, 0x95, 0x10, 0x50 \
112 class nsFrameLoader final
: public nsStubMutationObserver
,
113 public mozilla::dom::ipc::MessageManagerCallback
,
114 public nsWrapperCache
,
115 public mozilla::LinkedListElement
<nsFrameLoader
> {
116 friend class AutoResetInShow
;
117 friend class AutoResetInFrameSwap
;
118 friend class nsFrameLoaderOwner
;
119 using Document
= mozilla::dom::Document
;
120 using Element
= mozilla::dom::Element
;
121 using BrowserParent
= mozilla::dom::BrowserParent
;
122 using BrowserBridgeChild
= mozilla::dom::BrowserBridgeChild
;
123 using BrowsingContext
= mozilla::dom::BrowsingContext
;
124 using BrowsingContextGroup
= mozilla::dom::BrowsingContextGroup
;
125 using Promise
= mozilla::dom::Promise
;
128 // Called by Frame Elements to create a new FrameLoader.
129 static already_AddRefed
<nsFrameLoader
> Create(
130 Element
* aOwner
, bool aNetworkCreated
,
131 nsIOpenWindowInfo
* aOpenWindowInfo
= nullptr);
133 // Called by nsFrameLoaderOwner::ChangeRemoteness when switching out
135 static already_AddRefed
<nsFrameLoader
> Recreate(
136 Element
* aOwner
, BrowsingContext
* aContext
, BrowsingContextGroup
* aGroup
,
137 const mozilla::dom::NavigationIsolationOptions
& aRemotenessOptions
,
138 bool aIsRemote
, bool aNetworkCreated
, bool aPreserveContext
);
140 NS_DECLARE_STATIC_IID_ACCESSOR(NS_FRAMELOADER_IID
)
142 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
143 NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(nsFrameLoader
)
145 NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
146 nsresult
CheckForRecursiveLoad(nsIURI
* aURI
);
147 nsresult
ReallyStartLoading();
148 void StartDestroy(bool aForProcessSwitch
);
149 void DestroyDocShell();
150 void DestroyComplete();
151 nsDocShell
* GetExistingDocShell() const { return mDocShell
; }
152 mozilla::dom::InProcessBrowserChildMessageManager
*
153 GetBrowserChildMessageManager() const {
154 return mChildMessageManager
;
156 nsresult
UpdatePositionAndSize(nsSubDocumentFrame
* aIFrame
);
157 void PropagateIsUnderHiddenEmbedderElement(
158 bool aIsUnderHiddenEmbedderElement
);
160 void UpdateRemoteStyle(mozilla::StyleImageRendering aImageRendering
);
162 // When creating a nsFrameLoaderOwner which is a static clone, a
163 // `nsFrameLoader` is not immediately attached to it. Instead, it is added to
164 // the static clone document's `PendingFrameStaticClones` list.
166 // After the parent document has been fully cloned, a new frameloader will be
167 // created for the cloned iframe, and `FinishStaticClone` will be called on
168 // it, which will clone the inner document of the source nsFrameLoader.
169 nsresult
FinishStaticClone(nsFrameLoader
* aStaticCloneOf
,
170 nsIPrintSettings
* aPrintSettings
,
171 bool* aOutHasInProcessPrintCallbacks
);
173 nsresult
DoRemoteStaticClone(nsFrameLoader
* aStaticCloneOf
,
174 nsIPrintSettings
* aPrintSettings
);
178 nsDocShell
* GetDocShell(mozilla::ErrorResult
& aRv
);
180 already_AddRefed
<nsIRemoteTab
> GetRemoteTab();
182 already_AddRefed
<nsILoadContext
> GetLoadContext();
184 mozilla::dom::BrowsingContext
* GetBrowsingContext();
185 mozilla::dom::BrowsingContext
* GetExtantBrowsingContext();
186 mozilla::dom::BrowsingContext
* GetMaybePendingBrowsingContext() {
187 return mPendingBrowsingContext
;
191 * Start loading the frame. This method figures out what to load
192 * from the owner content in the frame loader.
194 void LoadFrame(bool aOriginalSrc
);
197 * Loads the specified URI in this frame. Behaves identically to loadFrame,
198 * except that this method allows specifying the URI to load.
200 * @param aURI The URI to load.
201 * @param aTriggeringPrincipal The triggering principal for the load. May be
202 * null, in which case the node principal of the owner content will be
204 * @param aCsp The CSP to be used for the load. That is not the CSP to be
205 * applied to subresources within the frame, but to the iframe load
206 * itself. E.g. if the CSP holds upgrade-insecure-requests the the
207 * frame load is upgraded from http to https.
209 nsresult
LoadURI(nsIURI
* aURI
, nsIPrincipal
* aTriggeringPrincipal
,
210 nsIContentSecurityPolicy
* aCsp
, bool aOriginalSrc
);
213 * Resume a redirected load within this frame.
215 * @param aPendingSwitchID ID of a process-switching load to be reusmed
218 void ResumeLoad(uint64_t aPendingSwitchID
);
221 * Destroy the frame loader and everything inside it. This will
222 * clear the weak owner content reference.
224 void Destroy(bool aForProcessSwitch
= false);
226 void AsyncDestroy() {
227 mNeedsAsyncDestroy
= true;
231 void RequestUpdatePosition(mozilla::ErrorResult
& aRv
);
233 already_AddRefed
<Promise
> RequestTabStateFlush(mozilla::ErrorResult
& aRv
);
235 void RequestEpochUpdate(uint32_t aEpoch
);
237 void RequestSHistoryUpdate();
239 MOZ_CAN_RUN_SCRIPT already_AddRefed
<Promise
> PrintPreview(
240 nsIPrintSettings
* aPrintSettings
, BrowsingContext
* aSourceBC
,
241 mozilla::ErrorResult
& aRv
);
243 void ExitPrintPreview();
245 void StartPersistence(BrowsingContext
* aContext
,
246 nsIWebBrowserPersistDocumentReceiver
* aRecv
,
247 mozilla::ErrorResult
& aRv
);
251 already_AddRefed
<mozilla::dom::MessageSender
> GetMessageManager();
253 already_AddRefed
<Element
> GetOwnerElement();
255 uint32_t LazyWidth() const;
257 uint32_t LazyHeight() const;
259 uint64_t ChildID() const { return mChildID
; }
261 bool DepthTooGreat() const { return mDepthTooGreat
; }
263 bool IsDead() const { return mDestroyCalled
; }
265 bool IsNetworkCreated() const { return mNetworkCreated
; }
267 nsIContent
* GetParentObject() const;
270 * MessageManagerCallback methods that we override.
272 virtual bool DoLoadMessageManagerScript(const nsAString
& aURL
,
273 bool aRunInGlobalScope
) override
;
274 virtual nsresult
DoSendAsyncMessage(
275 const nsAString
& aMessage
,
276 mozilla::dom::ipc::StructuredCloneData
& aData
) override
;
279 * Called from the layout frame associated with this frame loader;
280 * this notifies us to hook up with the widget and view.
282 MOZ_CAN_RUN_SCRIPT_BOUNDARY
bool Show(nsSubDocumentFrame
*);
284 void MaybeShowFrame();
287 * Called when the margin properties of the containing frame are changed.
289 void MarginsChanged();
292 * Called from the layout frame associated with this frame loader, when
293 * the frame is being torn down; this notifies us that out widget and view
294 * are going away and we should unhook from them.
298 // Used when content is causing a FrameLoader to be created, and
299 // needs to try forcing layout to flush in order to get accurate
300 // dimensions for the content area.
301 MOZ_CAN_RUN_SCRIPT_BOUNDARY
void ForceLayoutIfNecessary();
303 // The guts of an nsFrameLoaderOwner::SwapFrameLoader implementation. A
304 // frame loader owner needs to call this, and pass in the two references to
305 // nsRefPtrs for frame loaders that need to be swapped.
306 nsresult
SwapWithOtherLoader(nsFrameLoader
* aOther
,
307 nsFrameLoaderOwner
* aThisOwner
,
308 nsFrameLoaderOwner
* aOtherOwner
);
310 nsresult
SwapWithOtherRemoteLoader(nsFrameLoader
* aOther
,
311 nsFrameLoaderOwner
* aThisOwner
,
312 nsFrameLoaderOwner
* aOtherOwner
);
315 * Return the primary frame for our owning content, or null if it
318 nsIFrame
* GetPrimaryFrameOfOwningContent() const;
321 * Return the document that owns this, or null if we don't have
324 Document
* GetOwnerDoc() const;
327 * Returns whether this frame is a remote frame.
329 * This is true for either a top-level remote browser in the parent process,
330 * or a remote subframe in the child process.
332 bool IsRemoteFrame();
334 mozilla::dom::RemoteBrowser
* GetRemoteBrowser() const;
337 * Returns the IPDL actor used if this is a top-level remote browser, or null
340 BrowserParent
* GetBrowserParent() const;
343 * Returns the IPDL actor used if this is an out-of-process iframe, or null
346 BrowserBridgeChild
* GetBrowserBridgeChild() const;
349 * Returns the layers ID that this remote frame is using to render.
351 * This must only be called if this is a remote frame.
353 mozilla::layers::LayersId
GetLayersId() const;
355 mozilla::dom::ChromeMessageSender
* GetFrameMessageManager() {
356 return mMessageManager
;
359 mozilla::dom::Element
* GetOwnerContent() { return mOwnerContent
; }
362 * Stashes a detached nsIFrame on the frame loader. We do this when we're
363 * destroying the nsSubDocumentFrame. If the nsSubdocumentFrame is
364 * being reframed we'll restore the detached nsIFrame when it's recreated,
365 * otherwise we'll discard the old presentation and set the detached
366 * subdoc nsIFrame to null.
368 void SetDetachedSubdocFrame(nsIFrame
* aDetachedFrame
);
371 * Retrieves the detached nsIFrame as set by SetDetachedSubdocFrame().
373 nsIFrame
* GetDetachedSubdocFrame(bool* aOutIsSet
= nullptr) const;
376 * Applies a new set of sandbox flags. These are merged with the sandbox
377 * flags from our owning content's owning document with a logical OR, this
378 * ensures that we can only add restrictions and never remove them.
380 void ApplySandboxFlags(uint32_t sandboxFlags
);
382 void GetURL(nsString
& aURL
, nsIPrincipal
** aTriggeringPrincipal
,
383 nsIContentSecurityPolicy
** aCsp
);
385 // Properly retrieves documentSize of any subdocument type.
386 nsresult
GetWindowDimensions(nsIntRect
& aRect
);
388 virtual mozilla::dom::ProcessMessageManager
* GetProcessMessageManager()
391 // public because a callback needs these.
392 RefPtr
<mozilla::dom::ChromeMessageSender
> mMessageManager
;
393 RefPtr
<mozilla::dom::InProcessBrowserChildMessageManager
>
394 mChildMessageManager
;
396 virtual JSObject
* WrapObject(JSContext
* cx
,
397 JS::Handle
<JSObject
*> aGivenProto
) override
;
399 void SetWillChangeProcess();
401 // Configure which remote process should be used to host the remote browser
402 // created in `TryRemoteBrowser`. This method _must_ be called before
403 // `TryRemoteBrowser`, and a script blocker must be on the stack.
405 // |aContentParent|, if set, must have the remote type |aRemoteType|.
406 void ConfigRemoteProcess(const nsACString
& aRemoteType
,
407 mozilla::dom::ContentParent
* aContentParent
);
409 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
410 MOZ_CAN_RUN_SCRIPT_BOUNDARY
void MaybeNotifyCrashed(
411 mozilla::dom::BrowsingContext
* aBrowsingContext
,
412 mozilla::dom::ContentParentId aChildID
,
413 mozilla::ipc::MessageChannel
* aChannel
);
415 void FireErrorEvent();
417 mozilla::dom::SessionStoreChild
* GetSessionStoreChild() {
418 return mSessionStoreChild
;
421 mozilla::dom::SessionStoreParent
* GetSessionStoreParent();
424 nsFrameLoader(mozilla::dom::Element
* aOwner
,
425 mozilla::dom::BrowsingContext
* aBrowsingContext
, bool aIsRemote
,
426 bool aNetworkCreated
);
429 void SetOwnerContent(mozilla::dom::Element
* aContent
);
432 * Get our owning element's app manifest URL, or return the empty string if
433 * our owning element doesn't have an app manifest URL.
435 void GetOwnerAppManifestURL(nsAString
& aOut
);
438 * If we are an IPC frame, set mRemoteFrame. Otherwise, create and
439 * initialize mDocShell.
441 nsresult
MaybeCreateDocShell();
442 nsresult
EnsureMessageManager();
443 nsresult
ReallyLoadFrameScripts();
444 nsDocShell
* GetDocShell() const { return mDocShell
; }
446 void AssertSafeToInit();
448 // Updates the subdocument position and size. This gets called only
449 // when we have our own in-process DocShell.
450 void UpdateBaseWindowPositionAndSize(nsSubDocumentFrame
* aIFrame
);
453 * Checks whether a load of the given URI should be allowed, and returns an
454 * error result if it should not.
456 * @param aURI The URI to check.
457 * @param aTriggeringPrincipal The triggering principal for the load. May be
458 * null, in which case the node principal of the owner content is used.
460 nsresult
CheckURILoad(nsIURI
* aURI
, nsIPrincipal
* aTriggeringPrincipal
);
461 nsresult
ReallyStartLoadingInternal();
463 // Returns true if we have a remote browser or else attempts to create a
464 // remote browser and returns true if successful.
465 bool EnsureRemoteBrowser();
467 // Return true if remote browser created; nothing else to do
468 bool TryRemoteBrowser();
469 bool TryRemoteBrowserInternal();
471 // Tell the remote browser that it's now "virtually visible"
472 bool ShowRemoteFrame(const mozilla::ScreenIntSize
& size
,
473 nsSubDocumentFrame
* aFrame
= nullptr);
475 void AddTreeItemToTreeOwner(nsIDocShellTreeItem
* aItem
,
476 nsIDocShellTreeOwner
* aOwner
);
478 nsresult
GetNewTabContext(mozilla::dom::MutableTabContext
* aTabContext
,
479 nsIURI
* aURI
= nullptr);
481 enum BrowserParentChange
{ eBrowserParentRemoved
, eBrowserParentChanged
};
482 void MaybeUpdatePrimaryBrowserParent(BrowserParentChange aChange
);
484 nsresult
PopulateOriginContextIdsFromAttributes(
485 mozilla::OriginAttributes
& aAttr
);
487 bool EnsureBrowsingContextAttached();
489 // Invoke the callback from nsOpenWindowInfo to indicate that a
490 // browsing context for a newly opened tab/window is ready.
491 void InvokeBrowsingContextReadyCallback();
493 void RequestFinalTabStateFlush();
495 const mozilla::dom::LazyLoadFrameResumptionState
&
496 GetLazyLoadFrameResumptionState();
498 RefPtr
<mozilla::dom::BrowsingContext
> mPendingBrowsingContext
;
499 nsCOMPtr
<nsIURI
> mURIToLoad
;
500 nsCOMPtr
<nsIPrincipal
> mTriggeringPrincipal
;
501 nsCOMPtr
<nsIContentSecurityPolicy
> mCsp
;
502 nsCOMPtr
<nsIOpenWindowInfo
> mOpenWindowInfo
;
503 mozilla::dom::Element
* mOwnerContent
; // WEAK
505 // After the frameloader has been removed from the DOM but before all of the
506 // messages from the frame have been received, we keep a strong reference to
507 // our <browser> element.
508 RefPtr
<mozilla::dom::Element
> mOwnerContentStrong
;
510 // Stores the root frame of the subdocument while the subdocument is being
511 // reframed. Used to restore the presentation after reframing.
512 WeakFrame mDetachedSubdocFrame
;
514 // When performing a process switch, this value is used rather than mURIToLoad
515 // to identify the process-switching load which should be resumed in the
517 uint64_t mPendingSwitchID
;
520 RefPtr
<mozilla::dom::RemoteBrowser
> mRemoteBrowser
;
521 RefPtr
<nsDocShell
> mDocShell
;
523 // Holds the last known size of the frame.
524 mozilla::ScreenIntSize mLazySize
;
526 // Actor for collecting session store data from content children. This will be
527 // cleared and set to null eagerly when taking down the frameloader to break
528 // refcounted cycles early.
529 RefPtr
<mozilla::dom::SessionStoreChild
> mSessionStoreChild
;
531 nsCString mRemoteType
;
533 bool mInitialized
: 1;
534 bool mDepthTooGreat
: 1;
535 bool mIsTopLevelContent
: 1;
536 bool mDestroyCalled
: 1;
537 bool mNeedsAsyncDestroy
: 1;
540 bool mHideCalled
: 1;
541 // True when the object is created for an element which the parser has
542 // created using NS_FROM_PARSER_NETWORK flag. If the element is modified,
543 // it may lose the flag.
544 bool mNetworkCreated
: 1;
546 // True if a pending load corresponds to the original src (or srcdoc)
547 // attribute of the frame element.
548 bool mLoadingOriginalSrc
: 1;
550 bool mRemoteBrowserShown
: 1;
551 bool mIsRemoteFrame
: 1;
552 // If true, the FrameLoader will be re-created with the same BrowsingContext,
553 // but for a different process, after it is destroyed.
554 bool mWillChangeProcess
: 1;
555 bool mObservingOwnerContent
: 1;
556 // Whether we had a (possibly dead now) mDetachedSubdocFrame.
557 bool mHadDetachedFrame
: 1;
559 // When an out-of-process nsFrameLoader crashes, an event is fired on the
560 // frame. To ensure this is only fired once, this bit is checked.
561 bool mTabProcessCrashFired
: 1;
564 NS_DEFINE_STATIC_IID_ACCESSOR(nsFrameLoader
, NS_FRAMELOADER_IID
)
566 inline nsISupports
* ToSupports(nsFrameLoader
* aFrameLoader
) {