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/. */
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"
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"
99 # include "mozilla/Hal.h"
102 #include "mozilla/EMEUtils.h"
103 #include "mozilla/DetailedPromise.h"
104 #include "mozilla/Unused.h"
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");
116 void Navigator::Init() {
117 Preferences::AddBoolVarCache(&sVibratorEnabled
, "dom.vibrator.enabled", true);
118 Preferences::AddUintVarCache(&sMaxVibrateMS
, "dom.vibrator.max_vibrate_ms",
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
)
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
)
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;
175 mPlugins
->Invalidate();
179 mPermissions
= nullptr;
181 mStorageManager
= nullptr;
183 // If there is a page transition, make sure delete the geolocation object.
185 mGeolocation
->Shutdown();
186 mGeolocation
= nullptr;
189 if (mBatteryManager
) {
190 mBatteryManager
->Shutdown();
191 mBatteryManager
= nullptr;
194 mBatteryPromise
= nullptr;
197 mConnection
->Shutdown();
198 mConnection
= nullptr;
201 mMediaDevices
= nullptr;
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
;
235 nsIDocShell
* docshell
= window
->GetDocShell();
236 nsString customUserAgent
;
238 docshell
->GetCustomUserAgent(customUserAgent
);
240 if (!customUserAgent
.IsEmpty()) {
241 aUserAgent
= customUserAgent
;
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
))) {
256 void Navigator::GetAppCodeName(nsAString
& aAppCodeName
, ErrorResult
& aRv
) {
259 nsCOMPtr
<nsIHttpProtocolHandler
> service(
260 do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX
"http", &rv
));
261 if (NS_WARN_IF(NS_FAILED(rv
))) {
266 nsAutoCString appName
;
267 rv
= service
->GetAppName(appName
);
268 if (NS_WARN_IF(NS_FAILED(rv
))) {
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
))) {
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
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.
305 void Navigator::GetAcceptLanguages(nsTArray
<nsString
>& aLanguages
) {
306 MOZ_ASSERT(NS_IsMainThread());
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
, '-');
332 while (localeTokenizer
.hasMoreTokens()) {
333 const nsAString
& code
= localeTokenizer
.nextToken();
335 if (code
.Length() == 2 && !first
) {
336 nsAutoString
upper(code
);
338 lang
.Replace(pos
, code
.Length(), upper
);
341 pos
+= code
.Length() + 1; // 1 is the separator
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
357 void Navigator::GetLanguage(nsAString
& aLanguage
) {
358 nsTArray
<nsString
> languages
;
359 GetLanguages(languages
);
360 if (languages
.Length() >= 1) {
361 aLanguage
.Assign(languages
[0]);
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
))) {
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
);
398 nsAutoString override
;
399 nsresult rv
= Preferences::GetString("general.oscpu.override", override
);
400 if (NS_SUCCEEDED(rv
)) {
407 nsCOMPtr
<nsIHttpProtocolHandler
> service(
408 do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX
"http", &rv
));
409 if (NS_WARN_IF(NS_FAILED(rv
))) {
415 rv
= service
->GetOscpu(oscpu
);
416 if (NS_WARN_IF(NS_FAILED(rv
))) {
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
) {
440 aRv
.Throw(NS_ERROR_UNEXPECTED
);
443 mMimeTypes
= new nsMimeTypeArray(mWindow
);
449 nsPluginArray
* Navigator::GetPlugins(ErrorResult
& aRv
) {
452 aRv
.Throw(NS_ERROR_UNEXPECTED
);
455 mPlugins
= new nsPluginArray(mWindow
);
462 Permissions
* Navigator::GetPermissions(ErrorResult
& aRv
) {
464 aRv
.Throw(NS_ERROR_UNEXPECTED
);
469 mPermissions
= new Permissions(mWindow
);
475 StorageManager
* Navigator::Storage() {
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();
498 return cookieEnabled
;
501 nsCOMPtr
<nsIURI
> codebaseURI
;
502 doc
->NodePrincipal()->GetURI(getter_AddRefs(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(
516 granted
? AntiTrackingCommon::BlockingDecision::eAllow
517 : AntiTrackingCommon::BlockingDecision::eBlock
,
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
);
534 nsAutoString override
;
535 nsresult rv
= Preferences::GetString("general.buildID.override", override
);
536 if (NS_SUCCEEDED(rv
)) {
542 bool isHTTPS
= false;
544 nsCOMPtr
<Document
> doc
= mWindow
->GetDoc();
546 nsIURI
* uri
= doc
->GetDocumentURI();
548 MOZ_ALWAYS_SUCCEEDS(uri
->SchemeIs("https", &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
);
563 nsCOMPtr
<nsIXULAppInfo
> appInfo
=
564 do_GetService("@mozilla.org/xre/app-info;1");
566 aRv
.Throw(NS_ERROR_NOT_IMPLEMENTED
);
570 nsAutoCString buildID
;
571 nsresult rv
= appInfo
->GetAppBuildID(buildID
);
572 if (NS_WARN_IF(NS_FAILED(rv
))) {
578 AppendASCIItoUTF16(buildID
, aBuildID
);
581 void Navigator::GetDoNotTrack(nsAString
& aResult
) {
582 bool doNotTrack
= StaticPrefs::privacy_donottrackheader_enabled();
584 nsCOMPtr
<nsILoadContext
> loadContext
= do_GetInterface(mWindow
);
585 doNotTrack
= loadContext
&& loadContext
->UseTrackingProtection();
589 aResult
.AssignLiteral("1");
591 aResult
.AssignLiteral("unspecified");
595 uint64_t Navigator::HardwareConcurrency() {
596 workerinternals::RuntimeService
* rts
=
597 workerinternals::RuntimeService::GetOrCreateService();
602 return rts
->ClampedHardwareConcurrency();
605 void Navigator::RefreshMIMEArray() {
607 mMimeTypes
->Refresh();
613 class VibrateWindowListener
: public nsIDOMEventListener
{
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();
628 NS_DECL_NSIDOMEVENTLISTENER
631 virtual ~VibrateWindowListener() {}
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());
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
);
658 gVibrateWindowListener
= nullptr;
659 // Careful: The line above might have deleted |this|!
665 void VibrateWindowListener::RemoveListener() {
666 nsCOMPtr
<EventTarget
> target
= do_QueryReferent(mDocument
);
670 NS_NAMED_LITERAL_STRING(visibilitychange
, "visibilitychange");
671 target
->RemoveSystemEventListener(visibilitychange
, this,
672 true /* use capture */);
677 void Navigator::SetVibrationPermission(bool aPermitted
, bool aPersistent
) {
678 MOZ_ASSERT(NS_IsMainThread());
680 nsTArray
<uint32_t> pattern
;
681 pattern
.SwapElements(mRequestedVibrationPattern
);
687 nsCOMPtr
<Document
> doc
= mWindow
->GetExtantDoc();
689 if (!MayVibrate(doc
)) {
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
);
702 gVibrateWindowListener
->RemoveListener();
704 gVibrateWindowListener
= new VibrateWindowListener(mWindow
, doc
);
705 hal::Vibrate(pattern
, mWindow
);
709 nsCOMPtr
<nsIPermissionManager
> permMgr
= services::GetPermissionManager();
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());
733 nsCOMPtr
<Document
> doc
= mWindow
->GetExtantDoc();
735 if (!MayVibrate(doc
)) {
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
) {
755 mRequestedVibrationPattern
.SwapElements(pattern
);
756 nsCOMPtr
<nsIPermissionManager
> permMgr
= services::GetPermissionManager();
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 */);
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 */);
782 // Request user permission.
783 obs
->NotifyObservers(ToSupports(this), "Vibration:Request", nullptr);
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())) {
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
,
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
,
825 nsIURI
* aDocumentURI
,
827 auto raisePermissionDeniedHandler
= [&] {
829 aHandlerURI
->GetSpec(spec
);
830 nsPrintfCString
message("Permission denied to add %s as a protocol handler",
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
);
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
);
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();
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();
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();
893 for (; iter
!= iterEnd
; iter
++) {
894 if (*iter
< 'a' || *iter
> 'z') {
895 raisePermissionDeniedScheme();
900 bool matches
= false;
901 for (const char* safeScheme
: kSafeSchemes
) {
902 if (scheme
.Equals(safeScheme
)) {
908 raisePermissionDeniedScheme();
913 nsCOMPtr
<nsIProtocolHandler
> handler
;
914 nsCOMPtr
<nsIIOService
> io
= services::GetIOService();
916 io
->GetProtocolHandler(scheme
.get(), getter_AddRefs(handler
)))) {
917 raisePermissionDeniedScheme();
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
);
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",
935 if (!Preferences::GetBool(specificPref
.get(), defaultExternal
)) {
936 raisePermissionDeniedScheme();
941 void Navigator::RegisterProtocolHandler(const nsAString
& aScheme
,
942 const nsAString
& aURI
,
943 const nsAString
& aTitle
,
945 if (!mWindow
|| !mWindow
->GetOuterWindow() || !mWindow
->GetDocShell() ||
946 !mWindow
->GetDoc()) {
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");
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
);
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
,
984 nsCOMPtr
<nsIWebProtocolHandlerRegistrar
> registrar
=
985 do_GetService(NS_WEBPROTOCOLHANDLERREGISTRAR_CONTRACTID
);
987 aRv
= registrar
->RegisterProtocolHandler(aScheme
, handlerURI
, aTitle
,
988 docURI
, mWindow
->GetOuterWindow());
992 Geolocation
* Navigator::GetGeolocation(ErrorResult
& aRv
) {
997 if (!mWindow
|| !mWindow
->GetOuterWindow() || !mWindow
->GetDocShell()) {
998 aRv
.Throw(NS_ERROR_FAILURE
);
1002 mGeolocation
= new Geolocation();
1003 if (NS_FAILED(mGeolocation
->Init(mWindow
))) {
1004 mGeolocation
= nullptr;
1005 aRv
.Throw(NS_ERROR_FAILURE
);
1009 return mGeolocation
;
1012 class BeaconStreamListener final
: public nsIStreamListener
{
1013 ~BeaconStreamListener() {}
1016 BeaconStreamListener() : mLoadGroup(nullptr) {}
1018 void SetLoadGroup(nsILoadGroup
* aLoadGroup
) { mLoadGroup
= aLoadGroup
; }
1021 NS_DECL_NSISTREAMLISTENER
1022 NS_DECL_NSIREQUESTOBSERVER
1025 nsCOMPtr
<nsILoadGroup
> mLoadGroup
;
1028 NS_IMPL_ISUPPORTS(BeaconStreamListener
, nsIStreamListener
, nsIRequestObserver
)
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
;
1040 BeaconStreamListener::OnStopRequest(nsIRequest
* aRequest
, nsresult aStatus
) {
1045 BeaconStreamListener::OnDataAvailable(nsIRequest
* aRequest
,
1046 nsIInputStream
* inStr
,
1047 uint64_t sourceOffset
, uint32_t count
) {
1052 bool Navigator::SendBeacon(const nsAString
& aUrl
,
1053 const Nullable
<fetch::BodyInit
>& aData
,
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.");
1095 bool Navigator::SendBeaconInternal(const nsAString
& aUrl
,
1096 BodyExtractorBase
* aBody
, BeaconType aType
,
1099 aRv
.Throw(NS_ERROR_DOM_INVALID_STATE_ERR
);
1103 nsCOMPtr
<Document
> doc
= mWindow
->GetDoc();
1105 aRv
.Throw(NS_ERROR_DOM_INVALID_STATE_ERR
);
1109 nsIURI
* documentURI
= doc
->GetDocumentURI();
1111 aRv
.Throw(NS_ERROR_DOM_INVALID_STATE_ERR
);
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
);
1123 // Spec disallows any schemes save for HTTP/HTTPs
1125 if (!(NS_SUCCEEDED(uri
->SchemeIs("http", &isValidScheme
)) && isValidScheme
) &&
1126 !(NS_SUCCEEDED(uri
->SchemeIs("https", &isValidScheme
)) &&
1128 aRv
.ThrowTypeError
<MSG_INVALID_URL_SCHEME
>(NS_LITERAL_STRING("Beacon"),
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
)) {
1149 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(channel
);
1151 // Beacon spec only supports HTTP requests at this time
1152 aRv
.Throw(NS_ERROR_DOM_BAD_URI
);
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;
1167 aRv
= aBody
->GetAsStream(getter_AddRefs(in
), &length
,
1168 contentTypeWithCharset
, charset
);
1169 if (NS_WARN_IF(aRv
.Failed())) {
1173 nsCOMPtr
<nsIUploadChannel2
> uploadChannel
= do_QueryInterface(channel
);
1174 if (!uploadChannel
) {
1175 aRv
.Throw(NS_ERROR_FAILURE
);
1179 uploadChannel
->ExplicitSetUploadStream(in
, contentTypeWithCharset
, length
,
1180 NS_LITERAL_CSTRING("POST"), false);
1182 rv
= httpChannel
->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
1183 MOZ_ASSERT(NS_SUCCEEDED(rv
));
1186 nsCOMPtr
<nsISupportsPriority
> p
= do_QueryInterface(channel
);
1188 p
->SetPriority(nsISupportsPriority::PRIORITY_LOWEST
);
1191 nsCOMPtr
<nsIClassOfService
> cos(do_QueryInterface(channel
));
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
);
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
);
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
);
1240 RefPtr
<NavigatorUserMediaSuccessCallback
> onsuccess(&aOnSuccess
);
1241 RefPtr
<NavigatorUserMediaErrorCallback
> onerror(&aOnError
);
1243 nsWeakPtr weakWindow
= nsWeakPtr(do_GetWeakReference(mWindow
));
1246 ->GetUserMedia(mWindow
, aConstraints
, aCallerType
)
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
);
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
);
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
);
1315 RefPtr
<Promise
> batteryPromise
= Promise::Create(mWindow
->AsGlobal(), aRv
);
1316 if (NS_WARN_IF(aRv
.Failed())) {
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
,
1339 aRv
.Throw(NS_ERROR_UNEXPECTED
);
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
);
1361 if (!FeaturePolicyUtils::IsFeatureAllowed(mWindow
->GetExtantDoc(),
1362 NS_LITERAL_STRING("vr"))) {
1363 aRv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
1367 nsGlobalWindowInner
* win
= nsGlobalWindowInner::Cast(mWindow
);
1368 win
->NotifyVREventListenerAdded();
1370 RefPtr
<Promise
> p
= Promise::Create(mWindow
->AsGlobal(), aRv
);
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
);
1382 mVRGetDisplaysPromises
.AppendElement(p
);
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
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
1399 if (!mWindow
|| !mWindow
->GetDocShell()) {
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
);
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
) {
1465 aRv
.Throw(NS_ERROR_UNEXPECTED
);
1468 MIDIAccessManager
* accessMgr
= MIDIAccessManager::Get();
1469 return accessMgr
->RequestMIDIAccess(mWindow
, aOptions
, aRv
);
1472 network::Connection
* Navigator::GetConnection(ErrorResult
& aRv
) {
1475 aRv
.Throw(NS_ERROR_UNEXPECTED
);
1478 mConnection
= network::Connection::CreateForWindow(mWindow
);
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.
1508 void Navigator::SetWindow(nsPIDOMWindowInner
* aInnerWindow
) {
1509 mWindow
= aInnerWindow
;
1512 void Navigator::OnNavigation() {
1517 // If MediaManager is open let it inform any live streams or pending callbacks
1518 MediaManager
* manager
= MediaManager::GetIfExists();
1520 manager
->OnNavigation(mWindow
->WindowID());
1524 JSObject
* Navigator::WrapObject(JSContext
* cx
,
1525 JS::Handle
<JSObject
*> aGivenProto
) {
1526 return Navigator_Binding::Wrap(cx
, this, aGivenProto
);
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());
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
);
1558 nsAutoString override
;
1560 mozilla::Preferences::GetString("general.platform.override", override
);
1562 if (NS_SUCCEEDED(rv
)) {
1563 aPlatform
= override
;
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).
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");
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.
1589 rv
= service
->GetOscpu(plat
);
1590 CopyASCIItoUTF16(plat
, aPlatform
);
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
);
1609 nsAutoString override
;
1610 nsresult rv
= mozilla::Preferences::GetString("general.appversion.override",
1613 if (NS_SUCCEEDED(rv
)) {
1614 aAppVersion
= override
;
1621 nsCOMPtr
<nsIHttpProtocolHandler
> service(
1622 do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX
"http", &rv
));
1623 NS_ENSURE_SUCCESS(rv
, rv
);
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(')'));
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
);
1654 nsAutoString override
;
1656 mozilla::Preferences::GetString("general.appname.override", override
);
1658 if (NS_SUCCEEDED(rv
)) {
1659 aAppName
= override
;
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
;
1682 mozilla::Preferences::GetString("general.useragent.override", override
);
1684 if (NS_SUCCEEDED(rv
)) {
1685 aUserAgent
= override
;
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
);
1702 nsCOMPtr
<nsIHttpProtocolHandler
> service(
1703 do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX
"http", &rv
));
1704 if (NS_WARN_IF(NS_FAILED(rv
))) {
1709 rv
= service
->GetUserAgent(ua
);
1710 if (NS_WARN_IF(NS_FAILED(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.
1720 (nsContentUtils::ShouldResistFingerprinting(aCallerPrincipal
) &&
1721 !aIsCallerChrome
)) {
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();
1731 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(doc
->GetChannel());
1733 nsAutoCString userAgent
;
1734 rv
= httpChannel
->GetRequestHeader(NS_LITERAL_CSTRING("User-Agent"),
1736 if (NS_WARN_IF(NS_FAILED(rv
))) {
1739 CopyASCIItoUTF16(userAgent
, aUserAgent
);
1744 static nsCString
RequestKeySystemAccessLogString(
1745 const nsAString
& aKeySystem
,
1746 const Sequence
<MediaKeySystemConfiguration
>& aConfigs
,
1747 bool aIsSecureContext
) {
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
);
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())
1765 Telemetry::Accumulate(Telemetry::MEDIA_EME_SECURE_CONTEXT
,
1766 mWindow
->IsSecureContext());
1768 if (!mWindow
->IsSecureContext()) {
1769 Document
* doc
= mWindow
->GetExtantDoc();
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
);
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
);
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
) {
1809 aRv
.Throw(NS_ERROR_UNEXPECTED
);
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() {
1834 mClipboard
= new dom::Clipboard(GetWindow());
1840 bool Navigator::Webdriver() {
1841 return Preferences::GetBool("marionette.enabled", false);
1845 } // namespace mozilla