michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set sw=2 ts=2 et tw=78: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: // Needs to be first. michael@0: #include "base/basictypes.h" michael@0: michael@0: #include "Navigator.h" michael@0: #include "nsIXULAppInfo.h" michael@0: #include "nsPluginArray.h" michael@0: #include "nsMimeTypeArray.h" michael@0: #include "mozilla/MemoryReporting.h" michael@0: #include "mozilla/dom/DesktopNotification.h" michael@0: #include "nsGeolocation.h" michael@0: #include "nsIHttpProtocolHandler.h" michael@0: #include "nsIContentPolicy.h" michael@0: #include "nsIContentSecurityPolicy.h" michael@0: #include "nsContentPolicyUtils.h" michael@0: #include "nsCrossSiteListenerProxy.h" michael@0: #include "nsISupportsPriority.h" michael@0: #include "nsICachingChannel.h" michael@0: #include "nsIWebContentHandlerRegistrar.h" michael@0: #include "nsICookiePermission.h" michael@0: #include "nsIScriptSecurityManager.h" michael@0: #include "nsCharSeparatedTokenizer.h" michael@0: #include "nsContentUtils.h" michael@0: #include "nsUnicharUtils.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "mozilla/Telemetry.h" michael@0: #include "BatteryManager.h" michael@0: #include "mozilla/dom/PowerManager.h" michael@0: #include "mozilla/dom/WakeLock.h" michael@0: #include "mozilla/dom/power/PowerManagerService.h" michael@0: #include "mozilla/dom/MobileMessageManager.h" michael@0: #include "mozilla/dom/Telephony.h" michael@0: #include "mozilla/Hal.h" michael@0: #include "nsISiteSpecificUserAgent.h" michael@0: #include "mozilla/ClearOnShutdown.h" michael@0: #include "mozilla/StaticPtr.h" michael@0: #include "Connection.h" michael@0: #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent() michael@0: #include "nsGlobalWindow.h" michael@0: #ifdef MOZ_B2G_RIL michael@0: #include "mozilla/dom/IccManager.h" michael@0: #include "mozilla/dom/CellBroadcast.h" michael@0: #include "mozilla/dom/MobileConnectionArray.h" michael@0: #include "mozilla/dom/Voicemail.h" michael@0: #endif michael@0: #include "nsIIdleObserver.h" michael@0: #include "nsIPermissionManager.h" michael@0: #include "nsMimeTypes.h" michael@0: #include "nsNetUtil.h" michael@0: #include "nsIHttpChannel.h" michael@0: #include "nsIHttpChannelInternal.h" michael@0: #include "TimeManager.h" michael@0: #include "DeviceStorage.h" michael@0: #include "nsIDOMNavigatorSystemMessages.h" michael@0: #include "nsStreamUtils.h" michael@0: #include "nsIAppsService.h" michael@0: #include "mozIApplication.h" michael@0: #include "WidgetUtils.h" michael@0: #include "mozIThirdPartyUtil.h" michael@0: #include "nsChannelPolicy.h" michael@0: michael@0: #ifdef MOZ_MEDIA_NAVIGATOR michael@0: #include "MediaManager.h" michael@0: #endif michael@0: #ifdef MOZ_B2G_BT michael@0: #include "BluetoothManager.h" michael@0: #endif michael@0: #include "DOMCameraManager.h" michael@0: michael@0: #ifdef MOZ_AUDIO_CHANNEL_MANAGER michael@0: #include "AudioChannelManager.h" michael@0: #endif michael@0: michael@0: #ifdef MOZ_B2G_FM michael@0: #include "mozilla/dom/FMRadio.h" michael@0: #endif michael@0: michael@0: #include "nsIDOMGlobalPropertyInitializer.h" michael@0: #include "nsIDataStoreService.h" michael@0: #include "nsJSUtils.h" michael@0: michael@0: #include "nsScriptNameSpaceManager.h" michael@0: michael@0: #include "mozilla/dom/NavigatorBinding.h" michael@0: #include "mozilla/dom/Promise.h" michael@0: michael@0: #include "nsIUploadChannel2.h" michael@0: #include "nsFormData.h" michael@0: #include "nsIPrivateBrowsingChannel.h" michael@0: #include "nsIDocShell.h" michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: static bool sDoNotTrackEnabled = false; michael@0: static bool sVibratorEnabled = false; michael@0: static uint32_t sMaxVibrateMS = 0; michael@0: static uint32_t sMaxVibrateListLen = 0; michael@0: michael@0: /* static */ michael@0: void michael@0: Navigator::Init() michael@0: { michael@0: Preferences::AddBoolVarCache(&sDoNotTrackEnabled, michael@0: "privacy.donottrackheader.enabled", michael@0: false); michael@0: Preferences::AddBoolVarCache(&sVibratorEnabled, michael@0: "dom.vibrator.enabled", true); michael@0: Preferences::AddUintVarCache(&sMaxVibrateMS, michael@0: "dom.vibrator.max_vibrate_ms", 10000); michael@0: Preferences::AddUintVarCache(&sMaxVibrateListLen, michael@0: "dom.vibrator.max_vibrate_list_len", 128); michael@0: } michael@0: michael@0: Navigator::Navigator(nsPIDOMWindow* aWindow) michael@0: : mWindow(aWindow) michael@0: { michael@0: MOZ_ASSERT(aWindow->IsInnerWindow(), "Navigator must get an inner window!"); michael@0: SetIsDOMBinding(); michael@0: } michael@0: michael@0: Navigator::~Navigator() michael@0: { michael@0: Invalidate(); michael@0: } michael@0: michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Navigator) michael@0: NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY michael@0: NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMNavigator) michael@0: NS_INTERFACE_MAP_ENTRY(nsIDOMNavigator) michael@0: NS_INTERFACE_MAP_ENTRY(nsIMozNavigatorNetwork) michael@0: NS_INTERFACE_MAP_END michael@0: michael@0: NS_IMPL_CYCLE_COLLECTING_ADDREF(Navigator) michael@0: NS_IMPL_CYCLE_COLLECTING_RELEASE(Navigator) michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_CLASS(Navigator) michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Navigator) michael@0: tmp->Invalidate(); michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow) michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedResolveResults) michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_END michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlugins) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMimeTypes) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGeolocation) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotification) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryManager) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPowerManager) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileMessageManager) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTelephony) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection) michael@0: #ifdef MOZ_B2G_RIL michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileConnections) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCellBroadcast) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIccManager) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVoicemail) michael@0: #endif michael@0: #ifdef MOZ_B2G_BT michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBluetooth) michael@0: #endif michael@0: #ifdef MOZ_AUDIO_CHANNEL_MANAGER michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioChannelManager) michael@0: #endif michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCameraManager) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessagesManager) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDeviceStorageStores) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTimeManager) michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedResolveResults) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(Navigator) michael@0: michael@0: void michael@0: Navigator::Invalidate() michael@0: { michael@0: // Don't clear mWindow here so we know we've got a non-null mWindow michael@0: // until we're unlinked. michael@0: michael@0: if (mPlugins) { michael@0: mPlugins->Invalidate(); michael@0: mPlugins = nullptr; michael@0: } michael@0: michael@0: mMimeTypes = nullptr; michael@0: michael@0: // If there is a page transition, make sure delete the geolocation object. michael@0: if (mGeolocation) { michael@0: mGeolocation->Shutdown(); michael@0: mGeolocation = nullptr; michael@0: } michael@0: michael@0: if (mNotification) { michael@0: mNotification->Shutdown(); michael@0: mNotification = nullptr; michael@0: } michael@0: michael@0: if (mBatteryManager) { michael@0: mBatteryManager->Shutdown(); michael@0: mBatteryManager = nullptr; michael@0: } michael@0: michael@0: #ifdef MOZ_B2G_FM michael@0: if (mFMRadio) { michael@0: mFMRadio->Shutdown(); michael@0: mFMRadio = nullptr; michael@0: } michael@0: #endif michael@0: michael@0: if (mPowerManager) { michael@0: mPowerManager->Shutdown(); michael@0: mPowerManager = nullptr; michael@0: } michael@0: michael@0: if (mMobileMessageManager) { michael@0: mMobileMessageManager->Shutdown(); michael@0: mMobileMessageManager = nullptr; michael@0: } michael@0: michael@0: if (mTelephony) { michael@0: mTelephony = nullptr; michael@0: } michael@0: michael@0: if (mConnection) { michael@0: mConnection->Shutdown(); michael@0: mConnection = nullptr; michael@0: } michael@0: michael@0: #ifdef MOZ_B2G_RIL michael@0: if (mMobileConnections) { michael@0: mMobileConnections = nullptr; michael@0: } michael@0: michael@0: if (mCellBroadcast) { michael@0: mCellBroadcast = nullptr; michael@0: } michael@0: michael@0: if (mIccManager) { michael@0: mIccManager->Shutdown(); michael@0: mIccManager = nullptr; michael@0: } michael@0: michael@0: if (mVoicemail) { michael@0: mVoicemail = nullptr; michael@0: } michael@0: #endif michael@0: michael@0: #ifdef MOZ_B2G_BT michael@0: if (mBluetooth) { michael@0: mBluetooth = nullptr; michael@0: } michael@0: #endif michael@0: michael@0: mCameraManager = nullptr; michael@0: michael@0: if (mMessagesManager) { michael@0: mMessagesManager = nullptr; michael@0: } michael@0: michael@0: #ifdef MOZ_AUDIO_CHANNEL_MANAGER michael@0: if (mAudioChannelManager) { michael@0: mAudioChannelManager = nullptr; michael@0: } michael@0: #endif michael@0: michael@0: uint32_t len = mDeviceStorageStores.Length(); michael@0: for (uint32_t i = 0; i < len; ++i) { michael@0: mDeviceStorageStores[i]->Shutdown(); michael@0: } michael@0: mDeviceStorageStores.Clear(); michael@0: michael@0: if (mTimeManager) { michael@0: mTimeManager = nullptr; michael@0: } michael@0: } michael@0: michael@0: //***************************************************************************** michael@0: // Navigator::nsIDOMNavigator michael@0: //***************************************************************************** michael@0: michael@0: NS_IMETHODIMP michael@0: Navigator::GetUserAgent(nsAString& aUserAgent) michael@0: { michael@0: nsresult rv = NS_GetNavigatorUserAgent(aUserAgent); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: if (!mWindow || !mWindow->GetDocShell()) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsIDocument* doc = mWindow->GetExtantDoc(); michael@0: if (!doc) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsCOMPtr codebaseURI; michael@0: doc->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI)); michael@0: if (!codebaseURI) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsCOMPtr siteSpecificUA = michael@0: do_GetService("@mozilla.org/dom/site-specific-user-agent;1"); michael@0: NS_ENSURE_TRUE(siteSpecificUA, NS_OK); michael@0: michael@0: return siteSpecificUA->GetUserAgentForURIAndWindow(codebaseURI, mWindow, michael@0: aUserAgent); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: Navigator::GetAppCodeName(nsAString& aAppCodeName) michael@0: { michael@0: nsresult rv; michael@0: michael@0: nsCOMPtr michael@0: service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsAutoCString appName; michael@0: rv = service->GetAppName(appName); michael@0: CopyASCIItoUTF16(appName, aAppCodeName); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: Navigator::GetAppVersion(nsAString& aAppVersion) michael@0: { michael@0: return GetAppVersion(aAppVersion, /* aUsePrefOverriddenValue */ true); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: Navigator::GetAppName(nsAString& aAppName) michael@0: { michael@0: AppName(aAppName, /* aUsePrefOverriddenValue */ true); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /** michael@0: * JS property navigator.language, exposed to web content. michael@0: * Take first value from Accept-Languages (HTTP header), which is michael@0: * the "content language" freely set by the user in the Pref window. michael@0: * michael@0: * Do not use UI language (chosen app locale) here. michael@0: * See RFC 2616, Section 15.1.4 "Privacy Issues Connected to Accept Headers" michael@0: * michael@0: * "en", "en-US" and "i-cherokee" and "" are valid. michael@0: * Fallback in case of invalid pref should be "" (empty string), to michael@0: * let site do fallback, e.g. to site's local language. michael@0: */ michael@0: NS_IMETHODIMP michael@0: Navigator::GetLanguage(nsAString& aLanguage) michael@0: { michael@0: // E.g. "de-de, en-us,en". michael@0: const nsAdoptingString& acceptLang = michael@0: Preferences::GetLocalizedString("intl.accept_languages"); michael@0: michael@0: // Take everything before the first "," or ";", without trailing space. michael@0: nsCharSeparatedTokenizer langTokenizer(acceptLang, ','); michael@0: const nsSubstring &firstLangPart = langTokenizer.nextToken(); michael@0: nsCharSeparatedTokenizer qTokenizer(firstLangPart, ';'); michael@0: aLanguage.Assign(qTokenizer.nextToken()); michael@0: michael@0: // Checks and fixups: michael@0: // replace "_" with "-" to avoid POSIX/Windows "en_US" notation. michael@0: if (aLanguage.Length() > 2 && aLanguage[2] == char16_t('_')) { michael@0: aLanguage.Replace(2, 1, char16_t('-')); // TODO replace all michael@0: } michael@0: michael@0: // Use uppercase for country part, e.g. "en-US", not "en-us", see BCP47 michael@0: // only uppercase 2-letter country codes, not "zh-Hant", "de-DE-x-goethe". michael@0: if (aLanguage.Length() <= 2) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsCharSeparatedTokenizer localeTokenizer(aLanguage, '-'); michael@0: int32_t pos = 0; michael@0: bool first = true; michael@0: while (localeTokenizer.hasMoreTokens()) { michael@0: const nsSubstring& code = localeTokenizer.nextToken(); michael@0: michael@0: if (code.Length() == 2 && !first) { michael@0: nsAutoString upper(code); michael@0: ToUpperCase(upper); michael@0: aLanguage.Replace(pos, code.Length(), upper); michael@0: } michael@0: michael@0: pos += code.Length() + 1; // 1 is the separator michael@0: first = false; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: Navigator::GetPlatform(nsAString& aPlatform) michael@0: { michael@0: return GetPlatform(aPlatform, /* aUsePrefOverriddenValue */ true); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: Navigator::GetOscpu(nsAString& aOSCPU) michael@0: { michael@0: if (!nsContentUtils::IsCallerChrome()) { michael@0: const nsAdoptingString& override = michael@0: Preferences::GetString("general.oscpu.override"); michael@0: michael@0: if (override) { michael@0: aOSCPU = override; michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: nsresult rv; michael@0: michael@0: nsCOMPtr michael@0: service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsAutoCString oscpu; michael@0: rv = service->GetOscpu(oscpu); michael@0: CopyASCIItoUTF16(oscpu, aOSCPU); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: Navigator::GetVendor(nsAString& aVendor) michael@0: { michael@0: aVendor.Truncate(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: Navigator::GetVendorSub(nsAString& aVendorSub) michael@0: { michael@0: aVendorSub.Truncate(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: Navigator::GetProduct(nsAString& aProduct) michael@0: { michael@0: aProduct.AssignLiteral("Gecko"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: Navigator::GetProductSub(nsAString& aProductSub) michael@0: { michael@0: // Legacy build ID hardcoded for backward compatibility (bug 776376) michael@0: aProductSub.AssignLiteral("20100101"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsMimeTypeArray* michael@0: Navigator::GetMimeTypes(ErrorResult& aRv) michael@0: { michael@0: if (!mMimeTypes) { michael@0: if (!mWindow) { michael@0: aRv.Throw(NS_ERROR_UNEXPECTED); michael@0: return nullptr; michael@0: } michael@0: mMimeTypes = new nsMimeTypeArray(mWindow); michael@0: } michael@0: michael@0: return mMimeTypes; michael@0: } michael@0: michael@0: nsPluginArray* michael@0: Navigator::GetPlugins(ErrorResult& aRv) michael@0: { michael@0: if (!mPlugins) { michael@0: if (!mWindow) { michael@0: aRv.Throw(NS_ERROR_UNEXPECTED); michael@0: return nullptr; michael@0: } michael@0: mPlugins = new nsPluginArray(mWindow); michael@0: mPlugins->Init(); michael@0: } michael@0: michael@0: return mPlugins; michael@0: } michael@0: michael@0: // Values for the network.cookie.cookieBehavior pref are documented in michael@0: // nsCookieService.cpp. michael@0: #define COOKIE_BEHAVIOR_REJECT 2 michael@0: michael@0: bool michael@0: Navigator::CookieEnabled() michael@0: { michael@0: bool cookieEnabled = michael@0: (Preferences::GetInt("network.cookie.cookieBehavior", michael@0: COOKIE_BEHAVIOR_REJECT) != COOKIE_BEHAVIOR_REJECT); michael@0: michael@0: // Check whether an exception overrides the global cookie behavior michael@0: // Note that the code for getting the URI here matches that in michael@0: // nsHTMLDocument::SetCookie. michael@0: if (!mWindow || !mWindow->GetDocShell()) { michael@0: return cookieEnabled; michael@0: } michael@0: michael@0: nsCOMPtr doc = mWindow->GetExtantDoc(); michael@0: if (!doc) { michael@0: return cookieEnabled; michael@0: } michael@0: michael@0: nsCOMPtr codebaseURI; michael@0: doc->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI)); michael@0: michael@0: if (!codebaseURI) { michael@0: // Not a codebase, so technically can't set cookies, but let's michael@0: // just return the default value. michael@0: return cookieEnabled; michael@0: } michael@0: michael@0: nsCOMPtr permMgr = michael@0: do_GetService(NS_COOKIEPERMISSION_CONTRACTID); michael@0: NS_ENSURE_TRUE(permMgr, cookieEnabled); michael@0: michael@0: // Pass null for the channel, just like the cookie service does. michael@0: nsCookieAccess access; michael@0: nsresult rv = permMgr->CanAccess(codebaseURI, nullptr, &access); michael@0: NS_ENSURE_SUCCESS(rv, cookieEnabled); michael@0: michael@0: if (access != nsICookiePermission::ACCESS_DEFAULT) { michael@0: cookieEnabled = access != nsICookiePermission::ACCESS_DENY; michael@0: } michael@0: michael@0: return cookieEnabled; michael@0: } michael@0: michael@0: bool michael@0: Navigator::OnLine() michael@0: { michael@0: return !NS_IsOffline(); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: Navigator::GetBuildID(nsAString& aBuildID) michael@0: { michael@0: if (!nsContentUtils::IsCallerChrome()) { michael@0: const nsAdoptingString& override = michael@0: Preferences::GetString("general.buildID.override"); michael@0: michael@0: if (override) { michael@0: aBuildID = override; michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: nsCOMPtr appInfo = michael@0: do_GetService("@mozilla.org/xre/app-info;1"); michael@0: if (!appInfo) { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: nsAutoCString buildID; michael@0: nsresult rv = appInfo->GetAppBuildID(buildID); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: michael@0: aBuildID.Truncate(); michael@0: AppendASCIItoUTF16(buildID, aBuildID); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: Navigator::GetDoNotTrack(nsAString &aResult) michael@0: { michael@0: if (sDoNotTrackEnabled) { michael@0: aResult.AssignLiteral("yes"); michael@0: } else { michael@0: aResult.AssignLiteral("unspecified"); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: Navigator::JavaEnabled(ErrorResult& aRv) michael@0: { michael@0: Telemetry::AutoTimer telemetryTimer; michael@0: michael@0: // Return true if we have a handler for the java mime michael@0: nsAdoptingString javaMIME = Preferences::GetString("plugin.java.mime"); michael@0: NS_ENSURE_TRUE(!javaMIME.IsEmpty(), false); michael@0: michael@0: if (!mMimeTypes) { michael@0: if (!mWindow) { michael@0: aRv.Throw(NS_ERROR_UNEXPECTED); michael@0: return false; michael@0: } michael@0: mMimeTypes = new nsMimeTypeArray(mWindow); michael@0: } michael@0: michael@0: RefreshMIMEArray(); michael@0: michael@0: nsMimeType *mimeType = mMimeTypes->NamedItem(javaMIME); michael@0: michael@0: return mimeType && mimeType->GetEnabledPlugin(); michael@0: } michael@0: michael@0: void michael@0: Navigator::RefreshMIMEArray() michael@0: { michael@0: if (mMimeTypes) { michael@0: mMimeTypes->Refresh(); michael@0: } michael@0: } michael@0: michael@0: bool michael@0: Navigator::HasDesktopNotificationSupport() michael@0: { michael@0: return Preferences::GetBool("notification.feature.enabled", false); michael@0: } michael@0: michael@0: namespace { michael@0: michael@0: class VibrateWindowListener : public nsIDOMEventListener michael@0: { michael@0: public: michael@0: VibrateWindowListener(nsIDOMWindow* aWindow, nsIDocument* aDocument) michael@0: { michael@0: mWindow = do_GetWeakReference(aWindow); michael@0: mDocument = do_GetWeakReference(aDocument); michael@0: michael@0: NS_NAMED_LITERAL_STRING(visibilitychange, "visibilitychange"); michael@0: aDocument->AddSystemEventListener(visibilitychange, michael@0: this, /* listener */ michael@0: true, /* use capture */ michael@0: false /* wants untrusted */); michael@0: } michael@0: michael@0: virtual ~VibrateWindowListener() michael@0: { michael@0: } michael@0: michael@0: void RemoveListener(); michael@0: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIDOMEVENTLISTENER michael@0: michael@0: private: michael@0: nsWeakPtr mWindow; michael@0: nsWeakPtr mDocument; michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(VibrateWindowListener, nsIDOMEventListener) michael@0: michael@0: StaticRefPtr gVibrateWindowListener; michael@0: michael@0: NS_IMETHODIMP michael@0: VibrateWindowListener::HandleEvent(nsIDOMEvent* aEvent) michael@0: { michael@0: nsCOMPtr doc = michael@0: do_QueryInterface(aEvent->InternalDOMEvent()->GetTarget()); michael@0: michael@0: if (!doc || doc->Hidden()) { michael@0: // It's important that we call CancelVibrate(), not Vibrate() with an michael@0: // empty list, because Vibrate() will fail if we're no longer focused, but michael@0: // CancelVibrate() will succeed, so long as nobody else has started a new michael@0: // vibration pattern. michael@0: nsCOMPtr window = do_QueryReferent(mWindow); michael@0: hal::CancelVibrate(window); michael@0: RemoveListener(); michael@0: gVibrateWindowListener = nullptr; michael@0: // Careful: The line above might have deleted |this|! michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: VibrateWindowListener::RemoveListener() michael@0: { michael@0: nsCOMPtr target = do_QueryReferent(mDocument); michael@0: if (!target) { michael@0: return; michael@0: } michael@0: NS_NAMED_LITERAL_STRING(visibilitychange, "visibilitychange"); michael@0: target->RemoveSystemEventListener(visibilitychange, this, michael@0: true /* use capture */); michael@0: } michael@0: michael@0: } // anonymous namespace michael@0: michael@0: void michael@0: Navigator::AddIdleObserver(MozIdleObserver& aIdleObserver, ErrorResult& aRv) michael@0: { michael@0: if (!mWindow) { michael@0: aRv.Throw(NS_ERROR_UNEXPECTED); michael@0: return; michael@0: } michael@0: CallbackObjectHolder holder(&aIdleObserver); michael@0: nsCOMPtr obs = holder.ToXPCOMCallback(); michael@0: if (NS_FAILED(mWindow->RegisterIdleObserver(obs))) { michael@0: NS_WARNING("Failed to add idle observer."); michael@0: } michael@0: } michael@0: michael@0: void michael@0: Navigator::RemoveIdleObserver(MozIdleObserver& aIdleObserver, ErrorResult& aRv) michael@0: { michael@0: if (!mWindow) { michael@0: aRv.Throw(NS_ERROR_UNEXPECTED); michael@0: return; michael@0: } michael@0: CallbackObjectHolder holder(&aIdleObserver); michael@0: nsCOMPtr obs = holder.ToXPCOMCallback(); michael@0: if (NS_FAILED(mWindow->UnregisterIdleObserver(obs))) { michael@0: NS_WARNING("Failed to remove idle observer."); michael@0: } michael@0: } michael@0: michael@0: bool michael@0: Navigator::Vibrate(uint32_t aDuration) michael@0: { michael@0: nsAutoTArray pattern; michael@0: pattern.AppendElement(aDuration); michael@0: return Vibrate(pattern); michael@0: } michael@0: michael@0: bool michael@0: Navigator::Vibrate(const nsTArray& aPattern) michael@0: { michael@0: if (!mWindow) { michael@0: return false; michael@0: } michael@0: michael@0: nsCOMPtr doc = mWindow->GetExtantDoc(); michael@0: if (!doc) { michael@0: return false; michael@0: } michael@0: michael@0: if (doc->Hidden()) { michael@0: // Hidden documents cannot start or stop a vibration. michael@0: return false; michael@0: } michael@0: michael@0: if (aPattern.Length() > sMaxVibrateListLen) { michael@0: return false; michael@0: } michael@0: michael@0: for (size_t i = 0; i < aPattern.Length(); ++i) { michael@0: if (aPattern[i] > sMaxVibrateMS) { michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: // The spec says we check sVibratorEnabled after we've done the sanity michael@0: // checking on the pattern. michael@0: if (aPattern.IsEmpty() || !sVibratorEnabled) { michael@0: return true; michael@0: } michael@0: michael@0: // Add a listener to cancel the vibration if the document becomes hidden, michael@0: // and remove the old visibility listener, if there was one. michael@0: michael@0: if (!gVibrateWindowListener) { michael@0: // If gVibrateWindowListener is null, this is the first time we've vibrated, michael@0: // and we need to register a listener to clear gVibrateWindowListener on michael@0: // shutdown. michael@0: ClearOnShutdown(&gVibrateWindowListener); michael@0: } michael@0: else { michael@0: gVibrateWindowListener->RemoveListener(); michael@0: } michael@0: gVibrateWindowListener = new VibrateWindowListener(mWindow, doc); michael@0: michael@0: hal::Vibrate(aPattern, mWindow); michael@0: return true; michael@0: } michael@0: michael@0: //***************************************************************************** michael@0: // Pointer Events interface michael@0: //***************************************************************************** michael@0: michael@0: uint32_t michael@0: Navigator::MaxTouchPoints() michael@0: { michael@0: nsCOMPtr widget = widget::WidgetUtils::DOMWindowToWidget(mWindow); michael@0: michael@0: NS_ENSURE_TRUE(widget, 0); michael@0: return widget->GetMaxTouchPoints(); michael@0: } michael@0: michael@0: //***************************************************************************** michael@0: // Navigator::nsIDOMClientInformation michael@0: //***************************************************************************** michael@0: michael@0: void michael@0: Navigator::RegisterContentHandler(const nsAString& aMIMEType, michael@0: const nsAString& aURI, michael@0: const nsAString& aTitle, michael@0: ErrorResult& aRv) michael@0: { michael@0: if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) { michael@0: return; michael@0: } michael@0: michael@0: nsCOMPtr registrar = michael@0: do_GetService(NS_WEBCONTENTHANDLERREGISTRAR_CONTRACTID); michael@0: if (!registrar) { michael@0: return; michael@0: } michael@0: michael@0: aRv = registrar->RegisterContentHandler(aMIMEType, aURI, aTitle, michael@0: mWindow->GetOuterWindow()); michael@0: } michael@0: michael@0: void michael@0: Navigator::RegisterProtocolHandler(const nsAString& aProtocol, michael@0: const nsAString& aURI, michael@0: const nsAString& aTitle, michael@0: ErrorResult& aRv) michael@0: { michael@0: if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) { michael@0: return; michael@0: } michael@0: michael@0: nsCOMPtr registrar = michael@0: do_GetService(NS_WEBCONTENTHANDLERREGISTRAR_CONTRACTID); michael@0: if (!registrar) { michael@0: return; michael@0: } michael@0: michael@0: aRv = registrar->RegisterProtocolHandler(aProtocol, aURI, aTitle, michael@0: mWindow->GetOuterWindow()); michael@0: } michael@0: michael@0: bool michael@0: Navigator::MozIsLocallyAvailable(const nsAString &aURI, michael@0: bool aWhenOffline, michael@0: ErrorResult& aRv) michael@0: { michael@0: nsCOMPtr uri; michael@0: nsresult rv = NS_NewURI(getter_AddRefs(uri), aURI); michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(rv); michael@0: return false; michael@0: } michael@0: michael@0: // This method of checking the cache will only work for http/https urls. michael@0: bool match; michael@0: rv = uri->SchemeIs("http", &match); michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(rv); michael@0: return false; michael@0: } michael@0: michael@0: if (!match) { michael@0: rv = uri->SchemeIs("https", &match); michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(rv); michael@0: return false; michael@0: } michael@0: if (!match) { michael@0: aRv.Throw(NS_ERROR_DOM_BAD_URI); michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: // Same origin check. michael@0: JSContext *cx = nsContentUtils::GetCurrentJSContext(); michael@0: if (!cx) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return false; michael@0: } michael@0: michael@0: rv = nsContentUtils::GetSecurityManager()->CheckSameOrigin(cx, uri); michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(rv); michael@0: return false; michael@0: } michael@0: michael@0: // These load flags cause an error to be thrown if there is no michael@0: // valid cache entry, and skip the load if there is. michael@0: // If the cache is busy, assume that it is not yet available rather michael@0: // than waiting for it to become available. michael@0: uint32_t loadFlags = nsIChannel::INHIBIT_CACHING | michael@0: nsICachingChannel::LOAD_NO_NETWORK_IO | michael@0: nsICachingChannel::LOAD_ONLY_IF_MODIFIED | michael@0: nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY; michael@0: michael@0: if (aWhenOffline) { michael@0: loadFlags |= nsICachingChannel::LOAD_CHECK_OFFLINE_CACHE | michael@0: nsICachingChannel::LOAD_ONLY_FROM_CACHE | michael@0: nsIRequest::LOAD_FROM_CACHE; michael@0: } michael@0: michael@0: if (!mWindow) { michael@0: aRv.Throw(NS_ERROR_UNEXPECTED); michael@0: return false; michael@0: } michael@0: michael@0: nsCOMPtr loadGroup; michael@0: nsCOMPtr doc = mWindow->GetDoc(); michael@0: if (doc) { michael@0: loadGroup = doc->GetDocumentLoadGroup(); michael@0: } michael@0: michael@0: nsCOMPtr channel; michael@0: rv = NS_NewChannel(getter_AddRefs(channel), uri, michael@0: nullptr, loadGroup, nullptr, loadFlags); michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(rv); michael@0: return false; michael@0: } michael@0: michael@0: nsCOMPtr stream; michael@0: rv = channel->Open(getter_AddRefs(stream)); michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(rv); michael@0: return false; michael@0: } michael@0: michael@0: stream->Close(); michael@0: michael@0: nsresult status; michael@0: rv = channel->GetStatus(&status); michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(rv); michael@0: return false; michael@0: } michael@0: michael@0: if (NS_FAILED(status)) { michael@0: return false; michael@0: } michael@0: michael@0: nsCOMPtr httpChannel = do_QueryInterface(channel); michael@0: bool isAvailable; michael@0: rv = httpChannel->GetRequestSucceeded(&isAvailable); michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(rv); michael@0: return false; michael@0: } michael@0: return isAvailable; michael@0: } michael@0: michael@0: nsDOMDeviceStorage* michael@0: Navigator::GetDeviceStorage(const nsAString& aType, ErrorResult& aRv) michael@0: { michael@0: if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr storage; michael@0: nsDOMDeviceStorage::CreateDeviceStorageFor(mWindow, aType, michael@0: getter_AddRefs(storage)); michael@0: michael@0: if (!storage) { michael@0: return nullptr; michael@0: } michael@0: michael@0: mDeviceStorageStores.AppendElement(storage); michael@0: return storage; michael@0: } michael@0: michael@0: void michael@0: Navigator::GetDeviceStorages(const nsAString& aType, michael@0: nsTArray >& aStores, michael@0: ErrorResult& aRv) michael@0: { michael@0: if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return; michael@0: } michael@0: michael@0: nsDOMDeviceStorage::CreateDeviceStoragesFor(mWindow, aType, aStores); michael@0: michael@0: mDeviceStorageStores.AppendElements(aStores); michael@0: } michael@0: michael@0: Geolocation* michael@0: Navigator::GetGeolocation(ErrorResult& aRv) michael@0: { michael@0: if (mGeolocation) { michael@0: return mGeolocation; michael@0: } michael@0: michael@0: if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: mGeolocation = new Geolocation(); michael@0: if (NS_FAILED(mGeolocation->Init(mWindow->GetOuterWindow()))) { michael@0: mGeolocation = nullptr; michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: return mGeolocation; michael@0: } michael@0: michael@0: class BeaconStreamListener MOZ_FINAL : public nsIStreamListener michael@0: { michael@0: public: michael@0: BeaconStreamListener() {} michael@0: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSISTREAMLISTENER michael@0: NS_DECL_NSIREQUESTOBSERVER michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(BeaconStreamListener, michael@0: nsIStreamListener, michael@0: nsIRequestObserver) michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: BeaconStreamListener::OnStartRequest(nsIRequest *aRequest, michael@0: nsISupports *aContext) michael@0: { michael@0: aRequest->Cancel(NS_ERROR_NET_INTERRUPT); michael@0: return NS_BINDING_ABORTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: BeaconStreamListener::OnStopRequest(nsIRequest *aRequest, michael@0: nsISupports *aContext, michael@0: nsresult aStatus) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: BeaconStreamListener::OnDataAvailable(nsIRequest *aRequest, michael@0: nsISupports *ctxt, michael@0: nsIInputStream *inStr, michael@0: uint64_t sourceOffset, michael@0: uint32_t count) michael@0: { michael@0: MOZ_ASSERT(false); michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: Navigator::SendBeacon(const nsAString& aUrl, michael@0: const Nullable& aData, michael@0: ErrorResult& aRv) michael@0: { michael@0: if (!mWindow) { michael@0: aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); michael@0: return false; michael@0: } michael@0: michael@0: nsCOMPtr doc = mWindow->GetDoc(); michael@0: if (!doc) { michael@0: aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); michael@0: return false; michael@0: } michael@0: michael@0: nsIURI* documentURI = doc->GetDocumentURI(); michael@0: if (!documentURI) { michael@0: aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); michael@0: return false; michael@0: } michael@0: michael@0: nsCOMPtr uri; michael@0: nsresult rv = nsContentUtils::NewURIWithDocumentCharset( michael@0: getter_AddRefs(uri), michael@0: aUrl, michael@0: doc, michael@0: doc->GetDocBaseURI()); michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(NS_ERROR_DOM_URL_MISMATCH_ERR); michael@0: return false; michael@0: } michael@0: michael@0: // Check whether this is a sane URI to load michael@0: // Explicitly disallow things like chrome:, javascript:, and data: URIs michael@0: nsCOMPtr principal = doc->NodePrincipal(); michael@0: nsCOMPtr secMan = nsContentUtils::GetSecurityManager(); michael@0: uint32_t flags = nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL michael@0: & nsIScriptSecurityManager::DISALLOW_SCRIPT; michael@0: rv = secMan->CheckLoadURIWithPrincipal(principal, michael@0: uri, michael@0: flags); michael@0: if (NS_FAILED(rv)) { michael@0: // Bad URI michael@0: aRv.Throw(rv); michael@0: return false; michael@0: } michael@0: michael@0: // Check whether the CSP allows us to load michael@0: int16_t shouldLoad = nsIContentPolicy::ACCEPT; michael@0: rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_BEACON, michael@0: uri, michael@0: principal, michael@0: doc, michael@0: EmptyCString(), //mime guess michael@0: nullptr, //extra michael@0: &shouldLoad, michael@0: nsContentUtils::GetContentPolicy(), michael@0: nsContentUtils::GetSecurityManager()); michael@0: if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) { michael@0: // Disallowed by content policy michael@0: aRv.Throw(NS_ERROR_CONTENT_BLOCKED); michael@0: return false; michael@0: } michael@0: michael@0: nsCOMPtr channel; michael@0: nsCOMPtr channelPolicy; michael@0: nsCOMPtr csp; michael@0: rv = principal->GetCsp(getter_AddRefs(csp)); michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return false; michael@0: } michael@0: michael@0: if (csp) { michael@0: channelPolicy = do_CreateInstance(NSCHANNELPOLICY_CONTRACTID); michael@0: channelPolicy->SetContentSecurityPolicy(csp); michael@0: channelPolicy->SetLoadType(nsIContentPolicy::TYPE_BEACON); michael@0: } michael@0: rv = NS_NewChannel(getter_AddRefs(channel), michael@0: uri, michael@0: nullptr, michael@0: nullptr, michael@0: nullptr, michael@0: nsIRequest::LOAD_NORMAL, michael@0: channelPolicy); michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(rv); michael@0: return false; michael@0: } michael@0: michael@0: nsCOMPtr pbChannel = do_QueryInterface(channel); michael@0: if (pbChannel) { michael@0: nsIDocShell* docShell = mWindow->GetDocShell(); michael@0: nsCOMPtr loadContext = do_QueryInterface(docShell); michael@0: if (loadContext) { michael@0: rv = pbChannel->SetPrivate(loadContext->UsePrivateBrowsing()); michael@0: if (NS_FAILED(rv)) { michael@0: NS_WARNING("Setting the privacy status on the beacon channel failed"); michael@0: } michael@0: } michael@0: } michael@0: michael@0: nsCOMPtr httpChannel = do_QueryInterface(channel); michael@0: if (!httpChannel) { michael@0: // Beacon spec only supports HTTP requests at this time michael@0: aRv.Throw(NS_ERROR_DOM_BAD_URI); michael@0: return false; michael@0: } michael@0: httpChannel->SetReferrer(documentURI); michael@0: michael@0: // Anything that will need to refer to the window during the request michael@0: // will need to be done now. For example, detection of whether any michael@0: // cookies set by this request are foreign. Note that ThirdPartyUtil michael@0: // (nsIThirdPartyUtil.isThirdPartyChannel) does a secondary check between michael@0: // the channel URI and the cookie URI even when forceAllowThirdPartyCookie michael@0: // is set, so this is safe with regard to redirects. michael@0: nsCOMPtr httpChannelInternal(do_QueryInterface(channel)); michael@0: nsCOMPtr thirdPartyUtil = do_GetService(THIRDPARTYUTIL_CONTRACTID); michael@0: if (!httpChannelInternal) { michael@0: aRv.Throw(NS_ERROR_DOM_BAD_URI); michael@0: return false; michael@0: } michael@0: bool isForeign = true; michael@0: thirdPartyUtil->IsThirdPartyWindow(mWindow, uri, &isForeign); michael@0: httpChannelInternal->SetForceAllowThirdPartyCookie(!isForeign); michael@0: michael@0: nsCString mimeType; michael@0: if (!aData.IsNull()) { michael@0: nsCOMPtr in; michael@0: michael@0: if (aData.Value().IsString()) { michael@0: nsCString stringData = NS_ConvertUTF16toUTF8(aData.Value().GetAsString()); michael@0: nsCOMPtr strStream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv); michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return false; michael@0: } michael@0: rv = strStream->SetData(stringData.BeginReading(), stringData.Length()); michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return false; michael@0: } michael@0: mimeType.AssignLiteral("text/plain;charset=UTF-8"); michael@0: in = strStream; michael@0: michael@0: } else if (aData.Value().IsArrayBufferView()) { michael@0: michael@0: nsCOMPtr strStream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv); michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return false; michael@0: } michael@0: michael@0: ArrayBufferView& view = aData.Value().GetAsArrayBufferView(); michael@0: view.ComputeLengthAndData(); michael@0: rv = strStream->SetData(reinterpret_cast(view.Data()), michael@0: view.Length()); michael@0: michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return false; michael@0: } michael@0: mimeType.AssignLiteral("application/octet-stream"); michael@0: in = strStream; michael@0: michael@0: } else if (aData.Value().IsBlob()) { michael@0: nsCOMPtr blob = aData.Value().GetAsBlob(); michael@0: rv = blob->GetInternalStream(getter_AddRefs(in)); michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return false; michael@0: } michael@0: nsAutoString type; michael@0: rv = blob->GetType(type); michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return false; michael@0: } michael@0: mimeType = NS_ConvertUTF16toUTF8(type); michael@0: michael@0: } else if (aData.Value().IsFormData()) { michael@0: nsFormData& form = aData.Value().GetAsFormData(); michael@0: uint64_t len; michael@0: nsAutoCString charset; michael@0: form.GetSendInfo(getter_AddRefs(in), michael@0: &len, michael@0: mimeType, michael@0: charset); michael@0: } else { michael@0: MOZ_ASSERT(false, "switch statements not in sync"); michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return false; michael@0: } michael@0: michael@0: nsCOMPtr uploadChannel = do_QueryInterface(channel); michael@0: if (!uploadChannel) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return false; michael@0: } michael@0: uploadChannel->ExplicitSetUploadStream(in, mimeType, -1, michael@0: NS_LITERAL_CSTRING("POST"), michael@0: false); michael@0: } else { michael@0: httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("POST")); michael@0: } michael@0: michael@0: nsCOMPtr p = do_QueryInterface(channel); michael@0: if (p) { michael@0: p->SetPriority(nsISupportsPriority::PRIORITY_LOWEST); michael@0: } michael@0: michael@0: nsRefPtr cors = new nsCORSListenerProxy(new BeaconStreamListener(), michael@0: principal, michael@0: true); michael@0: michael@0: // Start a preflight if cross-origin and content type is not whitelisted michael@0: rv = secMan->CheckSameOriginURI(documentURI, uri, false); michael@0: bool crossOrigin = NS_FAILED(rv); michael@0: nsAutoCString contentType, parsedCharset; michael@0: rv = NS_ParseContentType(mimeType, contentType, parsedCharset); michael@0: if (crossOrigin && michael@0: contentType.Length() > 0 && michael@0: !contentType.Equals(APPLICATION_WWW_FORM_URLENCODED) && michael@0: !contentType.Equals(MULTIPART_FORM_DATA) && michael@0: !contentType.Equals(TEXT_PLAIN)) { michael@0: nsCOMPtr preflightChannel; michael@0: nsTArray unsafeHeaders; michael@0: unsafeHeaders.AppendElement(NS_LITERAL_CSTRING("Content-Type")); michael@0: rv = NS_StartCORSPreflight(channel, michael@0: cors, michael@0: principal, michael@0: true, michael@0: unsafeHeaders, michael@0: getter_AddRefs(preflightChannel)); michael@0: } else { michael@0: rv = channel->AsyncOpen(cors, nullptr); michael@0: } michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(rv); michael@0: return false; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: #ifdef MOZ_MEDIA_NAVIGATOR michael@0: void michael@0: Navigator::MozGetUserMedia(const MediaStreamConstraints& aConstraints, michael@0: NavigatorUserMediaSuccessCallback& aOnSuccess, michael@0: NavigatorUserMediaErrorCallback& aOnError, michael@0: ErrorResult& aRv) michael@0: { michael@0: CallbackObjectHolder holder1(&aOnSuccess); michael@0: nsCOMPtr onsuccess = michael@0: holder1.ToXPCOMCallback(); michael@0: michael@0: CallbackObjectHolder holder2(&aOnError); michael@0: nsCOMPtr onerror = holder2.ToXPCOMCallback(); michael@0: michael@0: if (!mWindow || !mWindow->GetOuterWindow() || michael@0: mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) { michael@0: aRv.Throw(NS_ERROR_NOT_AVAILABLE); michael@0: return; michael@0: } michael@0: michael@0: bool privileged = nsContentUtils::IsChromeDoc(mWindow->GetExtantDoc()); michael@0: michael@0: MediaManager* manager = MediaManager::Get(); michael@0: aRv = manager->GetUserMedia(privileged, mWindow, aConstraints, michael@0: onsuccess, onerror); michael@0: } michael@0: michael@0: void michael@0: Navigator::MozGetUserMediaDevices(const MediaStreamConstraints& aConstraints, michael@0: MozGetUserMediaDevicesSuccessCallback& aOnSuccess, michael@0: NavigatorUserMediaErrorCallback& aOnError, michael@0: uint64_t aInnerWindowID, michael@0: ErrorResult& aRv) michael@0: { michael@0: CallbackObjectHolder holder1(&aOnSuccess); michael@0: nsCOMPtr onsuccess = michael@0: holder1.ToXPCOMCallback(); michael@0: michael@0: CallbackObjectHolder holder2(&aOnError); michael@0: nsCOMPtr onerror = holder2.ToXPCOMCallback(); michael@0: michael@0: if (!mWindow || !mWindow->GetOuterWindow() || michael@0: mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) { michael@0: aRv.Throw(NS_ERROR_NOT_AVAILABLE); michael@0: return; michael@0: } michael@0: michael@0: MediaManager* manager = MediaManager::Get(); michael@0: aRv = manager->GetUserMediaDevices(mWindow, aConstraints, onsuccess, onerror, michael@0: aInnerWindowID); michael@0: } michael@0: #endif michael@0: michael@0: DesktopNotificationCenter* michael@0: Navigator::GetMozNotification(ErrorResult& aRv) michael@0: { michael@0: if (mNotification) { michael@0: return mNotification; michael@0: } michael@0: michael@0: if (!mWindow || !mWindow->GetDocShell()) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: mNotification = new DesktopNotificationCenter(mWindow); michael@0: return mNotification; michael@0: } michael@0: michael@0: #ifdef MOZ_B2G_FM michael@0: michael@0: using mozilla::dom::FMRadio; michael@0: michael@0: FMRadio* michael@0: Navigator::GetMozFMRadio(ErrorResult& aRv) michael@0: { michael@0: if (!mFMRadio) { michael@0: if (!mWindow) { michael@0: aRv.Throw(NS_ERROR_UNEXPECTED); michael@0: return nullptr; michael@0: } michael@0: michael@0: NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr); michael@0: michael@0: mFMRadio = new FMRadio(); michael@0: mFMRadio->Init(mWindow); michael@0: } michael@0: michael@0: return mFMRadio; michael@0: } michael@0: michael@0: #endif // MOZ_B2G_FM michael@0: michael@0: //***************************************************************************** michael@0: // Navigator::nsINavigatorBattery michael@0: //***************************************************************************** michael@0: michael@0: battery::BatteryManager* michael@0: Navigator::GetBattery(ErrorResult& aRv) michael@0: { michael@0: if (!mBatteryManager) { michael@0: if (!mWindow) { michael@0: aRv.Throw(NS_ERROR_UNEXPECTED); michael@0: return nullptr; michael@0: } michael@0: NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr); michael@0: michael@0: mBatteryManager = new battery::BatteryManager(mWindow); michael@0: mBatteryManager->Init(); michael@0: } michael@0: michael@0: return mBatteryManager; michael@0: } michael@0: michael@0: already_AddRefed michael@0: Navigator::GetDataStores(const nsAString& aName, ErrorResult& aRv) michael@0: { michael@0: if (!mWindow || !mWindow->GetDocShell()) { michael@0: aRv.Throw(NS_ERROR_UNEXPECTED); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsCOMPtr service = michael@0: do_GetService("@mozilla.org/datastore-service;1"); michael@0: if (!service) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsCOMPtr promise; michael@0: aRv = service->GetDataStores(mWindow, aName, getter_AddRefs(promise)); michael@0: michael@0: nsRefPtr p = static_cast(promise.get()); michael@0: return p.forget(); michael@0: } michael@0: michael@0: PowerManager* michael@0: Navigator::GetMozPower(ErrorResult& aRv) michael@0: { michael@0: if (!mPowerManager) { michael@0: if (!mWindow) { michael@0: aRv.Throw(NS_ERROR_UNEXPECTED); michael@0: return nullptr; michael@0: } michael@0: mPowerManager = PowerManager::CreateInstance(mWindow); michael@0: if (!mPowerManager) { michael@0: // We failed to get the power manager service? michael@0: aRv.Throw(NS_ERROR_UNEXPECTED); michael@0: } michael@0: } michael@0: michael@0: return mPowerManager; michael@0: } michael@0: michael@0: already_AddRefed michael@0: Navigator::RequestWakeLock(const nsAString &aTopic, ErrorResult& aRv) michael@0: { michael@0: if (!mWindow) { michael@0: aRv.Throw(NS_ERROR_UNEXPECTED); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr pmService = michael@0: power::PowerManagerService::GetInstance(); michael@0: // Maybe it went away for some reason... Or maybe we're just called michael@0: // from our XPCOM method. michael@0: if (!pmService) { michael@0: aRv.Throw(NS_ERROR_UNEXPECTED); michael@0: return nullptr; michael@0: } michael@0: michael@0: return pmService->NewWakeLock(aTopic, mWindow, aRv); michael@0: } michael@0: michael@0: nsIDOMMozMobileMessageManager* michael@0: Navigator::GetMozMobileMessage() michael@0: { michael@0: if (!mMobileMessageManager) { michael@0: // Check that our window has not gone away michael@0: NS_ENSURE_TRUE(mWindow, nullptr); michael@0: NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr); michael@0: michael@0: mMobileMessageManager = new MobileMessageManager(); michael@0: mMobileMessageManager->Init(mWindow); michael@0: } michael@0: michael@0: return mMobileMessageManager; michael@0: } michael@0: michael@0: Telephony* michael@0: Navigator::GetMozTelephony(ErrorResult& aRv) michael@0: { michael@0: if (!mTelephony) { michael@0: if (!mWindow) { michael@0: aRv.Throw(NS_ERROR_UNEXPECTED); michael@0: return nullptr; michael@0: } michael@0: mTelephony = Telephony::Create(mWindow, aRv); michael@0: } michael@0: michael@0: return mTelephony; michael@0: } michael@0: michael@0: #ifdef MOZ_B2G_RIL michael@0: michael@0: MobileConnectionArray* michael@0: Navigator::GetMozMobileConnections(ErrorResult& aRv) michael@0: { michael@0: if (!mMobileConnections) { michael@0: if (!mWindow) { michael@0: aRv.Throw(NS_ERROR_UNEXPECTED); michael@0: return nullptr; michael@0: } michael@0: mMobileConnections = new MobileConnectionArray(mWindow); michael@0: } michael@0: michael@0: return mMobileConnections; michael@0: } michael@0: michael@0: CellBroadcast* michael@0: Navigator::GetMozCellBroadcast(ErrorResult& aRv) michael@0: { michael@0: if (!mCellBroadcast) { michael@0: if (!mWindow) { michael@0: aRv.Throw(NS_ERROR_UNEXPECTED); michael@0: return nullptr; michael@0: } michael@0: mCellBroadcast = CellBroadcast::Create(mWindow, aRv); michael@0: } michael@0: michael@0: return mCellBroadcast; michael@0: } michael@0: michael@0: Voicemail* michael@0: Navigator::GetMozVoicemail(ErrorResult& aRv) michael@0: { michael@0: if (!mVoicemail) { michael@0: if (!mWindow) { michael@0: aRv.Throw(NS_ERROR_UNEXPECTED); michael@0: return nullptr; michael@0: } michael@0: michael@0: aRv = NS_NewVoicemail(mWindow, getter_AddRefs(mVoicemail)); michael@0: if (aRv.Failed()) { michael@0: return nullptr; michael@0: } michael@0: } michael@0: michael@0: return mVoicemail; michael@0: } michael@0: michael@0: IccManager* michael@0: Navigator::GetMozIccManager(ErrorResult& aRv) michael@0: { michael@0: if (!mIccManager) { michael@0: if (!mWindow) { michael@0: aRv.Throw(NS_ERROR_UNEXPECTED); michael@0: return nullptr; michael@0: } michael@0: NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr); michael@0: michael@0: mIccManager = new IccManager(mWindow); michael@0: } michael@0: michael@0: return mIccManager; michael@0: } michael@0: michael@0: #endif // MOZ_B2G_RIL michael@0: michael@0: #ifdef MOZ_GAMEPAD michael@0: void michael@0: Navigator::GetGamepads(nsTArray >& aGamepads, michael@0: ErrorResult& aRv) michael@0: { michael@0: if (!mWindow) { michael@0: aRv.Throw(NS_ERROR_UNEXPECTED); michael@0: return; michael@0: } michael@0: NS_ENSURE_TRUE_VOID(mWindow->GetDocShell()); michael@0: nsGlobalWindow* win = static_cast(mWindow.get()); michael@0: win->SetHasGamepadEventListener(true); michael@0: win->GetGamepads(aGamepads); michael@0: } michael@0: #endif michael@0: michael@0: //***************************************************************************** michael@0: // Navigator::nsIMozNavigatorNetwork michael@0: //***************************************************************************** michael@0: michael@0: NS_IMETHODIMP michael@0: Navigator::GetProperties(nsINetworkProperties** aProperties) michael@0: { michael@0: ErrorResult rv; michael@0: NS_IF_ADDREF(*aProperties = GetConnection(rv)); michael@0: return NS_OK; michael@0: } michael@0: michael@0: network::Connection* michael@0: Navigator::GetConnection(ErrorResult& aRv) michael@0: { michael@0: if (!mConnection) { michael@0: if (!mWindow) { michael@0: aRv.Throw(NS_ERROR_UNEXPECTED); michael@0: return nullptr; michael@0: } michael@0: mConnection = new network::Connection(); michael@0: mConnection->Init(mWindow); michael@0: } michael@0: michael@0: return mConnection; michael@0: } michael@0: michael@0: #ifdef MOZ_B2G_BT michael@0: bluetooth::BluetoothManager* michael@0: Navigator::GetMozBluetooth(ErrorResult& aRv) michael@0: { michael@0: if (!mBluetooth) { michael@0: if (!mWindow) { michael@0: aRv.Throw(NS_ERROR_UNEXPECTED); michael@0: return nullptr; michael@0: } michael@0: mBluetooth = bluetooth::BluetoothManager::Create(mWindow); michael@0: } michael@0: michael@0: return mBluetooth; michael@0: } michael@0: #endif //MOZ_B2G_BT michael@0: michael@0: nsresult michael@0: Navigator::EnsureMessagesManager() michael@0: { michael@0: if (mMessagesManager) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_ENSURE_STATE(mWindow); michael@0: michael@0: nsresult rv; michael@0: nsCOMPtr messageManager = michael@0: do_CreateInstance("@mozilla.org/system-message-manager;1", &rv); michael@0: michael@0: nsCOMPtr gpi = michael@0: do_QueryInterface(messageManager); michael@0: NS_ENSURE_TRUE(gpi, NS_ERROR_FAILURE); michael@0: michael@0: // We don't do anything with the return value. michael@0: AutoJSContext cx; michael@0: JS::Rooted prop_val(cx); michael@0: rv = gpi->Init(mWindow, &prop_val); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: mMessagesManager = messageManager.forget(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: Navigator::MozHasPendingMessage(const nsAString& aType, ErrorResult& aRv) michael@0: { michael@0: // The WebIDL binding is responsible for the pref check here. michael@0: nsresult rv = EnsureMessagesManager(); michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(rv); michael@0: return false; michael@0: } michael@0: michael@0: bool result = false; michael@0: rv = mMessagesManager->MozHasPendingMessage(aType, &result); michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(rv); michael@0: return false; michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: void michael@0: Navigator::MozSetMessageHandler(const nsAString& aType, michael@0: systemMessageCallback* aCallback, michael@0: ErrorResult& aRv) michael@0: { michael@0: // The WebIDL binding is responsible for the pref check here. michael@0: nsresult rv = EnsureMessagesManager(); michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(rv); michael@0: return; michael@0: } michael@0: michael@0: CallbackObjectHolder michael@0: holder(aCallback); michael@0: nsCOMPtr callback = holder.ToXPCOMCallback(); michael@0: michael@0: rv = mMessagesManager->MozSetMessageHandler(aType, callback); michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(rv); michael@0: } michael@0: } michael@0: michael@0: #ifdef MOZ_TIME_MANAGER michael@0: time::TimeManager* michael@0: Navigator::GetMozTime(ErrorResult& aRv) michael@0: { michael@0: if (!mWindow) { michael@0: aRv.Throw(NS_ERROR_UNEXPECTED); michael@0: return nullptr; michael@0: } michael@0: michael@0: if (!mTimeManager) { michael@0: mTimeManager = new time::TimeManager(mWindow); michael@0: } michael@0: michael@0: return mTimeManager; michael@0: } michael@0: #endif michael@0: michael@0: nsDOMCameraManager* michael@0: Navigator::GetMozCameras(ErrorResult& aRv) michael@0: { michael@0: if (!mCameraManager) { michael@0: if (!mWindow || michael@0: !mWindow->GetOuterWindow() || michael@0: mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) { michael@0: aRv.Throw(NS_ERROR_NOT_AVAILABLE); michael@0: return nullptr; michael@0: } michael@0: michael@0: mCameraManager = nsDOMCameraManager::CreateInstance(mWindow); michael@0: } michael@0: michael@0: return mCameraManager; michael@0: } michael@0: michael@0: size_t michael@0: Navigator::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const michael@0: { michael@0: size_t n = aMallocSizeOf(this); michael@0: michael@0: // TODO: add SizeOfIncludingThis() to nsMimeTypeArray, bug 674113. michael@0: // TODO: add SizeOfIncludingThis() to nsPluginArray, bug 674114. michael@0: // TODO: add SizeOfIncludingThis() to Geolocation, bug 674115. michael@0: // TODO: add SizeOfIncludingThis() to DesktopNotificationCenter, bug 674116. michael@0: michael@0: return n; michael@0: } michael@0: michael@0: void michael@0: Navigator::SetWindow(nsPIDOMWindow *aInnerWindow) michael@0: { michael@0: NS_ASSERTION(aInnerWindow->IsInnerWindow(), michael@0: "Navigator must get an inner window!"); michael@0: mWindow = aInnerWindow; michael@0: } michael@0: michael@0: void michael@0: Navigator::OnNavigation() michael@0: { michael@0: if (!mWindow) { michael@0: return; michael@0: } michael@0: michael@0: #ifdef MOZ_MEDIA_NAVIGATOR michael@0: // Inform MediaManager in case there are live streams or pending callbacks. michael@0: MediaManager *manager = MediaManager::Get(); michael@0: if (manager) { michael@0: manager->OnNavigation(mWindow->WindowID()); michael@0: } michael@0: #endif michael@0: if (mCameraManager) { michael@0: mCameraManager->OnNavigation(mWindow->WindowID()); michael@0: } michael@0: } michael@0: michael@0: bool michael@0: Navigator::CheckPermission(const char* type) michael@0: { michael@0: return CheckPermission(mWindow, type); michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: Navigator::CheckPermission(nsPIDOMWindow* aWindow, const char* aType) michael@0: { michael@0: if (!aWindow) { michael@0: return false; michael@0: } michael@0: michael@0: nsCOMPtr permMgr = michael@0: do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); michael@0: NS_ENSURE_TRUE(permMgr, false); michael@0: michael@0: uint32_t permission = nsIPermissionManager::DENY_ACTION; michael@0: permMgr->TestPermissionFromWindow(aWindow, aType, &permission); michael@0: return permission == nsIPermissionManager::ALLOW_ACTION; michael@0: } michael@0: michael@0: #ifdef MOZ_AUDIO_CHANNEL_MANAGER michael@0: system::AudioChannelManager* michael@0: Navigator::GetMozAudioChannelManager(ErrorResult& aRv) michael@0: { michael@0: if (!mAudioChannelManager) { michael@0: if (!mWindow) { michael@0: aRv.Throw(NS_ERROR_UNEXPECTED); michael@0: return nullptr; michael@0: } michael@0: mAudioChannelManager = new system::AudioChannelManager(); michael@0: mAudioChannelManager->Init(mWindow); michael@0: } michael@0: michael@0: return mAudioChannelManager; michael@0: } michael@0: #endif michael@0: michael@0: bool michael@0: Navigator::DoNewResolve(JSContext* aCx, JS::Handle aObject, michael@0: JS::Handle aId, michael@0: JS::MutableHandle aDesc) michael@0: { michael@0: if (!JSID_IS_STRING(aId)) { michael@0: return true; michael@0: } michael@0: michael@0: nsScriptNameSpaceManager* nameSpaceManager = GetNameSpaceManager(); michael@0: if (!nameSpaceManager) { michael@0: return Throw(aCx, NS_ERROR_NOT_INITIALIZED); michael@0: } michael@0: michael@0: nsDependentJSString name(aId); michael@0: michael@0: const nsGlobalNameStruct* name_struct = michael@0: nameSpaceManager->LookupNavigatorName(name); michael@0: if (!name_struct) { michael@0: return true; michael@0: } michael@0: michael@0: JS::Rooted naviObj(aCx, michael@0: js::CheckedUnwrap(aObject, michael@0: /* stopAtOuter = */ false)); michael@0: if (!naviObj) { michael@0: return Throw(aCx, NS_ERROR_DOM_SECURITY_ERR); michael@0: } michael@0: michael@0: if (name_struct->mType == nsGlobalNameStruct::eTypeNewDOMBinding) { michael@0: ConstructNavigatorProperty construct = name_struct->mConstructNavigatorProperty; michael@0: MOZ_ASSERT(construct); michael@0: michael@0: JS::Rooted domObject(aCx); michael@0: { michael@0: // Make sure to do the creation of our object in the compartment michael@0: // of naviObj, especially since we plan to cache that object. michael@0: JSAutoCompartment ac(aCx, naviObj); michael@0: michael@0: // Check whether our constructor is enabled after we unwrap Xrays, since michael@0: // we don't want to define an interface on the Xray if it's disabled in michael@0: // the target global, even if it's enabled in the Xray's global. michael@0: if (name_struct->mConstructorEnabled && michael@0: !(*name_struct->mConstructorEnabled)(aCx, naviObj)) { michael@0: return true; michael@0: } michael@0: michael@0: if (name.EqualsLiteral("mozSettings")) { michael@0: bool hasPermission = CheckPermission("settings-read") || michael@0: CheckPermission("settings-write"); michael@0: if (!hasPermission) { michael@0: FillPropertyDescriptor(aDesc, aObject, JS::NullValue(), false); michael@0: return true; michael@0: } michael@0: } michael@0: michael@0: if (name.EqualsLiteral("mozDownloadManager")) { michael@0: if (!CheckPermission("downloads")) { michael@0: FillPropertyDescriptor(aDesc, aObject, JS::NullValue(), false); michael@0: return true; michael@0: } michael@0: } michael@0: michael@0: nsISupports* existingObject = mCachedResolveResults.GetWeak(name); michael@0: if (existingObject) { michael@0: // We know all of our WebIDL objects here are wrappercached, so just go michael@0: // ahead and WrapObject() them. We can't use WrapNewBindingObject, michael@0: // because we don't have the concrete type. michael@0: JS::Rooted wrapped(aCx); michael@0: if (!dom::WrapObject(aCx, existingObject, &wrapped)) { michael@0: return false; michael@0: } michael@0: domObject = &wrapped.toObject(); michael@0: } else { michael@0: domObject = construct(aCx, naviObj); michael@0: if (!domObject) { michael@0: return Throw(aCx, NS_ERROR_FAILURE); michael@0: } michael@0: michael@0: // Store the value in our cache michael@0: nsISupports* native = UnwrapDOMObjectToISupports(domObject); michael@0: MOZ_ASSERT(native); michael@0: mCachedResolveResults.Put(name, native); michael@0: } michael@0: } michael@0: michael@0: if (!JS_WrapObject(aCx, &domObject)) { michael@0: return false; michael@0: } michael@0: michael@0: FillPropertyDescriptor(aDesc, aObject, JS::ObjectValue(*domObject), false); michael@0: return true; michael@0: } michael@0: michael@0: NS_ASSERTION(name_struct->mType == nsGlobalNameStruct::eTypeNavigatorProperty, michael@0: "unexpected type"); michael@0: michael@0: nsresult rv = NS_OK; michael@0: michael@0: nsCOMPtr native; michael@0: bool hadCachedNative = mCachedResolveResults.Get(name, getter_AddRefs(native)); michael@0: bool okToUseNative; michael@0: JS::Rooted prop_val(aCx); michael@0: if (hadCachedNative) { michael@0: okToUseNative = true; michael@0: } else { michael@0: native = do_CreateInstance(name_struct->mCID, &rv); michael@0: if (NS_FAILED(rv)) { michael@0: return Throw(aCx, rv); michael@0: } michael@0: michael@0: nsCOMPtr gpi(do_QueryInterface(native)); michael@0: michael@0: if (gpi) { michael@0: if (!mWindow) { michael@0: return Throw(aCx, NS_ERROR_UNEXPECTED); michael@0: } michael@0: michael@0: rv = gpi->Init(mWindow, &prop_val); michael@0: if (NS_FAILED(rv)) { michael@0: return Throw(aCx, rv); michael@0: } michael@0: } michael@0: michael@0: okToUseNative = !prop_val.isObjectOrNull(); michael@0: } michael@0: michael@0: if (okToUseNative) { michael@0: // Make sure to do the creation of our object in the compartment michael@0: // of naviObj, especially since we plan to cache that object. michael@0: JSAutoCompartment ac(aCx, naviObj); michael@0: michael@0: rv = nsContentUtils::WrapNative(aCx, native, &prop_val); michael@0: michael@0: if (NS_FAILED(rv)) { michael@0: return Throw(aCx, rv); michael@0: } michael@0: michael@0: // Now that we know we managed to wrap this thing properly, go ahead and michael@0: // cache it as needed. michael@0: if (!hadCachedNative) { michael@0: mCachedResolveResults.Put(name, native); michael@0: } michael@0: } michael@0: michael@0: if (!JS_WrapValue(aCx, &prop_val)) { michael@0: return Throw(aCx, NS_ERROR_UNEXPECTED); michael@0: } michael@0: michael@0: FillPropertyDescriptor(aDesc, aObject, prop_val, false); michael@0: return true; michael@0: } michael@0: michael@0: struct NavigatorNameEnumeratorClosure michael@0: { michael@0: NavigatorNameEnumeratorClosure(JSContext* aCx, JSObject* aWrapper, michael@0: nsTArray& aNames) michael@0: : mCx(aCx), michael@0: mWrapper(aCx, aWrapper), michael@0: mNames(aNames) michael@0: { michael@0: } michael@0: michael@0: JSContext* mCx; michael@0: JS::Rooted mWrapper; michael@0: nsTArray& mNames; michael@0: }; michael@0: michael@0: static PLDHashOperator michael@0: SaveNavigatorName(const nsAString& aName, michael@0: const nsGlobalNameStruct& aNameStruct, michael@0: void* aClosure) michael@0: { michael@0: NavigatorNameEnumeratorClosure* closure = michael@0: static_cast(aClosure); michael@0: if (!aNameStruct.mConstructorEnabled || michael@0: aNameStruct.mConstructorEnabled(closure->mCx, closure->mWrapper)) { michael@0: closure->mNames.AppendElement(aName); michael@0: } michael@0: return PL_DHASH_NEXT; michael@0: } michael@0: michael@0: void michael@0: Navigator::GetOwnPropertyNames(JSContext* aCx, nsTArray& aNames, michael@0: ErrorResult& aRv) michael@0: { michael@0: nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager(); michael@0: if (!nameSpaceManager) { michael@0: NS_ERROR("Can't get namespace manager."); michael@0: aRv.Throw(NS_ERROR_UNEXPECTED); michael@0: return; michael@0: } michael@0: michael@0: NavigatorNameEnumeratorClosure closure(aCx, GetWrapper(), aNames); michael@0: nameSpaceManager->EnumerateNavigatorNames(SaveNavigatorName, &closure); michael@0: } michael@0: michael@0: JSObject* michael@0: Navigator::WrapObject(JSContext* cx) michael@0: { michael@0: return NavigatorBinding::Wrap(cx, this); michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: Navigator::HasBatterySupport(JSContext* /* unused*/, JSObject* /*unused */) michael@0: { michael@0: return battery::BatteryManager::HasSupport(); michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: Navigator::HasPowerSupport(JSContext* /* unused */, JSObject* aGlobal) michael@0: { michael@0: nsCOMPtr win = GetWindowFromGlobal(aGlobal); michael@0: return win && PowerManager::CheckPermission(win); michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: Navigator::HasPhoneNumberSupport(JSContext* /* unused */, JSObject* aGlobal) michael@0: { michael@0: nsCOMPtr win = GetWindowFromGlobal(aGlobal); michael@0: return CheckPermission(win, "phonenumberservice"); michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: Navigator::HasIdleSupport(JSContext* /* unused */, JSObject* aGlobal) michael@0: { michael@0: if (!nsContentUtils::IsIdleObserverAPIEnabled()) { michael@0: return false; michael@0: } michael@0: michael@0: nsCOMPtr win = GetWindowFromGlobal(aGlobal); michael@0: return CheckPermission(win, "idle"); michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: Navigator::HasWakeLockSupport(JSContext* /* unused*/, JSObject* /*unused */) michael@0: { michael@0: nsCOMPtr pmService = michael@0: do_GetService(POWERMANAGERSERVICE_CONTRACTID); michael@0: // No service means no wake lock support michael@0: return !!pmService; michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: Navigator::HasMobileMessageSupport(JSContext* /* unused */, JSObject* aGlobal) michael@0: { michael@0: nsCOMPtr win = GetWindowFromGlobal(aGlobal); michael@0: michael@0: #ifndef MOZ_WEBSMS_BACKEND michael@0: return false; michael@0: #endif michael@0: michael@0: // First of all, the general pref has to be turned on. michael@0: bool enabled = false; michael@0: Preferences::GetBool("dom.sms.enabled", &enabled); michael@0: if (!enabled) { michael@0: return false; michael@0: } michael@0: michael@0: NS_ENSURE_TRUE(win, false); michael@0: NS_ENSURE_TRUE(win->GetDocShell(), false); michael@0: michael@0: if (!CheckPermission(win, "sms")) { michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: Navigator::HasTelephonySupport(JSContext* cx, JSObject* aGlobal) michael@0: { michael@0: JS::Rooted global(cx, aGlobal); michael@0: michael@0: // First of all, the general pref has to be turned on. michael@0: bool enabled = false; michael@0: Preferences::GetBool("dom.telephony.enabled", &enabled); michael@0: if (!enabled) { michael@0: return false; michael@0: } michael@0: michael@0: nsCOMPtr win = GetWindowFromGlobal(global); michael@0: return win && CheckPermission(win, "telephony"); michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: Navigator::HasCameraSupport(JSContext* /* unused */, JSObject* aGlobal) michael@0: { michael@0: nsCOMPtr win = GetWindowFromGlobal(aGlobal); michael@0: return win && nsDOMCameraManager::CheckPermission(win); michael@0: } michael@0: michael@0: #ifdef MOZ_B2G_RIL michael@0: /* static */ michael@0: bool michael@0: Navigator::HasMobileConnectionSupport(JSContext* /* unused */, michael@0: JSObject* aGlobal) michael@0: { michael@0: // First of all, the general pref has to be turned on. michael@0: bool enabled = false; michael@0: Preferences::GetBool("dom.mobileconnection.enabled", &enabled); michael@0: NS_ENSURE_TRUE(enabled, false); michael@0: michael@0: nsCOMPtr win = GetWindowFromGlobal(aGlobal); michael@0: return win && (CheckPermission(win, "mobileconnection") || michael@0: CheckPermission(win, "mobilenetwork")); michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: Navigator::HasCellBroadcastSupport(JSContext* /* unused */, michael@0: JSObject* aGlobal) michael@0: { michael@0: // First of all, the general pref has to be turned on. michael@0: bool enabled = false; michael@0: Preferences::GetBool("dom.cellbroadcast.enabled", &enabled); michael@0: NS_ENSURE_TRUE(enabled, false); michael@0: michael@0: nsCOMPtr win = GetWindowFromGlobal(aGlobal); michael@0: return win && CheckPermission(win, "cellbroadcast"); michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: Navigator::HasVoicemailSupport(JSContext* /* unused */, michael@0: JSObject* aGlobal) michael@0: { michael@0: // First of all, the general pref has to be turned on. michael@0: bool enabled = false; michael@0: Preferences::GetBool("dom.voicemail.enabled", &enabled); michael@0: NS_ENSURE_TRUE(enabled, false); michael@0: michael@0: nsCOMPtr win = GetWindowFromGlobal(aGlobal); michael@0: return win && CheckPermission(win, "voicemail"); michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: Navigator::HasIccManagerSupport(JSContext* /* unused */, michael@0: JSObject* aGlobal) michael@0: { michael@0: // First of all, the general pref has to be turned on. michael@0: bool enabled = false; michael@0: Preferences::GetBool("dom.icc.enabled", &enabled); michael@0: NS_ENSURE_TRUE(enabled, false); michael@0: michael@0: nsCOMPtr win = GetWindowFromGlobal(aGlobal); michael@0: return win && CheckPermission(win, "mobileconnection"); michael@0: } michael@0: #endif // MOZ_B2G_RIL michael@0: michael@0: /* static */ michael@0: bool michael@0: Navigator::HasWifiManagerSupport(JSContext* /* unused */, michael@0: JSObject* aGlobal) michael@0: { michael@0: // On XBL scope, the global object is NOT |window|. So we have michael@0: // to use nsContentUtils::GetObjectPrincipal to get the principal michael@0: // and test directly with permission manager. michael@0: michael@0: nsIPrincipal* principal = nsContentUtils::GetObjectPrincipal(aGlobal); michael@0: michael@0: nsCOMPtr permMgr = michael@0: do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); michael@0: NS_ENSURE_TRUE(permMgr, false); michael@0: michael@0: uint32_t permission = nsIPermissionManager::DENY_ACTION; michael@0: permMgr->TestPermissionFromPrincipal(principal, "wifi-manage", &permission); michael@0: return nsIPermissionManager::ALLOW_ACTION == permission; michael@0: } michael@0: michael@0: #ifdef MOZ_B2G_BT michael@0: /* static */ michael@0: bool michael@0: Navigator::HasBluetoothSupport(JSContext* /* unused */, JSObject* aGlobal) michael@0: { michael@0: nsCOMPtr win = GetWindowFromGlobal(aGlobal); michael@0: return win && bluetooth::BluetoothManager::CheckPermission(win); michael@0: } michael@0: #endif // MOZ_B2G_BT michael@0: michael@0: #ifdef MOZ_B2G_FM michael@0: /* static */ michael@0: bool michael@0: Navigator::HasFMRadioSupport(JSContext* /* unused */, JSObject* aGlobal) michael@0: { michael@0: nsCOMPtr win = GetWindowFromGlobal(aGlobal); michael@0: return win && CheckPermission(win, "fmradio"); michael@0: } michael@0: #endif // MOZ_B2G_FM michael@0: michael@0: #ifdef MOZ_NFC michael@0: /* static */ michael@0: bool michael@0: Navigator::HasNfcSupport(JSContext* /* unused */, JSObject* aGlobal) michael@0: { michael@0: // Do not support NFC if NFC content helper does not exist. michael@0: nsCOMPtr contentHelper = do_GetService("@mozilla.org/nfc/content-helper;1"); michael@0: if (!contentHelper) { michael@0: return false; michael@0: } michael@0: michael@0: nsCOMPtr win = GetWindowFromGlobal(aGlobal); michael@0: return win && (CheckPermission(win, "nfc-read") || michael@0: CheckPermission(win, "nfc-write")); michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: Navigator::HasNfcPeerSupport(JSContext* /* unused */, JSObject* aGlobal) michael@0: { michael@0: nsCOMPtr win = GetWindowFromGlobal(aGlobal); michael@0: return win && CheckPermission(win, "nfc-write"); michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: Navigator::HasNfcManagerSupport(JSContext* /* unused */, JSObject* aGlobal) michael@0: { michael@0: nsCOMPtr win = GetWindowFromGlobal(aGlobal); michael@0: return win && CheckPermission(win, "nfc-manager"); michael@0: } michael@0: #endif // MOZ_NFC michael@0: michael@0: #ifdef MOZ_TIME_MANAGER michael@0: /* static */ michael@0: bool michael@0: Navigator::HasTimeSupport(JSContext* /* unused */, JSObject* aGlobal) michael@0: { michael@0: nsCOMPtr win = GetWindowFromGlobal(aGlobal); michael@0: return win && CheckPermission(win, "time"); michael@0: } michael@0: #endif // MOZ_TIME_MANAGER michael@0: michael@0: #ifdef MOZ_MEDIA_NAVIGATOR michael@0: /* static */ michael@0: bool michael@0: Navigator::HasUserMediaSupport(JSContext* /* unused */, michael@0: JSObject* /* unused */) michael@0: { michael@0: // Make enabling peerconnection enable getUserMedia() as well michael@0: return Preferences::GetBool("media.navigator.enabled", false) || michael@0: Preferences::GetBool("media.peerconnection.enabled", false); michael@0: } michael@0: #endif // MOZ_MEDIA_NAVIGATOR michael@0: michael@0: /* static */ michael@0: bool michael@0: Navigator::HasPushNotificationsSupport(JSContext* /* unused */, michael@0: JSObject* aGlobal) michael@0: { michael@0: nsCOMPtr win = GetWindowFromGlobal(aGlobal); michael@0: return Preferences::GetBool("services.push.enabled", false) && michael@0: win && CheckPermission(win, "push"); michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: Navigator::HasInputMethodSupport(JSContext* /* unused */, michael@0: JSObject* aGlobal) michael@0: { michael@0: nsCOMPtr win = GetWindowFromGlobal(aGlobal); michael@0: if (!win || !Preferences::GetBool("dom.mozInputMethod.enabled", false)) { michael@0: return false; michael@0: } michael@0: michael@0: if (Preferences::GetBool("dom.mozInputMethod.testing", false)) { michael@0: return true; michael@0: } michael@0: michael@0: return CheckPermission(win, "input") || michael@0: CheckPermission(win, "input-manage"); michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: Navigator::HasDataStoreSupport(JSContext* cx, JSObject* aGlobal) michael@0: { michael@0: JS::Rooted global(cx, aGlobal); michael@0: michael@0: // First of all, the general pref has to be turned on. michael@0: bool enabled = false; michael@0: Preferences::GetBool("dom.datastore.enabled", &enabled); michael@0: if (!enabled) { michael@0: return false; michael@0: } michael@0: michael@0: // Just for testing, we can enable DataStore for any kind of app. michael@0: if (Preferences::GetBool("dom.testing.datastore_enabled_for_hosted_apps", false)) { michael@0: return true; michael@0: } michael@0: michael@0: nsCOMPtr win = GetWindowFromGlobal(global); michael@0: if (!win) { michael@0: return false; michael@0: } michael@0: michael@0: nsIDocument* doc = win->GetExtantDoc(); michael@0: if (!doc || !doc->NodePrincipal()) { michael@0: return false; michael@0: } michael@0: michael@0: uint16_t status; michael@0: if (NS_FAILED(doc->NodePrincipal()->GetAppStatus(&status))) { michael@0: return false; michael@0: } michael@0: michael@0: return status == nsIPrincipal::APP_STATUS_CERTIFIED; michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: Navigator::HasDownloadsSupport(JSContext* aCx, JSObject* aGlobal) michael@0: { michael@0: nsCOMPtr win = GetWindowFromGlobal(aGlobal); michael@0: michael@0: return win && michael@0: CheckPermission(win, "downloads") && michael@0: Preferences::GetBool("dom.mozDownloads.enabled"); michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: Navigator::HasPermissionSettingsSupport(JSContext* /* unused */, JSObject* aGlobal) michael@0: { michael@0: nsCOMPtr win = GetWindowFromGlobal(aGlobal); michael@0: return CheckPermission(win, "permissions"); michael@0: } michael@0: michael@0: /* static */ michael@0: already_AddRefed michael@0: Navigator::GetWindowFromGlobal(JSObject* aGlobal) michael@0: { michael@0: nsCOMPtr win = michael@0: do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(aGlobal)); michael@0: MOZ_ASSERT(!win || win->IsInnerWindow()); michael@0: return win.forget(); michael@0: } michael@0: michael@0: nsresult michael@0: Navigator::GetPlatform(nsAString& aPlatform, bool aUsePrefOverriddenValue) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: if (aUsePrefOverriddenValue && !nsContentUtils::IsCallerChrome()) { michael@0: const nsAdoptingString& override = michael@0: mozilla::Preferences::GetString("general.platform.override"); michael@0: michael@0: if (override) { michael@0: aPlatform = override; michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: nsresult rv; michael@0: michael@0: nsCOMPtr michael@0: service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Sorry for the #if platform ugliness, but Communicator is likewise michael@0: // hardcoded and we are seeking backward compatibility here (bug 47080). michael@0: #if defined(_WIN64) michael@0: aPlatform.AssignLiteral("Win64"); michael@0: #elif defined(WIN32) michael@0: aPlatform.AssignLiteral("Win32"); michael@0: #elif defined(XP_MACOSX) && defined(__ppc__) michael@0: aPlatform.AssignLiteral("MacPPC"); michael@0: #elif defined(XP_MACOSX) && defined(__i386__) michael@0: aPlatform.AssignLiteral("MacIntel"); michael@0: #elif defined(XP_MACOSX) && defined(__x86_64__) michael@0: aPlatform.AssignLiteral("MacIntel"); michael@0: #else michael@0: // XXX Communicator uses compiled-in build-time string defines michael@0: // to indicate the platform it was compiled *for*, not what it is michael@0: // currently running *on* which is what this does. michael@0: nsAutoCString plat; michael@0: rv = service->GetOscpu(plat); michael@0: CopyASCIItoUTF16(plat, aPlatform); michael@0: #endif michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: /* static */ nsresult michael@0: Navigator::GetAppVersion(nsAString& aAppVersion, bool aUsePrefOverriddenValue) michael@0: { michael@0: if (aUsePrefOverriddenValue && !nsContentUtils::IsCallerChrome()) { michael@0: const nsAdoptingString& override = michael@0: mozilla::Preferences::GetString("general.appversion.override"); michael@0: michael@0: if (override) { michael@0: aAppVersion = override; michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: nsresult rv; michael@0: michael@0: nsCOMPtr michael@0: service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsAutoCString str; michael@0: rv = service->GetAppVersion(str); michael@0: CopyASCIItoUTF16(str, aAppVersion); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: aAppVersion.AppendLiteral(" ("); michael@0: michael@0: rv = service->GetPlatform(str); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: AppendASCIItoUTF16(str, aAppVersion); michael@0: aAppVersion.Append(char16_t(')')); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: /* static */ void michael@0: Navigator::AppName(nsAString& aAppName, bool aUsePrefOverriddenValue) michael@0: { michael@0: if (aUsePrefOverriddenValue && !nsContentUtils::IsCallerChrome()) { michael@0: const nsAdoptingString& override = michael@0: mozilla::Preferences::GetString("general.appname.override"); michael@0: michael@0: if (override) { michael@0: aAppName = override; michael@0: return; michael@0: } michael@0: } michael@0: michael@0: aAppName.AssignLiteral("Netscape"); michael@0: } michael@0: michael@0: } // namespace dom michael@0: } // namespace mozilla michael@0: michael@0: nsresult michael@0: NS_GetNavigatorUserAgent(nsAString& aUserAgent) michael@0: { michael@0: nsresult rv; michael@0: michael@0: nsCOMPtr michael@0: service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsAutoCString ua; michael@0: rv = service->GetUserAgent(ua); michael@0: CopyASCIItoUTF16(ua, aUserAgent); michael@0: michael@0: return rv; michael@0: }