tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

WindowGlobalParent.cpp (63291B)


      1 /* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
      2 /* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
      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 #include "mozilla/dom/WindowGlobalParent.h"
      8 
      9 #include <algorithm>
     10 
     11 #include "MMPrinter.h"
     12 #include "mozilla/AntiTrackingUtils.h"
     13 #include "mozilla/AsyncEventDispatcher.h"
     14 #include "mozilla/BounceTrackingProtection.h"
     15 #include "mozilla/BounceTrackingStorageObserver.h"
     16 #include "mozilla/ClearOnShutdown.h"
     17 #include "mozilla/Components.h"
     18 #include "mozilla/ContentBlockingAllowList.h"
     19 #include "mozilla/IdentityCredentialRequestManager.h"
     20 #include "mozilla/ScopeExit.h"
     21 #include "mozilla/ServoCSSParser.h"
     22 #include "mozilla/ServoStyleSet.h"
     23 #include "mozilla/StaticPrefs_dom.h"
     24 #include "mozilla/StaticPrefs_network.h"
     25 #include "mozilla/dom/BrowserBridgeParent.h"
     26 #include "mozilla/dom/BrowserHost.h"
     27 #include "mozilla/dom/BrowserParent.h"
     28 #include "mozilla/dom/BrowsingContextGroup.h"
     29 #include "mozilla/dom/CanonicalBrowsingContext.h"
     30 #include "mozilla/dom/ChromeUtils.h"
     31 #include "mozilla/dom/ClientIPCTypes.h"
     32 #include "mozilla/dom/ClientInfo.h"
     33 #include "mozilla/dom/ContentChild.h"
     34 #include "mozilla/dom/ContentParent.h"
     35 #include "mozilla/dom/DOMException.h"
     36 #include "mozilla/dom/DOMExceptionBinding.h"
     37 #include "mozilla/dom/IdentityCredential.h"
     38 #include "mozilla/dom/InProcessParent.h"
     39 #include "mozilla/dom/JSActorService.h"
     40 #include "mozilla/dom/JSWindowActorBinding.h"
     41 #include "mozilla/dom/JSWindowActorParent.h"
     42 #include "mozilla/dom/MediaController.h"
     43 #include "mozilla/dom/Navigation.h"
     44 #include "mozilla/dom/NavigatorLogin.h"
     45 #include "mozilla/dom/PBackgroundSessionStorageCache.h"
     46 #include "mozilla/dom/UseCounterMetrics.h"
     47 #include "mozilla/dom/WebAuthnTransactionParent.h"
     48 #include "mozilla/dom/WebIdentityParent.h"
     49 #include "mozilla/dom/WindowGlobalChild.h"
     50 #include "mozilla/dom/ipc/IdType.h"
     51 #include "mozilla/dom/ipc/StructuredCloneData.h"
     52 #include "mozilla/glean/CaptchadetectionMetrics.h"
     53 #include "mozilla/glean/DomMediaMetrics.h"
     54 #include "mozilla/glean/DomSecurityMetrics.h"
     55 #include "mozilla/glean/DomUseCounterMetrics.h"
     56 #include "mozilla/glean/GeckoviewMetrics.h"
     57 #include "mozilla/glean/NetwerkProtocolHttpMetrics.h"
     58 #include "mozilla/ipc/ProtocolUtils.h"
     59 #include "mozilla/net/CookieServiceParent.h"
     60 #include "mozilla/net/NeckoParent.h"
     61 #include "mozilla/net/PCookieServiceParent.h"
     62 #include "nsContentUtils.h"
     63 #include "nsDocShell.h"
     64 #include "nsDocShellLoadState.h"
     65 #include "nsError.h"
     66 #include "nsFrameLoader.h"
     67 #include "nsFrameLoaderOwner.h"
     68 #include "nsIBrowser.h"
     69 #include "nsICookieManager.h"
     70 #include "nsICookieService.h"
     71 #include "nsIEffectiveTLDService.h"
     72 #include "nsIHttpsOnlyModePermission.h"
     73 #include "nsIOService.h"
     74 #include "nsIPromptCollection.h"
     75 #include "nsISessionStoreFunctions.h"
     76 #include "nsISharePicker.h"
     77 #include "nsITimer.h"
     78 #include "nsITransportSecurityInfo.h"
     79 #include "nsIURIMutator.h"
     80 #include "nsIWebProgressListener.h"
     81 #include "nsIXPConnect.h"
     82 #include "nsIXULRuntime.h"
     83 #include "nsImportModule.h"
     84 #include "nsNetUtil.h"
     85 #include "nsQueryObject.h"
     86 #include "nsSandboxFlags.h"
     87 #include "nsScriptSecurityManager.h"
     88 #include "nsSerializationHelper.h"
     89 
     90 using namespace mozilla::ipc;
     91 using namespace mozilla::dom::ipc;
     92 
     93 extern mozilla::LazyLogModule gSHIPBFCacheLog;
     94 extern mozilla::LazyLogModule gUseCountersLog;
     95 
     96 namespace mozilla::dom {
     97 
     98 WindowGlobalParent::WindowGlobalParent(
     99    CanonicalBrowsingContext* aBrowsingContext, uint64_t aInnerWindowId,
    100    uint64_t aOuterWindowId, FieldValues&& aInit)
    101    : WindowContext(aBrowsingContext, aInnerWindowId, aOuterWindowId,
    102                    std::move(aInit)),
    103      mIsUncommittedInitialDocument(false),
    104      mSandboxFlags(0),
    105      mDocumentHasLoaded(false),
    106      mDocumentHasUserInteracted(false),
    107      mBlockAllMixedContent(false),
    108      mUpgradeInsecureRequests(false) {
    109  MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess(), "Parent process only");
    110 }
    111 
    112 already_AddRefed<WindowGlobalParent> WindowGlobalParent::CreateDisconnected(
    113    const WindowGlobalInit& aInit) {
    114  RefPtr<CanonicalBrowsingContext> browsingContext =
    115      CanonicalBrowsingContext::Get(aInit.context().mBrowsingContextId);
    116  if (NS_WARN_IF(!browsingContext)) {
    117    return nullptr;
    118  }
    119 
    120  RefPtr<WindowGlobalParent> wgp =
    121      GetByInnerWindowId(aInit.context().mInnerWindowId);
    122  MOZ_RELEASE_ASSERT(!wgp, "Creating duplicate WindowGlobalParent");
    123 
    124  FieldValues fields(aInit.context().mFields);
    125  wgp =
    126      new WindowGlobalParent(browsingContext, aInit.context().mInnerWindowId,
    127                             aInit.context().mOuterWindowId, std::move(fields));
    128  wgp->mDocumentPrincipal = aInit.principal();
    129  wgp->mDocumentURI = aInit.documentURI();
    130  wgp->mIsInitialDocument = Some(aInit.isInitialDocument());
    131  wgp->mIsUncommittedInitialDocument = aInit.isUncommittedInitialDocument();
    132  wgp->mBlockAllMixedContent = aInit.blockAllMixedContent();
    133  wgp->mUpgradeInsecureRequests = aInit.upgradeInsecureRequests();
    134  wgp->mSandboxFlags = aInit.sandboxFlags();
    135  wgp->mHttpsOnlyStatus = aInit.httpsOnlyStatus();
    136  wgp->mSecurityInfo = aInit.securityInfo();
    137  net::CookieJarSettings::Deserialize(aInit.cookieJarSettings(),
    138                                      getter_AddRefs(wgp->mCookieJarSettings));
    139  MOZ_RELEASE_ASSERT(wgp->mDocumentPrincipal, "Must have a valid principal");
    140 
    141  nsresult rv = wgp->SetDocumentStoragePrincipal(aInit.storagePrincipal());
    142  MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv),
    143                     "Must succeed in setting storage principal");
    144 
    145  return wgp.forget();
    146 }
    147 
    148 void WindowGlobalParent::Init() {
    149  MOZ_ASSERT(Manager(), "Should have a manager!");
    150 
    151  // Invoke our base class' `Init` method. This will register us in
    152  // `gWindowContexts`.
    153  WindowContext::Init();
    154 
    155  // Determine which content process the window global is coming from.
    156  dom::ContentParentId processId(0);
    157  ContentParent* cp = nullptr;
    158  if (!IsInProcess()) {
    159    cp = static_cast<ContentParent*>(Manager()->Manager());
    160    processId = cp->ChildID();
    161 
    162    // Ensure the content process has permissions for this principal.
    163    cp->TransmitPermissionsForPrincipal(mDocumentPrincipal);
    164  }
    165 
    166  MOZ_DIAGNOSTIC_ASSERT(
    167      !BrowsingContext()->GetParent() ||
    168          BrowsingContext()->GetEmbedderInnerWindowId(),
    169      "When creating a non-root WindowGlobalParent, the WindowGlobalParent "
    170      "for our embedder should've already been created.");
    171 
    172  // Ensure we have a document URI
    173  if (!mDocumentURI) {
    174    NS_NewURI(getter_AddRefs(mDocumentURI), "about:blank");
    175  }
    176 
    177  // NOTE: `cp` may be nullptr, but that's OK, we need to tell every other
    178  // process in our group in that case.
    179  IPCInitializer ipcinit = GetIPCInitializer();
    180  Group()->EachOtherParent(cp, [&](ContentParent* otherContent) {
    181    (void)otherContent->SendCreateWindowContext(ipcinit);
    182  });
    183 
    184  if (!BrowsingContext()->IsDiscarded()) {
    185    MOZ_ALWAYS_SUCCEEDS(
    186        BrowsingContext()->SetCurrentInnerWindowId(InnerWindowId()));
    187  }
    188 
    189  if (BrowsingContext()->IsTopContent()) {
    190    // For top level sandboxed documents we need to create a new principal
    191    // from URI + OriginAttributes, since the document principal will be a
    192    // NullPrincipal. See Bug 1654546.
    193    if (mSandboxFlags & SANDBOXED_ORIGIN) {
    194      ContentBlockingAllowList::RecomputePrincipal(
    195          mDocumentURI, mDocumentPrincipal->OriginAttributesRef(),
    196          getter_AddRefs(mDocContentBlockingAllowListPrincipal));
    197    } else {
    198      ContentBlockingAllowList::ComputePrincipal(
    199          mDocumentPrincipal,
    200          getter_AddRefs(mDocContentBlockingAllowListPrincipal));
    201    }
    202  }
    203 
    204  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
    205  if (obs) {
    206    obs->NotifyObservers(ToSupports(this), "window-global-created", nullptr);
    207  }
    208 
    209  if (!BrowsingContext()->IsDiscarded() && ShouldTrackSiteOriginTelemetry()) {
    210    mOriginCounter.emplace();
    211    mOriginCounter->UpdateSiteOriginsFrom(this, /* aIncrease = */ true);
    212  }
    213 }
    214 
    215 void WindowGlobalParent::OriginCounter::UpdateSiteOriginsFrom(
    216    WindowGlobalParent* aParent, bool aIncrease) {
    217  MOZ_RELEASE_ASSERT(aParent);
    218 
    219  if (aParent->DocumentPrincipal()->GetIsContentPrincipal()) {
    220    nsAutoCString origin;
    221    aParent->DocumentPrincipal()->GetSiteOrigin(origin);
    222 
    223    if (aIncrease) {
    224      int32_t& count = mOriginMap.LookupOrInsert(origin);
    225      count += 1;
    226      mMaxOrigins = std::max(mMaxOrigins, mOriginMap.Count());
    227    } else if (auto entry = mOriginMap.Lookup(origin)) {
    228      entry.Data() -= 1;
    229 
    230      if (entry.Data() == 0) {
    231        entry.Remove();
    232      }
    233    }
    234  }
    235 }
    236 
    237 void WindowGlobalParent::OriginCounter::Accumulate() {
    238  mozilla::glean::geckoview::per_document_site_origins.AccumulateSingleSample(
    239      mMaxOrigins);
    240 
    241  mMaxOrigins = 0;
    242  mOriginMap.Clear();
    243 }
    244 
    245 /* static */
    246 already_AddRefed<WindowGlobalParent> WindowGlobalParent::GetByInnerWindowId(
    247    uint64_t aInnerWindowId) {
    248  if (!XRE_IsParentProcess()) {
    249    return nullptr;
    250  }
    251 
    252  return WindowContext::GetById(aInnerWindowId).downcast<WindowGlobalParent>();
    253 }
    254 
    255 already_AddRefed<WindowGlobalChild> WindowGlobalParent::GetChildActor() {
    256  if (!CanSend()) {
    257    return nullptr;
    258  }
    259  IProtocol* otherSide = InProcessParent::ChildActorFor(this);
    260  return do_AddRef(static_cast<WindowGlobalChild*>(otherSide));
    261 }
    262 
    263 BrowserParent* WindowGlobalParent::GetBrowserParent() const {
    264  if (IsInProcess() || !CanSend()) {
    265    return nullptr;
    266  }
    267  return static_cast<BrowserParent*>(Manager());
    268 }
    269 
    270 ContentParent* WindowGlobalParent::GetContentParent() {
    271  if (IsInProcess() || !CanSend()) {
    272    return nullptr;
    273  }
    274  return static_cast<ContentParent*>(Manager()->Manager());
    275 }
    276 
    277 already_AddRefed<nsFrameLoader> WindowGlobalParent::GetRootFrameLoader() {
    278  dom::BrowsingContext* top = BrowsingContext()->Top();
    279 
    280  RefPtr<nsFrameLoaderOwner> frameLoaderOwner =
    281      do_QueryObject(top->GetEmbedderElement());
    282  if (frameLoaderOwner) {
    283    return frameLoaderOwner->GetFrameLoader();
    284  }
    285  return nullptr;
    286 }
    287 
    288 uint64_t WindowGlobalParent::ContentParentId() {
    289  RefPtr<BrowserParent> browserParent = GetBrowserParent();
    290  return browserParent ? browserParent->Manager()->ChildID() : 0;
    291 }
    292 
    293 int32_t WindowGlobalParent::OsPid() {
    294  RefPtr<BrowserParent> browserParent = GetBrowserParent();
    295  return browserParent ? browserParent->Manager()->Pid() : -1;
    296 }
    297 
    298 // A WindowGlobalPaernt is the root in its process if it has no parent, or its
    299 // embedder is in a different process.
    300 bool WindowGlobalParent::IsProcessRoot() {
    301  if (!BrowsingContext()->GetParent()) {
    302    return true;
    303  }
    304 
    305  RefPtr<WindowGlobalParent> embedder =
    306      BrowsingContext()->GetEmbedderWindowGlobal();
    307  if (NS_WARN_IF(!embedder)) {
    308    return false;
    309  }
    310 
    311  return ContentParentId() != embedder->ContentParentId();
    312 }
    313 
    314 uint32_t WindowGlobalParent::ContentBlockingEvents() {
    315  return GetContentBlockingLog()->GetContentBlockingEventsInLog();
    316 }
    317 
    318 void WindowGlobalParent::GetContentBlockingLog(nsAString& aLog) {
    319  NS_ConvertUTF8toUTF16 log(GetContentBlockingLog()->Stringify());
    320  aLog.Assign(std::move(log));
    321 }
    322 
    323 mozilla::ipc::IPCResult WindowGlobalParent::RecvLoadURI(
    324    const MaybeDiscarded<dom::BrowsingContext>& aTargetBC,
    325    nsDocShellLoadState* aLoadState, bool aSetNavigating) {
    326  if (aTargetBC.IsNullOrDiscarded()) {
    327    MOZ_LOG(
    328        BrowsingContext::GetLog(), LogLevel::Debug,
    329        ("ParentIPC: Trying to send a message with dead or detached context"));
    330    return IPC_OK();
    331  }
    332 
    333  if (aLoadState->URI()->SchemeIs("javascript")) {
    334    return IPC_FAIL(this, "Illegal cross-process javascript: load attempt");
    335  }
    336 
    337  RefPtr<CanonicalBrowsingContext> targetBC = aTargetBC.get_canonical();
    338 
    339  // FIXME: For cross-process loads, we should double check CanAccess() for the
    340  // source browsing context in the parent process.
    341 
    342  if (targetBC->Group() != BrowsingContext()->Group()) {
    343    return IPC_FAIL(this, "Illegal cross-group BrowsingContext load");
    344  }
    345 
    346  // FIXME: We should really initiate the load in the parent before bouncing
    347  // back down to the child.
    348 
    349  targetBC->LoadURI(aLoadState, aSetNavigating);
    350  return IPC_OK();
    351 }
    352 
    353 mozilla::ipc::IPCResult WindowGlobalParent::RecvInternalLoad(
    354    nsDocShellLoadState* aLoadState) {
    355  if (!aLoadState->Target().IsEmpty() ||
    356      aLoadState->TargetBrowsingContext().IsNull()) {
    357    return IPC_FAIL(this, "must already be retargeted");
    358  }
    359  if (aLoadState->TargetBrowsingContext().IsDiscarded()) {
    360    MOZ_LOG(
    361        BrowsingContext::GetLog(), LogLevel::Debug,
    362        ("ParentIPC: Trying to send a message with dead or detached context"));
    363    return IPC_OK();
    364  }
    365 
    366  if (aLoadState->URI()->SchemeIs("javascript")) {
    367    return IPC_FAIL(this, "Illegal cross-process javascript: load attempt");
    368  }
    369 
    370  RefPtr<CanonicalBrowsingContext> targetBC =
    371      aLoadState->TargetBrowsingContext().get_canonical();
    372 
    373  // FIXME: For cross-process loads, we should double check CanAccess() for the
    374  // source browsing context in the parent process.
    375 
    376  if (targetBC->Group() != BrowsingContext()->Group()) {
    377    return IPC_FAIL(this, "Illegal cross-group BrowsingContext load");
    378  }
    379 
    380  // FIXME: We should really initiate the load in the parent before bouncing
    381  // back down to the child.
    382 
    383  targetBC->InternalLoad(aLoadState);
    384  return IPC_OK();
    385 }
    386 
    387 IPCResult WindowGlobalParent::RecvUpdateDocumentURI(NotNull<nsIURI*> aURI) {
    388  // XXX(nika): Assert that the URI change was one which makes sense (either
    389  // about:blank -> a real URI, or a legal push/popstate URI change):
    390  nsAutoCString scheme;
    391  if (NS_FAILED(aURI->GetScheme(scheme))) {
    392    return IPC_FAIL(this, "Setting DocumentURI without scheme.");
    393  }
    394 
    395  nsCOMPtr<nsIIOService> ios = do_GetIOService();
    396  if (!ios) {
    397    return IPC_FAIL(this, "Cannot get IOService");
    398  }
    399  nsCOMPtr<nsIProtocolHandler> handler;
    400  ios->GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
    401  if (!handler) {
    402    return IPC_FAIL(this, "Setting DocumentURI with unknown protocol.");
    403  }
    404 
    405  nsCOMPtr<nsIURI> principalURI = mDocumentPrincipal->GetURI();
    406  if (mDocumentPrincipal->GetIsNullPrincipal()) {
    407    if (nsCOMPtr<nsIPrincipal> precursor =
    408            mDocumentPrincipal->GetPrecursorPrincipal()) {
    409      principalURI = precursor->GetURI();
    410    }
    411  }
    412 
    413  if (nsScriptSecurityManager::IsHttpOrHttpsAndCrossOrigin(principalURI,
    414                                                           aURI)) {
    415    return IPC_FAIL(this,
    416                    "Setting DocumentURI with a different Origin than "
    417                    "principal URI");
    418  }
    419 
    420  mDocumentURI = aURI;
    421  return IPC_OK();
    422 }
    423 
    424 nsresult WindowGlobalParent::SetDocumentStoragePrincipal(
    425    nsIPrincipal* aNewDocumentStoragePrincipal) {
    426  if (mDocumentPrincipal->Equals(aNewDocumentStoragePrincipal)) {
    427    mDocumentStoragePrincipal = mDocumentPrincipal;
    428    return NS_OK;
    429  }
    430 
    431  // Compare originNoSuffix to ensure it's equal.
    432  nsCString noSuffix;
    433  nsresult rv = mDocumentPrincipal->GetOriginNoSuffix(noSuffix);
    434  if (NS_FAILED(rv)) {
    435    return rv;
    436  }
    437 
    438  nsCString storageNoSuffix;
    439  rv = aNewDocumentStoragePrincipal->GetOriginNoSuffix(storageNoSuffix);
    440  if (NS_FAILED(rv)) {
    441    return rv;
    442  }
    443 
    444  if (noSuffix != storageNoSuffix) {
    445    return NS_ERROR_FAILURE;
    446  }
    447 
    448  if (!mDocumentPrincipal->OriginAttributesRef().EqualsIgnoringPartitionKey(
    449          aNewDocumentStoragePrincipal->OriginAttributesRef())) {
    450    return NS_ERROR_FAILURE;
    451  }
    452 
    453  mDocumentStoragePrincipal = aNewDocumentStoragePrincipal;
    454  return NS_OK;
    455 }
    456 
    457 IPCResult WindowGlobalParent::RecvUpdateDocumentPrincipal(
    458    nsIPrincipal* aNewDocumentPrincipal,
    459    nsIPrincipal* aNewDocumentStoragePrincipal) {
    460  if (!mDocumentPrincipal->Equals(aNewDocumentPrincipal)) {
    461    return IPC_FAIL(this,
    462                    "Trying to reuse WindowGlobalParent but the principal of "
    463                    "the new document does not match the old one");
    464  }
    465  mDocumentPrincipal = aNewDocumentPrincipal;
    466 
    467  if (NS_FAILED(SetDocumentStoragePrincipal(aNewDocumentStoragePrincipal))) {
    468    return IPC_FAIL(this,
    469                    "Trying to reuse WindowGlobalParent but the principal of "
    470                    "the new document does not match the storage principal");
    471  }
    472 
    473  return IPC_OK();
    474 }
    475 mozilla::ipc::IPCResult WindowGlobalParent::RecvUpdateDocumentTitle(
    476    const nsString& aTitle) {
    477  if (mDocumentTitle.isSome() && mDocumentTitle.value() == aTitle) {
    478    return IPC_OK();
    479  }
    480 
    481  mDocumentTitle = Some(aTitle);
    482 
    483  // Send a pagetitlechanged event only for changes to the title
    484  // for top-level frames.
    485  if (!BrowsingContext()->IsTop()) {
    486    return IPC_OK();
    487  }
    488 
    489  // Notify media controller in order to update its default metadata.
    490  if (BrowsingContext()->HasCreatedMediaController()) {
    491    BrowsingContext()->GetMediaController()->NotifyPageTitleChanged();
    492  }
    493 
    494  Element* frameElement = BrowsingContext()->GetEmbedderElement();
    495  if (!frameElement) {
    496    return IPC_OK();
    497  }
    498 
    499  AsyncEventDispatcher::RunDOMEventWhenSafe(
    500      *frameElement, u"pagetitlechanged"_ns, CanBubble::eYes,
    501      ChromeOnlyDispatch::eYes);
    502 
    503  return IPC_OK();
    504 }
    505 
    506 mozilla::ipc::IPCResult WindowGlobalParent::RecvUpdateHttpsOnlyStatus(
    507    uint32_t aHttpsOnlyStatus) {
    508  mHttpsOnlyStatus = aHttpsOnlyStatus;
    509  return IPC_OK();
    510 }
    511 
    512 IPCResult WindowGlobalParent::RecvUpdateDocumentHasLoaded(
    513    bool aDocumentHasLoaded) {
    514  mDocumentHasLoaded = aDocumentHasLoaded;
    515  return IPC_OK();
    516 }
    517 
    518 IPCResult WindowGlobalParent::RecvUpdateDocumentHasUserInteracted(
    519    bool aDocumentHasUserInteracted) {
    520  mDocumentHasUserInteracted = aDocumentHasUserInteracted;
    521  return IPC_OK();
    522 }
    523 
    524 IPCResult WindowGlobalParent::RecvUpdateSandboxFlags(uint32_t aSandboxFlags) {
    525  mSandboxFlags = aSandboxFlags;
    526  return IPC_OK();
    527 }
    528 
    529 IPCResult WindowGlobalParent::RecvUpdateDocumentCspSettings(
    530    bool aBlockAllMixedContent, bool aUpgradeInsecureRequests) {
    531  mBlockAllMixedContent = aBlockAllMixedContent;
    532  mUpgradeInsecureRequests = aUpgradeInsecureRequests;
    533  return IPC_OK();
    534 }
    535 
    536 mozilla::ipc::IPCResult WindowGlobalParent::RecvSetClientInfo(
    537    const IPCClientInfo& aIPCClientInfo) {
    538  mClientInfo = Some(ClientInfo(aIPCClientInfo));
    539  return IPC_OK();
    540 }
    541 
    542 IPCResult WindowGlobalParent::RecvDestroy() {
    543  // Make a copy so that we can avoid potential iterator invalidation when
    544  // calling the user-provided Destroy() methods.
    545  JSActorWillDestroy();
    546 
    547  if (CanSend()) {
    548    RefPtr<BrowserParent> browserParent = GetBrowserParent();
    549    if (!browserParent || !browserParent->IsDestroyed()) {
    550      (void)Send__delete__(this);
    551    }
    552  }
    553  return IPC_OK();
    554 }
    555 
    556 IPCResult WindowGlobalParent::RecvRawMessage(
    557    const JSActorMessageMeta& aMeta, JSIPCValue&& aData,
    558    const UniquePtr<ClonedMessageData>& aStack) {
    559  UniquePtr<StructuredCloneData> stack;
    560  if (aStack) {
    561    stack = MakeUnique<StructuredCloneData>();
    562    stack->BorrowFromClonedMessageData(*aStack);
    563  }
    564  ReceiveRawMessage(aMeta, std::move(aData), std::move(stack));
    565  return IPC_OK();
    566 }
    567 
    568 const nsACString& WindowGlobalParent::GetRemoteType() const {
    569  if (RefPtr<BrowserParent> browserParent = GetBrowserParent()) {
    570    return browserParent->Manager()->GetRemoteType();
    571  }
    572 
    573  return NOT_REMOTE_TYPE;
    574 }
    575 
    576 void WindowGlobalParent::NotifyContentBlockingEvent(
    577    uint32_t aEvent, nsIRequest* aRequest, bool aBlocked,
    578    const nsACString& aTrackingOrigin,
    579    const nsTArray<nsCString>& aTrackingFullHashes,
    580    const Maybe<ContentBlockingNotifier::StorageAccessPermissionGrantedReason>&
    581        aReason,
    582    const Maybe<CanvasFingerprintingEvent>& aCanvasFingerprintingEvent) {
    583  MOZ_ASSERT(NS_IsMainThread());
    584  DebugOnly<bool> isCookiesBlocked =
    585      aEvent == nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER ||
    586      aEvent == nsIWebProgressListener::STATE_COOKIES_BLOCKED_SOCIALTRACKER;
    587  MOZ_ASSERT_IF(aBlocked, aReason.isNothing());
    588  MOZ_ASSERT_IF(!isCookiesBlocked, aReason.isNothing());
    589  MOZ_ASSERT_IF(isCookiesBlocked && !aBlocked, aReason.isSome());
    590  MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
    591  // TODO: temporarily remove this until we find the root case of Bug 1609144
    592  // MOZ_DIAGNOSTIC_ASSERT_IF(XRE_IsE10sParentProcess(), !IsInProcess());
    593 
    594  // Return early if this WindowGlobalParent is in process.
    595  if (IsInProcess()) {
    596    return;
    597  }
    598 
    599  Maybe<uint32_t> event = GetContentBlockingLog()->RecordLogParent(
    600      aTrackingOrigin, aEvent, aBlocked, aReason, aTrackingFullHashes,
    601      aCanvasFingerprintingEvent);
    602 
    603  // Notify the OnContentBlockingEvent if necessary.
    604  if (event) {
    605    if (auto* webProgress = GetBrowsingContext()->GetWebProgress()) {
    606      webProgress->OnContentBlockingEvent(webProgress, aRequest, event.value());
    607    }
    608  }
    609 }
    610 
    611 already_AddRefed<JSWindowActorParent> WindowGlobalParent::GetActor(
    612    JSContext* aCx, const nsACString& aName, ErrorResult& aRv) {
    613  return JSActorManager::GetActor(aCx, aName, aRv)
    614      .downcast<JSWindowActorParent>();
    615 }
    616 
    617 already_AddRefed<JSWindowActorParent> WindowGlobalParent::GetExistingActor(
    618    const nsACString& aName) {
    619  return JSActorManager::GetExistingActor(aName)
    620      .downcast<JSWindowActorParent>();
    621 }
    622 
    623 already_AddRefed<JSActor> WindowGlobalParent::InitJSActor(
    624    JS::Handle<JSObject*> aMaybeActor, const nsACString& aName,
    625    ErrorResult& aRv) {
    626  RefPtr<JSWindowActorParent> actor;
    627  if (aMaybeActor.get()) {
    628    aRv = UNWRAP_OBJECT(JSWindowActorParent, aMaybeActor.get(), actor);
    629    if (aRv.Failed()) {
    630      return nullptr;
    631    }
    632  } else {
    633    actor = new JSWindowActorParent();
    634  }
    635 
    636  MOZ_RELEASE_ASSERT(!actor->GetManager(),
    637                     "mManager was already initialized once!");
    638  actor->Init(aName, this);
    639  return actor.forget();
    640 }
    641 
    642 bool WindowGlobalParent::IsCurrentGlobal() {
    643  if (mozilla::SessionHistoryInParent() && BrowsingContext() &&
    644      BrowsingContext()->IsInBFCache()) {
    645    return false;
    646  }
    647 
    648  return CanSend() && BrowsingContext()->GetCurrentWindowGlobal() == this;
    649 }
    650 
    651 bool WindowGlobalParent::IsActiveInTab() {
    652  if (!CanSend()) {
    653    return false;
    654  }
    655 
    656  CanonicalBrowsingContext* bc = BrowsingContext();
    657  if (!bc || bc->GetCurrentWindowGlobal() != this) {
    658    return false;
    659  }
    660 
    661  // We check the top BC so we don't need to worry about getting a stale value.
    662  // That may not be necessary.
    663  MOZ_ASSERT(bc->Top()->IsInBFCache() == bc->IsInBFCache(),
    664             "BFCache bit out of sync?");
    665  return bc->AncestorsAreCurrent() && !bc->Top()->IsInBFCache();
    666 }
    667 
    668 namespace {
    669 
    670 class ShareHandler final : public PromiseNativeHandler {
    671 public:
    672  explicit ShareHandler(
    673      mozilla::dom::WindowGlobalParent::ShareResolver&& aResolver)
    674      : mResolver(std::move(aResolver)) {}
    675 
    676  NS_DECL_ISUPPORTS
    677 
    678 public:
    679  virtual void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue,
    680                                ErrorResult& aRv) override {
    681    mResolver(NS_OK);
    682  }
    683 
    684  virtual void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue,
    685                                ErrorResult& aRv) override {
    686    if (NS_WARN_IF(!aValue.isObject())) {
    687      mResolver(NS_ERROR_FAILURE);
    688      return;
    689    }
    690 
    691    // nsresult is stored as Exception internally in Promise
    692    JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
    693    RefPtr<DOMException> unwrapped;
    694    nsresult rv = UNWRAP_OBJECT(DOMException, &obj, unwrapped);
    695    if (NS_WARN_IF(NS_FAILED(rv))) {
    696      mResolver(NS_ERROR_FAILURE);
    697      return;
    698    }
    699 
    700    mResolver(unwrapped->GetResult());
    701  }
    702 
    703 private:
    704  ~ShareHandler() = default;
    705 
    706  mozilla::dom::WindowGlobalParent::ShareResolver mResolver;
    707 };
    708 
    709 NS_IMPL_ISUPPORTS0(ShareHandler)
    710 
    711 }  // namespace
    712 
    713 mozilla::ipc::IPCResult WindowGlobalParent::RecvGetContentBlockingEvents(
    714    WindowGlobalParent::GetContentBlockingEventsResolver&& aResolver) {
    715  uint32_t events = GetContentBlockingLog()->GetContentBlockingEventsInLog();
    716  aResolver(events);
    717 
    718  return IPC_OK();
    719 }
    720 
    721 mozilla::ipc::IPCResult WindowGlobalParent::RecvUpdateCookieJarSettings(
    722    const CookieJarSettingsArgs& aCookieJarSettingsArgs) {
    723  net::CookieJarSettings::Deserialize(aCookieJarSettingsArgs,
    724                                      getter_AddRefs(mCookieJarSettings));
    725  return IPC_OK();
    726 }
    727 
    728 mozilla::ipc::IPCResult WindowGlobalParent::RecvUpdateDocumentSecurityInfo(
    729    nsITransportSecurityInfo* aSecurityInfo) {
    730  mSecurityInfo = aSecurityInfo;
    731  return IPC_OK();
    732 }
    733 
    734 mozilla::ipc::IPCResult WindowGlobalParent::RecvShare(
    735    IPCWebShareData&& aData, WindowGlobalParent::ShareResolver&& aResolver) {
    736  // Widget Layer handoff...
    737  nsCOMPtr<nsISharePicker> sharePicker =
    738      do_GetService("@mozilla.org/sharepicker;1");
    739  if (!sharePicker) {
    740    aResolver(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    741    return IPC_OK();
    742  }
    743 
    744  // Initialize the ShareWidget
    745  RefPtr<BrowserParent> parent = GetBrowserParent();
    746  nsCOMPtr<mozIDOMWindowProxy> openerWindow;
    747  if (parent) {
    748    openerWindow = parent->GetParentWindowOuter();
    749    if (!openerWindow) {
    750      aResolver(NS_ERROR_FAILURE);
    751      return IPC_OK();
    752    }
    753  }
    754  sharePicker->Init(openerWindow);
    755 
    756  // And finally share the data...
    757  RefPtr<Promise> promise;
    758  nsresult rv = sharePicker->Share(aData.title(), aData.text(), aData.url(),
    759                                   getter_AddRefs(promise));
    760  if (NS_FAILED(rv)) {
    761    aResolver(rv);
    762    return IPC_OK();
    763  }
    764 
    765  // Handler finally awaits response...
    766  RefPtr<ShareHandler> handler = new ShareHandler(std::move(aResolver));
    767  promise->AppendNativeHandler(handler);
    768 
    769  return IPC_OK();
    770 }
    771 
    772 namespace {
    773 
    774 class CheckPermitUnloadRequest final : public PromiseNativeHandler,
    775                                       public nsITimerCallback {
    776 public:
    777  CheckPermitUnloadRequest(
    778      WindowGlobalParent* aWGP, bool aHasInProcessBlocker,
    779      nsIDocumentViewer::PermitUnloadAction aAction,
    780      std::function<void(nsIDocumentViewer::PermitUnloadResult)>&& aResolver)
    781      : mResolver(std::move(aResolver)),
    782        mWGP(aWGP),
    783        mAction(aAction),
    784        mFoundBlocker(aHasInProcessBlocker) {}
    785 
    786  // Special case for when we also want to dispatch a "navigate" event to the
    787  // top level window's navigation object. The target session history entry that
    788  // we dispatch is what we use when we #fire-a-traverse-navigate-event. This
    789  // will _only_ run `DispatchBeforeUnloadToSubtree` for the content process of
    790  // the top level window. See further comments below in `Run` and in
    791  // `DispatchBeforeUnloadToSubtree`.
    792  void RunTraversable(const SessionHistoryInfo& aInfo) {
    793    MOZ_DIAGNOSTIC_ASSERT(mWGP->BrowsingContext()->IsTop());
    794    Run(nullptr, 0, Some(aInfo));
    795  }
    796 
    797  // The complementing special case for `RunTraversable`, which is short hand
    798  // for running `DispatchBeforeUnloadToSubtree` for all content processes
    799  // except for the content process of the top level window. See further
    800  // comments below in `Run` and in `DispatchBeforeUnloadToSubtree`.
    801  void RunChildNavigables() {
    802    MOZ_DIAGNOSTIC_ASSERT(mWGP->BrowsingContext()->IsTop());
    803    Run(mWGP->BrowsingContext()->GetContentParent(), 0);
    804  }
    805 
    806  void Run(ContentParent* aIgnoreProcess = nullptr, uint32_t aTimeout = 0,
    807           const Maybe<SessionHistoryInfo>& aInfo = Nothing()) {
    808    MOZ_ASSERT(mState == State::UNINITIALIZED);
    809    mState = State::WAITING;
    810 
    811    RefPtr<CheckPermitUnloadRequest> self(this);
    812 
    813    AutoTArray<ContentParent*, 8> seen;
    814    if (aIgnoreProcess) {
    815      seen.AppendElement(aIgnoreProcess);
    816    }
    817 
    818    BrowsingContext* bc = mWGP->GetBrowsingContext();
    819    auto resolve = [self](nsIDocumentViewer::PermitUnloadResult aResult) {
    820      self->mFoundBlocker =
    821          aResult == nsIDocumentViewer::eCanceledByBeforeUnload;
    822      self->mReason = aResult;
    823      self->ResolveRequest();
    824    };
    825    auto reject = [self](auto) { self->ResolveRequest(); };
    826    // If `aInfo` is passed, only dispatch to the content process of the top
    827    // level window.
    828    if (aInfo) {
    829      MOZ_DIAGNOSTIC_ASSERT(Navigation::IsAPIEnabled());
    830      ContentParent* cp = mWGP->GetContentParent();
    831      mPendingRequests++;
    832      // Here eDontPromptAndUnload means that we ignore beforeunload handlers,
    833      // but we still need to handle the traversable navigate handler.
    834      if (mAction ==
    835          nsIDocumentViewer::PermitUnloadAction::eDontPromptAndUnload) {
    836        cp->SendDispatchNavigateToTraversable(bc, aInfo, resolve, reject);
    837      } else {
    838        cp->SendDispatchBeforeUnloadToSubtree(bc, aInfo, resolve, reject);
    839      }
    840    } else {
    841      bc->PreOrderWalk([&](dom::BrowsingContext* aBC) {
    842        if (WindowGlobalParent* wgp =
    843                aBC->Canonical()->GetCurrentWindowGlobal()) {
    844          ContentParent* cp = wgp->GetContentParent();
    845          // `seen` contains processes that we've already dispatched
    846          // "beforeunload" to.
    847          if (wgp->NeedsBeforeUnload() && !seen.ContainsSorted(cp)) {
    848            seen.InsertElementSorted(cp);
    849            mPendingRequests++;
    850 
    851            if (cp) {
    852              cp->SendDispatchBeforeUnloadToSubtree(bc, Nothing(), resolve,
    853                                                    reject);
    854            } else {
    855              NS_DispatchToMainThread(NS_NewRunnableFunction(
    856                  "DispatchBeforeUnloadToSubtree",
    857                  [bc = RefPtr{bc}, resolve]() {
    858                    ContentChild::DispatchBeforeUnloadToSubtree(bc, Nothing(),
    859                                                                resolve);
    860                  }));
    861            }
    862          }
    863        }
    864      });
    865    }
    866 
    867    if (mPendingRequests && aTimeout) {
    868      (void)NS_NewTimerWithCallback(getter_AddRefs(mTimer), this, aTimeout,
    869                                    nsITimer::TYPE_ONE_SHOT);
    870    }
    871 
    872    CheckDoneWaiting();
    873  }
    874 
    875  void ResolveRequest() {
    876    mPendingRequests--;
    877    CheckDoneWaiting();
    878  }
    879 
    880  NS_IMETHODIMP Notify(nsITimer* aTimer) override {
    881    MOZ_ASSERT(aTimer == mTimer);
    882    if (mState == State::WAITING) {
    883      mState = State::TIMED_OUT;
    884      CheckDoneWaiting();
    885    }
    886    return NS_OK;
    887  }
    888 
    889  void CheckDoneWaiting() {
    890    // If we've found a blocker, we prompt immediately without waiting for
    891    // further responses. The user's response applies to the entire navigation
    892    // attempt, regardless of how many "beforeunload" listeners we call.
    893    if (mState != State::TIMED_OUT &&
    894        (mState != State::WAITING || (mPendingRequests && !mFoundBlocker))) {
    895      return;
    896    }
    897 
    898    mState = State::PROMPTING;
    899 
    900    // Clearing our reference to the timer will automatically cancel it if it's
    901    // still running.
    902    mTimer = nullptr;
    903 
    904    if (!mFoundBlocker) {
    905      SendReply();
    906      return;
    907    }
    908 
    909    auto action = mAction;
    910    if (StaticPrefs::dom_disable_beforeunload()) {
    911      action = nsIDocumentViewer::eDontPromptAndUnload;
    912    }
    913    if (action != nsIDocumentViewer::ePrompt) {
    914      if (action == nsIDocumentViewer::eDontPromptAndUnload) {
    915        mReason = nsIDocumentViewer::eContinue;
    916      } else {
    917        mReason = nsIDocumentViewer::eCanceledByBeforeUnload;
    918      }
    919      SendReply();
    920      return;
    921    }
    922 
    923    // Handle any failure in prompting by aborting the navigation. See comment
    924    // in nsDocumentViewer::PermitUnload for reasoning.
    925    auto cleanup = MakeScopeExit([&]() {
    926      mReason = nsIDocumentViewer::eCanceledByBeforeUnload;
    927      SendReply();
    928    });
    929 
    930    if (nsCOMPtr<nsIPromptCollection> prompt =
    931            do_GetService("@mozilla.org/embedcomp/prompt-collection;1")) {
    932      RefPtr<Promise> promise;
    933      prompt->AsyncBeforeUnloadCheck(mWGP->GetBrowsingContext(),
    934                                     getter_AddRefs(promise));
    935 
    936      if (!promise) {
    937        return;
    938      }
    939 
    940      promise->AppendNativeHandler(this);
    941      cleanup.release();
    942    }
    943  }
    944 
    945  void SendReply() {
    946    MOZ_ASSERT(mState != State::REPLIED);
    947    mResolver(mReason);
    948    mState = State::REPLIED;
    949  }
    950 
    951  void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue,
    952                        ErrorResult& aRv) override {
    953    MOZ_ASSERT(mState == State::PROMPTING);
    954    if (!JS::ToBoolean(aValue)) {
    955      mReason = nsIDocumentViewer::eCanceledByBeforeUnload;
    956    } else {
    957      mReason = nsIDocumentViewer::eContinue;
    958    }
    959 
    960    SendReply();
    961  }
    962 
    963  void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue,
    964                        ErrorResult& aRv) override {
    965    MOZ_ASSERT(mState == State::PROMPTING);
    966 
    967    mReason = nsIDocumentViewer::eCanceledByBeforeUnload;
    968    SendReply();
    969  }
    970 
    971  NS_DECL_ISUPPORTS
    972 
    973 private:
    974  ~CheckPermitUnloadRequest() {
    975    // We may get here without having sent a reply if the promise we're waiting
    976    // on is destroyed without being resolved or rejected.
    977    if (mState != State::REPLIED) {
    978      mReason = nsIDocumentViewer::eCanceledByBeforeUnload;
    979      SendReply();
    980    }
    981  }
    982 
    983  enum class State : uint8_t {
    984    UNINITIALIZED,
    985    WAITING,
    986    TIMED_OUT,
    987    PROMPTING,
    988    REPLIED,
    989  };
    990 
    991  std::function<void(nsIDocumentViewer::PermitUnloadResult)> mResolver;
    992 
    993  RefPtr<WindowGlobalParent> mWGP;
    994  nsCOMPtr<nsITimer> mTimer;
    995 
    996  uint32_t mPendingRequests = 0;
    997 
    998  nsIDocumentViewer::PermitUnloadAction mAction;
    999 
   1000  State mState = State::UNINITIALIZED;
   1001 
   1002  bool mFoundBlocker = false;
   1003 
   1004  nsIDocumentViewer::PermitUnloadResult mReason = nsIDocumentViewer::eContinue;
   1005 };
   1006 
   1007 NS_IMPL_ISUPPORTS(CheckPermitUnloadRequest, nsITimerCallback)
   1008 
   1009 }  // namespace
   1010 
   1011 mozilla::ipc::IPCResult WindowGlobalParent::RecvCheckPermitUnload(
   1012    bool aHasInProcessBlocker, XPCOMPermitUnloadAction aAction,
   1013    CheckPermitUnloadResolver&& aResolver) {
   1014  if (!IsCurrentGlobal()) {
   1015    aResolver(false);
   1016    return IPC_OK();
   1017  }
   1018 
   1019  auto request = MakeRefPtr<CheckPermitUnloadRequest>(
   1020      this, aHasInProcessBlocker, aAction,
   1021      [resolver = std::move(aResolver)](
   1022          nsIDocumentViewer::PermitUnloadResult aResult) {
   1023        resolver(aResult == nsIDocumentViewer::eContinue);
   1024      });
   1025  request->Run(/* aIgnoreProcess */ GetContentParent());
   1026 
   1027  return IPC_OK();
   1028 }
   1029 
   1030 already_AddRefed<Promise> WindowGlobalParent::PermitUnload(
   1031    PermitUnloadAction aAction, uint32_t aTimeout, mozilla::ErrorResult& aRv) {
   1032  nsIGlobalObject* global = GetParentObject();
   1033  RefPtr<Promise> promise = Promise::Create(global, aRv);
   1034  if (NS_WARN_IF(aRv.Failed())) {
   1035    return nullptr;
   1036  }
   1037 
   1038  auto request = MakeRefPtr<CheckPermitUnloadRequest>(
   1039      this, /* aHasInProcessBlocker */ false,
   1040      nsIDocumentViewer::PermitUnloadAction(aAction),
   1041      [promise](nsIDocumentViewer::PermitUnloadResult aResult) {
   1042        promise->MaybeResolve(aResult == nsIDocumentViewer::eContinue);
   1043      });
   1044  request->Run(/* aIgnoreProcess */ nullptr, aTimeout);
   1045 
   1046  return promise.forget();
   1047 }
   1048 
   1049 void WindowGlobalParent::PermitUnload(
   1050    std::function<void(nsIDocumentViewer::PermitUnloadResult)>&& aResolver) {
   1051  RefPtr<CheckPermitUnloadRequest> request =
   1052      MakeRefPtr<CheckPermitUnloadRequest>(
   1053          this, /* aHasInProcessBlocker */ false,
   1054          nsIDocumentViewer::PermitUnloadAction::ePrompt, std::move(aResolver));
   1055  request->Run();
   1056 }
   1057 
   1058 void WindowGlobalParent::PermitUnloadTraversable(
   1059    const SessionHistoryInfo& aInfo,
   1060    nsIDocumentViewer::PermitUnloadAction aAction,
   1061    std::function<void(nsIDocumentViewer::PermitUnloadResult)>&& aResolver) {
   1062  MOZ_DIAGNOSTIC_ASSERT(BrowsingContext()->IsTop());
   1063  RefPtr<CheckPermitUnloadRequest> request =
   1064      MakeRefPtr<CheckPermitUnloadRequest>(this,
   1065                                           /* aHasInProcessBlocker */ false,
   1066                                           aAction, std::move(aResolver));
   1067  request->RunTraversable(aInfo);
   1068 }
   1069 
   1070 void WindowGlobalParent::PermitUnloadChildNavigables(
   1071    nsIDocumentViewer::PermitUnloadAction aAction,
   1072    std::function<void(nsIDocumentViewer::PermitUnloadResult)>&& aResolver) {
   1073  RefPtr<CheckPermitUnloadRequest> request =
   1074      MakeRefPtr<CheckPermitUnloadRequest>(this,
   1075                                           /* aHasInProcessBlocker */ false,
   1076                                           aAction, std::move(aResolver));
   1077  request->RunChildNavigables();
   1078 }
   1079 
   1080 already_AddRefed<mozilla::dom::Promise> WindowGlobalParent::DrawSnapshot(
   1081    const DOMRect* aRect, double aScale, const nsACString& aBackgroundColor,
   1082    bool aResetScrollPosition, mozilla::ErrorResult& aRv) {
   1083  nsIGlobalObject* global = GetParentObject();
   1084  RefPtr<Promise> promise = Promise::Create(global, aRv);
   1085  if (NS_WARN_IF(aRv.Failed())) {
   1086    return nullptr;
   1087  }
   1088 
   1089  nscolor color;
   1090  if (NS_WARN_IF(!ServoCSSParser::ComputeColor(nullptr, NS_RGB(0, 0, 0),
   1091                                               aBackgroundColor, &color,
   1092                                               nullptr, nullptr))) {
   1093    aRv = NS_ERROR_FAILURE;
   1094    return nullptr;
   1095  }
   1096 
   1097  gfx::CrossProcessPaintFlags flags =
   1098      gfx::CrossProcessPaintFlags::UseHighQualityScaling;
   1099  if (!aRect) {
   1100    // If no explicit Rect was passed, we want the currently visible viewport.
   1101    flags |= gfx::CrossProcessPaintFlags::DrawView;
   1102  } else if (aResetScrollPosition) {
   1103    flags |= gfx::CrossProcessPaintFlags::ResetScrollPosition;
   1104  }
   1105 
   1106  if (!gfx::CrossProcessPaint::Start(this, aRect, (float)aScale, color, flags,
   1107                                     promise)) {
   1108    aRv = NS_ERROR_FAILURE;
   1109    return nullptr;
   1110  }
   1111  return promise.forget();
   1112 }
   1113 
   1114 void WindowGlobalParent::DrawSnapshotInternal(gfx::CrossProcessPaint* aPaint,
   1115                                              const Maybe<IntRect>& aRect,
   1116                                              float aScale,
   1117                                              nscolor aBackgroundColor,
   1118                                              uint32_t aFlags) {
   1119  auto promise = SendDrawSnapshot(aRect, aScale, aBackgroundColor, aFlags);
   1120 
   1121  RefPtr<gfx::CrossProcessPaint> paint(aPaint);
   1122  RefPtr<WindowGlobalParent> wgp(this);
   1123  promise->Then(
   1124      GetMainThreadSerialEventTarget(), __func__,
   1125      [paint, wgp](PaintFragment&& aFragment) {
   1126        paint->ReceiveFragment(wgp, std::move(aFragment));
   1127      },
   1128      [paint, wgp](ResponseRejectReason&& aReason) {
   1129        paint->LostFragment(wgp);
   1130      });
   1131 }
   1132 
   1133 /**
   1134 * Accumulated page use counter data for a given top-level content document.
   1135 */
   1136 struct PageUseCounters {
   1137  // The number of page use counter data messages we are still waiting for.
   1138  uint32_t mWaiting = 0;
   1139 
   1140  // Whether we have received any page use counter data.
   1141  bool mReceivedAny = false;
   1142 
   1143  // The accumulated page use counters.
   1144  UseCounters mUseCounters;
   1145 };
   1146 
   1147 mozilla::ipc::IPCResult WindowGlobalParent::RecvExpectPageUseCounters(
   1148    const MaybeDiscarded<WindowContext>& aTop) {
   1149  if (aTop.IsNull()) {
   1150    return IPC_FAIL(this, "aTop must not be null");
   1151  }
   1152 
   1153  MOZ_LOG(gUseCountersLog, LogLevel::Debug,
   1154          ("Expect page use counters: WindowContext %" PRIu64 " -> %" PRIu64,
   1155           InnerWindowId(), aTop.ContextId()));
   1156 
   1157  // We've been called to indicate that the document in our window intends
   1158  // to send use counter data to accumulate towards the top-level document's
   1159  // page use counters.  This causes us to wait for this window to go away
   1160  // (in WindowGlobalParent::ActorDestroy) before reporting the page use
   1161  // counters via Telemetry.
   1162  RefPtr<WindowGlobalParent> page =
   1163      static_cast<WindowGlobalParent*>(aTop.GetMaybeDiscarded());
   1164  if (!page || page->mSentPageUseCounters) {
   1165    MOZ_LOG(gUseCountersLog, LogLevel::Debug,
   1166            (" > too late, won't report page use counters for this straggler"));
   1167    return IPC_OK();
   1168  }
   1169 
   1170  if (mPageUseCountersWindow) {
   1171    if (mPageUseCountersWindow != page) {
   1172      return IPC_FAIL(this,
   1173                      "ExpectPageUseCounters called on the same "
   1174                      "WindowContext with a different aTop value");
   1175    }
   1176 
   1177    // We can get called with the same aTop value more than once, e.g. for
   1178    // initial about:blank documents and then subsequent "real" documents loaded
   1179    // into the same window.  We must note each source window only once.
   1180    return IPC_OK();
   1181  }
   1182 
   1183  // Note that the top-level document must wait for one more window's use
   1184  // counters before reporting via Telemetry.
   1185  mPageUseCountersWindow = page;
   1186  if (!page->mPageUseCounters) {
   1187    page->mPageUseCounters = MakeUnique<PageUseCounters>();
   1188  }
   1189  ++page->mPageUseCounters->mWaiting;
   1190 
   1191  MOZ_LOG(
   1192      gUseCountersLog, LogLevel::Debug,
   1193      (" > top-level now waiting on %d\n", page->mPageUseCounters->mWaiting));
   1194 
   1195  return IPC_OK();
   1196 }
   1197 
   1198 mozilla::ipc::IPCResult WindowGlobalParent::RecvAccumulatePageUseCounters(
   1199    const UseCounters& aUseCounters) {
   1200  // We've been called to accumulate use counter data into the page use counters
   1201  // for the document in mPageUseCountersWindow.
   1202 
   1203  MOZ_LOG(
   1204      gUseCountersLog, LogLevel::Debug,
   1205      ("Accumulate page use counters: WindowContext %" PRIu64 " -> %" PRIu64,
   1206       InnerWindowId(),
   1207       mPageUseCountersWindow ? mPageUseCountersWindow->InnerWindowId() : 0));
   1208 
   1209  if (!mPageUseCountersWindow || mPageUseCountersWindow->mSentPageUseCounters) {
   1210    MOZ_LOG(gUseCountersLog, LogLevel::Debug,
   1211            (" > too late, won't report page use counters for this straggler"));
   1212    return IPC_OK();
   1213  }
   1214 
   1215  MOZ_ASSERT(mPageUseCountersWindow->mPageUseCounters);
   1216  MOZ_ASSERT(mPageUseCountersWindow->mPageUseCounters->mWaiting > 0);
   1217 
   1218  mPageUseCountersWindow->mPageUseCounters->mUseCounters |= aUseCounters;
   1219  mPageUseCountersWindow->mPageUseCounters->mReceivedAny = true;
   1220  return IPC_OK();
   1221 }
   1222 
   1223 // This is called on the top-level WindowGlobal, i.e. the one that is
   1224 // accumulating the page use counters, not the (potentially descendant) window
   1225 // that has finished providing use counter data.
   1226 WindowGlobalParent::PageUseCounterResult
   1227 WindowGlobalParent::FinishAccumulatingPageUseCounters() {
   1228  MOZ_LOG(gUseCountersLog, LogLevel::Debug,
   1229          ("Stop expecting page use counters: -> WindowContext %" PRIu64,
   1230           InnerWindowId()));
   1231 
   1232  if (!mPageUseCounters) {
   1233    MOZ_ASSERT_UNREACHABLE("Not expecting page use counter data");
   1234    MOZ_LOG(gUseCountersLog, LogLevel::Debug,
   1235            (" > not expecting page use counter data"));
   1236    return WindowGlobalParent::PageUseCounterResult();
   1237  }
   1238 
   1239  MOZ_ASSERT(mPageUseCounters->mWaiting > 0);
   1240  --mPageUseCounters->mWaiting;
   1241 
   1242  if (mPageUseCounters->mWaiting > 0) {
   1243    MOZ_LOG(gUseCountersLog, LogLevel::Debug,
   1244            (" > now waiting on %d", mPageUseCounters->mWaiting));
   1245    return PageUseCounterResultBits::WAITING;
   1246  }
   1247 
   1248  PageUseCounterResult result;
   1249  if (mPageUseCounters->mReceivedAny) {
   1250    MOZ_LOG(gUseCountersLog, LogLevel::Debug,
   1251            (" > reporting [%s]",
   1252             nsContentUtils::TruncatedURLForDisplay(mDocumentURI).get()));
   1253 
   1254    result += PageUseCounterResultBits::DATA_RECEIVED;
   1255    Maybe<nsCString> urlForLogging;
   1256    const bool dumpCounters = StaticPrefs::dom_use_counters_dump_page();
   1257    if (dumpCounters) {
   1258      urlForLogging.emplace(
   1259          nsContentUtils::TruncatedURLForDisplay(mDocumentURI));
   1260    }
   1261 
   1262    glean::use_counter::top_level_content_documents_destroyed.Add();
   1263    if (CanonicalBrowsingContext* bc = BrowsingContext()) {
   1264      if (bc->UsePrivateBrowsing()) {
   1265        glean::captcha_detection::pages_visited_pbm.Add();
   1266      } else {
   1267        glean::captcha_detection::pages_visited.Add();
   1268      }
   1269    }
   1270 
   1271    bool any = false;
   1272    for (int32_t c = 0; c < eUseCounter_Count; ++c) {
   1273      auto uc = static_cast<UseCounter>(c);
   1274      if (!mPageUseCounters->mUseCounters[uc]) {
   1275        continue;
   1276      }
   1277      any = true;
   1278      const char* metricName = IncrementUseCounter(uc, /* aIsPage = */ true);
   1279      if (dumpCounters) {
   1280        printf_stderr("USE_COUNTER_PAGE: %s - %s\n", metricName,
   1281                      urlForLogging->get());
   1282      }
   1283    }
   1284 
   1285    if (!any) {
   1286      MOZ_LOG(gUseCountersLog, LogLevel::Debug,
   1287              (" > page use counter data was received, but was empty"));
   1288      result += PageUseCounterResultBits::EMPTY_DATA;
   1289    }
   1290  } else {
   1291    MOZ_LOG(gUseCountersLog, LogLevel::Debug,
   1292            (" > no page use counter data was received"));
   1293  }
   1294 
   1295  mSentPageUseCounters = true;
   1296  mPageUseCounters = nullptr;
   1297  return result;
   1298 }
   1299 
   1300 Element* WindowGlobalParent::GetRootOwnerElement() {
   1301  WindowGlobalParent* top = TopWindowContext();
   1302  if (!top) {
   1303    return nullptr;
   1304  }
   1305 
   1306  if (IsInProcess()) {
   1307    return top->BrowsingContext()->GetEmbedderElement();
   1308  }
   1309 
   1310  if (BrowserParent* parent = top->GetBrowserParent()) {
   1311    return parent->GetOwnerElement();
   1312  }
   1313 
   1314  return nullptr;
   1315 }
   1316 
   1317 void WindowGlobalParent::NotifySessionStoreUpdatesComplete(Element* aEmbedder) {
   1318  if (!aEmbedder) {
   1319    aEmbedder = GetRootOwnerElement();
   1320  }
   1321  if (aEmbedder) {
   1322    if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
   1323      obs->NotifyWhenScriptSafe(ToSupports(aEmbedder),
   1324                                "browser-shutdown-tabstate-updated", nullptr);
   1325    }
   1326  }
   1327 }
   1328 
   1329 mozilla::ipc::IPCResult WindowGlobalParent::RecvRequestRestoreTabContent() {
   1330  CanonicalBrowsingContext* bc = BrowsingContext();
   1331  if (bc && bc->AncestorsAreCurrent()) {
   1332    bc->Top()->RequestRestoreTabContent(this);
   1333  }
   1334  return IPC_OK();
   1335 }
   1336 
   1337 nsCString BFCacheStatusToString(uint32_t aFlags) {
   1338  if (aFlags == 0) {
   1339    return "0"_ns;
   1340  }
   1341 
   1342  nsCString flags;
   1343 #define ADD_BFCACHESTATUS_TO_STRING(_flag) \
   1344  if (aFlags & BFCacheStatus::_flag) {     \
   1345    if (!flags.IsEmpty()) {                \
   1346      flags.Append('|');                   \
   1347    }                                      \
   1348    flags.AppendLiteral(#_flag);           \
   1349    aFlags &= ~BFCacheStatus::_flag;       \
   1350  }
   1351 
   1352  ADD_BFCACHESTATUS_TO_STRING(NOT_ALLOWED);
   1353  ADD_BFCACHESTATUS_TO_STRING(EVENT_HANDLING_SUPPRESSED);
   1354  ADD_BFCACHESTATUS_TO_STRING(SUSPENDED);
   1355  ADD_BFCACHESTATUS_TO_STRING(UNLOAD_LISTENER);
   1356  ADD_BFCACHESTATUS_TO_STRING(REQUEST);
   1357  ADD_BFCACHESTATUS_TO_STRING(ACTIVE_GET_USER_MEDIA);
   1358  ADD_BFCACHESTATUS_TO_STRING(ACTIVE_PEER_CONNECTION);
   1359  ADD_BFCACHESTATUS_TO_STRING(CONTAINS_EME_CONTENT);
   1360  ADD_BFCACHESTATUS_TO_STRING(CONTAINS_MSE_CONTENT);
   1361  ADD_BFCACHESTATUS_TO_STRING(HAS_ACTIVE_SPEECH_SYNTHESIS);
   1362  ADD_BFCACHESTATUS_TO_STRING(HAS_USED_VR);
   1363  ADD_BFCACHESTATUS_TO_STRING(CONTAINS_REMOTE_SUBFRAMES);
   1364  ADD_BFCACHESTATUS_TO_STRING(NOT_ONLY_TOPLEVEL_IN_BCG);
   1365  ADD_BFCACHESTATUS_TO_STRING(BEFOREUNLOAD_LISTENER);
   1366  ADD_BFCACHESTATUS_TO_STRING(ACTIVE_LOCK);
   1367  ADD_BFCACHESTATUS_TO_STRING(PAGE_LOADING);
   1368 
   1369 #undef ADD_BFCACHESTATUS_TO_STRING
   1370 
   1371  MOZ_ASSERT(aFlags == 0,
   1372             "Missing stringification for enum value in BFCacheStatus.");
   1373  return flags;
   1374 }
   1375 
   1376 mozilla::ipc::IPCResult WindowGlobalParent::RecvUpdateBFCacheStatus(
   1377    const uint32_t& aOnFlags, const uint32_t& aOffFlags) {
   1378  if (MOZ_UNLIKELY(MOZ_LOG_TEST(gSHIPBFCacheLog, LogLevel::Debug))) {
   1379    nsAutoCString uri("[no uri]");
   1380    if (mDocumentURI) {
   1381      uri = mDocumentURI->GetSpecOrDefault();
   1382    }
   1383    MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug,
   1384            ("Setting BFCache flags for %s +(%s) -(%s)", uri.get(),
   1385             BFCacheStatusToString(aOnFlags).get(),
   1386             BFCacheStatusToString(aOffFlags).get()));
   1387  }
   1388  mBFCacheStatus |= aOnFlags;
   1389  mBFCacheStatus &= ~aOffFlags;
   1390  return IPC_OK();
   1391 }
   1392 
   1393 mozilla::ipc::IPCResult
   1394 WindowGlobalParent::RecvUpdateActivePeerConnectionStatus(bool aIsAdded) {
   1395  if (aIsAdded) {
   1396    RecvUpdateBFCacheStatus(BFCacheStatus::ACTIVE_PEER_CONNECTION, 0);
   1397  } else {
   1398    RecvUpdateBFCacheStatus(0, BFCacheStatus::ACTIVE_PEER_CONNECTION);
   1399  }
   1400 
   1401  if (WindowGlobalParent* top = TopWindowContext()) {
   1402    CheckedUint32 newValue(top->mNumOfProcessesWithActivePeerConnections);
   1403    if (aIsAdded) {
   1404      ++newValue;
   1405    } else {
   1406      --newValue;
   1407    }
   1408    if (!newValue.isValid()) {
   1409      return IPC_FAIL(this,
   1410                      "mNumOfProcessesWithActivePeerConnections overflowed");
   1411    }
   1412 
   1413    top->mNumOfProcessesWithActivePeerConnections = newValue.value();
   1414    (void)top->SetHasActivePeerConnections(newValue.value() > 0);
   1415  }
   1416 
   1417  return IPC_OK();
   1418 }
   1419 
   1420 mozilla::ipc::IPCResult WindowGlobalParent::RecvSetSingleChannelId(
   1421    const Maybe<uint64_t>& aSingleChannelId) {
   1422  mSingleChannelId = aSingleChannelId;
   1423  return IPC_OK();
   1424 }
   1425 
   1426 mozilla::ipc::IPCResult WindowGlobalParent::RecvSetDocumentDomain(
   1427    NotNull<nsIURI*> aDomain) {
   1428  if (mSandboxFlags & SANDBOXED_DOMAIN) {
   1429    // We're sandboxed; disallow setting domain
   1430    return IPC_FAIL(this, "Sandbox disallows domain setting.");
   1431  }
   1432 
   1433  // Might need to do a featurepolicy check here, like we currently do in the
   1434  // child process?
   1435 
   1436  nsCOMPtr<nsIURI> uri;
   1437  mDocumentPrincipal->GetDomain(getter_AddRefs(uri));
   1438  if (!uri) {
   1439    uri = mDocumentPrincipal->GetURI();
   1440    if (!uri) {
   1441      return IPC_OK();
   1442    }
   1443  }
   1444 
   1445  if (!Document::IsValidDomain(uri, aDomain)) {
   1446    // Error: illegal domain
   1447    return IPC_FAIL(
   1448        this, "Setting domain that's not a suffix of existing domain value.");
   1449  }
   1450 
   1451  if (Group()->IsPotentiallyCrossOriginIsolated()) {
   1452    return IPC_FAIL(this, "Setting domain in a cross-origin isolated BC.");
   1453  }
   1454 
   1455  mDocumentPrincipal->SetDomain(aDomain);
   1456  return IPC_OK();
   1457 }
   1458 
   1459 mozilla::ipc::IPCResult WindowGlobalParent::RecvReloadWithHttpsOnlyException() {
   1460  nsresult rv;
   1461  nsCOMPtr<nsIURI> currentURI = BrowsingContext()->Top()->GetCurrentURI();
   1462 
   1463  if (!currentURI) {
   1464    return IPC_FAIL(this, "HTTPS-only mode: Failed to get current URI");
   1465  }
   1466 
   1467  bool isViewSource = currentURI->SchemeIs("view-source");
   1468 
   1469  nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(currentURI);
   1470  nsCOMPtr<nsIURI> innerURI;
   1471  if (isViewSource) {
   1472    nestedURI->GetInnerURI(getter_AddRefs(innerURI));
   1473  } else {
   1474    innerURI = currentURI;
   1475  }
   1476 
   1477  if (!net::SchemeIsHttpOrHttps(innerURI)) {
   1478    return IPC_FAIL(this, "HTTPS-only mode: Illegal state");
   1479  }
   1480 
   1481  // We replace the scheme with http, because the user wants to unbreak the
   1482  // whole page.
   1483  nsCOMPtr<nsIURI> newURI;
   1484  (void)NS_MutateURI(innerURI).SetScheme("http"_ns).Finalize(
   1485      getter_AddRefs(newURI));
   1486 
   1487  OriginAttributes originAttributes =
   1488      TopWindowContext()->DocumentPrincipal()->OriginAttributesRef();
   1489 
   1490  originAttributes.SetFirstPartyDomain(true, newURI);
   1491 
   1492  nsCOMPtr<nsIPermissionManager> permMgr =
   1493      components::PermissionManager::Service();
   1494  if (!permMgr) {
   1495    return IPC_FAIL(
   1496        this, "HTTPS-only mode: Failed to get Permission Manager service");
   1497  }
   1498 
   1499  nsCOMPtr<nsIPrincipal> principal =
   1500      BasePrincipal::CreateContentPrincipal(newURI, originAttributes);
   1501 
   1502  rv = permMgr->AddFromPrincipal(
   1503      principal, "https-only-load-insecure"_ns,
   1504      nsIHttpsOnlyModePermission::LOAD_INSECURE_ALLOW_SESSION,
   1505      nsIPermissionManager::EXPIRE_SESSION, 0);
   1506 
   1507  if (NS_FAILED(rv)) {
   1508    return IPC_FAIL(
   1509        this, "HTTPS-only mode: Failed to add permission to the principal");
   1510  }
   1511 
   1512  nsCOMPtr<nsIURI> insecureURI = newURI;
   1513  if (isViewSource) {
   1514    nsAutoCString spec;
   1515    MOZ_ALWAYS_SUCCEEDS(newURI->GetSpec(spec));
   1516    if (NS_FAILED(
   1517            NS_NewURI(getter_AddRefs(insecureURI), "view-source:"_ns + spec))) {
   1518      return IPC_FAIL(
   1519          this, "HTTPS-only mode: Failed to re-construct view-source URI");
   1520    }
   1521  }
   1522 
   1523  RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState(insecureURI);
   1524  loadState->SetTriggeringPrincipal(nsContentUtils::GetSystemPrincipal());
   1525  loadState->SetLoadType(LOAD_NORMAL_REPLACE);
   1526  loadState->SetHttpsUpgradeTelemetry(
   1527      nsILoadInfo::HTTPS_ONLY_UPGRADE_DOWNGRADE);
   1528 
   1529  RefPtr<CanonicalBrowsingContext> topBC = BrowsingContext()->Top();
   1530  topBC->LoadURI(loadState, /* setNavigating */ true);
   1531 
   1532  return IPC_OK();
   1533 }
   1534 
   1535 IPCResult WindowGlobalParent::RecvGetStorageAccessPermission(
   1536    bool aIncludeIdentityCredential,
   1537    GetStorageAccessPermissionResolver&& aResolve) {
   1538  WindowGlobalParent* top = TopWindowContext();
   1539  if (!top) {
   1540    return IPC_FAIL_NO_REASON(this);
   1541  }
   1542  nsIPrincipal* topPrincipal = top->DocumentPrincipal();
   1543  nsIPrincipal* principal = DocumentPrincipal();
   1544  uint32_t result;
   1545  nsresult rv = AntiTrackingUtils::TestStoragePermissionInParent(
   1546      topPrincipal, principal, &result);
   1547  if (NS_WARN_IF(NS_FAILED(rv))) {
   1548    aResolve(nsIPermissionManager::UNKNOWN_ACTION);
   1549    return IPC_OK();
   1550  }
   1551  if (result == nsIPermissionManager::ALLOW_ACTION) {
   1552    aResolve(nsIPermissionManager::ALLOW_ACTION);
   1553    return IPC_OK();
   1554  }
   1555 
   1556  if (aIncludeIdentityCredential) {
   1557    bool canCollect;
   1558    rv = identity::CanSilentlyCollect(topPrincipal, principal, &canCollect);
   1559    if (NS_WARN_IF(NS_FAILED(rv))) {
   1560      aResolve(nsIPermissionManager::UNKNOWN_ACTION);
   1561      return IPC_OK();
   1562    }
   1563    if (canCollect) {
   1564      aResolve(nsIPermissionManager::ALLOW_ACTION);
   1565      return IPC_OK();
   1566    }
   1567  }
   1568 
   1569  aResolve(result);
   1570  return IPC_OK();
   1571 }
   1572 
   1573 void WindowGlobalParent::ActorDestroy(ActorDestroyReason aWhy) {
   1574  if (GetBrowsingContext()->IsTopContent()) {
   1575    glean::orb::did_ever_block_response
   1576        .EnumGet(mShouldReportHasBlockedOpaqueResponse
   1577                     ? glean::orb::DidEverBlockResponseLabel::eTrue
   1578                     : glean::orb::DidEverBlockResponseLabel::eFalse)
   1579        .Add();
   1580  }
   1581 
   1582  PageUseCounterResult pageUseCounterResult;
   1583  if (mPageUseCountersWindow) {
   1584    pageUseCounterResult =
   1585        mPageUseCountersWindow->FinishAccumulatingPageUseCounters();
   1586    mPageUseCountersWindow = nullptr;
   1587  }
   1588 
   1589  if (GetBrowsingContext()->IsTopContent() &&
   1590      !mDocumentPrincipal->SchemeIs("about")) {
   1591    // Record the page load
   1592    uint32_t pageLoaded = 1;
   1593    glean::mixed_content::unblock_counter.AccumulateSingleSample(pageLoaded);
   1594 
   1595    // Record the mixed content status of the docshell in Telemetry
   1596    enum {
   1597      NO_MIXED_CONTENT = 0,  // There is no Mixed Content on the page
   1598      MIXED_DISPLAY_CONTENT =
   1599          1,  // The page attempted to load Mixed Display Content
   1600      MIXED_ACTIVE_CONTENT =
   1601          2,  // The page attempted to load Mixed Active Content
   1602      MIXED_DISPLAY_AND_ACTIVE_CONTENT = 3  // The page attempted to load Mixed
   1603                                            // Display & Mixed Active Content
   1604    };
   1605 
   1606    bool hasMixedDisplay =
   1607        mSecurityState &
   1608        (nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT |
   1609         nsIWebProgressListener::STATE_BLOCKED_MIXED_DISPLAY_CONTENT);
   1610    bool hasMixedActive =
   1611        mSecurityState &
   1612        (nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT |
   1613         nsIWebProgressListener::STATE_BLOCKED_MIXED_ACTIVE_CONTENT);
   1614 
   1615    uint32_t mixedContentLevel = NO_MIXED_CONTENT;
   1616    if (hasMixedDisplay && hasMixedActive) {
   1617      mixedContentLevel = MIXED_DISPLAY_AND_ACTIVE_CONTENT;
   1618    } else if (hasMixedActive) {
   1619      mixedContentLevel = MIXED_ACTIVE_CONTENT;
   1620    } else if (hasMixedDisplay) {
   1621      mixedContentLevel = MIXED_DISPLAY_CONTENT;
   1622    }
   1623    glean::mixed_content::page_load.AccumulateSingleSample(mixedContentLevel);
   1624 
   1625    if (GetDocTreeHadMedia()) {
   1626      glean::media::element_in_page_count.Add(1);
   1627    }
   1628  }
   1629 
   1630  ContentParent* cp = nullptr;
   1631  if (!IsInProcess()) {
   1632    cp = static_cast<ContentParent*>(Manager()->Manager());
   1633  }
   1634 
   1635  Group()->EachOtherParent(cp, [&](ContentParent* otherContent) {
   1636    // Keep the WindowContext and our BrowsingContextGroup alive until other
   1637    // processes have acknowledged it has been discarded.
   1638    Group()->AddKeepAlive();
   1639    auto callback = [self = RefPtr{this}](auto) {
   1640      self->Group()->RemoveKeepAlive();
   1641    };
   1642    otherContent->SendDiscardWindowContext(InnerWindowId(), callback, callback);
   1643  });
   1644 
   1645  // Report content blocking log when destroyed.
   1646  // There shouldn't have any content blocking log when a document is loaded in
   1647  // the parent process(See NotifyContentBlockingEvent), so we could skip
   1648  // reporting log when it is in-process.
   1649  if (!IsInProcess()) {
   1650    RefPtr<BrowserParent> browserParent =
   1651        static_cast<BrowserParent*>(Manager());
   1652    if (browserParent) {
   1653      nsCOMPtr<nsILoadContext> loadContext = browserParent->GetLoadContext();
   1654      if (loadContext && !loadContext->UsePrivateBrowsing() &&
   1655          BrowsingContext()->IsTopContent()) {
   1656        GetContentBlockingLog()->ReportLog();
   1657 
   1658        if (mDocumentURI && net::SchemeIsHttpOrHttps(mDocumentURI)) {
   1659          GetContentBlockingLog()->ReportCanvasFingerprintingLog(
   1660              DocumentPrincipal());
   1661          GetContentBlockingLog()->ReportFontFingerprintingLog(
   1662              DocumentPrincipal());
   1663          GetContentBlockingLog()->ReportEmailTrackingLog(DocumentPrincipal());
   1664        }
   1665      }
   1666    }
   1667  }
   1668 
   1669  // Note that our WindowContext has become discarded.
   1670  WindowContext::Discard();
   1671 
   1672  // Destroy our JSWindowActors, and reject any pending queries.
   1673  JSActorDidDestroy();
   1674 
   1675  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   1676  if (obs) {
   1677    obs->NotifyObservers(ToSupports(this), "window-global-destroyed", nullptr);
   1678  }
   1679 
   1680  if (mOriginCounter) {
   1681    mOriginCounter->Accumulate();
   1682  }
   1683 }
   1684 
   1685 WindowGlobalParent::~WindowGlobalParent() = default;
   1686 
   1687 JSObject* WindowGlobalParent::WrapObject(JSContext* aCx,
   1688                                         JS::Handle<JSObject*> aGivenProto) {
   1689  return WindowGlobalParent_Binding::Wrap(aCx, this, aGivenProto);
   1690 }
   1691 
   1692 nsIGlobalObject* WindowGlobalParent::GetParentObject() {
   1693  return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
   1694 }
   1695 
   1696 nsIDOMProcessParent* WindowGlobalParent::GetDomProcess() {
   1697  if (RefPtr<BrowserParent> browserParent = GetBrowserParent()) {
   1698    return browserParent->Manager();
   1699  }
   1700  return InProcessParent::Singleton();
   1701 }
   1702 
   1703 void WindowGlobalParent::DidBecomeCurrentWindowGlobal(bool aCurrent) {
   1704  WindowGlobalParent* top = BrowsingContext()->GetTopWindowContext();
   1705  if (top && top->mOriginCounter) {
   1706    top->mOriginCounter->UpdateSiteOriginsFrom(this,
   1707                                               /* aIncrease = */ aCurrent);
   1708  }
   1709 
   1710  if (!aCurrent && Fullscreen()) {
   1711    ExitTopChromeDocumentFullscreen();
   1712  }
   1713 }
   1714 
   1715 bool WindowGlobalParent::ShouldTrackSiteOriginTelemetry() {
   1716  CanonicalBrowsingContext* bc = BrowsingContext();
   1717 
   1718  if (!bc->IsTopContent()) {
   1719    return false;
   1720  }
   1721 
   1722  RefPtr<BrowserParent> browserParent = GetBrowserParent();
   1723  if (!browserParent ||
   1724      !IsWebRemoteType(browserParent->Manager()->GetRemoteType())) {
   1725    return false;
   1726  }
   1727 
   1728  return DocumentPrincipal()->GetIsContentPrincipal();
   1729 }
   1730 
   1731 void WindowGlobalParent::AddSecurityState(uint32_t aStateFlags) {
   1732  MOZ_ASSERT(TopWindowContext() == this);
   1733  MOZ_ASSERT((aStateFlags &
   1734              (nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT |
   1735               nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT |
   1736               nsIWebProgressListener::STATE_BLOCKED_MIXED_DISPLAY_CONTENT |
   1737               nsIWebProgressListener::STATE_BLOCKED_MIXED_ACTIVE_CONTENT |
   1738               nsIWebProgressListener::STATE_HTTPS_ONLY_MODE_UPGRADED |
   1739               nsIWebProgressListener::STATE_HTTPS_ONLY_MODE_UPGRADE_FAILED |
   1740               nsIWebProgressListener::STATE_HTTPS_ONLY_MODE_UPGRADED_FIRST)) ==
   1741                 aStateFlags,
   1742             "Invalid flags specified!");
   1743 
   1744  if ((mSecurityState & aStateFlags) == aStateFlags) {
   1745    return;
   1746  }
   1747 
   1748  mSecurityState |= aStateFlags;
   1749 
   1750  if (GetBrowsingContext()->GetCurrentWindowGlobal() == this) {
   1751    GetBrowsingContext()->UpdateSecurityState();
   1752  }
   1753 }
   1754 
   1755 bool WindowGlobalParent::HasActivePeerConnections() {
   1756  MOZ_ASSERT(TopWindowContext() == this,
   1757             "mNumOfProcessesWithActivePeerConnections is set only "
   1758             "in the top window context");
   1759  return mNumOfProcessesWithActivePeerConnections > 0;
   1760 }
   1761 
   1762 void WindowGlobalParent::ExitTopChromeDocumentFullscreen() {
   1763  RefPtr<CanonicalBrowsingContext> chromeTop =
   1764      BrowsingContext()->TopCrossChromeBoundary();
   1765  if (Document* chromeDoc = chromeTop->GetDocument()) {
   1766    Document::ClearPendingFullscreenRequests(chromeDoc);
   1767    if (chromeDoc->Fullscreen()) {
   1768      // This only clears the DOM fullscreen, will not exit from browser UI
   1769      // fullscreen mode.
   1770      Document::AsyncExitFullscreen(chromeDoc);
   1771    }
   1772  }
   1773 }
   1774 
   1775 void WindowGlobalParent::SetShouldReportHasBlockedOpaqueResponse(
   1776    nsContentPolicyType aContentPolicy) {
   1777  // It's always okay to block TYPE_BEACON, TYPE_PING and TYPE_CSP_REPORT in
   1778  // the parent process because content processes can do nothing to their
   1779  // responses. Hence excluding them from the telemetry as blocking
   1780  // them have no webcompat concerns.
   1781  if (aContentPolicy != nsIContentPolicy::TYPE_BEACON &&
   1782      aContentPolicy != nsIContentPolicy::TYPE_PING &&
   1783      aContentPolicy != nsIContentPolicy::TYPE_CSP_REPORT) {
   1784    if (IsTop()) {
   1785      mShouldReportHasBlockedOpaqueResponse = true;
   1786    }
   1787  }
   1788 }
   1789 
   1790 IPCResult WindowGlobalParent::RecvSetCookies(
   1791    const nsCString& aBaseDomain, const OriginAttributes& aOriginAttributes,
   1792    nsIURI* aHost, bool aFromHttp, bool aIsThirdParty,
   1793    const nsTArray<CookieStruct>& aCookies) {
   1794  // Get CookieServiceParent via
   1795  // ContentParent->NeckoParent->CookieServiceParent.
   1796  ContentParent* contentParent = GetContentParent();
   1797  NS_ENSURE_TRUE(contentParent, IPC_OK());
   1798 
   1799  net::PNeckoParent* neckoParent =
   1800      LoneManagedOrNullAsserts(contentParent->ManagedPNeckoParent());
   1801  NS_ENSURE_TRUE(neckoParent, IPC_OK());
   1802  net::PCookieServiceParent* csParent =
   1803      LoneManagedOrNullAsserts(neckoParent->ManagedPCookieServiceParent());
   1804  NS_ENSURE_TRUE(csParent, IPC_OK());
   1805  auto* cs = static_cast<net::CookieServiceParent*>(csParent);
   1806 
   1807  return cs->SetCookies(aBaseDomain, aOriginAttributes, aHost, aFromHttp,
   1808                        aIsThirdParty, aCookies, GetBrowsingContext());
   1809 }
   1810 
   1811 IPCResult WindowGlobalParent::RecvOnInitialStorageAccess() {
   1812  DebugOnly<nsresult> rv =
   1813      BounceTrackingStorageObserver::OnInitialStorageAccess(this);
   1814  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to notify storage access");
   1815  return IPC_OK();
   1816 }
   1817 
   1818 IPCResult WindowGlobalParent::RecvRecordUserActivationForBTP() {
   1819  WindowGlobalParent* top = TopWindowContext();
   1820  if (!top) {
   1821    return IPC_OK();
   1822  }
   1823  nsIPrincipal* principal = top->DocumentPrincipal();
   1824  if (!principal) {
   1825    return IPC_OK();
   1826  }
   1827 
   1828  DebugOnly<nsresult> rv = BounceTrackingProtection::RecordUserActivation(
   1829      principal, Some(PR_Now()), top->BrowsingContext());
   1830  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
   1831                       "Failed to record BTP user activation.");
   1832 
   1833  return IPC_OK();
   1834 }
   1835 
   1836 already_AddRefed<PWebAuthnTransactionParent>
   1837 WindowGlobalParent::AllocPWebAuthnTransactionParent() {
   1838  return MakeAndAddRef<WebAuthnTransactionParent>();
   1839 }
   1840 
   1841 already_AddRefed<PWebIdentityParent>
   1842 WindowGlobalParent::AllocPWebIdentityParent() {
   1843  return MakeAndAddRef<WebIdentityParent>();
   1844 }
   1845 
   1846 NS_IMPL_CYCLE_COLLECTION_CLASS(WindowGlobalParent)
   1847 
   1848 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WindowGlobalParent,
   1849                                                WindowContext)
   1850  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPageUseCountersWindow)
   1851  tmp->UnlinkManager();
   1852 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
   1853 
   1854 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WindowGlobalParent,
   1855                                                  WindowContext)
   1856  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPageUseCountersWindow)
   1857  if (!tmp->IsInProcess()) {
   1858    CycleCollectionNoteChild(cb, static_cast<BrowserParent*>(tmp->Manager()),
   1859                             "Manager()");
   1860  }
   1861 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   1862 
   1863 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WindowGlobalParent,
   1864                                               WindowContext)
   1865 NS_IMPL_CYCLE_COLLECTION_TRACE_END
   1866 
   1867 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WindowGlobalParent)
   1868 NS_INTERFACE_MAP_END_INHERITING(WindowContext)
   1869 
   1870 NS_IMPL_ADDREF_INHERITED(WindowGlobalParent, WindowContext)
   1871 NS_IMPL_RELEASE_INHERITED(WindowGlobalParent, WindowContext)
   1872 
   1873 }  // namespace mozilla::dom