1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_BrowsingContextGroup_h
#define mozilla_dom_BrowsingContextGroup_h
#include "mozilla/PrincipalHashKey.h"
#include "mozilla/dom/BrowsingContext.h"
#include "nsRefPtrHashtable.h"
#include "nsHashKeys.h"
#include "nsTArray.h"
#include "nsTHashSet.h"
#include "nsWrapperCache.h"
#include "nsXULAppAPI.h"
namespace mozilla {
class ThrottledEventQueue;
namespace dom {
// Amount of time allowed between alert/prompt/confirm before enabling
// the stop dialog checkbox.
#define DEFAULT_SUCCESSIVE_DIALOG_TIME_LIMIT 3 // 3 sec
class BrowsingContext;
class WindowContext;
class ContentParent;
class DocGroup;
struct DocGroupKey {
nsCString mKey;
bool mOriginKeyed = false;
bool operator==(const DocGroupKey& aOther) const {
return mKey == aOther.mKey && mOriginKeyed == aOther.mOriginKeyed;
};
PLDHashNumber Hash() const {
return mozilla::HashGeneric(mozilla::HashString(mKey), mOriginKeyed);
}
};
// A BrowsingContextGroup represents the Unit of Related Browsing Contexts in
// the standard.
//
// A BrowsingContext may not hold references to other BrowsingContext objects
// which are not in the same BrowsingContextGroup.
class BrowsingContextGroup final : public nsWrapperCache {
public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(BrowsingContextGroup)
NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(BrowsingContextGroup)
// Interact with the list of synced contexts. This controls the lifecycle of
// the BrowsingContextGroup and contexts loaded within them.
void Register(nsISupports* aContext);
void Unregister(nsISupports* aContext);
// Control which processes will be used to host documents loaded in this
// BrowsingContextGroup. There should only ever be one host process per remote
// type.
//
// A new host process will be subscribed to the BrowsingContextGroup unless it
// is still launching, in which case it will subscribe itself when it is done
// launching.
void EnsureHostProcess(ContentParent* aProcess);
// A removed host process will no longer be used to host documents loaded in
// this BrowsingContextGroup.
void RemoveHostProcess(ContentParent* aProcess);
// Synchronize the current BrowsingContextGroup state down to the given
// content process, and continue updating it.
//
// You rarely need to call this directly, as it's automatically called by
// |EnsureHostProcess| as needed.
void Subscribe(ContentParent* aProcess);
// Stop synchronizing the current BrowsingContextGroup state down to a given
// content process. The content process must no longer be a host process.
void Unsubscribe(ContentParent* aProcess);
// Look up the process which should be used to host documents with this
// RemoteType. This will be a non-dead process associated with this
// BrowsingContextGroup, if possible.
ContentParent* GetHostProcess(const nsACString& aRemoteType);
// When a BrowsingContext is being discarded, we may want to keep the
// corresponding BrowsingContextGroup alive until the other process
// acknowledges that the BrowsingContext has been discarded. A `KeepAlive`
// will be added to the `BrowsingContextGroup`, delaying destruction.
void AddKeepAlive();
void RemoveKeepAlive();
// A `KeepAlivePtr` will hold both a strong reference to the
// `BrowsingContextGroup` and holds a `KeepAlive`. When the pointer is
// dropped, it will release both the strong reference and the keepalive.
struct KeepAliveDeleter {
void operator()(BrowsingContextGroup* aPtr) {
if (RefPtr<BrowsingContextGroup> ptr = already_AddRefed(aPtr)) {
ptr->RemoveKeepAlive();
}
}
};
using KeepAlivePtr = UniquePtr<BrowsingContextGroup, KeepAliveDeleter>;
KeepAlivePtr MakeKeepAlivePtr();
// Call when we want to check if we should suspend or resume all top level
// contexts.
void UpdateToplevelsSuspendedIfNeeded();
// Get a reference to the list of toplevel contexts in this
// BrowsingContextGroup.
nsTArray<RefPtr<BrowsingContext>>& Toplevels() { return mToplevels; }
void GetToplevels(nsTArray<RefPtr<BrowsingContext>>& aToplevels) {
aToplevels.AppendElements(mToplevels);
}
uint64_t Id() { return mId; }
nsISupports* GetParentObject() const;
JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
// Get or create a BrowsingContextGroup with the given ID.
static already_AddRefed<BrowsingContextGroup> GetOrCreate(uint64_t aId);
static already_AddRefed<BrowsingContextGroup> GetExisting(uint64_t aId);
static already_AddRefed<BrowsingContextGroup> Create(
bool aPotentiallyCrossOriginIsolated = false);
static already_AddRefed<BrowsingContextGroup> Select(
WindowContext* aParent, BrowsingContext* aOpener);
// Like `Create` but only generates and reserves a new ID without actually
// creating the BrowsingContextGroup object.
static uint64_t CreateId(bool aPotentiallyCrossOriginIsolated = false);
// For each 'ContentParent', except for 'aExcludedParent',
// associated with this group call 'aCallback'.
template <typename Func>
void EachOtherParent(ContentParent* aExcludedParent, Func&& aCallback) {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
for (const auto& key : mSubscribers) {
if (key != aExcludedParent) {
aCallback(key);
}
}
}
// For each 'ContentParent' associated with
// this group call 'aCallback'.
template <typename Func>
void EachParent(Func&& aCallback) {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
for (const auto& key : mSubscribers) {
aCallback(key);
}
}
nsresult QueuePostMessageEvent(nsIRunnable* aRunnable);
void FlushPostMessageEvents();
// Increase or decrease the suspension level in InputTaskManager
void UpdateInputTaskManagerIfNeeded(bool aIsActive);
static BrowsingContextGroup* GetChromeGroup();
void GetDocGroups(nsTArray<DocGroup*>& aDocGroups);
// Called by Document when a Document needs to be added to a DocGroup.
already_AddRefed<DocGroup> AddDocument(Document* aDocument);
// Called by Document when a Document needs to be removed from a DocGroup.
// aDocGroup should be from aDocument. This is done to avoid the assert
// in GetDocGroup() which can crash when called during unlinking.
void RemoveDocument(Document* aDocument, DocGroup* aDocGroup);
mozilla::ThrottledEventQueue* GetTimerEventQueue() const {
return mTimerEventQueue;
}
mozilla::ThrottledEventQueue* GetWorkerEventQueue() const {
return mWorkerEventQueue;
}
void SetAreDialogsEnabled(bool aAreDialogsEnabled) {
mAreDialogsEnabled = aAreDialogsEnabled;
}
bool GetAreDialogsEnabled() { return mAreDialogsEnabled; }
bool GetDialogAbuseCount() { return mDialogAbuseCount; }
// For tests only.
void ResetDialogAbuseState();
bool DialogsAreBeingAbused();
TimeStamp GetLastDialogQuitTime() { return mLastDialogQuitTime; }
void SetLastDialogQuitTime(TimeStamp aLastDialogQuitTime) {
mLastDialogQuitTime = aLastDialogQuitTime;
}
// Whether all toplevel documents loaded in this group are allowed to be
// Cross-Origin Isolated.
//
// This does not reflect the actual value of `crossOriginIsolated`, as that
// also requires that the document is loaded within a `webCOOP+COEP` content
// process.
bool IsPotentiallyCrossOriginIsolated();
void NotifyFocusedOrActiveBrowsingContextToProcess(ContentParent* aProcess);
static void GetAllGroups(nsTArray<RefPtr<BrowsingContextGroup>>& aGroups);
void IncInputEventSuspensionLevel();
void DecInputEventSuspensionLevel();
// As documents are loaded, whether or not each origin is origin-keyed is
// recorded within the BrowsingContextGroup. This in turn controls whether
// document.domain can be used, as well as the options available to us for
// process isolation.
// The relevant subset of this mapping is mirrored to content processes, to be
// used when determining DocGroup keying.
void SetUseOriginAgentClusterFromNetwork(nsIPrincipal* aPrincipal,
bool aUseOriginAgentCluster);
void SetUseOriginAgentClusterFromIPC(nsIPrincipal* aPrincipal,
bool aUseOriginAgentCluster);
Maybe<bool> UsesOriginAgentCluster(nsIPrincipal* aPrincipal);
// Ensures that the given principal will return `Some(...)` from
// `UsesOriginAgentCluster` going forward, setting it to a default value if no
// value is set.
// As the map can only be modified in the parent process, this method will
// crash if there is no CrossOriginIsolatedStatus for the principal when
// called in a content process.
void EnsureUsesOriginAgentClusterInitialized(nsIPrincipal* aPrincipal);
void ChildDestroy();
private:
friend class CanonicalBrowsingContext;
explicit BrowsingContextGroup(uint64_t aId);
~BrowsingContextGroup();
void MaybeDestroy();
void Destroy();
bool ShouldSuspendAllTopLevelContexts() const;
bool HasActiveBC();
void DecInputTaskManagerSuspensionLevel();
void IncInputTaskManagerSuspensionLevel();
uint64_t mId;
uint32_t mKeepAliveCount = 0;
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
bool mDestroyed = false;
#endif
// A BrowsingContextGroup contains a series of {Browsing,Window}Context
// objects. They are addressed using a hashtable to avoid linear lookup when
// adding or removing elements from the set.
//
// FIXME: This list is only required over a counter to keep nested
// non-discarded contexts within discarded contexts alive. It should be
// removed in the future.
// FIXME: Consider introducing a better common base than `nsISupports`?
nsTHashSet<nsRefPtrHashKey<nsISupports>> mContexts;
// The set of toplevel browsing contexts in the current BrowsingContextGroup.
nsTArray<RefPtr<BrowsingContext>> mToplevels;
// Whether or not all toplevels in this group should be suspended
bool mToplevelsSuspended = false;
// DocGroups are thread-safe, and not able to be cycle collected,
// but we still keep strong pointers. When all Documents are removed
// from DocGroup (by the BrowsingContextGroup), the DocGroup is
// removed from here.
nsRefPtrHashtable<nsGenericHashKey<DocGroupKey>, DocGroup> mDocGroups;
// The content process which will host documents in this BrowsingContextGroup
// which need to be loaded with a given remote type.
//
// A non-launching host process must also be a subscriber, though a launching
// host process may not yet be subscribed, and a subscriber need not be a host
// process.
nsRefPtrHashtable<nsCStringHashKey, ContentParent> mHosts;
// Whether or not a given http(s) origin uses origin or siteOrigin-keyed
// DocGroups/AgentClusters. Only contains entries for http(s) origins.
//
// https://html.spec.whatwg.org/#historical-agent-cluster-key-map
nsTHashMap<PrincipalHashKey, bool> mUseOriginAgentCluster;
nsTHashSet<nsRefPtrHashKey<ContentParent>> mSubscribers;
// A queue to store postMessage events during page load, the queue will be
// flushed once the page is loaded
RefPtr<mozilla::ThrottledEventQueue> mPostMessageEventQueue;
RefPtr<mozilla::ThrottledEventQueue> mTimerEventQueue;
RefPtr<mozilla::ThrottledEventQueue> mWorkerEventQueue;
// A counter to keep track of the input event suspension level of this BCG
//
// We use BrowsingContextGroup to emulate process isolation in Fission, so
// documents within the same the same BCG will behave like they share
// the same input task queue.
uint32_t mInputEventSuspensionLevel = 0;
// Whether this BCG has increased the suspension level in InputTaskManager
bool mHasIncreasedInputTaskManagerSuspensionLevel = false;
// This flag keeps track of whether dialogs are
// currently enabled for windows of this group.
// It's OK to have these local to each process only because even if
// frames from two/three different sites (and thus, processes) coordinate a
// dialog abuse attack, they would only the double/triple number of dialogs,
// as it is still limited per-site.
bool mAreDialogsEnabled = true;
// This counts the number of windows that have been opened in rapid succession
// (i.e. within dom.successive_dialog_time_limit of each other). It is reset
// to 0 once a dialog is opened after dom.successive_dialog_time_limit seconds
// have elapsed without any other dialogs.
// See comment for mAreDialogsEnabled as to why it's ok to have this local to
// each process.
uint32_t mDialogAbuseCount = 0;
// This holds the time when the last modal dialog was shown. If more than
// MAX_DIALOG_LIMIT dialogs are shown within the time span defined by
// dom.successive_dialog_time_limit, we show a checkbox or confirmation prompt
// to allow disabling of further dialogs from windows in this BC group.
TimeStamp mLastDialogQuitTime;
};
} // namespace dom
} // namespace mozilla
inline void ImplCycleCollectionUnlink(
mozilla::dom::BrowsingContextGroup::KeepAlivePtr& aField) {
aField = nullptr;
}
inline void ImplCycleCollectionTraverse(
nsCycleCollectionTraversalCallback& aCallback,
mozilla::dom::BrowsingContextGroup::KeepAlivePtr& aField, const char* aName,
uint32_t aFlags = 0) {
CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags);
}
#endif // !defined(mozilla_dom_BrowsingContextGroup_h)
|