1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 // Needs to be first.
8 #include "base/basictypes.h"
9 
10 #include "Navigator.h"
11 #include "nsIXULAppInfo.h"
12 #include "nsPluginArray.h"
13 #include "nsMimeTypeArray.h"
14 #include "mozilla/MemoryReporting.h"
15 #include "mozilla/dom/BodyExtractor.h"
16 #include "mozilla/dom/FetchBinding.h"
17 #include "mozilla/dom/File.h"
18 #include "nsGeolocation.h"
19 #include "nsIClassOfService.h"
20 #include "nsIHttpProtocolHandler.h"
21 #include "nsIContentPolicy.h"
22 #include "nsIContentSecurityPolicy.h"
23 #include "nsContentPolicyUtils.h"
24 #include "nsISupportsPriority.h"
25 #include "nsICachingChannel.h"
26 #include "nsIWebContentHandlerRegistrar.h"
27 #include "nsICookiePermission.h"
28 #include "nsIScriptSecurityManager.h"
29 #include "nsCharSeparatedTokenizer.h"
30 #include "nsContentUtils.h"
31 #include "nsUnicharUtils.h"
32 #include "mozilla/Preferences.h"
33 #include "mozilla/Telemetry.h"
34 #include "BatteryManager.h"
35 #include "mozilla/dom/CredentialsContainer.h"
36 #include "mozilla/dom/GamepadServiceTest.h"
37 #include "mozilla/dom/WakeLock.h"
38 #include "mozilla/dom/power/PowerManagerService.h"
39 #include "mozilla/dom/MIDIAccessManager.h"
40 #include "mozilla/dom/MIDIOptionsBinding.h"
41 #include "mozilla/dom/Permissions.h"
42 #include "mozilla/dom/Presentation.h"
43 #include "mozilla/dom/ServiceWorkerContainer.h"
44 #include "mozilla/dom/StorageManager.h"
45 #include "mozilla/dom/TCPSocket.h"
46 #include "mozilla/dom/URLSearchParams.h"
47 #include "mozilla/dom/VRDisplay.h"
48 #include "mozilla/dom/VRDisplayEvent.h"
49 #include "mozilla/dom/VRServiceTest.h"
50 #include "mozilla/dom/workerinternals/RuntimeService.h"
51 #include "mozilla/Hal.h"
52 #include "mozilla/ClearOnShutdown.h"
53 #include "mozilla/StaticPtr.h"
54 #include "Connection.h"
55 #include "mozilla/dom/Event.h"  // for nsIDOMEvent::InternalDOMEvent()
56 #include "nsGlobalWindow.h"
57 #include "nsIIdleObserver.h"
58 #include "nsIPermissionManager.h"
59 #include "nsMimeTypes.h"
60 #include "nsNetUtil.h"
61 #include "nsRFPService.h"
62 #include "nsStringStream.h"
63 #include "nsComponentManagerUtils.h"
64 #include "nsIStringStream.h"
65 #include "nsIHttpChannel.h"
66 #include "nsIHttpChannelInternal.h"
67 #include "nsStreamUtils.h"
68 #include "WidgetUtils.h"
69 #include "nsIPresentationService.h"
70 #include "nsIScriptError.h"
71 
72 #include "mozilla/dom/MediaDevices.h"
73 #include "MediaManager.h"
74 
75 #include "nsIDOMGlobalPropertyInitializer.h"
76 #include "nsJSUtils.h"
77 
78 #include "nsScriptNameSpaceManager.h"
79 
80 #include "mozilla/dom/NavigatorBinding.h"
81 #include "mozilla/dom/Promise.h"
82 
83 #include "nsIUploadChannel2.h"
84 #include "mozilla/dom/FormData.h"
85 #include "nsIDocShell.h"
86 
87 #include "mozilla/dom/WorkerPrivate.h"
88 #include "mozilla/dom/WorkerRunnable.h"
89 
90 #if defined(XP_LINUX)
91 #include "mozilla/Hal.h"
92 #endif
93 #include "mozilla/dom/ContentChild.h"
94 
95 #include "mozilla/EMEUtils.h"
96 #include "mozilla/DetailedPromise.h"
97 #include "mozilla/Unused.h"
98 
99 namespace mozilla {
100 namespace dom {
101 
102 static bool sVibratorEnabled = false;
103 static uint32_t sMaxVibrateMS = 0;
104 static uint32_t sMaxVibrateListLen = 0;
105 static const char* kVibrationPermissionType = "vibration";
106 
AddPermission(nsIPrincipal * aPrincipal,const char * aType,uint32_t aPermission,uint32_t aExpireType,int64_t aExpireTime)107 static void AddPermission(nsIPrincipal* aPrincipal, const char* aType,
108                           uint32_t aPermission, uint32_t aExpireType,
109                           int64_t aExpireTime) {
110   MOZ_ASSERT(aType);
111   MOZ_ASSERT(aPrincipal);
112 
113   nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
114   if (!permMgr) {
115     return;
116   }
117   permMgr->AddFromPrincipal(aPrincipal, aType, aPermission, aExpireType,
118                             aExpireTime);
119 }
120 
GetPermission(nsPIDOMWindowInner * aWindow,const char * aType)121 static uint32_t GetPermission(nsPIDOMWindowInner* aWindow, const char* aType) {
122   MOZ_ASSERT(aType);
123 
124   uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION;
125 
126   nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
127   if (!permMgr) {
128     return permission;
129   }
130   permMgr->TestPermissionFromWindow(aWindow, aType, &permission);
131   return permission;
132 }
133 
GetPermission(nsIPrincipal * aPrincipal,const char * aType)134 static uint32_t GetPermission(nsIPrincipal* aPrincipal, const char* aType) {
135   MOZ_ASSERT(aType);
136   MOZ_ASSERT(aPrincipal);
137 
138   uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION;
139 
140   nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
141   if (!permMgr) {
142     return permission;
143   }
144   permMgr->TestPermissionFromPrincipal(aPrincipal, aType, &permission);
145   return permission;
146 }
147 
148 /* static */
Init()149 void Navigator::Init() {
150   Preferences::AddBoolVarCache(&sVibratorEnabled, "dom.vibrator.enabled", true);
151   Preferences::AddUintVarCache(&sMaxVibrateMS, "dom.vibrator.max_vibrate_ms",
152                                10000);
153   Preferences::AddUintVarCache(&sMaxVibrateListLen,
154                                "dom.vibrator.max_vibrate_list_len", 128);
155 }
156 
Navigator(nsPIDOMWindowInner * aWindow)157 Navigator::Navigator(nsPIDOMWindowInner* aWindow) : mWindow(aWindow) {}
158 
~Navigator()159 Navigator::~Navigator() { Invalidate(); }
160 
161 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Navigator)
162   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
163   NS_INTERFACE_MAP_ENTRY(nsISupports)
164 NS_INTERFACE_MAP_END
165 
166 NS_IMPL_CYCLE_COLLECTING_ADDREF(Navigator)
167 NS_IMPL_CYCLE_COLLECTING_RELEASE(Navigator)
168 
169 NS_IMPL_CYCLE_COLLECTION_CLASS(Navigator)
170 
171 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Navigator)
172   tmp->Invalidate();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)173   NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
174   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
175 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
176 
177 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
178   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMimeTypes)
179   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlugins)
180   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPermissions)
181   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGeolocation)
182   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryManager)
183   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryPromise)
184   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
185   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStorageManager)
186   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCredentials)
187   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaDevices)
188   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerContainer)
189 
190   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
191   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaKeySystemAccessManager)
192   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresentation)
193   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGamepadServiceTest)
194   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVRGetDisplaysPromises)
195   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVRServiceTest)
196 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
197 
198 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(Navigator)
199 
200 void Navigator::Invalidate() {
201   // Don't clear mWindow here so we know we've got a non-null mWindow
202   // until we're unlinked.
203 
204   mMimeTypes = nullptr;
205 
206   if (mPlugins) {
207     mPlugins->Invalidate();
208     mPlugins = nullptr;
209   }
210 
211   mPermissions = nullptr;
212 
213   mStorageManager = nullptr;
214 
215   // If there is a page transition, make sure delete the geolocation object.
216   if (mGeolocation) {
217     mGeolocation->Shutdown();
218     mGeolocation = nullptr;
219   }
220 
221   if (mBatteryManager) {
222     mBatteryManager->Shutdown();
223     mBatteryManager = nullptr;
224   }
225 
226   mBatteryPromise = nullptr;
227 
228   if (mConnection) {
229     mConnection->Shutdown();
230     mConnection = nullptr;
231   }
232 
233   mMediaDevices = nullptr;
234 
235   if (mPresentation) {
236     mPresentation = nullptr;
237   }
238 
239   mServiceWorkerContainer = nullptr;
240 
241   if (mMediaKeySystemAccessManager) {
242     mMediaKeySystemAccessManager->Shutdown();
243     mMediaKeySystemAccessManager = nullptr;
244   }
245 
246   if (mGamepadServiceTest) {
247     mGamepadServiceTest->Shutdown();
248     mGamepadServiceTest = nullptr;
249   }
250 
251   mVRGetDisplaysPromises.Clear();
252 
253   if (mVRServiceTest) {
254     mVRServiceTest->Shutdown();
255     mVRServiceTest = nullptr;
256   }
257 }
258 
GetUserAgent(nsAString & aUserAgent,CallerType aCallerType,ErrorResult & aRv) const259 void Navigator::GetUserAgent(nsAString& aUserAgent, CallerType aCallerType,
260                              ErrorResult& aRv) const {
261   nsCOMPtr<nsPIDOMWindowInner> window;
262 
263   if (mWindow) {
264     window = mWindow;
265     nsIDocShell* docshell = window->GetDocShell();
266     nsString customUserAgent;
267     if (docshell) {
268       docshell->GetCustomUserAgent(customUserAgent);
269 
270       if (!customUserAgent.IsEmpty()) {
271         aUserAgent = customUserAgent;
272         return;
273       }
274     }
275   }
276 
277   nsresult rv =
278       GetUserAgent(window, aCallerType == CallerType::System, aUserAgent);
279   if (NS_WARN_IF(NS_FAILED(rv))) {
280     aRv.Throw(rv);
281   }
282 }
283 
GetAppCodeName(nsAString & aAppCodeName,ErrorResult & aRv)284 void Navigator::GetAppCodeName(nsAString& aAppCodeName, ErrorResult& aRv) {
285   nsresult rv;
286 
287   nsCOMPtr<nsIHttpProtocolHandler> service(
288       do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
289   if (NS_WARN_IF(NS_FAILED(rv))) {
290     aRv.Throw(rv);
291     return;
292   }
293 
294   nsAutoCString appName;
295   rv = service->GetAppName(appName);
296   if (NS_WARN_IF(NS_FAILED(rv))) {
297     aRv.Throw(rv);
298     return;
299   }
300 
301   CopyASCIItoUTF16(appName, aAppCodeName);
302 }
303 
GetAppVersion(nsAString & aAppVersion,CallerType aCallerType,ErrorResult & aRv) const304 void Navigator::GetAppVersion(nsAString& aAppVersion, CallerType aCallerType,
305                               ErrorResult& aRv) const {
306   nsresult rv = GetAppVersion(
307       aAppVersion,
308       /* aUsePrefOverriddenValue = */ aCallerType != CallerType::System);
309   if (NS_WARN_IF(NS_FAILED(rv))) {
310     aRv.Throw(rv);
311   }
312 }
313 
GetAppName(nsAString & aAppName,CallerType aCallerType) const314 void Navigator::GetAppName(nsAString& aAppName, CallerType aCallerType) const {
315   AppName(aAppName,
316           /* aUsePrefOverriddenValue = */ aCallerType != CallerType::System);
317 }
318 
319 /**
320  * Returns the value of Accept-Languages (HTTP header) as a nsTArray of
321  * languages. The value is set in the preference by the user ("Content
322  * Languages").
323  *
324  * "en", "en-US" and "i-cherokee" and "" are valid languages tokens.
325  *
326  * An empty array will be returned if there is no valid languages.
327  */
GetAcceptLanguages(nsTArray<nsString> & aLanguages)328 /* static */ void Navigator::GetAcceptLanguages(
329     nsTArray<nsString>& aLanguages) {
330   MOZ_ASSERT(NS_IsMainThread());
331 
332   aLanguages.Clear();
333 
334   // E.g. "de-de, en-us,en".
335   nsAutoString acceptLang;
336   Preferences::GetLocalizedString("intl.accept_languages", acceptLang);
337 
338   // Split values on commas.
339   nsCharSeparatedTokenizer langTokenizer(acceptLang, ',');
340   while (langTokenizer.hasMoreTokens()) {
341     nsDependentSubstring lang = langTokenizer.nextToken();
342 
343     // Replace "_" with "-" to avoid POSIX/Windows "en_US" notation.
344     // NOTE: we should probably rely on the pref being set correctly.
345     if (lang.Length() > 2 && lang[2] == char16_t('_')) {
346       lang.Replace(2, 1, char16_t('-'));
347     }
348 
349     // Use uppercase for country part, e.g. "en-US", not "en-us", see BCP47
350     // only uppercase 2-letter country codes, not "zh-Hant", "de-DE-x-goethe".
351     // NOTE: we should probably rely on the pref being set correctly.
352     if (lang.Length() > 2) {
353       nsCharSeparatedTokenizer localeTokenizer(lang, '-');
354       int32_t pos = 0;
355       bool first = true;
356       while (localeTokenizer.hasMoreTokens()) {
357         const nsAString& code = localeTokenizer.nextToken();
358 
359         if (code.Length() == 2 && !first) {
360           nsAutoString upper(code);
361           ToUpperCase(upper);
362           lang.Replace(pos, code.Length(), upper);
363         }
364 
365         pos += code.Length() + 1;  // 1 is the separator
366         first = false;
367       }
368     }
369 
370     aLanguages.AppendElement(lang);
371   }
372 }
373 
374 /**
375  * Do not use UI language (chosen app locale) here but the first value set in
376  * the Accept Languages header, see ::GetAcceptLanguages().
377  *
378  * See RFC 2616, Section 15.1.4 "Privacy Issues Connected to Accept Headers" for
379  * the reasons why.
380  */
GetLanguage(nsAString & aLanguage)381 void Navigator::GetLanguage(nsAString& aLanguage) {
382   nsTArray<nsString> languages;
383   GetLanguages(languages);
384   if (languages.Length() >= 1) {
385     aLanguage.Assign(languages[0]);
386   } else {
387     aLanguage.Truncate();
388   }
389 }
390 
GetLanguages(nsTArray<nsString> & aLanguages)391 void Navigator::GetLanguages(nsTArray<nsString>& aLanguages) {
392   GetAcceptLanguages(aLanguages);
393 
394   // The returned value is cached by the binding code. The window listen to the
395   // accept languages change and will clear the cache when needed. It has to
396   // take care of dispatching the DOM event already and the invalidation and the
397   // event has to be timed correctly.
398 }
399 
GetPlatform(nsAString & aPlatform,CallerType aCallerType,ErrorResult & aRv) const400 void Navigator::GetPlatform(nsAString& aPlatform, CallerType aCallerType,
401                             ErrorResult& aRv) const {
402   nsresult rv = GetPlatform(
403       aPlatform,
404       /* aUsePrefOverriddenValue = */ aCallerType != CallerType::System);
405   if (NS_WARN_IF(NS_FAILED(rv))) {
406     aRv.Throw(rv);
407   }
408 }
409 
GetOscpu(nsAString & aOSCPU,CallerType aCallerType,ErrorResult & aRv) const410 void Navigator::GetOscpu(nsAString& aOSCPU, CallerType aCallerType,
411                          ErrorResult& aRv) const {
412   if (aCallerType != CallerType::System) {
413     // If fingerprinting resistance is on, we will spoof this value. See
414     // nsRFPService.h for details about spoofed values.
415     if (nsContentUtils::ShouldResistFingerprinting()) {
416       aOSCPU.AssignLiteral(SPOOFED_OSCPU);
417       return;
418     }
419 
420     nsAutoString override;
421     nsresult rv = Preferences::GetString("general.oscpu.override", override);
422     if (NS_SUCCEEDED(rv)) {
423       aOSCPU = override;
424       return;
425     }
426   }
427 
428   nsresult rv;
429   nsCOMPtr<nsIHttpProtocolHandler> service(
430       do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
431   if (NS_WARN_IF(NS_FAILED(rv))) {
432     aRv.Throw(rv);
433     return;
434   }
435 
436   nsAutoCString oscpu;
437   rv = service->GetOscpu(oscpu);
438   if (NS_WARN_IF(NS_FAILED(rv))) {
439     aRv.Throw(rv);
440     return;
441   }
442 
443   CopyASCIItoUTF16(oscpu, aOSCPU);
444 }
445 
GetVendor(nsAString & aVendor)446 void Navigator::GetVendor(nsAString& aVendor) { aVendor.Truncate(); }
447 
GetVendorSub(nsAString & aVendorSub)448 void Navigator::GetVendorSub(nsAString& aVendorSub) { aVendorSub.Truncate(); }
449 
GetProduct(nsAString & aProduct)450 void Navigator::GetProduct(nsAString& aProduct) {
451   aProduct.AssignLiteral("Gecko");
452 }
453 
GetProductSub(nsAString & aProductSub)454 void Navigator::GetProductSub(nsAString& aProductSub) {
455   // Legacy build ID hardcoded for backward compatibility (bug 776376)
456   aProductSub.AssignLiteral(LEGACY_BUILD_ID);
457 }
458 
GetMimeTypes(ErrorResult & aRv)459 nsMimeTypeArray* Navigator::GetMimeTypes(ErrorResult& aRv) {
460   if (!mMimeTypes) {
461     if (!mWindow) {
462       aRv.Throw(NS_ERROR_UNEXPECTED);
463       return nullptr;
464     }
465     mMimeTypes = new nsMimeTypeArray(mWindow);
466   }
467 
468   return mMimeTypes;
469 }
470 
GetPlugins(ErrorResult & aRv)471 nsPluginArray* Navigator::GetPlugins(ErrorResult& aRv) {
472   if (!mPlugins) {
473     if (!mWindow) {
474       aRv.Throw(NS_ERROR_UNEXPECTED);
475       return nullptr;
476     }
477     mPlugins = new nsPluginArray(mWindow);
478     mPlugins->Init();
479   }
480 
481   return mPlugins;
482 }
483 
GetPermissions(ErrorResult & aRv)484 Permissions* Navigator::GetPermissions(ErrorResult& aRv) {
485   if (!mWindow) {
486     aRv.Throw(NS_ERROR_UNEXPECTED);
487     return nullptr;
488   }
489 
490   if (!mPermissions) {
491     mPermissions = new Permissions(mWindow);
492   }
493 
494   return mPermissions;
495 }
496 
Storage()497 StorageManager* Navigator::Storage() {
498   MOZ_ASSERT(mWindow);
499 
500   if (!mStorageManager) {
501     mStorageManager = new StorageManager(mWindow->AsGlobal());
502   }
503 
504   return mStorageManager;
505 }
506 
507 // Values for the network.cookie.cookieBehavior pref are documented in
508 // nsCookieService.cpp.
509 #define COOKIE_BEHAVIOR_REJECT 2
510 
CookieEnabled()511 bool Navigator::CookieEnabled() {
512   bool cookieEnabled =
513       (Preferences::GetInt("network.cookie.cookieBehavior",
514                            COOKIE_BEHAVIOR_REJECT) != COOKIE_BEHAVIOR_REJECT);
515 
516   // Check whether an exception overrides the global cookie behavior
517   // Note that the code for getting the URI here matches that in
518   // nsHTMLDocument::SetCookie.
519   if (!mWindow || !mWindow->GetDocShell()) {
520     return cookieEnabled;
521   }
522 
523   nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc();
524   if (!doc) {
525     return cookieEnabled;
526   }
527 
528   nsCOMPtr<nsIURI> codebaseURI;
529   doc->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
530 
531   if (!codebaseURI) {
532     // Not a codebase, so technically can't set cookies, but let's
533     // just return the default value.
534     return cookieEnabled;
535   }
536 
537   nsCOMPtr<nsICookiePermission> permMgr =
538       do_GetService(NS_COOKIEPERMISSION_CONTRACTID);
539   NS_ENSURE_TRUE(permMgr, cookieEnabled);
540 
541   // Pass null for the channel, just like the cookie service does.
542   nsCookieAccess access;
543   nsresult rv = permMgr->CanAccess(doc->NodePrincipal(), &access);
544   NS_ENSURE_SUCCESS(rv, cookieEnabled);
545 
546   if (access != nsICookiePermission::ACCESS_DEFAULT) {
547     cookieEnabled = access != nsICookiePermission::ACCESS_DENY;
548   }
549 
550   return cookieEnabled;
551 }
552 
OnLine()553 bool Navigator::OnLine() { return !NS_IsOffline(); }
554 
GetBuildID(nsAString & aBuildID,CallerType aCallerType,ErrorResult & aRv) const555 void Navigator::GetBuildID(nsAString& aBuildID, CallerType aCallerType,
556                            ErrorResult& aRv) const {
557   if (aCallerType != CallerType::System) {
558     // If fingerprinting resistance is on, we will spoof this value. See
559     // nsRFPService.h for details about spoofed values.
560     if (nsContentUtils::ShouldResistFingerprinting()) {
561       aBuildID.AssignLiteral(LEGACY_BUILD_ID);
562       return;
563     }
564     nsAutoString override;
565     nsresult rv = Preferences::GetString("general.buildID.override", override);
566     if (NS_SUCCEEDED(rv)) {
567       aBuildID = override;
568       return;
569     }
570   }
571 
572   nsCOMPtr<nsIXULAppInfo> appInfo =
573       do_GetService("@mozilla.org/xre/app-info;1");
574   if (!appInfo) {
575     aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
576     return;
577   }
578 
579   nsAutoCString buildID;
580   nsresult rv = appInfo->GetAppBuildID(buildID);
581   if (NS_WARN_IF(NS_FAILED(rv))) {
582     aRv.Throw(rv);
583     return;
584   }
585 
586   aBuildID.Truncate();
587   AppendASCIItoUTF16(buildID, aBuildID);
588 }
589 
GetDoNotTrack(nsAString & aResult)590 void Navigator::GetDoNotTrack(nsAString& aResult) {
591   bool doNotTrack = nsContentUtils::DoNotTrackEnabled();
592   if (!doNotTrack) {
593     nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(mWindow);
594     doNotTrack = loadContext && loadContext->UseTrackingProtection();
595   }
596 
597   if (doNotTrack) {
598     aResult.AssignLiteral("1");
599   } else {
600     aResult.AssignLiteral("unspecified");
601   }
602 }
603 
JavaEnabled(CallerType aCallerType,ErrorResult & aRv)604 bool Navigator::JavaEnabled(CallerType aCallerType, ErrorResult& aRv) {
605   Telemetry::AutoTimer<Telemetry::CHECK_JAVA_ENABLED> telemetryTimer;
606 
607   // Return true if we have a handler for the java mime
608   nsAutoString javaMIME;
609   Preferences::GetString("plugin.java.mime", javaMIME);
610   NS_ENSURE_TRUE(!javaMIME.IsEmpty(), false);
611 
612   if (!mMimeTypes) {
613     if (!mWindow) {
614       aRv.Throw(NS_ERROR_UNEXPECTED);
615       return false;
616     }
617     mMimeTypes = new nsMimeTypeArray(mWindow);
618   }
619 
620   RefreshMIMEArray();
621 
622   nsMimeType* mimeType = mMimeTypes->NamedItem(javaMIME, aCallerType);
623 
624   return mimeType && mimeType->GetEnabledPlugin();
625 }
626 
HardwareConcurrency()627 uint64_t Navigator::HardwareConcurrency() {
628   workerinternals::RuntimeService* rts =
629       workerinternals::RuntimeService::GetOrCreateService();
630   if (!rts) {
631     return 1;
632   }
633 
634   return rts->ClampedHardwareConcurrency();
635 }
636 
RefreshMIMEArray()637 void Navigator::RefreshMIMEArray() {
638   if (mMimeTypes) {
639     mMimeTypes->Refresh();
640   }
641 }
642 
643 namespace {
644 
645 class VibrateWindowListener : public nsIDOMEventListener {
646  public:
VibrateWindowListener(nsPIDOMWindowInner * aWindow,nsIDocument * aDocument)647   VibrateWindowListener(nsPIDOMWindowInner* aWindow, nsIDocument* aDocument) {
648     mWindow = do_GetWeakReference(aWindow);
649     mDocument = do_GetWeakReference(aDocument);
650 
651     NS_NAMED_LITERAL_STRING(visibilitychange, "visibilitychange");
652     aDocument->AddSystemEventListener(visibilitychange, this, /* listener */
653                                       true,                   /* use capture */
654                                       false /* wants untrusted */);
655   }
656 
657   void RemoveListener();
658 
659   NS_DECL_ISUPPORTS
660   NS_DECL_NSIDOMEVENTLISTENER
661 
662  private:
~VibrateWindowListener()663   virtual ~VibrateWindowListener() {}
664 
665   nsWeakPtr mWindow;
666   nsWeakPtr mDocument;
667 };
668 
669 NS_IMPL_ISUPPORTS(VibrateWindowListener, nsIDOMEventListener)
670 
671 StaticRefPtr<VibrateWindowListener> gVibrateWindowListener;
672 
MayVibrate(nsIDocument * doc)673 static bool MayVibrate(nsIDocument* doc) {
674   // Hidden documents cannot start or stop a vibration.
675   return (doc && !doc->Hidden());
676 }
677 
678 NS_IMETHODIMP
HandleEvent(nsIDOMEvent * aEvent)679 VibrateWindowListener::HandleEvent(nsIDOMEvent* aEvent) {
680   nsCOMPtr<nsIDocument> doc =
681       do_QueryInterface(aEvent->InternalDOMEvent()->GetTarget());
682 
683   if (!MayVibrate(doc)) {
684     // It's important that we call CancelVibrate(), not Vibrate() with an
685     // empty list, because Vibrate() will fail if we're no longer focused, but
686     // CancelVibrate() will succeed, so long as nobody else has started a new
687     // vibration pattern.
688     nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(mWindow);
689     hal::CancelVibrate(window);
690     RemoveListener();
691     gVibrateWindowListener = nullptr;
692     // Careful: The line above might have deleted |this|!
693   }
694 
695   return NS_OK;
696 }
697 
RemoveListener()698 void VibrateWindowListener::RemoveListener() {
699   nsCOMPtr<EventTarget> target = do_QueryReferent(mDocument);
700   if (!target) {
701     return;
702   }
703   NS_NAMED_LITERAL_STRING(visibilitychange, "visibilitychange");
704   target->RemoveSystemEventListener(visibilitychange, this,
705                                     true /* use capture */);
706 }
707 
708 }  // namespace
709 
AddIdleObserver(MozIdleObserver & aIdleObserver,ErrorResult & aRv)710 void Navigator::AddIdleObserver(MozIdleObserver& aIdleObserver,
711                                 ErrorResult& aRv) {
712   if (!mWindow) {
713     aRv.Throw(NS_ERROR_UNEXPECTED);
714     return;
715   }
716   CallbackObjectHolder<MozIdleObserver, nsIIdleObserver> holder(&aIdleObserver);
717   nsCOMPtr<nsIIdleObserver> obs = holder.ToXPCOMCallback();
718   if (NS_FAILED(mWindow->RegisterIdleObserver(obs))) {
719     NS_WARNING("Failed to add idle observer.");
720   }
721 }
722 
RemoveIdleObserver(MozIdleObserver & aIdleObserver,ErrorResult & aRv)723 void Navigator::RemoveIdleObserver(MozIdleObserver& aIdleObserver,
724                                    ErrorResult& aRv) {
725   if (!mWindow) {
726     aRv.Throw(NS_ERROR_UNEXPECTED);
727     return;
728   }
729   CallbackObjectHolder<MozIdleObserver, nsIIdleObserver> holder(&aIdleObserver);
730   nsCOMPtr<nsIIdleObserver> obs = holder.ToXPCOMCallback();
731   if (NS_FAILED(mWindow->UnregisterIdleObserver(obs))) {
732     NS_WARNING("Failed to remove idle observer.");
733   }
734 }
735 
SetVibrationPermission(bool aPermitted,bool aPersistent)736 void Navigator::SetVibrationPermission(bool aPermitted, bool aPersistent) {
737   MOZ_ASSERT(NS_IsMainThread());
738 
739   nsTArray<uint32_t> pattern;
740   pattern.SwapElements(mRequestedVibrationPattern);
741 
742   if (!mWindow) {
743     return;
744   }
745 
746   nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc();
747 
748   if (!MayVibrate(doc)) {
749     return;
750   }
751 
752   if (aPermitted) {
753     // Add a listener to cancel the vibration if the document becomes hidden,
754     // and remove the old visibility listener, if there was one.
755     if (!gVibrateWindowListener) {
756       // If gVibrateWindowListener is null, this is the first time we've
757       // vibrated, and we need to register a listener to clear
758       // gVibrateWindowListener on shutdown.
759       ClearOnShutdown(&gVibrateWindowListener);
760     } else {
761       gVibrateWindowListener->RemoveListener();
762     }
763     gVibrateWindowListener = new VibrateWindowListener(mWindow, doc);
764     hal::Vibrate(pattern, mWindow);
765   }
766 
767   if (aPersistent) {
768     AddPermission(doc->NodePrincipal(), kVibrationPermissionType,
769                   aPermitted ? nsIPermissionManager::ALLOW_ACTION
770                              : nsIPermissionManager::DENY_ACTION,
771                   nsIPermissionManager::EXPIRE_SESSION, 0);
772   }
773 }
774 
Vibrate(uint32_t aDuration)775 bool Navigator::Vibrate(uint32_t aDuration) {
776   AutoTArray<uint32_t, 1> pattern;
777   pattern.AppendElement(aDuration);
778   return Vibrate(pattern);
779 }
780 
Vibrate(const nsTArray<uint32_t> & aPattern)781 bool Navigator::Vibrate(const nsTArray<uint32_t>& aPattern) {
782   MOZ_ASSERT(NS_IsMainThread());
783 
784   if (!mWindow) {
785     return false;
786   }
787 
788   nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc();
789 
790   if (!MayVibrate(doc)) {
791     return false;
792   }
793 
794   nsTArray<uint32_t> pattern(aPattern);
795 
796   if (pattern.Length() > sMaxVibrateListLen) {
797     pattern.SetLength(sMaxVibrateListLen);
798   }
799 
800   for (size_t i = 0; i < pattern.Length(); ++i) {
801     pattern[i] = std::min(sMaxVibrateMS, pattern[i]);
802   }
803 
804   // The spec says we check sVibratorEnabled after we've done the sanity
805   // checking on the pattern.
806   if (!sVibratorEnabled) {
807     return true;
808   }
809 
810   mRequestedVibrationPattern.SwapElements(pattern);
811   uint32_t permission = GetPermission(mWindow, kVibrationPermissionType);
812 
813   if (permission == nsIPermissionManager::ALLOW_ACTION ||
814       mRequestedVibrationPattern.IsEmpty() ||
815       (mRequestedVibrationPattern.Length() == 1 &&
816        mRequestedVibrationPattern[0] == 0)) {
817     // Always allow cancelling vibration and respect session permissions.
818     SetVibrationPermission(true /* permitted */, false /* persistent */);
819     return true;
820   }
821 
822   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
823   if (!obs || permission == nsIPermissionManager::DENY_ACTION) {
824     // Abort without observer service or on denied session permission.
825     SetVibrationPermission(false /* permitted */, false /* persistent */);
826     return true;
827   }
828 
829   // Request user permission.
830   obs->NotifyObservers(ToSupports(this), "Vibration:Request", nullptr);
831 
832   return true;
833 }
834 
835 //*****************************************************************************
836 //  Pointer Events interface
837 //*****************************************************************************
838 
MaxTouchPoints()839 uint32_t Navigator::MaxTouchPoints() {
840   nsCOMPtr<nsIWidget> widget =
841       widget::WidgetUtils::DOMWindowToWidget(mWindow->GetOuterWindow());
842 
843   NS_ENSURE_TRUE(widget, 0);
844   return widget->GetMaxTouchPoints();
845 }
846 
847 //*****************************************************************************
848 //    Navigator::nsIDOMClientInformation
849 //*****************************************************************************
850 
RegisterContentHandler(const nsAString & aMIMEType,const nsAString & aURI,const nsAString & aTitle,ErrorResult & aRv)851 void Navigator::RegisterContentHandler(const nsAString& aMIMEType,
852                                        const nsAString& aURI,
853                                        const nsAString& aTitle,
854                                        ErrorResult& aRv) {
855   if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) {
856     return;
857   }
858 
859   nsCOMPtr<nsIWebContentHandlerRegistrar> registrar =
860       do_GetService(NS_WEBCONTENTHANDLERREGISTRAR_CONTRACTID);
861   if (!registrar) {
862     return;
863   }
864 
865   aRv = registrar->RegisterContentHandler(aMIMEType, aURI, aTitle,
866                                           mWindow->GetOuterWindow());
867 }
868 
RegisterProtocolHandler(const nsAString & aProtocol,const nsAString & aURI,const nsAString & aTitle,ErrorResult & aRv)869 void Navigator::RegisterProtocolHandler(const nsAString& aProtocol,
870                                         const nsAString& aURI,
871                                         const nsAString& aTitle,
872                                         ErrorResult& aRv) {
873   if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) {
874     return;
875   }
876 
877   if (!mWindow->IsSecureContext() && mWindow->GetDoc()) {
878     mWindow->GetDoc()->WarnOnceAbout(
879         nsIDocument::eRegisterProtocolHandlerInsecure);
880   }
881 
882   nsCOMPtr<nsIWebContentHandlerRegistrar> registrar =
883       do_GetService(NS_WEBCONTENTHANDLERREGISTRAR_CONTRACTID);
884   if (!registrar) {
885     return;
886   }
887 
888   aRv = registrar->RegisterProtocolHandler(aProtocol, aURI, aTitle,
889                                            mWindow->GetOuterWindow());
890 }
891 
GetGeolocation(ErrorResult & aRv)892 Geolocation* Navigator::GetGeolocation(ErrorResult& aRv) {
893   if (mGeolocation) {
894     return mGeolocation;
895   }
896 
897   if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) {
898     aRv.Throw(NS_ERROR_FAILURE);
899     return nullptr;
900   }
901 
902   mGeolocation = new Geolocation();
903   if (NS_FAILED(mGeolocation->Init(mWindow))) {
904     mGeolocation = nullptr;
905     aRv.Throw(NS_ERROR_FAILURE);
906     return nullptr;
907   }
908 
909   return mGeolocation;
910 }
911 
912 class BeaconStreamListener final : public nsIStreamListener {
~BeaconStreamListener()913   ~BeaconStreamListener() {}
914 
915  public:
BeaconStreamListener()916   BeaconStreamListener() : mLoadGroup(nullptr) {}
917 
SetLoadGroup(nsILoadGroup * aLoadGroup)918   void SetLoadGroup(nsILoadGroup* aLoadGroup) { mLoadGroup = aLoadGroup; }
919 
920   NS_DECL_ISUPPORTS
921   NS_DECL_NSISTREAMLISTENER
922   NS_DECL_NSIREQUESTOBSERVER
923 
924  private:
925   nsCOMPtr<nsILoadGroup> mLoadGroup;
926 };
927 
NS_IMPL_ISUPPORTS(BeaconStreamListener,nsIStreamListener,nsIRequestObserver)928 NS_IMPL_ISUPPORTS(BeaconStreamListener, nsIStreamListener, nsIRequestObserver)
929 
930 NS_IMETHODIMP
931 BeaconStreamListener::OnStartRequest(nsIRequest* aRequest,
932                                      nsISupports* aContext) {
933   // release the loadgroup first
934   mLoadGroup = nullptr;
935 
936   aRequest->Cancel(NS_ERROR_NET_INTERRUPT);
937   return NS_BINDING_ABORTED;
938 }
939 
940 NS_IMETHODIMP
OnStopRequest(nsIRequest * aRequest,nsISupports * aContext,nsresult aStatus)941 BeaconStreamListener::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext,
942                                     nsresult aStatus) {
943   return NS_OK;
944 }
945 
946 NS_IMETHODIMP
OnDataAvailable(nsIRequest * aRequest,nsISupports * ctxt,nsIInputStream * inStr,uint64_t sourceOffset,uint32_t count)947 BeaconStreamListener::OnDataAvailable(nsIRequest* aRequest, nsISupports* ctxt,
948                                       nsIInputStream* inStr,
949                                       uint64_t sourceOffset, uint32_t count) {
950   MOZ_ASSERT(false);
951   return NS_OK;
952 }
953 
SendBeacon(const nsAString & aUrl,const Nullable<fetch::BodyInit> & aData,ErrorResult & aRv)954 bool Navigator::SendBeacon(const nsAString& aUrl,
955                            const Nullable<fetch::BodyInit>& aData,
956                            ErrorResult& aRv) {
957   if (aData.IsNull()) {
958     return SendBeaconInternal(aUrl, nullptr, eBeaconTypeOther, aRv);
959   }
960 
961   if (aData.Value().IsArrayBuffer()) {
962     BodyExtractor<const ArrayBuffer> body(&aData.Value().GetAsArrayBuffer());
963     return SendBeaconInternal(aUrl, &body, eBeaconTypeArrayBuffer, aRv);
964   }
965 
966   if (aData.Value().IsArrayBufferView()) {
967     BodyExtractor<const ArrayBufferView> body(
968         &aData.Value().GetAsArrayBufferView());
969     return SendBeaconInternal(aUrl, &body, eBeaconTypeArrayBuffer, aRv);
970   }
971 
972   if (aData.Value().IsBlob()) {
973     BodyExtractor<const Blob> body(&aData.Value().GetAsBlob());
974     return SendBeaconInternal(aUrl, &body, eBeaconTypeBlob, aRv);
975   }
976 
977   if (aData.Value().IsFormData()) {
978     BodyExtractor<const FormData> body(&aData.Value().GetAsFormData());
979     return SendBeaconInternal(aUrl, &body, eBeaconTypeOther, aRv);
980   }
981 
982   if (aData.Value().IsUSVString()) {
983     BodyExtractor<const nsAString> body(&aData.Value().GetAsUSVString());
984     return SendBeaconInternal(aUrl, &body, eBeaconTypeOther, aRv);
985   }
986 
987   if (aData.Value().IsURLSearchParams()) {
988     BodyExtractor<const URLSearchParams> body(
989         &aData.Value().GetAsURLSearchParams());
990     return SendBeaconInternal(aUrl, &body, eBeaconTypeOther, aRv);
991   }
992 
993   MOZ_CRASH("Invalid data type.");
994   return false;
995 }
996 
SendBeaconInternal(const nsAString & aUrl,BodyExtractorBase * aBody,BeaconType aType,ErrorResult & aRv)997 bool Navigator::SendBeaconInternal(const nsAString& aUrl,
998                                    BodyExtractorBase* aBody, BeaconType aType,
999                                    ErrorResult& aRv) {
1000   if (!mWindow) {
1001     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
1002     return false;
1003   }
1004 
1005   nsCOMPtr<nsIDocument> doc = mWindow->GetDoc();
1006   if (!doc) {
1007     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
1008     return false;
1009   }
1010 
1011   nsIURI* documentURI = doc->GetDocumentURI();
1012   if (!documentURI) {
1013     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
1014     return false;
1015   }
1016 
1017   nsCOMPtr<nsIURI> uri;
1018   nsresult rv = nsContentUtils::NewURIWithDocumentCharset(
1019       getter_AddRefs(uri), aUrl, doc, doc->GetDocBaseURI());
1020   if (NS_FAILED(rv)) {
1021     aRv.ThrowTypeError<MSG_INVALID_URL>(aUrl);
1022     return false;
1023   }
1024 
1025   // Spec disallows any schemes save for HTTP/HTTPs
1026   bool isValidScheme;
1027   if (!(NS_SUCCEEDED(uri->SchemeIs("http", &isValidScheme)) && isValidScheme) &&
1028       !(NS_SUCCEEDED(uri->SchemeIs("https", &isValidScheme)) &&
1029         isValidScheme)) {
1030     aRv.ThrowTypeError<MSG_INVALID_URL_SCHEME>(NS_LITERAL_STRING("Beacon"),
1031                                                aUrl);
1032     return false;
1033   }
1034 
1035   nsLoadFlags loadFlags =
1036       nsIRequest::LOAD_NORMAL | nsIChannel::LOAD_CLASSIFY_URI;
1037 
1038   // No need to use CORS for sendBeacon unless it's a BLOB
1039   nsSecurityFlags securityFlags =
1040       aType == eBeaconTypeBlob
1041           ? nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS
1042           : nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS;
1043   securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
1044 
1045   nsCOMPtr<nsIChannel> channel;
1046   rv = NS_NewChannel(getter_AddRefs(channel), uri, doc, securityFlags,
1047                      nsIContentPolicy::TYPE_BEACON,
1048                      nullptr,  // aPerformanceStorage
1049                      nullptr,  // aLoadGroup
1050                      nullptr,  // aCallbacks
1051                      loadFlags);
1052 
1053   if (NS_FAILED(rv)) {
1054     aRv.Throw(rv);
1055     return false;
1056   }
1057 
1058   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
1059   if (!httpChannel) {
1060     // Beacon spec only supports HTTP requests at this time
1061     aRv.Throw(NS_ERROR_DOM_BAD_URI);
1062     return false;
1063   }
1064   mozilla::net::ReferrerPolicy referrerPolicy = doc->GetReferrerPolicy();
1065   rv = httpChannel->SetReferrerWithPolicy(documentURI, referrerPolicy);
1066   MOZ_ASSERT(NS_SUCCEEDED(rv));
1067 
1068   nsCOMPtr<nsIInputStream> in;
1069   nsAutoCString contentTypeWithCharset;
1070   nsAutoCString charset;
1071   uint64_t length = 0;
1072 
1073   if (aBody) {
1074     aRv = aBody->GetAsStream(getter_AddRefs(in), &length,
1075                              contentTypeWithCharset, charset);
1076     if (NS_WARN_IF(aRv.Failed())) {
1077       return false;
1078     }
1079 
1080     nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(channel);
1081     if (!uploadChannel) {
1082       aRv.Throw(NS_ERROR_FAILURE);
1083       return false;
1084     }
1085 
1086     uploadChannel->ExplicitSetUploadStream(in, contentTypeWithCharset, length,
1087                                            NS_LITERAL_CSTRING("POST"), false);
1088   } else {
1089     rv = httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
1090     MOZ_ASSERT(NS_SUCCEEDED(rv));
1091   }
1092 
1093   nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(channel);
1094   if (p) {
1095     p->SetPriority(nsISupportsPriority::PRIORITY_LOWEST);
1096   }
1097 
1098   nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
1099   if (cos) {
1100     cos->AddClassFlags(nsIClassOfService::Background);
1101   }
1102 
1103   // The channel needs to have a loadgroup associated with it, so that we can
1104   // cancel the channel and any redirected channels it may create.
1105   nsCOMPtr<nsILoadGroup> loadGroup = do_CreateInstance(NS_LOADGROUP_CONTRACTID);
1106   nsCOMPtr<nsIInterfaceRequestor> callbacks =
1107       do_QueryInterface(mWindow->GetDocShell());
1108   loadGroup->SetNotificationCallbacks(callbacks);
1109   channel->SetLoadGroup(loadGroup);
1110 
1111   RefPtr<BeaconStreamListener> beaconListener = new BeaconStreamListener();
1112   rv = channel->AsyncOpen2(beaconListener);
1113   // do not throw if security checks fail within asyncOpen2
1114   NS_ENSURE_SUCCESS(rv, false);
1115 
1116   // make the beaconListener hold a strong reference to the loadgroup
1117   // which is released in ::OnStartRequest
1118   beaconListener->SetLoadGroup(loadGroup);
1119 
1120   return true;
1121 }
1122 
GetMediaDevices(ErrorResult & aRv)1123 MediaDevices* Navigator::GetMediaDevices(ErrorResult& aRv) {
1124   if (!mMediaDevices) {
1125     if (!mWindow || !mWindow->GetOuterWindow() ||
1126         mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) {
1127       aRv.Throw(NS_ERROR_NOT_AVAILABLE);
1128       return nullptr;
1129     }
1130     mMediaDevices = new MediaDevices(mWindow);
1131   }
1132   return mMediaDevices;
1133 }
1134 
MozGetUserMedia(const MediaStreamConstraints & aConstraints,NavigatorUserMediaSuccessCallback & aOnSuccess,NavigatorUserMediaErrorCallback & aOnError,CallerType aCallerType,ErrorResult & aRv)1135 void Navigator::MozGetUserMedia(const MediaStreamConstraints& aConstraints,
1136                                 NavigatorUserMediaSuccessCallback& aOnSuccess,
1137                                 NavigatorUserMediaErrorCallback& aOnError,
1138                                 CallerType aCallerType, ErrorResult& aRv) {
1139   CallbackObjectHolder<NavigatorUserMediaSuccessCallback,
1140                        nsIDOMGetUserMediaSuccessCallback>
1141       holder1(&aOnSuccess);
1142   nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onsuccess =
1143       holder1.ToXPCOMCallback();
1144 
1145   CallbackObjectHolder<NavigatorUserMediaErrorCallback,
1146                        nsIDOMGetUserMediaErrorCallback>
1147       holder2(&aOnError);
1148   nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onerror = holder2.ToXPCOMCallback();
1149 
1150   if (!mWindow || !mWindow->GetOuterWindow() ||
1151       mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) {
1152     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
1153     return;
1154   }
1155 
1156   MediaManager* manager = MediaManager::Get();
1157   aRv = manager->GetUserMedia(mWindow, aConstraints, onsuccess, onerror,
1158                               aCallerType);
1159 }
1160 
MozGetUserMediaDevices(const MediaStreamConstraints & aConstraints,MozGetUserMediaDevicesSuccessCallback & aOnSuccess,NavigatorUserMediaErrorCallback & aOnError,uint64_t aInnerWindowID,const nsAString & aCallID,ErrorResult & aRv)1161 void Navigator::MozGetUserMediaDevices(
1162     const MediaStreamConstraints& aConstraints,
1163     MozGetUserMediaDevicesSuccessCallback& aOnSuccess,
1164     NavigatorUserMediaErrorCallback& aOnError, uint64_t aInnerWindowID,
1165     const nsAString& aCallID, ErrorResult& aRv) {
1166   CallbackObjectHolder<MozGetUserMediaDevicesSuccessCallback,
1167                        nsIGetUserMediaDevicesSuccessCallback>
1168       holder1(&aOnSuccess);
1169   nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> onsuccess =
1170       holder1.ToXPCOMCallback();
1171 
1172   CallbackObjectHolder<NavigatorUserMediaErrorCallback,
1173                        nsIDOMGetUserMediaErrorCallback>
1174       holder2(&aOnError);
1175   nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onerror = holder2.ToXPCOMCallback();
1176 
1177   if (!mWindow || !mWindow->GetOuterWindow() ||
1178       mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) {
1179     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
1180     return;
1181   }
1182 
1183   MediaManager* manager = MediaManager::Get();
1184   aRv = manager->GetUserMediaDevices(mWindow, aConstraints, onsuccess, onerror,
1185                                      aInnerWindowID, aCallID);
1186 }
1187 
1188 //*****************************************************************************
1189 //    Navigator::nsINavigatorBattery
1190 //*****************************************************************************
1191 
GetBattery(ErrorResult & aRv)1192 Promise* Navigator::GetBattery(ErrorResult& aRv) {
1193   if (mBatteryPromise) {
1194     return mBatteryPromise;
1195   }
1196 
1197   if (!mWindow || !mWindow->GetDocShell()) {
1198     aRv.Throw(NS_ERROR_UNEXPECTED);
1199     return nullptr;
1200   }
1201 
1202   RefPtr<Promise> batteryPromise = Promise::Create(mWindow->AsGlobal(), aRv);
1203   if (NS_WARN_IF(aRv.Failed())) {
1204     return nullptr;
1205   }
1206   mBatteryPromise = batteryPromise;
1207 
1208   if (!mBatteryManager) {
1209     mBatteryManager = new battery::BatteryManager(mWindow);
1210     mBatteryManager->Init();
1211   }
1212 
1213   mBatteryPromise->MaybeResolve(mBatteryManager);
1214 
1215   return mBatteryPromise;
1216 }
1217 
MozTCPSocket()1218 already_AddRefed<LegacyMozTCPSocket> Navigator::MozTCPSocket() {
1219   RefPtr<LegacyMozTCPSocket> socket = new LegacyMozTCPSocket(GetWindow());
1220   return socket.forget();
1221 }
1222 
GetGamepads(nsTArray<RefPtr<Gamepad>> & aGamepads,ErrorResult & aRv)1223 void Navigator::GetGamepads(nsTArray<RefPtr<Gamepad>>& aGamepads,
1224                             ErrorResult& aRv) {
1225   if (!mWindow) {
1226     aRv.Throw(NS_ERROR_UNEXPECTED);
1227     return;
1228   }
1229   NS_ENSURE_TRUE_VOID(mWindow->GetDocShell());
1230   nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
1231   win->SetHasGamepadEventListener(true);
1232   win->GetGamepads(aGamepads);
1233 }
1234 
RequestGamepadServiceTest()1235 GamepadServiceTest* Navigator::RequestGamepadServiceTest() {
1236   if (!mGamepadServiceTest) {
1237     mGamepadServiceTest = GamepadServiceTest::CreateTestService(mWindow);
1238   }
1239   return mGamepadServiceTest;
1240 }
1241 
GetVRDisplays(ErrorResult & aRv)1242 already_AddRefed<Promise> Navigator::GetVRDisplays(ErrorResult& aRv) {
1243   if (!mWindow || !mWindow->GetDocShell()) {
1244     aRv.Throw(NS_ERROR_UNEXPECTED);
1245     return nullptr;
1246   }
1247 
1248   nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
1249   win->NotifyVREventListenerAdded();
1250 
1251   RefPtr<Promise> p = Promise::Create(mWindow->AsGlobal(), aRv);
1252   if (aRv.Failed()) {
1253     return nullptr;
1254   }
1255 
1256   // We pass mWindow's id to RefreshVRDisplays, so NotifyVRDisplaysUpdated will
1257   // be called asynchronously, resolving the promises in mVRGetDisplaysPromises.
1258   if (!VRDisplay::RefreshVRDisplays(win->WindowID())) {
1259     p->MaybeReject(NS_ERROR_FAILURE);
1260     return p.forget();
1261   }
1262 
1263   mVRGetDisplaysPromises.AppendElement(p);
1264   return p.forget();
1265 }
1266 
GetActiveVRDisplays(nsTArray<RefPtr<VRDisplay>> & aDisplays) const1267 void Navigator::GetActiveVRDisplays(
1268     nsTArray<RefPtr<VRDisplay>>& aDisplays) const {
1269   /**
1270    * Get only the active VR displays.
1271    * GetActiveVRDisplays should only enumerate displays that
1272    * are already active without causing any other hardware to be
1273    * activated.
1274    * We must not call nsGlobalWindow::NotifyVREventListenerAdded here,
1275    * as that would cause enumeration and activation of other VR hardware.
1276    * Activating VR hardware is intrusive to the end user, as it may
1277    * involve physically powering on devices that the user did not
1278    * intend to use.
1279    */
1280   if (!mWindow || !mWindow->GetDocShell()) {
1281     return;
1282   }
1283   nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
1284   nsTArray<RefPtr<VRDisplay>> displays;
1285   if (win->UpdateVRDisplays(displays)) {
1286     for (auto display : displays) {
1287       if (display->IsPresenting()) {
1288         aDisplays.AppendElement(display);
1289       }
1290     }
1291   }
1292 }
1293 
NotifyVRDisplaysUpdated()1294 void Navigator::NotifyVRDisplaysUpdated() {
1295   // Synchronize the VR devices and resolve the promises in
1296   // mVRGetDisplaysPromises
1297   nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
1298 
1299   nsTArray<RefPtr<VRDisplay>> vrDisplays;
1300   if (win->UpdateVRDisplays(vrDisplays)) {
1301     for (auto p : mVRGetDisplaysPromises) {
1302       p->MaybeResolve(vrDisplays);
1303     }
1304   } else {
1305     for (auto p : mVRGetDisplaysPromises) {
1306       p->MaybeReject(NS_ERROR_FAILURE);
1307     }
1308   }
1309   mVRGetDisplaysPromises.Clear();
1310 }
1311 
NotifyActiveVRDisplaysChanged()1312 void Navigator::NotifyActiveVRDisplaysChanged() {
1313   NavigatorBinding::ClearCachedActiveVRDisplaysValue(this);
1314 }
1315 
RequestVRServiceTest()1316 VRServiceTest* Navigator::RequestVRServiceTest() {
1317   // Ensure that the Mock VR devices are not released prematurely
1318   nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
1319   win->NotifyVREventListenerAdded();
1320 
1321   if (!mVRServiceTest) {
1322     mVRServiceTest = VRServiceTest::CreateTestService(mWindow);
1323   }
1324   return mVRServiceTest;
1325 }
1326 
IsWebVRContentDetected() const1327 bool Navigator::IsWebVRContentDetected() const {
1328   nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
1329   return win->IsVRContentDetected();
1330 }
1331 
IsWebVRContentPresenting() const1332 bool Navigator::IsWebVRContentPresenting() const {
1333   nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
1334   return win->IsVRContentPresenting();
1335 }
1336 
RequestVRPresentation(VRDisplay & aDisplay)1337 void Navigator::RequestVRPresentation(VRDisplay& aDisplay) {
1338   nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
1339   win->DispatchVRDisplayActivate(aDisplay.DisplayId(),
1340                                  VRDisplayEventReason::Requested);
1341 }
1342 
RequestMIDIAccess(const MIDIOptions & aOptions,ErrorResult & aRv)1343 already_AddRefed<Promise> Navigator::RequestMIDIAccess(
1344     const MIDIOptions& aOptions, ErrorResult& aRv) {
1345   if (!mWindow) {
1346     aRv.Throw(NS_ERROR_UNEXPECTED);
1347     return nullptr;
1348   }
1349   MIDIAccessManager* accessMgr = MIDIAccessManager::Get();
1350   return accessMgr->RequestMIDIAccess(mWindow, aOptions, aRv);
1351 }
1352 
GetNetworkProperties()1353 nsINetworkProperties* Navigator::GetNetworkProperties() {
1354   return GetConnection(IgnoreErrors());
1355 }
1356 
GetConnection(ErrorResult & aRv)1357 network::Connection* Navigator::GetConnection(ErrorResult& aRv) {
1358   if (!mConnection) {
1359     if (!mWindow) {
1360       aRv.Throw(NS_ERROR_UNEXPECTED);
1361       return nullptr;
1362     }
1363     mConnection = network::Connection::CreateForWindow(mWindow);
1364   }
1365 
1366   return mConnection;
1367 }
1368 
ServiceWorker()1369 already_AddRefed<ServiceWorkerContainer> Navigator::ServiceWorker() {
1370   MOZ_ASSERT(mWindow);
1371 
1372   if (!mServiceWorkerContainer) {
1373     mServiceWorkerContainer = new ServiceWorkerContainer(mWindow);
1374   }
1375 
1376   RefPtr<ServiceWorkerContainer> ref = mServiceWorkerContainer;
1377   return ref.forget();
1378 }
1379 
SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const1380 size_t Navigator::SizeOfIncludingThis(
1381     mozilla::MallocSizeOf aMallocSizeOf) const {
1382   size_t n = aMallocSizeOf(this);
1383 
1384   // TODO: add SizeOfIncludingThis() to nsMimeTypeArray, bug 674113.
1385   // TODO: add SizeOfIncludingThis() to nsPluginArray, bug 674114.
1386   // TODO: add SizeOfIncludingThis() to Geolocation, bug 674115.
1387   // TODO: add SizeOfIncludingThis() to DesktopNotificationCenter, bug 674116.
1388 
1389   return n;
1390 }
1391 
SetWindow(nsPIDOMWindowInner * aInnerWindow)1392 void Navigator::SetWindow(nsPIDOMWindowInner* aInnerWindow) {
1393   mWindow = aInnerWindow;
1394 }
1395 
OnNavigation()1396 void Navigator::OnNavigation() {
1397   if (!mWindow) {
1398     return;
1399   }
1400 
1401   // If MediaManager is open let it inform any live streams or pending callbacks
1402   MediaManager* manager = MediaManager::GetIfExists();
1403   if (manager) {
1404     manager->OnNavigation(mWindow->WindowID());
1405   }
1406 }
1407 
CheckPermission(const char * type)1408 bool Navigator::CheckPermission(const char* type) {
1409   return CheckPermission(mWindow, type);
1410 }
1411 
1412 /* static */
CheckPermission(nsPIDOMWindowInner * aWindow,const char * aType)1413 bool Navigator::CheckPermission(nsPIDOMWindowInner* aWindow,
1414                                 const char* aType) {
1415   if (!aWindow) {
1416     return false;
1417   }
1418 
1419   uint32_t permission = GetPermission(aWindow, aType);
1420   return permission == nsIPermissionManager::ALLOW_ACTION;
1421 }
1422 
WrapObject(JSContext * cx,JS::Handle<JSObject * > aGivenProto)1423 JSObject* Navigator::WrapObject(JSContext* cx,
1424                                 JS::Handle<JSObject*> aGivenProto) {
1425   return NavigatorBinding::Wrap(cx, this, aGivenProto);
1426 }
1427 
1428 /* static */
HasWakeLockSupport(JSContext *,JSObject *)1429 bool Navigator::HasWakeLockSupport(JSContext* /* unused*/,
1430                                    JSObject* /*unused */) {
1431   nsCOMPtr<nsIPowerManagerService> pmService =
1432       do_GetService(POWERMANAGERSERVICE_CONTRACTID);
1433   // No service means no wake lock support
1434   return !!pmService;
1435 }
1436 
1437 /* static */
HasWifiManagerSupport(JSContext *,JSObject * aGlobal)1438 bool Navigator::HasWifiManagerSupport(JSContext* /* unused */,
1439                                       JSObject* aGlobal) {
1440   // On XBL scope, the global object is NOT |window|. So we have
1441   // to use nsContentUtils::GetObjectPrincipal to get the principal
1442   // and test directly with permission manager.
1443 
1444   nsIPrincipal* principal = nsContentUtils::ObjectPrincipal(aGlobal);
1445   uint32_t permission = GetPermission(principal, "wifi-manage");
1446 
1447   return permission == nsIPermissionManager::ALLOW_ACTION;
1448 }
1449 
1450 /* static */
HasUserMediaSupport(JSContext *,JSObject *)1451 bool Navigator::HasUserMediaSupport(JSContext* /* unused */,
1452                                     JSObject* /* unused */) {
1453   // Make enabling peerconnection enable getUserMedia() as well
1454   return Preferences::GetBool("media.navigator.enabled", false) ||
1455          Preferences::GetBool("media.peerconnection.enabled", false);
1456 }
1457 
1458 /* static */
GetWindowFromGlobal(JSObject * aGlobal)1459 already_AddRefed<nsPIDOMWindowInner> Navigator::GetWindowFromGlobal(
1460     JSObject* aGlobal) {
1461   nsCOMPtr<nsPIDOMWindowInner> win =
1462       do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(aGlobal));
1463   return win.forget();
1464 }
1465 
GetPlatform(nsAString & aPlatform,bool aUsePrefOverriddenValue)1466 nsresult Navigator::GetPlatform(nsAString& aPlatform,
1467                                 bool aUsePrefOverriddenValue) {
1468   MOZ_ASSERT(NS_IsMainThread());
1469 
1470   if (aUsePrefOverriddenValue) {
1471     // If fingerprinting resistance is on, we will spoof this value. See
1472     // nsRFPService.h for details about spoofed values.
1473     if (nsContentUtils::ShouldResistFingerprinting()) {
1474       aPlatform.AssignLiteral(SPOOFED_PLATFORM);
1475       return NS_OK;
1476     }
1477     nsAutoString override;
1478     nsresult rv =
1479         mozilla::Preferences::GetString("general.platform.override", override);
1480 
1481     if (NS_SUCCEEDED(rv)) {
1482       aPlatform = override;
1483       return NS_OK;
1484     }
1485   }
1486 
1487   nsresult rv;
1488 
1489   nsCOMPtr<nsIHttpProtocolHandler> service(
1490       do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
1491   NS_ENSURE_SUCCESS(rv, rv);
1492 
1493   // Sorry for the #if platform ugliness, but Communicator is likewise
1494   // hardcoded and we are seeking backward compatibility here (bug 47080).
1495 #if defined(_WIN64)
1496   aPlatform.AssignLiteral("Win64");
1497 #elif defined(WIN32)
1498   aPlatform.AssignLiteral("Win32");
1499 #elif defined(XP_MACOSX) && defined(__ppc__)
1500   aPlatform.AssignLiteral("MacPPC");
1501 #elif defined(XP_MACOSX) && defined(__i386__)
1502   aPlatform.AssignLiteral("MacIntel");
1503 #elif defined(XP_MACOSX) && defined(__x86_64__)
1504   aPlatform.AssignLiteral("MacIntel");
1505 #else
1506   // XXX Communicator uses compiled-in build-time string defines
1507   // to indicate the platform it was compiled *for*, not what it is
1508   // currently running *on* which is what this does.
1509   nsAutoCString plat;
1510   rv = service->GetOscpu(plat);
1511   CopyASCIItoUTF16(plat, aPlatform);
1512 #endif
1513 
1514   return rv;
1515 }
1516 
GetAppVersion(nsAString & aAppVersion,bool aUsePrefOverriddenValue)1517 /* static */ nsresult Navigator::GetAppVersion(nsAString& aAppVersion,
1518                                                bool aUsePrefOverriddenValue) {
1519   MOZ_ASSERT(NS_IsMainThread());
1520 
1521   if (aUsePrefOverriddenValue) {
1522     // If fingerprinting resistance is on, we will spoof this value. See
1523     // nsRFPService.h for details about spoofed values.
1524     if (nsContentUtils::ShouldResistFingerprinting()) {
1525       aAppVersion.AssignLiteral(SPOOFED_APPVERSION);
1526       return NS_OK;
1527     }
1528     nsAutoString override;
1529     nsresult rv = mozilla::Preferences::GetString("general.appversion.override",
1530                                                   override);
1531 
1532     if (NS_SUCCEEDED(rv)) {
1533       aAppVersion = override;
1534       return NS_OK;
1535     }
1536   }
1537 
1538   nsresult rv;
1539 
1540   nsCOMPtr<nsIHttpProtocolHandler> service(
1541       do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
1542   NS_ENSURE_SUCCESS(rv, rv);
1543 
1544   nsAutoCString str;
1545   rv = service->GetAppVersion(str);
1546   CopyASCIItoUTF16(str, aAppVersion);
1547   NS_ENSURE_SUCCESS(rv, rv);
1548 
1549   aAppVersion.AppendLiteral(" (");
1550 
1551   rv = service->GetPlatform(str);
1552   NS_ENSURE_SUCCESS(rv, rv);
1553 
1554   AppendASCIItoUTF16(str, aAppVersion);
1555   aAppVersion.Append(char16_t(')'));
1556 
1557   return rv;
1558 }
1559 
AppName(nsAString & aAppName,bool aUsePrefOverriddenValue)1560 /* static */ void Navigator::AppName(nsAString& aAppName,
1561                                      bool aUsePrefOverriddenValue) {
1562   MOZ_ASSERT(NS_IsMainThread());
1563 
1564   if (aUsePrefOverriddenValue) {
1565     // If fingerprinting resistance is on, we will spoof this value. See
1566     // nsRFPService.h for details about spoofed values.
1567     if (nsContentUtils::ShouldResistFingerprinting()) {
1568       aAppName.AssignLiteral(SPOOFED_APPNAME);
1569       return;
1570     }
1571 
1572     nsAutoString override;
1573     nsresult rv =
1574         mozilla::Preferences::GetString("general.appname.override", override);
1575 
1576     if (NS_SUCCEEDED(rv)) {
1577       aAppName = override;
1578       return;
1579     }
1580   }
1581 
1582   aAppName.AssignLiteral("Netscape");
1583 }
1584 
ClearUserAgentCache()1585 void Navigator::ClearUserAgentCache() {
1586   NavigatorBinding::ClearCachedUserAgentValue(this);
1587 }
1588 
GetUserAgent(nsPIDOMWindowInner * aWindow,bool aIsCallerChrome,nsAString & aUserAgent)1589 nsresult Navigator::GetUserAgent(nsPIDOMWindowInner* aWindow,
1590                                  bool aIsCallerChrome, nsAString& aUserAgent) {
1591   MOZ_ASSERT(NS_IsMainThread());
1592 
1593   // We will skip the override and pass to httpHandler to get spoofed userAgent
1594   // when 'privacy.resistFingerprinting' is true.
1595   if (!aIsCallerChrome && !nsContentUtils::ShouldResistFingerprinting()) {
1596     nsAutoString override;
1597     nsresult rv =
1598         mozilla::Preferences::GetString("general.useragent.override", override);
1599 
1600     if (NS_SUCCEEDED(rv)) {
1601       aUserAgent = override;
1602       return NS_OK;
1603     }
1604   }
1605 
1606   // When the caller is content and 'privacy.resistFingerprinting' is true,
1607   // return a spoofed userAgent which reveals the platform but not the
1608   // specific OS version, etc.
1609   if (!aIsCallerChrome && nsContentUtils::ShouldResistFingerprinting()) {
1610     nsAutoCString spoofedUA;
1611     nsresult rv = nsRFPService::GetSpoofedUserAgent(spoofedUA, false);
1612     if (NS_WARN_IF(NS_FAILED(rv))) {
1613       return rv;
1614     }
1615     CopyASCIItoUTF16(spoofedUA, aUserAgent);
1616     return NS_OK;
1617   }
1618 
1619   nsresult rv;
1620   nsCOMPtr<nsIHttpProtocolHandler> service(
1621       do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
1622   if (NS_WARN_IF(NS_FAILED(rv))) {
1623     return rv;
1624   }
1625 
1626   nsAutoCString ua;
1627   rv = service->GetUserAgent(ua);
1628   if (NS_WARN_IF(NS_FAILED(rv))) {
1629     return rv;
1630   }
1631 
1632   CopyASCIItoUTF16(ua, aUserAgent);
1633 
1634   // When the caller is content, we will always return spoofed userAgent and
1635   // ignore the User-Agent header from the document channel when
1636   // 'privacy.resistFingerprinting' is true.
1637   if (!aWindow ||
1638       (nsContentUtils::ShouldResistFingerprinting() && !aIsCallerChrome)) {
1639     return NS_OK;
1640   }
1641 
1642   // Copy the User-Agent header from the document channel which has already been
1643   // subject to UA overrides.
1644   nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
1645   if (!doc) {
1646     return NS_OK;
1647   }
1648   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(doc->GetChannel());
1649   if (httpChannel) {
1650     nsAutoCString userAgent;
1651     rv = httpChannel->GetRequestHeader(NS_LITERAL_CSTRING("User-Agent"),
1652                                        userAgent);
1653     if (NS_WARN_IF(NS_FAILED(rv))) {
1654       return rv;
1655     }
1656     CopyASCIItoUTF16(userAgent, aUserAgent);
1657   }
1658   return NS_OK;
1659 }
1660 
RequestKeySystemAccessLogString(const nsAString & aKeySystem,const Sequence<MediaKeySystemConfiguration> & aConfigs,bool aIsSecureContext)1661 static nsCString RequestKeySystemAccessLogString(
1662     const nsAString& aKeySystem,
1663     const Sequence<MediaKeySystemConfiguration>& aConfigs,
1664     bool aIsSecureContext) {
1665   nsCString str;
1666   str.AppendPrintf(
1667       "Navigator::RequestMediaKeySystemAccess(keySystem='%s' options=",
1668       NS_ConvertUTF16toUTF8(aKeySystem).get());
1669   str.Append(MediaKeySystemAccess::ToCString(aConfigs));
1670   str.AppendLiteral(") secureContext=");
1671   str.AppendInt(aIsSecureContext);
1672   return str;
1673 }
1674 
RequestMediaKeySystemAccess(const nsAString & aKeySystem,const Sequence<MediaKeySystemConfiguration> & aConfigs,ErrorResult & aRv)1675 already_AddRefed<Promise> Navigator::RequestMediaKeySystemAccess(
1676     const nsAString& aKeySystem,
1677     const Sequence<MediaKeySystemConfiguration>& aConfigs, ErrorResult& aRv) {
1678   EME_LOG("%s", RequestKeySystemAccessLogString(aKeySystem, aConfigs,
1679                                                 mWindow->IsSecureContext())
1680                     .get());
1681 
1682   Telemetry::Accumulate(Telemetry::MEDIA_EME_SECURE_CONTEXT,
1683                         mWindow->IsSecureContext());
1684 
1685   if (!mWindow->IsSecureContext()) {
1686     nsIDocument* doc = mWindow->GetExtantDoc();
1687     nsString uri;
1688     if (doc) {
1689       Unused << doc->GetDocumentURI(uri);
1690     }
1691     const char16_t* params[] = {uri.get()};
1692     nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
1693                                     NS_LITERAL_CSTRING("Media"), doc,
1694                                     nsContentUtils::eDOM_PROPERTIES,
1695                                     "MediaEMEInsecureContextDeprecatedWarning",
1696                                     params, ArrayLength(params));
1697   }
1698 
1699   RefPtr<DetailedPromise> promise = DetailedPromise::Create(
1700       mWindow->AsGlobal(), aRv,
1701       NS_LITERAL_CSTRING("navigator.requestMediaKeySystemAccess"),
1702       Telemetry::VIDEO_EME_REQUEST_SUCCESS_LATENCY_MS,
1703       Telemetry::VIDEO_EME_REQUEST_FAILURE_LATENCY_MS);
1704   if (aRv.Failed()) {
1705     return nullptr;
1706   }
1707 
1708   if (!mMediaKeySystemAccessManager) {
1709     mMediaKeySystemAccessManager = new MediaKeySystemAccessManager(mWindow);
1710   }
1711 
1712   mMediaKeySystemAccessManager->Request(promise, aKeySystem, aConfigs);
1713   return promise.forget();
1714 }
1715 
GetPresentation(ErrorResult & aRv)1716 Presentation* Navigator::GetPresentation(ErrorResult& aRv) {
1717   if (!mPresentation) {
1718     if (!mWindow) {
1719       aRv.Throw(NS_ERROR_UNEXPECTED);
1720       return nullptr;
1721     }
1722     mPresentation = Presentation::Create(mWindow);
1723   }
1724 
1725   return mPresentation;
1726 }
1727 
Credentials()1728 CredentialsContainer* Navigator::Credentials() {
1729   if (!mCredentials) {
1730     mCredentials = new CredentialsContainer(GetWindow());
1731   }
1732   return mCredentials;
1733 }
1734 
1735 /* static */
Webdriver()1736 bool Navigator::Webdriver() {
1737   return Preferences::GetBool("marionette.enabled", false);
1738 }
1739 
1740 }  // namespace dom
1741 }  // namespace mozilla
1742