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