nsFrameLoader.h (19360B)
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/. */ 6 7 /* 8 * Class for managing loading of a subframe (creation of the docshell, 9 * handling of loads in it, recursion-checking). 10 */ 11 12 #ifndef nsFrameLoader_h_ 13 #define nsFrameLoader_h_ 14 15 #include <cstdint> 16 17 #include "ErrorList.h" 18 #include "Units.h" 19 #include "js/RootingAPI.h" 20 #include "mozilla/AlreadyAddRefed.h" 21 #include "mozilla/Assertions.h" 22 #include "mozilla/Attributes.h" 23 #include "mozilla/LinkedList.h" 24 #include "mozilla/RefPtr.h" 25 #include "mozilla/dom/BrowsingContext.h" 26 #include "mozilla/dom/MessageManagerCallback.h" 27 #include "mozilla/dom/Nullable.h" 28 #include "mozilla/dom/Promise.h" 29 #include "mozilla/dom/ReferrerPolicyBinding.h" 30 #include "mozilla/dom/WindowProxyHolder.h" 31 #include "mozilla/dom/ipc/IdType.h" 32 #include "mozilla/layers/LayersTypes.h" 33 #include "nsCOMPtr.h" 34 #include "nsCycleCollectionParticipant.h" 35 #include "nsDocShell.h" 36 #include "nsID.h" 37 #include "nsIFrame.h" 38 #include "nsIMutationObserver.h" 39 #include "nsISupports.h" 40 #include "nsRect.h" 41 #include "nsStringFwd.h" 42 #include "nsStubMutationObserver.h" 43 #include "nsWrapperCache.h" 44 45 class nsIURI; 46 class nsSubDocumentFrame; 47 class AutoResetInShow; 48 class AutoResetInFrameSwap; 49 class nsFrameLoaderOwner; 50 class nsIRemoteTab; 51 class nsIDocShellTreeItem; 52 class nsIDocShellTreeOwner; 53 class nsILoadContext; 54 class nsIPrintSettings; 55 class nsIWebBrowserPersistDocumentReceiver; 56 class nsIWebProgressListener; 57 class nsIOpenWindowInfo; 58 59 namespace mozilla { 60 61 class OriginAttributes; 62 63 namespace dom { 64 class ChromeMessageSender; 65 class ContentParent; 66 class Document; 67 class Element; 68 class InProcessBrowserChildMessageManager; 69 class MessageSender; 70 class ProcessMessageManager; 71 class BrowserParent; 72 class MutableTabContext; 73 class BrowserBridgeChild; 74 class RemoteBrowser; 75 struct RemotenessOptions; 76 struct NavigationIsolationOptions; 77 class SessionStoreChild; 78 class SessionStoreParent; 79 80 struct LazyLoadFrameResumptionState { 81 RefPtr<nsIURI> mBaseURI; 82 ReferrerPolicy mReferrerPolicy = ReferrerPolicy::_empty; 83 84 void Clear() { 85 mBaseURI = nullptr; 86 mReferrerPolicy = ReferrerPolicy::_empty; 87 } 88 }; 89 90 namespace ipc { 91 class StructuredCloneData; 92 } // namespace ipc 93 94 } // namespace dom 95 96 namespace ipc { 97 class MessageChannel; 98 } // namespace ipc 99 } // namespace mozilla 100 101 #if defined(MOZ_WIDGET_GTK) 102 typedef struct _GtkWidget GtkWidget; 103 #endif 104 105 // IID for nsFrameLoader, because some places want to QI to it. 106 #define NS_FRAMELOADER_IID \ 107 {0x297fd0ea, 0x1b4a, 0x4c9a, {0xa4, 0x04, 0xe5, 0x8b, 0xe8, 0x95, 0x10, 0x50}} 108 109 class nsFrameLoader final : public nsStubMutationObserver, 110 public mozilla::dom::ipc::MessageManagerCallback, 111 public nsWrapperCache, 112 public mozilla::LinkedListElement<nsFrameLoader> { 113 friend class AutoResetInShow; 114 friend class AutoResetInFrameSwap; 115 friend class nsFrameLoaderOwner; 116 using Document = mozilla::dom::Document; 117 using Element = mozilla::dom::Element; 118 using BrowserParent = mozilla::dom::BrowserParent; 119 using BrowserBridgeChild = mozilla::dom::BrowserBridgeChild; 120 using BrowsingContext = mozilla::dom::BrowsingContext; 121 using BrowsingContextGroup = mozilla::dom::BrowsingContextGroup; 122 using Promise = mozilla::dom::Promise; 123 124 public: 125 // Called by Frame Elements to create a new FrameLoader. 126 static already_AddRefed<nsFrameLoader> Create( 127 Element* aOwner, bool aNetworkCreated, 128 nsIOpenWindowInfo* aOpenWindowInfo = nullptr); 129 130 // Called by nsFrameLoaderOwner::ChangeRemoteness when switching out 131 // FrameLoaders. 132 static already_AddRefed<nsFrameLoader> Recreate( 133 Element* aOwner, BrowsingContext* aContext, BrowsingContextGroup* aGroup, 134 const mozilla::dom::NavigationIsolationOptions& aRemotenessOptions, 135 bool aIsRemote, bool aNetworkCreated, bool aPreserveContext); 136 137 NS_INLINE_DECL_STATIC_IID(NS_FRAMELOADER_IID) 138 139 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 140 NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(nsFrameLoader) 141 142 NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED 143 nsresult CheckForRecursiveLoad(nsIURI* aURI); 144 nsresult ReallyStartLoading(); 145 void StartDestroy(bool aForProcessSwitch); 146 void DestroyDocShell(); 147 void DestroyComplete(); 148 nsDocShell* GetExistingDocShell() const { return mDocShell; } 149 mozilla::dom::InProcessBrowserChildMessageManager* 150 GetBrowserChildMessageManager() const { 151 return mChildMessageManager; 152 } 153 nsresult UpdatePositionAndSize(nsSubDocumentFrame* aFrame); 154 void PropagateIsUnderHiddenEmbedderElement( 155 bool aIsUnderHiddenEmbedderElement); 156 157 void UpdateRemoteStyle(mozilla::StyleImageRendering aImageRendering); 158 159 // When creating a nsFrameLoaderOwner which is a static clone, a 160 // `nsFrameLoader` is not immediately attached to it. Instead, it is added to 161 // the static clone document's `PendingFrameStaticClones` list. 162 // 163 // After the parent document has been fully cloned, a new frameloader will be 164 // created for the cloned iframe, and `FinishStaticClone` will be called on 165 // it, which will clone the inner document of the source nsFrameLoader. 166 nsresult FinishStaticClone(nsFrameLoader* aStaticCloneOf, 167 nsIPrintSettings* aPrintSettings, 168 bool* aOutHasInProcessPrintCallbacks); 169 170 nsresult DoRemoteStaticClone(nsFrameLoader* aStaticCloneOf, 171 nsIPrintSettings* aPrintSettings); 172 173 // WebIDL methods 174 175 nsDocShell* GetDocShell(mozilla::ErrorResult& aRv); 176 177 already_AddRefed<nsIRemoteTab> GetRemoteTab(); 178 179 already_AddRefed<nsILoadContext> GetLoadContext(); 180 181 mozilla::dom::BrowsingContext* GetBrowsingContext(); 182 mozilla::dom::BrowsingContext* GetExtantBrowsingContext(); 183 mozilla::dom::BrowsingContext* GetMaybePendingBrowsingContext() { 184 return mPendingBrowsingContext; 185 } 186 187 /** 188 * Start loading the frame. This method figures out what to load 189 * from the owner content in the frame loader. 190 */ 191 void LoadFrame(bool aOriginalSrc, bool aShouldCheckForRecursion); 192 193 /** 194 * Loads the specified URI in this frame. Behaves identically to loadFrame, 195 * except that this method allows specifying the URI to load. 196 * 197 * @param aURI The URI to load. 198 * @param aTriggeringPrincipal The triggering principal for the load. May be 199 * null, in which case the node principal of the owner content will be 200 * used. 201 * @param aPolicyContainer The policyContainer to be used for the load. That 202 * is not the policyContainer to be applied to subresources within the frame, 203 * but to the iframe load itself. E.g. if the policyContainer's CSP holds 204 * upgrade-insecure-requests the the frame load is upgraded from http to 205 * https. 206 */ 207 nsresult LoadURI(nsIURI* aURI, nsIPrincipal* aTriggeringPrincipal, 208 nsIPolicyContainer* aPolicyContainer, bool aOriginalSrc, 209 bool aShouldCheckForRecursion); 210 211 /** 212 * Resume a redirected load within this frame. 213 * 214 * @param aPendingSwitchID ID of a process-switching load to be reusmed 215 * within this frame. 216 */ 217 void ResumeLoad(uint64_t aPendingSwitchID); 218 219 /** 220 * Destroy the frame loader and everything inside it. This will 221 * clear the weak owner content reference. 222 */ 223 void Destroy(bool aForProcessSwitch = false); 224 225 void AsyncDestroy() { 226 mNeedsAsyncDestroy = true; 227 Destroy(); 228 } 229 230 void RequestUpdatePosition(mozilla::ErrorResult& aRv); 231 232 already_AddRefed<Promise> RequestTabStateFlush(mozilla::ErrorResult& aRv); 233 234 void RequestEpochUpdate(uint32_t aEpoch); 235 236 void RequestSHistoryUpdate(); 237 238 MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> PrintPreview( 239 nsIPrintSettings* aPrintSettings, BrowsingContext* aSourceBC, 240 mozilla::ErrorResult& aRv); 241 242 void ExitPrintPreview(); 243 244 void StartPersistence(BrowsingContext* aContext, 245 nsIWebBrowserPersistDocumentReceiver* aRecv, 246 mozilla::ErrorResult& aRv); 247 248 // WebIDL getters 249 250 already_AddRefed<mozilla::dom::MessageSender> GetMessageManager(); 251 252 already_AddRefed<Element> GetOwnerElement(); 253 254 uint32_t LazyWidth() const; 255 256 uint32_t LazyHeight() const; 257 258 uint64_t ChildID() const { return mChildID; } 259 260 bool DepthTooGreat() const { return mDepthTooGreat; } 261 262 bool IsDead() const { return mDestroyCalled; } 263 264 bool IsNetworkCreated() const { return mNetworkCreated; } 265 266 nsIContent* GetParentObject() const; 267 268 /** 269 * MessageManagerCallback methods that we override. 270 */ 271 virtual bool DoLoadMessageManagerScript(const nsAString& aURL, 272 bool aRunInGlobalScope) override; 273 virtual nsresult DoSendAsyncMessage( 274 const nsAString& aMessage, 275 mozilla::dom::ipc::StructuredCloneData& aData) override; 276 277 /** 278 * Called from the layout frame associated with this frame loader; 279 * this notifies us to hook up with the widget and view. 280 */ 281 MOZ_CAN_RUN_SCRIPT_BOUNDARY bool Show(nsSubDocumentFrame*); 282 283 void MaybeShowFrame(); 284 285 /** 286 * Called when the margin properties of the containing frame are changed. 287 */ 288 void MarginsChanged(); 289 290 /** 291 * Called from the layout frame associated with this frame loader, when 292 * the frame is being torn down; this notifies us that out widget and view 293 * are going away and we should unhook from them. 294 */ 295 void Hide(); 296 297 // Used when content is causing a FrameLoader to be created, and 298 // needs to try forcing layout to flush in order to get accurate 299 // dimensions for the content area. 300 MOZ_CAN_RUN_SCRIPT_BOUNDARY void ForceLayoutIfNecessary(); 301 302 // The guts of an nsFrameLoaderOwner::SwapFrameLoader implementation. A 303 // frame loader owner needs to call this, and pass in the two references to 304 // nsRefPtrs for frame loaders that need to be swapped. 305 nsresult SwapWithOtherLoader(nsFrameLoader* aOther, 306 nsFrameLoaderOwner* aThisOwner, 307 nsFrameLoaderOwner* aOtherOwner); 308 309 nsresult SwapWithOtherRemoteLoader(nsFrameLoader* aOther, 310 nsFrameLoaderOwner* aThisOwner, 311 nsFrameLoaderOwner* aOtherOwner); 312 313 /** 314 * Return the primary frame for our owning content, or null if it 315 * can't be found. 316 */ 317 nsIFrame* GetPrimaryFrameOfOwningContent() const; 318 319 /** 320 * Return the document that owns this, or null if we don't have 321 * an owner. 322 */ 323 Document* GetOwnerDoc() const; 324 325 /** 326 * Returns whether this frame is a remote frame. 327 * 328 * This is true for either a top-level remote browser in the parent process, 329 * or a remote subframe in the child process. 330 */ 331 bool IsRemoteFrame() const { 332 MOZ_ASSERT_IF(mIsRemoteFrame, !GetDocShell()); 333 return mIsRemoteFrame; 334 } 335 336 mozilla::dom::RemoteBrowser* GetRemoteBrowser() const { 337 return mRemoteBrowser; 338 } 339 340 bool HasRemoteBrowserBeenSized() const { return mRemoteBrowserSized; } 341 342 /** 343 * Returns the IPDL actor used if this is a top-level remote browser, or null 344 * otherwise. 345 */ 346 BrowserParent* GetBrowserParent() const; 347 348 /** 349 * Returns the IPDL actor used if this is an out-of-process iframe, or null 350 * otherwise. 351 */ 352 BrowserBridgeChild* GetBrowserBridgeChild() const; 353 354 /** 355 * Returns the layers ID that this remote frame is using to render. 356 * 357 * This must only be called if this is a remote frame. 358 */ 359 mozilla::layers::LayersId GetLayersId() const; 360 361 mozilla::dom::ChromeMessageSender* GetFrameMessageManager() { 362 return mMessageManager; 363 } 364 365 mozilla::dom::Element* GetOwnerContent() { return mOwnerContent; } 366 367 /** 368 * Stashes a list of detached pres shells on the frame loader. We do this when 369 * we're destroying the nsSubDocumentFrame. If the nsSubdocumentFrame is being 370 * reframed we'll restore the detached shells when they're recreated, 371 * otherwise we'll discard the old presentation and clear these. 372 */ 373 using WeakPresShellArray = nsTArray<nsWeakPtr>; 374 void SetDetachedSubdocs(WeakPresShellArray&&); 375 WeakPresShellArray TakeDetachedSubdocs(); 376 const WeakPresShellArray& GetDetachedSubdocs() const { 377 return mDetachedSubdocs; 378 } 379 380 /** 381 * Applies a new set of sandbox flags. These are merged with the sandbox 382 * flags from our owning content's owning document with a logical OR, this 383 * ensures that we can only add restrictions and never remove them. 384 */ 385 void ApplySandboxFlags(uint32_t sandboxFlags); 386 387 void GetURL(nsString& aURL, nsIPrincipal** aTriggeringPrincipal, 388 nsIPolicyContainer** aPolicyContainer); 389 390 // Properly retrieves documentSize of any subdocument type. 391 nsresult GetWindowDimensions(mozilla::LayoutDeviceIntRect& aRect); 392 393 virtual mozilla::dom::ProcessMessageManager* GetProcessMessageManager() 394 const override; 395 396 // public because a callback needs these. 397 RefPtr<mozilla::dom::ChromeMessageSender> mMessageManager; 398 RefPtr<mozilla::dom::InProcessBrowserChildMessageManager> 399 mChildMessageManager; 400 401 virtual JSObject* WrapObject(JSContext* cx, 402 JS::Handle<JSObject*> aGivenProto) override; 403 404 void SetWillChangeProcess(); 405 406 // Configure which remote process should be used to host the remote browser 407 // created in `TryRemoteBrowser`. This method _must_ be called before 408 // `TryRemoteBrowser`, and a script blocker must be on the stack. 409 // 410 // |aContentParent|, if set, must have the remote type |aRemoteType|. 411 void ConfigRemoteProcess(const nsACString& aRemoteType, 412 mozilla::dom::ContentParent* aContentParent); 413 414 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230) 415 MOZ_CAN_RUN_SCRIPT_BOUNDARY void MaybeNotifyCrashed( 416 mozilla::dom::BrowsingContext* aBrowsingContext, 417 mozilla::dom::ContentParentId aChildID, 418 mozilla::ipc::MessageChannel* aChannel); 419 420 void FireErrorEvent(); 421 422 mozilla::dom::SessionStoreChild* GetSessionStoreChild() { 423 return mSessionStoreChild; 424 } 425 426 mozilla::dom::SessionStoreParent* GetSessionStoreParent(); 427 428 private: 429 nsFrameLoader(mozilla::dom::Element* aOwner, 430 mozilla::dom::BrowsingContext* aBrowsingContext, bool aIsRemote, 431 bool aNetworkCreated); 432 ~nsFrameLoader(); 433 434 void SetOwnerContent(mozilla::dom::Element* aContent); 435 436 /** 437 * Get our owning element's app manifest URL, or return the empty string if 438 * our owning element doesn't have an app manifest URL. 439 */ 440 void GetOwnerAppManifestURL(nsAString& aOut); 441 442 /** 443 * If we are an IPC frame, set mRemoteFrame. Otherwise, create and 444 * initialize mDocShell. 445 */ 446 nsresult MaybeCreateDocShell(); 447 nsresult EnsureMessageManager(); 448 nsresult ReallyLoadFrameScripts(); 449 nsDocShell* GetDocShell() const { return mDocShell; } 450 451 void AssertSafeToInit(); 452 453 /** 454 * Checks whether a load of the given URI should be allowed, and returns an 455 * error result if it should not. 456 * 457 * @param aURI The URI to check. 458 * @param aTriggeringPrincipal The triggering principal for the load. May be 459 * null, in which case the node principal of the owner content is used. 460 */ 461 nsresult CheckURILoad(nsIURI* aURI, nsIPrincipal* aTriggeringPrincipal); 462 nsresult ReallyStartLoadingInternal(); 463 464 // Returns true if we have a remote browser or else attempts to create a 465 // remote browser and returns true if successful. 466 bool EnsureRemoteBrowser(); 467 468 // Return true if remote browser created; nothing else to do 469 bool TryRemoteBrowser(); 470 bool TryRemoteBrowserInternal(); 471 472 // Tell the remote browser that it's now "virtually visible" 473 bool ShowRemoteFrame(nsSubDocumentFrame* aFrame); 474 475 void AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem, 476 nsIDocShellTreeOwner* aOwner); 477 478 nsresult GetNewTabContext(mozilla::dom::MutableTabContext* aTabContext, 479 nsIURI* aURI = nullptr); 480 481 enum BrowserParentChange { eBrowserParentRemoved, eBrowserParentChanged }; 482 void MaybeUpdatePrimaryBrowserParent(BrowserParentChange aChange); 483 484 nsresult PopulateOriginContextIdsFromAttributes( 485 mozilla::OriginAttributes& aAttr); 486 487 bool EnsureBrowsingContextAttached(); 488 489 // Invoke the callback from nsOpenWindowInfo to indicate that a 490 // browsing context for a newly opened tab/window is ready. 491 void InvokeBrowsingContextReadyCallback(); 492 493 void RequestFinalTabStateFlush(); 494 495 const mozilla::dom::LazyLoadFrameResumptionState& 496 GetLazyLoadFrameResumptionState(); 497 498 RefPtr<mozilla::dom::BrowsingContext> mPendingBrowsingContext; 499 nsCOMPtr<nsIURI> mURIToLoad; 500 nsCOMPtr<nsIPrincipal> mTriggeringPrincipal; 501 nsCOMPtr<nsIPolicyContainer> mPolicyContainer; 502 nsCOMPtr<nsIOpenWindowInfo> mOpenWindowInfo; 503 mozilla::dom::Element* mOwnerContent; // WEAK 504 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; 509 510 // Stores the detached pres shells of subdocuments. 511 // Used to restore the presentation after reframing. 512 WeakPresShellArray mDetachedSubdocs; 513 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 516 // target process. 517 uint64_t mPendingSwitchID; 518 519 uint64_t mChildID; 520 RefPtr<mozilla::dom::RemoteBrowser> mRemoteBrowser; 521 RefPtr<nsDocShell> mDocShell; 522 523 // Holds the last known size of the frame. 524 mozilla::LayoutDeviceIntSize mLazySize; 525 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; 530 531 nsCString mRemoteType; 532 533 bool mInitialized : 1; 534 bool mDepthTooGreat : 1; 535 bool mIsTopLevelContent : 1; 536 bool mDestroyCalled : 1; 537 bool mNeedsAsyncDestroy : 1; 538 bool mInSwap : 1; 539 bool mInShow : 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; 545 546 // True if a pending load corresponds to the original src (or srcdoc) 547 // attribute of the frame element. 548 bool mLoadingOriginalSrc : 1; 549 550 // True if a pending load corresponds to the src attribute being changed. 551 bool mShouldCheckForRecursion : 1; 552 553 bool mRemoteBrowserShown : 1; 554 bool mRemoteBrowserSized : 1; 555 bool mIsRemoteFrame : 1; 556 // If true, the FrameLoader will be re-created with the same BrowsingContext, 557 // but for a different process, after it is destroyed. 558 bool mWillChangeProcess : 1; 559 bool mObservingOwnerContent : 1; 560 // Whether we had a (possibly dead now) mDetachedSubdocFrame. 561 bool mHadDetachedFrame : 1; 562 563 // When an out-of-process nsFrameLoader crashes, an event is fired on the 564 // frame. To ensure this is only fired once, this bit is checked. 565 bool mTabProcessCrashFired : 1; 566 }; 567 568 inline nsISupports* ToSupports(nsFrameLoader* aFrameLoader) { 569 return aFrameLoader; 570 } 571 572 #endif