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