dom/base/Navigator.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:e6c9f72b4b40
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=2 et tw=78: */
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/DesktopNotification.h"
16 #include "nsGeolocation.h"
17 #include "nsIHttpProtocolHandler.h"
18 #include "nsIContentPolicy.h"
19 #include "nsIContentSecurityPolicy.h"
20 #include "nsContentPolicyUtils.h"
21 #include "nsCrossSiteListenerProxy.h"
22 #include "nsISupportsPriority.h"
23 #include "nsICachingChannel.h"
24 #include "nsIWebContentHandlerRegistrar.h"
25 #include "nsICookiePermission.h"
26 #include "nsIScriptSecurityManager.h"
27 #include "nsCharSeparatedTokenizer.h"
28 #include "nsContentUtils.h"
29 #include "nsUnicharUtils.h"
30 #include "mozilla/Preferences.h"
31 #include "mozilla/Telemetry.h"
32 #include "BatteryManager.h"
33 #include "mozilla/dom/PowerManager.h"
34 #include "mozilla/dom/WakeLock.h"
35 #include "mozilla/dom/power/PowerManagerService.h"
36 #include "mozilla/dom/MobileMessageManager.h"
37 #include "mozilla/dom/Telephony.h"
38 #include "mozilla/Hal.h"
39 #include "nsISiteSpecificUserAgent.h"
40 #include "mozilla/ClearOnShutdown.h"
41 #include "mozilla/StaticPtr.h"
42 #include "Connection.h"
43 #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
44 #include "nsGlobalWindow.h"
45 #ifdef MOZ_B2G_RIL
46 #include "mozilla/dom/IccManager.h"
47 #include "mozilla/dom/CellBroadcast.h"
48 #include "mozilla/dom/MobileConnectionArray.h"
49 #include "mozilla/dom/Voicemail.h"
50 #endif
51 #include "nsIIdleObserver.h"
52 #include "nsIPermissionManager.h"
53 #include "nsMimeTypes.h"
54 #include "nsNetUtil.h"
55 #include "nsIHttpChannel.h"
56 #include "nsIHttpChannelInternal.h"
57 #include "TimeManager.h"
58 #include "DeviceStorage.h"
59 #include "nsIDOMNavigatorSystemMessages.h"
60 #include "nsStreamUtils.h"
61 #include "nsIAppsService.h"
62 #include "mozIApplication.h"
63 #include "WidgetUtils.h"
64 #include "mozIThirdPartyUtil.h"
65 #include "nsChannelPolicy.h"
66
67 #ifdef MOZ_MEDIA_NAVIGATOR
68 #include "MediaManager.h"
69 #endif
70 #ifdef MOZ_B2G_BT
71 #include "BluetoothManager.h"
72 #endif
73 #include "DOMCameraManager.h"
74
75 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
76 #include "AudioChannelManager.h"
77 #endif
78
79 #ifdef MOZ_B2G_FM
80 #include "mozilla/dom/FMRadio.h"
81 #endif
82
83 #include "nsIDOMGlobalPropertyInitializer.h"
84 #include "nsIDataStoreService.h"
85 #include "nsJSUtils.h"
86
87 #include "nsScriptNameSpaceManager.h"
88
89 #include "mozilla/dom/NavigatorBinding.h"
90 #include "mozilla/dom/Promise.h"
91
92 #include "nsIUploadChannel2.h"
93 #include "nsFormData.h"
94 #include "nsIPrivateBrowsingChannel.h"
95 #include "nsIDocShell.h"
96
97 namespace mozilla {
98 namespace dom {
99
100 static bool sDoNotTrackEnabled = false;
101 static bool sVibratorEnabled = false;
102 static uint32_t sMaxVibrateMS = 0;
103 static uint32_t sMaxVibrateListLen = 0;
104
105 /* static */
106 void
107 Navigator::Init()
108 {
109 Preferences::AddBoolVarCache(&sDoNotTrackEnabled,
110 "privacy.donottrackheader.enabled",
111 false);
112 Preferences::AddBoolVarCache(&sVibratorEnabled,
113 "dom.vibrator.enabled", true);
114 Preferences::AddUintVarCache(&sMaxVibrateMS,
115 "dom.vibrator.max_vibrate_ms", 10000);
116 Preferences::AddUintVarCache(&sMaxVibrateListLen,
117 "dom.vibrator.max_vibrate_list_len", 128);
118 }
119
120 Navigator::Navigator(nsPIDOMWindow* aWindow)
121 : mWindow(aWindow)
122 {
123 MOZ_ASSERT(aWindow->IsInnerWindow(), "Navigator must get an inner window!");
124 SetIsDOMBinding();
125 }
126
127 Navigator::~Navigator()
128 {
129 Invalidate();
130 }
131
132 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Navigator)
133 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
134 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMNavigator)
135 NS_INTERFACE_MAP_ENTRY(nsIDOMNavigator)
136 NS_INTERFACE_MAP_ENTRY(nsIMozNavigatorNetwork)
137 NS_INTERFACE_MAP_END
138
139 NS_IMPL_CYCLE_COLLECTING_ADDREF(Navigator)
140 NS_IMPL_CYCLE_COLLECTING_RELEASE(Navigator)
141
142 NS_IMPL_CYCLE_COLLECTION_CLASS(Navigator)
143
144 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Navigator)
145 tmp->Invalidate();
146 NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
147 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedResolveResults)
148 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
149 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
150
151 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
152 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlugins)
153 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMimeTypes)
154 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGeolocation)
155 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotification)
156 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryManager)
157 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPowerManager)
158 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileMessageManager)
159 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTelephony)
160 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
161 #ifdef MOZ_B2G_RIL
162 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileConnections)
163 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCellBroadcast)
164 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIccManager)
165 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVoicemail)
166 #endif
167 #ifdef MOZ_B2G_BT
168 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBluetooth)
169 #endif
170 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
171 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioChannelManager)
172 #endif
173 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCameraManager)
174 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessagesManager)
175 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDeviceStorageStores)
176 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTimeManager)
177
178 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
179 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedResolveResults)
180 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
181 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
182
183 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(Navigator)
184
185 void
186 Navigator::Invalidate()
187 {
188 // Don't clear mWindow here so we know we've got a non-null mWindow
189 // until we're unlinked.
190
191 if (mPlugins) {
192 mPlugins->Invalidate();
193 mPlugins = nullptr;
194 }
195
196 mMimeTypes = nullptr;
197
198 // If there is a page transition, make sure delete the geolocation object.
199 if (mGeolocation) {
200 mGeolocation->Shutdown();
201 mGeolocation = nullptr;
202 }
203
204 if (mNotification) {
205 mNotification->Shutdown();
206 mNotification = nullptr;
207 }
208
209 if (mBatteryManager) {
210 mBatteryManager->Shutdown();
211 mBatteryManager = nullptr;
212 }
213
214 #ifdef MOZ_B2G_FM
215 if (mFMRadio) {
216 mFMRadio->Shutdown();
217 mFMRadio = nullptr;
218 }
219 #endif
220
221 if (mPowerManager) {
222 mPowerManager->Shutdown();
223 mPowerManager = nullptr;
224 }
225
226 if (mMobileMessageManager) {
227 mMobileMessageManager->Shutdown();
228 mMobileMessageManager = nullptr;
229 }
230
231 if (mTelephony) {
232 mTelephony = nullptr;
233 }
234
235 if (mConnection) {
236 mConnection->Shutdown();
237 mConnection = nullptr;
238 }
239
240 #ifdef MOZ_B2G_RIL
241 if (mMobileConnections) {
242 mMobileConnections = nullptr;
243 }
244
245 if (mCellBroadcast) {
246 mCellBroadcast = nullptr;
247 }
248
249 if (mIccManager) {
250 mIccManager->Shutdown();
251 mIccManager = nullptr;
252 }
253
254 if (mVoicemail) {
255 mVoicemail = nullptr;
256 }
257 #endif
258
259 #ifdef MOZ_B2G_BT
260 if (mBluetooth) {
261 mBluetooth = nullptr;
262 }
263 #endif
264
265 mCameraManager = nullptr;
266
267 if (mMessagesManager) {
268 mMessagesManager = nullptr;
269 }
270
271 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
272 if (mAudioChannelManager) {
273 mAudioChannelManager = nullptr;
274 }
275 #endif
276
277 uint32_t len = mDeviceStorageStores.Length();
278 for (uint32_t i = 0; i < len; ++i) {
279 mDeviceStorageStores[i]->Shutdown();
280 }
281 mDeviceStorageStores.Clear();
282
283 if (mTimeManager) {
284 mTimeManager = nullptr;
285 }
286 }
287
288 //*****************************************************************************
289 // Navigator::nsIDOMNavigator
290 //*****************************************************************************
291
292 NS_IMETHODIMP
293 Navigator::GetUserAgent(nsAString& aUserAgent)
294 {
295 nsresult rv = NS_GetNavigatorUserAgent(aUserAgent);
296 NS_ENSURE_SUCCESS(rv, rv);
297
298 if (!mWindow || !mWindow->GetDocShell()) {
299 return NS_OK;
300 }
301
302 nsIDocument* doc = mWindow->GetExtantDoc();
303 if (!doc) {
304 return NS_OK;
305 }
306
307 nsCOMPtr<nsIURI> codebaseURI;
308 doc->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
309 if (!codebaseURI) {
310 return NS_OK;
311 }
312
313 nsCOMPtr<nsISiteSpecificUserAgent> siteSpecificUA =
314 do_GetService("@mozilla.org/dom/site-specific-user-agent;1");
315 NS_ENSURE_TRUE(siteSpecificUA, NS_OK);
316
317 return siteSpecificUA->GetUserAgentForURIAndWindow(codebaseURI, mWindow,
318 aUserAgent);
319 }
320
321 NS_IMETHODIMP
322 Navigator::GetAppCodeName(nsAString& aAppCodeName)
323 {
324 nsresult rv;
325
326 nsCOMPtr<nsIHttpProtocolHandler>
327 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
328 NS_ENSURE_SUCCESS(rv, rv);
329
330 nsAutoCString appName;
331 rv = service->GetAppName(appName);
332 CopyASCIItoUTF16(appName, aAppCodeName);
333
334 return rv;
335 }
336
337 NS_IMETHODIMP
338 Navigator::GetAppVersion(nsAString& aAppVersion)
339 {
340 return GetAppVersion(aAppVersion, /* aUsePrefOverriddenValue */ true);
341 }
342
343 NS_IMETHODIMP
344 Navigator::GetAppName(nsAString& aAppName)
345 {
346 AppName(aAppName, /* aUsePrefOverriddenValue */ true);
347 return NS_OK;
348 }
349
350 /**
351 * JS property navigator.language, exposed to web content.
352 * Take first value from Accept-Languages (HTTP header), which is
353 * the "content language" freely set by the user in the Pref window.
354 *
355 * Do not use UI language (chosen app locale) here.
356 * See RFC 2616, Section 15.1.4 "Privacy Issues Connected to Accept Headers"
357 *
358 * "en", "en-US" and "i-cherokee" and "" are valid.
359 * Fallback in case of invalid pref should be "" (empty string), to
360 * let site do fallback, e.g. to site's local language.
361 */
362 NS_IMETHODIMP
363 Navigator::GetLanguage(nsAString& aLanguage)
364 {
365 // E.g. "de-de, en-us,en".
366 const nsAdoptingString& acceptLang =
367 Preferences::GetLocalizedString("intl.accept_languages");
368
369 // Take everything before the first "," or ";", without trailing space.
370 nsCharSeparatedTokenizer langTokenizer(acceptLang, ',');
371 const nsSubstring &firstLangPart = langTokenizer.nextToken();
372 nsCharSeparatedTokenizer qTokenizer(firstLangPart, ';');
373 aLanguage.Assign(qTokenizer.nextToken());
374
375 // Checks and fixups:
376 // replace "_" with "-" to avoid POSIX/Windows "en_US" notation.
377 if (aLanguage.Length() > 2 && aLanguage[2] == char16_t('_')) {
378 aLanguage.Replace(2, 1, char16_t('-')); // TODO replace all
379 }
380
381 // Use uppercase for country part, e.g. "en-US", not "en-us", see BCP47
382 // only uppercase 2-letter country codes, not "zh-Hant", "de-DE-x-goethe".
383 if (aLanguage.Length() <= 2) {
384 return NS_OK;
385 }
386
387 nsCharSeparatedTokenizer localeTokenizer(aLanguage, '-');
388 int32_t pos = 0;
389 bool first = true;
390 while (localeTokenizer.hasMoreTokens()) {
391 const nsSubstring& code = localeTokenizer.nextToken();
392
393 if (code.Length() == 2 && !first) {
394 nsAutoString upper(code);
395 ToUpperCase(upper);
396 aLanguage.Replace(pos, code.Length(), upper);
397 }
398
399 pos += code.Length() + 1; // 1 is the separator
400 first = false;
401 }
402
403 return NS_OK;
404 }
405
406 NS_IMETHODIMP
407 Navigator::GetPlatform(nsAString& aPlatform)
408 {
409 return GetPlatform(aPlatform, /* aUsePrefOverriddenValue */ true);
410 }
411
412 NS_IMETHODIMP
413 Navigator::GetOscpu(nsAString& aOSCPU)
414 {
415 if (!nsContentUtils::IsCallerChrome()) {
416 const nsAdoptingString& override =
417 Preferences::GetString("general.oscpu.override");
418
419 if (override) {
420 aOSCPU = override;
421 return NS_OK;
422 }
423 }
424
425 nsresult rv;
426
427 nsCOMPtr<nsIHttpProtocolHandler>
428 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
429 NS_ENSURE_SUCCESS(rv, rv);
430
431 nsAutoCString oscpu;
432 rv = service->GetOscpu(oscpu);
433 CopyASCIItoUTF16(oscpu, aOSCPU);
434
435 return rv;
436 }
437
438 NS_IMETHODIMP
439 Navigator::GetVendor(nsAString& aVendor)
440 {
441 aVendor.Truncate();
442 return NS_OK;
443 }
444
445 NS_IMETHODIMP
446 Navigator::GetVendorSub(nsAString& aVendorSub)
447 {
448 aVendorSub.Truncate();
449 return NS_OK;
450 }
451
452 NS_IMETHODIMP
453 Navigator::GetProduct(nsAString& aProduct)
454 {
455 aProduct.AssignLiteral("Gecko");
456 return NS_OK;
457 }
458
459 NS_IMETHODIMP
460 Navigator::GetProductSub(nsAString& aProductSub)
461 {
462 // Legacy build ID hardcoded for backward compatibility (bug 776376)
463 aProductSub.AssignLiteral("20100101");
464 return NS_OK;
465 }
466
467 nsMimeTypeArray*
468 Navigator::GetMimeTypes(ErrorResult& aRv)
469 {
470 if (!mMimeTypes) {
471 if (!mWindow) {
472 aRv.Throw(NS_ERROR_UNEXPECTED);
473 return nullptr;
474 }
475 mMimeTypes = new nsMimeTypeArray(mWindow);
476 }
477
478 return mMimeTypes;
479 }
480
481 nsPluginArray*
482 Navigator::GetPlugins(ErrorResult& aRv)
483 {
484 if (!mPlugins) {
485 if (!mWindow) {
486 aRv.Throw(NS_ERROR_UNEXPECTED);
487 return nullptr;
488 }
489 mPlugins = new nsPluginArray(mWindow);
490 mPlugins->Init();
491 }
492
493 return mPlugins;
494 }
495
496 // Values for the network.cookie.cookieBehavior pref are documented in
497 // nsCookieService.cpp.
498 #define COOKIE_BEHAVIOR_REJECT 2
499
500 bool
501 Navigator::CookieEnabled()
502 {
503 bool cookieEnabled =
504 (Preferences::GetInt("network.cookie.cookieBehavior",
505 COOKIE_BEHAVIOR_REJECT) != COOKIE_BEHAVIOR_REJECT);
506
507 // Check whether an exception overrides the global cookie behavior
508 // Note that the code for getting the URI here matches that in
509 // nsHTMLDocument::SetCookie.
510 if (!mWindow || !mWindow->GetDocShell()) {
511 return cookieEnabled;
512 }
513
514 nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc();
515 if (!doc) {
516 return cookieEnabled;
517 }
518
519 nsCOMPtr<nsIURI> codebaseURI;
520 doc->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
521
522 if (!codebaseURI) {
523 // Not a codebase, so technically can't set cookies, but let's
524 // just return the default value.
525 return cookieEnabled;
526 }
527
528 nsCOMPtr<nsICookiePermission> permMgr =
529 do_GetService(NS_COOKIEPERMISSION_CONTRACTID);
530 NS_ENSURE_TRUE(permMgr, cookieEnabled);
531
532 // Pass null for the channel, just like the cookie service does.
533 nsCookieAccess access;
534 nsresult rv = permMgr->CanAccess(codebaseURI, nullptr, &access);
535 NS_ENSURE_SUCCESS(rv, cookieEnabled);
536
537 if (access != nsICookiePermission::ACCESS_DEFAULT) {
538 cookieEnabled = access != nsICookiePermission::ACCESS_DENY;
539 }
540
541 return cookieEnabled;
542 }
543
544 bool
545 Navigator::OnLine()
546 {
547 return !NS_IsOffline();
548 }
549
550 NS_IMETHODIMP
551 Navigator::GetBuildID(nsAString& aBuildID)
552 {
553 if (!nsContentUtils::IsCallerChrome()) {
554 const nsAdoptingString& override =
555 Preferences::GetString("general.buildID.override");
556
557 if (override) {
558 aBuildID = override;
559 return NS_OK;
560 }
561 }
562
563 nsCOMPtr<nsIXULAppInfo> appInfo =
564 do_GetService("@mozilla.org/xre/app-info;1");
565 if (!appInfo) {
566 return NS_ERROR_NOT_IMPLEMENTED;
567 }
568
569 nsAutoCString buildID;
570 nsresult rv = appInfo->GetAppBuildID(buildID);
571 if (NS_FAILED(rv)) {
572 return rv;
573 }
574
575 aBuildID.Truncate();
576 AppendASCIItoUTF16(buildID, aBuildID);
577 return NS_OK;
578 }
579
580 NS_IMETHODIMP
581 Navigator::GetDoNotTrack(nsAString &aResult)
582 {
583 if (sDoNotTrackEnabled) {
584 aResult.AssignLiteral("yes");
585 } else {
586 aResult.AssignLiteral("unspecified");
587 }
588
589 return NS_OK;
590 }
591
592 bool
593 Navigator::JavaEnabled(ErrorResult& aRv)
594 {
595 Telemetry::AutoTimer<Telemetry::CHECK_JAVA_ENABLED> telemetryTimer;
596
597 // Return true if we have a handler for the java mime
598 nsAdoptingString javaMIME = Preferences::GetString("plugin.java.mime");
599 NS_ENSURE_TRUE(!javaMIME.IsEmpty(), false);
600
601 if (!mMimeTypes) {
602 if (!mWindow) {
603 aRv.Throw(NS_ERROR_UNEXPECTED);
604 return false;
605 }
606 mMimeTypes = new nsMimeTypeArray(mWindow);
607 }
608
609 RefreshMIMEArray();
610
611 nsMimeType *mimeType = mMimeTypes->NamedItem(javaMIME);
612
613 return mimeType && mimeType->GetEnabledPlugin();
614 }
615
616 void
617 Navigator::RefreshMIMEArray()
618 {
619 if (mMimeTypes) {
620 mMimeTypes->Refresh();
621 }
622 }
623
624 bool
625 Navigator::HasDesktopNotificationSupport()
626 {
627 return Preferences::GetBool("notification.feature.enabled", false);
628 }
629
630 namespace {
631
632 class VibrateWindowListener : public nsIDOMEventListener
633 {
634 public:
635 VibrateWindowListener(nsIDOMWindow* aWindow, nsIDocument* aDocument)
636 {
637 mWindow = do_GetWeakReference(aWindow);
638 mDocument = do_GetWeakReference(aDocument);
639
640 NS_NAMED_LITERAL_STRING(visibilitychange, "visibilitychange");
641 aDocument->AddSystemEventListener(visibilitychange,
642 this, /* listener */
643 true, /* use capture */
644 false /* wants untrusted */);
645 }
646
647 virtual ~VibrateWindowListener()
648 {
649 }
650
651 void RemoveListener();
652
653 NS_DECL_ISUPPORTS
654 NS_DECL_NSIDOMEVENTLISTENER
655
656 private:
657 nsWeakPtr mWindow;
658 nsWeakPtr mDocument;
659 };
660
661 NS_IMPL_ISUPPORTS(VibrateWindowListener, nsIDOMEventListener)
662
663 StaticRefPtr<VibrateWindowListener> gVibrateWindowListener;
664
665 NS_IMETHODIMP
666 VibrateWindowListener::HandleEvent(nsIDOMEvent* aEvent)
667 {
668 nsCOMPtr<nsIDocument> doc =
669 do_QueryInterface(aEvent->InternalDOMEvent()->GetTarget());
670
671 if (!doc || doc->Hidden()) {
672 // It's important that we call CancelVibrate(), not Vibrate() with an
673 // empty list, because Vibrate() will fail if we're no longer focused, but
674 // CancelVibrate() will succeed, so long as nobody else has started a new
675 // vibration pattern.
676 nsCOMPtr<nsIDOMWindow> window = do_QueryReferent(mWindow);
677 hal::CancelVibrate(window);
678 RemoveListener();
679 gVibrateWindowListener = nullptr;
680 // Careful: The line above might have deleted |this|!
681 }
682
683 return NS_OK;
684 }
685
686 void
687 VibrateWindowListener::RemoveListener()
688 {
689 nsCOMPtr<EventTarget> target = do_QueryReferent(mDocument);
690 if (!target) {
691 return;
692 }
693 NS_NAMED_LITERAL_STRING(visibilitychange, "visibilitychange");
694 target->RemoveSystemEventListener(visibilitychange, this,
695 true /* use capture */);
696 }
697
698 } // anonymous namespace
699
700 void
701 Navigator::AddIdleObserver(MozIdleObserver& aIdleObserver, ErrorResult& aRv)
702 {
703 if (!mWindow) {
704 aRv.Throw(NS_ERROR_UNEXPECTED);
705 return;
706 }
707 CallbackObjectHolder<MozIdleObserver, nsIIdleObserver> holder(&aIdleObserver);
708 nsCOMPtr<nsIIdleObserver> obs = holder.ToXPCOMCallback();
709 if (NS_FAILED(mWindow->RegisterIdleObserver(obs))) {
710 NS_WARNING("Failed to add idle observer.");
711 }
712 }
713
714 void
715 Navigator::RemoveIdleObserver(MozIdleObserver& aIdleObserver, ErrorResult& aRv)
716 {
717 if (!mWindow) {
718 aRv.Throw(NS_ERROR_UNEXPECTED);
719 return;
720 }
721 CallbackObjectHolder<MozIdleObserver, nsIIdleObserver> holder(&aIdleObserver);
722 nsCOMPtr<nsIIdleObserver> obs = holder.ToXPCOMCallback();
723 if (NS_FAILED(mWindow->UnregisterIdleObserver(obs))) {
724 NS_WARNING("Failed to remove idle observer.");
725 }
726 }
727
728 bool
729 Navigator::Vibrate(uint32_t aDuration)
730 {
731 nsAutoTArray<uint32_t, 1> pattern;
732 pattern.AppendElement(aDuration);
733 return Vibrate(pattern);
734 }
735
736 bool
737 Navigator::Vibrate(const nsTArray<uint32_t>& aPattern)
738 {
739 if (!mWindow) {
740 return false;
741 }
742
743 nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc();
744 if (!doc) {
745 return false;
746 }
747
748 if (doc->Hidden()) {
749 // Hidden documents cannot start or stop a vibration.
750 return false;
751 }
752
753 if (aPattern.Length() > sMaxVibrateListLen) {
754 return false;
755 }
756
757 for (size_t i = 0; i < aPattern.Length(); ++i) {
758 if (aPattern[i] > sMaxVibrateMS) {
759 return false;
760 }
761 }
762
763 // The spec says we check sVibratorEnabled after we've done the sanity
764 // checking on the pattern.
765 if (aPattern.IsEmpty() || !sVibratorEnabled) {
766 return true;
767 }
768
769 // Add a listener to cancel the vibration if the document becomes hidden,
770 // and remove the old visibility listener, if there was one.
771
772 if (!gVibrateWindowListener) {
773 // If gVibrateWindowListener is null, this is the first time we've vibrated,
774 // and we need to register a listener to clear gVibrateWindowListener on
775 // shutdown.
776 ClearOnShutdown(&gVibrateWindowListener);
777 }
778 else {
779 gVibrateWindowListener->RemoveListener();
780 }
781 gVibrateWindowListener = new VibrateWindowListener(mWindow, doc);
782
783 hal::Vibrate(aPattern, mWindow);
784 return true;
785 }
786
787 //*****************************************************************************
788 // Pointer Events interface
789 //*****************************************************************************
790
791 uint32_t
792 Navigator::MaxTouchPoints()
793 {
794 nsCOMPtr<nsIWidget> widget = widget::WidgetUtils::DOMWindowToWidget(mWindow);
795
796 NS_ENSURE_TRUE(widget, 0);
797 return widget->GetMaxTouchPoints();
798 }
799
800 //*****************************************************************************
801 // Navigator::nsIDOMClientInformation
802 //*****************************************************************************
803
804 void
805 Navigator::RegisterContentHandler(const nsAString& aMIMEType,
806 const nsAString& aURI,
807 const nsAString& aTitle,
808 ErrorResult& aRv)
809 {
810 if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) {
811 return;
812 }
813
814 nsCOMPtr<nsIWebContentHandlerRegistrar> registrar =
815 do_GetService(NS_WEBCONTENTHANDLERREGISTRAR_CONTRACTID);
816 if (!registrar) {
817 return;
818 }
819
820 aRv = registrar->RegisterContentHandler(aMIMEType, aURI, aTitle,
821 mWindow->GetOuterWindow());
822 }
823
824 void
825 Navigator::RegisterProtocolHandler(const nsAString& aProtocol,
826 const nsAString& aURI,
827 const nsAString& aTitle,
828 ErrorResult& aRv)
829 {
830 if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) {
831 return;
832 }
833
834 nsCOMPtr<nsIWebContentHandlerRegistrar> registrar =
835 do_GetService(NS_WEBCONTENTHANDLERREGISTRAR_CONTRACTID);
836 if (!registrar) {
837 return;
838 }
839
840 aRv = registrar->RegisterProtocolHandler(aProtocol, aURI, aTitle,
841 mWindow->GetOuterWindow());
842 }
843
844 bool
845 Navigator::MozIsLocallyAvailable(const nsAString &aURI,
846 bool aWhenOffline,
847 ErrorResult& aRv)
848 {
849 nsCOMPtr<nsIURI> uri;
850 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURI);
851 if (NS_FAILED(rv)) {
852 aRv.Throw(rv);
853 return false;
854 }
855
856 // This method of checking the cache will only work for http/https urls.
857 bool match;
858 rv = uri->SchemeIs("http", &match);
859 if (NS_FAILED(rv)) {
860 aRv.Throw(rv);
861 return false;
862 }
863
864 if (!match) {
865 rv = uri->SchemeIs("https", &match);
866 if (NS_FAILED(rv)) {
867 aRv.Throw(rv);
868 return false;
869 }
870 if (!match) {
871 aRv.Throw(NS_ERROR_DOM_BAD_URI);
872 return false;
873 }
874 }
875
876 // Same origin check.
877 JSContext *cx = nsContentUtils::GetCurrentJSContext();
878 if (!cx) {
879 aRv.Throw(NS_ERROR_FAILURE);
880 return false;
881 }
882
883 rv = nsContentUtils::GetSecurityManager()->CheckSameOrigin(cx, uri);
884 if (NS_FAILED(rv)) {
885 aRv.Throw(rv);
886 return false;
887 }
888
889 // These load flags cause an error to be thrown if there is no
890 // valid cache entry, and skip the load if there is.
891 // If the cache is busy, assume that it is not yet available rather
892 // than waiting for it to become available.
893 uint32_t loadFlags = nsIChannel::INHIBIT_CACHING |
894 nsICachingChannel::LOAD_NO_NETWORK_IO |
895 nsICachingChannel::LOAD_ONLY_IF_MODIFIED |
896 nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY;
897
898 if (aWhenOffline) {
899 loadFlags |= nsICachingChannel::LOAD_CHECK_OFFLINE_CACHE |
900 nsICachingChannel::LOAD_ONLY_FROM_CACHE |
901 nsIRequest::LOAD_FROM_CACHE;
902 }
903
904 if (!mWindow) {
905 aRv.Throw(NS_ERROR_UNEXPECTED);
906 return false;
907 }
908
909 nsCOMPtr<nsILoadGroup> loadGroup;
910 nsCOMPtr<nsIDocument> doc = mWindow->GetDoc();
911 if (doc) {
912 loadGroup = doc->GetDocumentLoadGroup();
913 }
914
915 nsCOMPtr<nsIChannel> channel;
916 rv = NS_NewChannel(getter_AddRefs(channel), uri,
917 nullptr, loadGroup, nullptr, loadFlags);
918 if (NS_FAILED(rv)) {
919 aRv.Throw(rv);
920 return false;
921 }
922
923 nsCOMPtr<nsIInputStream> stream;
924 rv = channel->Open(getter_AddRefs(stream));
925 if (NS_FAILED(rv)) {
926 aRv.Throw(rv);
927 return false;
928 }
929
930 stream->Close();
931
932 nsresult status;
933 rv = channel->GetStatus(&status);
934 if (NS_FAILED(rv)) {
935 aRv.Throw(rv);
936 return false;
937 }
938
939 if (NS_FAILED(status)) {
940 return false;
941 }
942
943 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
944 bool isAvailable;
945 rv = httpChannel->GetRequestSucceeded(&isAvailable);
946 if (NS_FAILED(rv)) {
947 aRv.Throw(rv);
948 return false;
949 }
950 return isAvailable;
951 }
952
953 nsDOMDeviceStorage*
954 Navigator::GetDeviceStorage(const nsAString& aType, ErrorResult& aRv)
955 {
956 if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) {
957 aRv.Throw(NS_ERROR_FAILURE);
958 return nullptr;
959 }
960
961 nsRefPtr<nsDOMDeviceStorage> storage;
962 nsDOMDeviceStorage::CreateDeviceStorageFor(mWindow, aType,
963 getter_AddRefs(storage));
964
965 if (!storage) {
966 return nullptr;
967 }
968
969 mDeviceStorageStores.AppendElement(storage);
970 return storage;
971 }
972
973 void
974 Navigator::GetDeviceStorages(const nsAString& aType,
975 nsTArray<nsRefPtr<nsDOMDeviceStorage> >& aStores,
976 ErrorResult& aRv)
977 {
978 if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) {
979 aRv.Throw(NS_ERROR_FAILURE);
980 return;
981 }
982
983 nsDOMDeviceStorage::CreateDeviceStoragesFor(mWindow, aType, aStores);
984
985 mDeviceStorageStores.AppendElements(aStores);
986 }
987
988 Geolocation*
989 Navigator::GetGeolocation(ErrorResult& aRv)
990 {
991 if (mGeolocation) {
992 return mGeolocation;
993 }
994
995 if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) {
996 aRv.Throw(NS_ERROR_FAILURE);
997 return nullptr;
998 }
999
1000 mGeolocation = new Geolocation();
1001 if (NS_FAILED(mGeolocation->Init(mWindow->GetOuterWindow()))) {
1002 mGeolocation = nullptr;
1003 aRv.Throw(NS_ERROR_FAILURE);
1004 return nullptr;
1005 }
1006
1007 return mGeolocation;
1008 }
1009
1010 class BeaconStreamListener MOZ_FINAL : public nsIStreamListener
1011 {
1012 public:
1013 BeaconStreamListener() {}
1014
1015 NS_DECL_ISUPPORTS
1016 NS_DECL_NSISTREAMLISTENER
1017 NS_DECL_NSIREQUESTOBSERVER
1018 };
1019
1020 NS_IMPL_ISUPPORTS(BeaconStreamListener,
1021 nsIStreamListener,
1022 nsIRequestObserver)
1023
1024
1025 NS_IMETHODIMP
1026 BeaconStreamListener::OnStartRequest(nsIRequest *aRequest,
1027 nsISupports *aContext)
1028 {
1029 aRequest->Cancel(NS_ERROR_NET_INTERRUPT);
1030 return NS_BINDING_ABORTED;
1031 }
1032
1033 NS_IMETHODIMP
1034 BeaconStreamListener::OnStopRequest(nsIRequest *aRequest,
1035 nsISupports *aContext,
1036 nsresult aStatus)
1037 {
1038 return NS_OK;
1039 }
1040
1041 NS_IMETHODIMP
1042 BeaconStreamListener::OnDataAvailable(nsIRequest *aRequest,
1043 nsISupports *ctxt,
1044 nsIInputStream *inStr,
1045 uint64_t sourceOffset,
1046 uint32_t count)
1047 {
1048 MOZ_ASSERT(false);
1049 return NS_OK;
1050 }
1051
1052 bool
1053 Navigator::SendBeacon(const nsAString& aUrl,
1054 const Nullable<ArrayBufferViewOrBlobOrStringOrFormData>& aData,
1055 ErrorResult& aRv)
1056 {
1057 if (!mWindow) {
1058 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
1059 return false;
1060 }
1061
1062 nsCOMPtr<nsIDocument> doc = mWindow->GetDoc();
1063 if (!doc) {
1064 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
1065 return false;
1066 }
1067
1068 nsIURI* documentURI = doc->GetDocumentURI();
1069 if (!documentURI) {
1070 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
1071 return false;
1072 }
1073
1074 nsCOMPtr<nsIURI> uri;
1075 nsresult rv = nsContentUtils::NewURIWithDocumentCharset(
1076 getter_AddRefs(uri),
1077 aUrl,
1078 doc,
1079 doc->GetDocBaseURI());
1080 if (NS_FAILED(rv)) {
1081 aRv.Throw(NS_ERROR_DOM_URL_MISMATCH_ERR);
1082 return false;
1083 }
1084
1085 // Check whether this is a sane URI to load
1086 // Explicitly disallow things like chrome:, javascript:, and data: URIs
1087 nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
1088 nsCOMPtr<nsIScriptSecurityManager> secMan = nsContentUtils::GetSecurityManager();
1089 uint32_t flags = nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL
1090 & nsIScriptSecurityManager::DISALLOW_SCRIPT;
1091 rv = secMan->CheckLoadURIWithPrincipal(principal,
1092 uri,
1093 flags);
1094 if (NS_FAILED(rv)) {
1095 // Bad URI
1096 aRv.Throw(rv);
1097 return false;
1098 }
1099
1100 // Check whether the CSP allows us to load
1101 int16_t shouldLoad = nsIContentPolicy::ACCEPT;
1102 rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_BEACON,
1103 uri,
1104 principal,
1105 doc,
1106 EmptyCString(), //mime guess
1107 nullptr, //extra
1108 &shouldLoad,
1109 nsContentUtils::GetContentPolicy(),
1110 nsContentUtils::GetSecurityManager());
1111 if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
1112 // Disallowed by content policy
1113 aRv.Throw(NS_ERROR_CONTENT_BLOCKED);
1114 return false;
1115 }
1116
1117 nsCOMPtr<nsIChannel> channel;
1118 nsCOMPtr<nsIChannelPolicy> channelPolicy;
1119 nsCOMPtr<nsIContentSecurityPolicy> csp;
1120 rv = principal->GetCsp(getter_AddRefs(csp));
1121 if (NS_FAILED(rv)) {
1122 aRv.Throw(NS_ERROR_FAILURE);
1123 return false;
1124 }
1125
1126 if (csp) {
1127 channelPolicy = do_CreateInstance(NSCHANNELPOLICY_CONTRACTID);
1128 channelPolicy->SetContentSecurityPolicy(csp);
1129 channelPolicy->SetLoadType(nsIContentPolicy::TYPE_BEACON);
1130 }
1131 rv = NS_NewChannel(getter_AddRefs(channel),
1132 uri,
1133 nullptr,
1134 nullptr,
1135 nullptr,
1136 nsIRequest::LOAD_NORMAL,
1137 channelPolicy);
1138 if (NS_FAILED(rv)) {
1139 aRv.Throw(rv);
1140 return false;
1141 }
1142
1143 nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryInterface(channel);
1144 if (pbChannel) {
1145 nsIDocShell* docShell = mWindow->GetDocShell();
1146 nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
1147 if (loadContext) {
1148 rv = pbChannel->SetPrivate(loadContext->UsePrivateBrowsing());
1149 if (NS_FAILED(rv)) {
1150 NS_WARNING("Setting the privacy status on the beacon channel failed");
1151 }
1152 }
1153 }
1154
1155 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
1156 if (!httpChannel) {
1157 // Beacon spec only supports HTTP requests at this time
1158 aRv.Throw(NS_ERROR_DOM_BAD_URI);
1159 return false;
1160 }
1161 httpChannel->SetReferrer(documentURI);
1162
1163 // Anything that will need to refer to the window during the request
1164 // will need to be done now. For example, detection of whether any
1165 // cookies set by this request are foreign. Note that ThirdPartyUtil
1166 // (nsIThirdPartyUtil.isThirdPartyChannel) does a secondary check between
1167 // the channel URI and the cookie URI even when forceAllowThirdPartyCookie
1168 // is set, so this is safe with regard to redirects.
1169 nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal(do_QueryInterface(channel));
1170 nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = do_GetService(THIRDPARTYUTIL_CONTRACTID);
1171 if (!httpChannelInternal) {
1172 aRv.Throw(NS_ERROR_DOM_BAD_URI);
1173 return false;
1174 }
1175 bool isForeign = true;
1176 thirdPartyUtil->IsThirdPartyWindow(mWindow, uri, &isForeign);
1177 httpChannelInternal->SetForceAllowThirdPartyCookie(!isForeign);
1178
1179 nsCString mimeType;
1180 if (!aData.IsNull()) {
1181 nsCOMPtr<nsIInputStream> in;
1182
1183 if (aData.Value().IsString()) {
1184 nsCString stringData = NS_ConvertUTF16toUTF8(aData.Value().GetAsString());
1185 nsCOMPtr<nsIStringInputStream> strStream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
1186 if (NS_FAILED(rv)) {
1187 aRv.Throw(NS_ERROR_FAILURE);
1188 return false;
1189 }
1190 rv = strStream->SetData(stringData.BeginReading(), stringData.Length());
1191 if (NS_FAILED(rv)) {
1192 aRv.Throw(NS_ERROR_FAILURE);
1193 return false;
1194 }
1195 mimeType.AssignLiteral("text/plain;charset=UTF-8");
1196 in = strStream;
1197
1198 } else if (aData.Value().IsArrayBufferView()) {
1199
1200 nsCOMPtr<nsIStringInputStream> strStream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
1201 if (NS_FAILED(rv)) {
1202 aRv.Throw(NS_ERROR_FAILURE);
1203 return false;
1204 }
1205
1206 ArrayBufferView& view = aData.Value().GetAsArrayBufferView();
1207 view.ComputeLengthAndData();
1208 rv = strStream->SetData(reinterpret_cast<char*>(view.Data()),
1209 view.Length());
1210
1211 if (NS_FAILED(rv)) {
1212 aRv.Throw(NS_ERROR_FAILURE);
1213 return false;
1214 }
1215 mimeType.AssignLiteral("application/octet-stream");
1216 in = strStream;
1217
1218 } else if (aData.Value().IsBlob()) {
1219 nsCOMPtr<nsIDOMBlob> blob = aData.Value().GetAsBlob();
1220 rv = blob->GetInternalStream(getter_AddRefs(in));
1221 if (NS_FAILED(rv)) {
1222 aRv.Throw(NS_ERROR_FAILURE);
1223 return false;
1224 }
1225 nsAutoString type;
1226 rv = blob->GetType(type);
1227 if (NS_FAILED(rv)) {
1228 aRv.Throw(NS_ERROR_FAILURE);
1229 return false;
1230 }
1231 mimeType = NS_ConvertUTF16toUTF8(type);
1232
1233 } else if (aData.Value().IsFormData()) {
1234 nsFormData& form = aData.Value().GetAsFormData();
1235 uint64_t len;
1236 nsAutoCString charset;
1237 form.GetSendInfo(getter_AddRefs(in),
1238 &len,
1239 mimeType,
1240 charset);
1241 } else {
1242 MOZ_ASSERT(false, "switch statements not in sync");
1243 aRv.Throw(NS_ERROR_FAILURE);
1244 return false;
1245 }
1246
1247 nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(channel);
1248 if (!uploadChannel) {
1249 aRv.Throw(NS_ERROR_FAILURE);
1250 return false;
1251 }
1252 uploadChannel->ExplicitSetUploadStream(in, mimeType, -1,
1253 NS_LITERAL_CSTRING("POST"),
1254 false);
1255 } else {
1256 httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
1257 }
1258
1259 nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(channel);
1260 if (p) {
1261 p->SetPriority(nsISupportsPriority::PRIORITY_LOWEST);
1262 }
1263
1264 nsRefPtr<nsCORSListenerProxy> cors = new nsCORSListenerProxy(new BeaconStreamListener(),
1265 principal,
1266 true);
1267
1268 // Start a preflight if cross-origin and content type is not whitelisted
1269 rv = secMan->CheckSameOriginURI(documentURI, uri, false);
1270 bool crossOrigin = NS_FAILED(rv);
1271 nsAutoCString contentType, parsedCharset;
1272 rv = NS_ParseContentType(mimeType, contentType, parsedCharset);
1273 if (crossOrigin &&
1274 contentType.Length() > 0 &&
1275 !contentType.Equals(APPLICATION_WWW_FORM_URLENCODED) &&
1276 !contentType.Equals(MULTIPART_FORM_DATA) &&
1277 !contentType.Equals(TEXT_PLAIN)) {
1278 nsCOMPtr<nsIChannel> preflightChannel;
1279 nsTArray<nsCString> unsafeHeaders;
1280 unsafeHeaders.AppendElement(NS_LITERAL_CSTRING("Content-Type"));
1281 rv = NS_StartCORSPreflight(channel,
1282 cors,
1283 principal,
1284 true,
1285 unsafeHeaders,
1286 getter_AddRefs(preflightChannel));
1287 } else {
1288 rv = channel->AsyncOpen(cors, nullptr);
1289 }
1290 if (NS_FAILED(rv)) {
1291 aRv.Throw(rv);
1292 return false;
1293 }
1294 return true;
1295 }
1296
1297 #ifdef MOZ_MEDIA_NAVIGATOR
1298 void
1299 Navigator::MozGetUserMedia(const MediaStreamConstraints& aConstraints,
1300 NavigatorUserMediaSuccessCallback& aOnSuccess,
1301 NavigatorUserMediaErrorCallback& aOnError,
1302 ErrorResult& aRv)
1303 {
1304 CallbackObjectHolder<NavigatorUserMediaSuccessCallback,
1305 nsIDOMGetUserMediaSuccessCallback> holder1(&aOnSuccess);
1306 nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onsuccess =
1307 holder1.ToXPCOMCallback();
1308
1309 CallbackObjectHolder<NavigatorUserMediaErrorCallback,
1310 nsIDOMGetUserMediaErrorCallback> holder2(&aOnError);
1311 nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onerror = holder2.ToXPCOMCallback();
1312
1313 if (!mWindow || !mWindow->GetOuterWindow() ||
1314 mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) {
1315 aRv.Throw(NS_ERROR_NOT_AVAILABLE);
1316 return;
1317 }
1318
1319 bool privileged = nsContentUtils::IsChromeDoc(mWindow->GetExtantDoc());
1320
1321 MediaManager* manager = MediaManager::Get();
1322 aRv = manager->GetUserMedia(privileged, mWindow, aConstraints,
1323 onsuccess, onerror);
1324 }
1325
1326 void
1327 Navigator::MozGetUserMediaDevices(const MediaStreamConstraints& aConstraints,
1328 MozGetUserMediaDevicesSuccessCallback& aOnSuccess,
1329 NavigatorUserMediaErrorCallback& aOnError,
1330 uint64_t aInnerWindowID,
1331 ErrorResult& aRv)
1332 {
1333 CallbackObjectHolder<MozGetUserMediaDevicesSuccessCallback,
1334 nsIGetUserMediaDevicesSuccessCallback> holder1(&aOnSuccess);
1335 nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> onsuccess =
1336 holder1.ToXPCOMCallback();
1337
1338 CallbackObjectHolder<NavigatorUserMediaErrorCallback,
1339 nsIDOMGetUserMediaErrorCallback> holder2(&aOnError);
1340 nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onerror = holder2.ToXPCOMCallback();
1341
1342 if (!mWindow || !mWindow->GetOuterWindow() ||
1343 mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) {
1344 aRv.Throw(NS_ERROR_NOT_AVAILABLE);
1345 return;
1346 }
1347
1348 MediaManager* manager = MediaManager::Get();
1349 aRv = manager->GetUserMediaDevices(mWindow, aConstraints, onsuccess, onerror,
1350 aInnerWindowID);
1351 }
1352 #endif
1353
1354 DesktopNotificationCenter*
1355 Navigator::GetMozNotification(ErrorResult& aRv)
1356 {
1357 if (mNotification) {
1358 return mNotification;
1359 }
1360
1361 if (!mWindow || !mWindow->GetDocShell()) {
1362 aRv.Throw(NS_ERROR_FAILURE);
1363 return nullptr;
1364 }
1365
1366 mNotification = new DesktopNotificationCenter(mWindow);
1367 return mNotification;
1368 }
1369
1370 #ifdef MOZ_B2G_FM
1371
1372 using mozilla::dom::FMRadio;
1373
1374 FMRadio*
1375 Navigator::GetMozFMRadio(ErrorResult& aRv)
1376 {
1377 if (!mFMRadio) {
1378 if (!mWindow) {
1379 aRv.Throw(NS_ERROR_UNEXPECTED);
1380 return nullptr;
1381 }
1382
1383 NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr);
1384
1385 mFMRadio = new FMRadio();
1386 mFMRadio->Init(mWindow);
1387 }
1388
1389 return mFMRadio;
1390 }
1391
1392 #endif // MOZ_B2G_FM
1393
1394 //*****************************************************************************
1395 // Navigator::nsINavigatorBattery
1396 //*****************************************************************************
1397
1398 battery::BatteryManager*
1399 Navigator::GetBattery(ErrorResult& aRv)
1400 {
1401 if (!mBatteryManager) {
1402 if (!mWindow) {
1403 aRv.Throw(NS_ERROR_UNEXPECTED);
1404 return nullptr;
1405 }
1406 NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr);
1407
1408 mBatteryManager = new battery::BatteryManager(mWindow);
1409 mBatteryManager->Init();
1410 }
1411
1412 return mBatteryManager;
1413 }
1414
1415 already_AddRefed<Promise>
1416 Navigator::GetDataStores(const nsAString& aName, ErrorResult& aRv)
1417 {
1418 if (!mWindow || !mWindow->GetDocShell()) {
1419 aRv.Throw(NS_ERROR_UNEXPECTED);
1420 return nullptr;
1421 }
1422
1423 nsCOMPtr<nsIDataStoreService> service =
1424 do_GetService("@mozilla.org/datastore-service;1");
1425 if (!service) {
1426 aRv.Throw(NS_ERROR_FAILURE);
1427 return nullptr;
1428 }
1429
1430 nsCOMPtr<nsISupports> promise;
1431 aRv = service->GetDataStores(mWindow, aName, getter_AddRefs(promise));
1432
1433 nsRefPtr<Promise> p = static_cast<Promise*>(promise.get());
1434 return p.forget();
1435 }
1436
1437 PowerManager*
1438 Navigator::GetMozPower(ErrorResult& aRv)
1439 {
1440 if (!mPowerManager) {
1441 if (!mWindow) {
1442 aRv.Throw(NS_ERROR_UNEXPECTED);
1443 return nullptr;
1444 }
1445 mPowerManager = PowerManager::CreateInstance(mWindow);
1446 if (!mPowerManager) {
1447 // We failed to get the power manager service?
1448 aRv.Throw(NS_ERROR_UNEXPECTED);
1449 }
1450 }
1451
1452 return mPowerManager;
1453 }
1454
1455 already_AddRefed<WakeLock>
1456 Navigator::RequestWakeLock(const nsAString &aTopic, ErrorResult& aRv)
1457 {
1458 if (!mWindow) {
1459 aRv.Throw(NS_ERROR_UNEXPECTED);
1460 return nullptr;
1461 }
1462
1463 nsRefPtr<power::PowerManagerService> pmService =
1464 power::PowerManagerService::GetInstance();
1465 // Maybe it went away for some reason... Or maybe we're just called
1466 // from our XPCOM method.
1467 if (!pmService) {
1468 aRv.Throw(NS_ERROR_UNEXPECTED);
1469 return nullptr;
1470 }
1471
1472 return pmService->NewWakeLock(aTopic, mWindow, aRv);
1473 }
1474
1475 nsIDOMMozMobileMessageManager*
1476 Navigator::GetMozMobileMessage()
1477 {
1478 if (!mMobileMessageManager) {
1479 // Check that our window has not gone away
1480 NS_ENSURE_TRUE(mWindow, nullptr);
1481 NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr);
1482
1483 mMobileMessageManager = new MobileMessageManager();
1484 mMobileMessageManager->Init(mWindow);
1485 }
1486
1487 return mMobileMessageManager;
1488 }
1489
1490 Telephony*
1491 Navigator::GetMozTelephony(ErrorResult& aRv)
1492 {
1493 if (!mTelephony) {
1494 if (!mWindow) {
1495 aRv.Throw(NS_ERROR_UNEXPECTED);
1496 return nullptr;
1497 }
1498 mTelephony = Telephony::Create(mWindow, aRv);
1499 }
1500
1501 return mTelephony;
1502 }
1503
1504 #ifdef MOZ_B2G_RIL
1505
1506 MobileConnectionArray*
1507 Navigator::GetMozMobileConnections(ErrorResult& aRv)
1508 {
1509 if (!mMobileConnections) {
1510 if (!mWindow) {
1511 aRv.Throw(NS_ERROR_UNEXPECTED);
1512 return nullptr;
1513 }
1514 mMobileConnections = new MobileConnectionArray(mWindow);
1515 }
1516
1517 return mMobileConnections;
1518 }
1519
1520 CellBroadcast*
1521 Navigator::GetMozCellBroadcast(ErrorResult& aRv)
1522 {
1523 if (!mCellBroadcast) {
1524 if (!mWindow) {
1525 aRv.Throw(NS_ERROR_UNEXPECTED);
1526 return nullptr;
1527 }
1528 mCellBroadcast = CellBroadcast::Create(mWindow, aRv);
1529 }
1530
1531 return mCellBroadcast;
1532 }
1533
1534 Voicemail*
1535 Navigator::GetMozVoicemail(ErrorResult& aRv)
1536 {
1537 if (!mVoicemail) {
1538 if (!mWindow) {
1539 aRv.Throw(NS_ERROR_UNEXPECTED);
1540 return nullptr;
1541 }
1542
1543 aRv = NS_NewVoicemail(mWindow, getter_AddRefs(mVoicemail));
1544 if (aRv.Failed()) {
1545 return nullptr;
1546 }
1547 }
1548
1549 return mVoicemail;
1550 }
1551
1552 IccManager*
1553 Navigator::GetMozIccManager(ErrorResult& aRv)
1554 {
1555 if (!mIccManager) {
1556 if (!mWindow) {
1557 aRv.Throw(NS_ERROR_UNEXPECTED);
1558 return nullptr;
1559 }
1560 NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr);
1561
1562 mIccManager = new IccManager(mWindow);
1563 }
1564
1565 return mIccManager;
1566 }
1567
1568 #endif // MOZ_B2G_RIL
1569
1570 #ifdef MOZ_GAMEPAD
1571 void
1572 Navigator::GetGamepads(nsTArray<nsRefPtr<Gamepad> >& aGamepads,
1573 ErrorResult& aRv)
1574 {
1575 if (!mWindow) {
1576 aRv.Throw(NS_ERROR_UNEXPECTED);
1577 return;
1578 }
1579 NS_ENSURE_TRUE_VOID(mWindow->GetDocShell());
1580 nsGlobalWindow* win = static_cast<nsGlobalWindow*>(mWindow.get());
1581 win->SetHasGamepadEventListener(true);
1582 win->GetGamepads(aGamepads);
1583 }
1584 #endif
1585
1586 //*****************************************************************************
1587 // Navigator::nsIMozNavigatorNetwork
1588 //*****************************************************************************
1589
1590 NS_IMETHODIMP
1591 Navigator::GetProperties(nsINetworkProperties** aProperties)
1592 {
1593 ErrorResult rv;
1594 NS_IF_ADDREF(*aProperties = GetConnection(rv));
1595 return NS_OK;
1596 }
1597
1598 network::Connection*
1599 Navigator::GetConnection(ErrorResult& aRv)
1600 {
1601 if (!mConnection) {
1602 if (!mWindow) {
1603 aRv.Throw(NS_ERROR_UNEXPECTED);
1604 return nullptr;
1605 }
1606 mConnection = new network::Connection();
1607 mConnection->Init(mWindow);
1608 }
1609
1610 return mConnection;
1611 }
1612
1613 #ifdef MOZ_B2G_BT
1614 bluetooth::BluetoothManager*
1615 Navigator::GetMozBluetooth(ErrorResult& aRv)
1616 {
1617 if (!mBluetooth) {
1618 if (!mWindow) {
1619 aRv.Throw(NS_ERROR_UNEXPECTED);
1620 return nullptr;
1621 }
1622 mBluetooth = bluetooth::BluetoothManager::Create(mWindow);
1623 }
1624
1625 return mBluetooth;
1626 }
1627 #endif //MOZ_B2G_BT
1628
1629 nsresult
1630 Navigator::EnsureMessagesManager()
1631 {
1632 if (mMessagesManager) {
1633 return NS_OK;
1634 }
1635
1636 NS_ENSURE_STATE(mWindow);
1637
1638 nsresult rv;
1639 nsCOMPtr<nsIDOMNavigatorSystemMessages> messageManager =
1640 do_CreateInstance("@mozilla.org/system-message-manager;1", &rv);
1641
1642 nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi =
1643 do_QueryInterface(messageManager);
1644 NS_ENSURE_TRUE(gpi, NS_ERROR_FAILURE);
1645
1646 // We don't do anything with the return value.
1647 AutoJSContext cx;
1648 JS::Rooted<JS::Value> prop_val(cx);
1649 rv = gpi->Init(mWindow, &prop_val);
1650 NS_ENSURE_SUCCESS(rv, rv);
1651
1652 mMessagesManager = messageManager.forget();
1653
1654 return NS_OK;
1655 }
1656
1657 bool
1658 Navigator::MozHasPendingMessage(const nsAString& aType, ErrorResult& aRv)
1659 {
1660 // The WebIDL binding is responsible for the pref check here.
1661 nsresult rv = EnsureMessagesManager();
1662 if (NS_FAILED(rv)) {
1663 aRv.Throw(rv);
1664 return false;
1665 }
1666
1667 bool result = false;
1668 rv = mMessagesManager->MozHasPendingMessage(aType, &result);
1669 if (NS_FAILED(rv)) {
1670 aRv.Throw(rv);
1671 return false;
1672 }
1673 return result;
1674 }
1675
1676 void
1677 Navigator::MozSetMessageHandler(const nsAString& aType,
1678 systemMessageCallback* aCallback,
1679 ErrorResult& aRv)
1680 {
1681 // The WebIDL binding is responsible for the pref check here.
1682 nsresult rv = EnsureMessagesManager();
1683 if (NS_FAILED(rv)) {
1684 aRv.Throw(rv);
1685 return;
1686 }
1687
1688 CallbackObjectHolder<systemMessageCallback, nsIDOMSystemMessageCallback>
1689 holder(aCallback);
1690 nsCOMPtr<nsIDOMSystemMessageCallback> callback = holder.ToXPCOMCallback();
1691
1692 rv = mMessagesManager->MozSetMessageHandler(aType, callback);
1693 if (NS_FAILED(rv)) {
1694 aRv.Throw(rv);
1695 }
1696 }
1697
1698 #ifdef MOZ_TIME_MANAGER
1699 time::TimeManager*
1700 Navigator::GetMozTime(ErrorResult& aRv)
1701 {
1702 if (!mWindow) {
1703 aRv.Throw(NS_ERROR_UNEXPECTED);
1704 return nullptr;
1705 }
1706
1707 if (!mTimeManager) {
1708 mTimeManager = new time::TimeManager(mWindow);
1709 }
1710
1711 return mTimeManager;
1712 }
1713 #endif
1714
1715 nsDOMCameraManager*
1716 Navigator::GetMozCameras(ErrorResult& aRv)
1717 {
1718 if (!mCameraManager) {
1719 if (!mWindow ||
1720 !mWindow->GetOuterWindow() ||
1721 mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) {
1722 aRv.Throw(NS_ERROR_NOT_AVAILABLE);
1723 return nullptr;
1724 }
1725
1726 mCameraManager = nsDOMCameraManager::CreateInstance(mWindow);
1727 }
1728
1729 return mCameraManager;
1730 }
1731
1732 size_t
1733 Navigator::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
1734 {
1735 size_t n = aMallocSizeOf(this);
1736
1737 // TODO: add SizeOfIncludingThis() to nsMimeTypeArray, bug 674113.
1738 // TODO: add SizeOfIncludingThis() to nsPluginArray, bug 674114.
1739 // TODO: add SizeOfIncludingThis() to Geolocation, bug 674115.
1740 // TODO: add SizeOfIncludingThis() to DesktopNotificationCenter, bug 674116.
1741
1742 return n;
1743 }
1744
1745 void
1746 Navigator::SetWindow(nsPIDOMWindow *aInnerWindow)
1747 {
1748 NS_ASSERTION(aInnerWindow->IsInnerWindow(),
1749 "Navigator must get an inner window!");
1750 mWindow = aInnerWindow;
1751 }
1752
1753 void
1754 Navigator::OnNavigation()
1755 {
1756 if (!mWindow) {
1757 return;
1758 }
1759
1760 #ifdef MOZ_MEDIA_NAVIGATOR
1761 // Inform MediaManager in case there are live streams or pending callbacks.
1762 MediaManager *manager = MediaManager::Get();
1763 if (manager) {
1764 manager->OnNavigation(mWindow->WindowID());
1765 }
1766 #endif
1767 if (mCameraManager) {
1768 mCameraManager->OnNavigation(mWindow->WindowID());
1769 }
1770 }
1771
1772 bool
1773 Navigator::CheckPermission(const char* type)
1774 {
1775 return CheckPermission(mWindow, type);
1776 }
1777
1778 /* static */
1779 bool
1780 Navigator::CheckPermission(nsPIDOMWindow* aWindow, const char* aType)
1781 {
1782 if (!aWindow) {
1783 return false;
1784 }
1785
1786 nsCOMPtr<nsIPermissionManager> permMgr =
1787 do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
1788 NS_ENSURE_TRUE(permMgr, false);
1789
1790 uint32_t permission = nsIPermissionManager::DENY_ACTION;
1791 permMgr->TestPermissionFromWindow(aWindow, aType, &permission);
1792 return permission == nsIPermissionManager::ALLOW_ACTION;
1793 }
1794
1795 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
1796 system::AudioChannelManager*
1797 Navigator::GetMozAudioChannelManager(ErrorResult& aRv)
1798 {
1799 if (!mAudioChannelManager) {
1800 if (!mWindow) {
1801 aRv.Throw(NS_ERROR_UNEXPECTED);
1802 return nullptr;
1803 }
1804 mAudioChannelManager = new system::AudioChannelManager();
1805 mAudioChannelManager->Init(mWindow);
1806 }
1807
1808 return mAudioChannelManager;
1809 }
1810 #endif
1811
1812 bool
1813 Navigator::DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
1814 JS::Handle<jsid> aId,
1815 JS::MutableHandle<JSPropertyDescriptor> aDesc)
1816 {
1817 if (!JSID_IS_STRING(aId)) {
1818 return true;
1819 }
1820
1821 nsScriptNameSpaceManager* nameSpaceManager = GetNameSpaceManager();
1822 if (!nameSpaceManager) {
1823 return Throw(aCx, NS_ERROR_NOT_INITIALIZED);
1824 }
1825
1826 nsDependentJSString name(aId);
1827
1828 const nsGlobalNameStruct* name_struct =
1829 nameSpaceManager->LookupNavigatorName(name);
1830 if (!name_struct) {
1831 return true;
1832 }
1833
1834 JS::Rooted<JSObject*> naviObj(aCx,
1835 js::CheckedUnwrap(aObject,
1836 /* stopAtOuter = */ false));
1837 if (!naviObj) {
1838 return Throw(aCx, NS_ERROR_DOM_SECURITY_ERR);
1839 }
1840
1841 if (name_struct->mType == nsGlobalNameStruct::eTypeNewDOMBinding) {
1842 ConstructNavigatorProperty construct = name_struct->mConstructNavigatorProperty;
1843 MOZ_ASSERT(construct);
1844
1845 JS::Rooted<JSObject*> domObject(aCx);
1846 {
1847 // Make sure to do the creation of our object in the compartment
1848 // of naviObj, especially since we plan to cache that object.
1849 JSAutoCompartment ac(aCx, naviObj);
1850
1851 // Check whether our constructor is enabled after we unwrap Xrays, since
1852 // we don't want to define an interface on the Xray if it's disabled in
1853 // the target global, even if it's enabled in the Xray's global.
1854 if (name_struct->mConstructorEnabled &&
1855 !(*name_struct->mConstructorEnabled)(aCx, naviObj)) {
1856 return true;
1857 }
1858
1859 if (name.EqualsLiteral("mozSettings")) {
1860 bool hasPermission = CheckPermission("settings-read") ||
1861 CheckPermission("settings-write");
1862 if (!hasPermission) {
1863 FillPropertyDescriptor(aDesc, aObject, JS::NullValue(), false);
1864 return true;
1865 }
1866 }
1867
1868 if (name.EqualsLiteral("mozDownloadManager")) {
1869 if (!CheckPermission("downloads")) {
1870 FillPropertyDescriptor(aDesc, aObject, JS::NullValue(), false);
1871 return true;
1872 }
1873 }
1874
1875 nsISupports* existingObject = mCachedResolveResults.GetWeak(name);
1876 if (existingObject) {
1877 // We know all of our WebIDL objects here are wrappercached, so just go
1878 // ahead and WrapObject() them. We can't use WrapNewBindingObject,
1879 // because we don't have the concrete type.
1880 JS::Rooted<JS::Value> wrapped(aCx);
1881 if (!dom::WrapObject(aCx, existingObject, &wrapped)) {
1882 return false;
1883 }
1884 domObject = &wrapped.toObject();
1885 } else {
1886 domObject = construct(aCx, naviObj);
1887 if (!domObject) {
1888 return Throw(aCx, NS_ERROR_FAILURE);
1889 }
1890
1891 // Store the value in our cache
1892 nsISupports* native = UnwrapDOMObjectToISupports(domObject);
1893 MOZ_ASSERT(native);
1894 mCachedResolveResults.Put(name, native);
1895 }
1896 }
1897
1898 if (!JS_WrapObject(aCx, &domObject)) {
1899 return false;
1900 }
1901
1902 FillPropertyDescriptor(aDesc, aObject, JS::ObjectValue(*domObject), false);
1903 return true;
1904 }
1905
1906 NS_ASSERTION(name_struct->mType == nsGlobalNameStruct::eTypeNavigatorProperty,
1907 "unexpected type");
1908
1909 nsresult rv = NS_OK;
1910
1911 nsCOMPtr<nsISupports> native;
1912 bool hadCachedNative = mCachedResolveResults.Get(name, getter_AddRefs(native));
1913 bool okToUseNative;
1914 JS::Rooted<JS::Value> prop_val(aCx);
1915 if (hadCachedNative) {
1916 okToUseNative = true;
1917 } else {
1918 native = do_CreateInstance(name_struct->mCID, &rv);
1919 if (NS_FAILED(rv)) {
1920 return Throw(aCx, rv);
1921 }
1922
1923 nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi(do_QueryInterface(native));
1924
1925 if (gpi) {
1926 if (!mWindow) {
1927 return Throw(aCx, NS_ERROR_UNEXPECTED);
1928 }
1929
1930 rv = gpi->Init(mWindow, &prop_val);
1931 if (NS_FAILED(rv)) {
1932 return Throw(aCx, rv);
1933 }
1934 }
1935
1936 okToUseNative = !prop_val.isObjectOrNull();
1937 }
1938
1939 if (okToUseNative) {
1940 // Make sure to do the creation of our object in the compartment
1941 // of naviObj, especially since we plan to cache that object.
1942 JSAutoCompartment ac(aCx, naviObj);
1943
1944 rv = nsContentUtils::WrapNative(aCx, native, &prop_val);
1945
1946 if (NS_FAILED(rv)) {
1947 return Throw(aCx, rv);
1948 }
1949
1950 // Now that we know we managed to wrap this thing properly, go ahead and
1951 // cache it as needed.
1952 if (!hadCachedNative) {
1953 mCachedResolveResults.Put(name, native);
1954 }
1955 }
1956
1957 if (!JS_WrapValue(aCx, &prop_val)) {
1958 return Throw(aCx, NS_ERROR_UNEXPECTED);
1959 }
1960
1961 FillPropertyDescriptor(aDesc, aObject, prop_val, false);
1962 return true;
1963 }
1964
1965 struct NavigatorNameEnumeratorClosure
1966 {
1967 NavigatorNameEnumeratorClosure(JSContext* aCx, JSObject* aWrapper,
1968 nsTArray<nsString>& aNames)
1969 : mCx(aCx),
1970 mWrapper(aCx, aWrapper),
1971 mNames(aNames)
1972 {
1973 }
1974
1975 JSContext* mCx;
1976 JS::Rooted<JSObject*> mWrapper;
1977 nsTArray<nsString>& mNames;
1978 };
1979
1980 static PLDHashOperator
1981 SaveNavigatorName(const nsAString& aName,
1982 const nsGlobalNameStruct& aNameStruct,
1983 void* aClosure)
1984 {
1985 NavigatorNameEnumeratorClosure* closure =
1986 static_cast<NavigatorNameEnumeratorClosure*>(aClosure);
1987 if (!aNameStruct.mConstructorEnabled ||
1988 aNameStruct.mConstructorEnabled(closure->mCx, closure->mWrapper)) {
1989 closure->mNames.AppendElement(aName);
1990 }
1991 return PL_DHASH_NEXT;
1992 }
1993
1994 void
1995 Navigator::GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames,
1996 ErrorResult& aRv)
1997 {
1998 nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
1999 if (!nameSpaceManager) {
2000 NS_ERROR("Can't get namespace manager.");
2001 aRv.Throw(NS_ERROR_UNEXPECTED);
2002 return;
2003 }
2004
2005 NavigatorNameEnumeratorClosure closure(aCx, GetWrapper(), aNames);
2006 nameSpaceManager->EnumerateNavigatorNames(SaveNavigatorName, &closure);
2007 }
2008
2009 JSObject*
2010 Navigator::WrapObject(JSContext* cx)
2011 {
2012 return NavigatorBinding::Wrap(cx, this);
2013 }
2014
2015 /* static */
2016 bool
2017 Navigator::HasBatterySupport(JSContext* /* unused*/, JSObject* /*unused */)
2018 {
2019 return battery::BatteryManager::HasSupport();
2020 }
2021
2022 /* static */
2023 bool
2024 Navigator::HasPowerSupport(JSContext* /* unused */, JSObject* aGlobal)
2025 {
2026 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2027 return win && PowerManager::CheckPermission(win);
2028 }
2029
2030 /* static */
2031 bool
2032 Navigator::HasPhoneNumberSupport(JSContext* /* unused */, JSObject* aGlobal)
2033 {
2034 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2035 return CheckPermission(win, "phonenumberservice");
2036 }
2037
2038 /* static */
2039 bool
2040 Navigator::HasIdleSupport(JSContext* /* unused */, JSObject* aGlobal)
2041 {
2042 if (!nsContentUtils::IsIdleObserverAPIEnabled()) {
2043 return false;
2044 }
2045
2046 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2047 return CheckPermission(win, "idle");
2048 }
2049
2050 /* static */
2051 bool
2052 Navigator::HasWakeLockSupport(JSContext* /* unused*/, JSObject* /*unused */)
2053 {
2054 nsCOMPtr<nsIPowerManagerService> pmService =
2055 do_GetService(POWERMANAGERSERVICE_CONTRACTID);
2056 // No service means no wake lock support
2057 return !!pmService;
2058 }
2059
2060 /* static */
2061 bool
2062 Navigator::HasMobileMessageSupport(JSContext* /* unused */, JSObject* aGlobal)
2063 {
2064 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2065
2066 #ifndef MOZ_WEBSMS_BACKEND
2067 return false;
2068 #endif
2069
2070 // First of all, the general pref has to be turned on.
2071 bool enabled = false;
2072 Preferences::GetBool("dom.sms.enabled", &enabled);
2073 if (!enabled) {
2074 return false;
2075 }
2076
2077 NS_ENSURE_TRUE(win, false);
2078 NS_ENSURE_TRUE(win->GetDocShell(), false);
2079
2080 if (!CheckPermission(win, "sms")) {
2081 return false;
2082 }
2083
2084 return true;
2085 }
2086
2087 /* static */
2088 bool
2089 Navigator::HasTelephonySupport(JSContext* cx, JSObject* aGlobal)
2090 {
2091 JS::Rooted<JSObject*> global(cx, aGlobal);
2092
2093 // First of all, the general pref has to be turned on.
2094 bool enabled = false;
2095 Preferences::GetBool("dom.telephony.enabled", &enabled);
2096 if (!enabled) {
2097 return false;
2098 }
2099
2100 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(global);
2101 return win && CheckPermission(win, "telephony");
2102 }
2103
2104 /* static */
2105 bool
2106 Navigator::HasCameraSupport(JSContext* /* unused */, JSObject* aGlobal)
2107 {
2108 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2109 return win && nsDOMCameraManager::CheckPermission(win);
2110 }
2111
2112 #ifdef MOZ_B2G_RIL
2113 /* static */
2114 bool
2115 Navigator::HasMobileConnectionSupport(JSContext* /* unused */,
2116 JSObject* aGlobal)
2117 {
2118 // First of all, the general pref has to be turned on.
2119 bool enabled = false;
2120 Preferences::GetBool("dom.mobileconnection.enabled", &enabled);
2121 NS_ENSURE_TRUE(enabled, false);
2122
2123 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2124 return win && (CheckPermission(win, "mobileconnection") ||
2125 CheckPermission(win, "mobilenetwork"));
2126 }
2127
2128 /* static */
2129 bool
2130 Navigator::HasCellBroadcastSupport(JSContext* /* unused */,
2131 JSObject* aGlobal)
2132 {
2133 // First of all, the general pref has to be turned on.
2134 bool enabled = false;
2135 Preferences::GetBool("dom.cellbroadcast.enabled", &enabled);
2136 NS_ENSURE_TRUE(enabled, false);
2137
2138 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2139 return win && CheckPermission(win, "cellbroadcast");
2140 }
2141
2142 /* static */
2143 bool
2144 Navigator::HasVoicemailSupport(JSContext* /* unused */,
2145 JSObject* aGlobal)
2146 {
2147 // First of all, the general pref has to be turned on.
2148 bool enabled = false;
2149 Preferences::GetBool("dom.voicemail.enabled", &enabled);
2150 NS_ENSURE_TRUE(enabled, false);
2151
2152 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2153 return win && CheckPermission(win, "voicemail");
2154 }
2155
2156 /* static */
2157 bool
2158 Navigator::HasIccManagerSupport(JSContext* /* unused */,
2159 JSObject* aGlobal)
2160 {
2161 // First of all, the general pref has to be turned on.
2162 bool enabled = false;
2163 Preferences::GetBool("dom.icc.enabled", &enabled);
2164 NS_ENSURE_TRUE(enabled, false);
2165
2166 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2167 return win && CheckPermission(win, "mobileconnection");
2168 }
2169 #endif // MOZ_B2G_RIL
2170
2171 /* static */
2172 bool
2173 Navigator::HasWifiManagerSupport(JSContext* /* unused */,
2174 JSObject* aGlobal)
2175 {
2176 // On XBL scope, the global object is NOT |window|. So we have
2177 // to use nsContentUtils::GetObjectPrincipal to get the principal
2178 // and test directly with permission manager.
2179
2180 nsIPrincipal* principal = nsContentUtils::GetObjectPrincipal(aGlobal);
2181
2182 nsCOMPtr<nsIPermissionManager> permMgr =
2183 do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
2184 NS_ENSURE_TRUE(permMgr, false);
2185
2186 uint32_t permission = nsIPermissionManager::DENY_ACTION;
2187 permMgr->TestPermissionFromPrincipal(principal, "wifi-manage", &permission);
2188 return nsIPermissionManager::ALLOW_ACTION == permission;
2189 }
2190
2191 #ifdef MOZ_B2G_BT
2192 /* static */
2193 bool
2194 Navigator::HasBluetoothSupport(JSContext* /* unused */, JSObject* aGlobal)
2195 {
2196 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2197 return win && bluetooth::BluetoothManager::CheckPermission(win);
2198 }
2199 #endif // MOZ_B2G_BT
2200
2201 #ifdef MOZ_B2G_FM
2202 /* static */
2203 bool
2204 Navigator::HasFMRadioSupport(JSContext* /* unused */, JSObject* aGlobal)
2205 {
2206 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2207 return win && CheckPermission(win, "fmradio");
2208 }
2209 #endif // MOZ_B2G_FM
2210
2211 #ifdef MOZ_NFC
2212 /* static */
2213 bool
2214 Navigator::HasNfcSupport(JSContext* /* unused */, JSObject* aGlobal)
2215 {
2216 // Do not support NFC if NFC content helper does not exist.
2217 nsCOMPtr<nsISupports> contentHelper = do_GetService("@mozilla.org/nfc/content-helper;1");
2218 if (!contentHelper) {
2219 return false;
2220 }
2221
2222 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2223 return win && (CheckPermission(win, "nfc-read") ||
2224 CheckPermission(win, "nfc-write"));
2225 }
2226
2227 /* static */
2228 bool
2229 Navigator::HasNfcPeerSupport(JSContext* /* unused */, JSObject* aGlobal)
2230 {
2231 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2232 return win && CheckPermission(win, "nfc-write");
2233 }
2234
2235 /* static */
2236 bool
2237 Navigator::HasNfcManagerSupport(JSContext* /* unused */, JSObject* aGlobal)
2238 {
2239 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2240 return win && CheckPermission(win, "nfc-manager");
2241 }
2242 #endif // MOZ_NFC
2243
2244 #ifdef MOZ_TIME_MANAGER
2245 /* static */
2246 bool
2247 Navigator::HasTimeSupport(JSContext* /* unused */, JSObject* aGlobal)
2248 {
2249 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2250 return win && CheckPermission(win, "time");
2251 }
2252 #endif // MOZ_TIME_MANAGER
2253
2254 #ifdef MOZ_MEDIA_NAVIGATOR
2255 /* static */
2256 bool
2257 Navigator::HasUserMediaSupport(JSContext* /* unused */,
2258 JSObject* /* unused */)
2259 {
2260 // Make enabling peerconnection enable getUserMedia() as well
2261 return Preferences::GetBool("media.navigator.enabled", false) ||
2262 Preferences::GetBool("media.peerconnection.enabled", false);
2263 }
2264 #endif // MOZ_MEDIA_NAVIGATOR
2265
2266 /* static */
2267 bool
2268 Navigator::HasPushNotificationsSupport(JSContext* /* unused */,
2269 JSObject* aGlobal)
2270 {
2271 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2272 return Preferences::GetBool("services.push.enabled", false) &&
2273 win && CheckPermission(win, "push");
2274 }
2275
2276 /* static */
2277 bool
2278 Navigator::HasInputMethodSupport(JSContext* /* unused */,
2279 JSObject* aGlobal)
2280 {
2281 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2282 if (!win || !Preferences::GetBool("dom.mozInputMethod.enabled", false)) {
2283 return false;
2284 }
2285
2286 if (Preferences::GetBool("dom.mozInputMethod.testing", false)) {
2287 return true;
2288 }
2289
2290 return CheckPermission(win, "input") ||
2291 CheckPermission(win, "input-manage");
2292 }
2293
2294 /* static */
2295 bool
2296 Navigator::HasDataStoreSupport(JSContext* cx, JSObject* aGlobal)
2297 {
2298 JS::Rooted<JSObject*> global(cx, aGlobal);
2299
2300 // First of all, the general pref has to be turned on.
2301 bool enabled = false;
2302 Preferences::GetBool("dom.datastore.enabled", &enabled);
2303 if (!enabled) {
2304 return false;
2305 }
2306
2307 // Just for testing, we can enable DataStore for any kind of app.
2308 if (Preferences::GetBool("dom.testing.datastore_enabled_for_hosted_apps", false)) {
2309 return true;
2310 }
2311
2312 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(global);
2313 if (!win) {
2314 return false;
2315 }
2316
2317 nsIDocument* doc = win->GetExtantDoc();
2318 if (!doc || !doc->NodePrincipal()) {
2319 return false;
2320 }
2321
2322 uint16_t status;
2323 if (NS_FAILED(doc->NodePrincipal()->GetAppStatus(&status))) {
2324 return false;
2325 }
2326
2327 return status == nsIPrincipal::APP_STATUS_CERTIFIED;
2328 }
2329
2330 /* static */
2331 bool
2332 Navigator::HasDownloadsSupport(JSContext* aCx, JSObject* aGlobal)
2333 {
2334 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2335
2336 return win &&
2337 CheckPermission(win, "downloads") &&
2338 Preferences::GetBool("dom.mozDownloads.enabled");
2339 }
2340
2341 /* static */
2342 bool
2343 Navigator::HasPermissionSettingsSupport(JSContext* /* unused */, JSObject* aGlobal)
2344 {
2345 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2346 return CheckPermission(win, "permissions");
2347 }
2348
2349 /* static */
2350 already_AddRefed<nsPIDOMWindow>
2351 Navigator::GetWindowFromGlobal(JSObject* aGlobal)
2352 {
2353 nsCOMPtr<nsPIDOMWindow> win =
2354 do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(aGlobal));
2355 MOZ_ASSERT(!win || win->IsInnerWindow());
2356 return win.forget();
2357 }
2358
2359 nsresult
2360 Navigator::GetPlatform(nsAString& aPlatform, bool aUsePrefOverriddenValue)
2361 {
2362 MOZ_ASSERT(NS_IsMainThread());
2363
2364 if (aUsePrefOverriddenValue && !nsContentUtils::IsCallerChrome()) {
2365 const nsAdoptingString& override =
2366 mozilla::Preferences::GetString("general.platform.override");
2367
2368 if (override) {
2369 aPlatform = override;
2370 return NS_OK;
2371 }
2372 }
2373
2374 nsresult rv;
2375
2376 nsCOMPtr<nsIHttpProtocolHandler>
2377 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
2378 NS_ENSURE_SUCCESS(rv, rv);
2379
2380 // Sorry for the #if platform ugliness, but Communicator is likewise
2381 // hardcoded and we are seeking backward compatibility here (bug 47080).
2382 #if defined(_WIN64)
2383 aPlatform.AssignLiteral("Win64");
2384 #elif defined(WIN32)
2385 aPlatform.AssignLiteral("Win32");
2386 #elif defined(XP_MACOSX) && defined(__ppc__)
2387 aPlatform.AssignLiteral("MacPPC");
2388 #elif defined(XP_MACOSX) && defined(__i386__)
2389 aPlatform.AssignLiteral("MacIntel");
2390 #elif defined(XP_MACOSX) && defined(__x86_64__)
2391 aPlatform.AssignLiteral("MacIntel");
2392 #else
2393 // XXX Communicator uses compiled-in build-time string defines
2394 // to indicate the platform it was compiled *for*, not what it is
2395 // currently running *on* which is what this does.
2396 nsAutoCString plat;
2397 rv = service->GetOscpu(plat);
2398 CopyASCIItoUTF16(plat, aPlatform);
2399 #endif
2400
2401 return rv;
2402 }
2403
2404 /* static */ nsresult
2405 Navigator::GetAppVersion(nsAString& aAppVersion, bool aUsePrefOverriddenValue)
2406 {
2407 if (aUsePrefOverriddenValue && !nsContentUtils::IsCallerChrome()) {
2408 const nsAdoptingString& override =
2409 mozilla::Preferences::GetString("general.appversion.override");
2410
2411 if (override) {
2412 aAppVersion = override;
2413 return NS_OK;
2414 }
2415 }
2416
2417 nsresult rv;
2418
2419 nsCOMPtr<nsIHttpProtocolHandler>
2420 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
2421 NS_ENSURE_SUCCESS(rv, rv);
2422
2423 nsAutoCString str;
2424 rv = service->GetAppVersion(str);
2425 CopyASCIItoUTF16(str, aAppVersion);
2426 NS_ENSURE_SUCCESS(rv, rv);
2427
2428 aAppVersion.AppendLiteral(" (");
2429
2430 rv = service->GetPlatform(str);
2431 NS_ENSURE_SUCCESS(rv, rv);
2432
2433 AppendASCIItoUTF16(str, aAppVersion);
2434 aAppVersion.Append(char16_t(')'));
2435
2436 return rv;
2437 }
2438
2439 /* static */ void
2440 Navigator::AppName(nsAString& aAppName, bool aUsePrefOverriddenValue)
2441 {
2442 if (aUsePrefOverriddenValue && !nsContentUtils::IsCallerChrome()) {
2443 const nsAdoptingString& override =
2444 mozilla::Preferences::GetString("general.appname.override");
2445
2446 if (override) {
2447 aAppName = override;
2448 return;
2449 }
2450 }
2451
2452 aAppName.AssignLiteral("Netscape");
2453 }
2454
2455 } // namespace dom
2456 } // namespace mozilla
2457
2458 nsresult
2459 NS_GetNavigatorUserAgent(nsAString& aUserAgent)
2460 {
2461 nsresult rv;
2462
2463 nsCOMPtr<nsIHttpProtocolHandler>
2464 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
2465 NS_ENSURE_SUCCESS(rv, rv);
2466
2467 nsAutoCString ua;
2468 rv = service->GetUserAgent(ua);
2469 CopyASCIItoUTF16(ua, aUserAgent);
2470
2471 return rv;
2472 }

mercurial