Bumping manifests a=b2g-bump
[gecko.git] / dom / base / Navigator.cpp
blob3db29fac7a117760baa9eb5bc6e73deca7173835
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/. */
7 // Needs to be first.
8 #include "base/basictypes.h"
10 #include "Navigator.h"
11 #include "nsIXULAppInfo.h"
12 #include "nsPluginArray.h"
13 #include "nsMimeTypeArray.h"
14 #include "mozilla/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/ServiceWorkerContainer.h"
38 #include "mozilla/dom/Telephony.h"
39 #include "mozilla/Hal.h"
40 #include "nsISiteSpecificUserAgent.h"
41 #include "mozilla/ClearOnShutdown.h"
42 #include "mozilla/StaticPtr.h"
43 #include "Connection.h"
44 #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
45 #include "nsGlobalWindow.h"
46 #ifdef MOZ_B2G
47 #include "nsIMobileIdentityService.h"
48 #endif
49 #ifdef MOZ_B2G_RIL
50 #include "mozilla/dom/IccManager.h"
51 #include "mozilla/dom/CellBroadcast.h"
52 #include "mozilla/dom/MobileConnectionArray.h"
53 #include "mozilla/dom/Voicemail.h"
54 #endif
55 #include "nsIIdleObserver.h"
56 #include "nsIPermissionManager.h"
57 #include "nsMimeTypes.h"
58 #include "nsNetUtil.h"
59 #include "nsIHttpChannel.h"
60 #include "nsIHttpChannelInternal.h"
61 #include "TimeManager.h"
62 #include "DeviceStorage.h"
63 #include "nsIDOMNavigatorSystemMessages.h"
64 #include "nsStreamUtils.h"
65 #include "nsIAppsService.h"
66 #include "mozIApplication.h"
67 #include "WidgetUtils.h"
68 #include "mozIThirdPartyUtil.h"
69 #include "nsChannelPolicy.h"
71 #ifdef MOZ_MEDIA_NAVIGATOR
72 #include "MediaManager.h"
73 #endif
74 #ifdef MOZ_B2G_BT
75 #include "BluetoothManager.h"
76 #endif
77 #include "DOMCameraManager.h"
79 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
80 #include "AudioChannelManager.h"
81 #endif
83 #ifdef MOZ_B2G_FM
84 #include "mozilla/dom/FMRadio.h"
85 #endif
87 #include "nsIDOMGlobalPropertyInitializer.h"
88 #include "mozilla/dom/DataStoreService.h"
89 #include "nsJSUtils.h"
91 #include "nsScriptNameSpaceManager.h"
93 #include "mozilla/dom/NavigatorBinding.h"
94 #include "mozilla/dom/Promise.h"
96 #include "nsIUploadChannel2.h"
97 #include "nsFormData.h"
98 #include "nsIPrivateBrowsingChannel.h"
99 #include "nsIDocShell.h"
101 #include "WorkerPrivate.h"
102 #include "WorkerRunnable.h"
104 #if defined(XP_LINUX)
105 #include "mozilla/Hal.h"
106 #endif
107 #include "mozilla/dom/ContentChild.h"
109 #include "mozilla/dom/FeatureList.h"
111 #ifdef MOZ_WIDGET_GONK
112 #include <cutils/properties.h>
113 #endif
115 namespace mozilla {
116 namespace dom {
118 static bool sDoNotTrackEnabled = false;
119 static uint32_t sDoNotTrackValue = 1;
120 static bool sVibratorEnabled = false;
121 static uint32_t sMaxVibrateMS = 0;
122 static uint32_t sMaxVibrateListLen = 0;
124 /* static */
125 void
126 Navigator::Init()
128 Preferences::AddBoolVarCache(&sDoNotTrackEnabled,
129 "privacy.donottrackheader.enabled",
130 false);
131 Preferences::AddUintVarCache(&sDoNotTrackValue,
132 "privacy.donottrackheader.value",
134 Preferences::AddBoolVarCache(&sVibratorEnabled,
135 "dom.vibrator.enabled", true);
136 Preferences::AddUintVarCache(&sMaxVibrateMS,
137 "dom.vibrator.max_vibrate_ms", 10000);
138 Preferences::AddUintVarCache(&sMaxVibrateListLen,
139 "dom.vibrator.max_vibrate_list_len", 128);
142 Navigator::Navigator(nsPIDOMWindow* aWindow)
143 : mWindow(aWindow)
145 MOZ_ASSERT(aWindow->IsInnerWindow(), "Navigator must get an inner window!");
146 SetIsDOMBinding();
149 Navigator::~Navigator()
151 Invalidate();
154 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Navigator)
155 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
156 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMNavigator)
157 NS_INTERFACE_MAP_ENTRY(nsIDOMNavigator)
158 NS_INTERFACE_MAP_ENTRY(nsIMozNavigatorNetwork)
159 NS_INTERFACE_MAP_END
161 NS_IMPL_CYCLE_COLLECTING_ADDREF(Navigator)
162 NS_IMPL_CYCLE_COLLECTING_RELEASE(Navigator)
164 NS_IMPL_CYCLE_COLLECTION_CLASS(Navigator)
166 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Navigator)
167 tmp->Invalidate();
168 NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
169 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedResolveResults)
170 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
171 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
173 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
174 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlugins)
175 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMimeTypes)
176 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGeolocation)
177 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotification)
178 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryManager)
179 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPowerManager)
180 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileMessageManager)
181 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTelephony)
182 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
183 #ifdef MOZ_B2G_RIL
184 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileConnections)
185 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCellBroadcast)
186 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIccManager)
187 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVoicemail)
188 #endif
189 #ifdef MOZ_B2G_BT
190 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBluetooth)
191 #endif
192 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
193 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioChannelManager)
194 #endif
195 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCameraManager)
196 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessagesManager)
197 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDeviceStorageStores)
198 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTimeManager)
199 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerContainer)
201 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
202 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedResolveResults)
203 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
204 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
206 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(Navigator)
208 void
209 Navigator::Invalidate()
211 // Don't clear mWindow here so we know we've got a non-null mWindow
212 // until we're unlinked.
214 if (mPlugins) {
215 mPlugins->Invalidate();
216 mPlugins = nullptr;
219 mMimeTypes = nullptr;
221 // If there is a page transition, make sure delete the geolocation object.
222 if (mGeolocation) {
223 mGeolocation->Shutdown();
224 mGeolocation = nullptr;
227 if (mNotification) {
228 mNotification->Shutdown();
229 mNotification = nullptr;
232 if (mBatteryManager) {
233 mBatteryManager->Shutdown();
234 mBatteryManager = nullptr;
237 #ifdef MOZ_B2G_FM
238 if (mFMRadio) {
239 mFMRadio->Shutdown();
240 mFMRadio = nullptr;
242 #endif
244 if (mPowerManager) {
245 mPowerManager->Shutdown();
246 mPowerManager = nullptr;
249 if (mMobileMessageManager) {
250 mMobileMessageManager->Shutdown();
251 mMobileMessageManager = nullptr;
254 if (mTelephony) {
255 mTelephony = nullptr;
258 if (mConnection) {
259 mConnection->Shutdown();
260 mConnection = nullptr;
263 #ifdef MOZ_B2G_RIL
264 if (mMobileConnections) {
265 mMobileConnections = nullptr;
268 if (mCellBroadcast) {
269 mCellBroadcast = nullptr;
272 if (mIccManager) {
273 mIccManager->Shutdown();
274 mIccManager = nullptr;
277 if (mVoicemail) {
278 mVoicemail = nullptr;
280 #endif
282 #ifdef MOZ_B2G_BT
283 if (mBluetooth) {
284 mBluetooth = nullptr;
286 #endif
288 mCameraManager = nullptr;
290 if (mMessagesManager) {
291 mMessagesManager = nullptr;
294 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
295 if (mAudioChannelManager) {
296 mAudioChannelManager = nullptr;
298 #endif
300 uint32_t len = mDeviceStorageStores.Length();
301 for (uint32_t i = 0; i < len; ++i) {
302 mDeviceStorageStores[i]->Shutdown();
304 mDeviceStorageStores.Clear();
306 if (mTimeManager) {
307 mTimeManager = nullptr;
310 mServiceWorkerContainer = nullptr;
313 //*****************************************************************************
314 // Navigator::nsIDOMNavigator
315 //*****************************************************************************
317 NS_IMETHODIMP
318 Navigator::GetUserAgent(nsAString& aUserAgent)
320 nsCOMPtr<nsIURI> codebaseURI;
321 nsCOMPtr<nsPIDOMWindow> window;
323 if (mWindow && mWindow->GetDocShell()) {
324 window = mWindow;
325 nsIDocument* doc = mWindow->GetExtantDoc();
326 if (doc) {
327 doc->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
331 return GetUserAgent(window, codebaseURI, nsContentUtils::IsCallerChrome(),
332 aUserAgent);
335 NS_IMETHODIMP
336 Navigator::GetAppCodeName(nsAString& aAppCodeName)
338 nsresult rv;
340 nsCOMPtr<nsIHttpProtocolHandler>
341 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
342 NS_ENSURE_SUCCESS(rv, rv);
344 nsAutoCString appName;
345 rv = service->GetAppName(appName);
346 CopyASCIItoUTF16(appName, aAppCodeName);
348 return rv;
351 NS_IMETHODIMP
352 Navigator::GetAppVersion(nsAString& aAppVersion)
354 return GetAppVersion(aAppVersion, /* aUsePrefOverriddenValue */ true);
357 NS_IMETHODIMP
358 Navigator::GetAppName(nsAString& aAppName)
360 AppName(aAppName, /* aUsePrefOverriddenValue */ true);
361 return NS_OK;
365 * Returns the value of Accept-Languages (HTTP header) as a nsTArray of
366 * languages. The value is set in the preference by the user ("Content
367 * Languages").
369 * "en", "en-US" and "i-cherokee" and "" are valid languages tokens.
371 * An empty array will be returned if there is no valid languages.
373 void
374 Navigator::GetAcceptLanguages(nsTArray<nsString>& aLanguages)
376 aLanguages.Clear();
378 // E.g. "de-de, en-us,en".
379 const nsAdoptingString& acceptLang =
380 Preferences::GetLocalizedString("intl.accept_languages");
382 // Split values on commas.
383 nsCharSeparatedTokenizer langTokenizer(acceptLang, ',');
384 while (langTokenizer.hasMoreTokens()) {
385 nsDependentSubstring lang = langTokenizer.nextToken();
387 // Replace "_" with "-" to avoid POSIX/Windows "en_US" notation.
388 // NOTE: we should probably rely on the pref being set correctly.
389 if (lang.Length() > 2 && lang[2] == char16_t('_')) {
390 lang.Replace(2, 1, char16_t('-'));
393 // Use uppercase for country part, e.g. "en-US", not "en-us", see BCP47
394 // only uppercase 2-letter country codes, not "zh-Hant", "de-DE-x-goethe".
395 // NOTE: we should probably rely on the pref being set correctly.
396 if (lang.Length() > 2) {
397 nsCharSeparatedTokenizer localeTokenizer(lang, '-');
398 int32_t pos = 0;
399 bool first = true;
400 while (localeTokenizer.hasMoreTokens()) {
401 const nsSubstring& code = localeTokenizer.nextToken();
403 if (code.Length() == 2 && !first) {
404 nsAutoString upper(code);
405 ToUpperCase(upper);
406 lang.Replace(pos, code.Length(), upper);
409 pos += code.Length() + 1; // 1 is the separator
410 first = false;
414 aLanguages.AppendElement(lang);
419 * Do not use UI language (chosen app locale) here but the first value set in
420 * the Accept Languages header, see ::GetAcceptLanguages().
422 * See RFC 2616, Section 15.1.4 "Privacy Issues Connected to Accept Headers" for
423 * the reasons why.
425 NS_IMETHODIMP
426 Navigator::GetLanguage(nsAString& aLanguage)
428 nsTArray<nsString> languages;
429 GetLanguages(languages);
430 if (languages.Length() >= 1) {
431 aLanguage.Assign(languages[0]);
432 } else {
433 aLanguage.Truncate();
436 return NS_OK;
439 void
440 Navigator::GetLanguages(nsTArray<nsString>& aLanguages)
442 GetAcceptLanguages(aLanguages);
444 // The returned value is cached by the binding code. The window listen to the
445 // accept languages change and will clear the cache when needed. It has to
446 // take care of dispatching the DOM event already and the invalidation and the
447 // event has to be timed correctly.
450 NS_IMETHODIMP
451 Navigator::GetPlatform(nsAString& aPlatform)
453 return GetPlatform(aPlatform, /* aUsePrefOverriddenValue */ true);
456 NS_IMETHODIMP
457 Navigator::GetOscpu(nsAString& aOSCPU)
459 if (!nsContentUtils::IsCallerChrome()) {
460 const nsAdoptingString& override =
461 Preferences::GetString("general.oscpu.override");
463 if (override) {
464 aOSCPU = override;
465 return NS_OK;
469 nsresult rv;
471 nsCOMPtr<nsIHttpProtocolHandler>
472 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
473 NS_ENSURE_SUCCESS(rv, rv);
475 nsAutoCString oscpu;
476 rv = service->GetOscpu(oscpu);
477 CopyASCIItoUTF16(oscpu, aOSCPU);
479 return rv;
482 NS_IMETHODIMP
483 Navigator::GetVendor(nsAString& aVendor)
485 aVendor.Truncate();
486 return NS_OK;
489 NS_IMETHODIMP
490 Navigator::GetVendorSub(nsAString& aVendorSub)
492 aVendorSub.Truncate();
493 return NS_OK;
496 NS_IMETHODIMP
497 Navigator::GetProduct(nsAString& aProduct)
499 aProduct.AssignLiteral("Gecko");
500 return NS_OK;
503 NS_IMETHODIMP
504 Navigator::GetProductSub(nsAString& aProductSub)
506 // Legacy build ID hardcoded for backward compatibility (bug 776376)
507 aProductSub.AssignLiteral("20100101");
508 return NS_OK;
511 nsMimeTypeArray*
512 Navigator::GetMimeTypes(ErrorResult& aRv)
514 if (!mMimeTypes) {
515 if (!mWindow) {
516 aRv.Throw(NS_ERROR_UNEXPECTED);
517 return nullptr;
519 mMimeTypes = new nsMimeTypeArray(mWindow);
522 return mMimeTypes;
525 nsPluginArray*
526 Navigator::GetPlugins(ErrorResult& aRv)
528 if (!mPlugins) {
529 if (!mWindow) {
530 aRv.Throw(NS_ERROR_UNEXPECTED);
531 return nullptr;
533 mPlugins = new nsPluginArray(mWindow);
534 mPlugins->Init();
537 return mPlugins;
540 // Values for the network.cookie.cookieBehavior pref are documented in
541 // nsCookieService.cpp.
542 #define COOKIE_BEHAVIOR_REJECT 2
544 bool
545 Navigator::CookieEnabled()
547 bool cookieEnabled =
548 (Preferences::GetInt("network.cookie.cookieBehavior",
549 COOKIE_BEHAVIOR_REJECT) != COOKIE_BEHAVIOR_REJECT);
551 // Check whether an exception overrides the global cookie behavior
552 // Note that the code for getting the URI here matches that in
553 // nsHTMLDocument::SetCookie.
554 if (!mWindow || !mWindow->GetDocShell()) {
555 return cookieEnabled;
558 nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc();
559 if (!doc) {
560 return cookieEnabled;
563 nsCOMPtr<nsIURI> codebaseURI;
564 doc->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
566 if (!codebaseURI) {
567 // Not a codebase, so technically can't set cookies, but let's
568 // just return the default value.
569 return cookieEnabled;
572 nsCOMPtr<nsICookiePermission> permMgr =
573 do_GetService(NS_COOKIEPERMISSION_CONTRACTID);
574 NS_ENSURE_TRUE(permMgr, cookieEnabled);
576 // Pass null for the channel, just like the cookie service does.
577 nsCookieAccess access;
578 nsresult rv = permMgr->CanAccess(codebaseURI, nullptr, &access);
579 NS_ENSURE_SUCCESS(rv, cookieEnabled);
581 if (access != nsICookiePermission::ACCESS_DEFAULT) {
582 cookieEnabled = access != nsICookiePermission::ACCESS_DENY;
585 return cookieEnabled;
588 bool
589 Navigator::OnLine()
591 return !NS_IsOffline();
594 NS_IMETHODIMP
595 Navigator::GetBuildID(nsAString& aBuildID)
597 if (!nsContentUtils::IsCallerChrome()) {
598 const nsAdoptingString& override =
599 Preferences::GetString("general.buildID.override");
601 if (override) {
602 aBuildID = override;
603 return NS_OK;
607 nsCOMPtr<nsIXULAppInfo> appInfo =
608 do_GetService("@mozilla.org/xre/app-info;1");
609 if (!appInfo) {
610 return NS_ERROR_NOT_IMPLEMENTED;
613 nsAutoCString buildID;
614 nsresult rv = appInfo->GetAppBuildID(buildID);
615 if (NS_FAILED(rv)) {
616 return rv;
619 aBuildID.Truncate();
620 AppendASCIItoUTF16(buildID, aBuildID);
621 return NS_OK;
624 NS_IMETHODIMP
625 Navigator::GetDoNotTrack(nsAString &aResult)
627 if (sDoNotTrackEnabled) {
628 if (sDoNotTrackValue == 0) {
629 aResult.AssignLiteral("0");
630 } else {
631 aResult.AssignLiteral("1");
633 } else {
634 aResult.AssignLiteral("unspecified");
637 return NS_OK;
640 bool
641 Navigator::JavaEnabled(ErrorResult& aRv)
643 Telemetry::AutoTimer<Telemetry::CHECK_JAVA_ENABLED> telemetryTimer;
645 // Return true if we have a handler for the java mime
646 nsAdoptingString javaMIME = Preferences::GetString("plugin.java.mime");
647 NS_ENSURE_TRUE(!javaMIME.IsEmpty(), false);
649 if (!mMimeTypes) {
650 if (!mWindow) {
651 aRv.Throw(NS_ERROR_UNEXPECTED);
652 return false;
654 mMimeTypes = new nsMimeTypeArray(mWindow);
657 RefreshMIMEArray();
659 nsMimeType *mimeType = mMimeTypes->NamedItem(javaMIME);
661 return mimeType && mimeType->GetEnabledPlugin();
664 void
665 Navigator::RefreshMIMEArray()
667 if (mMimeTypes) {
668 mMimeTypes->Refresh();
672 namespace {
674 class VibrateWindowListener : public nsIDOMEventListener
676 public:
677 VibrateWindowListener(nsIDOMWindow* aWindow, nsIDocument* aDocument)
679 mWindow = do_GetWeakReference(aWindow);
680 mDocument = do_GetWeakReference(aDocument);
682 NS_NAMED_LITERAL_STRING(visibilitychange, "visibilitychange");
683 aDocument->AddSystemEventListener(visibilitychange,
684 this, /* listener */
685 true, /* use capture */
686 false /* wants untrusted */);
689 void RemoveListener();
691 NS_DECL_ISUPPORTS
692 NS_DECL_NSIDOMEVENTLISTENER
694 private:
695 virtual ~VibrateWindowListener()
699 nsWeakPtr mWindow;
700 nsWeakPtr mDocument;
703 NS_IMPL_ISUPPORTS(VibrateWindowListener, nsIDOMEventListener)
705 StaticRefPtr<VibrateWindowListener> gVibrateWindowListener;
707 NS_IMETHODIMP
708 VibrateWindowListener::HandleEvent(nsIDOMEvent* aEvent)
710 nsCOMPtr<nsIDocument> doc =
711 do_QueryInterface(aEvent->InternalDOMEvent()->GetTarget());
713 if (!doc || doc->Hidden()) {
714 // It's important that we call CancelVibrate(), not Vibrate() with an
715 // empty list, because Vibrate() will fail if we're no longer focused, but
716 // CancelVibrate() will succeed, so long as nobody else has started a new
717 // vibration pattern.
718 nsCOMPtr<nsIDOMWindow> window = do_QueryReferent(mWindow);
719 hal::CancelVibrate(window);
720 RemoveListener();
721 gVibrateWindowListener = nullptr;
722 // Careful: The line above might have deleted |this|!
725 return NS_OK;
728 void
729 VibrateWindowListener::RemoveListener()
731 nsCOMPtr<EventTarget> target = do_QueryReferent(mDocument);
732 if (!target) {
733 return;
735 NS_NAMED_LITERAL_STRING(visibilitychange, "visibilitychange");
736 target->RemoveSystemEventListener(visibilitychange, this,
737 true /* use capture */);
740 } // anonymous namespace
742 void
743 Navigator::AddIdleObserver(MozIdleObserver& aIdleObserver, ErrorResult& aRv)
745 if (!mWindow) {
746 aRv.Throw(NS_ERROR_UNEXPECTED);
747 return;
749 CallbackObjectHolder<MozIdleObserver, nsIIdleObserver> holder(&aIdleObserver);
750 nsCOMPtr<nsIIdleObserver> obs = holder.ToXPCOMCallback();
751 if (NS_FAILED(mWindow->RegisterIdleObserver(obs))) {
752 NS_WARNING("Failed to add idle observer.");
756 void
757 Navigator::RemoveIdleObserver(MozIdleObserver& aIdleObserver, ErrorResult& aRv)
759 if (!mWindow) {
760 aRv.Throw(NS_ERROR_UNEXPECTED);
761 return;
763 CallbackObjectHolder<MozIdleObserver, nsIIdleObserver> holder(&aIdleObserver);
764 nsCOMPtr<nsIIdleObserver> obs = holder.ToXPCOMCallback();
765 if (NS_FAILED(mWindow->UnregisterIdleObserver(obs))) {
766 NS_WARNING("Failed to remove idle observer.");
770 bool
771 Navigator::Vibrate(uint32_t aDuration)
773 nsAutoTArray<uint32_t, 1> pattern;
774 pattern.AppendElement(aDuration);
775 return Vibrate(pattern);
778 bool
779 Navigator::Vibrate(const nsTArray<uint32_t>& aPattern)
781 if (!mWindow) {
782 return false;
785 nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc();
786 if (!doc) {
787 return false;
790 if (doc->Hidden()) {
791 // Hidden documents cannot start or stop a vibration.
792 return false;
795 nsTArray<uint32_t> pattern(aPattern);
797 if (pattern.Length() > sMaxVibrateListLen) {
798 pattern.SetLength(sMaxVibrateListLen);
801 for (size_t i = 0; i < pattern.Length(); ++i) {
802 if (pattern[i] > sMaxVibrateMS) {
803 pattern[i] = sMaxVibrateMS;
807 // The spec says we check sVibratorEnabled after we've done the sanity
808 // checking on the pattern.
809 if (!sVibratorEnabled) {
810 return true;
813 // Add a listener to cancel the vibration if the document becomes hidden,
814 // and remove the old visibility listener, if there was one.
816 if (!gVibrateWindowListener) {
817 // If gVibrateWindowListener is null, this is the first time we've vibrated,
818 // and we need to register a listener to clear gVibrateWindowListener on
819 // shutdown.
820 ClearOnShutdown(&gVibrateWindowListener);
822 else {
823 gVibrateWindowListener->RemoveListener();
825 gVibrateWindowListener = new VibrateWindowListener(mWindow, doc);
827 hal::Vibrate(pattern, mWindow);
828 return true;
831 //*****************************************************************************
832 // Pointer Events interface
833 //*****************************************************************************
835 uint32_t
836 Navigator::MaxTouchPoints()
838 nsCOMPtr<nsIWidget> widget = widget::WidgetUtils::DOMWindowToWidget(mWindow);
840 NS_ENSURE_TRUE(widget, 0);
841 return widget->GetMaxTouchPoints();
844 //*****************************************************************************
845 // Navigator::nsIDOMClientInformation
846 //*****************************************************************************
848 void
849 Navigator::RegisterContentHandler(const nsAString& aMIMEType,
850 const nsAString& aURI,
851 const nsAString& aTitle,
852 ErrorResult& aRv)
854 if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) {
855 return;
858 nsCOMPtr<nsIWebContentHandlerRegistrar> registrar =
859 do_GetService(NS_WEBCONTENTHANDLERREGISTRAR_CONTRACTID);
860 if (!registrar) {
861 return;
864 aRv = registrar->RegisterContentHandler(aMIMEType, aURI, aTitle,
865 mWindow->GetOuterWindow());
868 void
869 Navigator::RegisterProtocolHandler(const nsAString& aProtocol,
870 const nsAString& aURI,
871 const nsAString& aTitle,
872 ErrorResult& aRv)
874 if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) {
875 return;
878 nsCOMPtr<nsIWebContentHandlerRegistrar> registrar =
879 do_GetService(NS_WEBCONTENTHANDLERREGISTRAR_CONTRACTID);
880 if (!registrar) {
881 return;
884 aRv = registrar->RegisterProtocolHandler(aProtocol, aURI, aTitle,
885 mWindow->GetOuterWindow());
888 bool
889 Navigator::MozIsLocallyAvailable(const nsAString &aURI,
890 bool aWhenOffline,
891 ErrorResult& aRv)
893 nsCOMPtr<nsIURI> uri;
894 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURI);
895 if (NS_FAILED(rv)) {
896 aRv.Throw(rv);
897 return false;
900 // This method of checking the cache will only work for http/https urls.
901 bool match;
902 rv = uri->SchemeIs("http", &match);
903 if (NS_FAILED(rv)) {
904 aRv.Throw(rv);
905 return false;
908 if (!match) {
909 rv = uri->SchemeIs("https", &match);
910 if (NS_FAILED(rv)) {
911 aRv.Throw(rv);
912 return false;
914 if (!match) {
915 aRv.Throw(NS_ERROR_DOM_BAD_URI);
916 return false;
920 // Same origin check.
921 JSContext *cx = nsContentUtils::GetCurrentJSContext();
922 if (!cx) {
923 aRv.Throw(NS_ERROR_FAILURE);
924 return false;
927 rv = nsContentUtils::GetSecurityManager()->CheckSameOrigin(cx, uri);
928 if (NS_FAILED(rv)) {
929 aRv.Throw(rv);
930 return false;
933 // These load flags cause an error to be thrown if there is no
934 // valid cache entry, and skip the load if there is.
935 // If the cache is busy, assume that it is not yet available rather
936 // than waiting for it to become available.
937 uint32_t loadFlags = nsIChannel::INHIBIT_CACHING |
938 nsICachingChannel::LOAD_NO_NETWORK_IO |
939 nsICachingChannel::LOAD_ONLY_IF_MODIFIED |
940 nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY;
942 if (aWhenOffline) {
943 loadFlags |= nsICachingChannel::LOAD_CHECK_OFFLINE_CACHE |
944 nsICachingChannel::LOAD_ONLY_FROM_CACHE |
945 nsIRequest::LOAD_FROM_CACHE;
948 if (!mWindow) {
949 aRv.Throw(NS_ERROR_UNEXPECTED);
950 return false;
953 nsCOMPtr<nsILoadGroup> loadGroup;
954 nsCOMPtr<nsIDocument> doc = mWindow->GetDoc();
955 if (doc) {
956 loadGroup = doc->GetDocumentLoadGroup();
959 nsCOMPtr<nsIChannel> channel;
960 rv = NS_NewChannel(getter_AddRefs(channel), uri,
961 nullptr, loadGroup, nullptr, loadFlags);
962 if (NS_FAILED(rv)) {
963 aRv.Throw(rv);
964 return false;
967 nsCOMPtr<nsIInputStream> stream;
968 rv = channel->Open(getter_AddRefs(stream));
969 if (NS_FAILED(rv)) {
970 aRv.Throw(rv);
971 return false;
974 stream->Close();
976 nsresult status;
977 rv = channel->GetStatus(&status);
978 if (NS_FAILED(rv)) {
979 aRv.Throw(rv);
980 return false;
983 if (NS_FAILED(status)) {
984 return false;
987 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
988 bool isAvailable;
989 rv = httpChannel->GetRequestSucceeded(&isAvailable);
990 if (NS_FAILED(rv)) {
991 aRv.Throw(rv);
992 return false;
994 return isAvailable;
997 nsDOMDeviceStorage*
998 Navigator::GetDeviceStorage(const nsAString& aType, ErrorResult& aRv)
1000 if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) {
1001 aRv.Throw(NS_ERROR_FAILURE);
1002 return nullptr;
1005 nsRefPtr<nsDOMDeviceStorage> storage;
1006 nsDOMDeviceStorage::CreateDeviceStorageFor(mWindow, aType,
1007 getter_AddRefs(storage));
1009 if (!storage) {
1010 return nullptr;
1013 mDeviceStorageStores.AppendElement(storage);
1014 return storage;
1017 void
1018 Navigator::GetDeviceStorages(const nsAString& aType,
1019 nsTArray<nsRefPtr<nsDOMDeviceStorage> >& aStores,
1020 ErrorResult& aRv)
1022 if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) {
1023 aRv.Throw(NS_ERROR_FAILURE);
1024 return;
1027 nsDOMDeviceStorage::CreateDeviceStoragesFor(mWindow, aType, aStores);
1029 mDeviceStorageStores.AppendElements(aStores);
1032 Geolocation*
1033 Navigator::GetGeolocation(ErrorResult& aRv)
1035 if (mGeolocation) {
1036 return mGeolocation;
1039 if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) {
1040 aRv.Throw(NS_ERROR_FAILURE);
1041 return nullptr;
1044 mGeolocation = new Geolocation();
1045 if (NS_FAILED(mGeolocation->Init(mWindow->GetOuterWindow()))) {
1046 mGeolocation = nullptr;
1047 aRv.Throw(NS_ERROR_FAILURE);
1048 return nullptr;
1051 return mGeolocation;
1054 class BeaconStreamListener MOZ_FINAL : public nsIStreamListener
1056 ~BeaconStreamListener() {}
1058 public:
1059 BeaconStreamListener() {}
1061 NS_DECL_ISUPPORTS
1062 NS_DECL_NSISTREAMLISTENER
1063 NS_DECL_NSIREQUESTOBSERVER
1066 NS_IMPL_ISUPPORTS(BeaconStreamListener,
1067 nsIStreamListener,
1068 nsIRequestObserver)
1071 NS_IMETHODIMP
1072 BeaconStreamListener::OnStartRequest(nsIRequest *aRequest,
1073 nsISupports *aContext)
1075 aRequest->Cancel(NS_ERROR_NET_INTERRUPT);
1076 return NS_BINDING_ABORTED;
1079 NS_IMETHODIMP
1080 BeaconStreamListener::OnStopRequest(nsIRequest *aRequest,
1081 nsISupports *aContext,
1082 nsresult aStatus)
1084 return NS_OK;
1087 NS_IMETHODIMP
1088 BeaconStreamListener::OnDataAvailable(nsIRequest *aRequest,
1089 nsISupports *ctxt,
1090 nsIInputStream *inStr,
1091 uint64_t sourceOffset,
1092 uint32_t count)
1094 MOZ_ASSERT(false);
1095 return NS_OK;
1098 bool
1099 Navigator::SendBeacon(const nsAString& aUrl,
1100 const Nullable<ArrayBufferViewOrBlobOrStringOrFormData>& aData,
1101 ErrorResult& aRv)
1103 if (!mWindow) {
1104 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
1105 return false;
1108 nsCOMPtr<nsIDocument> doc = mWindow->GetDoc();
1109 if (!doc) {
1110 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
1111 return false;
1114 nsIURI* documentURI = doc->GetDocumentURI();
1115 if (!documentURI) {
1116 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
1117 return false;
1120 nsCOMPtr<nsIURI> uri;
1121 nsresult rv = nsContentUtils::NewURIWithDocumentCharset(
1122 getter_AddRefs(uri),
1123 aUrl,
1124 doc,
1125 doc->GetDocBaseURI());
1126 if (NS_FAILED(rv)) {
1127 aRv.Throw(NS_ERROR_DOM_URL_MISMATCH_ERR);
1128 return false;
1131 // Check whether this is a sane URI to load
1132 // Explicitly disallow things like chrome:, javascript:, and data: URIs
1133 nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
1134 nsCOMPtr<nsIScriptSecurityManager> secMan = nsContentUtils::GetSecurityManager();
1135 uint32_t flags = nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL
1136 & nsIScriptSecurityManager::DISALLOW_SCRIPT;
1137 rv = secMan->CheckLoadURIWithPrincipal(principal,
1138 uri,
1139 flags);
1140 if (NS_FAILED(rv)) {
1141 // Bad URI
1142 aRv.Throw(rv);
1143 return false;
1146 // Check whether the CSP allows us to load
1147 int16_t shouldLoad = nsIContentPolicy::ACCEPT;
1148 rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_BEACON,
1149 uri,
1150 principal,
1151 doc,
1152 EmptyCString(), //mime guess
1153 nullptr, //extra
1154 &shouldLoad,
1155 nsContentUtils::GetContentPolicy(),
1156 nsContentUtils::GetSecurityManager());
1157 if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
1158 // Disallowed by content policy
1159 aRv.Throw(NS_ERROR_CONTENT_BLOCKED);
1160 return false;
1163 nsCOMPtr<nsIChannel> channel;
1164 nsCOMPtr<nsIChannelPolicy> channelPolicy;
1165 nsCOMPtr<nsIContentSecurityPolicy> csp;
1166 rv = principal->GetCsp(getter_AddRefs(csp));
1167 if (NS_FAILED(rv)) {
1168 aRv.Throw(NS_ERROR_FAILURE);
1169 return false;
1172 if (csp) {
1173 channelPolicy = do_CreateInstance(NSCHANNELPOLICY_CONTRACTID);
1174 channelPolicy->SetContentSecurityPolicy(csp);
1175 channelPolicy->SetLoadType(nsIContentPolicy::TYPE_BEACON);
1177 rv = NS_NewChannel(getter_AddRefs(channel),
1178 uri,
1179 nullptr,
1180 nullptr,
1181 nullptr,
1182 nsIRequest::LOAD_NORMAL,
1183 channelPolicy);
1184 if (NS_FAILED(rv)) {
1185 aRv.Throw(rv);
1186 return false;
1189 nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryInterface(channel);
1190 if (pbChannel) {
1191 nsIDocShell* docShell = mWindow->GetDocShell();
1192 nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
1193 if (loadContext) {
1194 rv = pbChannel->SetPrivate(loadContext->UsePrivateBrowsing());
1195 if (NS_FAILED(rv)) {
1196 NS_WARNING("Setting the privacy status on the beacon channel failed");
1201 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
1202 if (!httpChannel) {
1203 // Beacon spec only supports HTTP requests at this time
1204 aRv.Throw(NS_ERROR_DOM_BAD_URI);
1205 return false;
1207 httpChannel->SetReferrer(documentURI);
1209 // Anything that will need to refer to the window during the request
1210 // will need to be done now. For example, detection of whether any
1211 // cookies set by this request are foreign. Note that ThirdPartyUtil
1212 // (nsIThirdPartyUtil.isThirdPartyChannel) does a secondary check between
1213 // the channel URI and the cookie URI even when forceAllowThirdPartyCookie
1214 // is set, so this is safe with regard to redirects.
1215 nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal(do_QueryInterface(channel));
1216 nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = do_GetService(THIRDPARTYUTIL_CONTRACTID);
1217 if (!httpChannelInternal) {
1218 aRv.Throw(NS_ERROR_DOM_BAD_URI);
1219 return false;
1221 bool isForeign = true;
1222 thirdPartyUtil->IsThirdPartyWindow(mWindow, uri, &isForeign);
1223 httpChannelInternal->SetForceAllowThirdPartyCookie(!isForeign);
1225 nsCString mimeType;
1226 if (!aData.IsNull()) {
1227 nsCOMPtr<nsIInputStream> in;
1229 if (aData.Value().IsString()) {
1230 nsCString stringData = NS_ConvertUTF16toUTF8(aData.Value().GetAsString());
1231 nsCOMPtr<nsIStringInputStream> strStream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
1232 if (NS_FAILED(rv)) {
1233 aRv.Throw(NS_ERROR_FAILURE);
1234 return false;
1236 rv = strStream->SetData(stringData.BeginReading(), stringData.Length());
1237 if (NS_FAILED(rv)) {
1238 aRv.Throw(NS_ERROR_FAILURE);
1239 return false;
1241 mimeType.AssignLiteral("text/plain;charset=UTF-8");
1242 in = strStream;
1244 } else if (aData.Value().IsArrayBufferView()) {
1246 nsCOMPtr<nsIStringInputStream> strStream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
1247 if (NS_FAILED(rv)) {
1248 aRv.Throw(NS_ERROR_FAILURE);
1249 return false;
1252 const ArrayBufferView& view = aData.Value().GetAsArrayBufferView();
1253 view.ComputeLengthAndData();
1254 rv = strStream->SetData(reinterpret_cast<char*>(view.Data()),
1255 view.Length());
1257 if (NS_FAILED(rv)) {
1258 aRv.Throw(NS_ERROR_FAILURE);
1259 return false;
1261 mimeType.AssignLiteral("application/octet-stream");
1262 in = strStream;
1264 } else if (aData.Value().IsBlob()) {
1265 nsCOMPtr<nsIDOMBlob> blob = aData.Value().GetAsBlob();
1266 rv = blob->GetInternalStream(getter_AddRefs(in));
1267 if (NS_FAILED(rv)) {
1268 aRv.Throw(NS_ERROR_FAILURE);
1269 return false;
1271 nsAutoString type;
1272 rv = blob->GetType(type);
1273 if (NS_FAILED(rv)) {
1274 aRv.Throw(NS_ERROR_FAILURE);
1275 return false;
1277 mimeType = NS_ConvertUTF16toUTF8(type);
1279 } else if (aData.Value().IsFormData()) {
1280 nsFormData& form = aData.Value().GetAsFormData();
1281 uint64_t len;
1282 nsAutoCString charset;
1283 form.GetSendInfo(getter_AddRefs(in),
1284 &len,
1285 mimeType,
1286 charset);
1287 } else {
1288 MOZ_ASSERT(false, "switch statements not in sync");
1289 aRv.Throw(NS_ERROR_FAILURE);
1290 return false;
1293 nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(channel);
1294 if (!uploadChannel) {
1295 aRv.Throw(NS_ERROR_FAILURE);
1296 return false;
1298 uploadChannel->ExplicitSetUploadStream(in, mimeType, -1,
1299 NS_LITERAL_CSTRING("POST"),
1300 false);
1301 } else {
1302 httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
1305 nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(channel);
1306 if (p) {
1307 p->SetPriority(nsISupportsPriority::PRIORITY_LOWEST);
1310 nsRefPtr<nsCORSListenerProxy> cors = new nsCORSListenerProxy(new BeaconStreamListener(),
1311 principal,
1312 true);
1314 rv = cors->Init(channel, true);
1315 NS_ENSURE_SUCCESS(rv, false);
1317 // Start a preflight if cross-origin and content type is not whitelisted
1318 rv = secMan->CheckSameOriginURI(documentURI, uri, false);
1319 bool crossOrigin = NS_FAILED(rv);
1320 nsAutoCString contentType, parsedCharset;
1321 rv = NS_ParseContentType(mimeType, contentType, parsedCharset);
1322 if (crossOrigin &&
1323 contentType.Length() > 0 &&
1324 !contentType.Equals(APPLICATION_WWW_FORM_URLENCODED) &&
1325 !contentType.Equals(MULTIPART_FORM_DATA) &&
1326 !contentType.Equals(TEXT_PLAIN)) {
1328 // we need to set the sameOriginChecker as a notificationCallback
1329 // so we can tell the channel not to follow redirects
1330 nsCOMPtr<nsIInterfaceRequestor> soc = nsContentUtils::GetSameOriginChecker();
1331 channel->SetNotificationCallbacks(soc);
1333 nsCOMPtr<nsIChannel> preflightChannel;
1334 nsTArray<nsCString> unsafeHeaders;
1335 unsafeHeaders.AppendElement(NS_LITERAL_CSTRING("Content-Type"));
1336 rv = NS_StartCORSPreflight(channel,
1337 cors,
1338 principal,
1339 true,
1340 unsafeHeaders,
1341 getter_AddRefs(preflightChannel));
1342 } else {
1343 rv = channel->AsyncOpen(cors, nullptr);
1345 if (NS_FAILED(rv)) {
1346 aRv.Throw(rv);
1347 return false;
1349 return true;
1352 #ifdef MOZ_MEDIA_NAVIGATOR
1353 void
1354 Navigator::MozGetUserMedia(const MediaStreamConstraints& aConstraints,
1355 NavigatorUserMediaSuccessCallback& aOnSuccess,
1356 NavigatorUserMediaErrorCallback& aOnError,
1357 ErrorResult& aRv)
1359 CallbackObjectHolder<NavigatorUserMediaSuccessCallback,
1360 nsIDOMGetUserMediaSuccessCallback> holder1(&aOnSuccess);
1361 nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onsuccess =
1362 holder1.ToXPCOMCallback();
1364 CallbackObjectHolder<NavigatorUserMediaErrorCallback,
1365 nsIDOMGetUserMediaErrorCallback> holder2(&aOnError);
1366 nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onerror = holder2.ToXPCOMCallback();
1368 if (!mWindow || !mWindow->GetOuterWindow() ||
1369 mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) {
1370 aRv.Throw(NS_ERROR_NOT_AVAILABLE);
1371 return;
1374 bool privileged = nsContentUtils::IsChromeDoc(mWindow->GetExtantDoc());
1376 MediaManager* manager = MediaManager::Get();
1377 aRv = manager->GetUserMedia(privileged, mWindow, aConstraints,
1378 onsuccess, onerror);
1381 void
1382 Navigator::MozGetUserMediaDevices(const MediaStreamConstraints& aConstraints,
1383 MozGetUserMediaDevicesSuccessCallback& aOnSuccess,
1384 NavigatorUserMediaErrorCallback& aOnError,
1385 uint64_t aInnerWindowID,
1386 ErrorResult& aRv)
1388 CallbackObjectHolder<MozGetUserMediaDevicesSuccessCallback,
1389 nsIGetUserMediaDevicesSuccessCallback> holder1(&aOnSuccess);
1390 nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> onsuccess =
1391 holder1.ToXPCOMCallback();
1393 CallbackObjectHolder<NavigatorUserMediaErrorCallback,
1394 nsIDOMGetUserMediaErrorCallback> holder2(&aOnError);
1395 nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onerror = holder2.ToXPCOMCallback();
1397 if (!mWindow || !mWindow->GetOuterWindow() ||
1398 mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) {
1399 aRv.Throw(NS_ERROR_NOT_AVAILABLE);
1400 return;
1403 MediaManager* manager = MediaManager::Get();
1404 aRv = manager->GetUserMediaDevices(mWindow, aConstraints, onsuccess, onerror,
1405 aInnerWindowID);
1407 #endif
1409 DesktopNotificationCenter*
1410 Navigator::GetMozNotification(ErrorResult& aRv)
1412 if (mNotification) {
1413 return mNotification;
1416 if (!mWindow || !mWindow->GetDocShell()) {
1417 aRv.Throw(NS_ERROR_FAILURE);
1418 return nullptr;
1421 mNotification = new DesktopNotificationCenter(mWindow);
1422 return mNotification;
1425 #ifdef MOZ_B2G_FM
1427 using mozilla::dom::FMRadio;
1429 FMRadio*
1430 Navigator::GetMozFMRadio(ErrorResult& aRv)
1432 if (!mFMRadio) {
1433 if (!mWindow) {
1434 aRv.Throw(NS_ERROR_UNEXPECTED);
1435 return nullptr;
1438 NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr);
1440 mFMRadio = new FMRadio();
1441 mFMRadio->Init(mWindow);
1444 return mFMRadio;
1447 #endif // MOZ_B2G_FM
1449 //*****************************************************************************
1450 // Navigator::nsINavigatorBattery
1451 //*****************************************************************************
1453 battery::BatteryManager*
1454 Navigator::GetBattery(ErrorResult& aRv)
1456 if (!mBatteryManager) {
1457 if (!mWindow) {
1458 aRv.Throw(NS_ERROR_UNEXPECTED);
1459 return nullptr;
1461 NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr);
1463 mBatteryManager = new battery::BatteryManager(mWindow);
1464 mBatteryManager->Init();
1467 return mBatteryManager;
1470 /* static */ already_AddRefed<Promise>
1471 Navigator::GetDataStores(nsPIDOMWindow* aWindow,
1472 const nsAString& aName,
1473 const nsAString& aOwner,
1474 ErrorResult& aRv)
1476 if (!aWindow || !aWindow->GetDocShell()) {
1477 aRv.Throw(NS_ERROR_UNEXPECTED);
1478 return nullptr;
1481 nsRefPtr<DataStoreService> service = DataStoreService::GetOrCreate();
1482 if (!service) {
1483 aRv.Throw(NS_ERROR_FAILURE);
1484 return nullptr;
1487 nsCOMPtr<nsISupports> promise;
1488 aRv = service->GetDataStores(aWindow, aName, aOwner, getter_AddRefs(promise));
1490 nsRefPtr<Promise> p = static_cast<Promise*>(promise.get());
1491 return p.forget();
1494 already_AddRefed<Promise>
1495 Navigator::GetDataStores(const nsAString& aName,
1496 const nsAString& aOwner,
1497 ErrorResult& aRv)
1499 return GetDataStores(mWindow, aName, aOwner, aRv);
1502 already_AddRefed<Promise>
1503 Navigator::GetFeature(const nsAString& aName, ErrorResult& aRv)
1505 nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow);
1506 nsRefPtr<Promise> p = Promise::Create(go, aRv);
1507 if (aRv.Failed()) {
1508 return nullptr;
1511 #if defined(XP_LINUX)
1512 if (aName.EqualsLiteral("hardware.memory")) {
1513 // with seccomp enabled, fopen() should be in a non-sandboxed process
1514 if (XRE_GetProcessType() == GeckoProcessType_Default) {
1515 uint32_t memLevel = mozilla::hal::GetTotalSystemMemoryLevel();
1516 if (memLevel == 0) {
1517 p->MaybeReject(NS_ERROR_NOT_AVAILABLE);
1518 return p.forget();
1520 p->MaybeResolve((int)memLevel);
1521 } else {
1522 mozilla::dom::ContentChild* cc =
1523 mozilla::dom::ContentChild::GetSingleton();
1524 nsRefPtr<Promise> ipcRef(p);
1525 cc->SendGetSystemMemory(reinterpret_cast<uint64_t>(ipcRef.forget().take()));
1527 return p.forget();
1528 } // hardware.memory
1529 #endif
1531 #ifdef MOZ_WIDGET_GONK
1532 if (aName.EqualsLiteral("acl.version")) {
1533 char value[PROPERTY_VALUE_MAX];
1534 uint32_t len = property_get("persist.acl.version", value, nullptr);
1535 if (len > 0) {
1536 p->MaybeResolve(NS_ConvertUTF8toUTF16(value));
1537 return p.forget();
1540 #endif
1542 p->MaybeResolve(JS::UndefinedHandleValue);
1543 return p.forget();
1546 already_AddRefed<Promise>
1547 Navigator::HasFeature(const nsAString& aName, ErrorResult& aRv)
1549 nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow);
1550 nsRefPtr<Promise> p = Promise::Create(go, aRv);
1551 if (aRv.Failed()) {
1552 return nullptr;
1555 // Hardcoded manifest features. Some are still b2g specific.
1556 const char manifestFeatures[][64] = {
1557 "manifest.origin"
1558 , "manifest.redirects"
1559 #ifdef MOZ_B2G
1560 , "manifest.chrome.navigation"
1561 , "manifest.precompile"
1562 #endif
1565 nsAutoCString feature = NS_ConvertUTF16toUTF8(aName);
1566 for (uint32_t i = 0; i < MOZ_ARRAY_LENGTH(manifestFeatures); i++) {
1567 if (feature.Equals(manifestFeatures[i])) {
1568 p->MaybeResolve(true);
1569 return p.forget();
1573 NS_NAMED_LITERAL_STRING(apiWindowPrefix, "api.window.");
1574 if (StringBeginsWith(aName, apiWindowPrefix)) {
1575 const nsAString& featureName = Substring(aName, apiWindowPrefix.Length());
1577 // Temporary hardcoded entry points due to technical constraints
1578 if (featureName.EqualsLiteral("Navigator.mozTCPSocket")) {
1579 p->MaybeResolve(Preferences::GetBool("dom.mozTCPSocket.enabled"));
1580 return p.forget();
1583 if (featureName.EqualsLiteral("Navigator.mozMobileConnections") ||
1584 featureName.EqualsLiteral("MozMobileNetworkInfo")) {
1585 p->MaybeResolve(Preferences::GetBool("dom.mobileconnection.enabled"));
1586 return p.forget();
1589 if (featureName.EqualsLiteral("Navigator.mozInputMethod")) {
1590 p->MaybeResolve(Preferences::GetBool("dom.mozInputMethod.enabled"));
1591 return p.forget();
1594 if (featureName.EqualsLiteral("Navigator.mozContacts")) {
1595 p->MaybeResolve(true);
1596 return p.forget();
1599 if (featureName.EqualsLiteral("Navigator.getDeviceStorage")) {
1600 p->MaybeResolve(Preferences::GetBool("device.storage.enabled"));
1601 return p.forget();
1604 if (featureName.EqualsLiteral("Navigator.mozNetworkStats")) {
1605 p->MaybeResolve(Preferences::GetBool("dom.mozNetworkStats.enabled"));
1606 return p.forget();
1609 if (featureName.EqualsLiteral("Navigator.push")) {
1610 p->MaybeResolve(Preferences::GetBool("services.push.enabled"));
1611 return p.forget();
1614 if (featureName.EqualsLiteral("Navigator.mozAlarms")) {
1615 p->MaybeResolve(Preferences::GetBool("dom.mozAlarms.enabled"));
1616 return p.forget();
1619 if (featureName.EqualsLiteral("Navigator.mozCameras")) {
1620 p->MaybeResolve(true);
1621 return p.forget();
1624 #ifdef MOZ_B2G
1625 if (featureName.EqualsLiteral("Navigator.getMobileIdAssertion")) {
1626 p->MaybeResolve(true);
1627 return p.forget();
1629 #endif
1631 if (featureName.EqualsLiteral("XMLHttpRequest.mozSystem")) {
1632 p->MaybeResolve(true);
1633 return p.forget();
1636 if (IsFeatureDetectible(featureName)) {
1637 p->MaybeResolve(true);
1638 } else {
1639 p->MaybeResolve(JS::UndefinedHandleValue);
1641 return p.forget();
1644 // resolve with <undefined> because the feature name is not supported
1645 p->MaybeResolve(JS::UndefinedHandleValue);
1647 return p.forget();
1650 PowerManager*
1651 Navigator::GetMozPower(ErrorResult& aRv)
1653 if (!mPowerManager) {
1654 if (!mWindow) {
1655 aRv.Throw(NS_ERROR_UNEXPECTED);
1656 return nullptr;
1658 mPowerManager = PowerManager::CreateInstance(mWindow);
1659 if (!mPowerManager) {
1660 // We failed to get the power manager service?
1661 aRv.Throw(NS_ERROR_UNEXPECTED);
1665 return mPowerManager;
1668 already_AddRefed<WakeLock>
1669 Navigator::RequestWakeLock(const nsAString &aTopic, ErrorResult& aRv)
1671 if (!mWindow) {
1672 aRv.Throw(NS_ERROR_UNEXPECTED);
1673 return nullptr;
1676 nsRefPtr<power::PowerManagerService> pmService =
1677 power::PowerManagerService::GetInstance();
1678 // Maybe it went away for some reason... Or maybe we're just called
1679 // from our XPCOM method.
1680 if (!pmService) {
1681 aRv.Throw(NS_ERROR_UNEXPECTED);
1682 return nullptr;
1685 return pmService->NewWakeLock(aTopic, mWindow, aRv);
1688 MobileMessageManager*
1689 Navigator::GetMozMobileMessage()
1691 if (!mMobileMessageManager) {
1692 // Check that our window has not gone away
1693 NS_ENSURE_TRUE(mWindow, nullptr);
1694 NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr);
1696 mMobileMessageManager = new MobileMessageManager(mWindow);
1697 mMobileMessageManager->Init();
1700 return mMobileMessageManager;
1703 Telephony*
1704 Navigator::GetMozTelephony(ErrorResult& aRv)
1706 if (!mTelephony) {
1707 if (!mWindow) {
1708 aRv.Throw(NS_ERROR_UNEXPECTED);
1709 return nullptr;
1711 mTelephony = Telephony::Create(mWindow, aRv);
1714 return mTelephony;
1717 #ifdef MOZ_B2G
1718 already_AddRefed<Promise>
1719 Navigator::GetMobileIdAssertion(const MobileIdOptions& aOptions,
1720 ErrorResult& aRv)
1722 if (!mWindow || !mWindow->GetDocShell()) {
1723 aRv.Throw(NS_ERROR_UNEXPECTED);
1724 return nullptr;
1727 nsCOMPtr<nsIMobileIdentityService> service =
1728 do_GetService("@mozilla.org/mobileidentity-service;1");
1729 if (!service) {
1730 aRv.Throw(NS_ERROR_FAILURE);
1731 return nullptr;
1734 JSContext *cx = nsContentUtils::GetCurrentJSContext();
1735 if (!cx) {
1736 aRv.Throw(NS_ERROR_FAILURE);
1737 return nullptr;
1740 JS::Rooted<JS::Value> optionsValue(cx);
1741 if (!ToJSValue(cx, aOptions, &optionsValue)) {
1742 aRv.Throw(NS_ERROR_FAILURE);
1743 return nullptr;
1746 nsCOMPtr<nsISupports> promise;
1747 aRv = service->GetMobileIdAssertion(mWindow,
1748 optionsValue,
1749 getter_AddRefs(promise));
1751 nsRefPtr<Promise> p = static_cast<Promise*>(promise.get());
1752 return p.forget();
1754 #endif // MOZ_B2G
1756 #ifdef MOZ_B2G_RIL
1758 MobileConnectionArray*
1759 Navigator::GetMozMobileConnections(ErrorResult& aRv)
1761 if (!mMobileConnections) {
1762 if (!mWindow) {
1763 aRv.Throw(NS_ERROR_UNEXPECTED);
1764 return nullptr;
1766 mMobileConnections = new MobileConnectionArray(mWindow);
1769 return mMobileConnections;
1772 CellBroadcast*
1773 Navigator::GetMozCellBroadcast(ErrorResult& aRv)
1775 if (!mCellBroadcast) {
1776 if (!mWindow) {
1777 aRv.Throw(NS_ERROR_UNEXPECTED);
1778 return nullptr;
1780 mCellBroadcast = CellBroadcast::Create(mWindow, aRv);
1783 return mCellBroadcast;
1786 Voicemail*
1787 Navigator::GetMozVoicemail(ErrorResult& aRv)
1789 if (!mVoicemail) {
1790 if (!mWindow) {
1791 aRv.Throw(NS_ERROR_UNEXPECTED);
1792 return nullptr;
1795 aRv = NS_NewVoicemail(mWindow, getter_AddRefs(mVoicemail));
1796 if (aRv.Failed()) {
1797 return nullptr;
1801 return mVoicemail;
1804 IccManager*
1805 Navigator::GetMozIccManager(ErrorResult& aRv)
1807 if (!mIccManager) {
1808 if (!mWindow) {
1809 aRv.Throw(NS_ERROR_UNEXPECTED);
1810 return nullptr;
1812 NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr);
1814 mIccManager = new IccManager(mWindow);
1817 return mIccManager;
1819 #endif // MOZ_B2G_RIL
1821 #ifdef MOZ_GAMEPAD
1822 void
1823 Navigator::GetGamepads(nsTArray<nsRefPtr<Gamepad> >& aGamepads,
1824 ErrorResult& aRv)
1826 if (!mWindow) {
1827 aRv.Throw(NS_ERROR_UNEXPECTED);
1828 return;
1830 NS_ENSURE_TRUE_VOID(mWindow->GetDocShell());
1831 nsGlobalWindow* win = static_cast<nsGlobalWindow*>(mWindow.get());
1832 win->SetHasGamepadEventListener(true);
1833 win->GetGamepads(aGamepads);
1835 #endif
1837 //*****************************************************************************
1838 // Navigator::nsIMozNavigatorNetwork
1839 //*****************************************************************************
1841 NS_IMETHODIMP
1842 Navigator::GetProperties(nsINetworkProperties** aProperties)
1844 ErrorResult rv;
1845 NS_IF_ADDREF(*aProperties = GetConnection(rv));
1846 return NS_OK;
1849 network::Connection*
1850 Navigator::GetConnection(ErrorResult& aRv)
1852 if (!mConnection) {
1853 if (!mWindow) {
1854 aRv.Throw(NS_ERROR_UNEXPECTED);
1855 return nullptr;
1857 mConnection = new network::Connection();
1858 mConnection->Init(mWindow);
1861 return mConnection;
1864 #ifdef MOZ_B2G_BT
1865 bluetooth::BluetoothManager*
1866 Navigator::GetMozBluetooth(ErrorResult& aRv)
1868 if (!mBluetooth) {
1869 if (!mWindow) {
1870 aRv.Throw(NS_ERROR_UNEXPECTED);
1871 return nullptr;
1873 mBluetooth = bluetooth::BluetoothManager::Create(mWindow);
1876 return mBluetooth;
1878 #endif //MOZ_B2G_BT
1880 nsresult
1881 Navigator::EnsureMessagesManager()
1883 if (mMessagesManager) {
1884 return NS_OK;
1887 NS_ENSURE_STATE(mWindow);
1889 nsresult rv;
1890 nsCOMPtr<nsIDOMNavigatorSystemMessages> messageManager =
1891 do_CreateInstance("@mozilla.org/system-message-manager;1", &rv);
1893 nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi =
1894 do_QueryInterface(messageManager);
1895 NS_ENSURE_TRUE(gpi, NS_ERROR_FAILURE);
1897 // We don't do anything with the return value.
1898 AutoJSContext cx;
1899 JS::Rooted<JS::Value> prop_val(cx);
1900 rv = gpi->Init(mWindow, &prop_val);
1901 NS_ENSURE_SUCCESS(rv, rv);
1903 mMessagesManager = messageManager.forget();
1905 return NS_OK;
1908 bool
1909 Navigator::MozHasPendingMessage(const nsAString& aType, ErrorResult& aRv)
1911 // The WebIDL binding is responsible for the pref check here.
1912 nsresult rv = EnsureMessagesManager();
1913 if (NS_FAILED(rv)) {
1914 aRv.Throw(rv);
1915 return false;
1918 bool result = false;
1919 rv = mMessagesManager->MozHasPendingMessage(aType, &result);
1920 if (NS_FAILED(rv)) {
1921 aRv.Throw(rv);
1922 return false;
1924 return result;
1927 void
1928 Navigator::MozSetMessageHandler(const nsAString& aType,
1929 systemMessageCallback* aCallback,
1930 ErrorResult& aRv)
1932 // The WebIDL binding is responsible for the pref check here.
1933 nsresult rv = EnsureMessagesManager();
1934 if (NS_FAILED(rv)) {
1935 aRv.Throw(rv);
1936 return;
1939 CallbackObjectHolder<systemMessageCallback, nsIDOMSystemMessageCallback>
1940 holder(aCallback);
1941 nsCOMPtr<nsIDOMSystemMessageCallback> callback = holder.ToXPCOMCallback();
1943 rv = mMessagesManager->MozSetMessageHandler(aType, callback);
1944 if (NS_FAILED(rv)) {
1945 aRv.Throw(rv);
1949 #ifdef MOZ_TIME_MANAGER
1950 time::TimeManager*
1951 Navigator::GetMozTime(ErrorResult& aRv)
1953 if (!mWindow) {
1954 aRv.Throw(NS_ERROR_UNEXPECTED);
1955 return nullptr;
1958 if (!mTimeManager) {
1959 mTimeManager = new time::TimeManager(mWindow);
1962 return mTimeManager;
1964 #endif
1966 nsDOMCameraManager*
1967 Navigator::GetMozCameras(ErrorResult& aRv)
1969 if (!mCameraManager) {
1970 if (!mWindow ||
1971 !mWindow->GetOuterWindow() ||
1972 mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) {
1973 aRv.Throw(NS_ERROR_NOT_AVAILABLE);
1974 return nullptr;
1977 mCameraManager = nsDOMCameraManager::CreateInstance(mWindow);
1980 return mCameraManager;
1983 already_AddRefed<ServiceWorkerContainer>
1984 Navigator::ServiceWorker()
1986 MOZ_ASSERT(mWindow);
1988 if (!mServiceWorkerContainer) {
1989 mServiceWorkerContainer = new ServiceWorkerContainer(mWindow);
1992 nsRefPtr<ServiceWorkerContainer> ref = mServiceWorkerContainer;
1993 return ref.forget();
1996 size_t
1997 Navigator::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
1999 size_t n = aMallocSizeOf(this);
2001 // TODO: add SizeOfIncludingThis() to nsMimeTypeArray, bug 674113.
2002 // TODO: add SizeOfIncludingThis() to nsPluginArray, bug 674114.
2003 // TODO: add SizeOfIncludingThis() to Geolocation, bug 674115.
2004 // TODO: add SizeOfIncludingThis() to DesktopNotificationCenter, bug 674116.
2006 return n;
2009 void
2010 Navigator::SetWindow(nsPIDOMWindow *aInnerWindow)
2012 NS_ASSERTION(aInnerWindow->IsInnerWindow(),
2013 "Navigator must get an inner window!");
2014 mWindow = aInnerWindow;
2017 void
2018 Navigator::OnNavigation()
2020 if (!mWindow) {
2021 return;
2024 #ifdef MOZ_MEDIA_NAVIGATOR
2025 // Inform MediaManager in case there are live streams or pending callbacks.
2026 MediaManager *manager = MediaManager::Get();
2027 if (manager) {
2028 manager->OnNavigation(mWindow->WindowID());
2030 #endif
2031 if (mCameraManager) {
2032 mCameraManager->OnNavigation(mWindow->WindowID());
2036 bool
2037 Navigator::CheckPermission(const char* type)
2039 return CheckPermission(mWindow, type);
2042 /* static */
2043 bool
2044 Navigator::CheckPermission(nsPIDOMWindow* aWindow, const char* aType)
2046 if (!aWindow) {
2047 return false;
2050 nsCOMPtr<nsIPermissionManager> permMgr =
2051 services::GetPermissionManager();
2052 NS_ENSURE_TRUE(permMgr, false);
2054 uint32_t permission = nsIPermissionManager::DENY_ACTION;
2055 permMgr->TestPermissionFromWindow(aWindow, aType, &permission);
2056 return permission == nsIPermissionManager::ALLOW_ACTION;
2059 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
2060 system::AudioChannelManager*
2061 Navigator::GetMozAudioChannelManager(ErrorResult& aRv)
2063 if (!mAudioChannelManager) {
2064 if (!mWindow) {
2065 aRv.Throw(NS_ERROR_UNEXPECTED);
2066 return nullptr;
2068 mAudioChannelManager = new system::AudioChannelManager();
2069 mAudioChannelManager->Init(mWindow);
2072 return mAudioChannelManager;
2074 #endif
2076 bool
2077 Navigator::DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
2078 JS::Handle<jsid> aId,
2079 JS::MutableHandle<JSPropertyDescriptor> aDesc)
2081 if (!JSID_IS_STRING(aId)) {
2082 return true;
2085 nsScriptNameSpaceManager* nameSpaceManager = GetNameSpaceManager();
2086 if (!nameSpaceManager) {
2087 return Throw(aCx, NS_ERROR_NOT_INITIALIZED);
2090 nsAutoJSString name;
2091 if (!name.init(aCx, JSID_TO_STRING(aId))) {
2092 return false;
2095 const nsGlobalNameStruct* name_struct =
2096 nameSpaceManager->LookupNavigatorName(name);
2097 if (!name_struct) {
2098 return true;
2101 JS::Rooted<JSObject*> naviObj(aCx,
2102 js::CheckedUnwrap(aObject,
2103 /* stopAtOuter = */ false));
2104 if (!naviObj) {
2105 return Throw(aCx, NS_ERROR_DOM_SECURITY_ERR);
2108 if (name_struct->mType == nsGlobalNameStruct::eTypeNewDOMBinding) {
2109 ConstructNavigatorProperty construct = name_struct->mConstructNavigatorProperty;
2110 MOZ_ASSERT(construct);
2112 JS::Rooted<JSObject*> domObject(aCx);
2114 // Make sure to do the creation of our object in the compartment
2115 // of naviObj, especially since we plan to cache that object.
2116 JSAutoCompartment ac(aCx, naviObj);
2118 // Check whether our constructor is enabled after we unwrap Xrays, since
2119 // we don't want to define an interface on the Xray if it's disabled in
2120 // the target global, even if it's enabled in the Xray's global.
2121 if (name_struct->mConstructorEnabled &&
2122 !(*name_struct->mConstructorEnabled)(aCx, naviObj)) {
2123 return true;
2126 if (name.EqualsLiteral("mozSettings")) {
2127 bool hasPermission = CheckPermission("settings-api-read") ||
2128 CheckPermission("settings-api-write");
2129 if (!hasPermission) {
2130 FillPropertyDescriptor(aDesc, aObject, JS::NullValue(), false);
2131 return true;
2135 if (name.EqualsLiteral("mozDownloadManager")) {
2136 if (!CheckPermission("downloads")) {
2137 FillPropertyDescriptor(aDesc, aObject, JS::NullValue(), false);
2138 return true;
2142 nsISupports* existingObject = mCachedResolveResults.GetWeak(name);
2143 if (existingObject) {
2144 // We know all of our WebIDL objects here are wrappercached, so just go
2145 // ahead and WrapObject() them. We can't use WrapNewBindingObject,
2146 // because we don't have the concrete type.
2147 JS::Rooted<JS::Value> wrapped(aCx);
2148 if (!dom::WrapObject(aCx, existingObject, &wrapped)) {
2149 return false;
2151 domObject = &wrapped.toObject();
2152 } else {
2153 domObject = construct(aCx, naviObj);
2154 if (!domObject) {
2155 return Throw(aCx, NS_ERROR_FAILURE);
2158 // Store the value in our cache
2159 nsISupports* native = UnwrapDOMObjectToISupports(domObject);
2160 MOZ_ASSERT(native);
2161 mCachedResolveResults.Put(name, native);
2165 if (!JS_WrapObject(aCx, &domObject)) {
2166 return false;
2169 FillPropertyDescriptor(aDesc, aObject, JS::ObjectValue(*domObject), false);
2170 return true;
2173 NS_ASSERTION(name_struct->mType == nsGlobalNameStruct::eTypeNavigatorProperty,
2174 "unexpected type");
2176 nsresult rv = NS_OK;
2178 nsCOMPtr<nsISupports> native;
2179 bool hadCachedNative = mCachedResolveResults.Get(name, getter_AddRefs(native));
2180 bool okToUseNative;
2181 JS::Rooted<JS::Value> prop_val(aCx);
2182 if (hadCachedNative) {
2183 okToUseNative = true;
2184 } else {
2185 native = do_CreateInstance(name_struct->mCID, &rv);
2186 if (NS_FAILED(rv)) {
2187 return Throw(aCx, rv);
2190 nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi(do_QueryInterface(native));
2192 if (gpi) {
2193 if (!mWindow) {
2194 return Throw(aCx, NS_ERROR_UNEXPECTED);
2197 rv = gpi->Init(mWindow, &prop_val);
2198 if (NS_FAILED(rv)) {
2199 return Throw(aCx, rv);
2203 okToUseNative = !prop_val.isObjectOrNull();
2206 if (okToUseNative) {
2207 // Make sure to do the creation of our object in the compartment
2208 // of naviObj, especially since we plan to cache that object.
2209 JSAutoCompartment ac(aCx, naviObj);
2211 rv = nsContentUtils::WrapNative(aCx, native, &prop_val);
2213 if (NS_FAILED(rv)) {
2214 return Throw(aCx, rv);
2217 // Now that we know we managed to wrap this thing properly, go ahead and
2218 // cache it as needed.
2219 if (!hadCachedNative) {
2220 mCachedResolveResults.Put(name, native);
2224 if (!JS_WrapValue(aCx, &prop_val)) {
2225 return Throw(aCx, NS_ERROR_UNEXPECTED);
2228 FillPropertyDescriptor(aDesc, aObject, prop_val, false);
2229 return true;
2232 struct NavigatorNameEnumeratorClosure
2234 NavigatorNameEnumeratorClosure(JSContext* aCx, JSObject* aWrapper,
2235 nsTArray<nsString>& aNames)
2236 : mCx(aCx),
2237 mWrapper(aCx, aWrapper),
2238 mNames(aNames)
2242 JSContext* mCx;
2243 JS::Rooted<JSObject*> mWrapper;
2244 nsTArray<nsString>& mNames;
2247 static PLDHashOperator
2248 SaveNavigatorName(const nsAString& aName,
2249 const nsGlobalNameStruct& aNameStruct,
2250 void* aClosure)
2252 NavigatorNameEnumeratorClosure* closure =
2253 static_cast<NavigatorNameEnumeratorClosure*>(aClosure);
2254 if (!aNameStruct.mConstructorEnabled ||
2255 aNameStruct.mConstructorEnabled(closure->mCx, closure->mWrapper)) {
2256 closure->mNames.AppendElement(aName);
2258 return PL_DHASH_NEXT;
2261 void
2262 Navigator::GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames,
2263 ErrorResult& aRv)
2265 nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
2266 if (!nameSpaceManager) {
2267 NS_ERROR("Can't get namespace manager.");
2268 aRv.Throw(NS_ERROR_UNEXPECTED);
2269 return;
2272 NavigatorNameEnumeratorClosure closure(aCx, GetWrapper(), aNames);
2273 nameSpaceManager->EnumerateNavigatorNames(SaveNavigatorName, &closure);
2276 JSObject*
2277 Navigator::WrapObject(JSContext* cx)
2279 return NavigatorBinding::Wrap(cx, this);
2282 /* static */
2283 bool
2284 Navigator::HasWakeLockSupport(JSContext* /* unused*/, JSObject* /*unused */)
2286 nsCOMPtr<nsIPowerManagerService> pmService =
2287 do_GetService(POWERMANAGERSERVICE_CONTRACTID);
2288 // No service means no wake lock support
2289 return !!pmService;
2292 /* static */
2293 bool
2294 Navigator::HasCameraSupport(JSContext* /* unused */, JSObject* aGlobal)
2296 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2297 return win && nsDOMCameraManager::CheckPermission(win);
2300 /* static */
2301 bool
2302 Navigator::HasWifiManagerSupport(JSContext* /* unused */,
2303 JSObject* aGlobal)
2305 // On XBL scope, the global object is NOT |window|. So we have
2306 // to use nsContentUtils::GetObjectPrincipal to get the principal
2307 // and test directly with permission manager.
2309 nsIPrincipal* principal = nsContentUtils::ObjectPrincipal(aGlobal);
2311 nsCOMPtr<nsIPermissionManager> permMgr =
2312 services::GetPermissionManager();
2313 NS_ENSURE_TRUE(permMgr, false);
2315 uint32_t permission = nsIPermissionManager::DENY_ACTION;
2316 permMgr->TestPermissionFromPrincipal(principal, "wifi-manage", &permission);
2317 return nsIPermissionManager::ALLOW_ACTION == permission;
2320 #ifdef MOZ_NFC
2321 /* static */
2322 bool
2323 Navigator::HasNFCSupport(JSContext* /* unused */, JSObject* aGlobal)
2325 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2327 // Do not support NFC if NFC content helper does not exist.
2328 nsCOMPtr<nsISupports> contentHelper = do_GetService("@mozilla.org/nfc/content-helper;1");
2329 return !!contentHelper;
2331 #endif // MOZ_NFC
2333 #ifdef MOZ_MEDIA_NAVIGATOR
2334 /* static */
2335 bool
2336 Navigator::HasUserMediaSupport(JSContext* /* unused */,
2337 JSObject* /* unused */)
2339 // Make enabling peerconnection enable getUserMedia() as well
2340 return Preferences::GetBool("media.navigator.enabled", false) ||
2341 Preferences::GetBool("media.peerconnection.enabled", false);
2343 #endif // MOZ_MEDIA_NAVIGATOR
2345 /* static */
2346 bool
2347 Navigator::HasInputMethodSupport(JSContext* /* unused */,
2348 JSObject* aGlobal)
2350 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2351 if (!win || !Preferences::GetBool("dom.mozInputMethod.enabled", false)) {
2352 return false;
2355 if (Preferences::GetBool("dom.mozInputMethod.testing", false)) {
2356 return true;
2359 return CheckPermission(win, "input") ||
2360 CheckPermission(win, "input-manage");
2363 /* static */
2364 bool
2365 Navigator::HasDataStoreSupport(nsIPrincipal* aPrincipal)
2367 workers::AssertIsOnMainThread();
2369 return DataStoreService::CheckPermission(aPrincipal);
2372 // A WorkerMainThreadRunnable to synchronously dispatch the call of
2373 // HasDataStoreSupport() from the worker thread to the main thread.
2374 class HasDataStoreSupportRunnable MOZ_FINAL
2375 : public workers::WorkerMainThreadRunnable
2377 public:
2378 bool mResult;
2380 explicit HasDataStoreSupportRunnable(workers::WorkerPrivate* aWorkerPrivate)
2381 : workers::WorkerMainThreadRunnable(aWorkerPrivate)
2382 , mResult(false)
2384 MOZ_ASSERT(aWorkerPrivate);
2385 aWorkerPrivate->AssertIsOnWorkerThread();
2388 protected:
2389 virtual bool
2390 MainThreadRun() MOZ_OVERRIDE
2392 workers::AssertIsOnMainThread();
2394 mResult = Navigator::HasDataStoreSupport(mWorkerPrivate->GetPrincipal());
2396 return true;
2400 /* static */
2401 bool
2402 Navigator::HasDataStoreSupport(JSContext* aCx, JSObject* aGlobal)
2404 // If the caller is on the worker thread, dispatch this to the main thread.
2405 if (!NS_IsMainThread()) {
2406 workers::WorkerPrivate* workerPrivate =
2407 workers::GetWorkerPrivateFromContext(aCx);
2408 workerPrivate->AssertIsOnWorkerThread();
2410 nsRefPtr<HasDataStoreSupportRunnable> runnable =
2411 new HasDataStoreSupportRunnable(workerPrivate);
2412 runnable->Dispatch(aCx);
2414 return runnable->mResult;
2417 workers::AssertIsOnMainThread();
2419 JS::Rooted<JSObject*> global(aCx, aGlobal);
2421 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(global);
2422 if (!win) {
2423 return false;
2426 nsIDocument* doc = win->GetExtantDoc();
2427 if (!doc || !doc->NodePrincipal()) {
2428 return false;
2431 return HasDataStoreSupport(doc->NodePrincipal());
2434 #ifdef MOZ_B2G
2435 /* static */
2436 bool
2437 Navigator::HasMobileIdSupport(JSContext* aCx, JSObject* aGlobal)
2439 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2440 if (!win) {
2441 return false;
2444 nsIDocument* doc = win->GetExtantDoc();
2445 if (!doc) {
2446 return false;
2449 nsIPrincipal* principal = doc->NodePrincipal();
2451 nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
2452 NS_ENSURE_TRUE(permMgr, false);
2454 uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION;
2455 permMgr->TestPermissionFromPrincipal(principal, "mobileid", &permission);
2456 return permission == nsIPermissionManager::PROMPT_ACTION ||
2457 permission == nsIPermissionManager::ALLOW_ACTION;
2459 #endif
2461 /* static */
2462 already_AddRefed<nsPIDOMWindow>
2463 Navigator::GetWindowFromGlobal(JSObject* aGlobal)
2465 nsCOMPtr<nsPIDOMWindow> win =
2466 do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(aGlobal));
2467 MOZ_ASSERT(!win || win->IsInnerWindow());
2468 return win.forget();
2471 nsresult
2472 Navigator::GetPlatform(nsAString& aPlatform, bool aUsePrefOverriddenValue)
2474 MOZ_ASSERT(NS_IsMainThread());
2476 if (aUsePrefOverriddenValue && !nsContentUtils::IsCallerChrome()) {
2477 const nsAdoptingString& override =
2478 mozilla::Preferences::GetString("general.platform.override");
2480 if (override) {
2481 aPlatform = override;
2482 return NS_OK;
2486 nsresult rv;
2488 nsCOMPtr<nsIHttpProtocolHandler>
2489 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
2490 NS_ENSURE_SUCCESS(rv, rv);
2492 // Sorry for the #if platform ugliness, but Communicator is likewise
2493 // hardcoded and we are seeking backward compatibility here (bug 47080).
2494 #if defined(_WIN64)
2495 aPlatform.AssignLiteral("Win64");
2496 #elif defined(WIN32)
2497 aPlatform.AssignLiteral("Win32");
2498 #elif defined(XP_MACOSX) && defined(__ppc__)
2499 aPlatform.AssignLiteral("MacPPC");
2500 #elif defined(XP_MACOSX) && defined(__i386__)
2501 aPlatform.AssignLiteral("MacIntel");
2502 #elif defined(XP_MACOSX) && defined(__x86_64__)
2503 aPlatform.AssignLiteral("MacIntel");
2504 #else
2505 // XXX Communicator uses compiled-in build-time string defines
2506 // to indicate the platform it was compiled *for*, not what it is
2507 // currently running *on* which is what this does.
2508 nsAutoCString plat;
2509 rv = service->GetOscpu(plat);
2510 CopyASCIItoUTF16(plat, aPlatform);
2511 #endif
2513 return rv;
2516 /* static */ nsresult
2517 Navigator::GetAppVersion(nsAString& aAppVersion, bool aUsePrefOverriddenValue)
2519 MOZ_ASSERT(NS_IsMainThread());
2521 if (aUsePrefOverriddenValue && !nsContentUtils::IsCallerChrome()) {
2522 const nsAdoptingString& override =
2523 mozilla::Preferences::GetString("general.appversion.override");
2525 if (override) {
2526 aAppVersion = override;
2527 return NS_OK;
2531 nsresult rv;
2533 nsCOMPtr<nsIHttpProtocolHandler>
2534 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
2535 NS_ENSURE_SUCCESS(rv, rv);
2537 nsAutoCString str;
2538 rv = service->GetAppVersion(str);
2539 CopyASCIItoUTF16(str, aAppVersion);
2540 NS_ENSURE_SUCCESS(rv, rv);
2542 aAppVersion.AppendLiteral(" (");
2544 rv = service->GetPlatform(str);
2545 NS_ENSURE_SUCCESS(rv, rv);
2547 AppendASCIItoUTF16(str, aAppVersion);
2548 aAppVersion.Append(char16_t(')'));
2550 return rv;
2553 /* static */ void
2554 Navigator::AppName(nsAString& aAppName, bool aUsePrefOverriddenValue)
2556 MOZ_ASSERT(NS_IsMainThread());
2558 if (aUsePrefOverriddenValue && !nsContentUtils::IsCallerChrome()) {
2559 const nsAdoptingString& override =
2560 mozilla::Preferences::GetString("general.appname.override");
2562 if (override) {
2563 aAppName = override;
2564 return;
2568 aAppName.AssignLiteral("Netscape");
2571 nsresult
2572 Navigator::GetUserAgent(nsPIDOMWindow* aWindow, nsIURI* aURI,
2573 bool aIsCallerChrome,
2574 nsAString& aUserAgent)
2576 MOZ_ASSERT(NS_IsMainThread());
2578 if (!aIsCallerChrome) {
2579 const nsAdoptingString& override =
2580 mozilla::Preferences::GetString("general.useragent.override");
2582 if (override) {
2583 aUserAgent = override;
2584 return NS_OK;
2588 nsresult rv;
2589 nsCOMPtr<nsIHttpProtocolHandler>
2590 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
2591 if (NS_WARN_IF(NS_FAILED(rv))) {
2592 return rv;
2595 nsAutoCString ua;
2596 rv = service->GetUserAgent(ua);
2597 if (NS_WARN_IF(NS_FAILED(rv))) {
2598 return rv;
2601 CopyASCIItoUTF16(ua, aUserAgent);
2603 if (!aWindow || !aURI) {
2604 return NS_OK;
2607 MOZ_ASSERT(aWindow->GetDocShell());
2609 nsCOMPtr<nsISiteSpecificUserAgent> siteSpecificUA =
2610 do_GetService("@mozilla.org/dom/site-specific-user-agent;1");
2611 if (!siteSpecificUA) {
2612 return NS_OK;
2615 return siteSpecificUA->GetUserAgentForURIAndWindow(aURI, aWindow, aUserAgent);
2618 } // namespace dom
2619 } // namespace mozilla