Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / dom / base / Navigator.cpp
blob14a00b8ed85f69312a89990acbb5e0f9755bd832
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/. */
7 // Needs to be first.
8 #include "base/basictypes.h"
10 #include "Navigator.h"
11 #include "nsIXULAppInfo.h"
12 #include "nsPluginArray.h"
13 #include "nsMimeTypeArray.h"
14 #include "mozilla/Components.h"
15 #include "mozilla/ContentBlockingNotifier.h"
16 #include "mozilla/MemoryReporting.h"
17 #include "mozilla/dom/BodyExtractor.h"
18 #include "mozilla/dom/FetchBinding.h"
19 #include "mozilla/dom/File.h"
20 #include "Geolocation.h"
21 #include "nsIClassOfService.h"
22 #include "nsIHttpProtocolHandler.h"
23 #include "nsIContentPolicy.h"
24 #include "nsContentPolicyUtils.h"
25 #include "nsISupportsPriority.h"
26 #include "nsIWebProtocolHandlerRegistrar.h"
27 #include "nsCharSeparatedTokenizer.h"
28 #include "nsContentUtils.h"
29 #include "nsUnicharUtils.h"
30 #include "mozilla/Preferences.h"
31 #include "mozilla/StaticPrefs_dom.h"
32 #ifdef FUZZING
33 # include "mozilla/StaticPrefs_fuzzing.h"
34 #endif
35 #include "mozilla/StaticPrefs_media.h"
36 #include "mozilla/StaticPrefs_network.h"
37 #include "mozilla/StaticPrefs_pdfjs.h"
38 #include "mozilla/StaticPrefs_privacy.h"
39 #include "mozilla/StorageAccess.h"
40 #include "mozilla/Telemetry.h"
41 #include "BatteryManager.h"
42 #include "mozilla/dom/CredentialsContainer.h"
43 #include "mozilla/dom/Clipboard.h"
44 #include "mozilla/dom/FeaturePolicyUtils.h"
45 #include "mozilla/dom/GamepadServiceTest.h"
46 #include "mozilla/dom/MediaCapabilities.h"
47 #include "mozilla/dom/MediaSession.h"
48 #include "mozilla/dom/power/PowerManagerService.h"
49 #include "mozilla/dom/LockManager.h"
50 #include "mozilla/dom/MIDIAccessManager.h"
51 #include "mozilla/dom/MIDIOptionsBinding.h"
52 #include "mozilla/dom/Permissions.h"
53 #include "mozilla/dom/ServiceWorkerContainer.h"
54 #include "mozilla/dom/StorageManager.h"
55 #include "mozilla/dom/TCPSocket.h"
56 #include "mozilla/dom/URLSearchParams.h"
57 #include "mozilla/dom/UserActivation.h"
58 #include "mozilla/dom/VRDisplay.h"
59 #include "mozilla/dom/VRDisplayEvent.h"
60 #include "mozilla/dom/VRServiceTest.h"
61 #include "mozilla/dom/XRSystem.h"
62 #include "mozilla/dom/workerinternals/RuntimeService.h"
63 #include "mozilla/dom/WakeLockJS.h"
64 #include "mozilla/Hal.h"
65 #include "mozilla/ClearOnShutdown.h"
66 #include "mozilla/StaticPtr.h"
67 #include "Connection.h"
68 #include "mozilla/dom/Event.h" // for Event
69 #include "nsGlobalWindowInner.h"
70 #include "nsIPermissionManager.h"
71 #include "nsMimeTypes.h"
72 #include "nsNetUtil.h"
73 #include "nsRFPService.h"
74 #include "nsStringStream.h"
75 #include "nsComponentManagerUtils.h"
76 #include "nsICookieManager.h"
77 #include "nsICookieService.h"
78 #include "nsIHttpChannel.h"
79 #ifdef ENABLE_WEBDRIVER
80 # include "nsIMarionette.h"
81 # include "nsIRemoteAgent.h"
82 #endif
83 #include "nsStreamUtils.h"
84 #include "WidgetUtils.h"
85 #include "nsIScriptError.h"
86 #include "ReferrerInfo.h"
87 #include "mozilla/PermissionDelegateHandler.h"
89 #include "nsIExternalProtocolHandler.h"
90 #include "BrowserChild.h"
91 #include "mozilla/ipc/URIUtils.h"
93 #include "mozilla/dom/MediaDevices.h"
94 #include "MediaManager.h"
96 #include "nsJSUtils.h"
98 #include "mozilla/dom/Promise.h"
100 #include "nsIUploadChannel2.h"
101 #include "mozilla/dom/FormData.h"
102 #include "nsIDocShell.h"
104 #include "mozilla/dom/WorkerPrivate.h"
105 #include "mozilla/dom/WorkerRunnable.h"
107 #if defined(XP_WIN)
108 # include "mozilla/WindowsVersion.h"
109 #endif
111 #include "mozilla/EMEUtils.h"
112 #include "mozilla/DetailedPromise.h"
113 #include "mozilla/Unused.h"
115 #include "mozilla/webgpu/Instance.h"
116 #include "mozilla/dom/WindowGlobalChild.h"
118 #include "mozilla/intl/LocaleService.h"
119 #include "mozilla/dom/AudioContext.h"
120 #include "mozilla/dom/HTMLMediaElement.h"
121 #include "AutoplayPolicy.h"
123 namespace mozilla::dom {
125 static const nsLiteralCString kVibrationPermissionType = "vibration"_ns;
127 Navigator::Navigator(nsPIDOMWindowInner* aWindow) : mWindow(aWindow) {}
129 Navigator::~Navigator() { Invalidate(); }
131 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Navigator)
132 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
133 NS_INTERFACE_MAP_ENTRY(nsISupports)
134 NS_INTERFACE_MAP_END
136 NS_IMPL_CYCLE_COLLECTING_ADDREF(Navigator)
137 NS_IMPL_CYCLE_COLLECTING_RELEASE(Navigator)
139 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(Navigator)
141 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Navigator)
142 tmp->Invalidate();
143 NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
144 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSharePromise)
145 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
146 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
148 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
149 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlugins)
150 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPermissions)
151 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGeolocation)
152 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryManager)
153 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryPromise)
154 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
155 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStorageManager)
156 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCredentials)
157 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaDevices)
158 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerContainer)
159 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaCapabilities)
160 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaSession)
161 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAddonManager)
162 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebGpu)
163 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocks)
164 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUserActivation)
165 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWakeLock)
167 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
168 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaKeySystemAccessManager)
169 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGamepadServiceTest)
170 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVRGetDisplaysPromises)
171 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVRServiceTest)
172 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSharePromise)
173 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mXRSystem)
174 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mClipboard)
175 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
177 void Navigator::Invalidate() {
178 // Don't clear mWindow here so we know we've got a non-null mWindow
179 // until we're unlinked.
181 mPlugins = nullptr;
183 mPermissions = nullptr;
185 if (mStorageManager) {
186 mStorageManager->Shutdown();
187 mStorageManager = nullptr;
190 // If there is a page transition, make sure delete the geolocation object.
191 if (mGeolocation) {
192 mGeolocation->Shutdown();
193 mGeolocation = nullptr;
196 if (mBatteryManager) {
197 mBatteryManager->Shutdown();
198 mBatteryManager = nullptr;
201 mBatteryPromise = nullptr;
203 if (mConnection) {
204 mConnection->Shutdown();
205 mConnection = nullptr;
208 mMediaDevices = nullptr;
210 mServiceWorkerContainer = nullptr;
212 if (mMediaKeySystemAccessManager) {
213 mMediaKeySystemAccessManager->Shutdown();
214 mMediaKeySystemAccessManager = nullptr;
217 if (mGamepadServiceTest) {
218 mGamepadServiceTest->Shutdown();
219 mGamepadServiceTest = nullptr;
222 mVRGetDisplaysPromises.Clear();
224 if (mVRServiceTest) {
225 mVRServiceTest->Shutdown();
226 mVRServiceTest = nullptr;
229 if (mXRSystem) {
230 mXRSystem->Shutdown();
231 mXRSystem = nullptr;
234 mMediaCapabilities = nullptr;
236 if (mMediaSession) {
237 mMediaSession->Shutdown();
238 mMediaSession = nullptr;
241 mAddonManager = nullptr;
243 mWebGpu = nullptr;
245 if (mLocks) {
246 // Unloading a page does not immediately destruct the lock manager actor,
247 // but we want to abort the lock requests as soon as possible. Explicitly
248 // call Shutdown() to do that.
249 mLocks->Shutdown();
250 mLocks = nullptr;
253 mUserActivation = nullptr;
255 mSharePromise = nullptr;
257 mWakeLock = nullptr;
259 mClipboard = nullptr;
262 void Navigator::GetUserAgent(nsAString& aUserAgent, CallerType aCallerType,
263 ErrorResult& aRv) const {
264 nsCOMPtr<nsPIDOMWindowInner> window;
266 if (mWindow) {
267 window = mWindow;
268 nsIDocShell* docshell = window->GetDocShell();
269 nsString customUserAgent;
270 if (docshell) {
271 docshell->GetBrowsingContext()->GetCustomUserAgent(customUserAgent);
273 if (!customUserAgent.IsEmpty()) {
274 aUserAgent = customUserAgent;
275 return;
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);
289 void Navigator::GetAppCodeName(nsAString& aAppCodeName, ErrorResult& aRv) {
290 nsresult rv;
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;
299 nsAutoCString appName;
300 rv = service->GetAppName(appName);
301 if (NS_WARN_IF(NS_FAILED(rv))) {
302 aRv.Throw(rv);
303 return;
306 CopyASCIItoUTF16(appName, aAppCodeName);
309 void Navigator::GetAppVersion(nsAString& aAppVersion, CallerType aCallerType,
310 ErrorResult& aRv) const {
311 nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
313 nsresult rv = GetAppVersion(
314 aAppVersion, doc,
315 /* aUsePrefOverriddenValue = */ aCallerType != CallerType::System);
316 if (NS_WARN_IF(NS_FAILED(rv))) {
317 aRv.Throw(rv);
321 void Navigator::GetAppName(nsAString& aAppName) const {
322 aAppName.AssignLiteral("Netscape");
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").
330 * "en", "en-US" and "i-cherokee" and "" are valid languages tokens.
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.
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.
340 /* static */
341 void Navigator::GetAcceptLanguages(nsTArray<nsString>& aLanguages) {
342 MOZ_ASSERT(NS_IsMainThread());
344 aLanguages.Clear();
346 // E.g. "de-de, en-us,en".
347 nsAutoString acceptLang;
348 Preferences::GetLocalizedString("intl.accept_languages", acceptLang);
350 // Split values on commas.
351 for (nsDependentSubstring lang :
352 nsCharSeparatedTokenizer(acceptLang, ',').ToRange()) {
353 // Replace "_" with "-" to avoid POSIX/Windows "en_US" notation.
354 // NOTE: we should probably rely on the pref being set correctly.
355 if (lang.Length() > 2 && lang[2] == char16_t('_')) {
356 lang.Replace(2, 1, char16_t('-'));
359 // Use uppercase for country part, e.g. "en-US", not "en-us", see BCP47
360 // only uppercase 2-letter country codes, not "zh-Hant", "de-DE-x-goethe".
361 // NOTE: we should probably rely on the pref being set correctly.
362 if (lang.Length() > 2) {
363 int32_t pos = 0;
364 bool first = true;
365 for (const nsAString& code :
366 nsCharSeparatedTokenizer(lang, '-').ToRange()) {
367 if (code.Length() == 2 && !first) {
368 nsAutoString upper(code);
369 ToUpperCase(upper);
370 lang.Replace(pos, code.Length(), upper);
373 pos += code.Length() + 1; // 1 is the separator
374 first = false;
378 aLanguages.AppendElement(lang);
380 if (aLanguages.Length() == 0) {
381 nsTArray<nsCString> locales;
382 mozilla::intl::LocaleService::GetInstance()->GetWebExposedLocales(locales);
383 aLanguages.AppendElement(NS_ConvertUTF8toUTF16(locales[0]));
388 * Returns the first language from GetAcceptLanguages.
390 * Full details above in GetAcceptLanguages.
392 void Navigator::GetLanguage(nsAString& aLanguage) {
393 nsTArray<nsString> languages;
394 GetLanguages(languages);
395 MOZ_ASSERT(languages.Length() >= 1);
396 aLanguage.Assign(languages[0]);
399 void Navigator::GetLanguages(nsTArray<nsString>& aLanguages) {
400 GetAcceptLanguages(aLanguages);
402 // The returned value is cached by the binding code. The window listens to the
403 // accept languages change and will clear the cache when needed. It has to
404 // take care of dispatching the DOM event already and the invalidation and the
405 // event has to be timed correctly.
408 void Navigator::GetPlatform(nsAString& aPlatform, CallerType aCallerType,
409 ErrorResult& aRv) const {
410 if (mWindow) {
411 BrowsingContext* bc = mWindow->GetBrowsingContext();
412 nsString customPlatform;
413 if (bc) {
414 bc->GetCustomPlatform(customPlatform);
416 if (!customPlatform.IsEmpty()) {
417 aPlatform = customPlatform;
418 return;
423 nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
425 nsresult rv = GetPlatform(
426 aPlatform, doc,
427 /* aUsePrefOverriddenValue = */ aCallerType != CallerType::System);
428 if (NS_WARN_IF(NS_FAILED(rv))) {
429 aRv.Throw(rv);
433 void Navigator::GetOscpu(nsAString& aOSCPU, CallerType aCallerType,
434 ErrorResult& aRv) const {
435 if (aCallerType != CallerType::System) {
436 // If fingerprinting resistance is on, we will spoof this value. See
437 // nsRFPService.h for details about spoofed values.
438 if (nsContentUtils::ShouldResistFingerprinting(GetDocShell(),
439 RFPTarget::NavigatorOscpu)) {
440 aOSCPU.AssignLiteral(SPOOFED_OSCPU);
441 return;
444 nsAutoString override;
445 nsresult rv = Preferences::GetString("general.oscpu.override", override);
446 if (NS_SUCCEEDED(rv)) {
447 aOSCPU = override;
448 return;
452 nsresult rv;
453 nsCOMPtr<nsIHttpProtocolHandler> service(
454 do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
455 if (NS_WARN_IF(NS_FAILED(rv))) {
456 aRv.Throw(rv);
457 return;
460 nsAutoCString oscpu;
461 rv = service->GetOscpu(oscpu);
462 if (NS_WARN_IF(NS_FAILED(rv))) {
463 aRv.Throw(rv);
464 return;
467 CopyASCIItoUTF16(oscpu, aOSCPU);
470 void Navigator::GetVendor(nsAString& aVendor) { aVendor.Truncate(); }
472 void Navigator::GetVendorSub(nsAString& aVendorSub) { aVendorSub.Truncate(); }
474 void Navigator::GetProduct(nsAString& aProduct) {
475 aProduct.AssignLiteral("Gecko");
478 void Navigator::GetProductSub(nsAString& aProductSub) {
479 // Legacy build date hardcoded for backward compatibility (bug 776376)
480 aProductSub.AssignLiteral(LEGACY_UA_GECKO_TRAIL);
483 nsMimeTypeArray* Navigator::GetMimeTypes(ErrorResult& aRv) {
484 auto* plugins = GetPlugins(aRv);
485 if (!plugins) {
486 return nullptr;
489 return plugins->MimeTypeArray();
492 nsPluginArray* Navigator::GetPlugins(ErrorResult& aRv) {
493 if (!mPlugins) {
494 if (!mWindow) {
495 aRv.Throw(NS_ERROR_UNEXPECTED);
496 return nullptr;
498 mPlugins = MakeRefPtr<nsPluginArray>(mWindow);
501 return mPlugins;
504 bool Navigator::PdfViewerEnabled() { return !StaticPrefs::pdfjs_disabled(); }
506 Permissions* Navigator::GetPermissions(ErrorResult& aRv) {
507 if (!mWindow) {
508 aRv.Throw(NS_ERROR_UNEXPECTED);
509 return nullptr;
512 if (!mPermissions) {
513 mPermissions = new Permissions(mWindow);
516 return mPermissions;
519 StorageManager* Navigator::Storage() {
520 MOZ_ASSERT(mWindow);
522 if (!mStorageManager) {
523 mStorageManager = new StorageManager(mWindow->AsGlobal());
526 return mStorageManager;
529 bool Navigator::CookieEnabled() {
530 // Check whether an exception overrides the global cookie behavior
531 // Note that the code for getting the URI here matches that in
532 // nsHTMLDocument::SetCookie.
533 if (!mWindow || !mWindow->GetDocShell()) {
534 return nsICookieManager::GetCookieBehavior(false) !=
535 nsICookieService::BEHAVIOR_REJECT;
538 nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(mWindow);
539 uint32_t cookieBehavior = loadContext
540 ? nsICookieManager::GetCookieBehavior(
541 loadContext->UsePrivateBrowsing())
542 : nsICookieManager::GetCookieBehavior(false);
543 bool cookieEnabled = cookieBehavior != nsICookieService::BEHAVIOR_REJECT;
545 nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
546 if (!doc) {
547 return cookieEnabled;
550 uint32_t rejectedReason = 0;
551 bool granted = false;
552 nsresult rv = doc->NodePrincipal()->HasFirstpartyStorageAccess(
553 mWindow, &rejectedReason, &granted);
554 if (NS_FAILED(rv)) {
555 // Not a content, so technically can't set cookies, but let's
556 // just return the default value.
557 return cookieEnabled;
560 // We should return true if the cookie is partitioned because the cookie is
561 // still available in this case.
562 if (!granted &&
563 StoragePartitioningEnabled(rejectedReason, doc->CookieJarSettings())) {
564 granted = true;
567 ContentBlockingNotifier::OnDecision(
568 mWindow,
569 granted ? ContentBlockingNotifier::BlockingDecision::eAllow
570 : ContentBlockingNotifier::BlockingDecision::eBlock,
571 rejectedReason);
572 return granted;
575 bool Navigator::OnLine() {
576 if (mWindow) {
577 // Check if this tab is set to be offline.
578 BrowsingContext* bc = mWindow->GetBrowsingContext();
579 if (bc && bc->Top()->GetForceOffline()) {
580 return false;
583 // Return the default browser value
584 return !NS_IsOffline();
587 void Navigator::GetBuildID(nsAString& aBuildID, CallerType aCallerType,
588 ErrorResult& aRv) const {
589 if (aCallerType != CallerType::System) {
590 // If fingerprinting resistance is on, we will spoof this value. See
591 // nsRFPService.h for details about spoofed values.
592 if (nsContentUtils::ShouldResistFingerprinting(
593 GetDocShell(), RFPTarget::NavigatorBuildID)) {
594 aBuildID.AssignLiteral(LEGACY_BUILD_ID);
595 return;
598 nsAutoString override;
599 nsresult rv = Preferences::GetString("general.buildID.override", override);
600 if (NS_SUCCEEDED(rv)) {
601 aBuildID = override;
602 return;
605 nsAutoCString host;
606 bool isHTTPS = false;
607 if (mWindow) {
608 nsCOMPtr<Document> doc = mWindow->GetDoc();
609 if (doc) {
610 nsIURI* uri = doc->GetDocumentURI();
611 if (uri) {
612 isHTTPS = uri->SchemeIs("https");
613 if (isHTTPS) {
614 MOZ_ALWAYS_SUCCEEDS(uri->GetHost(host));
620 // Spoof the buildID on pages not loaded from "https://*.mozilla.org".
621 if (!isHTTPS || !StringEndsWith(host, ".mozilla.org"_ns)) {
622 aBuildID.AssignLiteral(LEGACY_BUILD_ID);
623 return;
627 nsCOMPtr<nsIXULAppInfo> appInfo =
628 do_GetService("@mozilla.org/xre/app-info;1");
629 if (!appInfo) {
630 aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
631 return;
634 nsAutoCString buildID;
635 nsresult rv = appInfo->GetAppBuildID(buildID);
636 if (NS_WARN_IF(NS_FAILED(rv))) {
637 aRv.Throw(rv);
638 return;
641 aBuildID.Truncate();
642 AppendASCIItoUTF16(buildID, aBuildID);
645 void Navigator::GetDoNotTrack(nsAString& aResult) {
646 bool doNotTrack = StaticPrefs::privacy_donottrackheader_enabled();
647 if (!doNotTrack) {
648 nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(mWindow);
649 doNotTrack = loadContext && loadContext->UseTrackingProtection();
652 if (doNotTrack) {
653 aResult.AssignLiteral("1");
654 } else {
655 aResult.AssignLiteral("unspecified");
659 bool Navigator::GlobalPrivacyControl() {
660 bool gpcStatus = StaticPrefs::privacy_globalprivacycontrol_enabled();
661 if (!gpcStatus) {
662 nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(mWindow);
663 gpcStatus = loadContext && loadContext->UsePrivateBrowsing() &&
664 StaticPrefs::privacy_globalprivacycontrol_pbmode_enabled();
666 return StaticPrefs::privacy_globalprivacycontrol_functionality_enabled() &&
667 gpcStatus;
670 uint64_t Navigator::HardwareConcurrency() {
671 workerinternals::RuntimeService* rts =
672 workerinternals::RuntimeService::GetOrCreateService();
673 if (!rts) {
674 return 1;
677 return rts->ClampedHardwareConcurrency(
678 nsGlobalWindowInner::Cast(mWindow)->ShouldResistFingerprinting(
679 RFPTarget::NavigatorHWConcurrency));
682 namespace {
684 class VibrateWindowListener : public nsIDOMEventListener {
685 public:
686 VibrateWindowListener(nsPIDOMWindowInner* aWindow, Document* aDocument)
687 : mWindow(do_GetWeakReference(aWindow)), mDocument(aDocument) {
688 constexpr auto visibilitychange = u"visibilitychange"_ns;
689 aDocument->AddSystemEventListener(visibilitychange, this, /* listener */
690 true, /* use capture */
691 false /* wants untrusted */);
694 void RemoveListener();
696 NS_DECL_ISUPPORTS
697 NS_DECL_NSIDOMEVENTLISTENER
699 private:
700 virtual ~VibrateWindowListener() = default;
702 nsWeakPtr mWindow;
703 WeakPtr<Document> mDocument;
706 NS_IMPL_ISUPPORTS(VibrateWindowListener, nsIDOMEventListener)
708 StaticRefPtr<VibrateWindowListener> gVibrateWindowListener;
710 static bool MayVibrate(Document* doc) {
711 // Hidden documents cannot start or stop a vibration.
712 return (doc && !doc->Hidden());
715 NS_IMETHODIMP
716 VibrateWindowListener::HandleEvent(Event* aEvent) {
717 nsCOMPtr<Document> doc = do_QueryInterface(aEvent->GetTarget());
719 if (!MayVibrate(doc)) {
720 // It's important that we call CancelVibrate(), not Vibrate() with an
721 // empty list, because Vibrate() will fail if we're no longer focused, but
722 // CancelVibrate() will succeed, so long as nobody else has started a new
723 // vibration pattern.
724 nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(mWindow);
725 hal::CancelVibrate(window);
726 RemoveListener();
727 gVibrateWindowListener = nullptr;
728 // Careful: The line above might have deleted |this|!
731 return NS_OK;
734 void VibrateWindowListener::RemoveListener() {
735 nsCOMPtr<Document> target(mDocument);
736 if (!target) {
737 return;
739 constexpr auto visibilitychange = u"visibilitychange"_ns;
740 target->RemoveSystemEventListener(visibilitychange, this,
741 true /* use capture */);
744 } // namespace
746 void Navigator::SetVibrationPermission(bool aPermitted, bool aPersistent) {
747 MOZ_ASSERT(NS_IsMainThread());
749 nsTArray<uint32_t> pattern = std::move(mRequestedVibrationPattern);
751 if (!mWindow) {
752 return;
755 nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
757 if (!MayVibrate(doc)) {
758 return;
761 if (aPermitted) {
762 // Add a listener to cancel the vibration if the document becomes hidden,
763 // and remove the old visibility listener, if there was one.
764 if (!gVibrateWindowListener) {
765 // If gVibrateWindowListener is null, this is the first time we've
766 // vibrated, and we need to register a listener to clear
767 // gVibrateWindowListener on shutdown.
768 ClearOnShutdown(&gVibrateWindowListener);
769 } else {
770 gVibrateWindowListener->RemoveListener();
772 gVibrateWindowListener = new VibrateWindowListener(mWindow, doc);
773 hal::Vibrate(pattern, mWindow);
776 if (aPersistent) {
777 nsCOMPtr<nsIPermissionManager> permMgr =
778 components::PermissionManager::Service();
779 if (!permMgr) {
780 return;
782 permMgr->AddFromPrincipal(doc->NodePrincipal(), kVibrationPermissionType,
783 aPermitted ? nsIPermissionManager::ALLOW_ACTION
784 : nsIPermissionManager::DENY_ACTION,
785 nsIPermissionManager::EXPIRE_SESSION, 0);
789 bool Navigator::Vibrate(uint32_t aDuration) {
790 AutoTArray<uint32_t, 1> pattern;
791 pattern.AppendElement(aDuration);
792 return Vibrate(pattern);
795 nsTArray<uint32_t> SanitizeVibratePattern(const nsTArray<uint32_t>& aPattern) {
796 nsTArray<uint32_t> pattern(aPattern.Clone());
798 if (pattern.Length() > StaticPrefs::dom_vibrator_max_vibrate_list_len()) {
799 pattern.SetLength(StaticPrefs::dom_vibrator_max_vibrate_list_len());
802 for (size_t i = 0; i < pattern.Length(); ++i) {
803 pattern[i] =
804 std::min(StaticPrefs::dom_vibrator_max_vibrate_ms(), pattern[i]);
807 return pattern;
810 bool Navigator::Vibrate(const nsTArray<uint32_t>& aPattern) {
811 MOZ_ASSERT(NS_IsMainThread());
813 if (!mWindow) {
814 return false;
817 nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
819 if (!MayVibrate(doc)) {
820 return false;
823 nsTArray<uint32_t> pattern = SanitizeVibratePattern(aPattern);
825 // The spec says we check dom.vibrator.enabled after we've done the sanity
826 // checking on the pattern.
827 if (!StaticPrefs::dom_vibrator_enabled()) {
828 return true;
831 mRequestedVibrationPattern = std::move(pattern);
833 PermissionDelegateHandler* permissionHandler =
834 doc->GetPermissionDelegateHandler();
835 if (NS_WARN_IF(!permissionHandler)) {
836 return false;
839 uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION;
841 permissionHandler->GetPermission(kVibrationPermissionType, &permission,
842 false);
844 if (permission == nsIPermissionManager::DENY_ACTION) {
845 // Abort without observer service or on denied session permission.
846 SetVibrationPermission(false /* permitted */, false /* persistent */);
847 return false;
850 if (permission == nsIPermissionManager::ALLOW_ACTION ||
851 mRequestedVibrationPattern.IsEmpty() ||
852 (mRequestedVibrationPattern.Length() == 1 &&
853 mRequestedVibrationPattern[0] == 0)) {
854 // Always allow cancelling vibration and respect session permissions.
855 SetVibrationPermission(true /* permitted */, false /* persistent */);
856 return true;
859 // Request user permission.
860 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
861 if (!obs) {
862 return true;
865 obs->NotifyObservers(ToSupports(this), "Vibration:Request", nullptr);
867 return true;
870 //*****************************************************************************
871 // Pointer Events interface
872 //*****************************************************************************
874 uint32_t Navigator::MaxTouchPoints(CallerType aCallerType) {
875 nsIDocShell* docshell = GetDocShell();
876 BrowsingContext* bc = docshell ? docshell->GetBrowsingContext() : nullptr;
878 // Responsive Design Mode overrides the maxTouchPoints property when
879 // touch simulation is enabled.
880 if (bc && bc->InRDMPane()) {
881 return bc->GetMaxTouchPointsOverride();
884 // The maxTouchPoints is going to reveal the detail of users' hardware. So,
885 // we will spoof it into 0 if fingerprinting resistance is on.
886 if (aCallerType != CallerType::System &&
887 nsContentUtils::ShouldResistFingerprinting(GetDocShell(),
888 RFPTarget::PointerEvents)) {
889 return 0;
892 nsCOMPtr<nsIWidget> widget =
893 widget::WidgetUtils::DOMWindowToWidget(mWindow->GetOuterWindow());
895 NS_ENSURE_TRUE(widget, 0);
896 return widget->GetMaxTouchPoints();
899 //*****************************************************************************
900 // Navigator::nsIDOMClientInformation
901 //*****************************************************************************
903 // This list should be kept up-to-date with the spec:
904 // https://html.spec.whatwg.org/multipage/system-state.html#custom-handlers
905 // If you change this list, please also update the copy in E10SUtils.sys.mjs.
906 static const char* const kSafeSchemes[] = {
907 // clang-format off
908 "bitcoin",
909 "ftp",
910 "ftps",
911 "geo",
912 "im",
913 "irc",
914 "ircs",
915 "magnet",
916 "mailto",
917 "matrix",
918 "mms",
919 "news",
920 "nntp",
921 "openpgp4fpr",
922 "sftp",
923 "sip",
924 "sms",
925 "smsto",
926 "ssh",
927 "tel",
928 "urn",
929 "webcal",
930 "wtai",
931 "xmpp",
932 // clang-format on
935 void Navigator::CheckProtocolHandlerAllowed(const nsAString& aScheme,
936 nsIURI* aHandlerURI,
937 nsIURI* aDocumentURI,
938 ErrorResult& aRv) {
939 auto raisePermissionDeniedHandler = [&] {
940 nsAutoCString spec;
941 aHandlerURI->GetSpec(spec);
942 nsPrintfCString message("Permission denied to add %s as a protocol handler",
943 spec.get());
944 aRv.ThrowSecurityError(message);
947 auto raisePermissionDeniedScheme = [&] {
948 nsPrintfCString message(
949 "Permission denied to add a protocol handler for %s",
950 NS_ConvertUTF16toUTF8(aScheme).get());
951 aRv.ThrowSecurityError(message);
954 if (!aDocumentURI || !aHandlerURI) {
955 aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
956 return;
959 nsCString spec;
960 aHandlerURI->GetSpec(spec);
961 // If the uri doesn't contain '%s', it won't be a good handler - the %s
962 // gets replaced with the handled URI.
963 if (!FindInReadable("%s"_ns, spec)) {
964 aRv.ThrowSyntaxError("Handler URI does not contain \"%s\".");
965 return;
968 // For security reasons we reject non-http(s) urls (see bug 354316),
969 nsAutoCString docScheme;
970 nsAutoCString handlerScheme;
971 aDocumentURI->GetScheme(docScheme);
972 aHandlerURI->GetScheme(handlerScheme);
973 if ((!docScheme.EqualsLiteral("https") && !docScheme.EqualsLiteral("http")) ||
974 (!handlerScheme.EqualsLiteral("https") &&
975 !handlerScheme.EqualsLiteral("http"))) {
976 raisePermissionDeniedHandler();
977 return;
980 // Should be same-origin:
981 nsAutoCString handlerHost;
982 aHandlerURI->GetHostPort(handlerHost);
983 nsAutoCString documentHost;
984 aDocumentURI->GetHostPort(documentHost);
985 if (!handlerHost.Equals(documentHost) || !handlerScheme.Equals(docScheme)) {
986 raisePermissionDeniedHandler();
987 return;
990 // Having checked the handler URI, check the scheme:
991 nsAutoCString scheme;
992 ToLowerCase(NS_ConvertUTF16toUTF8(aScheme), scheme);
993 if (StringBeginsWith(scheme, "web+"_ns)) {
994 // Check for non-ascii
995 nsReadingIterator<char> iter;
996 nsReadingIterator<char> iterEnd;
997 auto remainingScheme = Substring(scheme, 4 /* web+ */);
998 remainingScheme.BeginReading(iter);
999 remainingScheme.EndReading(iterEnd);
1000 // Scheme suffix must be non-empty
1001 if (iter == iterEnd) {
1002 raisePermissionDeniedScheme();
1003 return;
1005 for (; iter != iterEnd; iter++) {
1006 if (*iter < 'a' || *iter > 'z') {
1007 raisePermissionDeniedScheme();
1008 return;
1011 } else {
1012 bool matches = false;
1013 for (const char* safeScheme : kSafeSchemes) {
1014 if (scheme.Equals(safeScheme)) {
1015 matches = true;
1016 break;
1019 if (!matches) {
1020 raisePermissionDeniedScheme();
1021 return;
1025 nsCOMPtr<nsIProtocolHandler> handler;
1026 nsCOMPtr<nsIIOService> io = components::IO::Service();
1027 if (NS_FAILED(
1028 io->GetProtocolHandler(scheme.get(), getter_AddRefs(handler)))) {
1029 raisePermissionDeniedScheme();
1030 return;
1033 // check if we have prefs set saying not to add this.
1034 bool defaultExternal =
1035 Preferences::GetBool("network.protocol-handler.external-default");
1036 nsPrintfCString specificPref("network.protocol-handler.external.%s",
1037 scheme.get());
1038 if (!Preferences::GetBool(specificPref.get(), defaultExternal)) {
1039 raisePermissionDeniedScheme();
1040 return;
1043 // Check to make sure this isn't already handled internally (we don't
1044 // want to let them take over, say "chrome"). In theory, the checks above
1045 // should have already taken care of this.
1046 nsCOMPtr<nsIExternalProtocolHandler> externalHandler =
1047 do_QueryInterface(handler);
1048 MOZ_RELEASE_ASSERT(
1049 externalHandler,
1050 "We should never allow overriding a builtin protocol handler");
1053 void Navigator::RegisterProtocolHandler(const nsAString& aScheme,
1054 const nsAString& aURI,
1055 ErrorResult& aRv) {
1056 if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell() ||
1057 !mWindow->GetDoc()) {
1058 return;
1060 nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(mWindow);
1061 if (loadContext->UsePrivateBrowsing()) {
1062 // If we're a private window, don't alert the user or webpage. We log to the
1063 // console so that web developers have some way to tell what's going wrong.
1064 nsContentUtils::ReportToConsole(
1065 nsIScriptError::warningFlag, "DOM"_ns, mWindow->GetDoc(),
1066 nsContentUtils::eDOM_PROPERTIES,
1067 "RegisterProtocolHandlerPrivateBrowsingWarning");
1068 return;
1071 nsCOMPtr<Document> doc = mWindow->GetDoc();
1073 // Determine if doc is allowed to assign this handler
1074 nsIURI* docURI = doc->GetDocumentURIObject();
1075 nsCOMPtr<nsIURI> handlerURI;
1076 NS_NewURI(getter_AddRefs(handlerURI), NS_ConvertUTF16toUTF8(aURI),
1077 doc->GetDocumentCharacterSet(), docURI);
1078 CheckProtocolHandlerAllowed(aScheme, handlerURI, docURI, aRv);
1079 if (aRv.Failed()) {
1080 return;
1083 // Determine a title from the document URI.
1084 nsAutoCString docDisplayHostPort;
1085 docURI->GetDisplayHostPort(docDisplayHostPort);
1086 NS_ConvertASCIItoUTF16 title(docDisplayHostPort);
1088 if (XRE_IsContentProcess()) {
1089 nsAutoString scheme(aScheme);
1090 RefPtr<BrowserChild> browserChild = BrowserChild::GetFrom(mWindow);
1091 browserChild->SendRegisterProtocolHandler(scheme, handlerURI, title,
1092 docURI);
1093 return;
1096 nsCOMPtr<nsIWebProtocolHandlerRegistrar> registrar =
1097 do_GetService(NS_WEBPROTOCOLHANDLERREGISTRAR_CONTRACTID);
1098 if (registrar) {
1099 aRv = registrar->RegisterProtocolHandler(aScheme, handlerURI, title, docURI,
1100 mWindow->GetOuterWindow());
1104 Geolocation* Navigator::GetGeolocation(ErrorResult& aRv) {
1105 if (mGeolocation) {
1106 return mGeolocation;
1109 if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) {
1110 aRv.Throw(NS_ERROR_FAILURE);
1111 return nullptr;
1114 mGeolocation = new Geolocation();
1115 if (NS_FAILED(mGeolocation->Init(mWindow))) {
1116 mGeolocation = nullptr;
1117 aRv.Throw(NS_ERROR_FAILURE);
1118 return nullptr;
1121 return mGeolocation;
1124 class BeaconStreamListener final : public nsIStreamListener {
1125 ~BeaconStreamListener() = default;
1127 public:
1128 BeaconStreamListener() : mLoadGroup(nullptr) {}
1130 void SetLoadGroup(nsILoadGroup* aLoadGroup) { mLoadGroup = aLoadGroup; }
1132 NS_DECL_ISUPPORTS
1133 NS_DECL_NSISTREAMLISTENER
1134 NS_DECL_NSIREQUESTOBSERVER
1136 private:
1137 nsCOMPtr<nsILoadGroup> mLoadGroup;
1140 NS_IMPL_ISUPPORTS(BeaconStreamListener, nsIStreamListener, nsIRequestObserver)
1142 NS_IMETHODIMP
1143 BeaconStreamListener::OnStartRequest(nsIRequest* aRequest) {
1144 // release the loadgroup first
1145 mLoadGroup = nullptr;
1147 return NS_ERROR_ABORT;
1150 NS_IMETHODIMP
1151 BeaconStreamListener::OnStopRequest(nsIRequest* aRequest, nsresult aStatus) {
1152 return NS_OK;
1155 NS_IMETHODIMP
1156 BeaconStreamListener::OnDataAvailable(nsIRequest* aRequest,
1157 nsIInputStream* inStr,
1158 uint64_t sourceOffset, uint32_t count) {
1159 MOZ_ASSERT(false);
1160 return NS_OK;
1163 bool Navigator::SendBeacon(const nsAString& aUrl,
1164 const Nullable<fetch::BodyInit>& aData,
1165 ErrorResult& aRv) {
1166 if (aData.IsNull()) {
1167 return SendBeaconInternal(aUrl, nullptr, eBeaconTypeOther, aRv);
1170 if (aData.Value().IsArrayBuffer()) {
1171 BodyExtractor<const ArrayBuffer> body(&aData.Value().GetAsArrayBuffer());
1172 return SendBeaconInternal(aUrl, &body, eBeaconTypeArrayBuffer, aRv);
1175 if (aData.Value().IsArrayBufferView()) {
1176 BodyExtractor<const ArrayBufferView> body(
1177 &aData.Value().GetAsArrayBufferView());
1178 return SendBeaconInternal(aUrl, &body, eBeaconTypeArrayBuffer, aRv);
1181 if (aData.Value().IsBlob()) {
1182 BodyExtractor<const Blob> body(&aData.Value().GetAsBlob());
1183 return SendBeaconInternal(aUrl, &body, eBeaconTypeBlob, aRv);
1186 if (aData.Value().IsFormData()) {
1187 BodyExtractor<const FormData> body(&aData.Value().GetAsFormData());
1188 return SendBeaconInternal(aUrl, &body, eBeaconTypeOther, aRv);
1191 if (aData.Value().IsUSVString()) {
1192 BodyExtractor<const nsAString> body(&aData.Value().GetAsUSVString());
1193 return SendBeaconInternal(aUrl, &body, eBeaconTypeOther, aRv);
1196 if (aData.Value().IsURLSearchParams()) {
1197 BodyExtractor<const URLSearchParams> body(
1198 &aData.Value().GetAsURLSearchParams());
1199 return SendBeaconInternal(aUrl, &body, eBeaconTypeOther, aRv);
1202 MOZ_CRASH("Invalid data type.");
1203 return false;
1206 bool Navigator::SendBeaconInternal(const nsAString& aUrl,
1207 BodyExtractorBase* aBody, BeaconType aType,
1208 ErrorResult& aRv) {
1209 if (!mWindow) {
1210 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
1211 return false;
1214 nsCOMPtr<Document> doc = mWindow->GetDoc();
1215 if (!doc) {
1216 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
1217 return false;
1220 nsIURI* documentURI = doc->GetDocumentURI();
1221 if (!documentURI) {
1222 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
1223 return false;
1226 nsCOMPtr<nsIURI> uri;
1227 nsresult rv = nsContentUtils::NewURIWithDocumentCharset(
1228 getter_AddRefs(uri), aUrl, doc, doc->GetDocBaseURI());
1229 if (NS_FAILED(rv)) {
1230 aRv.ThrowTypeError<MSG_INVALID_URL>(NS_ConvertUTF16toUTF8(aUrl));
1231 return false;
1234 // Spec disallows any schemes save for HTTP/HTTPs
1235 if (!uri->SchemeIs("http") && !uri->SchemeIs("https")) {
1236 aRv.ThrowTypeError<MSG_INVALID_URL_SCHEME>("Beacon",
1237 uri->GetSpecOrDefault());
1238 return false;
1241 nsCOMPtr<nsIInputStream> in;
1242 nsAutoCString contentTypeWithCharset;
1243 nsAutoCString charset;
1244 uint64_t length = 0;
1245 if (aBody) {
1246 aRv = aBody->GetAsStream(getter_AddRefs(in), &length,
1247 contentTypeWithCharset, charset);
1248 if (NS_WARN_IF(aRv.Failed())) {
1249 return false;
1253 nsSecurityFlags securityFlags = nsILoadInfo::SEC_COOKIES_INCLUDE;
1254 // Ensure that only streams with content types that are safelisted ignore CORS
1255 // rules
1256 if (aBody && !contentTypeWithCharset.IsVoid() &&
1257 !nsContentUtils::IsCORSSafelistedRequestHeader("content-type"_ns,
1258 contentTypeWithCharset)) {
1259 securityFlags |= nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT;
1260 } else {
1261 securityFlags |= nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT;
1264 nsCOMPtr<nsIChannel> channel;
1265 rv = NS_NewChannel(getter_AddRefs(channel), uri, doc, securityFlags,
1266 nsIContentPolicy::TYPE_BEACON);
1268 if (NS_FAILED(rv)) {
1269 aRv.Throw(rv);
1270 return false;
1273 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
1274 if (!httpChannel) {
1275 // Beacon spec only supports HTTP requests at this time
1276 aRv.Throw(NS_ERROR_DOM_BAD_URI);
1277 return false;
1280 auto referrerInfo = MakeRefPtr<ReferrerInfo>(*doc);
1281 rv = httpChannel->SetReferrerInfoWithoutClone(referrerInfo);
1282 MOZ_ASSERT(NS_SUCCEEDED(rv));
1284 if (aBody) {
1285 nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(channel);
1286 if (!uploadChannel) {
1287 aRv.Throw(NS_ERROR_FAILURE);
1288 return false;
1291 uploadChannel->ExplicitSetUploadStream(in, contentTypeWithCharset, length,
1292 "POST"_ns, false);
1293 } else {
1294 rv = httpChannel->SetRequestMethod("POST"_ns);
1295 MOZ_ASSERT(NS_SUCCEEDED(rv));
1298 nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(channel);
1299 if (p) {
1300 p->SetPriority(nsISupportsPriority::PRIORITY_LOWEST);
1303 nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
1304 if (cos) {
1305 cos->AddClassFlags(nsIClassOfService::Background);
1308 // The channel needs to have a loadgroup associated with it, so that we can
1309 // cancel the channel and any redirected channels it may create.
1310 nsCOMPtr<nsILoadGroup> loadGroup = do_CreateInstance(NS_LOADGROUP_CONTRACTID);
1311 nsCOMPtr<nsIInterfaceRequestor> callbacks =
1312 do_QueryInterface(mWindow->GetDocShell());
1313 loadGroup->SetNotificationCallbacks(callbacks);
1314 channel->SetLoadGroup(loadGroup);
1316 RefPtr<BeaconStreamListener> beaconListener = new BeaconStreamListener();
1317 rv = channel->AsyncOpen(beaconListener);
1318 // do not throw if security checks fail within asyncOpen
1319 NS_ENSURE_SUCCESS(rv, false);
1321 // make the beaconListener hold a strong reference to the loadgroup
1322 // which is released in ::OnStartRequest
1323 beaconListener->SetLoadGroup(loadGroup);
1325 return true;
1328 MediaDevices* Navigator::GetMediaDevices(ErrorResult& aRv) {
1329 if (!mMediaDevices) {
1330 if (!mWindow || !mWindow->GetOuterWindow() ||
1331 mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) {
1332 aRv.Throw(NS_ERROR_NOT_AVAILABLE);
1333 return nullptr;
1335 mMediaDevices = new MediaDevices(mWindow);
1337 return mMediaDevices;
1340 void Navigator::MozGetUserMedia(const MediaStreamConstraints& aConstraints,
1341 NavigatorUserMediaSuccessCallback& aOnSuccess,
1342 NavigatorUserMediaErrorCallback& aOnError,
1343 CallerType aCallerType, ErrorResult& aRv) {
1344 MOZ_ASSERT(NS_IsMainThread());
1345 if (!mWindow || !mWindow->IsFullyActive()) {
1346 aRv.ThrowInvalidStateError("The document is not fully active.");
1347 return;
1349 GetMediaDevices(aRv);
1350 if (aRv.Failed()) {
1351 return;
1353 MOZ_ASSERT(mMediaDevices);
1354 if (Document* doc = mWindow->GetExtantDoc()) {
1355 if (!mWindow->IsSecureContext()) {
1356 doc->SetUseCounter(eUseCounter_custom_MozGetUserMediaInsec);
1359 RefPtr<MediaManager::StreamPromise> sp;
1360 if (!MediaManager::IsOn(aConstraints.mVideo) &&
1361 !MediaManager::IsOn(aConstraints.mAudio)) {
1362 sp = MediaManager::StreamPromise::CreateAndReject(
1363 MakeRefPtr<MediaMgrError>(MediaMgrError::Name::TypeError,
1364 "audio and/or video is required"),
1365 __func__);
1366 } else {
1367 sp = mMediaDevices->GetUserMedia(mWindow, aConstraints, aCallerType);
1369 RefPtr<NavigatorUserMediaSuccessCallback> onsuccess(&aOnSuccess);
1370 RefPtr<NavigatorUserMediaErrorCallback> onerror(&aOnError);
1372 nsWeakPtr weakWindow = nsWeakPtr(do_GetWeakReference(mWindow));
1373 sp->Then(
1374 GetMainThreadSerialEventTarget(), __func__,
1375 [weakWindow, onsuccess = std::move(onsuccess)](
1376 const RefPtr<DOMMediaStream>& aStream) MOZ_CAN_RUN_SCRIPT {
1377 nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(weakWindow);
1378 if (!window || !window->GetOuterWindow() ||
1379 window->GetOuterWindow()->GetCurrentInnerWindow() != window) {
1380 return; // Leave Promise pending after navigation by design.
1382 MediaManager::CallOnSuccess(*onsuccess, *aStream);
1384 [weakWindow, onerror = std::move(onerror)](
1385 const RefPtr<MediaMgrError>& aError) MOZ_CAN_RUN_SCRIPT {
1386 nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(weakWindow);
1387 if (!window || !window->GetOuterWindow() ||
1388 window->GetOuterWindow()->GetCurrentInnerWindow() != window) {
1389 return; // Leave Promise pending after navigation by design.
1391 auto error = MakeRefPtr<MediaStreamError>(window, *aError);
1392 MediaManager::CallOnError(*onerror, *error);
1396 //*****************************************************************************
1397 // Navigator::nsINavigatorBattery
1398 //*****************************************************************************
1400 Promise* Navigator::GetBattery(ErrorResult& aRv) {
1401 if (mBatteryPromise) {
1402 return mBatteryPromise;
1405 if (!mWindow || !mWindow->GetDocShell()) {
1406 aRv.Throw(NS_ERROR_UNEXPECTED);
1407 return nullptr;
1410 RefPtr<Promise> batteryPromise = Promise::Create(mWindow->AsGlobal(), aRv);
1411 if (NS_WARN_IF(aRv.Failed())) {
1412 return nullptr;
1414 mBatteryPromise = batteryPromise;
1416 if (!mBatteryManager) {
1417 mBatteryManager = new battery::BatteryManager(mWindow);
1418 mBatteryManager->Init();
1421 mBatteryPromise->MaybeResolve(mBatteryManager);
1423 return mBatteryPromise;
1426 //*****************************************************************************
1427 // Navigator::Share() - Web Share API
1428 //*****************************************************************************
1430 already_AddRefed<Promise> Navigator::Share(const ShareData& aData,
1431 ErrorResult& aRv) {
1432 if (!mWindow || !mWindow->IsFullyActive()) {
1433 aRv.ThrowInvalidStateError("The document is not fully active.");
1434 return nullptr;
1437 if (NS_WARN_IF(!mWindow->GetDocShell() || !mWindow->GetExtantDoc())) {
1438 aRv.Throw(NS_ERROR_UNEXPECTED);
1439 return nullptr;
1442 if (!FeaturePolicyUtils::IsFeatureAllowed(mWindow->GetExtantDoc(),
1443 u"web-share"_ns)) {
1444 aRv.ThrowNotAllowedError(
1445 "Document's Permissions Policy does not allow calling "
1446 "share() from this context.");
1447 return nullptr;
1450 if (mSharePromise) {
1451 NS_WARNING("Only one share picker at a time per navigator instance");
1452 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
1453 return nullptr;
1456 // null checked above
1457 Document* doc = mWindow->GetExtantDoc();
1459 if (StaticPrefs::dom_webshare_requireinteraction() &&
1460 !doc->ConsumeTransientUserGestureActivation()) {
1461 aRv.ThrowNotAllowedError(
1462 "User activation was already consumed "
1463 "or share() was not activated by a user gesture.");
1464 return nullptr;
1467 ValidateShareData(aData, aRv);
1469 if (aRv.Failed()) {
1470 return nullptr;
1473 // TODO: Process file member, which we don't currently support.
1475 // If data's url member is present, try to resolve it...
1476 nsCOMPtr<nsIURI> url;
1477 if (aData.mUrl.WasPassed()) {
1478 auto result = doc->ResolveWithBaseURI(aData.mUrl.Value());
1479 url = result.unwrap();
1480 MOZ_ASSERT(url);
1483 // Process the title member...
1484 nsCString title;
1485 if (aData.mTitle.WasPassed()) {
1486 title.Assign(NS_ConvertUTF16toUTF8(aData.mTitle.Value()));
1487 } else {
1488 title.SetIsVoid(true);
1491 // Process the text member...
1492 nsCString text;
1493 if (aData.mText.WasPassed()) {
1494 text.Assign(NS_ConvertUTF16toUTF8(aData.mText.Value()));
1495 } else {
1496 text.SetIsVoid(true);
1499 // Let mSharePromise be a new promise.
1500 mSharePromise = Promise::Create(mWindow->AsGlobal(), aRv);
1501 if (aRv.Failed()) {
1502 return nullptr;
1505 IPCWebShareData data(title, text, url);
1506 auto wgc = mWindow->GetWindowGlobalChild();
1507 if (!wgc) {
1508 aRv.Throw(NS_ERROR_FAILURE);
1509 return nullptr;
1512 // Do the share
1513 wgc->SendShare(data)->Then(
1514 GetCurrentSerialEventTarget(), __func__,
1515 [self = RefPtr{this}](
1516 PWindowGlobalChild::SharePromise::ResolveOrRejectValue&& aResult) {
1517 if (aResult.IsResolve()) {
1518 if (NS_SUCCEEDED(aResult.ResolveValue())) {
1519 self->mSharePromise->MaybeResolveWithUndefined();
1520 } else {
1521 self->mSharePromise->MaybeReject(aResult.ResolveValue());
1523 } else if (self->mSharePromise) {
1524 // IPC died
1525 self->mSharePromise->MaybeReject(NS_BINDING_ABORTED);
1527 self->mSharePromise = nullptr;
1529 return do_AddRef(mSharePromise);
1532 //*****************************************************************************
1533 // Navigator::CanShare() - Web Share API
1534 //*****************************************************************************
1535 bool Navigator::CanShare(const ShareData& aData) {
1536 if (!mWindow || !mWindow->IsFullyActive()) {
1537 return false;
1540 if (!FeaturePolicyUtils::IsFeatureAllowed(mWindow->GetExtantDoc(),
1541 u"web-share"_ns)) {
1542 return false;
1545 IgnoredErrorResult rv;
1546 ValidateShareData(aData, rv);
1547 return !rv.Failed();
1550 void Navigator::ValidateShareData(const ShareData& aData, ErrorResult& aRv) {
1551 // TODO: remove this check when we support files share.
1552 if (aData.mFiles.WasPassed() && !aData.mFiles.Value().IsEmpty()) {
1553 aRv.ThrowTypeError("Passing files is currently not supported.");
1554 return;
1557 bool titleTextOrUrlPassed = aData.mTitle.WasPassed() ||
1558 aData.mText.WasPassed() || aData.mUrl.WasPassed();
1560 // At least one member must be present.
1561 if (!titleTextOrUrlPassed) {
1562 aRv.ThrowTypeError(
1563 "Must have a title, text, or url member in the ShareData dictionary");
1564 return;
1567 // If data's url member is present, try to resolve it...
1568 nsCOMPtr<nsIURI> url;
1569 if (aData.mUrl.WasPassed()) {
1570 Document* doc = mWindow->GetExtantDoc();
1571 Result<OwningNonNull<nsIURI>, nsresult> result =
1572 doc->ResolveWithBaseURI(aData.mUrl.Value());
1573 if (NS_WARN_IF(result.isErr())) {
1574 aRv.ThrowTypeError<MSG_INVALID_URL>(
1575 NS_ConvertUTF16toUTF8(aData.mUrl.Value()));
1576 return;
1578 url = result.unwrap();
1579 // Check that we only share loadable URLs (e.g., http/https).
1580 // we also exclude blobs, as it doesn't make sense to share those outside
1581 // the context of the browser.
1582 const uint32_t flags =
1583 nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL |
1584 nsIScriptSecurityManager::DISALLOW_SCRIPT;
1585 if (NS_FAILED(
1586 nsContentUtils::GetSecurityManager()->CheckLoadURIWithPrincipal(
1587 doc->NodePrincipal(), url, flags, doc->InnerWindowID())) ||
1588 url->SchemeIs("blob")) {
1589 aRv.ThrowTypeError<MSG_INVALID_URL_SCHEME>("Share",
1590 url->GetSpecOrDefault());
1591 return;
1596 static bool ShouldResistFingerprinting(const Document* aDoc,
1597 RFPTarget aTarget) {
1598 return aDoc ? aDoc->ShouldResistFingerprinting(aTarget)
1599 : nsContentUtils::ShouldResistFingerprinting("Fallback", aTarget);
1602 already_AddRefed<LegacyMozTCPSocket> Navigator::MozTCPSocket() {
1603 RefPtr<LegacyMozTCPSocket> socket = new LegacyMozTCPSocket(GetWindow());
1604 return socket.forget();
1607 void Navigator::GetGamepads(nsTArray<RefPtr<Gamepad>>& aGamepads,
1608 ErrorResult& aRv) {
1609 if (!mWindow || !mWindow->IsFullyActive()) {
1610 return;
1612 NS_ENSURE_TRUE_VOID(mWindow->GetDocShell());
1613 nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
1615 if (!FeaturePolicyUtils::IsFeatureAllowed(win->GetExtantDoc(),
1616 u"gamepad"_ns)) {
1617 aRv.ThrowSecurityError(
1618 "Document's Permission Policy does not allow calling "
1619 "getGamepads() from this context.");
1620 return;
1623 win->SetHasGamepadEventListener(true);
1624 win->GetGamepads(aGamepads);
1627 GamepadServiceTest* Navigator::RequestGamepadServiceTest(ErrorResult& aRv) {
1628 #ifdef FUZZING
1629 if (!StaticPrefs::fuzzing_enabled()) {
1630 aRv.Throw(NS_ERROR_UNEXPECTED);
1631 return nullptr;
1633 #else
1634 if (!xpc::IsInAutomation()) {
1635 aRv.Throw(NS_ERROR_UNEXPECTED);
1636 return nullptr;
1638 #endif
1640 if (!mGamepadServiceTest) {
1641 mGamepadServiceTest = GamepadServiceTest::CreateTestService(mWindow);
1643 return mGamepadServiceTest;
1646 already_AddRefed<Promise> Navigator::GetVRDisplays(ErrorResult& aRv) {
1647 if (!mWindow || !mWindow->GetDocShell() || !mWindow->GetExtantDoc()) {
1648 aRv.Throw(NS_ERROR_UNEXPECTED);
1649 return nullptr;
1652 if (!FeaturePolicyUtils::IsFeatureAllowed(mWindow->GetExtantDoc(),
1653 u"vr"_ns)) {
1654 aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
1655 return nullptr;
1658 RefPtr<Promise> p = Promise::Create(mWindow->AsGlobal(), aRv);
1659 if (aRv.Failed()) {
1660 return nullptr;
1663 RefPtr<BrowserChild> browser(BrowserChild::GetFrom(mWindow));
1664 if (!browser) {
1665 MOZ_ASSERT(XRE_IsParentProcess());
1666 FinishGetVRDisplays(true, p);
1667 } else {
1668 RefPtr<Navigator> self(this);
1669 int browserID = browser->ChromeOuterWindowID();
1671 browser->SendIsWindowSupportingWebVR(browserID)->Then(
1672 GetCurrentSerialEventTarget(), __func__,
1673 [self, p](bool isSupported) {
1674 self->FinishGetVRDisplays(isSupported, p);
1676 [p](const mozilla::ipc::ResponseRejectReason) {
1677 p->MaybeRejectWithTypeError("Unable to start display enumeration");
1681 return p.forget();
1684 void Navigator::FinishGetVRDisplays(bool isWebVRSupportedInwindow, Promise* p) {
1685 if (!isWebVRSupportedInwindow) {
1686 // WebVR in this window is not supported, so resolve the promise
1687 // with no displays available
1688 nsTArray<RefPtr<VRDisplay>> vrDisplaysEmpty;
1689 p->MaybeResolve(vrDisplaysEmpty);
1690 return;
1693 // Since FinishGetVRDisplays can be called asynchronously after an IPC
1694 // response, it's possible that the Window can be torn down before this
1695 // call. In that case, the Window's cyclic references to VR objects are
1696 // also torn down and should not be recreated via
1697 // NotifyHasXRSession.
1698 nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
1699 if (win->IsDying()) {
1700 // The Window has been torn down, so there is no further work that can
1701 // be done.
1702 p->MaybeRejectWithTypeError(
1703 "Unable to return VRDisplays for a closed window.");
1704 return;
1707 mVRGetDisplaysPromises.AppendElement(p);
1708 win->RequestXRPermission();
1711 void Navigator::OnXRPermissionRequestAllow() {
1712 // The permission request that results in this callback could have
1713 // been instantiated by WebVR, WebXR, or both.
1714 nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
1715 bool usingWebXR = false;
1717 if (mXRSystem) {
1718 usingWebXR = mXRSystem->OnXRPermissionRequestAllow();
1721 bool rejectWebVR = true;
1722 // If WebVR and WebXR both requested permission, only grant it to
1723 // WebXR, which takes priority.
1724 if (!usingWebXR) {
1725 // We pass mWindow's id to RefreshVRDisplays, so NotifyVRDisplaysUpdated
1726 // will be called asynchronously, resolving the promises in
1727 // mVRGetDisplaysPromises.
1728 rejectWebVR = !VRDisplay::RefreshVRDisplays(win->WindowID());
1730 // Even if WebXR took priority, reject requests for WebVR in case they were
1731 // made simultaneously and coelesced into a single permission prompt.
1732 if (rejectWebVR) {
1733 for (auto& p : mVRGetDisplaysPromises) {
1734 // Failed to refresh, reject the promise now
1735 p->MaybeRejectWithTypeError("Failed to find attached VR displays.");
1737 mVRGetDisplaysPromises.Clear();
1741 void Navigator::OnXRPermissionRequestCancel() {
1742 if (mXRSystem) {
1743 mXRSystem->OnXRPermissionRequestCancel();
1746 nsTArray<RefPtr<VRDisplay>> vrDisplays;
1747 for (auto& p : mVRGetDisplaysPromises) {
1748 // Resolve the promise with no vr displays when
1749 // the user blocks access.
1750 p->MaybeResolve(vrDisplays);
1752 mVRGetDisplaysPromises.Clear();
1755 void Navigator::GetActiveVRDisplays(
1756 nsTArray<RefPtr<VRDisplay>>& aDisplays) const {
1758 * Get only the active VR displays.
1759 * GetActiveVRDisplays should only enumerate displays that
1760 * are already active without causing any other hardware to be
1761 * activated.
1762 * We must not call nsGlobalWindowInner::NotifyHasXRSession here,
1763 * as that would cause enumeration and activation of other VR hardware.
1764 * Activating VR hardware is intrusive to the end user, as it may
1765 * involve physically powering on devices that the user did not
1766 * intend to use.
1768 if (!mWindow || !mWindow->GetDocShell()) {
1769 return;
1771 nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
1772 nsTArray<RefPtr<VRDisplay>> displays;
1773 if (win->UpdateVRDisplays(displays)) {
1774 for (auto display : displays) {
1775 if (display->IsPresenting()) {
1776 aDisplays.AppendElement(display);
1782 void Navigator::NotifyVRDisplaysUpdated() {
1783 // Synchronize the VR devices and resolve the promises in
1784 // mVRGetDisplaysPromises
1785 nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
1787 nsTArray<RefPtr<VRDisplay>> vrDisplays;
1788 if (win->UpdateVRDisplays(vrDisplays)) {
1789 for (auto p : mVRGetDisplaysPromises) {
1790 p->MaybeResolve(vrDisplays);
1792 } else {
1793 for (auto p : mVRGetDisplaysPromises) {
1794 p->MaybeReject(NS_ERROR_FAILURE);
1797 mVRGetDisplaysPromises.Clear();
1800 void Navigator::NotifyActiveVRDisplaysChanged() {
1801 Navigator_Binding::ClearCachedActiveVRDisplaysValue(this);
1804 VRServiceTest* Navigator::RequestVRServiceTest(ErrorResult& aRv) {
1805 if (!xpc::IsInAutomation()) {
1806 aRv.Throw(NS_ERROR_UNEXPECTED);
1807 return nullptr;
1810 // Ensure that the Mock VR devices are not released prematurely
1811 nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
1812 win->NotifyHasXRSession();
1814 if (!mVRServiceTest) {
1815 mVRServiceTest = VRServiceTest::CreateTestService(mWindow);
1817 return mVRServiceTest;
1820 XRSystem* Navigator::GetXr(ErrorResult& aRv) {
1821 if (!mWindow) {
1822 aRv.Throw(NS_ERROR_UNEXPECTED);
1823 return nullptr;
1825 if (!mXRSystem) {
1826 mXRSystem = XRSystem::Create(mWindow);
1828 return mXRSystem;
1831 bool Navigator::IsWebVRContentDetected() const {
1832 nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
1833 return win->IsVRContentDetected();
1836 bool Navigator::IsWebVRContentPresenting() const {
1837 nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
1838 return win->IsVRContentPresenting();
1841 void Navigator::RequestVRPresentation(VRDisplay& aDisplay) {
1842 nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
1843 win->DispatchVRDisplayActivate(aDisplay.DisplayId(),
1844 VRDisplayEventReason::Requested);
1847 already_AddRefed<Promise> Navigator::RequestMIDIAccess(
1848 const MIDIOptions& aOptions, ErrorResult& aRv) {
1849 if (!mWindow) {
1850 aRv.Throw(NS_ERROR_UNEXPECTED);
1851 return nullptr;
1853 MIDIAccessManager* accessMgr = MIDIAccessManager::Get();
1854 return accessMgr->RequestMIDIAccess(mWindow, aOptions, aRv);
1857 network::Connection* Navigator::GetConnection(ErrorResult& aRv) {
1858 if (!mConnection) {
1859 if (!mWindow) {
1860 aRv.Throw(NS_ERROR_UNEXPECTED);
1861 return nullptr;
1863 mConnection = network::Connection::CreateForWindow(
1864 mWindow, nsGlobalWindowInner::Cast(mWindow)->ShouldResistFingerprinting(
1865 RFPTarget::NavigatorConnection));
1868 return mConnection;
1871 already_AddRefed<ServiceWorkerContainer> Navigator::ServiceWorker() {
1872 MOZ_ASSERT(mWindow);
1874 if (!mServiceWorkerContainer) {
1875 mServiceWorkerContainer =
1876 ServiceWorkerContainer::Create(mWindow->AsGlobal());
1879 RefPtr<ServiceWorkerContainer> ref = mServiceWorkerContainer;
1880 return ref.forget();
1883 already_AddRefed<ServiceWorkerContainer> Navigator::ServiceWorkerJS() {
1884 if (mWindow->AsGlobal()->GetStorageAccess() ==
1885 StorageAccess::ePrivateBrowsing) {
1886 SetUseCounter(mWindow->AsGlobal()->GetGlobalJSObject(),
1887 eUseCounter_custom_PrivateBrowsingNavigatorServiceWorker);
1890 return ServiceWorker();
1893 size_t Navigator::SizeOfIncludingThis(
1894 mozilla::MallocSizeOf aMallocSizeOf) const {
1895 size_t n = aMallocSizeOf(this);
1897 // TODO: add SizeOfIncludingThis() to nsMimeTypeArray, bug 674113.
1898 // TODO: add SizeOfIncludingThis() to nsPluginArray, bug 674114.
1899 // TODO: add SizeOfIncludingThis() to Geolocation, bug 674115.
1900 // TODO: add SizeOfIncludingThis() to DesktopNotificationCenter, bug 674116.
1902 return n;
1905 void Navigator::OnNavigation() {
1906 if (!mWindow) {
1907 return;
1910 // If MediaManager is open let it inform any live streams or pending callbacks
1911 MediaManager* manager = MediaManager::GetIfExists();
1912 if (manager) {
1913 manager->OnNavigation(mWindow->WindowID());
1917 JSObject* Navigator::WrapObject(JSContext* cx,
1918 JS::Handle<JSObject*> aGivenProto) {
1919 return Navigator_Binding::Wrap(cx, this, aGivenProto);
1922 /* static */
1923 bool Navigator::HasUserMediaSupport(JSContext* cx, JSObject* obj) {
1924 // Make enabling peerconnection enable getUserMedia() as well.
1925 // Emulate [SecureContext] unless media.devices.insecure.enabled=true
1926 return (StaticPrefs::media_navigator_enabled() ||
1927 StaticPrefs::media_peerconnection_enabled()) &&
1928 (IsSecureContextOrObjectIsFromSecureContext(cx, obj) ||
1929 StaticPrefs::media_devices_insecure_enabled());
1932 /* static */
1933 bool Navigator::HasShareSupport(JSContext* cx, JSObject* obj) {
1934 if (!StaticPrefs::dom_webshare_enabled()) {
1935 return false;
1937 #if defined(XP_WIN) && !defined(__MINGW32__)
1938 // The first public build that supports ShareCanceled API
1939 return IsWindows10BuildOrLater(18956);
1940 #else
1941 return true;
1942 #endif
1945 /* static */
1946 bool Navigator::HasMidiSupport(JSContext* cx, JSObject* obj) {
1947 nsIPrincipal* principal = nsContentUtils::SubjectPrincipal(cx);
1949 // Enable on secure contexts but exclude file schemes.
1950 return StaticPrefs::dom_webmidi_enabled() &&
1951 IsSecureContextOrObjectIsFromSecureContext(cx, obj) &&
1952 !principal->SchemeIs("file");
1955 /* static */
1956 already_AddRefed<nsPIDOMWindowInner> Navigator::GetWindowFromGlobal(
1957 JSObject* aGlobal) {
1958 nsCOMPtr<nsPIDOMWindowInner> win = xpc::WindowOrNull(aGlobal);
1959 return win.forget();
1962 void Navigator::ClearPlatformCache() {
1963 Navigator_Binding::ClearCachedPlatformValue(this);
1966 nsresult Navigator::GetPlatform(nsAString& aPlatform, Document* aCallerDoc,
1967 bool aUsePrefOverriddenValue) {
1968 MOZ_ASSERT(NS_IsMainThread());
1970 if (aUsePrefOverriddenValue) {
1971 // If fingerprinting resistance is on, we will spoof this value. See
1972 // nsRFPService.h for details about spoofed values.
1973 if (ShouldResistFingerprinting(aCallerDoc, RFPTarget::NavigatorPlatform)) {
1974 aPlatform.AssignLiteral(SPOOFED_PLATFORM);
1975 return NS_OK;
1977 nsAutoString override;
1978 nsresult rv =
1979 mozilla::Preferences::GetString("general.platform.override", override);
1981 if (NS_SUCCEEDED(rv)) {
1982 aPlatform = override;
1983 return NS_OK;
1987 #if defined(WIN32)
1988 aPlatform.AssignLiteral("Win32");
1989 #elif defined(XP_MACOSX)
1990 // Always return "MacIntel", even on ARM64 macOS like Safari does.
1991 aPlatform.AssignLiteral("MacIntel");
1992 #else
1993 nsresult rv;
1994 nsCOMPtr<nsIHttpProtocolHandler> service(
1995 do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
1996 NS_ENSURE_SUCCESS(rv, rv);
1998 nsAutoCString plat;
1999 rv = service->GetOscpu(plat);
2000 NS_ENSURE_SUCCESS(rv, rv);
2002 CopyASCIItoUTF16(plat, aPlatform);
2003 #endif
2005 return NS_OK;
2008 /* static */
2009 nsresult Navigator::GetAppVersion(nsAString& aAppVersion, Document* aCallerDoc,
2010 bool aUsePrefOverriddenValue) {
2011 MOZ_ASSERT(NS_IsMainThread());
2013 if (aUsePrefOverriddenValue) {
2014 // If fingerprinting resistance is on, we will spoof this value. See
2015 // nsRFPService.h for details about spoofed values.
2016 if (ShouldResistFingerprinting(aCallerDoc,
2017 RFPTarget::NavigatorAppVersion)) {
2018 aAppVersion.AssignLiteral(SPOOFED_APPVERSION);
2019 return NS_OK;
2021 nsAutoString override;
2022 nsresult rv = mozilla::Preferences::GetString("general.appversion.override",
2023 override);
2025 if (NS_SUCCEEDED(rv)) {
2026 aAppVersion = override;
2027 return NS_OK;
2031 nsresult rv;
2033 nsCOMPtr<nsIHttpProtocolHandler> service(
2034 do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
2035 NS_ENSURE_SUCCESS(rv, rv);
2037 nsAutoCString str;
2038 rv = service->GetAppVersion(str);
2039 CopyASCIItoUTF16(str, aAppVersion);
2040 NS_ENSURE_SUCCESS(rv, rv);
2042 aAppVersion.AppendLiteral(" (");
2044 rv = service->GetPlatform(str);
2045 NS_ENSURE_SUCCESS(rv, rv);
2047 AppendASCIItoUTF16(str, aAppVersion);
2048 aAppVersion.Append(char16_t(')'));
2050 return rv;
2053 void Navigator::ClearUserAgentCache() {
2054 Navigator_Binding::ClearCachedUserAgentValue(this);
2057 nsresult Navigator::GetUserAgent(nsPIDOMWindowInner* aWindow,
2058 Document* aCallerDoc,
2059 Maybe<bool> aShouldResistFingerprinting,
2060 nsAString& aUserAgent) {
2061 MOZ_ASSERT(NS_IsMainThread());
2064 ResistFingerprinting is migrating to fine-grained control based off
2065 either a channel or Principal+OriginAttributes
2067 This function can be called from Workers, Main Thread, and at least one
2068 other (unusual) case.
2070 For Main Thread, we will generally have a window and an associated
2071 Document, for Workers we will not.
2073 If aShouldResistFingerprinting is provided, we should respect it.
2074 If it is not provided, we will use aCallerDoc to determine our behavior.
2077 bool shouldResistFingerprinting =
2078 aShouldResistFingerprinting.isSome()
2079 ? aShouldResistFingerprinting.value()
2080 : ShouldResistFingerprinting(aCallerDoc,
2081 RFPTarget::NavigatorUserAgent);
2083 // We will skip the override and pass to httpHandler to get spoofed userAgent
2084 // when 'privacy.resistFingerprinting' is true.
2085 if (!shouldResistFingerprinting) {
2086 nsAutoString override;
2087 nsresult rv =
2088 mozilla::Preferences::GetString("general.useragent.override", override);
2090 if (NS_SUCCEEDED(rv)) {
2091 aUserAgent = override;
2092 return NS_OK;
2096 // When the caller is content and 'privacy.resistFingerprinting' is true,
2097 // return a spoofed userAgent which reveals the platform but not the
2098 // specific OS version, etc.
2099 if (shouldResistFingerprinting) {
2100 nsAutoCString spoofedUA;
2101 nsRFPService::GetSpoofedUserAgent(spoofedUA, false);
2102 CopyASCIItoUTF16(spoofedUA, aUserAgent);
2103 return NS_OK;
2106 nsresult rv;
2107 nsCOMPtr<nsIHttpProtocolHandler> service(
2108 do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
2109 if (NS_WARN_IF(NS_FAILED(rv))) {
2110 return rv;
2113 nsAutoCString ua;
2114 rv = service->GetUserAgent(ua);
2115 if (NS_WARN_IF(NS_FAILED(rv))) {
2116 return rv;
2119 CopyASCIItoUTF16(ua, aUserAgent);
2121 if (!aWindow) {
2122 return NS_OK;
2125 // Copy the User-Agent header from the document channel which has already been
2126 // subject to UA overrides.
2127 nsCOMPtr<Document> doc = aWindow->GetExtantDoc();
2128 if (!doc) {
2129 return NS_OK;
2131 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(doc->GetChannel());
2132 if (httpChannel) {
2133 nsAutoCString userAgent;
2134 rv = httpChannel->GetRequestHeader("User-Agent"_ns, userAgent);
2135 if (NS_WARN_IF(NS_FAILED(rv))) {
2136 return rv;
2138 CopyASCIItoUTF16(userAgent, aUserAgent);
2140 return NS_OK;
2143 static nsCString RequestKeySystemAccessLogString(
2144 const nsAString& aKeySystem,
2145 const Sequence<MediaKeySystemConfiguration>& aConfigs,
2146 bool aIsSecureContext) {
2147 nsCString str;
2148 str.AppendPrintf(
2149 "Navigator::RequestMediaKeySystemAccess(keySystem='%s' options=",
2150 NS_ConvertUTF16toUTF8(aKeySystem).get());
2151 str.Append(MediaKeySystemAccess::ToCString(aConfigs));
2152 str.AppendLiteral(") secureContext=");
2153 str.AppendInt(aIsSecureContext);
2154 return str;
2157 already_AddRefed<Promise> Navigator::RequestMediaKeySystemAccess(
2158 const nsAString& aKeySystem,
2159 const Sequence<MediaKeySystemConfiguration>& aConfigs, ErrorResult& aRv) {
2160 EME_LOG("%s", RequestKeySystemAccessLogString(aKeySystem, aConfigs,
2161 mWindow->IsSecureContext())
2162 .get());
2164 if (!mWindow->IsSecureContext()) {
2165 Document* doc = mWindow->GetExtantDoc();
2166 AutoTArray<nsString, 1> params;
2167 nsString* uri = params.AppendElement();
2168 if (doc) {
2169 Unused << doc->GetDocumentURI(*uri);
2171 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, "Media"_ns,
2172 doc, nsContentUtils::eDOM_PROPERTIES,
2173 "MediaEMEInsecureContextDeprecatedWarning",
2174 params);
2177 Document* doc = mWindow->GetExtantDoc();
2178 if (doc &&
2179 !FeaturePolicyUtils::IsFeatureAllowed(doc, u"encrypted-media"_ns)) {
2180 aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
2181 return nullptr;
2184 RefPtr<DetailedPromise> promise = DetailedPromise::Create(
2185 mWindow->AsGlobal(), aRv, "navigator.requestMediaKeySystemAccess"_ns);
2186 if (aRv.Failed()) {
2187 return nullptr;
2190 if (!mMediaKeySystemAccessManager) {
2191 mMediaKeySystemAccessManager = new MediaKeySystemAccessManager(mWindow);
2194 mMediaKeySystemAccessManager->Request(promise, aKeySystem, aConfigs);
2195 return promise.forget();
2198 CredentialsContainer* Navigator::Credentials() {
2199 if (!mCredentials) {
2200 mCredentials = new CredentialsContainer(GetWindow());
2202 return mCredentials;
2205 dom::MediaCapabilities* Navigator::MediaCapabilities() {
2206 if (!mMediaCapabilities) {
2207 mMediaCapabilities = new dom::MediaCapabilities(GetWindow()->AsGlobal());
2209 return mMediaCapabilities;
2212 dom::MediaSession* Navigator::MediaSession() {
2213 if (!mMediaSession) {
2214 mMediaSession = new dom::MediaSession(GetWindow());
2216 return mMediaSession;
2219 bool Navigator::HasCreatedMediaSession() const {
2220 return mMediaSession != nullptr;
2223 Clipboard* Navigator::Clipboard() {
2224 if (!mClipboard) {
2225 mClipboard = new dom::Clipboard(GetWindow());
2227 return mClipboard;
2230 AddonManager* Navigator::GetMozAddonManager(ErrorResult& aRv) {
2231 if (!mAddonManager) {
2232 nsPIDOMWindowInner* win = GetWindow();
2233 if (!win) {
2234 aRv.Throw(NS_ERROR_UNEXPECTED);
2235 return nullptr;
2238 mAddonManager = ConstructJSImplementation<AddonManager>(
2239 "@mozilla.org/addon-web-api/manager;1", win->AsGlobal(), aRv);
2240 if (aRv.Failed()) {
2241 return nullptr;
2245 return mAddonManager;
2248 webgpu::Instance* Navigator::Gpu() {
2249 if (!mWebGpu) {
2250 mWebGpu = webgpu::Instance::Create(GetWindow()->AsGlobal());
2252 return mWebGpu;
2255 dom::LockManager* Navigator::Locks() {
2256 if (!mLocks) {
2257 mLocks = dom::LockManager::Create(*GetWindow()->AsGlobal());
2259 return mLocks;
2262 /* static */
2263 bool Navigator::Webdriver() {
2264 #ifdef ENABLE_WEBDRIVER
2265 nsCOMPtr<nsIMarionette> marionette = do_GetService(NS_MARIONETTE_CONTRACTID);
2266 if (marionette) {
2267 bool marionetteRunning = false;
2268 marionette->GetRunning(&marionetteRunning);
2269 if (marionetteRunning) {
2270 return true;
2274 nsCOMPtr<nsIRemoteAgent> agent = do_GetService(NS_REMOTEAGENT_CONTRACTID);
2275 if (agent) {
2276 bool remoteAgentRunning = false;
2277 agent->GetRunning(&remoteAgentRunning);
2278 if (remoteAgentRunning) {
2279 return true;
2282 #endif
2284 return false;
2287 AutoplayPolicy Navigator::GetAutoplayPolicy(AutoplayPolicyMediaType aType) {
2288 if (!mWindow) {
2289 return AutoplayPolicy::Disallowed;
2291 nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
2292 if (!doc) {
2293 return AutoplayPolicy::Disallowed;
2295 return media::AutoplayPolicy::GetAutoplayPolicy(aType, *doc);
2298 AutoplayPolicy Navigator::GetAutoplayPolicy(HTMLMediaElement& aElement) {
2299 return media::AutoplayPolicy::GetAutoplayPolicy(aElement);
2302 AutoplayPolicy Navigator::GetAutoplayPolicy(AudioContext& aContext) {
2303 return media::AutoplayPolicy::GetAutoplayPolicy(aContext);
2306 already_AddRefed<dom::UserActivation> Navigator::UserActivation() {
2307 if (!mUserActivation) {
2308 mUserActivation = new dom::UserActivation(GetWindow());
2310 return do_AddRef(mUserActivation);
2313 dom::WakeLockJS* Navigator::WakeLock() {
2314 if (!mWakeLock) {
2315 mWakeLock = new WakeLockJS(mWindow);
2317 return mWakeLock;
2320 } // namespace mozilla::dom