tor-browser

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

Navigator.cpp (73190B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 // Needs to be first.
      8 #include "Navigator.h"
      9 
     10 #include "Geolocation.h"
     11 #include "base/basictypes.h"
     12 #include "mozilla/Components.h"
     13 #include "mozilla/ContentBlockingNotifier.h"
     14 #include "mozilla/MemoryReporting.h"
     15 #include "mozilla/Preferences.h"
     16 #include "mozilla/StaticPrefs_dom.h"
     17 #include "mozilla/dom/BodyExtractor.h"
     18 #include "mozilla/dom/FetchBinding.h"
     19 #include "mozilla/dom/File.h"
     20 #include "nsCharSeparatedTokenizer.h"
     21 #include "nsContentPolicyUtils.h"
     22 #include "nsContentUtils.h"
     23 #include "nsIClassOfService.h"
     24 #include "nsIContentPolicy.h"
     25 #include "nsIHttpProtocolHandler.h"
     26 #include "nsIPrivateAttributionService.h"
     27 #include "nsISupportsPriority.h"
     28 #include "nsIWebProtocolHandlerRegistrar.h"
     29 #include "nsIXULAppInfo.h"
     30 #include "nsMimeTypeArray.h"
     31 #include "nsPluginArray.h"
     32 #include "nsUnicharUtils.h"
     33 #ifdef FUZZING
     34 #  include "mozilla/StaticPrefs_fuzzing.h"
     35 #endif
     36 #include "BatteryManager.h"
     37 #include "Connection.h"
     38 #include "mozilla/ClearOnShutdown.h"
     39 #include "mozilla/Hal.h"
     40 #include "mozilla/StaticPrefs_media.h"
     41 #include "mozilla/StaticPrefs_network.h"
     42 #include "mozilla/StaticPrefs_pdfjs.h"
     43 #include "mozilla/StaticPrefs_privacy.h"
     44 #include "mozilla/StaticPtr.h"
     45 #include "mozilla/StorageAccess.h"
     46 #include "mozilla/dom/Clipboard.h"
     47 #include "mozilla/dom/ContentChild.h"
     48 #include "mozilla/dom/CredentialsContainer.h"
     49 #include "mozilla/dom/Event.h"  // for Event
     50 #include "mozilla/dom/FeaturePolicyUtils.h"
     51 #include "mozilla/dom/GamepadServiceTest.h"
     52 #include "mozilla/dom/LockManager.h"
     53 #include "mozilla/dom/MIDIAccessManager.h"
     54 #include "mozilla/dom/MIDIOptionsBinding.h"
     55 #include "mozilla/dom/MediaCapabilities.h"
     56 #include "mozilla/dom/MediaSession.h"
     57 #include "mozilla/dom/NavigatorLogin.h"
     58 #include "mozilla/dom/Permissions.h"
     59 #include "mozilla/dom/PrivateAttribution.h"
     60 #include "mozilla/dom/ServiceWorkerContainer.h"
     61 #include "mozilla/dom/StorageManager.h"
     62 #include "mozilla/dom/TCPSocket.h"
     63 #include "mozilla/dom/URLSearchParams.h"
     64 #include "mozilla/dom/UserActivation.h"
     65 #include "mozilla/dom/VRDisplay.h"
     66 #include "mozilla/dom/VRDisplayEvent.h"
     67 #include "mozilla/dom/VRServiceTest.h"
     68 #include "mozilla/dom/WakeLockJS.h"
     69 #include "mozilla/dom/XRSystem.h"
     70 #include "mozilla/dom/power/PowerManagerService.h"
     71 #include "mozilla/dom/workerinternals/RuntimeService.h"
     72 #include "nsComponentManagerUtils.h"
     73 #include "nsGlobalWindowInner.h"
     74 #include "nsICookieManager.h"
     75 #include "nsICookieService.h"
     76 #include "nsIHttpChannel.h"
     77 #include "nsIPermissionManager.h"
     78 #include "nsMimeTypes.h"
     79 #include "nsNetUtil.h"
     80 #include "nsRFPService.h"
     81 #include "nsStringStream.h"
     82 #ifdef ENABLE_WEBDRIVER
     83 #  include "nsIMarionette.h"
     84 #  include "nsIRemoteAgent.h"
     85 #endif
     86 #include "BrowserChild.h"
     87 #include "MediaManager.h"
     88 #include "ReferrerInfo.h"
     89 #include "WidgetUtils.h"
     90 #include "mozilla/PermissionDelegateHandler.h"
     91 #include "mozilla/dom/FormData.h"
     92 #include "mozilla/dom/MediaDevices.h"
     93 #include "mozilla/dom/Promise.h"
     94 #include "mozilla/dom/WorkerPrivate.h"
     95 #include "mozilla/dom/WorkerRunnable.h"
     96 #include "mozilla/ipc/URIUtils.h"
     97 #include "nsIDocShell.h"
     98 #include "nsIExternalProtocolHandler.h"
     99 #include "nsIScriptError.h"
    100 #include "nsIUploadChannel2.h"
    101 #include "nsJSUtils.h"
    102 #include "nsStreamUtils.h"
    103 
    104 #if defined(XP_WIN)
    105 #  include "mozilla/WindowsVersion.h"
    106 #endif
    107 
    108 #include "AutoplayPolicy.h"
    109 #include "mozilla/DetailedPromise.h"
    110 #include "mozilla/EMEUtils.h"
    111 #include "mozilla/dom/AudioContext.h"
    112 #include "mozilla/dom/HTMLMediaElement.h"
    113 #include "mozilla/dom/WindowGlobalChild.h"
    114 #include "mozilla/intl/LocaleService.h"
    115 #include "mozilla/webgpu/Instance.h"
    116 
    117 namespace mozilla::dom {
    118 
    119 static const nsLiteralCString kVibrationPermissionType = "vibration"_ns;
    120 
    121 Navigator::Navigator(nsPIDOMWindowInner* aWindow) : mWindow(aWindow) {}
    122 
    123 Navigator::~Navigator() { Invalidate(); }
    124 
    125 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Navigator)
    126  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
    127  NS_INTERFACE_MAP_ENTRY(nsISupports)
    128 NS_INTERFACE_MAP_END
    129 
    130 NS_IMPL_CYCLE_COLLECTING_ADDREF(Navigator)
    131 NS_IMPL_CYCLE_COLLECTING_RELEASE(Navigator)
    132 
    133 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(Navigator)
    134 
    135 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Navigator)
    136  tmp->Invalidate();
    137  NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
    138  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSharePromise)
    139  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
    140 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    141 
    142 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
    143  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlugins)
    144  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPermissions)
    145  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGeolocation)
    146  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryManager)
    147  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryPromise)
    148  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
    149  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStorageManager)
    150  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCredentials)
    151  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaDevices)
    152  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerContainer)
    153  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaCapabilities)
    154  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaSession)
    155  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAddonManager)
    156  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebGpu)
    157  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocks)
    158  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLogin)
    159  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrivateAttribution)
    160  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUserActivation)
    161  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWakeLock)
    162 
    163  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
    164  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaKeySystemAccessManager)
    165  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGamepadServiceTest)
    166  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVRGetDisplaysPromises)
    167  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVRServiceTest)
    168  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSharePromise)
    169  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mXRSystem)
    170  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mClipboard)
    171 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    172 
    173 void Navigator::Invalidate() {
    174  // Don't clear mWindow here so we know we've got a non-null mWindow
    175  // until we're unlinked.
    176 
    177  mPlugins = nullptr;
    178 
    179  mPermissions = nullptr;
    180 
    181  if (mStorageManager) {
    182    mStorageManager->Shutdown();
    183    mStorageManager = nullptr;
    184  }
    185 
    186  // If there is a page transition, make sure delete the geolocation object.
    187  if (mGeolocation) {
    188    mGeolocation->Shutdown();
    189    mGeolocation = nullptr;
    190  }
    191 
    192  if (mBatteryManager) {
    193    mBatteryManager->Shutdown();
    194    mBatteryManager = nullptr;
    195  }
    196 
    197  mBatteryPromise = nullptr;
    198 
    199  if (mConnection) {
    200    mConnection->Shutdown();
    201    mConnection = nullptr;
    202  }
    203 
    204  mMediaDevices = nullptr;
    205 
    206  mServiceWorkerContainer = nullptr;
    207 
    208  if (mMediaKeySystemAccessManager) {
    209    mMediaKeySystemAccessManager->Shutdown();
    210    mMediaKeySystemAccessManager = nullptr;
    211  }
    212 
    213  if (mGamepadServiceTest) {
    214    mGamepadServiceTest->Shutdown();
    215    mGamepadServiceTest = nullptr;
    216  }
    217 
    218  mVRGetDisplaysPromises.Clear();
    219 
    220  if (mVRServiceTest) {
    221    mVRServiceTest->Shutdown();
    222    mVRServiceTest = nullptr;
    223  }
    224 
    225  if (mXRSystem) {
    226    mXRSystem->Shutdown();
    227    mXRSystem = nullptr;
    228  }
    229 
    230  mMediaCapabilities = nullptr;
    231 
    232  if (mMediaSession) {
    233    mMediaSession->Shutdown();
    234    mMediaSession = nullptr;
    235  }
    236 
    237  mAddonManager = nullptr;
    238 
    239  mWebGpu = nullptr;
    240 
    241  if (mLocks) {
    242    // Unloading a page does not immediately destruct the lock manager actor,
    243    // but we want to abort the lock requests as soon as possible. Explicitly
    244    // call Shutdown() to do that.
    245    mLocks->Shutdown();
    246    mLocks = nullptr;
    247  }
    248 
    249  mLogin = nullptr;
    250 
    251  mPrivateAttribution = nullptr;
    252 
    253  mUserActivation = nullptr;
    254 
    255  mSharePromise = nullptr;
    256 
    257  mWakeLock = nullptr;
    258 
    259  mClipboard = nullptr;
    260 }
    261 
    262 void Navigator::GetUserAgent(nsAString& aUserAgent, CallerType aCallerType,
    263                             ErrorResult& aRv) const {
    264  nsCOMPtr<nsPIDOMWindowInner> window;
    265 
    266  if (mWindow) {
    267    window = mWindow;
    268    nsIDocShell* docshell = window->GetDocShell();
    269    nsString customUserAgent;
    270    if (docshell) {
    271      docshell->GetBrowsingContext()->GetCustomUserAgent(customUserAgent);
    272 
    273      if (!customUserAgent.IsEmpty()) {
    274        aUserAgent = customUserAgent;
    275        return;
    276      }
    277    }
    278  }
    279 
    280  nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
    281  nsresult rv = GetUserAgent(
    282      mWindow, doc, aCallerType == CallerType::System ? Some(false) : Nothing(),
    283      aUserAgent);
    284  if (NS_WARN_IF(NS_FAILED(rv))) {
    285    aRv.Throw(rv);
    286  }
    287 }
    288 
    289 void Navigator::GetAppCodeName(nsAString& aAppCodeName, ErrorResult& aRv) {
    290  nsresult rv;
    291 
    292  nsCOMPtr<nsIHttpProtocolHandler> service(
    293      do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
    294  if (NS_WARN_IF(NS_FAILED(rv))) {
    295    aRv.Throw(rv);
    296    return;
    297  }
    298 
    299  nsAutoCString appName;
    300  rv = service->GetAppName(appName);
    301  if (NS_WARN_IF(NS_FAILED(rv))) {
    302    aRv.Throw(rv);
    303    return;
    304  }
    305 
    306  CopyASCIItoUTF16(appName, aAppCodeName);
    307 }
    308 
    309 void Navigator::GetAppVersion(nsAString& aAppVersion, CallerType aCallerType,
    310                              ErrorResult& aRv) const {
    311  nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
    312 
    313  nsresult rv = GetAppVersion(
    314      aAppVersion, doc,
    315      /* aUsePrefOverriddenValue = */ aCallerType != CallerType::System);
    316  if (NS_WARN_IF(NS_FAILED(rv))) {
    317    aRv.Throw(rv);
    318  }
    319 }
    320 
    321 void Navigator::GetAppName(nsAString& aAppName) const {
    322  aAppName.AssignLiteral("Netscape");
    323 }
    324 
    325 /**
    326 * Returns the value of Accept-Languages (HTTP header) as a nsTArray of
    327 * languages. The value is set in the preference by the user ("Content
    328 * Languages").
    329 *
    330 * "en", "en-US" and "i-cherokee" and "" are valid languages tokens.
    331 *
    332 * If there is no valid language, the value of getWebExposedLocales is
    333 * used to ensure that locale spoofing is honored and to reduce
    334 * fingerprinting.
    335 *
    336 * See RFC 7231, Section 9.7 "Browser Fingerprinting" and
    337 * RFC 2616, Section 15.1.4 "Privacy Issues Connected to Accept Headers"
    338 * for more detail.
    339 */
    340 /* static */
    341 void Navigator::GetAcceptLanguages(nsTArray<nsString>& aLanguages,
    342                                   const nsCString* aLanguageOverride) {
    343  MOZ_ASSERT(NS_IsMainThread());
    344 
    345  aLanguages.Clear();
    346 
    347  // E.g. "de-de, en-us,en".
    348  nsAutoCString acceptLang;
    349  if (aLanguageOverride) {
    350    acceptLang.Assign(aLanguageOverride->get());
    351  } else {
    352    intl::LocaleService::GetInstance()->GetAcceptLanguages(acceptLang);
    353  }
    354 
    355  // Split values on commas.
    356  for (nsDependentCSubstring lang :
    357       nsCCharSeparatedTokenizer(acceptLang, ',').ToRange()) {
    358    // Replace "_" with "-" to avoid POSIX/Windows "en_US" notation.
    359    // NOTE: we should probably rely on the pref being set correctly.
    360    if (lang.Length() > 2 && lang[2] == '_') {
    361      lang.Replace(2, 1, '-');
    362    }
    363 
    364    // Use uppercase for country part, e.g. "en-US", not "en-us", see BCP47
    365    // only uppercase 2-letter country codes, not "zh-Hant", "de-DE-x-goethe".
    366    // NOTE: we should probably rely on the pref being set correctly.
    367    if (lang.Length() > 2) {
    368      int32_t pos = 0;
    369      bool first = true;
    370      for (const nsACString& code :
    371           nsCCharSeparatedTokenizer(lang, '-').ToRange()) {
    372        if (code.Length() == 2 && !first) {
    373          nsAutoCString upper(code);
    374          ToUpperCase(upper);
    375          lang.Replace(pos, code.Length(), upper);
    376        }
    377 
    378        pos += code.Length() + 1;  // 1 is the separator
    379        first = false;
    380      }
    381    }
    382 
    383    aLanguages.AppendElement(NS_ConvertUTF8toUTF16(lang));
    384  }
    385  if (aLanguages.Length() == 0) {
    386    nsTArray<nsCString> locales;
    387    mozilla::intl::LocaleService::GetInstance()->GetWebExposedLocales(locales);
    388    aLanguages.AppendElement(NS_ConvertUTF8toUTF16(locales[0]));
    389  }
    390 }
    391 
    392 /**
    393 * Returns the first language from GetAcceptLanguages.
    394 *
    395 * Full details above in GetAcceptLanguages.
    396 */
    397 void Navigator::GetLanguage(nsAString& aLanguage) {
    398  nsTArray<nsString> languages;
    399  GetLanguages(languages);
    400  MOZ_ASSERT(languages.Length() >= 1);
    401  aLanguage.Assign(languages[0]);
    402 }
    403 
    404 void Navigator::GetLanguages(nsTArray<nsString>& aLanguages) {
    405  BrowsingContext* bc = mWindow ? mWindow->GetBrowsingContext() : nullptr;
    406  if (bc) {
    407    const nsCString& languageOverride = bc->Top()->GetLanguageOverride();
    408 
    409    if (!languageOverride.IsEmpty()) {
    410      GetAcceptLanguages(aLanguages, &languageOverride);
    411 
    412      return;
    413    }
    414  }
    415 
    416  GetAcceptLanguages(aLanguages, nullptr);
    417 
    418  // The returned value is cached by the binding code. The window listens to the
    419  // accept languages change and will clear the cache when needed. It has to
    420  // take care of dispatching the DOM event already and the invalidation and the
    421  // event has to be timed correctly.
    422 }
    423 
    424 void Navigator::GetPlatform(nsAString& aPlatform, CallerType aCallerType,
    425                            ErrorResult& aRv) const {
    426  if (mWindow) {
    427    BrowsingContext* bc = mWindow->GetBrowsingContext();
    428    nsString customPlatform;
    429    if (bc) {
    430      bc->GetCustomPlatform(customPlatform);
    431 
    432      if (!customPlatform.IsEmpty()) {
    433        aPlatform = customPlatform;
    434        return;
    435      }
    436    }
    437  }
    438 
    439  nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
    440 
    441  nsresult rv = GetPlatform(
    442      aPlatform, doc,
    443      /* aUsePrefOverriddenValue = */ aCallerType != CallerType::System);
    444  if (NS_WARN_IF(NS_FAILED(rv))) {
    445    aRv.Throw(rv);
    446  }
    447 }
    448 
    449 void Navigator::GetOscpu(nsAString& aOSCPU, CallerType aCallerType,
    450                         ErrorResult& aRv) const {
    451  if (aCallerType != CallerType::System) {
    452    // If fingerprinting resistance is on, we will spoof this value. See
    453    // nsRFPService.h for details about spoofed values.
    454    if (nsContentUtils::ShouldResistFingerprinting(GetDocShell(),
    455                                                   RFPTarget::NavigatorOscpu)) {
    456      aOSCPU.AssignLiteral(SPOOFED_OSCPU);
    457      return;
    458    }
    459 
    460    nsAutoString override;
    461    nsresult rv = Preferences::GetString("general.oscpu.override", override);
    462    if (NS_SUCCEEDED(rv)) {
    463      aOSCPU = override;
    464      return;
    465    }
    466  }
    467 
    468  nsresult rv;
    469  nsCOMPtr<nsIHttpProtocolHandler> service(
    470      do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
    471  if (NS_WARN_IF(NS_FAILED(rv))) {
    472    aRv.Throw(rv);
    473    return;
    474  }
    475 
    476  nsAutoCString oscpu;
    477  rv = service->GetOscpu(oscpu);
    478  if (NS_WARN_IF(NS_FAILED(rv))) {
    479    aRv.Throw(rv);
    480    return;
    481  }
    482 
    483  CopyASCIItoUTF16(oscpu, aOSCPU);
    484 }
    485 
    486 void Navigator::GetVendor(nsAString& aVendor) { aVendor.Truncate(); }
    487 
    488 void Navigator::GetVendorSub(nsAString& aVendorSub) { aVendorSub.Truncate(); }
    489 
    490 void Navigator::GetProduct(nsAString& aProduct) {
    491  aProduct.AssignLiteral("Gecko");
    492 }
    493 
    494 void Navigator::GetProductSub(nsAString& aProductSub) {
    495  // Legacy build date hardcoded for backward compatibility (bug 776376)
    496  aProductSub.AssignLiteral(LEGACY_UA_GECKO_TRAIL);
    497 }
    498 
    499 nsMimeTypeArray* Navigator::GetMimeTypes(ErrorResult& aRv) {
    500  auto* plugins = GetPlugins(aRv);
    501  if (!plugins) {
    502    return nullptr;
    503  }
    504 
    505  return plugins->MimeTypeArray();
    506 }
    507 
    508 nsPluginArray* Navigator::GetPlugins(ErrorResult& aRv) {
    509  if (!mPlugins) {
    510    if (!mWindow) {
    511      aRv.Throw(NS_ERROR_UNEXPECTED);
    512      return nullptr;
    513    }
    514    mPlugins = MakeRefPtr<nsPluginArray>(mWindow);
    515  }
    516 
    517  return mPlugins;
    518 }
    519 
    520 bool Navigator::PdfViewerEnabled() {
    521  return !StaticPrefs::pdfjs_disabled() ||
    522         nsContentUtils::ShouldResistFingerprinting(GetDocShell(),
    523                                                    RFPTarget::PdfjsSpoof);
    524 }
    525 
    526 Permissions* Navigator::GetPermissions(ErrorResult& aRv) {
    527  if (!mWindow) {
    528    aRv.Throw(NS_ERROR_UNEXPECTED);
    529    return nullptr;
    530  }
    531 
    532  if (!mPermissions) {
    533    mPermissions = new Permissions(mWindow->AsGlobal());
    534  }
    535 
    536  return mPermissions;
    537 }
    538 
    539 StorageManager* Navigator::Storage() {
    540  MOZ_ASSERT(mWindow);
    541 
    542  if (!mStorageManager) {
    543    mStorageManager = new StorageManager(mWindow->AsGlobal());
    544  }
    545 
    546  return mStorageManager;
    547 }
    548 
    549 bool Navigator::CookieEnabled() {
    550  // Check whether an exception overrides the global cookie behavior
    551  // Note that the code for getting the URI here matches that in
    552  // nsHTMLDocument::SetCookie.
    553  if (!mWindow || !mWindow->GetDocShell()) {
    554    return nsICookieManager::GetCookieBehavior(false) !=
    555           nsICookieService::BEHAVIOR_REJECT;
    556  }
    557 
    558  nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(mWindow);
    559  uint32_t cookieBehavior = loadContext
    560                                ? nsICookieManager::GetCookieBehavior(
    561                                      loadContext->UsePrivateBrowsing())
    562                                : nsICookieManager::GetCookieBehavior(false);
    563  bool cookieEnabled = cookieBehavior != nsICookieService::BEHAVIOR_REJECT;
    564 
    565  nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
    566  if (!doc) {
    567    return cookieEnabled;
    568  }
    569 
    570  uint32_t rejectedReason = 0;
    571  bool granted = false;
    572  nsresult rv = doc->NodePrincipal()->HasFirstpartyStorageAccess(
    573      mWindow, &rejectedReason, &granted);
    574  if (NS_FAILED(rv)) {
    575    // Not a content, so technically can't set cookies, but let's
    576    // just return the default value.
    577    return cookieEnabled;
    578  }
    579 
    580  // We should return true if the cookie is partitioned because the cookie is
    581  // still available in this case.
    582  if (!granted &&
    583      StoragePartitioningEnabled(rejectedReason, doc->CookieJarSettings())) {
    584    granted = true;
    585  }
    586 
    587  ContentBlockingNotifier::OnDecision(
    588      mWindow,
    589      granted ? ContentBlockingNotifier::BlockingDecision::eAllow
    590              : ContentBlockingNotifier::BlockingDecision::eBlock,
    591      rejectedReason);
    592  return granted;
    593 }
    594 
    595 bool Navigator::OnLine() {
    596  if (nsContentUtils::ShouldResistFingerprinting(
    597          GetDocShell(), RFPTarget::NetworkConnection)) {
    598    return true;
    599  }
    600 
    601  if (mWindow) {
    602    // Check if this tab is set to be offline.
    603    BrowsingContext* bc = mWindow->GetBrowsingContext();
    604    if (bc && bc->Top()->GetForceOffline()) {
    605      return false;
    606    }
    607  }
    608  // Return the default browser value
    609  return !NS_IsOffline();
    610 }
    611 
    612 void Navigator::GetBuildID(nsAString& aBuildID, CallerType aCallerType,
    613                           ErrorResult& aRv) const {
    614  if (aCallerType != CallerType::System) {
    615    // If fingerprinting resistance is on, we will spoof this value. See
    616    // nsRFPService.h for details about spoofed values.
    617    if (nsContentUtils::ShouldResistFingerprinting(
    618            GetDocShell(), RFPTarget::NavigatorBuildID)) {
    619      aBuildID.AssignLiteral(LEGACY_BUILD_ID);
    620      return;
    621    }
    622 
    623    nsAutoString override;
    624    nsresult rv = Preferences::GetString("general.buildID.override", override);
    625    if (NS_SUCCEEDED(rv)) {
    626      aBuildID = override;
    627      return;
    628    }
    629 
    630    nsAutoCString host;
    631    bool isHTTPS = false;
    632    if (mWindow) {
    633      nsCOMPtr<Document> doc = mWindow->GetDoc();
    634      if (doc) {
    635        nsIURI* uri = doc->GetDocumentURI();
    636        if (uri) {
    637          isHTTPS = uri->SchemeIs("https");
    638          if (isHTTPS) {
    639            MOZ_ALWAYS_SUCCEEDS(uri->GetHost(host));
    640          }
    641        }
    642      }
    643    }
    644 
    645    // Spoof the buildID on pages not loaded from "https://*.mozilla.org".
    646    if (!isHTTPS || !StringEndsWith(host, ".mozilla.org"_ns)) {
    647      aBuildID.AssignLiteral(LEGACY_BUILD_ID);
    648      return;
    649    }
    650  }
    651 
    652  nsCOMPtr<nsIXULAppInfo> appInfo =
    653      do_GetService("@mozilla.org/xre/app-info;1");
    654  if (!appInfo) {
    655    aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
    656    return;
    657  }
    658 
    659  nsAutoCString buildID;
    660  nsresult rv = appInfo->GetAppBuildID(buildID);
    661  if (NS_WARN_IF(NS_FAILED(rv))) {
    662    aRv.Throw(rv);
    663    return;
    664  }
    665 
    666  aBuildID.Truncate();
    667  AppendASCIItoUTF16(buildID, aBuildID);
    668 }
    669 
    670 void Navigator::GetDoNotTrack(nsAString& aResult) {
    671  if (StaticPrefs::privacy_donottrackheader_enabled()) {
    672    aResult.AssignLiteral("1");
    673  } else {
    674    aResult.AssignLiteral("unspecified");
    675  }
    676 }
    677 
    678 bool Navigator::GlobalPrivacyControl() {
    679  bool gpcStatus = StaticPrefs::privacy_globalprivacycontrol_enabled();
    680  if (!gpcStatus) {
    681    nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(mWindow);
    682    gpcStatus = loadContext && loadContext->UsePrivateBrowsing() &&
    683                StaticPrefs::privacy_globalprivacycontrol_pbmode_enabled();
    684  }
    685  return StaticPrefs::privacy_globalprivacycontrol_functionality_enabled() &&
    686         gpcStatus;
    687 }
    688 
    689 uint64_t Navigator::HardwareConcurrency() {
    690  workerinternals::RuntimeService* rts =
    691      workerinternals::RuntimeService::GetOrCreateService();
    692  if (!rts) {
    693    return 1;
    694  }
    695 
    696  return rts->ClampedHardwareConcurrency(
    697      nsGlobalWindowInner::Cast(mWindow)->ShouldResistFingerprinting(
    698          RFPTarget::NavigatorHWConcurrency),
    699      nsGlobalWindowInner::Cast(mWindow)->ShouldResistFingerprinting(
    700          RFPTarget::NavigatorHWConcurrencyTiered));
    701 }
    702 
    703 namespace {
    704 
    705 class VibrateWindowListener : public nsIDOMEventListener {
    706 public:
    707  VibrateWindowListener(nsPIDOMWindowInner* aWindow, Document* aDocument)
    708      : mWindow(do_GetWeakReference(aWindow)), mDocument(aDocument) {
    709    constexpr auto visibilitychange = u"visibilitychange"_ns;
    710    aDocument->AddSystemEventListener(visibilitychange, this, /* listener */
    711                                      true,                   /* use capture */
    712                                      false /* wants untrusted */);
    713  }
    714 
    715  void RemoveListener();
    716 
    717  NS_DECL_ISUPPORTS
    718  NS_DECL_NSIDOMEVENTLISTENER
    719 
    720 private:
    721  virtual ~VibrateWindowListener() = default;
    722 
    723  nsWeakPtr mWindow;
    724  WeakPtr<Document> mDocument;
    725 };
    726 
    727 NS_IMPL_ISUPPORTS(VibrateWindowListener, nsIDOMEventListener)
    728 
    729 StaticRefPtr<VibrateWindowListener> gVibrateWindowListener;
    730 
    731 static bool MayVibrate(Document* doc) {
    732  // Hidden documents cannot start or stop a vibration.
    733  return (doc && !doc->Hidden());
    734 }
    735 
    736 NS_IMETHODIMP
    737 VibrateWindowListener::HandleEvent(Event* aEvent) {
    738  nsCOMPtr<Document> doc = do_QueryInterface(aEvent->GetTarget());
    739 
    740  if (!MayVibrate(doc)) {
    741    // It's important that we call CancelVibrate(), not Vibrate() with an
    742    // empty list, because Vibrate() will fail if we're no longer focused, but
    743    // CancelVibrate() will succeed, so long as nobody else has started a new
    744    // vibration pattern.
    745    nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(mWindow);
    746    hal::CancelVibrate(window);
    747    RemoveListener();
    748    gVibrateWindowListener = nullptr;
    749    // Careful: The line above might have deleted |this|!
    750  }
    751 
    752  return NS_OK;
    753 }
    754 
    755 void VibrateWindowListener::RemoveListener() {
    756  nsCOMPtr<Document> target(mDocument);
    757  if (!target) {
    758    return;
    759  }
    760  constexpr auto visibilitychange = u"visibilitychange"_ns;
    761  target->RemoveSystemEventListener(visibilitychange, this,
    762                                    true /* use capture */);
    763 }
    764 
    765 }  // namespace
    766 
    767 void Navigator::SetVibrationPermission(bool aPermitted, bool aPersistent) {
    768  MOZ_ASSERT(NS_IsMainThread());
    769 
    770  nsTArray<uint32_t> pattern = std::move(mRequestedVibrationPattern);
    771 
    772  if (!mWindow) {
    773    return;
    774  }
    775 
    776  nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
    777 
    778  if (!MayVibrate(doc)) {
    779    return;
    780  }
    781 
    782  if (aPermitted) {
    783    // Add a listener to cancel the vibration if the document becomes hidden,
    784    // and remove the old visibility listener, if there was one.
    785    if (!gVibrateWindowListener) {
    786      // If gVibrateWindowListener is null, this is the first time we've
    787      // vibrated, and we need to register a listener to clear
    788      // gVibrateWindowListener on shutdown.
    789      ClearOnShutdown(&gVibrateWindowListener);
    790    } else {
    791      gVibrateWindowListener->RemoveListener();
    792    }
    793    gVibrateWindowListener = new VibrateWindowListener(mWindow, doc);
    794    hal::Vibrate(pattern, mWindow);
    795  }
    796 
    797  if (aPersistent) {
    798    nsCOMPtr<nsIPermissionManager> permMgr =
    799        components::PermissionManager::Service();
    800    if (!permMgr) {
    801      return;
    802    }
    803    permMgr->AddFromPrincipal(doc->NodePrincipal(), kVibrationPermissionType,
    804                              aPermitted ? nsIPermissionManager::ALLOW_ACTION
    805                                         : nsIPermissionManager::DENY_ACTION,
    806                              nsIPermissionManager::EXPIRE_SESSION, 0);
    807  }
    808 }
    809 
    810 bool Navigator::Vibrate(uint32_t aDuration) {
    811  AutoTArray<uint32_t, 1> pattern;
    812  pattern.AppendElement(aDuration);
    813  return Vibrate(pattern);
    814 }
    815 
    816 nsTArray<uint32_t> SanitizeVibratePattern(const nsTArray<uint32_t>& aPattern) {
    817  nsTArray<uint32_t> pattern(aPattern.Clone());
    818 
    819  if (pattern.Length() > StaticPrefs::dom_vibrator_max_vibrate_list_len()) {
    820    pattern.SetLength(StaticPrefs::dom_vibrator_max_vibrate_list_len());
    821  }
    822 
    823  for (size_t i = 0; i < pattern.Length(); ++i) {
    824    pattern[i] =
    825        std::min(StaticPrefs::dom_vibrator_max_vibrate_ms(), pattern[i]);
    826  }
    827 
    828  return pattern;
    829 }
    830 
    831 bool Navigator::Vibrate(const nsTArray<uint32_t>& aPattern) {
    832  MOZ_ASSERT(NS_IsMainThread());
    833 
    834  if (!mWindow) {
    835    return false;
    836  }
    837 
    838  nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
    839 
    840  if (!MayVibrate(doc)) {
    841    return false;
    842  }
    843 
    844  nsTArray<uint32_t> pattern = SanitizeVibratePattern(aPattern);
    845 
    846  mRequestedVibrationPattern = std::move(pattern);
    847 
    848  PermissionDelegateHandler* permissionHandler =
    849      doc->GetPermissionDelegateHandler();
    850  if (NS_WARN_IF(!permissionHandler)) {
    851    return false;
    852  }
    853 
    854  uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION;
    855 
    856  permissionHandler->GetPermission(kVibrationPermissionType, &permission,
    857                                   false);
    858 
    859  if (permission == nsIPermissionManager::DENY_ACTION) {
    860    // Abort without observer service or on denied session permission.
    861    SetVibrationPermission(false /* permitted */, false /* persistent */);
    862    return false;
    863  }
    864 
    865  if (permission == nsIPermissionManager::ALLOW_ACTION ||
    866      mRequestedVibrationPattern.IsEmpty() ||
    867      (mRequestedVibrationPattern.Length() == 1 &&
    868       mRequestedVibrationPattern[0] == 0)) {
    869    // Always allow cancelling vibration and respect session permissions.
    870    SetVibrationPermission(true /* permitted */, false /* persistent */);
    871    return true;
    872  }
    873 
    874  // Request user permission.
    875  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
    876  if (!obs) {
    877    return true;
    878  }
    879 
    880  obs->NotifyObservers(ToSupports(this), "Vibration:Request", nullptr);
    881 
    882  return true;
    883 }
    884 
    885 //*****************************************************************************
    886 //  Pointer Events interface
    887 //*****************************************************************************
    888 
    889 uint32_t Navigator::MaxTouchPoints(CallerType aCallerType) {
    890  nsIDocShell* docshell = GetDocShell();
    891  BrowsingContext* bc = docshell ? docshell->GetBrowsingContext() : nullptr;
    892 
    893  // Responsive Design Mode overrides the maxTouchPoints property when
    894  // touch simulation is enabled.
    895  if (bc && bc->Top()->InRDMPane()) {
    896    return bc->Top()->GetMaxTouchPointsOverride();
    897  }
    898 
    899  // The maxTouchPoints is going to reveal the detail of users' hardware. So,
    900  // we will spoof it into 0 if fingerprinting resistance is on.
    901  if (aCallerType != CallerType::System &&
    902      nsContentUtils::ShouldResistFingerprinting(GetDocShell(),
    903                                                 RFPTarget::MaxTouchPoints)) {
    904    return SPOOFED_MAX_TOUCH_POINTS;
    905  }
    906 
    907  nsCOMPtr<nsIWidget> widget =
    908      widget::WidgetUtils::DOMWindowToWidget(mWindow->GetOuterWindow());
    909 
    910  NS_ENSURE_TRUE(widget, 0);
    911  uint32_t maxTouchPoints = widget->GetMaxTouchPoints();
    912 
    913  if (aCallerType != CallerType::System &&
    914      nsContentUtils::ShouldResistFingerprinting(
    915          GetDocShell(), RFPTarget::MaxTouchPointsCollapse)) {
    916    return nsRFPService::CollapseMaxTouchPoints(maxTouchPoints);
    917  }
    918  return maxTouchPoints;
    919 }
    920 
    921 //*****************************************************************************
    922 //    Navigator::nsIDOMClientInformation
    923 //*****************************************************************************
    924 
    925 // This list should be kept up-to-date with the spec:
    926 // https://html.spec.whatwg.org/multipage/system-state.html#custom-handlers
    927 // If you change this list, please also update the copy in E10SUtils.sys.mjs.
    928 static const char* const kSafeSchemes[] = {
    929    // clang-format off
    930    "bitcoin",
    931    "ftp",
    932    "ftps",
    933    "geo",
    934    "im",
    935    "irc",
    936    "ircs",
    937    "magnet",
    938    "mailto",
    939    "matrix",
    940    "mms",
    941    "news",
    942    "nntp",
    943    "openpgp4fpr",
    944    "sftp",
    945    "sip",
    946    "sms",
    947    "smsto",
    948    "ssh",
    949    "tel",
    950    "urn",
    951    "webcal",
    952    "wtai",
    953    "xmpp",
    954    // clang-format on
    955 };
    956 
    957 void Navigator::CheckProtocolHandlerAllowed(const nsAString& aScheme,
    958                                            nsIURI* aHandlerURI,
    959                                            nsIURI* aDocumentURI,
    960                                            ErrorResult& aRv) {
    961  auto raisePermissionDeniedHandler = [&] {
    962    nsAutoCString spec;
    963    aHandlerURI->GetSpec(spec);
    964    nsPrintfCString message("Permission denied to add %s as a protocol handler",
    965                            spec.get());
    966    aRv.ThrowSecurityError(message);
    967  };
    968 
    969  auto raisePermissionDeniedScheme = [&] {
    970    nsPrintfCString message(
    971        "Permission denied to add a protocol handler for %s",
    972        NS_ConvertUTF16toUTF8(aScheme).get());
    973    aRv.ThrowSecurityError(message);
    974  };
    975 
    976  if (!aDocumentURI || !aHandlerURI) {
    977    aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
    978    return;
    979  }
    980 
    981  nsCString spec;
    982  aHandlerURI->GetSpec(spec);
    983  // If the uri doesn't contain '%s', it won't be a good handler - the %s
    984  // gets replaced with the handled URI.
    985  if (!FindInReadable("%s"_ns, spec)) {
    986    aRv.ThrowSyntaxError("Handler URI does not contain \"%s\".");
    987    return;
    988  }
    989 
    990  // For security reasons we reject non-http(s) urls (see bug 354316),
    991  nsAutoCString docScheme;
    992  nsAutoCString handlerScheme;
    993  aDocumentURI->GetScheme(docScheme);
    994  aHandlerURI->GetScheme(handlerScheme);
    995  if ((!docScheme.EqualsLiteral("https") && !docScheme.EqualsLiteral("http")) ||
    996      (!handlerScheme.EqualsLiteral("https") &&
    997       !handlerScheme.EqualsLiteral("http"))) {
    998    raisePermissionDeniedHandler();
    999    return;
   1000  }
   1001 
   1002  // Should be same-origin:
   1003  nsAutoCString handlerHost;
   1004  aHandlerURI->GetHostPort(handlerHost);
   1005  nsAutoCString documentHost;
   1006  aDocumentURI->GetHostPort(documentHost);
   1007  if (!handlerHost.Equals(documentHost) || !handlerScheme.Equals(docScheme)) {
   1008    raisePermissionDeniedHandler();
   1009    return;
   1010  }
   1011 
   1012  // Having checked the handler URI, check the scheme:
   1013  nsAutoCString scheme;
   1014  ToLowerCase(NS_ConvertUTF16toUTF8(aScheme), scheme);
   1015  if (StringBeginsWith(scheme, "web+"_ns)) {
   1016    // Check for non-ascii
   1017    nsReadingIterator<char> iter;
   1018    nsReadingIterator<char> iterEnd;
   1019    auto remainingScheme = Substring(scheme, 4 /* web+ */);
   1020    remainingScheme.BeginReading(iter);
   1021    remainingScheme.EndReading(iterEnd);
   1022    // Scheme suffix must be non-empty
   1023    if (iter == iterEnd) {
   1024      raisePermissionDeniedScheme();
   1025      return;
   1026    }
   1027    for (; iter != iterEnd; iter++) {
   1028      if (*iter < 'a' || *iter > 'z') {
   1029        raisePermissionDeniedScheme();
   1030        return;
   1031      }
   1032    }
   1033  } else {
   1034    bool matches = false;
   1035    for (const char* safeScheme : kSafeSchemes) {
   1036      if (scheme.Equals(safeScheme)) {
   1037        matches = true;
   1038        break;
   1039      }
   1040    }
   1041    if (!matches) {
   1042      raisePermissionDeniedScheme();
   1043      return;
   1044    }
   1045  }
   1046 
   1047  nsCOMPtr<nsIProtocolHandler> handler;
   1048  nsCOMPtr<nsIIOService> io = components::IO::Service();
   1049  if (NS_FAILED(
   1050          io->GetProtocolHandler(scheme.get(), getter_AddRefs(handler)))) {
   1051    raisePermissionDeniedScheme();
   1052    return;
   1053  }
   1054 
   1055  // check if we have prefs set saying not to add this.
   1056  bool defaultExternal =
   1057      Preferences::GetBool("network.protocol-handler.external-default");
   1058  nsPrintfCString specificPref("network.protocol-handler.external.%s",
   1059                               scheme.get());
   1060  if (!Preferences::GetBool(specificPref.get(), defaultExternal)) {
   1061    raisePermissionDeniedScheme();
   1062    return;
   1063  }
   1064 
   1065  // Check to make sure this isn't already handled internally (we don't
   1066  // want to let them take over, say "chrome"). In theory, the checks above
   1067  // should have already taken care of this.
   1068  nsCOMPtr<nsIExternalProtocolHandler> externalHandler =
   1069      do_QueryInterface(handler);
   1070  MOZ_RELEASE_ASSERT(
   1071      externalHandler,
   1072      "We should never allow overriding a builtin protocol handler");
   1073 }
   1074 
   1075 void Navigator::RegisterProtocolHandler(const nsAString& aScheme,
   1076                                        const nsAString& aURI,
   1077                                        ErrorResult& aRv) {
   1078  if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell() ||
   1079      !mWindow->GetDoc()) {
   1080    return;
   1081  }
   1082  nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(mWindow);
   1083  if (loadContext->UsePrivateBrowsing()) {
   1084    // If we're a private window, don't alert the user or webpage. We log to the
   1085    // console so that web developers have some way to tell what's going wrong.
   1086    nsContentUtils::ReportToConsole(
   1087        nsIScriptError::warningFlag, "DOM"_ns, mWindow->GetDoc(),
   1088        nsContentUtils::eDOM_PROPERTIES,
   1089        "RegisterProtocolHandlerPrivateBrowsingWarning");
   1090    return;
   1091  }
   1092 
   1093  nsCOMPtr<Document> doc = mWindow->GetDoc();
   1094 
   1095  // Determine if doc is allowed to assign this handler
   1096  nsIURI* docURI = doc->GetDocumentURIObject();
   1097  nsCOMPtr<nsIURI> handlerURI;
   1098  NS_NewURI(getter_AddRefs(handlerURI), NS_ConvertUTF16toUTF8(aURI),
   1099            doc->GetDocumentCharacterSet(), docURI);
   1100  CheckProtocolHandlerAllowed(aScheme, handlerURI, docURI, aRv);
   1101  if (aRv.Failed()) {
   1102    return;
   1103  }
   1104 
   1105  // Determine a title from the document URI.
   1106  nsAutoCString docDisplayHostPort;
   1107  docURI->GetDisplayHostPort(docDisplayHostPort);
   1108  NS_ConvertASCIItoUTF16 title(docDisplayHostPort);
   1109 
   1110  if (XRE_IsContentProcess()) {
   1111    nsAutoString scheme(aScheme);
   1112    RefPtr<BrowserChild> browserChild = BrowserChild::GetFrom(mWindow);
   1113    browserChild->SendRegisterProtocolHandler(scheme, handlerURI, title,
   1114                                              docURI);
   1115    return;
   1116  }
   1117 
   1118  nsCOMPtr<nsIWebProtocolHandlerRegistrar> registrar =
   1119      do_GetService(NS_WEBPROTOCOLHANDLERREGISTRAR_CONTRACTID);
   1120  if (registrar) {
   1121    aRv = registrar->RegisterProtocolHandler(aScheme, handlerURI, title, docURI,
   1122                                             mWindow->GetOuterWindow());
   1123  }
   1124 }
   1125 
   1126 Geolocation* Navigator::GetGeolocation(ErrorResult& aRv) {
   1127  if (mGeolocation) {
   1128    return mGeolocation;
   1129  }
   1130 
   1131  if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) {
   1132    aRv.Throw(NS_ERROR_FAILURE);
   1133    return nullptr;
   1134  }
   1135 
   1136  mGeolocation = new Geolocation();
   1137  if (NS_FAILED(mGeolocation->Init(mWindow))) {
   1138    mGeolocation = nullptr;
   1139    aRv.Throw(NS_ERROR_FAILURE);
   1140    return nullptr;
   1141  }
   1142 
   1143  return mGeolocation;
   1144 }
   1145 
   1146 class BeaconStreamListener final : public nsIStreamListener {
   1147  ~BeaconStreamListener() = default;
   1148 
   1149 public:
   1150  BeaconStreamListener() : mLoadGroup(nullptr) {}
   1151 
   1152  void SetLoadGroup(nsILoadGroup* aLoadGroup) { mLoadGroup = aLoadGroup; }
   1153 
   1154  NS_DECL_ISUPPORTS
   1155  NS_DECL_NSISTREAMLISTENER
   1156  NS_DECL_NSIREQUESTOBSERVER
   1157 
   1158 private:
   1159  nsCOMPtr<nsILoadGroup> mLoadGroup;
   1160 };
   1161 
   1162 NS_IMPL_ISUPPORTS(BeaconStreamListener, nsIStreamListener, nsIRequestObserver)
   1163 
   1164 NS_IMETHODIMP
   1165 BeaconStreamListener::OnStartRequest(nsIRequest* aRequest) {
   1166  // release the loadgroup first
   1167  mLoadGroup = nullptr;
   1168 
   1169  return NS_ERROR_ABORT;
   1170 }
   1171 
   1172 NS_IMETHODIMP
   1173 BeaconStreamListener::OnStopRequest(nsIRequest* aRequest, nsresult aStatus) {
   1174  return NS_OK;
   1175 }
   1176 
   1177 NS_IMETHODIMP
   1178 BeaconStreamListener::OnDataAvailable(nsIRequest* aRequest,
   1179                                      nsIInputStream* inStr,
   1180                                      uint64_t sourceOffset, uint32_t count) {
   1181  MOZ_ASSERT(false);
   1182  return NS_OK;
   1183 }
   1184 
   1185 bool Navigator::SendBeacon(const nsAString& aUrl,
   1186                           const Nullable<fetch::BodyInit>& aData,
   1187                           ErrorResult& aRv) {
   1188  if (aData.IsNull()) {
   1189    return SendBeaconInternal(aUrl, nullptr, eBeaconTypeOther, aRv);
   1190  }
   1191 
   1192  if (aData.Value().IsArrayBuffer()) {
   1193    BodyExtractor<const ArrayBuffer> body(&aData.Value().GetAsArrayBuffer());
   1194    return SendBeaconInternal(aUrl, &body, eBeaconTypeArrayBuffer, aRv);
   1195  }
   1196 
   1197  if (aData.Value().IsArrayBufferView()) {
   1198    BodyExtractor<const ArrayBufferView> body(
   1199        &aData.Value().GetAsArrayBufferView());
   1200    return SendBeaconInternal(aUrl, &body, eBeaconTypeArrayBuffer, aRv);
   1201  }
   1202 
   1203  if (aData.Value().IsBlob()) {
   1204    BodyExtractor<const Blob> body(&aData.Value().GetAsBlob());
   1205    return SendBeaconInternal(aUrl, &body, eBeaconTypeBlob, aRv);
   1206  }
   1207 
   1208  if (aData.Value().IsFormData()) {
   1209    BodyExtractor<const FormData> body(&aData.Value().GetAsFormData());
   1210    return SendBeaconInternal(aUrl, &body, eBeaconTypeOther, aRv);
   1211  }
   1212 
   1213  if (aData.Value().IsUSVString()) {
   1214    BodyExtractor<const nsAString> body(&aData.Value().GetAsUSVString());
   1215    return SendBeaconInternal(aUrl, &body, eBeaconTypeOther, aRv);
   1216  }
   1217 
   1218  if (aData.Value().IsURLSearchParams()) {
   1219    BodyExtractor<const URLSearchParams> body(
   1220        &aData.Value().GetAsURLSearchParams());
   1221    return SendBeaconInternal(aUrl, &body, eBeaconTypeOther, aRv);
   1222  }
   1223 
   1224  MOZ_CRASH("Invalid data type.");
   1225  return false;
   1226 }
   1227 
   1228 bool Navigator::SendBeaconInternal(const nsAString& aUrl,
   1229                                   BodyExtractorBase* aBody, BeaconType aType,
   1230                                   ErrorResult& aRv) {
   1231  if (!mWindow) {
   1232    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
   1233    return false;
   1234  }
   1235 
   1236  nsCOMPtr<Document> doc = mWindow->GetDoc();
   1237  if (!doc) {
   1238    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
   1239    return false;
   1240  }
   1241 
   1242  nsIURI* documentURI = doc->GetDocumentURI();
   1243  if (!documentURI) {
   1244    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
   1245    return false;
   1246  }
   1247 
   1248  nsCOMPtr<nsIURI> uri;
   1249  nsresult rv = nsContentUtils::NewURIWithDocumentCharset(
   1250      getter_AddRefs(uri), aUrl, doc, doc->GetDocBaseURI());
   1251  if (NS_FAILED(rv)) {
   1252    aRv.ThrowTypeError<MSG_INVALID_URL>(NS_ConvertUTF16toUTF8(aUrl));
   1253    return false;
   1254  }
   1255 
   1256  // Spec disallows any schemes save for HTTP/HTTPs
   1257  if (!net::SchemeIsHttpOrHttps(uri)) {
   1258    aRv.ThrowTypeError<MSG_INVALID_URL_SCHEME>("Beacon",
   1259                                               uri->GetSpecOrDefault());
   1260    return false;
   1261  }
   1262 
   1263  nsCOMPtr<nsIInputStream> in;
   1264  nsAutoCString contentTypeWithCharset;
   1265  nsAutoCString charset;
   1266  uint64_t length = 0;
   1267  if (aBody) {
   1268    aRv = aBody->GetAsStream(getter_AddRefs(in), &length,
   1269                             contentTypeWithCharset, charset);
   1270    if (NS_WARN_IF(aRv.Failed())) {
   1271      return false;
   1272    }
   1273  }
   1274 
   1275  nsSecurityFlags securityFlags = nsILoadInfo::SEC_COOKIES_INCLUDE;
   1276  // Ensure that only streams with content types that are safelisted ignore CORS
   1277  // rules
   1278  if (aBody && !contentTypeWithCharset.IsVoid() &&
   1279      !nsContentUtils::IsCORSSafelistedRequestHeader("content-type"_ns,
   1280                                                     contentTypeWithCharset)) {
   1281    securityFlags |= nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT;
   1282  } else {
   1283    securityFlags |= nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT;
   1284  }
   1285 
   1286  nsCOMPtr<nsIChannel> channel;
   1287  rv = NS_NewChannel(getter_AddRefs(channel), uri, doc, securityFlags,
   1288                     nsIContentPolicy::TYPE_BEACON);
   1289 
   1290  if (NS_FAILED(rv)) {
   1291    aRv.Throw(rv);
   1292    return false;
   1293  }
   1294 
   1295  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
   1296  if (!httpChannel) {
   1297    // Beacon spec only supports HTTP requests at this time
   1298    aRv.Throw(NS_ERROR_DOM_BAD_URI);
   1299    return false;
   1300  }
   1301 
   1302  auto referrerInfo = MakeRefPtr<ReferrerInfo>(*doc);
   1303  rv = httpChannel->SetReferrerInfoWithoutClone(referrerInfo);
   1304  MOZ_ASSERT(NS_SUCCEEDED(rv));
   1305 
   1306  if (aBody) {
   1307    nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(channel);
   1308    if (!uploadChannel) {
   1309      aRv.Throw(NS_ERROR_FAILURE);
   1310      return false;
   1311    }
   1312 
   1313    uploadChannel->ExplicitSetUploadStream(in, contentTypeWithCharset, length,
   1314                                           "POST"_ns, false);
   1315  } else {
   1316    rv = httpChannel->SetRequestMethod("POST"_ns);
   1317    MOZ_ASSERT(NS_SUCCEEDED(rv));
   1318  }
   1319 
   1320  nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(channel);
   1321  if (p) {
   1322    p->SetPriority(nsISupportsPriority::PRIORITY_LOWEST);
   1323  }
   1324 
   1325  nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
   1326  if (cos) {
   1327    cos->AddClassFlags(nsIClassOfService::Background);
   1328  }
   1329 
   1330  // The channel needs to have a loadgroup associated with it, so that we can
   1331  // cancel the channel and any redirected channels it may create.
   1332  nsCOMPtr<nsILoadGroup> loadGroup = do_CreateInstance(NS_LOADGROUP_CONTRACTID);
   1333  nsCOMPtr<nsIInterfaceRequestor> callbacks =
   1334      do_QueryInterface(mWindow->GetDocShell());
   1335  loadGroup->SetNotificationCallbacks(callbacks);
   1336  channel->SetLoadGroup(loadGroup);
   1337 
   1338  RefPtr<BeaconStreamListener> beaconListener = new BeaconStreamListener();
   1339  rv = channel->AsyncOpen(beaconListener);
   1340  // do not throw if security checks fail within asyncOpen
   1341  NS_ENSURE_SUCCESS(rv, false);
   1342 
   1343  // make the beaconListener hold a strong reference to the loadgroup
   1344  // which is released in ::OnStartRequest
   1345  beaconListener->SetLoadGroup(loadGroup);
   1346 
   1347  return true;
   1348 }
   1349 
   1350 MediaDevices* Navigator::GetMediaDevices(ErrorResult& aRv) {
   1351  if (!mMediaDevices) {
   1352    if (!mWindow || !mWindow->GetOuterWindow() ||
   1353        mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) {
   1354      aRv.Throw(NS_ERROR_NOT_AVAILABLE);
   1355      return nullptr;
   1356    }
   1357    mMediaDevices = new MediaDevices(mWindow);
   1358  }
   1359  return mMediaDevices;
   1360 }
   1361 
   1362 void Navigator::MozGetUserMedia(const MediaStreamConstraints& aConstraints,
   1363                                NavigatorUserMediaSuccessCallback& aOnSuccess,
   1364                                NavigatorUserMediaErrorCallback& aOnError,
   1365                                CallerType aCallerType, ErrorResult& aRv) {
   1366  MOZ_ASSERT(NS_IsMainThread());
   1367  if (!mWindow || !mWindow->IsFullyActive()) {
   1368    aRv.ThrowInvalidStateError("The document is not fully active.");
   1369    return;
   1370  }
   1371  GetMediaDevices(aRv);
   1372  if (aRv.Failed()) {
   1373    return;
   1374  }
   1375  MOZ_ASSERT(mMediaDevices);
   1376  RefPtr<MediaManager::StreamPromise> sp;
   1377  if (!MediaManager::IsOn(aConstraints.mVideo) &&
   1378      !MediaManager::IsOn(aConstraints.mAudio)) {
   1379    sp = MediaManager::StreamPromise::CreateAndReject(
   1380        MakeRefPtr<MediaMgrError>(MediaMgrError::Name::TypeError,
   1381                                  "audio and/or video is required"),
   1382        __func__);
   1383  } else {
   1384    sp = mMediaDevices->GetUserMedia(mWindow, aConstraints, aCallerType);
   1385  }
   1386  RefPtr<NavigatorUserMediaSuccessCallback> onsuccess(&aOnSuccess);
   1387  RefPtr<NavigatorUserMediaErrorCallback> onerror(&aOnError);
   1388 
   1389  nsWeakPtr weakWindow = nsWeakPtr(do_GetWeakReference(mWindow));
   1390  sp->Then(
   1391      GetMainThreadSerialEventTarget(), __func__,
   1392      [weakWindow, onsuccess = std::move(onsuccess)](
   1393          const RefPtr<DOMMediaStream>& aStream) MOZ_CAN_RUN_SCRIPT {
   1394        nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(weakWindow);
   1395        if (!window || !window->GetOuterWindow() ||
   1396            window->GetOuterWindow()->GetCurrentInnerWindow() != window) {
   1397          return;  // Leave Promise pending after navigation by design.
   1398        }
   1399        MediaManager::CallOnSuccess(*onsuccess, *aStream);
   1400      },
   1401      [weakWindow, onerror = std::move(onerror)](
   1402          const RefPtr<MediaMgrError>& aError) MOZ_CAN_RUN_SCRIPT {
   1403        nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(weakWindow);
   1404        if (!window || !window->GetOuterWindow() ||
   1405            window->GetOuterWindow()->GetCurrentInnerWindow() != window) {
   1406          return;  // Leave Promise pending after navigation by design.
   1407        }
   1408        auto error = MakeRefPtr<MediaStreamError>(window, *aError);
   1409        MediaManager::CallOnError(*onerror, *error);
   1410      });
   1411 }
   1412 
   1413 //*****************************************************************************
   1414 //    Navigator::nsINavigatorBattery
   1415 //*****************************************************************************
   1416 
   1417 Promise* Navigator::GetBattery(ErrorResult& aRv) {
   1418  if (mBatteryPromise) {
   1419    return mBatteryPromise;
   1420  }
   1421 
   1422  if (!mWindow || !mWindow->GetDocShell()) {
   1423    aRv.Throw(NS_ERROR_UNEXPECTED);
   1424    return nullptr;
   1425  }
   1426 
   1427  RefPtr<Promise> batteryPromise = Promise::Create(mWindow->AsGlobal(), aRv);
   1428  if (NS_WARN_IF(aRv.Failed())) {
   1429    return nullptr;
   1430  }
   1431  mBatteryPromise = batteryPromise;
   1432 
   1433  if (!mBatteryManager) {
   1434    mBatteryManager = new battery::BatteryManager(mWindow);
   1435    mBatteryManager->Init();
   1436  }
   1437 
   1438  mBatteryPromise->MaybeResolve(mBatteryManager);
   1439 
   1440  return mBatteryPromise;
   1441 }
   1442 
   1443 //*****************************************************************************
   1444 //    Navigator::Share() - Web Share API
   1445 //*****************************************************************************
   1446 
   1447 already_AddRefed<Promise> Navigator::Share(const ShareData& aData,
   1448                                           ErrorResult& aRv) {
   1449  if (!mWindow || !mWindow->IsFullyActive()) {
   1450    aRv.ThrowInvalidStateError("The document is not fully active.");
   1451    return nullptr;
   1452  }
   1453 
   1454  if (NS_WARN_IF(!mWindow->GetDocShell() || !mWindow->GetExtantDoc())) {
   1455    aRv.Throw(NS_ERROR_UNEXPECTED);
   1456    return nullptr;
   1457  }
   1458 
   1459  if (!FeaturePolicyUtils::IsFeatureAllowed(mWindow->GetExtantDoc(),
   1460                                            u"web-share"_ns)) {
   1461    aRv.ThrowNotAllowedError(
   1462        "Document's Permissions Policy does not allow calling "
   1463        "share() from this context.");
   1464    return nullptr;
   1465  }
   1466 
   1467  if (mSharePromise) {
   1468    NS_WARNING("Only one share picker at a time per navigator instance");
   1469    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
   1470    return nullptr;
   1471  }
   1472 
   1473  // null checked above
   1474  Document* doc = mWindow->GetExtantDoc();
   1475 
   1476  if (StaticPrefs::dom_webshare_requireinteraction() &&
   1477      !doc->ConsumeTransientUserGestureActivation()) {
   1478    aRv.ThrowNotAllowedError(
   1479        "User activation was already consumed "
   1480        "or share() was not activated by a user gesture.");
   1481    return nullptr;
   1482  }
   1483 
   1484  ValidateShareData(aData, aRv);
   1485 
   1486  if (aRv.Failed()) {
   1487    return nullptr;
   1488  }
   1489 
   1490  // TODO: Process file member, which we don't currently support.
   1491 
   1492  // If data's url member is present, try to resolve it...
   1493  nsCOMPtr<nsIURI> url;
   1494  if (aData.mUrl.WasPassed()) {
   1495    auto result = doc->ResolveWithBaseURI(aData.mUrl.Value());
   1496    url = result.unwrap();
   1497    MOZ_ASSERT(url);
   1498  }
   1499 
   1500  // Process the title member...
   1501  nsCString title;
   1502  if (aData.mTitle.WasPassed()) {
   1503    title.Assign(NS_ConvertUTF16toUTF8(aData.mTitle.Value()));
   1504  } else {
   1505    title.SetIsVoid(true);
   1506  }
   1507 
   1508  // Process the text member...
   1509  nsCString text;
   1510  if (aData.mText.WasPassed()) {
   1511    text.Assign(NS_ConvertUTF16toUTF8(aData.mText.Value()));
   1512  } else {
   1513    text.SetIsVoid(true);
   1514  }
   1515 
   1516  // Let mSharePromise be a new promise.
   1517  mSharePromise = Promise::Create(mWindow->AsGlobal(), aRv);
   1518  if (aRv.Failed()) {
   1519    return nullptr;
   1520  }
   1521 
   1522  IPCWebShareData data(title, text, url);
   1523  auto wgc = mWindow->GetWindowGlobalChild();
   1524  if (!wgc) {
   1525    aRv.Throw(NS_ERROR_FAILURE);
   1526    return nullptr;
   1527  }
   1528 
   1529  // Do the share
   1530  wgc->SendShare(data)->Then(
   1531      GetCurrentSerialEventTarget(), __func__,
   1532      [self = RefPtr{this}](
   1533          PWindowGlobalChild::SharePromise::ResolveOrRejectValue&& aResult) {
   1534        if (aResult.IsResolve()) {
   1535          if (NS_SUCCEEDED(aResult.ResolveValue())) {
   1536            self->mSharePromise->MaybeResolveWithUndefined();
   1537          } else {
   1538            self->mSharePromise->MaybeReject(aResult.ResolveValue());
   1539          }
   1540        } else if (self->mSharePromise) {
   1541          // IPC died
   1542          self->mSharePromise->MaybeReject(NS_BINDING_ABORTED);
   1543        }
   1544        self->mSharePromise = nullptr;
   1545      });
   1546  return do_AddRef(mSharePromise);
   1547 }
   1548 
   1549 //*****************************************************************************
   1550 //    Navigator::CanShare() - Web Share API
   1551 //*****************************************************************************
   1552 bool Navigator::CanShare(const ShareData& aData) {
   1553  if (!mWindow || !mWindow->IsFullyActive()) {
   1554    return false;
   1555  }
   1556 
   1557  if (!FeaturePolicyUtils::IsFeatureAllowed(mWindow->GetExtantDoc(),
   1558                                            u"web-share"_ns)) {
   1559    return false;
   1560  }
   1561 
   1562  IgnoredErrorResult rv;
   1563  ValidateShareData(aData, rv);
   1564  return !rv.Failed();
   1565 }
   1566 
   1567 void Navigator::ValidateShareData(const ShareData& aData, ErrorResult& aRv) {
   1568  // TODO: remove this check when we support files share.
   1569  if (aData.mFiles.WasPassed() && !aData.mFiles.Value().IsEmpty()) {
   1570    aRv.ThrowTypeError("Passing files is currently not supported.");
   1571    return;
   1572  }
   1573 
   1574  bool titleTextOrUrlPassed = aData.mTitle.WasPassed() ||
   1575                              aData.mText.WasPassed() || aData.mUrl.WasPassed();
   1576 
   1577  // At least one member must be present.
   1578  if (!titleTextOrUrlPassed) {
   1579    aRv.ThrowTypeError(
   1580        "Must have a title, text, or url member in the ShareData dictionary");
   1581    return;
   1582  }
   1583 
   1584  // If data's url member is present, try to resolve it...
   1585  nsCOMPtr<nsIURI> url;
   1586  if (aData.mUrl.WasPassed()) {
   1587    Document* doc = mWindow->GetExtantDoc();
   1588    Result<OwningNonNull<nsIURI>, nsresult> result =
   1589        doc->ResolveWithBaseURI(aData.mUrl.Value());
   1590    if (NS_WARN_IF(result.isErr())) {
   1591      aRv.ThrowTypeError<MSG_INVALID_URL>(
   1592          NS_ConvertUTF16toUTF8(aData.mUrl.Value()));
   1593      return;
   1594    }
   1595    url = result.unwrap();
   1596    // Check that we only share loadable URLs (e.g., http/https).
   1597    // we also exclude blobs, as it doesn't make sense to share those outside
   1598    // the context of the browser.
   1599    const uint32_t flags =
   1600        nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL |
   1601        nsIScriptSecurityManager::DISALLOW_SCRIPT;
   1602    if (NS_FAILED(
   1603            nsContentUtils::GetSecurityManager()->CheckLoadURIWithPrincipal(
   1604                doc->NodePrincipal(), url, flags, doc->InnerWindowID())) ||
   1605        url->SchemeIs("blob")) {
   1606      aRv.ThrowTypeError<MSG_INVALID_URL_SCHEME>("Share",
   1607                                                 url->GetSpecOrDefault());
   1608      return;
   1609    }
   1610  }
   1611 }
   1612 
   1613 static bool ShouldResistFingerprinting(const Document* aDoc,
   1614                                       RFPTarget aTarget) {
   1615  return aDoc ? aDoc->ShouldResistFingerprinting(aTarget)
   1616              : nsContentUtils::ShouldResistFingerprinting("Fallback", aTarget);
   1617 }
   1618 
   1619 already_AddRefed<LegacyMozTCPSocket> Navigator::MozTCPSocket() {
   1620  RefPtr<LegacyMozTCPSocket> socket = new LegacyMozTCPSocket(GetWindow());
   1621  return socket.forget();
   1622 }
   1623 
   1624 void Navigator::GetGamepads(nsTArray<RefPtr<Gamepad>>& aGamepads,
   1625                            ErrorResult& aRv) {
   1626  if (!mWindow || !mWindow->IsFullyActive()) {
   1627    return;
   1628  }
   1629  NS_ENSURE_TRUE_VOID(mWindow->GetDocShell());
   1630  nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
   1631 
   1632  if (!FeaturePolicyUtils::IsFeatureAllowed(win->GetExtantDoc(),
   1633                                            u"gamepad"_ns)) {
   1634    aRv.ThrowSecurityError(
   1635        "Document's Permission Policy does not allow calling "
   1636        "getGamepads() from this context.");
   1637    return;
   1638  }
   1639 
   1640  win->SetHasGamepadEventListener(true);
   1641  win->GetGamepads(aGamepads);
   1642 }
   1643 
   1644 GamepadServiceTest* Navigator::RequestGamepadServiceTest(ErrorResult& aRv) {
   1645 #ifdef FUZZING
   1646  if (!StaticPrefs::fuzzing_enabled()) {
   1647    aRv.Throw(NS_ERROR_UNEXPECTED);
   1648    return nullptr;
   1649  }
   1650 #else
   1651  if (!xpc::IsInAutomation()) {
   1652    aRv.Throw(NS_ERROR_UNEXPECTED);
   1653    return nullptr;
   1654  }
   1655 #endif
   1656 
   1657  if (!mGamepadServiceTest) {
   1658    mGamepadServiceTest = GamepadServiceTest::CreateTestService(mWindow);
   1659  }
   1660  return mGamepadServiceTest;
   1661 }
   1662 
   1663 already_AddRefed<Promise> Navigator::RequestAllGamepads(ErrorResult& aRv) {
   1664  if (!mWindow || !mWindow->IsFullyActive()) {
   1665    aRv.Throw(NS_ERROR_UNEXPECTED);
   1666    return nullptr;
   1667  }
   1668 
   1669  nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
   1670 
   1671  // We need to set the flag to trigger the parent process to start monitoring
   1672  // gamepads. Otherwise, we cannot get any gamepad information.
   1673  win->SetHasGamepadEventListener(true);
   1674  return win->RequestAllGamepads(aRv);
   1675 }
   1676 
   1677 already_AddRefed<Promise> Navigator::GetVRDisplays(ErrorResult& aRv) {
   1678  if (!mWindow || !mWindow->GetDocShell() || !mWindow->GetExtantDoc()) {
   1679    aRv.Throw(NS_ERROR_UNEXPECTED);
   1680    return nullptr;
   1681  }
   1682 
   1683  if (!FeaturePolicyUtils::IsFeatureAllowed(mWindow->GetExtantDoc(),
   1684                                            u"vr"_ns)) {
   1685    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
   1686    return nullptr;
   1687  }
   1688 
   1689  RefPtr<Promise> p = Promise::Create(mWindow->AsGlobal(), aRv);
   1690  if (aRv.Failed()) {
   1691    return nullptr;
   1692  }
   1693 
   1694  RefPtr<BrowserChild> browser(BrowserChild::GetFrom(mWindow));
   1695  if (!browser) {
   1696    MOZ_ASSERT(XRE_IsParentProcess());
   1697    FinishGetVRDisplays(true, p);
   1698  } else {
   1699    RefPtr<Navigator> self(this);
   1700    int browserID = browser->ChromeOuterWindowID();
   1701 
   1702    browser->SendIsWindowSupportingWebVR(browserID)->Then(
   1703        GetCurrentSerialEventTarget(), __func__,
   1704        [self, p](bool isSupported) {
   1705          self->FinishGetVRDisplays(isSupported, p);
   1706        },
   1707        [p](const mozilla::ipc::ResponseRejectReason) {
   1708          p->MaybeRejectWithTypeError("Unable to start display enumeration");
   1709        });
   1710  }
   1711 
   1712  return p.forget();
   1713 }
   1714 
   1715 void Navigator::FinishGetVRDisplays(bool isWebVRSupportedInwindow, Promise* p) {
   1716  if (!isWebVRSupportedInwindow) {
   1717    // WebVR in this window is not supported, so resolve the promise
   1718    // with no displays available
   1719    nsTArray<RefPtr<VRDisplay>> vrDisplaysEmpty;
   1720    p->MaybeResolve(vrDisplaysEmpty);
   1721    return;
   1722  }
   1723 
   1724  // Since FinishGetVRDisplays can be called asynchronously after an IPC
   1725  // response, it's possible that the Window can be torn down before this
   1726  // call. In that case, the Window's cyclic references to VR objects are
   1727  // also torn down and should not be recreated via
   1728  // NotifyHasXRSession.
   1729  nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
   1730  if (win->IsDying()) {
   1731    // The Window has been torn down, so there is no further work that can
   1732    // be done.
   1733    p->MaybeRejectWithTypeError(
   1734        "Unable to return VRDisplays for a closed window.");
   1735    return;
   1736  }
   1737 
   1738  mVRGetDisplaysPromises.AppendElement(p);
   1739  win->RequestXRPermission();
   1740 }
   1741 
   1742 void Navigator::OnXRPermissionRequestAllow() {
   1743  // The permission request that results in this callback could have
   1744  // been instantiated by WebVR, WebXR, or both.
   1745  nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
   1746  bool usingWebXR = false;
   1747 
   1748  if (mXRSystem) {
   1749    usingWebXR = mXRSystem->OnXRPermissionRequestAllow();
   1750  }
   1751 
   1752  bool rejectWebVR = true;
   1753  // If WebVR and WebXR both requested permission, only grant it to
   1754  // WebXR, which takes priority.
   1755  if (!usingWebXR) {
   1756    // We pass mWindow's id to RefreshVRDisplays, so NotifyVRDisplaysUpdated
   1757    // will be called asynchronously, resolving the promises in
   1758    // mVRGetDisplaysPromises.
   1759    rejectWebVR = !VRDisplay::RefreshVRDisplays(win->WindowID());
   1760  }
   1761  // Even if WebXR took priority, reject requests for WebVR in case they were
   1762  // made simultaneously and coelesced into a single permission prompt.
   1763  if (rejectWebVR) {
   1764    for (auto& p : mVRGetDisplaysPromises) {
   1765      // Failed to refresh, reject the promise now
   1766      p->MaybeRejectWithTypeError("Failed to find attached VR displays.");
   1767    }
   1768    mVRGetDisplaysPromises.Clear();
   1769  }
   1770 }
   1771 
   1772 void Navigator::OnXRPermissionRequestCancel() {
   1773  if (mXRSystem) {
   1774    mXRSystem->OnXRPermissionRequestCancel();
   1775  }
   1776 
   1777  nsTArray<RefPtr<VRDisplay>> vrDisplays;
   1778  for (auto& p : mVRGetDisplaysPromises) {
   1779    // Resolve the promise with no vr displays when
   1780    // the user blocks access.
   1781    p->MaybeResolve(vrDisplays);
   1782  }
   1783  mVRGetDisplaysPromises.Clear();
   1784 }
   1785 
   1786 void Navigator::GetActiveVRDisplays(
   1787    nsTArray<RefPtr<VRDisplay>>& aDisplays) const {
   1788  /**
   1789   * Get only the active VR displays.
   1790   * GetActiveVRDisplays should only enumerate displays that
   1791   * are already active without causing any other hardware to be
   1792   * activated.
   1793   * We must not call nsGlobalWindowInner::NotifyHasXRSession here,
   1794   * as that would cause enumeration and activation of other VR hardware.
   1795   * Activating VR hardware is intrusive to the end user, as it may
   1796   * involve physically powering on devices that the user did not
   1797   * intend to use.
   1798   */
   1799  if (!mWindow || !mWindow->GetDocShell()) {
   1800    return;
   1801  }
   1802  nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
   1803  nsTArray<RefPtr<VRDisplay>> displays;
   1804  if (win->UpdateVRDisplays(displays)) {
   1805    for (auto display : displays) {
   1806      if (display->IsPresenting()) {
   1807        aDisplays.AppendElement(display);
   1808      }
   1809    }
   1810  }
   1811 }
   1812 
   1813 void Navigator::NotifyVRDisplaysUpdated() {
   1814  // Synchronize the VR devices and resolve the promises in
   1815  // mVRGetDisplaysPromises
   1816  nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
   1817 
   1818  nsTArray<RefPtr<VRDisplay>> vrDisplays;
   1819  if (win->UpdateVRDisplays(vrDisplays)) {
   1820    for (auto p : mVRGetDisplaysPromises) {
   1821      p->MaybeResolve(vrDisplays);
   1822    }
   1823  } else {
   1824    for (auto p : mVRGetDisplaysPromises) {
   1825      p->MaybeReject(NS_ERROR_FAILURE);
   1826    }
   1827  }
   1828  mVRGetDisplaysPromises.Clear();
   1829 }
   1830 
   1831 void Navigator::NotifyActiveVRDisplaysChanged() {
   1832  Navigator_Binding::ClearCachedActiveVRDisplaysValue(this);
   1833 }
   1834 
   1835 VRServiceTest* Navigator::RequestVRServiceTest(ErrorResult& aRv) {
   1836  if (!xpc::IsInAutomation()) {
   1837    aRv.Throw(NS_ERROR_UNEXPECTED);
   1838    return nullptr;
   1839  }
   1840 
   1841  // Ensure that the Mock VR devices are not released prematurely
   1842  nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
   1843  win->NotifyHasXRSession();
   1844 
   1845  if (!mVRServiceTest) {
   1846    mVRServiceTest = VRServiceTest::CreateTestService(mWindow);
   1847  }
   1848  return mVRServiceTest;
   1849 }
   1850 
   1851 XRSystem* Navigator::GetXr(ErrorResult& aRv) {
   1852  if (!mWindow) {
   1853    aRv.Throw(NS_ERROR_UNEXPECTED);
   1854    return nullptr;
   1855  }
   1856  if (!mXRSystem) {
   1857    mXRSystem = XRSystem::Create(mWindow);
   1858  }
   1859  return mXRSystem;
   1860 }
   1861 
   1862 bool Navigator::IsWebVRContentDetected() const {
   1863  nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
   1864  return win->IsVRContentDetected();
   1865 }
   1866 
   1867 bool Navigator::IsWebVRContentPresenting() const {
   1868  nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
   1869  return win->IsVRContentPresenting();
   1870 }
   1871 
   1872 void Navigator::RequestVRPresentation(VRDisplay& aDisplay) {
   1873  nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
   1874  win->DispatchVRDisplayActivate(aDisplay.DisplayId(),
   1875                                 VRDisplayEventReason::Requested);
   1876 }
   1877 
   1878 already_AddRefed<Promise> Navigator::RequestMIDIAccess(
   1879    const MIDIOptions& aOptions, ErrorResult& aRv) {
   1880  if (!mWindow) {
   1881    aRv.Throw(NS_ERROR_UNEXPECTED);
   1882    return nullptr;
   1883  }
   1884  MIDIAccessManager* accessMgr = MIDIAccessManager::Get();
   1885  return accessMgr->RequestMIDIAccess(mWindow, aOptions, aRv);
   1886 }
   1887 
   1888 network::Connection* Navigator::GetConnection(ErrorResult& aRv) {
   1889  if (!mConnection) {
   1890    if (!mWindow) {
   1891      aRv.Throw(NS_ERROR_UNEXPECTED);
   1892      return nullptr;
   1893    }
   1894    mConnection = network::Connection::CreateForWindow(
   1895        mWindow, nsGlobalWindowInner::Cast(mWindow)->ShouldResistFingerprinting(
   1896                     RFPTarget::NetworkConnection));
   1897  }
   1898 
   1899  return mConnection;
   1900 }
   1901 
   1902 already_AddRefed<ServiceWorkerContainer> Navigator::ServiceWorker() {
   1903  MOZ_ASSERT(mWindow);
   1904 
   1905  if (!mServiceWorkerContainer) {
   1906    mServiceWorkerContainer =
   1907        ServiceWorkerContainer::Create(mWindow->AsGlobal());
   1908  }
   1909 
   1910  RefPtr<ServiceWorkerContainer> ref = mServiceWorkerContainer;
   1911  return ref.forget();
   1912 }
   1913 
   1914 already_AddRefed<ServiceWorkerContainer> Navigator::ServiceWorkerJS() {
   1915  if (mWindow->AsGlobal()->GetStorageAccess() ==
   1916      StorageAccess::ePrivateBrowsing) {
   1917    SetUseCounter(mWindow->AsGlobal()->GetGlobalJSObject(),
   1918                  eUseCounter_custom_PrivateBrowsingNavigatorServiceWorker);
   1919  }
   1920 
   1921  return ServiceWorker();
   1922 }
   1923 
   1924 size_t Navigator::SizeOfIncludingThis(
   1925    mozilla::MallocSizeOf aMallocSizeOf) const {
   1926  size_t n = aMallocSizeOf(this);
   1927 
   1928  // TODO: add SizeOfIncludingThis() to nsMimeTypeArray, bug 674113.
   1929  // TODO: add SizeOfIncludingThis() to nsPluginArray, bug 674114.
   1930  // TODO: add SizeOfIncludingThis() to Geolocation, bug 674115.
   1931  // TODO: add SizeOfIncludingThis() to DesktopNotificationCenter, bug 674116.
   1932 
   1933  return n;
   1934 }
   1935 
   1936 void Navigator::OnNavigation() {
   1937  if (!mWindow) {
   1938    return;
   1939  }
   1940 
   1941  // If MediaManager is open let it inform any live streams or pending callbacks
   1942  MediaManager* manager = MediaManager::GetIfExists();
   1943  if (manager) {
   1944    manager->OnNavigation(mWindow->WindowID());
   1945  }
   1946 }
   1947 
   1948 JSObject* Navigator::WrapObject(JSContext* cx,
   1949                                JS::Handle<JSObject*> aGivenProto) {
   1950  return Navigator_Binding::Wrap(cx, this, aGivenProto);
   1951 }
   1952 
   1953 /* static */
   1954 bool Navigator::HasUserMediaSupport(JSContext* cx, JSObject* obj) {
   1955  // Make enabling peerconnection enable getUserMedia() as well.
   1956  // Emulate [SecureContext] unless media.devices.insecure.enabled=true
   1957  return (StaticPrefs::media_navigator_enabled() ||
   1958          StaticPrefs::media_peerconnection_enabled()) &&
   1959         (IsSecureContextOrObjectIsFromSecureContext(cx, obj) ||
   1960          StaticPrefs::media_devices_insecure_enabled());
   1961 }
   1962 
   1963 /* static */
   1964 bool Navigator::MozGetUserMediaSupport(JSContext* aCx, JSObject* aObj) {
   1965  return StaticPrefs::media_navigator_mozgetusermedia_enabled() &&
   1966         Navigator::HasUserMediaSupport(aCx, aObj);
   1967 }
   1968 
   1969 /* static */
   1970 bool Navigator::HasShareSupport(JSContext* cx, JSObject* obj) {
   1971  if (!StaticPrefs::dom_webshare_enabled()) {
   1972    return false;
   1973  }
   1974 #if defined(XP_WIN) && !defined(__MINGW32__)
   1975  // The first public build that supports ShareCanceled API
   1976  return IsWindows10BuildOrLater(18956);
   1977 #else
   1978  return true;
   1979 #endif
   1980 }
   1981 
   1982 /* static */
   1983 bool Navigator::HasMidiSupport(JSContext* cx, JSObject* obj) {
   1984  nsIPrincipal* principal = nsContentUtils::SubjectPrincipal(cx);
   1985 
   1986  // Enable on secure contexts but exclude file schemes.
   1987  return StaticPrefs::dom_webmidi_enabled() &&
   1988         IsSecureContextOrObjectIsFromSecureContext(cx, obj) &&
   1989         !principal->SchemeIs("file");
   1990 }
   1991 
   1992 /* static */
   1993 already_AddRefed<nsPIDOMWindowInner> Navigator::GetWindowFromGlobal(
   1994    JSObject* aGlobal) {
   1995  nsCOMPtr<nsPIDOMWindowInner> win = xpc::WindowOrNull(aGlobal);
   1996  return win.forget();
   1997 }
   1998 
   1999 void Navigator::ClearPlatformCache() {
   2000  Navigator_Binding::ClearCachedPlatformValue(this);
   2001 }
   2002 
   2003 void Navigator::ClearLanguageCache() {
   2004  Navigator_Binding::ClearCachedLanguageValue(this);
   2005  Navigator_Binding::ClearCachedLanguagesValue(this);
   2006 }
   2007 
   2008 nsresult Navigator::GetPlatform(nsAString& aPlatform, Document* aCallerDoc,
   2009                                bool aUsePrefOverriddenValue) {
   2010  MOZ_ASSERT(NS_IsMainThread());
   2011 
   2012  // navigator.platform is the same for default and spoofed values. The
   2013  // "general.platform.override" pref should override the default platform,
   2014  // but the spoofed platform should override the pref.
   2015  if (aUsePrefOverriddenValue &&
   2016      !ShouldResistFingerprinting(aCallerDoc, RFPTarget::NavigatorPlatform)) {
   2017    nsAutoString override;
   2018    nsresult rv =
   2019        mozilla::Preferences::GetString("general.platform.override", override);
   2020 
   2021    if (NS_SUCCEEDED(rv)) {
   2022      aPlatform = override;
   2023      return NS_OK;
   2024    }
   2025  }
   2026 
   2027 #if defined(WIN32)
   2028  aPlatform.AssignLiteral("Win32");
   2029 #elif defined(XP_MACOSX)
   2030  // Always return "MacIntel", even on ARM64 macOS like Safari does.
   2031  aPlatform.AssignLiteral("MacIntel");
   2032 #elif defined(ANDROID)
   2033  aPlatform.AssignLiteral("Linux armv81");
   2034 #else
   2035  aPlatform.AssignLiteral("Linux x86_64");
   2036 #endif
   2037 
   2038  return NS_OK;
   2039 }
   2040 
   2041 /* static */
   2042 nsresult Navigator::GetAppVersion(nsAString& aAppVersion, Document* aCallerDoc,
   2043                                  bool aUsePrefOverriddenValue) {
   2044  MOZ_ASSERT(NS_IsMainThread());
   2045 
   2046  if (aUsePrefOverriddenValue) {
   2047    // If fingerprinting resistance is on, we will spoof this value. See
   2048    // nsRFPService.h for details about spoofed values.
   2049    if (ShouldResistFingerprinting(aCallerDoc,
   2050                                   RFPTarget::NavigatorAppVersion)) {
   2051      aAppVersion.AssignLiteral(SPOOFED_APPVERSION);
   2052      return NS_OK;
   2053    }
   2054    nsAutoString override;
   2055    nsresult rv = mozilla::Preferences::GetString("general.appversion.override",
   2056                                                  override);
   2057 
   2058    if (NS_SUCCEEDED(rv)) {
   2059      aAppVersion = override;
   2060      return NS_OK;
   2061    }
   2062  }
   2063 
   2064  nsresult rv;
   2065 
   2066  nsCOMPtr<nsIHttpProtocolHandler> service(
   2067      do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
   2068  NS_ENSURE_SUCCESS(rv, rv);
   2069 
   2070  nsAutoCString str;
   2071  rv = service->GetAppVersion(str);
   2072  CopyASCIItoUTF16(str, aAppVersion);
   2073  NS_ENSURE_SUCCESS(rv, rv);
   2074 
   2075  aAppVersion.AppendLiteral(" (");
   2076 
   2077  rv = service->GetPlatform(str);
   2078  NS_ENSURE_SUCCESS(rv, rv);
   2079 
   2080  AppendASCIItoUTF16(str, aAppVersion);
   2081  aAppVersion.Append(char16_t(')'));
   2082 
   2083  return rv;
   2084 }
   2085 
   2086 void Navigator::ClearUserAgentCache() {
   2087  Navigator_Binding::ClearCachedUserAgentValue(this);
   2088 }
   2089 
   2090 nsresult Navigator::GetUserAgent(nsPIDOMWindowInner* aWindow,
   2091                                 Document* aCallerDoc,
   2092                                 Maybe<bool> aShouldResistFingerprinting,
   2093                                 nsAString& aUserAgent) {
   2094  MOZ_ASSERT(NS_IsMainThread());
   2095 
   2096  /*
   2097    ResistFingerprinting is migrating to fine-grained control based off
   2098    either a channel or Principal+OriginAttributes
   2099 
   2100    This function can be called from Workers, Main Thread, and at least one
   2101    other (unusual) case.
   2102 
   2103    For Main Thread, we will generally have a window and an associated
   2104    Document, for Workers we will not.
   2105 
   2106    If aShouldResistFingerprinting is provided, we should respect it.
   2107    If it is not provided, we will use aCallerDoc to determine our behavior.
   2108  */
   2109 
   2110  bool shouldResistFingerprinting =
   2111      aShouldResistFingerprinting.isSome()
   2112          ? aShouldResistFingerprinting.value()
   2113          : ShouldResistFingerprinting(aCallerDoc,
   2114                                       RFPTarget::NavigatorUserAgent);
   2115 
   2116  // We will skip the override and pass to httpHandler to get spoofed userAgent
   2117  // when 'privacy.resistFingerprinting' is true.
   2118  if (!shouldResistFingerprinting) {
   2119    nsAutoString override;
   2120    nsresult rv =
   2121        mozilla::Preferences::GetString("general.useragent.override", override);
   2122 
   2123    if (NS_SUCCEEDED(rv)) {
   2124      aUserAgent = override;
   2125      return NS_OK;
   2126    }
   2127  }
   2128 
   2129  // When the caller is content and 'privacy.resistFingerprinting' is true,
   2130  // return a spoofed userAgent which reveals the platform but not the
   2131  // specific OS version, etc.
   2132  if (shouldResistFingerprinting) {
   2133    nsAutoCString spoofedUA;
   2134    nsRFPService::GetSpoofedUserAgent(spoofedUA);
   2135    CopyASCIItoUTF16(spoofedUA, aUserAgent);
   2136    return NS_OK;
   2137  }
   2138 
   2139  nsresult rv;
   2140  nsCOMPtr<nsIHttpProtocolHandler> service(
   2141      do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
   2142  if (NS_WARN_IF(NS_FAILED(rv))) {
   2143    return rv;
   2144  }
   2145 
   2146  nsAutoCString ua;
   2147  rv = service->GetUserAgent(ua);
   2148  if (NS_WARN_IF(NS_FAILED(rv))) {
   2149    return rv;
   2150  }
   2151 
   2152  CopyASCIItoUTF16(ua, aUserAgent);
   2153 
   2154  if (!aWindow) {
   2155    return NS_OK;
   2156  }
   2157 
   2158  // Copy the User-Agent header from the document channel which has already been
   2159  // subject to UA overrides.
   2160  nsCOMPtr<Document> doc = aWindow->GetExtantDoc();
   2161  if (!doc) {
   2162    return NS_OK;
   2163  }
   2164  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(doc->GetChannel());
   2165  if (httpChannel) {
   2166    bool IsUserAgentHeaderOutdated;
   2167    (void)httpChannel->GetIsUserAgentHeaderOutdated(&IsUserAgentHeaderOutdated);
   2168 
   2169    // Do not return user agent from the request
   2170    // if the user agent of the channel is outdated.
   2171    if (!IsUserAgentHeaderOutdated) {
   2172      nsAutoCString userAgent;
   2173      rv = httpChannel->GetRequestHeader("User-Agent"_ns, userAgent);
   2174      if (NS_WARN_IF(NS_FAILED(rv))) {
   2175        return rv;
   2176      }
   2177      CopyASCIItoUTF16(userAgent, aUserAgent);
   2178    }
   2179  }
   2180  return NS_OK;
   2181 }
   2182 
   2183 static nsCString RequestKeySystemAccessLogString(
   2184    const nsAString& aKeySystem,
   2185    const Sequence<MediaKeySystemConfiguration>& aConfigs,
   2186    bool aIsSecureContext) {
   2187  nsCString str;
   2188  str.AppendPrintf(
   2189      "Navigator::RequestMediaKeySystemAccess(keySystem='%s' options=",
   2190      NS_ConvertUTF16toUTF8(aKeySystem).get());
   2191  str.Append(MediaKeySystemAccess::ToCString(aConfigs));
   2192  str.AppendLiteral(") secureContext=");
   2193  str.AppendInt(aIsSecureContext);
   2194  return str;
   2195 }
   2196 
   2197 already_AddRefed<Promise> Navigator::RequestMediaKeySystemAccess(
   2198    const nsAString& aKeySystem,
   2199    const Sequence<MediaKeySystemConfiguration>& aConfigs, ErrorResult& aRv) {
   2200  EME_LOG("%s", RequestKeySystemAccessLogString(aKeySystem, aConfigs,
   2201                                                mWindow->IsSecureContext())
   2202                    .get());
   2203 
   2204  if (!mWindow->IsSecureContext()) {
   2205    Document* doc = mWindow->GetExtantDoc();
   2206    AutoTArray<nsString, 1> params;
   2207    nsString* uri = params.AppendElement();
   2208    if (doc) {
   2209      (void)doc->GetDocumentURI(*uri);
   2210    }
   2211    nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, "Media"_ns,
   2212                                    doc, nsContentUtils::eDOM_PROPERTIES,
   2213                                    "MediaEMEInsecureContextDeprecatedWarning",
   2214                                    params);
   2215  }
   2216 
   2217  Document* doc = mWindow->GetExtantDoc();
   2218  if (doc &&
   2219      !FeaturePolicyUtils::IsFeatureAllowed(doc, u"encrypted-media"_ns)) {
   2220    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
   2221    return nullptr;
   2222  }
   2223 
   2224  RefPtr<DetailedPromise> promise = DetailedPromise::Create(
   2225      mWindow->AsGlobal(), aRv, "navigator.requestMediaKeySystemAccess"_ns);
   2226  if (aRv.Failed()) {
   2227    return nullptr;
   2228  }
   2229 
   2230  GetOrCreateMediaKeySystemAccessManager()->Request(promise, aKeySystem,
   2231                                                    aConfigs);
   2232  return promise.forget();
   2233 }
   2234 
   2235 MediaKeySystemAccessManager*
   2236 Navigator::GetOrCreateMediaKeySystemAccessManager() {
   2237  if (!mMediaKeySystemAccessManager) {
   2238    mMediaKeySystemAccessManager = new MediaKeySystemAccessManager(mWindow);
   2239  }
   2240  return mMediaKeySystemAccessManager;
   2241 }
   2242 
   2243 CredentialsContainer* Navigator::Credentials() {
   2244  if (!mCredentials) {
   2245    mCredentials = new CredentialsContainer(GetWindow());
   2246  }
   2247  return mCredentials;
   2248 }
   2249 
   2250 dom::MediaCapabilities* Navigator::MediaCapabilities() {
   2251  if (!mMediaCapabilities) {
   2252    mMediaCapabilities = new dom::MediaCapabilities(GetWindow()->AsGlobal());
   2253  }
   2254  return mMediaCapabilities;
   2255 }
   2256 
   2257 dom::MediaSession* Navigator::MediaSession() {
   2258  if (!mMediaSession) {
   2259    mMediaSession = new dom::MediaSession(GetWindow());
   2260  }
   2261  return mMediaSession;
   2262 }
   2263 
   2264 bool Navigator::HasCreatedMediaSession() const {
   2265  return mMediaSession != nullptr;
   2266 }
   2267 
   2268 Clipboard* Navigator::Clipboard() {
   2269  if (!mClipboard) {
   2270    mClipboard = new dom::Clipboard(GetWindow());
   2271  }
   2272  return mClipboard;
   2273 }
   2274 
   2275 AddonManager* Navigator::GetMozAddonManager(ErrorResult& aRv) {
   2276  if (!mAddonManager) {
   2277    nsPIDOMWindowInner* win = GetWindow();
   2278    if (!win) {
   2279      aRv.Throw(NS_ERROR_UNEXPECTED);
   2280      return nullptr;
   2281    }
   2282 
   2283    mAddonManager = ConstructJSImplementation<AddonManager>(
   2284        "@mozilla.org/addon-web-api/manager;1", win->AsGlobal(), aRv);
   2285    if (aRv.Failed()) {
   2286      return nullptr;
   2287    }
   2288  }
   2289 
   2290  return mAddonManager;
   2291 }
   2292 
   2293 webgpu::Instance* Navigator::Gpu() {
   2294  if (!mWebGpu) {
   2295    mWebGpu = webgpu::Instance::Create(GetWindow()->AsGlobal());
   2296  }
   2297  return mWebGpu;
   2298 }
   2299 
   2300 dom::LockManager* Navigator::Locks() {
   2301  if (!mLocks) {
   2302    mLocks = dom::LockManager::Create(*GetWindow()->AsGlobal());
   2303  }
   2304  return mLocks;
   2305 }
   2306 
   2307 NavigatorLogin* Navigator::Login() {
   2308  if (!mLogin) {
   2309    mLogin = new NavigatorLogin(GetWindow());
   2310  }
   2311  return mLogin;
   2312 }
   2313 
   2314 dom::PrivateAttribution* Navigator::PrivateAttribution() {
   2315  if (!mPrivateAttribution) {
   2316    mPrivateAttribution = new dom::PrivateAttribution(GetWindow()->AsGlobal());
   2317  }
   2318  return mPrivateAttribution;
   2319 }
   2320 
   2321 /* static */
   2322 bool Navigator::Webdriver() {
   2323 #ifdef ENABLE_WEBDRIVER
   2324  nsCOMPtr<nsIMarionette> marionette = do_GetService(NS_MARIONETTE_CONTRACTID);
   2325  if (marionette) {
   2326    bool marionetteRunning = false;
   2327    marionette->GetRunning(&marionetteRunning);
   2328    if (marionetteRunning) {
   2329      return true;
   2330    }
   2331  }
   2332 
   2333  nsCOMPtr<nsIRemoteAgent> agent = do_GetService(NS_REMOTEAGENT_CONTRACTID);
   2334  if (agent) {
   2335    bool remoteAgentRunning = false;
   2336    agent->GetRunning(&remoteAgentRunning);
   2337    if (remoteAgentRunning) {
   2338      return true;
   2339    }
   2340  }
   2341 #endif
   2342 
   2343  return false;
   2344 }
   2345 
   2346 AutoplayPolicy Navigator::GetAutoplayPolicy(AutoplayPolicyMediaType aType) {
   2347  if (!mWindow) {
   2348    return AutoplayPolicy::Disallowed;
   2349  }
   2350  nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
   2351  if (!doc) {
   2352    return AutoplayPolicy::Disallowed;
   2353  }
   2354  return media::AutoplayPolicy::GetAutoplayPolicy(aType, *doc);
   2355 }
   2356 
   2357 AutoplayPolicy Navigator::GetAutoplayPolicy(HTMLMediaElement& aElement) {
   2358  return media::AutoplayPolicy::GetAutoplayPolicy(aElement);
   2359 }
   2360 
   2361 AutoplayPolicy Navigator::GetAutoplayPolicy(AudioContext& aContext) {
   2362  return media::AutoplayPolicy::GetAutoplayPolicy(aContext);
   2363 }
   2364 
   2365 already_AddRefed<dom::UserActivation> Navigator::UserActivation() {
   2366  if (!mUserActivation) {
   2367    mUserActivation = new dom::UserActivation(GetWindow());
   2368  }
   2369  return do_AddRef(mUserActivation);
   2370 }
   2371 
   2372 dom::WakeLockJS* Navigator::WakeLock() {
   2373  if (!mWakeLock) {
   2374    mWakeLock = new WakeLockJS(mWindow);
   2375  }
   2376  return mWakeLock;
   2377 }
   2378 
   2379 }  // namespace mozilla::dom