Bug 1550519 - Show a translucent parent highlight when a subgrid is highlighted....
[gecko.git] / dom / base / Navigator.cpp
blob74ae24387b689eb26e4f00a0b4ba2e224daab778
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/AntiTrackingCommon.h"
15 #include "mozilla/MemoryReporting.h"
16 #include "mozilla/dom/BodyExtractor.h"
17 #include "mozilla/dom/FetchBinding.h"
18 #include "mozilla/dom/File.h"
19 #include "nsGeolocation.h"
20 #include "nsIClassOfService.h"
21 #include "nsIHttpProtocolHandler.h"
22 #include "nsIContentPolicy.h"
23 #include "nsIContentSecurityPolicy.h"
24 #include "nsContentPolicyUtils.h"
25 #include "nsISupportsPriority.h"
26 #include "nsICachingChannel.h"
27 #include "nsIWebProtocolHandlerRegistrar.h"
28 #include "nsICookiePermission.h"
29 #include "nsIScriptSecurityManager.h"
30 #include "nsCharSeparatedTokenizer.h"
31 #include "nsContentUtils.h"
32 #include "nsUnicharUtils.h"
33 #include "mozilla/Preferences.h"
34 #include "mozilla/StaticPrefs.h"
35 #include "mozilla/Telemetry.h"
36 #include "BatteryManager.h"
37 #include "mozilla/dom/CredentialsContainer.h"
38 #include "mozilla/dom/Clipboard.h"
39 #include "mozilla/dom/FeaturePolicyUtils.h"
40 #include "mozilla/dom/GamepadServiceTest.h"
41 #include "mozilla/dom/MediaCapabilities.h"
42 #include "mozilla/dom/WakeLock.h"
43 #include "mozilla/dom/power/PowerManagerService.h"
44 #include "mozilla/dom/MIDIAccessManager.h"
45 #include "mozilla/dom/MIDIOptionsBinding.h"
46 #include "mozilla/dom/Permissions.h"
47 #include "mozilla/dom/Presentation.h"
48 #include "mozilla/dom/ServiceWorkerContainer.h"
49 #include "mozilla/dom/StorageManager.h"
50 #include "mozilla/dom/TCPSocket.h"
51 #include "mozilla/dom/URLSearchParams.h"
52 #include "mozilla/dom/VRDisplay.h"
53 #include "mozilla/dom/VRDisplayEvent.h"
54 #include "mozilla/dom/VRServiceTest.h"
55 #include "mozilla/dom/workerinternals/RuntimeService.h"
56 #include "mozilla/Hal.h"
57 #include "mozilla/ClearOnShutdown.h"
58 #include "mozilla/StaticPtr.h"
59 #include "Connection.h"
60 #include "mozilla/dom/Event.h" // for Event
61 #include "nsGlobalWindow.h"
62 #include "nsIPermissionManager.h"
63 #include "nsMimeTypes.h"
64 #include "nsNetUtil.h"
65 #include "nsRFPService.h"
66 #include "nsStringStream.h"
67 #include "nsComponentManagerUtils.h"
68 #include "nsICookieService.h"
69 #include "nsIStringStream.h"
70 #include "nsIHttpChannel.h"
71 #include "nsIHttpChannelInternal.h"
72 #include "nsStreamUtils.h"
73 #include "WidgetUtils.h"
74 #include "nsIPresentationService.h"
75 #include "nsIScriptError.h"
76 #include "ReferrerInfo.h"
78 #include "nsIExternalProtocolHandler.h"
79 #include "BrowserChild.h"
80 #include "URIUtils.h"
82 #include "mozilla/dom/MediaDevices.h"
83 #include "MediaManager.h"
85 #include "nsIDOMGlobalPropertyInitializer.h"
86 #include "nsJSUtils.h"
88 #include "mozilla/dom/NavigatorBinding.h"
89 #include "mozilla/dom/Promise.h"
91 #include "nsIUploadChannel2.h"
92 #include "mozilla/dom/FormData.h"
93 #include "nsIDocShell.h"
95 #include "mozilla/dom/WorkerPrivate.h"
96 #include "mozilla/dom/WorkerRunnable.h"
98 #if defined(XP_LINUX)
99 # include "mozilla/Hal.h"
100 #endif
102 #include "mozilla/EMEUtils.h"
103 #include "mozilla/DetailedPromise.h"
104 #include "mozilla/Unused.h"
106 namespace mozilla {
107 namespace dom {
109 static bool sVibratorEnabled = false;
110 static uint32_t sMaxVibrateMS = 0;
111 static uint32_t sMaxVibrateListLen = 0;
112 static const nsLiteralCString kVibrationPermissionType =
113 NS_LITERAL_CSTRING("vibration");
115 /* static */
116 void Navigator::Init() {
117 Preferences::AddBoolVarCache(&sVibratorEnabled, "dom.vibrator.enabled", true);
118 Preferences::AddUintVarCache(&sMaxVibrateMS, "dom.vibrator.max_vibrate_ms",
119 10000);
120 Preferences::AddUintVarCache(&sMaxVibrateListLen,
121 "dom.vibrator.max_vibrate_list_len", 128);
124 Navigator::Navigator(nsPIDOMWindowInner* aWindow) : mWindow(aWindow) {}
126 Navigator::~Navigator() { Invalidate(); }
128 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Navigator)
129 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
130 NS_INTERFACE_MAP_ENTRY(nsISupports)
131 NS_INTERFACE_MAP_END
133 NS_IMPL_CYCLE_COLLECTING_ADDREF(Navigator)
134 NS_IMPL_CYCLE_COLLECTING_RELEASE(Navigator)
136 NS_IMPL_CYCLE_COLLECTION_CLASS(Navigator)
138 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Navigator)
139 tmp->Invalidate();
140 NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
141 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
142 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
144 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
145 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMimeTypes)
146 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlugins)
147 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPermissions)
148 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGeolocation)
149 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryManager)
150 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryPromise)
151 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
152 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStorageManager)
153 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCredentials)
154 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaDevices)
155 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerContainer)
156 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaCapabilities)
158 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
159 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaKeySystemAccessManager)
160 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresentation)
161 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGamepadServiceTest)
162 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVRGetDisplaysPromises)
163 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVRServiceTest)
164 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
166 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(Navigator)
168 void Navigator::Invalidate() {
169 // Don't clear mWindow here so we know we've got a non-null mWindow
170 // until we're unlinked.
172 mMimeTypes = nullptr;
174 if (mPlugins) {
175 mPlugins->Invalidate();
176 mPlugins = nullptr;
179 mPermissions = nullptr;
181 mStorageManager = nullptr;
183 // If there is a page transition, make sure delete the geolocation object.
184 if (mGeolocation) {
185 mGeolocation->Shutdown();
186 mGeolocation = nullptr;
189 if (mBatteryManager) {
190 mBatteryManager->Shutdown();
191 mBatteryManager = nullptr;
194 mBatteryPromise = nullptr;
196 if (mConnection) {
197 mConnection->Shutdown();
198 mConnection = nullptr;
201 mMediaDevices = nullptr;
203 if (mPresentation) {
204 mPresentation = nullptr;
207 mServiceWorkerContainer = nullptr;
209 if (mMediaKeySystemAccessManager) {
210 mMediaKeySystemAccessManager->Shutdown();
211 mMediaKeySystemAccessManager = nullptr;
214 if (mGamepadServiceTest) {
215 mGamepadServiceTest->Shutdown();
216 mGamepadServiceTest = nullptr;
219 mVRGetDisplaysPromises.Clear();
221 if (mVRServiceTest) {
222 mVRServiceTest->Shutdown();
223 mVRServiceTest = nullptr;
226 mMediaCapabilities = nullptr;
229 void Navigator::GetUserAgent(nsAString& aUserAgent, CallerType aCallerType,
230 ErrorResult& aRv) const {
231 nsCOMPtr<nsPIDOMWindowInner> window;
233 if (mWindow) {
234 window = mWindow;
235 nsIDocShell* docshell = window->GetDocShell();
236 nsString customUserAgent;
237 if (docshell) {
238 docshell->GetCustomUserAgent(customUserAgent);
240 if (!customUserAgent.IsEmpty()) {
241 aUserAgent = customUserAgent;
242 return;
247 nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
249 nsresult rv = GetUserAgent(window, doc ? doc->NodePrincipal() : nullptr,
250 aCallerType == CallerType::System, aUserAgent);
251 if (NS_WARN_IF(NS_FAILED(rv))) {
252 aRv.Throw(rv);
256 void Navigator::GetAppCodeName(nsAString& aAppCodeName, ErrorResult& aRv) {
257 nsresult rv;
259 nsCOMPtr<nsIHttpProtocolHandler> service(
260 do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
261 if (NS_WARN_IF(NS_FAILED(rv))) {
262 aRv.Throw(rv);
263 return;
266 nsAutoCString appName;
267 rv = service->GetAppName(appName);
268 if (NS_WARN_IF(NS_FAILED(rv))) {
269 aRv.Throw(rv);
270 return;
273 CopyASCIItoUTF16(appName, aAppCodeName);
276 void Navigator::GetAppVersion(nsAString& aAppVersion, CallerType aCallerType,
277 ErrorResult& aRv) const {
278 nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
280 nsresult rv = GetAppVersion(
281 aAppVersion, doc ? doc->NodePrincipal() : nullptr,
282 /* aUsePrefOverriddenValue = */ aCallerType != CallerType::System);
283 if (NS_WARN_IF(NS_FAILED(rv))) {
284 aRv.Throw(rv);
288 void Navigator::GetAppName(nsAString& aAppName, CallerType aCallerType) const {
289 nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
291 AppName(aAppName, doc ? doc->NodePrincipal() : nullptr,
292 /* aUsePrefOverriddenValue = */ aCallerType != CallerType::System);
296 * Returns the value of Accept-Languages (HTTP header) as a nsTArray of
297 * languages. The value is set in the preference by the user ("Content
298 * Languages").
300 * "en", "en-US" and "i-cherokee" and "" are valid languages tokens.
302 * An empty array will be returned if there is no valid languages.
304 /* static */
305 void Navigator::GetAcceptLanguages(nsTArray<nsString>& aLanguages) {
306 MOZ_ASSERT(NS_IsMainThread());
308 aLanguages.Clear();
310 // E.g. "de-de, en-us,en".
311 nsAutoString acceptLang;
312 Preferences::GetLocalizedString("intl.accept_languages", acceptLang);
314 // Split values on commas.
315 nsCharSeparatedTokenizer langTokenizer(acceptLang, ',');
316 while (langTokenizer.hasMoreTokens()) {
317 nsDependentSubstring lang = langTokenizer.nextToken();
319 // Replace "_" with "-" to avoid POSIX/Windows "en_US" notation.
320 // NOTE: we should probably rely on the pref being set correctly.
321 if (lang.Length() > 2 && lang[2] == char16_t('_')) {
322 lang.Replace(2, 1, char16_t('-'));
325 // Use uppercase for country part, e.g. "en-US", not "en-us", see BCP47
326 // only uppercase 2-letter country codes, not "zh-Hant", "de-DE-x-goethe".
327 // NOTE: we should probably rely on the pref being set correctly.
328 if (lang.Length() > 2) {
329 nsCharSeparatedTokenizer localeTokenizer(lang, '-');
330 int32_t pos = 0;
331 bool first = true;
332 while (localeTokenizer.hasMoreTokens()) {
333 const nsAString& code = localeTokenizer.nextToken();
335 if (code.Length() == 2 && !first) {
336 nsAutoString upper(code);
337 ToUpperCase(upper);
338 lang.Replace(pos, code.Length(), upper);
341 pos += code.Length() + 1; // 1 is the separator
342 first = false;
346 aLanguages.AppendElement(lang);
351 * Do not use UI language (chosen app locale) here but the first value set in
352 * the Accept Languages header, see ::GetAcceptLanguages().
354 * See RFC 2616, Section 15.1.4 "Privacy Issues Connected to Accept Headers" for
355 * the reasons why.
357 void Navigator::GetLanguage(nsAString& aLanguage) {
358 nsTArray<nsString> languages;
359 GetLanguages(languages);
360 if (languages.Length() >= 1) {
361 aLanguage.Assign(languages[0]);
362 } else {
363 aLanguage.Truncate();
367 void Navigator::GetLanguages(nsTArray<nsString>& aLanguages) {
368 GetAcceptLanguages(aLanguages);
370 // The returned value is cached by the binding code. The window listen to the
371 // accept languages change and will clear the cache when needed. It has to
372 // take care of dispatching the DOM event already and the invalidation and the
373 // event has to be timed correctly.
376 void Navigator::GetPlatform(nsAString& aPlatform, CallerType aCallerType,
377 ErrorResult& aRv) const {
378 nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
380 nsresult rv = GetPlatform(
381 aPlatform, doc ? doc->NodePrincipal() : nullptr,
382 /* aUsePrefOverriddenValue = */ aCallerType != CallerType::System);
383 if (NS_WARN_IF(NS_FAILED(rv))) {
384 aRv.Throw(rv);
388 void Navigator::GetOscpu(nsAString& aOSCPU, CallerType aCallerType,
389 ErrorResult& aRv) const {
390 if (aCallerType != CallerType::System) {
391 // If fingerprinting resistance is on, we will spoof this value. See
392 // nsRFPService.h for details about spoofed values.
393 if (nsContentUtils::ShouldResistFingerprinting(GetDocShell())) {
394 aOSCPU.AssignLiteral(SPOOFED_OSCPU);
395 return;
398 nsAutoString override;
399 nsresult rv = Preferences::GetString("general.oscpu.override", override);
400 if (NS_SUCCEEDED(rv)) {
401 aOSCPU = override;
402 return;
406 nsresult rv;
407 nsCOMPtr<nsIHttpProtocolHandler> service(
408 do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
409 if (NS_WARN_IF(NS_FAILED(rv))) {
410 aRv.Throw(rv);
411 return;
414 nsAutoCString oscpu;
415 rv = service->GetOscpu(oscpu);
416 if (NS_WARN_IF(NS_FAILED(rv))) {
417 aRv.Throw(rv);
418 return;
421 CopyASCIItoUTF16(oscpu, aOSCPU);
424 void Navigator::GetVendor(nsAString& aVendor) { aVendor.Truncate(); }
426 void Navigator::GetVendorSub(nsAString& aVendorSub) { aVendorSub.Truncate(); }
428 void Navigator::GetProduct(nsAString& aProduct) {
429 aProduct.AssignLiteral("Gecko");
432 void Navigator::GetProductSub(nsAString& aProductSub) {
433 // Legacy build date hardcoded for backward compatibility (bug 776376)
434 aProductSub.AssignLiteral(LEGACY_UA_GECKO_TRAIL);
437 nsMimeTypeArray* Navigator::GetMimeTypes(ErrorResult& aRv) {
438 if (!mMimeTypes) {
439 if (!mWindow) {
440 aRv.Throw(NS_ERROR_UNEXPECTED);
441 return nullptr;
443 mMimeTypes = new nsMimeTypeArray(mWindow);
446 return mMimeTypes;
449 nsPluginArray* Navigator::GetPlugins(ErrorResult& aRv) {
450 if (!mPlugins) {
451 if (!mWindow) {
452 aRv.Throw(NS_ERROR_UNEXPECTED);
453 return nullptr;
455 mPlugins = new nsPluginArray(mWindow);
456 mPlugins->Init();
459 return mPlugins;
462 Permissions* Navigator::GetPermissions(ErrorResult& aRv) {
463 if (!mWindow) {
464 aRv.Throw(NS_ERROR_UNEXPECTED);
465 return nullptr;
468 if (!mPermissions) {
469 mPermissions = new Permissions(mWindow);
472 return mPermissions;
475 StorageManager* Navigator::Storage() {
476 MOZ_ASSERT(mWindow);
478 if (!mStorageManager) {
479 mStorageManager = new StorageManager(mWindow->AsGlobal());
482 return mStorageManager;
485 bool Navigator::CookieEnabled() {
486 bool cookieEnabled = (StaticPrefs::network_cookie_cookieBehavior() !=
487 nsICookieService::BEHAVIOR_REJECT);
489 // Check whether an exception overrides the global cookie behavior
490 // Note that the code for getting the URI here matches that in
491 // nsHTMLDocument::SetCookie.
492 if (!mWindow || !mWindow->GetDocShell()) {
493 return cookieEnabled;
496 nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
497 if (!doc) {
498 return cookieEnabled;
501 nsCOMPtr<nsIURI> codebaseURI;
502 doc->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
504 if (!codebaseURI) {
505 // Not a codebase, so technically can't set cookies, but let's
506 // just return the default value.
507 return cookieEnabled;
510 uint32_t rejectedReason = 0;
511 bool granted = AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(
512 mWindow, codebaseURI, &rejectedReason);
514 AntiTrackingCommon::NotifyBlockingDecision(
515 mWindow,
516 granted ? AntiTrackingCommon::BlockingDecision::eAllow
517 : AntiTrackingCommon::BlockingDecision::eBlock,
518 rejectedReason);
519 return granted;
522 bool Navigator::OnLine() { return !NS_IsOffline(); }
524 void Navigator::GetBuildID(nsAString& aBuildID, CallerType aCallerType,
525 ErrorResult& aRv) const {
526 if (aCallerType != CallerType::System) {
527 // If fingerprinting resistance is on, we will spoof this value. See
528 // nsRFPService.h for details about spoofed values.
529 if (nsContentUtils::ShouldResistFingerprinting(GetDocShell())) {
530 aBuildID.AssignLiteral(LEGACY_BUILD_ID);
531 return;
534 nsAutoString override;
535 nsresult rv = Preferences::GetString("general.buildID.override", override);
536 if (NS_SUCCEEDED(rv)) {
537 aBuildID = override;
538 return;
541 nsAutoCString host;
542 bool isHTTPS = false;
543 if (mWindow) {
544 nsCOMPtr<Document> doc = mWindow->GetDoc();
545 if (doc) {
546 nsIURI* uri = doc->GetDocumentURI();
547 if (uri) {
548 MOZ_ALWAYS_SUCCEEDS(uri->SchemeIs("https", &isHTTPS));
549 if (isHTTPS) {
550 MOZ_ALWAYS_SUCCEEDS(uri->GetHost(host));
556 // Spoof the buildID on pages not loaded from "https://*.mozilla.org".
557 if (!isHTTPS || !StringEndsWith(host, NS_LITERAL_CSTRING(".mozilla.org"))) {
558 aBuildID.AssignLiteral(LEGACY_BUILD_ID);
559 return;
563 nsCOMPtr<nsIXULAppInfo> appInfo =
564 do_GetService("@mozilla.org/xre/app-info;1");
565 if (!appInfo) {
566 aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
567 return;
570 nsAutoCString buildID;
571 nsresult rv = appInfo->GetAppBuildID(buildID);
572 if (NS_WARN_IF(NS_FAILED(rv))) {
573 aRv.Throw(rv);
574 return;
577 aBuildID.Truncate();
578 AppendASCIItoUTF16(buildID, aBuildID);
581 void Navigator::GetDoNotTrack(nsAString& aResult) {
582 bool doNotTrack = StaticPrefs::privacy_donottrackheader_enabled();
583 if (!doNotTrack) {
584 nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(mWindow);
585 doNotTrack = loadContext && loadContext->UseTrackingProtection();
588 if (doNotTrack) {
589 aResult.AssignLiteral("1");
590 } else {
591 aResult.AssignLiteral("unspecified");
595 uint64_t Navigator::HardwareConcurrency() {
596 workerinternals::RuntimeService* rts =
597 workerinternals::RuntimeService::GetOrCreateService();
598 if (!rts) {
599 return 1;
602 return rts->ClampedHardwareConcurrency();
605 void Navigator::RefreshMIMEArray() {
606 if (mMimeTypes) {
607 mMimeTypes->Refresh();
611 namespace {
613 class VibrateWindowListener : public nsIDOMEventListener {
614 public:
615 VibrateWindowListener(nsPIDOMWindowInner* aWindow, Document* aDocument) {
616 mWindow = do_GetWeakReference(aWindow);
617 mDocument = do_GetWeakReference(aDocument);
619 NS_NAMED_LITERAL_STRING(visibilitychange, "visibilitychange");
620 aDocument->AddSystemEventListener(visibilitychange, this, /* listener */
621 true, /* use capture */
622 false /* wants untrusted */);
625 void RemoveListener();
627 NS_DECL_ISUPPORTS
628 NS_DECL_NSIDOMEVENTLISTENER
630 private:
631 virtual ~VibrateWindowListener() {}
633 nsWeakPtr mWindow;
634 nsWeakPtr mDocument;
637 NS_IMPL_ISUPPORTS(VibrateWindowListener, nsIDOMEventListener)
639 StaticRefPtr<VibrateWindowListener> gVibrateWindowListener;
641 static bool MayVibrate(Document* doc) {
642 // Hidden documents cannot start or stop a vibration.
643 return (doc && !doc->Hidden());
646 NS_IMETHODIMP
647 VibrateWindowListener::HandleEvent(Event* aEvent) {
648 nsCOMPtr<Document> doc = do_QueryInterface(aEvent->GetTarget());
650 if (!MayVibrate(doc)) {
651 // It's important that we call CancelVibrate(), not Vibrate() with an
652 // empty list, because Vibrate() will fail if we're no longer focused, but
653 // CancelVibrate() will succeed, so long as nobody else has started a new
654 // vibration pattern.
655 nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(mWindow);
656 hal::CancelVibrate(window);
657 RemoveListener();
658 gVibrateWindowListener = nullptr;
659 // Careful: The line above might have deleted |this|!
662 return NS_OK;
665 void VibrateWindowListener::RemoveListener() {
666 nsCOMPtr<EventTarget> target = do_QueryReferent(mDocument);
667 if (!target) {
668 return;
670 NS_NAMED_LITERAL_STRING(visibilitychange, "visibilitychange");
671 target->RemoveSystemEventListener(visibilitychange, this,
672 true /* use capture */);
675 } // namespace
677 void Navigator::SetVibrationPermission(bool aPermitted, bool aPersistent) {
678 MOZ_ASSERT(NS_IsMainThread());
680 nsTArray<uint32_t> pattern;
681 pattern.SwapElements(mRequestedVibrationPattern);
683 if (!mWindow) {
684 return;
687 nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
689 if (!MayVibrate(doc)) {
690 return;
693 if (aPermitted) {
694 // Add a listener to cancel the vibration if the document becomes hidden,
695 // and remove the old visibility listener, if there was one.
696 if (!gVibrateWindowListener) {
697 // If gVibrateWindowListener is null, this is the first time we've
698 // vibrated, and we need to register a listener to clear
699 // gVibrateWindowListener on shutdown.
700 ClearOnShutdown(&gVibrateWindowListener);
701 } else {
702 gVibrateWindowListener->RemoveListener();
704 gVibrateWindowListener = new VibrateWindowListener(mWindow, doc);
705 hal::Vibrate(pattern, mWindow);
708 if (aPersistent) {
709 nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
710 if (!permMgr) {
711 return;
713 permMgr->AddFromPrincipal(doc->NodePrincipal(), kVibrationPermissionType,
714 aPermitted ? nsIPermissionManager::ALLOW_ACTION
715 : nsIPermissionManager::DENY_ACTION,
716 nsIPermissionManager::EXPIRE_SESSION, 0);
720 bool Navigator::Vibrate(uint32_t aDuration) {
721 AutoTArray<uint32_t, 1> pattern;
722 pattern.AppendElement(aDuration);
723 return Vibrate(pattern);
726 bool Navigator::Vibrate(const nsTArray<uint32_t>& aPattern) {
727 MOZ_ASSERT(NS_IsMainThread());
729 if (!mWindow) {
730 return false;
733 nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
735 if (!MayVibrate(doc)) {
736 return false;
739 nsTArray<uint32_t> pattern(aPattern);
741 if (pattern.Length() > sMaxVibrateListLen) {
742 pattern.SetLength(sMaxVibrateListLen);
745 for (size_t i = 0; i < pattern.Length(); ++i) {
746 pattern[i] = std::min(sMaxVibrateMS, pattern[i]);
749 // The spec says we check sVibratorEnabled after we've done the sanity
750 // checking on the pattern.
751 if (!sVibratorEnabled) {
752 return true;
755 mRequestedVibrationPattern.SwapElements(pattern);
756 nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
757 if (!permMgr) {
758 return false;
761 uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION;
763 permMgr->TestPermissionFromPrincipal(doc->NodePrincipal(),
764 kVibrationPermissionType, &permission);
766 if (permission == nsIPermissionManager::ALLOW_ACTION ||
767 mRequestedVibrationPattern.IsEmpty() ||
768 (mRequestedVibrationPattern.Length() == 1 &&
769 mRequestedVibrationPattern[0] == 0)) {
770 // Always allow cancelling vibration and respect session permissions.
771 SetVibrationPermission(true /* permitted */, false /* persistent */);
772 return true;
775 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
776 if (!obs || permission == nsIPermissionManager::DENY_ACTION) {
777 // Abort without observer service or on denied session permission.
778 SetVibrationPermission(false /* permitted */, false /* persistent */);
779 return true;
782 // Request user permission.
783 obs->NotifyObservers(ToSupports(this), "Vibration:Request", nullptr);
785 return true;
788 //*****************************************************************************
789 // Pointer Events interface
790 //*****************************************************************************
792 uint32_t Navigator::MaxTouchPoints(CallerType aCallerType) {
793 // The maxTouchPoints is going to reveal the detail of users' hardware. So,
794 // we will spoof it into 0 if fingerprinting resistance is on.
795 if (aCallerType != CallerType::System &&
796 nsContentUtils::ShouldResistFingerprinting(GetDocShell())) {
797 return 0;
800 nsCOMPtr<nsIWidget> widget =
801 widget::WidgetUtils::DOMWindowToWidget(mWindow->GetOuterWindow());
803 NS_ENSURE_TRUE(widget, 0);
804 return widget->GetMaxTouchPoints();
807 //*****************************************************************************
808 // Navigator::nsIDOMClientInformation
809 //*****************************************************************************
811 void Navigator::RegisterContentHandler(const nsAString& aMIMEType,
812 const nsAString& aURI,
813 const nsAString& aTitle,
814 ErrorResult& aRv) {}
816 // This list should be kept up-to-date with the spec:
817 // https://html.spec.whatwg.org/multipage/system-state.html#custom-handlers
818 static const char* const kSafeSchemes[] = {
819 "bitcoin", "geo", "im", "irc", "ircs", "magnet", "mailto",
820 "mms", "news", "nntp", "openpgp4fpr", "sip", "sms", "smsto",
821 "ssh", "tel", "urn", "webcal", "wtai", "xmpp"};
823 void Navigator::CheckProtocolHandlerAllowed(const nsAString& aScheme,
824 nsIURI* aHandlerURI,
825 nsIURI* aDocumentURI,
826 ErrorResult& aRv) {
827 auto raisePermissionDeniedHandler = [&] {
828 nsAutoCString spec;
829 aHandlerURI->GetSpec(spec);
830 nsPrintfCString message("Permission denied to add %s as a protocol handler",
831 spec.get());
832 aRv.ThrowDOMException(NS_ERROR_DOM_SECURITY_ERR, message);
835 auto raisePermissionDeniedScheme = [&] {
836 nsPrintfCString message(
837 "Permission denied to add a protocol handler for %s",
838 NS_ConvertUTF16toUTF8(aScheme).get());
839 aRv.ThrowDOMException(NS_ERROR_DOM_SECURITY_ERR, message);
842 if (!aDocumentURI || !aHandlerURI) {
843 aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
844 return;
847 nsCString spec;
848 aHandlerURI->GetSpec(spec);
849 // If the uri doesn't contain '%s', it won't be a good handler - the %s
850 // gets replaced with the handled URI.
851 if (!FindInReadable(NS_LITERAL_CSTRING("%s"), spec)) {
852 aRv.ThrowDOMException(NS_ERROR_DOM_SYNTAX_ERR);
853 return;
856 // For security reasons we reject non-http(s) urls (see bug 354316),
857 nsAutoCString docScheme;
858 nsAutoCString handlerScheme;
859 aDocumentURI->GetScheme(docScheme);
860 aHandlerURI->GetScheme(handlerScheme);
861 if ((!docScheme.EqualsLiteral("https") && !docScheme.EqualsLiteral("http")) ||
862 (!handlerScheme.EqualsLiteral("https") &&
863 !handlerScheme.EqualsLiteral("http"))) {
864 raisePermissionDeniedHandler();
865 return;
868 // Should be same-origin:
869 nsAutoCString handlerHost;
870 aHandlerURI->GetHostPort(handlerHost);
871 nsAutoCString documentHost;
872 aDocumentURI->GetHostPort(documentHost);
873 if (!handlerHost.Equals(documentHost) || !handlerScheme.Equals(docScheme)) {
874 raisePermissionDeniedHandler();
875 return;
878 // Having checked the handler URI, check the scheme:
879 nsAutoCString scheme;
880 ToLowerCase(NS_ConvertUTF16toUTF8(aScheme), scheme);
881 if (StringBeginsWith(scheme, NS_LITERAL_CSTRING("web+"))) {
882 // Check for non-ascii
883 nsReadingIterator<char> iter;
884 nsReadingIterator<char> iterEnd;
885 auto remainingScheme = Substring(scheme, 4 /* web+ */);
886 remainingScheme.BeginReading(iter);
887 remainingScheme.EndReading(iterEnd);
888 // Scheme suffix must be non-empty
889 if (iter == iterEnd) {
890 raisePermissionDeniedScheme();
891 return;
893 for (; iter != iterEnd; iter++) {
894 if (*iter < 'a' || *iter > 'z') {
895 raisePermissionDeniedScheme();
896 return;
899 } else {
900 bool matches = false;
901 for (const char* safeScheme : kSafeSchemes) {
902 if (scheme.Equals(safeScheme)) {
903 matches = true;
904 break;
907 if (!matches) {
908 raisePermissionDeniedScheme();
909 return;
913 nsCOMPtr<nsIProtocolHandler> handler;
914 nsCOMPtr<nsIIOService> io = services::GetIOService();
915 if (NS_FAILED(
916 io->GetProtocolHandler(scheme.get(), getter_AddRefs(handler)))) {
917 raisePermissionDeniedScheme();
918 return;
921 // Check to make sure this isn't already handled internally (we don't
922 // want to let them take over, say "chrome"). In theory, the checks above
923 // should have already taken care of this.
924 nsCOMPtr<nsIExternalProtocolHandler> externalHandler =
925 do_QueryInterface(handler);
926 MOZ_RELEASE_ASSERT(
927 externalHandler,
928 "We should never allow overriding a builtin protocol handler");
930 // check if we have prefs set saying not to add this.
931 bool defaultExternal =
932 Preferences::GetBool("network.protocol-handler.external-default");
933 nsPrintfCString specificPref("network.protocol-handler.external.%s",
934 scheme.get());
935 if (!Preferences::GetBool(specificPref.get(), defaultExternal)) {
936 raisePermissionDeniedScheme();
937 return;
941 void Navigator::RegisterProtocolHandler(const nsAString& aScheme,
942 const nsAString& aURI,
943 const nsAString& aTitle,
944 ErrorResult& aRv) {
945 if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell() ||
946 !mWindow->GetDoc()) {
947 return;
949 nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(mWindow);
950 if (loadContext->UsePrivateBrowsing()) {
951 // If we're a private window, don't alert the user or webpage. We log to the
952 // console so that web developers have some way to tell what's going wrong.
953 nsContentUtils::ReportToConsole(
954 nsIScriptError::warningFlag, NS_LITERAL_CSTRING("DOM"),
955 mWindow->GetDoc(), nsContentUtils::eDOM_PROPERTIES,
956 "RegisterProtocolHandlerPrivateBrowsingWarning");
957 return;
960 nsCOMPtr<Document> doc = mWindow->GetDoc();
961 if (!mWindow->IsSecureContext()) {
962 doc->WarnOnceAbout(Document::eRegisterProtocolHandlerInsecure);
965 // Determine if doc is allowed to assign this handler
966 nsIURI* docURI = doc->GetDocumentURIObject();
967 nsCOMPtr<nsIURI> handlerURI;
968 NS_NewURI(getter_AddRefs(handlerURI), NS_ConvertUTF16toUTF8(aURI),
969 doc->GetDocumentCharacterSet(), docURI);
970 CheckProtocolHandlerAllowed(aScheme, handlerURI, docURI, aRv);
971 if (aRv.Failed()) {
972 return;
975 if (XRE_IsContentProcess()) {
976 nsAutoString scheme(aScheme);
977 nsAutoString title(aTitle);
978 RefPtr<BrowserChild> browserChild = BrowserChild::GetFrom(mWindow);
979 browserChild->SendRegisterProtocolHandler(scheme, handlerURI, title,
980 docURI);
981 return;
984 nsCOMPtr<nsIWebProtocolHandlerRegistrar> registrar =
985 do_GetService(NS_WEBPROTOCOLHANDLERREGISTRAR_CONTRACTID);
986 if (registrar) {
987 aRv = registrar->RegisterProtocolHandler(aScheme, handlerURI, aTitle,
988 docURI, mWindow->GetOuterWindow());
992 Geolocation* Navigator::GetGeolocation(ErrorResult& aRv) {
993 if (mGeolocation) {
994 return mGeolocation;
997 if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) {
998 aRv.Throw(NS_ERROR_FAILURE);
999 return nullptr;
1002 mGeolocation = new Geolocation();
1003 if (NS_FAILED(mGeolocation->Init(mWindow))) {
1004 mGeolocation = nullptr;
1005 aRv.Throw(NS_ERROR_FAILURE);
1006 return nullptr;
1009 return mGeolocation;
1012 class BeaconStreamListener final : public nsIStreamListener {
1013 ~BeaconStreamListener() {}
1015 public:
1016 BeaconStreamListener() : mLoadGroup(nullptr) {}
1018 void SetLoadGroup(nsILoadGroup* aLoadGroup) { mLoadGroup = aLoadGroup; }
1020 NS_DECL_ISUPPORTS
1021 NS_DECL_NSISTREAMLISTENER
1022 NS_DECL_NSIREQUESTOBSERVER
1024 private:
1025 nsCOMPtr<nsILoadGroup> mLoadGroup;
1028 NS_IMPL_ISUPPORTS(BeaconStreamListener, nsIStreamListener, nsIRequestObserver)
1030 NS_IMETHODIMP
1031 BeaconStreamListener::OnStartRequest(nsIRequest* aRequest) {
1032 // release the loadgroup first
1033 mLoadGroup = nullptr;
1035 aRequest->Cancel(NS_ERROR_NET_INTERRUPT);
1036 return NS_BINDING_ABORTED;
1039 NS_IMETHODIMP
1040 BeaconStreamListener::OnStopRequest(nsIRequest* aRequest, nsresult aStatus) {
1041 return NS_OK;
1044 NS_IMETHODIMP
1045 BeaconStreamListener::OnDataAvailable(nsIRequest* aRequest,
1046 nsIInputStream* inStr,
1047 uint64_t sourceOffset, uint32_t count) {
1048 MOZ_ASSERT(false);
1049 return NS_OK;
1052 bool Navigator::SendBeacon(const nsAString& aUrl,
1053 const Nullable<fetch::BodyInit>& aData,
1054 ErrorResult& aRv) {
1055 if (aData.IsNull()) {
1056 return SendBeaconInternal(aUrl, nullptr, eBeaconTypeOther, aRv);
1059 if (aData.Value().IsArrayBuffer()) {
1060 BodyExtractor<const ArrayBuffer> body(&aData.Value().GetAsArrayBuffer());
1061 return SendBeaconInternal(aUrl, &body, eBeaconTypeArrayBuffer, aRv);
1064 if (aData.Value().IsArrayBufferView()) {
1065 BodyExtractor<const ArrayBufferView> body(
1066 &aData.Value().GetAsArrayBufferView());
1067 return SendBeaconInternal(aUrl, &body, eBeaconTypeArrayBuffer, aRv);
1070 if (aData.Value().IsBlob()) {
1071 BodyExtractor<const Blob> body(&aData.Value().GetAsBlob());
1072 return SendBeaconInternal(aUrl, &body, eBeaconTypeBlob, aRv);
1075 if (aData.Value().IsFormData()) {
1076 BodyExtractor<const FormData> body(&aData.Value().GetAsFormData());
1077 return SendBeaconInternal(aUrl, &body, eBeaconTypeOther, aRv);
1080 if (aData.Value().IsUSVString()) {
1081 BodyExtractor<const nsAString> body(&aData.Value().GetAsUSVString());
1082 return SendBeaconInternal(aUrl, &body, eBeaconTypeOther, aRv);
1085 if (aData.Value().IsURLSearchParams()) {
1086 BodyExtractor<const URLSearchParams> body(
1087 &aData.Value().GetAsURLSearchParams());
1088 return SendBeaconInternal(aUrl, &body, eBeaconTypeOther, aRv);
1091 MOZ_CRASH("Invalid data type.");
1092 return false;
1095 bool Navigator::SendBeaconInternal(const nsAString& aUrl,
1096 BodyExtractorBase* aBody, BeaconType aType,
1097 ErrorResult& aRv) {
1098 if (!mWindow) {
1099 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
1100 return false;
1103 nsCOMPtr<Document> doc = mWindow->GetDoc();
1104 if (!doc) {
1105 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
1106 return false;
1109 nsIURI* documentURI = doc->GetDocumentURI();
1110 if (!documentURI) {
1111 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
1112 return false;
1115 nsCOMPtr<nsIURI> uri;
1116 nsresult rv = nsContentUtils::NewURIWithDocumentCharset(
1117 getter_AddRefs(uri), aUrl, doc, doc->GetDocBaseURI());
1118 if (NS_FAILED(rv)) {
1119 aRv.ThrowTypeError<MSG_INVALID_URL>(aUrl);
1120 return false;
1123 // Spec disallows any schemes save for HTTP/HTTPs
1124 bool isValidScheme;
1125 if (!(NS_SUCCEEDED(uri->SchemeIs("http", &isValidScheme)) && isValidScheme) &&
1126 !(NS_SUCCEEDED(uri->SchemeIs("https", &isValidScheme)) &&
1127 isValidScheme)) {
1128 aRv.ThrowTypeError<MSG_INVALID_URL_SCHEME>(NS_LITERAL_STRING("Beacon"),
1129 aUrl);
1130 return false;
1133 // No need to use CORS for sendBeacon unless it's a BLOB
1134 nsSecurityFlags securityFlags =
1135 aType == eBeaconTypeBlob
1136 ? nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS
1137 : nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS;
1138 securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
1140 nsCOMPtr<nsIChannel> channel;
1141 rv = NS_NewChannel(getter_AddRefs(channel), uri, doc, securityFlags,
1142 nsIContentPolicy::TYPE_BEACON);
1144 if (NS_FAILED(rv)) {
1145 aRv.Throw(rv);
1146 return false;
1149 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
1150 if (!httpChannel) {
1151 // Beacon spec only supports HTTP requests at this time
1152 aRv.Throw(NS_ERROR_DOM_BAD_URI);
1153 return false;
1156 nsCOMPtr<nsIReferrerInfo> referrerInfo =
1157 new ReferrerInfo(doc->GetDocumentURI(), doc->GetReferrerPolicy());
1158 rv = httpChannel->SetReferrerInfoWithoutClone(referrerInfo);
1159 MOZ_ASSERT(NS_SUCCEEDED(rv));
1161 nsCOMPtr<nsIInputStream> in;
1162 nsAutoCString contentTypeWithCharset;
1163 nsAutoCString charset;
1164 uint64_t length = 0;
1166 if (aBody) {
1167 aRv = aBody->GetAsStream(getter_AddRefs(in), &length,
1168 contentTypeWithCharset, charset);
1169 if (NS_WARN_IF(aRv.Failed())) {
1170 return false;
1173 nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(channel);
1174 if (!uploadChannel) {
1175 aRv.Throw(NS_ERROR_FAILURE);
1176 return false;
1179 uploadChannel->ExplicitSetUploadStream(in, contentTypeWithCharset, length,
1180 NS_LITERAL_CSTRING("POST"), false);
1181 } else {
1182 rv = httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
1183 MOZ_ASSERT(NS_SUCCEEDED(rv));
1186 nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(channel);
1187 if (p) {
1188 p->SetPriority(nsISupportsPriority::PRIORITY_LOWEST);
1191 nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
1192 if (cos) {
1193 cos->AddClassFlags(nsIClassOfService::Background);
1196 // The channel needs to have a loadgroup associated with it, so that we can
1197 // cancel the channel and any redirected channels it may create.
1198 nsCOMPtr<nsILoadGroup> loadGroup = do_CreateInstance(NS_LOADGROUP_CONTRACTID);
1199 nsCOMPtr<nsIInterfaceRequestor> callbacks =
1200 do_QueryInterface(mWindow->GetDocShell());
1201 loadGroup->SetNotificationCallbacks(callbacks);
1202 channel->SetLoadGroup(loadGroup);
1204 RefPtr<BeaconStreamListener> beaconListener = new BeaconStreamListener();
1205 rv = channel->AsyncOpen(beaconListener);
1206 // do not throw if security checks fail within asyncOpen
1207 NS_ENSURE_SUCCESS(rv, false);
1209 // make the beaconListener hold a strong reference to the loadgroup
1210 // which is released in ::OnStartRequest
1211 beaconListener->SetLoadGroup(loadGroup);
1213 return true;
1216 MediaDevices* Navigator::GetMediaDevices(ErrorResult& aRv) {
1217 if (!mMediaDevices) {
1218 if (!mWindow || !mWindow->GetOuterWindow() ||
1219 mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) {
1220 aRv.Throw(NS_ERROR_NOT_AVAILABLE);
1221 return nullptr;
1223 mMediaDevices = new MediaDevices(mWindow);
1225 return mMediaDevices;
1228 void Navigator::MozGetUserMedia(const MediaStreamConstraints& aConstraints,
1229 NavigatorUserMediaSuccessCallback& aOnSuccess,
1230 NavigatorUserMediaErrorCallback& aOnError,
1231 CallerType aCallerType, ErrorResult& aRv) {
1232 MOZ_ASSERT(NS_IsMainThread());
1234 if (!mWindow || !mWindow->GetOuterWindow() ||
1235 mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) {
1236 aRv.Throw(NS_ERROR_NOT_AVAILABLE);
1237 return;
1240 RefPtr<NavigatorUserMediaSuccessCallback> onsuccess(&aOnSuccess);
1241 RefPtr<NavigatorUserMediaErrorCallback> onerror(&aOnError);
1243 nsWeakPtr weakWindow = nsWeakPtr(do_GetWeakReference(mWindow));
1245 MediaManager::Get()
1246 ->GetUserMedia(mWindow, aConstraints, aCallerType)
1247 ->Then(
1248 GetMainThreadSerialEventTarget(), __func__,
1249 [weakWindow, onsuccess = std::move(onsuccess)](
1250 const RefPtr<DOMMediaStream>& aStream) MOZ_CAN_RUN_SCRIPT {
1251 nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(weakWindow);
1252 if (!window || !window->GetOuterWindow() ||
1253 window->GetOuterWindow()->GetCurrentInnerWindow() != window) {
1254 return; // Leave Promise pending after navigation by design.
1256 MediaManager::CallOnSuccess(*onsuccess, *aStream);
1258 [weakWindow, onerror = std::move(onerror)](
1259 const RefPtr<MediaMgrError>& aError) MOZ_CAN_RUN_SCRIPT {
1260 nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(weakWindow);
1261 if (!window || !window->GetOuterWindow() ||
1262 window->GetOuterWindow()->GetCurrentInnerWindow() != window) {
1263 return; // Leave Promise pending after navigation by design.
1265 auto error = MakeRefPtr<MediaStreamError>(window, *aError);
1266 MediaManager::CallOnError(*onerror, *error);
1270 void Navigator::MozGetUserMediaDevices(
1271 const MediaStreamConstraints& aConstraints,
1272 MozGetUserMediaDevicesSuccessCallback& aOnSuccess,
1273 NavigatorUserMediaErrorCallback& aOnError, uint64_t aInnerWindowID,
1274 const nsAString& aCallID, ErrorResult& aRv) {
1275 if (!mWindow || !mWindow->GetOuterWindow() ||
1276 mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) {
1277 aRv.Throw(NS_ERROR_NOT_AVAILABLE);
1278 return;
1280 if (Document* doc = mWindow->GetExtantDoc()) {
1281 if (!mWindow->IsSecureContext()) {
1282 doc->SetDocumentAndPageUseCounter(
1283 eUseCounter_custom_MozGetUserMediaInsec);
1285 nsINode* node = doc;
1286 while ((node = nsContentUtils::GetCrossDocParentNode(node))) {
1287 if (NS_FAILED(nsContentUtils::CheckSameOrigin(doc, node))) {
1288 doc->SetDocumentAndPageUseCounter(
1289 eUseCounter_custom_MozGetUserMediaXOrigin);
1290 break;
1294 RefPtr<MediaManager> manager = MediaManager::Get();
1295 // XXXbz aOnError seems to be unused?
1296 nsCOMPtr<nsPIDOMWindowInner> window(mWindow);
1297 aRv = manager->GetUserMediaDevices(window, aConstraints, aOnSuccess,
1298 aInnerWindowID, aCallID);
1301 //*****************************************************************************
1302 // Navigator::nsINavigatorBattery
1303 //*****************************************************************************
1305 Promise* Navigator::GetBattery(ErrorResult& aRv) {
1306 if (mBatteryPromise) {
1307 return mBatteryPromise;
1310 if (!mWindow || !mWindow->GetDocShell()) {
1311 aRv.Throw(NS_ERROR_UNEXPECTED);
1312 return nullptr;
1315 RefPtr<Promise> batteryPromise = Promise::Create(mWindow->AsGlobal(), aRv);
1316 if (NS_WARN_IF(aRv.Failed())) {
1317 return nullptr;
1319 mBatteryPromise = batteryPromise;
1321 if (!mBatteryManager) {
1322 mBatteryManager = new battery::BatteryManager(mWindow);
1323 mBatteryManager->Init();
1326 mBatteryPromise->MaybeResolve(mBatteryManager);
1328 return mBatteryPromise;
1331 already_AddRefed<LegacyMozTCPSocket> Navigator::MozTCPSocket() {
1332 RefPtr<LegacyMozTCPSocket> socket = new LegacyMozTCPSocket(GetWindow());
1333 return socket.forget();
1336 void Navigator::GetGamepads(nsTArray<RefPtr<Gamepad>>& aGamepads,
1337 ErrorResult& aRv) {
1338 if (!mWindow) {
1339 aRv.Throw(NS_ERROR_UNEXPECTED);
1340 return;
1342 NS_ENSURE_TRUE_VOID(mWindow->GetDocShell());
1343 nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
1344 win->SetHasGamepadEventListener(true);
1345 win->GetGamepads(aGamepads);
1348 GamepadServiceTest* Navigator::RequestGamepadServiceTest() {
1349 if (!mGamepadServiceTest) {
1350 mGamepadServiceTest = GamepadServiceTest::CreateTestService(mWindow);
1352 return mGamepadServiceTest;
1355 already_AddRefed<Promise> Navigator::GetVRDisplays(ErrorResult& aRv) {
1356 if (!mWindow || !mWindow->GetDocShell() || !mWindow->GetExtantDoc()) {
1357 aRv.Throw(NS_ERROR_UNEXPECTED);
1358 return nullptr;
1361 if (!FeaturePolicyUtils::IsFeatureAllowed(mWindow->GetExtantDoc(),
1362 NS_LITERAL_STRING("vr"))) {
1363 aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
1364 return nullptr;
1367 nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
1368 win->NotifyVREventListenerAdded();
1370 RefPtr<Promise> p = Promise::Create(mWindow->AsGlobal(), aRv);
1371 if (aRv.Failed()) {
1372 return nullptr;
1375 // We pass mWindow's id to RefreshVRDisplays, so NotifyVRDisplaysUpdated will
1376 // be called asynchronously, resolving the promises in mVRGetDisplaysPromises.
1377 if (!VRDisplay::RefreshVRDisplays(win->WindowID())) {
1378 p->MaybeReject(NS_ERROR_FAILURE);
1379 return p.forget();
1382 mVRGetDisplaysPromises.AppendElement(p);
1383 return p.forget();
1386 void Navigator::GetActiveVRDisplays(
1387 nsTArray<RefPtr<VRDisplay>>& aDisplays) const {
1389 * Get only the active VR displays.
1390 * GetActiveVRDisplays should only enumerate displays that
1391 * are already active without causing any other hardware to be
1392 * activated.
1393 * We must not call nsGlobalWindow::NotifyVREventListenerAdded here,
1394 * as that would cause enumeration and activation of other VR hardware.
1395 * Activating VR hardware is intrusive to the end user, as it may
1396 * involve physically powering on devices that the user did not
1397 * intend to use.
1399 if (!mWindow || !mWindow->GetDocShell()) {
1400 return;
1402 nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
1403 nsTArray<RefPtr<VRDisplay>> displays;
1404 if (win->UpdateVRDisplays(displays)) {
1405 for (auto display : displays) {
1406 if (display->IsPresenting()) {
1407 aDisplays.AppendElement(display);
1413 void Navigator::NotifyVRDisplaysUpdated() {
1414 // Synchronize the VR devices and resolve the promises in
1415 // mVRGetDisplaysPromises
1416 nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
1418 nsTArray<RefPtr<VRDisplay>> vrDisplays;
1419 if (win->UpdateVRDisplays(vrDisplays)) {
1420 for (auto p : mVRGetDisplaysPromises) {
1421 p->MaybeResolve(vrDisplays);
1423 } else {
1424 for (auto p : mVRGetDisplaysPromises) {
1425 p->MaybeReject(NS_ERROR_FAILURE);
1428 mVRGetDisplaysPromises.Clear();
1431 void Navigator::NotifyActiveVRDisplaysChanged() {
1432 Navigator_Binding::ClearCachedActiveVRDisplaysValue(this);
1435 VRServiceTest* Navigator::RequestVRServiceTest() {
1436 // Ensure that the Mock VR devices are not released prematurely
1437 nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
1438 win->NotifyVREventListenerAdded();
1440 if (!mVRServiceTest) {
1441 mVRServiceTest = VRServiceTest::CreateTestService(mWindow);
1443 return mVRServiceTest;
1446 bool Navigator::IsWebVRContentDetected() const {
1447 nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
1448 return win->IsVRContentDetected();
1451 bool Navigator::IsWebVRContentPresenting() const {
1452 nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
1453 return win->IsVRContentPresenting();
1456 void Navigator::RequestVRPresentation(VRDisplay& aDisplay) {
1457 nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
1458 win->DispatchVRDisplayActivate(aDisplay.DisplayId(),
1459 VRDisplayEventReason::Requested);
1462 already_AddRefed<Promise> Navigator::RequestMIDIAccess(
1463 const MIDIOptions& aOptions, ErrorResult& aRv) {
1464 if (!mWindow) {
1465 aRv.Throw(NS_ERROR_UNEXPECTED);
1466 return nullptr;
1468 MIDIAccessManager* accessMgr = MIDIAccessManager::Get();
1469 return accessMgr->RequestMIDIAccess(mWindow, aOptions, aRv);
1472 network::Connection* Navigator::GetConnection(ErrorResult& aRv) {
1473 if (!mConnection) {
1474 if (!mWindow) {
1475 aRv.Throw(NS_ERROR_UNEXPECTED);
1476 return nullptr;
1478 mConnection = network::Connection::CreateForWindow(mWindow);
1481 return mConnection;
1484 already_AddRefed<ServiceWorkerContainer> Navigator::ServiceWorker() {
1485 MOZ_ASSERT(mWindow);
1487 if (!mServiceWorkerContainer) {
1488 mServiceWorkerContainer =
1489 ServiceWorkerContainer::Create(mWindow->AsGlobal());
1492 RefPtr<ServiceWorkerContainer> ref = mServiceWorkerContainer;
1493 return ref.forget();
1496 size_t Navigator::SizeOfIncludingThis(
1497 mozilla::MallocSizeOf aMallocSizeOf) const {
1498 size_t n = aMallocSizeOf(this);
1500 // TODO: add SizeOfIncludingThis() to nsMimeTypeArray, bug 674113.
1501 // TODO: add SizeOfIncludingThis() to nsPluginArray, bug 674114.
1502 // TODO: add SizeOfIncludingThis() to Geolocation, bug 674115.
1503 // TODO: add SizeOfIncludingThis() to DesktopNotificationCenter, bug 674116.
1505 return n;
1508 void Navigator::SetWindow(nsPIDOMWindowInner* aInnerWindow) {
1509 mWindow = aInnerWindow;
1512 void Navigator::OnNavigation() {
1513 if (!mWindow) {
1514 return;
1517 // If MediaManager is open let it inform any live streams or pending callbacks
1518 MediaManager* manager = MediaManager::GetIfExists();
1519 if (manager) {
1520 manager->OnNavigation(mWindow->WindowID());
1524 JSObject* Navigator::WrapObject(JSContext* cx,
1525 JS::Handle<JSObject*> aGivenProto) {
1526 return Navigator_Binding::Wrap(cx, this, aGivenProto);
1529 /* static */
1530 bool Navigator::HasUserMediaSupport(JSContext* cx, JSObject* obj) {
1531 // Make enabling peerconnection enable getUserMedia() as well.
1532 // Emulate [SecureContext] unless media.devices.insecure.enabled=true
1533 return (StaticPrefs::media_navigator_enabled() ||
1534 StaticPrefs::media_peerconnection_enabled()) &&
1535 (IsSecureContextOrObjectIsFromSecureContext(cx, obj) ||
1536 StaticPrefs::media_devices_insecure_enabled());
1539 /* static */
1540 already_AddRefed<nsPIDOMWindowInner> Navigator::GetWindowFromGlobal(
1541 JSObject* aGlobal) {
1542 nsCOMPtr<nsPIDOMWindowInner> win = xpc::WindowOrNull(aGlobal);
1543 return win.forget();
1546 nsresult Navigator::GetPlatform(nsAString& aPlatform,
1547 nsIPrincipal* aCallerPrincipal,
1548 bool aUsePrefOverriddenValue) {
1549 MOZ_ASSERT(NS_IsMainThread());
1551 if (aUsePrefOverriddenValue) {
1552 // If fingerprinting resistance is on, we will spoof this value. See
1553 // nsRFPService.h for details about spoofed values.
1554 if (nsContentUtils::ShouldResistFingerprinting(aCallerPrincipal)) {
1555 aPlatform.AssignLiteral(SPOOFED_PLATFORM);
1556 return NS_OK;
1558 nsAutoString override;
1559 nsresult rv =
1560 mozilla::Preferences::GetString("general.platform.override", override);
1562 if (NS_SUCCEEDED(rv)) {
1563 aPlatform = override;
1564 return NS_OK;
1568 nsresult rv;
1570 nsCOMPtr<nsIHttpProtocolHandler> service(
1571 do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
1572 NS_ENSURE_SUCCESS(rv, rv);
1574 // Sorry for the #if platform ugliness, but Communicator is likewise
1575 // hardcoded and we are seeking backward compatibility here (bug 47080).
1576 #if defined(WIN32)
1577 aPlatform.AssignLiteral("Win32");
1578 #elif defined(XP_MACOSX) && defined(__ppc__)
1579 aPlatform.AssignLiteral("MacPPC");
1580 #elif defined(XP_MACOSX) && defined(__i386__)
1581 aPlatform.AssignLiteral("MacIntel");
1582 #elif defined(XP_MACOSX) && defined(__x86_64__)
1583 aPlatform.AssignLiteral("MacIntel");
1584 #else
1585 // XXX Communicator uses compiled-in build-time string defines
1586 // to indicate the platform it was compiled *for*, not what it is
1587 // currently running *on* which is what this does.
1588 nsAutoCString plat;
1589 rv = service->GetOscpu(plat);
1590 CopyASCIItoUTF16(plat, aPlatform);
1591 #endif
1593 return rv;
1596 /* static */
1597 nsresult Navigator::GetAppVersion(nsAString& aAppVersion,
1598 nsIPrincipal* aCallerPrincipal,
1599 bool aUsePrefOverriddenValue) {
1600 MOZ_ASSERT(NS_IsMainThread());
1602 if (aUsePrefOverriddenValue) {
1603 // If fingerprinting resistance is on, we will spoof this value. See
1604 // nsRFPService.h for details about spoofed values.
1605 if (nsContentUtils::ShouldResistFingerprinting(aCallerPrincipal)) {
1606 aAppVersion.AssignLiteral(SPOOFED_APPVERSION);
1607 return NS_OK;
1609 nsAutoString override;
1610 nsresult rv = mozilla::Preferences::GetString("general.appversion.override",
1611 override);
1613 if (NS_SUCCEEDED(rv)) {
1614 aAppVersion = override;
1615 return NS_OK;
1619 nsresult rv;
1621 nsCOMPtr<nsIHttpProtocolHandler> service(
1622 do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
1623 NS_ENSURE_SUCCESS(rv, rv);
1625 nsAutoCString str;
1626 rv = service->GetAppVersion(str);
1627 CopyASCIItoUTF16(str, aAppVersion);
1628 NS_ENSURE_SUCCESS(rv, rv);
1630 aAppVersion.AppendLiteral(" (");
1632 rv = service->GetPlatform(str);
1633 NS_ENSURE_SUCCESS(rv, rv);
1635 AppendASCIItoUTF16(str, aAppVersion);
1636 aAppVersion.Append(char16_t(')'));
1638 return rv;
1641 /* static */
1642 void Navigator::AppName(nsAString& aAppName, nsIPrincipal* aCallerPrincipal,
1643 bool aUsePrefOverriddenValue) {
1644 MOZ_ASSERT(NS_IsMainThread());
1646 if (aUsePrefOverriddenValue) {
1647 // If fingerprinting resistance is on, we will spoof this value. See
1648 // nsRFPService.h for details about spoofed values.
1649 if (nsContentUtils::ShouldResistFingerprinting(aCallerPrincipal)) {
1650 aAppName.AssignLiteral(SPOOFED_APPNAME);
1651 return;
1654 nsAutoString override;
1655 nsresult rv =
1656 mozilla::Preferences::GetString("general.appname.override", override);
1658 if (NS_SUCCEEDED(rv)) {
1659 aAppName = override;
1660 return;
1664 aAppName.AssignLiteral("Netscape");
1667 void Navigator::ClearUserAgentCache() {
1668 Navigator_Binding::ClearCachedUserAgentValue(this);
1671 nsresult Navigator::GetUserAgent(nsPIDOMWindowInner* aWindow,
1672 nsIPrincipal* aCallerPrincipal,
1673 bool aIsCallerChrome, nsAString& aUserAgent) {
1674 MOZ_ASSERT(NS_IsMainThread());
1676 // We will skip the override and pass to httpHandler to get spoofed userAgent
1677 // when 'privacy.resistFingerprinting' is true.
1678 if (!aIsCallerChrome &&
1679 !nsContentUtils::ShouldResistFingerprinting(aCallerPrincipal)) {
1680 nsAutoString override;
1681 nsresult rv =
1682 mozilla::Preferences::GetString("general.useragent.override", override);
1684 if (NS_SUCCEEDED(rv)) {
1685 aUserAgent = override;
1686 return NS_OK;
1690 // When the caller is content and 'privacy.resistFingerprinting' is true,
1691 // return a spoofed userAgent which reveals the platform but not the
1692 // specific OS version, etc.
1693 if (!aIsCallerChrome &&
1694 nsContentUtils::ShouldResistFingerprinting(aCallerPrincipal)) {
1695 nsAutoCString spoofedUA;
1696 nsRFPService::GetSpoofedUserAgent(spoofedUA, false);
1697 CopyASCIItoUTF16(spoofedUA, aUserAgent);
1698 return NS_OK;
1701 nsresult rv;
1702 nsCOMPtr<nsIHttpProtocolHandler> service(
1703 do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
1704 if (NS_WARN_IF(NS_FAILED(rv))) {
1705 return rv;
1708 nsAutoCString ua;
1709 rv = service->GetUserAgent(ua);
1710 if (NS_WARN_IF(NS_FAILED(rv))) {
1711 return rv;
1714 CopyASCIItoUTF16(ua, aUserAgent);
1716 // When the caller is content, we will always return spoofed userAgent and
1717 // ignore the User-Agent header from the document channel when
1718 // 'privacy.resistFingerprinting' is true.
1719 if (!aWindow ||
1720 (nsContentUtils::ShouldResistFingerprinting(aCallerPrincipal) &&
1721 !aIsCallerChrome)) {
1722 return NS_OK;
1725 // Copy the User-Agent header from the document channel which has already been
1726 // subject to UA overrides.
1727 nsCOMPtr<Document> doc = aWindow->GetExtantDoc();
1728 if (!doc) {
1729 return NS_OK;
1731 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(doc->GetChannel());
1732 if (httpChannel) {
1733 nsAutoCString userAgent;
1734 rv = httpChannel->GetRequestHeader(NS_LITERAL_CSTRING("User-Agent"),
1735 userAgent);
1736 if (NS_WARN_IF(NS_FAILED(rv))) {
1737 return rv;
1739 CopyASCIItoUTF16(userAgent, aUserAgent);
1741 return NS_OK;
1744 static nsCString RequestKeySystemAccessLogString(
1745 const nsAString& aKeySystem,
1746 const Sequence<MediaKeySystemConfiguration>& aConfigs,
1747 bool aIsSecureContext) {
1748 nsCString str;
1749 str.AppendPrintf(
1750 "Navigator::RequestMediaKeySystemAccess(keySystem='%s' options=",
1751 NS_ConvertUTF16toUTF8(aKeySystem).get());
1752 str.Append(MediaKeySystemAccess::ToCString(aConfigs));
1753 str.AppendLiteral(") secureContext=");
1754 str.AppendInt(aIsSecureContext);
1755 return str;
1758 already_AddRefed<Promise> Navigator::RequestMediaKeySystemAccess(
1759 const nsAString& aKeySystem,
1760 const Sequence<MediaKeySystemConfiguration>& aConfigs, ErrorResult& aRv) {
1761 EME_LOG("%s", RequestKeySystemAccessLogString(aKeySystem, aConfigs,
1762 mWindow->IsSecureContext())
1763 .get());
1765 Telemetry::Accumulate(Telemetry::MEDIA_EME_SECURE_CONTEXT,
1766 mWindow->IsSecureContext());
1768 if (!mWindow->IsSecureContext()) {
1769 Document* doc = mWindow->GetExtantDoc();
1770 nsString uri;
1771 if (doc) {
1772 Unused << doc->GetDocumentURI(uri);
1774 const char16_t* params[] = {uri.get()};
1775 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
1776 NS_LITERAL_CSTRING("Media"), doc,
1777 nsContentUtils::eDOM_PROPERTIES,
1778 "MediaEMEInsecureContextDeprecatedWarning",
1779 params, ArrayLength(params));
1782 Document* doc = mWindow->GetExtantDoc();
1783 if (doc && !FeaturePolicyUtils::IsFeatureAllowed(
1784 doc, NS_LITERAL_STRING("encrypted-media"))) {
1785 aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
1786 return nullptr;
1789 RefPtr<DetailedPromise> promise = DetailedPromise::Create(
1790 mWindow->AsGlobal(), aRv,
1791 NS_LITERAL_CSTRING("navigator.requestMediaKeySystemAccess"),
1792 Telemetry::VIDEO_EME_REQUEST_SUCCESS_LATENCY_MS,
1793 Telemetry::VIDEO_EME_REQUEST_FAILURE_LATENCY_MS);
1794 if (aRv.Failed()) {
1795 return nullptr;
1798 if (!mMediaKeySystemAccessManager) {
1799 mMediaKeySystemAccessManager = new MediaKeySystemAccessManager(mWindow);
1802 mMediaKeySystemAccessManager->Request(promise, aKeySystem, aConfigs);
1803 return promise.forget();
1806 Presentation* Navigator::GetPresentation(ErrorResult& aRv) {
1807 if (!mPresentation) {
1808 if (!mWindow) {
1809 aRv.Throw(NS_ERROR_UNEXPECTED);
1810 return nullptr;
1812 mPresentation = Presentation::Create(mWindow);
1815 return mPresentation;
1818 CredentialsContainer* Navigator::Credentials() {
1819 if (!mCredentials) {
1820 mCredentials = new CredentialsContainer(GetWindow());
1822 return mCredentials;
1825 dom::MediaCapabilities* Navigator::MediaCapabilities() {
1826 if (!mMediaCapabilities) {
1827 mMediaCapabilities = new dom::MediaCapabilities(GetWindow()->AsGlobal());
1829 return mMediaCapabilities;
1832 Clipboard* Navigator::Clipboard() {
1833 if (!mClipboard) {
1834 mClipboard = new dom::Clipboard(GetWindow());
1836 return mClipboard;
1839 /* static */
1840 bool Navigator::Webdriver() {
1841 return Preferences::GetBool("marionette.enabled", false);
1844 } // namespace dom
1845 } // namespace mozilla