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_WindowContext_h
8 #define mozilla_dom_WindowContext_h
9 
10 #include "mozilla/PermissionDelegateHandler.h"
11 #include "mozilla/WeakPtr.h"
12 #include "mozilla/Span.h"
13 #include "mozilla/dom/MaybeDiscarded.h"
14 #include "mozilla/dom/SyncedContext.h"
15 #include "mozilla/dom/UserActivation.h"
16 #include "nsILoadInfo.h"
17 #include "nsWrapperCache.h"
18 
19 class nsIGlobalObject;
20 
21 class nsGlobalWindowInner;
22 
23 namespace mozilla {
24 class LogModule;
25 
26 namespace dom {
27 
28 class WindowGlobalChild;
29 class WindowGlobalParent;
30 class WindowGlobalInit;
31 class BrowsingContext;
32 class BrowsingContextGroup;
33 
34 #define MOZ_EACH_WC_FIELD(FIELD)                                         \
35   /* Whether the SHEntry associated with the current top-level           \
36    * window has already seen user interaction.                           \
37    * As such, this will be reset to false when a new SHEntry is          \
38    * created without changing the WC (e.g. when using pushState or       \
39    * sub-frame navigation)                                               \
40    * This flag is set for optimization purposes, to avoid                \
41    * having to get the top SHEntry and update it on every                \
42    * user interaction.                                                   \
43    * This is only meaningful on the top-level WC. */                     \
44   FIELD(SHEntryHasUserInteraction, bool)                                 \
45   FIELD(CookieBehavior, Maybe<uint32_t>)                                 \
46   FIELD(IsOnContentBlockingAllowList, bool)                              \
47   /* Whether the given window hierarchy is third party. See              \
48    * ThirdPartyUtil::IsThirdPartyWindow for details */                   \
49   FIELD(IsThirdPartyWindow, bool)                                        \
50   /* Whether this window's channel has been marked as a third-party      \
51    * tracking resource */                                                \
52   FIELD(IsThirdPartyTrackingResourceWindow, bool)                        \
53   FIELD(IsSecureContext, bool)                                           \
54   FIELD(IsOriginalFrameSource, bool)                                     \
55   /* Mixed-Content: If the corresponding documentURI is https,           \
56    * then this flag is true. */                                          \
57   FIELD(IsSecure, bool)                                                  \
58   /* Whether the user has overriden the mixed content blocker to allow   \
59    * mixed content loads to happen */                                    \
60   FIELD(AllowMixedContent, bool)                                         \
61   /* Whether this window has registered a "beforeunload" event           \
62    * handler */                                                          \
63   FIELD(HasBeforeUnload, bool)                                           \
64   /* Controls whether the WindowContext is currently considered to be    \
65    * activated by a gesture */                                           \
66   FIELD(UserActivationState, UserActivation::State)                      \
67   FIELD(EmbedderPolicy, nsILoadInfo::CrossOriginEmbedderPolicy)          \
68   /* True if this document tree contained at least a HTMLMediaElement.   \
69    * This should only be set on top level context. */                    \
70   FIELD(DocTreeHadMedia, bool)                                           \
71   FIELD(AutoplayPermission, uint32_t)                                    \
72   FIELD(ShortcutsPermission, uint32_t)                                   \
73   /* Store the Id of the browsing context where active media session     \
74    * exists on the top level window context */                           \
75   FIELD(ActiveMediaSessionContextId, Maybe<uint64_t>)                    \
76   /* ALLOW_ACTION if it is allowed to open popups for the sub-tree       \
77    * starting and including the current WindowContext */                 \
78   FIELD(PopupPermission, uint32_t)                                       \
79   FIELD(DelegatedPermissions,                                            \
80         PermissionDelegateHandler::DelegatedPermissionList)              \
81   FIELD(DelegatedExactHostMatchPermissions,                              \
82         PermissionDelegateHandler::DelegatedPermissionList)              \
83   FIELD(HasReportedShadowDOMUsage, bool)                                 \
84   /* Whether the principal of this window is for a local                 \
85    * IP address */                                                       \
86   FIELD(IsLocalIP, bool)                                                 \
87   /* Whether the corresponding document has `loading='lazy'`             \
88    * images; It won't become false if the image becomes non-lazy */      \
89   FIELD(HadLazyLoadImage, bool)                                          \
90   /* Whether we can execute scripts in this WindowContext. Has no effect \
91    * unless scripts are also allowed in the BrowsingContext. */          \
92   FIELD(AllowJavascript, bool)                                           \
93   /* If this field is `true`, it means that this WindowContext's         \
94    * WindowState was saved to be stored in the legacy (non-SHIP) BFCache \
95    * implementation. Always false for SHIP */                            \
96   FIELD(WindowStateSaved, bool)
97 
98 class WindowContext : public nsISupports, public nsWrapperCache {
99   MOZ_DECL_SYNCED_CONTEXT(WindowContext, MOZ_EACH_WC_FIELD)
100 
101   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
102   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WindowContext)
103 
104  public:
105   static already_AddRefed<WindowContext> GetById(uint64_t aInnerWindowId);
106   static LogModule* GetLog();
107   static LogModule* GetSyncLog();
108 
GetBrowsingContext()109   BrowsingContext* GetBrowsingContext() const { return mBrowsingContext; }
110   BrowsingContextGroup* Group() const;
Id()111   uint64_t Id() const { return InnerWindowId(); }
InnerWindowId()112   uint64_t InnerWindowId() const { return mInnerWindowId; }
OuterWindowId()113   uint64_t OuterWindowId() const { return mOuterWindowId; }
IsDiscarded()114   bool IsDiscarded() const { return mIsDiscarded; }
115 
116   bool IsCached() const;
117 
118   // Returns `true` if this WindowContext is currently in the BFCache.
119   bool IsInBFCache();
120 
IsInProcess()121   bool IsInProcess() const { return mIsInProcess; }
122 
HasBeforeUnload()123   bool HasBeforeUnload() const { return GetHasBeforeUnload(); }
124 
IsLocalIP()125   bool IsLocalIP() const { return GetIsLocalIP(); }
126 
127   nsGlobalWindowInner* GetInnerWindow() const;
128   Document* GetDocument() const;
129   Document* GetExtantDoc() const;
130 
131   WindowGlobalChild* GetWindowGlobalChild() const;
132 
133   // Get the parent WindowContext of this WindowContext, taking the BFCache into
134   // account. This will not cross chrome/content <browser> boundaries.
135   WindowContext* GetParentWindowContext();
136   WindowContext* TopWindowContext();
137 
138   bool SameOriginWithTop() const;
139 
140   bool IsTop() const;
141 
Children()142   Span<RefPtr<BrowsingContext>> Children() { return mChildren; }
143 
144   // Cast this object to it's parent-process canonical form.
145   WindowGlobalParent* Canonical();
146 
147   nsIGlobalObject* GetParentObject() const;
148   JSObject* WrapObject(JSContext* cx,
149                        JS::Handle<JSObject*> aGivenProto) override;
150 
151   void Discard();
152 
153   struct IPCInitializer {
154     uint64_t mInnerWindowId;
155     uint64_t mOuterWindowId;
156     uint64_t mBrowsingContextId;
157 
158     FieldValues mFields;
159   };
160   IPCInitializer GetIPCInitializer();
161 
162   static void CreateFromIPC(IPCInitializer&& aInit);
163 
164   // Add new security state flags.
165   // These should be some of the nsIWebProgressListener 'HTTPS_ONLY_MODE' or
166   // 'MIXED' state flags, and should only be called on the top window context.
167   void AddSecurityState(uint32_t aStateFlags);
168 
169   // This function would be called when its corresponding window is activated
170   // by user gesture.
171   void NotifyUserGestureActivation();
172 
173   // This function would be called when we want to reset the user gesture
174   // activation flag.
175   void NotifyResetUserGestureActivation();
176 
177   // Return true if its corresponding window has been activated by user
178   // gesture.
179   bool HasBeenUserGestureActivated();
180 
181   // Return true if its corresponding window has transient user gesture
182   // activation and the transient user gesture activation haven't yet timed
183   // out.
184   bool HasValidTransientUserGestureActivation();
185 
186   // Return true if the corresponding window has valid transient user gesture
187   // activation and the transient user gesture activation had been consumed
188   // successfully.
189   bool ConsumeTransientUserGestureActivation();
190 
191   bool CanShowPopup();
192 
HadLazyLoadImage()193   bool HadLazyLoadImage() const { return GetHadLazyLoadImage(); }
194 
AllowJavascript()195   bool AllowJavascript() const { return GetAllowJavascript(); }
CanExecuteScripts()196   bool CanExecuteScripts() const { return mCanExecuteScripts; }
197 
198  protected:
199   WindowContext(BrowsingContext* aBrowsingContext, uint64_t aInnerWindowId,
200                 uint64_t aOuterWindowId, FieldValues&& aFields);
201   virtual ~WindowContext();
202 
203   virtual void Init();
204 
205  private:
206   friend class BrowsingContext;
207   friend class WindowGlobalChild;
208   friend class WindowGlobalActor;
209 
210   void AppendChildBrowsingContext(BrowsingContext* aBrowsingContext);
211   void RemoveChildBrowsingContext(BrowsingContext* aBrowsingContext);
212 
213   // Send a given `BaseTransaction` object to the correct remote.
214   void SendCommitTransaction(ContentParent* aParent,
215                              const BaseTransaction& aTxn, uint64_t aEpoch);
216   void SendCommitTransaction(ContentChild* aChild, const BaseTransaction& aTxn,
217                              uint64_t aEpoch);
218 
219   bool CheckOnlyOwningProcessCanSet(ContentParent* aSource);
220 
221   // Overload `CanSet` to get notifications for a particular field being set.
222   bool CanSet(FieldIndex<IDX_IsSecure>, const bool& aIsSecure,
223               ContentParent* aSource);
224   bool CanSet(FieldIndex<IDX_AllowMixedContent>, const bool& aAllowMixedContent,
225               ContentParent* aSource);
226 
227   bool CanSet(FieldIndex<IDX_HasBeforeUnload>, const bool& aHasBeforeUnload,
228               ContentParent* aSource);
229 
230   bool CanSet(FieldIndex<IDX_CookieBehavior>, const Maybe<uint32_t>& aValue,
231               ContentParent* aSource);
232 
233   bool CanSet(FieldIndex<IDX_IsOnContentBlockingAllowList>, const bool& aValue,
234               ContentParent* aSource);
235 
CanSet(FieldIndex<IDX_EmbedderPolicy>,const bool & aValue,ContentParent * aSource)236   bool CanSet(FieldIndex<IDX_EmbedderPolicy>, const bool& aValue,
237               ContentParent* aSource) {
238     return true;
239   }
240 
241   bool CanSet(FieldIndex<IDX_IsThirdPartyWindow>,
242               const bool& IsThirdPartyWindow, ContentParent* aSource);
243   bool CanSet(FieldIndex<IDX_IsThirdPartyTrackingResourceWindow>,
244               const bool& aIsThirdPartyTrackingResourceWindow,
245               ContentParent* aSource);
246   bool CanSet(FieldIndex<IDX_IsSecureContext>, const bool& aIsSecureContext,
247               ContentParent* aSource);
248   bool CanSet(FieldIndex<IDX_IsOriginalFrameSource>,
249               const bool& aIsOriginalFrameSource, ContentParent* aSource);
250   bool CanSet(FieldIndex<IDX_DocTreeHadMedia>, const bool& aValue,
251               ContentParent* aSource);
252   bool CanSet(FieldIndex<IDX_AutoplayPermission>, const uint32_t& aValue,
253               ContentParent* aSource);
254   bool CanSet(FieldIndex<IDX_ShortcutsPermission>, const uint32_t& aValue,
255               ContentParent* aSource);
256   bool CanSet(FieldIndex<IDX_ActiveMediaSessionContextId>,
257               const Maybe<uint64_t>& aValue, ContentParent* aSource);
258   bool CanSet(FieldIndex<IDX_PopupPermission>, const uint32_t&,
259               ContentParent* aSource);
CanSet(FieldIndex<IDX_SHEntryHasUserInteraction>,const bool & aSHEntryHasUserInteraction,ContentParent * aSource)260   bool CanSet(FieldIndex<IDX_SHEntryHasUserInteraction>,
261               const bool& aSHEntryHasUserInteraction, ContentParent* aSource) {
262     return true;
263   }
264   bool CanSet(FieldIndex<IDX_DelegatedPermissions>,
265               const PermissionDelegateHandler::DelegatedPermissionList& aValue,
266               ContentParent* aSource);
267   bool CanSet(FieldIndex<IDX_DelegatedExactHostMatchPermissions>,
268               const PermissionDelegateHandler::DelegatedPermissionList& aValue,
269               ContentParent* aSource);
CanSet(FieldIndex<IDX_UserActivationState>,const UserActivation::State & aUserActivationState,ContentParent * aSource)270   bool CanSet(FieldIndex<IDX_UserActivationState>,
271               const UserActivation::State& aUserActivationState,
272               ContentParent* aSource) {
273     return true;
274   }
275 
CanSet(FieldIndex<IDX_HasReportedShadowDOMUsage>,const bool & aValue,ContentParent * aSource)276   bool CanSet(FieldIndex<IDX_HasReportedShadowDOMUsage>, const bool& aValue,
277               ContentParent* aSource) {
278     return true;
279   }
280 
281   bool CanSet(FieldIndex<IDX_IsLocalIP>, const bool& aValue,
282               ContentParent* aSource);
283 
284   bool CanSet(FieldIndex<IDX_HadLazyLoadImage>, const bool& aValue,
285               ContentParent* aSource);
286 
287   bool CanSet(FieldIndex<IDX_AllowJavascript>, bool aValue,
288               ContentParent* aSource);
289   void DidSet(FieldIndex<IDX_AllowJavascript>, bool aOldValue);
290 
291   void DidSet(FieldIndex<IDX_HasReportedShadowDOMUsage>, bool aOldValue);
292 
293   void DidSet(FieldIndex<IDX_SHEntryHasUserInteraction>, bool aOldValue);
294 
295   bool CanSet(FieldIndex<IDX_WindowStateSaved>, bool aValue,
296               ContentParent* aSource);
297 
298   // Overload `DidSet` to get notifications for a particular field being set.
299   //
300   // You can also overload the variant that gets the old value if you need it.
301   template <size_t I>
DidSet(FieldIndex<I>)302   void DidSet(FieldIndex<I>) {}
303   template <size_t I, typename T>
DidSet(FieldIndex<I>,T && aOldValue)304   void DidSet(FieldIndex<I>, T&& aOldValue) {}
305   void DidSet(FieldIndex<IDX_UserActivationState>);
306 
307   // Recomputes whether we can execute scripts in this WindowContext based on
308   // the value of AllowJavascript() and whether scripts are allowed in the
309   // BrowsingContext.
310   void RecomputeCanExecuteScripts(bool aApplyChanges = true);
311 
312   const uint64_t mInnerWindowId;
313   const uint64_t mOuterWindowId;
314   RefPtr<BrowsingContext> mBrowsingContext;
315   WeakPtr<WindowGlobalChild> mWindowGlobalChild;
316 
317   // --- NEVER CHANGE `mChildren` DIRECTLY! ---
318   // Changes to this list need to be synchronized to the list within our
319   // `mBrowsingContext`, and should only be performed through the
320   // `AppendChildBrowsingContext` and `RemoveChildBrowsingContext` methods.
321   nsTArray<RefPtr<BrowsingContext>> mChildren;
322 
323   bool mIsDiscarded = false;
324   bool mIsInProcess = false;
325 
326   // Determines if we can execute scripts in this WindowContext. True if
327   // AllowJavascript() is true and script execution is allowed in the
328   // BrowsingContext.
329   bool mCanExecuteScripts = true;
330 
331   // The start time of user gesture, this is only available if the window
332   // context is in process.
333   TimeStamp mUserGestureStart;
334 };
335 
336 using WindowContextTransaction = WindowContext::BaseTransaction;
337 using WindowContextInitializer = WindowContext::IPCInitializer;
338 using MaybeDiscardedWindowContext = MaybeDiscarded<WindowContext>;
339 
340 // Don't specialize the `Transaction` object for every translation unit it's
341 // used in. This should help keep code size down.
342 extern template class syncedcontext::Transaction<WindowContext>;
343 
344 }  // namespace dom
345 
346 namespace ipc {
347 template <>
348 struct IPDLParamTraits<dom::MaybeDiscarded<dom::WindowContext>> {
349   static void Write(IPC::Message* aMsg, IProtocol* aActor,
350                     const dom::MaybeDiscarded<dom::WindowContext>& aParam);
351   static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
352                    IProtocol* aActor,
353                    dom::MaybeDiscarded<dom::WindowContext>* aResult);
354 };
355 
356 template <>
357 struct IPDLParamTraits<dom::WindowContext::IPCInitializer> {
358   static void Write(IPC::Message* aMessage, IProtocol* aActor,
359                     const dom::WindowContext::IPCInitializer& aInitializer);
360 
361   static bool Read(const IPC::Message* aMessage, PickleIterator* aIterator,
362                    IProtocol* aActor,
363                    dom::WindowContext::IPCInitializer* aInitializer);
364 };
365 }  // namespace ipc
366 }  // namespace mozilla
367 
368 #endif  // !defined(mozilla_dom_WindowContext_h)
369