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 #ifndef mozilla_dom_CanonicalBrowsingContext_h 8 #define mozilla_dom_CanonicalBrowsingContext_h 9 10 #include "mozilla/dom/BrowsingContext.h" 11 #include "mozilla/dom/MediaControlKeySource.h" 12 #include "mozilla/dom/BrowsingContextWebProgress.h" 13 #include "mozilla/dom/ProcessIsolation.h" 14 #include "mozilla/dom/Promise.h" 15 #include "mozilla/dom/SessionHistoryEntry.h" 16 #include "mozilla/dom/SessionStoreRestoreData.h" 17 #include "mozilla/dom/SessionStoreUtils.h" 18 #include "mozilla/dom/ipc/IdType.h" 19 #include "mozilla/RefPtr.h" 20 #include "mozilla/MozPromise.h" 21 #include "nsCycleCollectionParticipant.h" 22 #include "nsWrapperCache.h" 23 #include "nsTArray.h" 24 #include "nsTHashtable.h" 25 #include "nsHashKeys.h" 26 #include "nsISecureBrowserUI.h" 27 28 class nsISHistory; 29 class nsIWidget; 30 class nsIPrintSettings; 31 class nsSHistory; 32 class nsBrowserStatusFilter; 33 class nsSecureBrowserUI; 34 class CallerWillNotifyHistoryIndexAndLengthChanges; 35 class nsITimer; 36 37 namespace mozilla { 38 enum class CallState; 39 40 namespace embedding { 41 class PrintData; 42 } 43 44 namespace net { 45 class DocumentLoadListener; 46 } 47 48 namespace dom { 49 50 class BrowserParent; 51 class BrowserBridgeParent; 52 class FeaturePolicy; 53 struct LoadURIOptions; 54 class MediaController; 55 struct LoadingSessionHistoryInfo; 56 class SSCacheCopy; 57 class WindowGlobalParent; 58 59 // CanonicalBrowsingContext is a BrowsingContext living in the parent 60 // process, with whatever extra data that a BrowsingContext in the 61 // parent needs. 62 class CanonicalBrowsingContext final : public BrowsingContext { 63 public: 64 NS_DECL_ISUPPORTS_INHERITED 65 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED( 66 CanonicalBrowsingContext, BrowsingContext) 67 68 static already_AddRefed<CanonicalBrowsingContext> Get(uint64_t aId); 69 static CanonicalBrowsingContext* Cast(BrowsingContext* aContext); 70 static const CanonicalBrowsingContext* Cast(const BrowsingContext* aContext); 71 static already_AddRefed<CanonicalBrowsingContext> Cast( 72 already_AddRefed<BrowsingContext>&& aContext); 73 IsOwnedByProcess(uint64_t aProcessId)74 bool IsOwnedByProcess(uint64_t aProcessId) const { 75 return mProcessId == aProcessId; 76 } IsEmbeddedInProcess(uint64_t aProcessId)77 bool IsEmbeddedInProcess(uint64_t aProcessId) const { 78 return mEmbedderProcessId == aProcessId; 79 } OwnerProcessId()80 uint64_t OwnerProcessId() const { return mProcessId; } EmbedderProcessId()81 uint64_t EmbedderProcessId() const { return mEmbedderProcessId; } 82 ContentParent* GetContentParent() const; 83 84 void GetCurrentRemoteType(nsACString& aRemoteType, ErrorResult& aRv) const; 85 86 void SetOwnerProcessId(uint64_t aProcessId); 87 88 // The ID of the BrowsingContext which caused this BrowsingContext to be 89 // opened, or `0` if this is unknown. 90 // Only set for toplevel content BrowsingContexts, and may be from a different 91 // BrowsingContextGroup. GetCrossGroupOpenerId()92 uint64_t GetCrossGroupOpenerId() const { return mCrossGroupOpenerId; } 93 void SetCrossGroupOpenerId(uint64_t aOpenerId); 94 void SetCrossGroupOpener(CanonicalBrowsingContext& aCrossGroupOpener, 95 ErrorResult& aRv); 96 97 void GetWindowGlobals(nsTArray<RefPtr<WindowGlobalParent>>& aWindows); 98 99 // The current active WindowGlobal. 100 WindowGlobalParent* GetCurrentWindowGlobal() const; 101 102 // Same as the methods on `BrowsingContext`, but with the types already cast 103 // to the parent process type. GetParent()104 CanonicalBrowsingContext* GetParent() { 105 return Cast(BrowsingContext::GetParent()); 106 } Top()107 CanonicalBrowsingContext* Top() { return Cast(BrowsingContext::Top()); } 108 WindowGlobalParent* GetParentWindowContext(); 109 WindowGlobalParent* GetTopWindowContext(); 110 111 already_AddRefed<nsIWidget> GetParentProcessWidgetContaining(); 112 113 // Same as `GetParentWindowContext`, but will also cross <browser> and 114 // content/chrome boundaries. 115 already_AddRefed<WindowGlobalParent> GetEmbedderWindowGlobal() const; 116 117 already_AddRefed<CanonicalBrowsingContext> GetParentCrossChromeBoundary(); 118 119 already_AddRefed<CanonicalBrowsingContext> TopCrossChromeBoundary(); 120 Nullable<WindowProxyHolder> GetTopChromeWindow(); 121 122 nsISHistory* GetSessionHistory(); 123 SessionHistoryEntry* GetActiveSessionHistoryEntry(); 124 void SetActiveSessionHistoryEntry(SessionHistoryEntry* aEntry); 125 126 UniquePtr<LoadingSessionHistoryInfo> CreateLoadingSessionHistoryEntryForLoad( 127 nsDocShellLoadState* aLoadState, nsIChannel* aChannel); 128 129 UniquePtr<LoadingSessionHistoryInfo> ReplaceLoadingSessionHistoryEntryForLoad( 130 LoadingSessionHistoryInfo* aInfo, nsIChannel* aOldChannel, 131 nsIChannel* aNewChannel); 132 133 already_AddRefed<Promise> Print(nsIPrintSettings* aPrintSettings, 134 ErrorResult& aRv); 135 136 // Call the given callback on all top-level descendant BrowsingContexts. 137 // Return Callstate::Stop from the callback to stop calling 138 // further children. 139 void CallOnAllTopDescendants( 140 const std::function<mozilla::CallState(CanonicalBrowsingContext*)>& 141 aCallback); 142 143 void SessionHistoryCommit(uint64_t aLoadId, const nsID& aChangeID, 144 uint32_t aLoadType, bool aPersist, 145 bool aCloneEntryChildren, bool aChannelExpired, 146 uint32_t aCacheKey); 147 148 // Calls the session history listeners' OnHistoryReload, storing the result in 149 // aCanReload. If aCanReload is set to true and we have an active or a loading 150 // entry then aLoadState will be initialized from that entry, and 151 // aReloadActiveEntry will be true if we have an active entry. If aCanReload 152 // is true and aLoadState and aReloadActiveEntry are not set then we should 153 // attempt to reload based on the current document in the docshell. 154 void NotifyOnHistoryReload(bool aForceReload, bool& aCanReload, 155 Maybe<RefPtr<nsDocShellLoadState>>& aLoadState, 156 Maybe<bool>& aReloadActiveEntry); 157 158 // See BrowsingContext::SetActiveSessionHistoryEntry. 159 void SetActiveSessionHistoryEntry(const Maybe<nsPoint>& aPreviousScrollPos, 160 SessionHistoryInfo* aInfo, 161 uint32_t aLoadType, 162 uint32_t aUpdatedCacheKey, 163 const nsID& aChangeID); 164 165 void ReplaceActiveSessionHistoryEntry(SessionHistoryInfo* aInfo); 166 167 void RemoveDynEntriesFromActiveSessionHistoryEntry(); 168 169 void RemoveFromSessionHistory(const nsID& aChangeID); 170 171 void HistoryGo(int32_t aIndex, uint64_t aHistoryEpoch, 172 bool aRequireUserInteraction, bool aUserActivation, 173 Maybe<ContentParentId> aContentId, 174 std::function<void(int32_t&&)>&& aResolver); 175 176 JSObject* WrapObject(JSContext* aCx, 177 JS::Handle<JSObject*> aGivenProto) override; 178 179 // Dispatches a wheel zoom change to the embedder element. 180 void DispatchWheelZoomChange(bool aIncrease); 181 182 // This function is used to start the autoplay media which are delayed to 183 // start. If needed, it would also notify the content browsing context which 184 // are related with the canonical browsing content tree to start delayed 185 // autoplay media. 186 void NotifyStartDelayedAutoplayMedia(); 187 188 // This function is used to mute or unmute all media within a tab. It would 189 // set the media mute property for the top level window and propagate it to 190 // other top level windows in other processes. 191 void NotifyMediaMutedChanged(bool aMuted, ErrorResult& aRv); 192 193 // Return the number of unique site origins by iterating all given BCs, 194 // including their subtrees. 195 static uint32_t CountSiteOrigins( 196 GlobalObject& aGlobal, 197 const Sequence<mozilla::OwningNonNull<BrowsingContext>>& aRoots); 198 199 // This function would propogate the action to its all child browsing contexts 200 // in content processes. 201 void UpdateMediaControlAction(const MediaControlAction& aAction); 202 203 // Triggers a load in the process 204 using BrowsingContext::LoadURI; 205 void LoadURI(const nsAString& aURI, const LoadURIOptions& aOptions, 206 ErrorResult& aError); 207 208 void GoBack(const Optional<int32_t>& aCancelContentJSEpoch, 209 bool aRequireUserInteraction, bool aUserActivation); 210 void GoForward(const Optional<int32_t>& aCancelContentJSEpoch, 211 bool aRequireUserInteraction, bool aUserActivation); 212 void GoToIndex(int32_t aIndex, const Optional<int32_t>& aCancelContentJSEpoch, 213 bool aUserActivation); 214 void Reload(uint32_t aReloadFlags); 215 void Stop(uint32_t aStopFlags); 216 217 // Get the publicly exposed current URI loaded in this BrowsingContext. 218 already_AddRefed<nsIURI> GetCurrentURI() const; 219 void SetCurrentRemoteURI(nsIURI* aCurrentRemoteURI); 220 221 BrowserParent* GetBrowserParent() const; 222 void SetCurrentBrowserParent(BrowserParent* aBrowserParent); 223 224 // Internal method to change which process a BrowsingContext is being loaded 225 // in. The returned promise will resolve when the process switch is completed. 226 // 227 // A NOT_REMOTE_TYPE aRemoteType argument will perform a process switch into 228 // the parent process, and the method will resolve with a null BrowserParent. 229 using RemotenessPromise = MozPromise<RefPtr<BrowserParent>, nsresult, false>; 230 RefPtr<RemotenessPromise> ChangeRemoteness( 231 const NavigationIsolationOptions& aOptions, uint64_t aPendingSwitchId); 232 233 // Return a media controller from the top-level browsing context that can 234 // control all media belonging to this browsing context tree. Return nullptr 235 // if the top-level browsing context has been discarded. 236 MediaController* GetMediaController(); 237 bool HasCreatedMediaController() const; 238 239 // Attempts to start loading the given load state in this BrowsingContext, 240 // without requiring any communication from a docshell. This will handle 241 // computing the right process to load in, and organising handoff to 242 // the right docshell when we get a response. 243 bool LoadInParent(nsDocShellLoadState* aLoadState, bool aSetNavigating); 244 245 // Attempts to start loading the given load state in this BrowsingContext, 246 // in parallel with a DocumentChannelChild being created in the docshell. 247 // Requires the DocumentChannel to connect with this load for it to 248 // complete successfully. 249 bool AttemptSpeculativeLoadInParent(nsDocShellLoadState* aLoadState); 250 251 // Get or create a secure browser UI for this BrowsingContext 252 nsISecureBrowserUI* GetSecureBrowserUI(); 253 GetWebProgress()254 BrowsingContextWebProgress* GetWebProgress() { return mWebProgress; } 255 256 // Called when the current URI changes (from an 257 // nsIWebProgressListener::OnLocationChange event, so that we 258 // can update our security UI for the new location, or when the 259 // mixed content/https-only state for our current window is changed. 260 void UpdateSecurityState(); 261 262 void MaybeAddAsProgressListener(nsIWebProgress* aWebProgress); 263 264 // Called when a navigation forces us to recreate our browsing 265 // context (for example, when switching in or out of the parent 266 // process). 267 // aNewContext is the newly created BrowsingContext that is replacing 268 // us. 269 void ReplacedBy(CanonicalBrowsingContext* aNewContext, 270 const NavigationIsolationOptions& aRemotenessOptions); 271 272 bool HasHistoryEntry(nsISHEntry* aEntry); 273 274 void SwapHistoryEntries(nsISHEntry* aOldEntry, nsISHEntry* aNewEntry); 275 276 void AddLoadingSessionHistoryEntry(uint64_t aLoadId, 277 SessionHistoryEntry* aEntry); 278 279 void GetLoadingSessionHistoryInfoFromParent( 280 Maybe<LoadingSessionHistoryInfo>& aLoadingInfo); 281 282 void HistoryCommitIndexAndLength(); 283 284 void ResetScalingZoom(); 285 286 void SetContainerFeaturePolicy(FeaturePolicy* aContainerFeaturePolicy); GetContainerFeaturePolicy()287 FeaturePolicy* GetContainerFeaturePolicy() const { 288 return mContainerFeaturePolicy; 289 } 290 291 void SetRestoreData(SessionStoreRestoreData* aData, ErrorResult& aError); 292 void ClearRestoreState(); 293 MOZ_CAN_RUN_SCRIPT_BOUNDARY void RequestRestoreTabContent( 294 WindowGlobalParent* aWindow); 295 already_AddRefed<Promise> GetRestorePromise(); 296 297 nsresult WriteSessionStorageToSessionStore( 298 const nsTArray<SSCacheCopy>& aSesssionStorage, uint32_t aEpoch); 299 300 void UpdateSessionStoreSessionStorage(const std::function<void()>& aDone); 301 302 static void UpdateSessionStoreForStorage(uint64_t aBrowsingContextId); 303 304 // Called when a BrowserParent for this BrowsingContext has been fully 305 // destroyed (i.e. `ActorDestroy` was called). 306 void BrowserParentDestroyed(BrowserParent* aBrowserParent, 307 bool aAbnormalShutdown); 308 309 void StartUnloadingHost(uint64_t aChildID); 310 void ClearUnloadingHost(uint64_t aChildID); 311 312 bool AllowedInBFCache(const Maybe<uint64_t>& aChannelId, nsIURI* aNewURI); 313 314 // Methods for getting and setting the active state for top level 315 // browsing contexts, for the process priority manager. IsPriorityActive()316 bool IsPriorityActive() const { 317 MOZ_RELEASE_ASSERT(IsTop()); 318 return mPriorityActive; 319 } SetPriorityActive(bool aIsActive)320 void SetPriorityActive(bool aIsActive) { 321 MOZ_RELEASE_ASSERT(IsTop()); 322 mPriorityActive = aIsActive; 323 } 324 325 void SetTouchEventsOverride(dom::TouchEventsOverride, ErrorResult& aRv); 326 IsReplaced()327 bool IsReplaced() const { return mIsReplaced; } 328 PermanentKey()329 const JS::Heap<JS::Value>& PermanentKey() { return mPermanentKey; } ClearPermanentKey()330 void ClearPermanentKey() { mPermanentKey.setNull(); } 331 void MaybeSetPermanentKey(Element* aEmbedder); 332 333 // When request for page awake, it would increase a count that is used to 334 // prevent whole browsing context tree from being suspended. The request can 335 // be called multiple times. When calling the revoke, it would decrease the 336 // count and once the count reaches to zero, the browsing context tree could 337 // be suspended when the tree is inactive. 338 void AddPageAwakeRequest(); 339 void RemovePageAwakeRequest(); 340 341 void CloneDocumentTreeInto(CanonicalBrowsingContext* aSource, 342 const nsACString& aRemoteType, 343 embedding::PrintData&& aPrintData); 344 345 // Returns a Promise which resolves when cloning documents for printing 346 // finished if this browsing context is cloning document tree. GetClonePromise()347 RefPtr<GenericNonExclusivePromise> GetClonePromise() const { 348 return mClonePromise; 349 } 350 351 bool StartApzAutoscroll(float aAnchorX, float aAnchorY, nsViewID aScrollId, 352 uint32_t aPresShellId); 353 void StopApzAutoscroll(nsViewID aScrollId, uint32_t aPresShellId); 354 355 void AddFinalDiscardListener(std::function<void(uint64_t)>&& aListener); 356 357 protected: 358 // Called when the browsing context is being discarded. 359 void CanonicalDiscard(); 360 361 // Called when the browsing context is being attached. 362 void CanonicalAttach(); 363 364 // Called when the browsing context private mode is changed after 365 // being attached, but before being discarded. 366 void AdjustPrivateBrowsingCount(bool aPrivateBrowsing); 367 368 using Type = BrowsingContext::Type; 369 CanonicalBrowsingContext(WindowContext* aParentWindow, 370 BrowsingContextGroup* aGroup, 371 uint64_t aBrowsingContextId, 372 uint64_t aOwnerProcessId, 373 uint64_t aEmbedderProcessId, Type aType, 374 FieldValues&& aInit); 375 376 private: 377 friend class BrowsingContext; 378 379 virtual ~CanonicalBrowsingContext(); 380 381 class PendingRemotenessChange { 382 public: 383 NS_INLINE_DECL_REFCOUNTING(PendingRemotenessChange) 384 385 PendingRemotenessChange(CanonicalBrowsingContext* aTarget, 386 RemotenessPromise::Private* aPromise, 387 uint64_t aPendingSwitchId, 388 const NavigationIsolationOptions& aOptions); 389 390 void Cancel(nsresult aRv); 391 392 private: 393 friend class CanonicalBrowsingContext; 394 395 ~PendingRemotenessChange(); 396 void ProcessLaunched(); 397 void ProcessReady(); 398 void MaybeFinish(); 399 void Clear(); 400 401 nsresult FinishTopContent(); 402 nsresult FinishSubframe(); 403 404 RefPtr<CanonicalBrowsingContext> mTarget; 405 RefPtr<RemotenessPromise::Private> mPromise; 406 RefPtr<ContentParent> mContentParent; 407 RefPtr<BrowsingContextGroup> mSpecificGroup; 408 409 bool mProcessReady = false; 410 bool mWaitingForPrepareToChange = false; 411 412 uint64_t mPendingSwitchId; 413 NavigationIsolationOptions mOptions; 414 }; 415 416 struct RestoreState { NS_INLINE_DECL_REFCOUNTINGRestoreState417 NS_INLINE_DECL_REFCOUNTING(RestoreState) 418 419 void ClearData() { mData = nullptr; } 420 void Resolve(); 421 422 RefPtr<SessionStoreRestoreData> mData; 423 RefPtr<Promise> mPromise; 424 uint32_t mRequests = 0; 425 uint32_t mResolves = 0; 426 427 private: 428 ~RestoreState() = default; 429 }; 430 431 friend class net::DocumentLoadListener; 432 // Called when a DocumentLoadListener is created to start a load for 433 // this browsing context. Returns false if a higher priority load is 434 // already in-progress and the new one has been rejected. 435 bool StartDocumentLoad(net::DocumentLoadListener* aLoad); 436 // Called once DocumentLoadListener completes handling a load, and it 437 // is either complete, or handed off to the final channel to deliver 438 // data to the destination docshell. 439 void EndDocumentLoad(bool aForProcessSwitch); 440 441 bool SupportsLoadingInParent(nsDocShellLoadState* aLoadState, 442 uint64_t* aOuterWindowId); 443 444 void HistoryCommitIndexAndLength( 445 const nsID& aChangeID, 446 const CallerWillNotifyHistoryIndexAndLengthChanges& aProofOfCaller); 447 448 struct UnloadingHost { 449 uint64_t mChildID; 450 nsTArray<std::function<void()>> mCallbacks; 451 }; 452 nsTArray<UnloadingHost>::iterator FindUnloadingHost(uint64_t aChildID); 453 454 // Called when we want to show the subframe crashed UI as our previous browser 455 // has become unloaded for one reason or another. 456 void ShowSubframeCrashedUI(BrowserBridgeParent* aBridge); 457 458 void MaybeScheduleSessionStoreUpdate(); 459 460 void CancelSessionStoreUpdate(); 461 462 void AddPendingDiscard(); 463 464 void RemovePendingDiscard(); 465 ShouldAddEntryForRefresh(const SessionHistoryEntry * aEntry)466 bool ShouldAddEntryForRefresh(const SessionHistoryEntry* aEntry) { 467 return ShouldAddEntryForRefresh(aEntry->Info().GetURI(), 468 aEntry->Info().GetPostData()); 469 } ShouldAddEntryForRefresh(nsIURI * aNewURI,bool aHasPostData)470 bool ShouldAddEntryForRefresh(nsIURI* aNewURI, bool aHasPostData) { 471 nsCOMPtr<nsIURI> currentURI = GetCurrentURI(); 472 return BrowsingContext::ShouldAddEntryForRefresh(currentURI, aNewURI, 473 aHasPostData); 474 } 475 476 // XXX(farre): Store a ContentParent pointer here rather than mProcessId? 477 // Indicates which process owns the docshell. 478 uint64_t mProcessId; 479 480 // Indicates which process owns the embedder element. 481 uint64_t mEmbedderProcessId; 482 483 uint64_t mCrossGroupOpenerId = 0; 484 485 // This function will make the top window context reset its 486 // "SHEntryHasUserInteraction" cache that prevents documents from repeatedly 487 // setting user interaction on SH entries. Should be called anytime SH 488 // entries are added or replaced. 489 void ResetSHEntryHasUserInteractionCache(); 490 491 RefPtr<BrowserParent> mCurrentBrowserParent; 492 493 nsTArray<UnloadingHost> mUnloadingHosts; 494 495 // The current URI loaded in this BrowsingContext. This value is only set for 496 // BrowsingContexts loaded in content processes. 497 nsCOMPtr<nsIURI> mCurrentRemoteURI; 498 499 // The current remoteness change which is in a pending state. 500 RefPtr<PendingRemotenessChange> mPendingRemotenessChange; 501 502 RefPtr<nsSHistory> mSessionHistory; 503 504 // Tab media controller is used to control all media existing in the same 505 // browsing context tree, so it would only exist in the top level browsing 506 // context. 507 RefPtr<MediaController> mTabMediaController; 508 509 RefPtr<net::DocumentLoadListener> mCurrentLoad; 510 511 struct LoadingSessionHistoryEntry { 512 uint64_t mLoadId = 0; 513 RefPtr<SessionHistoryEntry> mEntry; 514 }; 515 nsTArray<LoadingSessionHistoryEntry> mLoadingEntries; 516 RefPtr<SessionHistoryEntry> mActiveEntry; 517 518 RefPtr<nsSecureBrowserUI> mSecureBrowserUI; 519 RefPtr<BrowsingContextWebProgress> mWebProgress; 520 521 nsCOMPtr<nsIWebProgressListener> mDocShellProgressBridge; 522 RefPtr<nsBrowserStatusFilter> mStatusFilter; 523 524 RefPtr<FeaturePolicy> mContainerFeaturePolicy; 525 526 RefPtr<RestoreState> mRestoreState; 527 528 // If this is a top level context, this is true if our browser ID is marked as 529 // active in the process priority manager. 530 bool mPriorityActive = false; 531 532 nsCOMPtr<nsITimer> mSessionStoreSessionStorageUpdateTimer; 533 534 bool mIsReplaced = false; 535 536 // A Promise created when cloning documents for printing. 537 RefPtr<GenericNonExclusivePromise> mClonePromise; 538 539 JS::Heap<JS::Value> mPermanentKey; 540 541 uint32_t mPendingDiscards = 0; 542 543 bool mFullyDiscarded = false; 544 545 nsTArray<std::function<void(uint64_t)>> mFullyDiscardedListeners; 546 }; 547 548 } // namespace dom 549 } // namespace mozilla 550 551 #endif // !defined(mozilla_dom_CanonicalBrowsingContext_h) 552