Bug 1062920 - WorkerNavigator strings should honor general.*.override prefs, r=khuey
authorAndrea Marchesini <amarchesini@mozilla.com>
Tue, 23 Sep 2014 20:11:18 +0100
changeset 206730 b0b831a03d9caa85efec5b5e592b533036f4b106
parent 206729 84b81989aa76f18e117609e0c47c0810661b9f44
child 206731 78d2993b85c93bca9a09cc69df4241c1758121a4
push id49495
push useramarchesini@mozilla.com
push dateTue, 23 Sep 2014 19:11:56 +0000
treeherdermozilla-inbound@b0b831a03d9c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs1062920
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1062920 - WorkerNavigator strings should honor general.*.override prefs, r=khuey
dom/base/Navigator.cpp
dom/base/Navigator.h
dom/workers/Navigator.cpp
dom/workers/Navigator.h
dom/workers/RuntimeService.cpp
dom/workers/RuntimeService.h
dom/workers/test/bug1062920_worker.js
dom/workers/test/chrome.ini
dom/workers/test/mochitest.ini
dom/workers/test/test_bug1062920.html
dom/workers/test/test_bug1062920.xul
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -353,23 +353,23 @@ Navigator::GetAppCodeName(nsAString& aAp
   CopyASCIItoUTF16(appName, aAppCodeName);
 
   return rv;
 }
 
 NS_IMETHODIMP
 Navigator::GetAppVersion(nsAString& aAppVersion)
 {
-  return NS_GetNavigatorAppVersion(aAppVersion);
+  return GetAppVersion(aAppVersion, /* aUsePrefOverriddenValue */ true);
 }
 
 NS_IMETHODIMP
 Navigator::GetAppName(nsAString& aAppName)
 {
-  NS_GetNavigatorAppName(aAppName);
+  AppName(aAppName, /* aUsePrefOverriddenValue */ true);
   return NS_OK;
 }
 
 /**
  * Returns the value of Accept-Languages (HTTP header) as a nsTArray of
  * languages. The value is set in the preference by the user ("Content
  * Languages").
  *
@@ -452,17 +452,17 @@ Navigator::GetLanguages(nsTArray<nsStrin
   // accept languages change and will clear the cache when needed. It has to
   // take care of dispatching the DOM event already and the invalidation and the
   // event has to be timed correctly.
 }
 
 NS_IMETHODIMP
 Navigator::GetPlatform(nsAString& aPlatform)
 {
-  return NS_GetNavigatorPlatform(aPlatform);
+  return GetPlatform(aPlatform, /* aUsePrefOverriddenValue */ true);
 }
 
 NS_IMETHODIMP
 Navigator::GetOscpu(nsAString& aOSCPU)
 {
   if (!nsContentUtils::IsCallerChrome()) {
     const nsAdoptingString& override =
       Preferences::GetString("general.oscpu.override");
@@ -2342,39 +2342,22 @@ already_AddRefed<nsPIDOMWindow>
 Navigator::GetWindowFromGlobal(JSObject* aGlobal)
 {
   nsCOMPtr<nsPIDOMWindow> win =
     do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(aGlobal));
   MOZ_ASSERT(!win || win->IsInnerWindow());
   return win.forget();
 }
 
-} // namespace dom
-} // namespace mozilla
-
 nsresult
-NS_GetNavigatorUserAgent(nsAString& aUserAgent)
+Navigator::GetPlatform(nsAString& aPlatform, bool aUsePrefOverriddenValue)
 {
-  nsresult rv;
-
-  nsCOMPtr<nsIHttpProtocolHandler>
-    service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
-  NS_ENSURE_SUCCESS(rv, rv);
+  MOZ_ASSERT(NS_IsMainThread());
 
-  nsAutoCString ua;
-  rv = service->GetUserAgent(ua);
-  CopyASCIItoUTF16(ua, aUserAgent);
-
-  return rv;
-}
-
-nsresult
-NS_GetNavigatorPlatform(nsAString& aPlatform)
-{
-  if (!nsContentUtils::IsCallerChrome()) {
+  if (aUsePrefOverriddenValue && !nsContentUtils::IsCallerChrome()) {
     const nsAdoptingString& override =
       mozilla::Preferences::GetString("general.platform.override");
 
     if (override) {
       aPlatform = override;
       return NS_OK;
     }
   }
@@ -2403,20 +2386,21 @@ NS_GetNavigatorPlatform(nsAString& aPlat
   // currently running *on* which is what this does.
   nsAutoCString plat;
   rv = service->GetOscpu(plat);
   CopyASCIItoUTF16(plat, aPlatform);
 #endif
 
   return rv;
 }
-nsresult
-NS_GetNavigatorAppVersion(nsAString& aAppVersion)
+
+/* static */ nsresult
+Navigator::GetAppVersion(nsAString& aAppVersion, bool aUsePrefOverriddenValue)
 {
-  if (!nsContentUtils::IsCallerChrome()) {
+  if (aUsePrefOverriddenValue && !nsContentUtils::IsCallerChrome()) {
     const nsAdoptingString& override =
       mozilla::Preferences::GetString("general.appversion.override");
 
     if (override) {
       aAppVersion = override;
       return NS_OK;
     }
   }
@@ -2438,23 +2422,42 @@ NS_GetNavigatorAppVersion(nsAString& aAp
   NS_ENSURE_SUCCESS(rv, rv);
 
   AppendASCIItoUTF16(str, aAppVersion);
   aAppVersion.Append(char16_t(')'));
 
   return rv;
 }
 
-void
-NS_GetNavigatorAppName(nsAString& aAppName)
+/* static */ void
+Navigator::AppName(nsAString& aAppName, bool aUsePrefOverriddenValue)
 {
-  if (!nsContentUtils::IsCallerChrome()) {
+  if (aUsePrefOverriddenValue && !nsContentUtils::IsCallerChrome()) {
     const nsAdoptingString& override =
       mozilla::Preferences::GetString("general.appname.override");
 
     if (override) {
       aAppName = override;
       return;
     }
   }
 
   aAppName.AssignLiteral("Netscape");
 }
+
+} // namespace dom
+} // namespace mozilla
+
+nsresult
+NS_GetNavigatorUserAgent(nsAString& aUserAgent)
+{
+  nsresult rv;
+
+  nsCOMPtr<nsIHttpProtocolHandler>
+    service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsAutoCString ua;
+  rv = service->GetUserAgent(ua);
+  CopyASCIItoUTF16(ua, aUserAgent);
+
+  return rv;
+}
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -43,18 +43,16 @@ class ServiceWorkerContainer;
 #ifdef MOZ_B2G_RIL
 class nsIDOMMozIccManager;
 #endif // MOZ_B2G_RIL
 
 //*****************************************************************************
 // Navigator: Script "navigator" object
 //*****************************************************************************
 
-void NS_GetNavigatorAppName(nsAString& aAppName);
-
 namespace mozilla {
 namespace dom {
 
 namespace battery {
 class BatteryManager;
 } // namespace battery
 
 #ifdef MOZ_B2G_FM
@@ -156,16 +154,24 @@ public:
   Geolocation* GetGeolocation(ErrorResult& aRv);
   battery::BatteryManager* GetBattery(ErrorResult& aRv);
 
   static already_AddRefed<Promise> GetDataStores(nsPIDOMWindow* aWindow,
                                                  const nsAString& aName,
                                                  const nsAString& aOwner,
                                                  ErrorResult& aRv);
 
+  static void AppName(nsAString& aAppName, bool aUsePrefOverriddenValue);
+
+  static nsresult GetPlatform(nsAString& aPlatform,
+                              bool aUsePrefOverriddenValue);
+
+  static nsresult GetAppVersion(nsAString& aAppVersion,
+                                bool aUsePrefOverriddenValue);
+
   already_AddRefed<Promise> GetDataStores(const nsAString& aName,
                                           const nsAString& aOwner,
                                           ErrorResult& aRv);
 
   // Feature Detection API
   already_AddRefed<Promise> GetFeature(const nsAString& aName,
                                        ErrorResult& aRv);
 
@@ -346,12 +352,10 @@ private:
   // rocket science.  :(
   nsInterfaceHashtable<nsStringHashKey, nsISupports> mCachedResolveResults;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 nsresult NS_GetNavigatorUserAgent(nsAString& aUserAgent);
-nsresult NS_GetNavigatorPlatform(nsAString& aPlatform);
-nsresult NS_GetNavigatorAppVersion(nsAString& aAppVersion);
 
 #endif // mozilla_dom_Navigator_h
--- a/dom/workers/Navigator.cpp
+++ b/dom/workers/Navigator.cpp
@@ -31,19 +31,17 @@ WorkerNavigator::Create(bool aOnLine)
 {
   RuntimeService* rts = RuntimeService::GetService();
   MOZ_ASSERT(rts);
 
   const RuntimeService::NavigatorProperties& properties =
     rts->GetNavigatorProperties();
 
   nsRefPtr<WorkerNavigator> navigator =
-    new WorkerNavigator(properties.mAppName, properties.mAppVersion,
-                        properties.mPlatform, properties.mUserAgent,
-                        properties.mLanguages, aOnLine);
+    new WorkerNavigator(properties, aOnLine);
 
   return navigator.forget();
 }
 
 JSObject*
 WorkerNavigator::WrapObject(JSContext* aCx)
 {
   return WorkerNavigatorBinding_workers::Wrap(aCx, this);
@@ -277,12 +275,54 @@ WorkerNavigator::GetDataStores(JSContext
 
   return promise.forget();
 }
 
 void
 WorkerNavigator::SetLanguages(const nsTArray<nsString>& aLanguages)
 {
   WorkerNavigatorBinding_workers::ClearCachedLanguagesValue(this);
-  mLanguages = aLanguages;
+  mProperties.mLanguages = aLanguages;
+}
+
+void
+WorkerNavigator::GetAppName(nsString& aAppName) const
+{
+  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
+  MOZ_ASSERT(workerPrivate);
+
+  if (!mProperties.mAppNameOverridden.IsEmpty() &&
+      !workerPrivate->UsesSystemPrincipal()) {
+    aAppName = mProperties.mAppNameOverridden;
+  } else {
+    aAppName = mProperties.mAppName;
+  }
+}
+
+void
+WorkerNavigator::GetAppVersion(nsString& aAppVersion) const
+{
+  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
+  MOZ_ASSERT(workerPrivate);
+
+  if (!mProperties.mAppVersionOverridden.IsEmpty() &&
+      !workerPrivate->UsesSystemPrincipal()) {
+    aAppVersion = mProperties.mAppVersionOverridden;
+  } else {
+    aAppVersion = mProperties.mAppVersion;
+  }
+}
+
+void
+WorkerNavigator::GetPlatform(nsString& aPlatform) const
+{
+  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
+  MOZ_ASSERT(workerPrivate);
+
+  if (!mProperties.mPlatformOverridden.IsEmpty() &&
+      !workerPrivate->UsesSystemPrincipal()) {
+    aPlatform = mProperties.mPlatformOverridden;
+  } else {
+    aPlatform = mProperties.mPlatform;
+  }
 }
 
 END_WORKERS_NAMESPACE
--- a/dom/workers/Navigator.h
+++ b/dom/workers/Navigator.h
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_workers_navigator_h__
 #define mozilla_dom_workers_navigator_h__
 
 #include "Workers.h"
+#include "RuntimeService.h"
 #include "nsString.h"
 #include "nsWrapperCache.h"
 
 // Need this to use Navigator::HasDataStoreSupport() in
 // WorkerNavigatorBinding.cpp
 #include "mozilla/dom/Navigator.h"
 
 namespace mozilla {
@@ -19,34 +20,24 @@ namespace dom {
 class Promise;
 }
 }
 
 BEGIN_WORKERS_NAMESPACE
 
 class WorkerNavigator MOZ_FINAL : public nsWrapperCache
 {
-  nsString mAppName;
-  nsString mAppVersion;
-  nsString mPlatform;
-  nsString mUserAgent;
-  nsTArray<nsString> mLanguages;
+  typedef struct RuntimeService::NavigatorProperties NavigatorProperties;
+
+  NavigatorProperties mProperties;
   bool mOnline;
 
-  WorkerNavigator(const nsAString& aAppName,
-                  const nsAString& aAppVersion,
-                  const nsAString& aPlatform,
-                  const nsAString& aUserAgent,
-                  const nsTArray<nsString>& aLanguages,
+  WorkerNavigator(const NavigatorProperties& aProperties,
                   bool aOnline)
-    : mAppName(aAppName)
-    , mAppVersion(aAppVersion)
-    , mPlatform(aPlatform)
-    , mUserAgent(aUserAgent)
-    , mLanguages(aLanguages)
+    : mProperties(aProperties)
     , mOnline(aOnline)
   {
     MOZ_COUNT_CTOR(WorkerNavigator);
     SetIsDOMBinding();
   }
 
   ~WorkerNavigator()
   {
@@ -67,56 +58,49 @@ public:
   nsISupports* GetParentObject() const {
     return nullptr;
   }
 
   void GetAppCodeName(nsString& aAppCodeName) const
   {
     aAppCodeName.AssignLiteral("Mozilla");
   }
-  void GetAppName(nsString& aAppName) const
-  {
-    aAppName = mAppName;
-  }
+  void GetAppName(nsString& aAppName) const;
 
-  void GetAppVersion(nsString& aAppVersion) const
-  {
-    aAppVersion = mAppVersion;
-  }
+  void GetAppVersion(nsString& aAppVersion) const;
 
-  void GetPlatform(nsString& aPlatform) const
-  {
-    aPlatform = mPlatform;
-  }
+  void GetPlatform(nsString& aPlatform) const;
+
   void GetProduct(nsString& aProduct) const
   {
     aProduct.AssignLiteral("Gecko");
   }
+
   bool TaintEnabled() const
   {
     return false;
   }
 
   void GetLanguage(nsString& aLanguage) const
   {
-    if (mLanguages.Length() >= 1) {
-      aLanguage.Assign(mLanguages[0]);
+    if (mProperties.mLanguages.Length() >= 1) {
+      aLanguage.Assign(mProperties.mLanguages[0]);
     } else {
       aLanguage.Truncate();
     }
   }
 
   void GetLanguages(nsTArray<nsString>& aLanguages) const
   {
-    aLanguages = mLanguages;
+    aLanguages = mProperties.mLanguages;
   }
 
   void GetUserAgent(nsString& aUserAgent) const
   {
-    aUserAgent = mUserAgent;
+    aUserAgent = mProperties.mUserAgent;
   }
 
   bool OnLine() const
   {
     return mOnline;
   }
 
   // Worker thread only!
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -119,16 +119,20 @@ static_assert(MAX_WORKERS_PER_DOMAIN >= 
 
 #define PREF_MAX_SCRIPT_RUN_TIME_CONTENT "dom.max_script_run_time"
 #define PREF_MAX_SCRIPT_RUN_TIME_CHROME "dom.max_chrome_script_run_time"
 
 #define GC_REQUEST_OBSERVER_TOPIC "child-gc-request"
 #define CC_REQUEST_OBSERVER_TOPIC "child-cc-request"
 #define MEMORY_PRESSURE_OBSERVER_TOPIC "memory-pressure"
 
+#define PREF_GENERAL_APPNAME_OVERRIDE "general.appname.override"
+#define PREF_GENERAL_APPVERSION_OVERRIDE "general.appversion.override"
+#define PREF_GENERAL_PLATFORM_OVERRIDE "general.platform.override"
+
 #define BROADCAST_ALL_WORKERS(_func, ...)                                      \
   PR_BEGIN_MACRO                                                               \
     AssertIsOnMainThread();                                                    \
                                                                                \
     nsAutoTArray<WorkerPrivate*, 100> workers;                                 \
     {                                                                          \
       MutexAutoLock lock(mMutex);                                              \
                                                                                \
@@ -1037,16 +1041,58 @@ PrefLanguagesChanged(const char* /* aPre
   Navigator::GetAcceptLanguages(languages);
 
   RuntimeService* runtime = RuntimeService::GetService();
   if (runtime) {
     runtime->UpdateAllWorkerLanguages(languages);
   }
 }
 
+void
+AppNameOverrideChanged(const char* /* aPrefName */, void* /* aClosure */)
+{
+  AssertIsOnMainThread();
+
+  const nsAdoptingString& override =
+    mozilla::Preferences::GetString(PREF_GENERAL_APPNAME_OVERRIDE);
+
+  RuntimeService* runtime = RuntimeService::GetService();
+  if (runtime) {
+    runtime->UpdateAppNameOverridePreference(override);
+  }
+}
+
+void
+AppVersionOverrideChanged(const char* /* aPrefName */, void* /* aClosure */)
+{
+  AssertIsOnMainThread();
+
+  const nsAdoptingString& override =
+    mozilla::Preferences::GetString(PREF_GENERAL_APPVERSION_OVERRIDE);
+
+  RuntimeService* runtime = RuntimeService::GetService();
+  if (runtime) {
+    runtime->UpdateAppVersionOverridePreference(override);
+  }
+}
+
+void
+PlatformOverrideChanged(const char* /* aPrefName */, void* /* aClosure */)
+{
+  AssertIsOnMainThread();
+
+  const nsAdoptingString& override =
+    mozilla::Preferences::GetString(PREF_GENERAL_PLATFORM_OVERRIDE);
+
+  RuntimeService* runtime = RuntimeService::GetService();
+  if (runtime) {
+    runtime->UpdatePlatformOverridePreference(override);
+  }
+}
+
 } /* anonymous namespace */
 
 class RuntimeService::WorkerThread MOZ_FINAL : public nsThread
 {
   class Observer MOZ_FINAL : public nsIThreadObserver
   {
     WorkerPrivate* mWorkerPrivate;
 
@@ -1459,25 +1505,30 @@ RuntimeService::RegisterWorker(JSContext
   if (parent) {
     if (!parent->AddChildWorker(aCx, aWorkerPrivate)) {
       UnregisterWorker(aCx, aWorkerPrivate);
       return false;
     }
   }
   else {
     if (!mNavigatorPropertiesLoaded) {
-      NS_GetNavigatorAppName(mNavigatorProperties.mAppName);
-      if (NS_FAILED(NS_GetNavigatorAppVersion(mNavigatorProperties.mAppVersion)) ||
-          NS_FAILED(NS_GetNavigatorPlatform(mNavigatorProperties.mPlatform)) ||
+      Navigator::AppName(mNavigatorProperties.mAppName,
+                         false /* aUsePrefOverriddenValue */);
+      if (NS_FAILED(Navigator::GetAppVersion(mNavigatorProperties.mAppVersion,
+                                             false /* aUsePrefOverriddenValue */)) ||
+          NS_FAILED(Navigator::GetPlatform(mNavigatorProperties.mPlatform,
+                                           false /* aUsePrefOverriddenValue */)) ||
           NS_FAILED(NS_GetNavigatorUserAgent(mNavigatorProperties.mUserAgent))) {
         JS_ReportError(aCx, "Failed to load navigator strings!");
         UnregisterWorker(aCx, aWorkerPrivate);
         return false;
       }
 
+      // The navigator overridden properties should have already been read.
+
       Navigator::GetAcceptLanguages(mNavigatorProperties.mLanguages);
       mNavigatorPropertiesLoaded = true;
     }
 
     nsPIDOMWindow* window = aWorkerPrivate->GetWindow();
 
     nsTArray<WorkerPrivate*>* windowArray;
     if (!mWindowMap.Get(window, &windowArray)) {
@@ -1812,16 +1863,28 @@ RuntimeService::Init()
       NS_FAILED(Preferences::RegisterCallbackAndCall(
                                                    LoadRuntimeOptions,
                                                    PREF_WORKERS_OPTIONS_PREFIX,
                                                    nullptr)) ||
       NS_FAILED(Preferences::RegisterCallbackAndCall(PrefLanguagesChanged,
                                                      PREF_INTL_ACCEPT_LANGUAGES,
                                                      nullptr)) ||
       NS_FAILED(Preferences::RegisterCallbackAndCall(
+                                                  AppNameOverrideChanged,
+                                                  PREF_GENERAL_APPNAME_OVERRIDE,
+                                                  nullptr)) ||
+      NS_FAILED(Preferences::RegisterCallbackAndCall(
+                                               AppVersionOverrideChanged,
+                                               PREF_GENERAL_APPVERSION_OVERRIDE,
+                                               nullptr)) ||
+      NS_FAILED(Preferences::RegisterCallbackAndCall(
+                                                 PlatformOverrideChanged,
+                                                 PREF_GENERAL_PLATFORM_OVERRIDE,
+                                                 nullptr)) ||
+      NS_FAILED(Preferences::RegisterCallbackAndCall(
                                                  JSVersionChanged,
                                                  PREF_WORKERS_LATEST_JS_VERSION,
                                                  nullptr))) {
     NS_WARNING("Failed to register pref callbacks!");
   }
 
   NS_ASSERTION(gRuntimeServiceDuringInit == this, "Should be 'this'!");
   gRuntimeServiceDuringInit = nullptr;
@@ -1957,19 +2020,27 @@ RuntimeService::Cleanup()
   }
 
   NS_ASSERTION(!mWindowMap.Count(), "All windows should have been released!");
 
   if (mObserved) {
     if (NS_FAILED(Preferences::UnregisterCallback(JSVersionChanged,
                                                   PREF_WORKERS_LATEST_JS_VERSION,
                                                   nullptr)) ||
-        NS_FAILED(Preferences::UnregisterCallback(PrefLanguagesChanged,
-                                                  PREF_INTL_ACCEPT_LANGUAGES,
+        NS_FAILED(Preferences::UnregisterCallback(AppNameOverrideChanged,
+                                                  PREF_GENERAL_APPNAME_OVERRIDE,
                                                   nullptr)) ||
+        NS_FAILED(Preferences::UnregisterCallback(
+                                               AppVersionOverrideChanged,
+                                               PREF_GENERAL_APPVERSION_OVERRIDE,
+                                               nullptr)) ||
+        NS_FAILED(Preferences::UnregisterCallback(
+                                                 PlatformOverrideChanged,
+                                                 PREF_GENERAL_PLATFORM_OVERRIDE,
+                                                 nullptr)) ||
         NS_FAILED(Preferences::UnregisterCallback(LoadRuntimeOptions,
                                                   PREF_JS_OPTIONS_PREFIX,
                                                   nullptr)) ||
         NS_FAILED(Preferences::UnregisterCallback(LoadRuntimeOptions,
                                                   PREF_WORKERS_OPTIONS_PREFIX,
                                                   nullptr)) ||
         NS_FAILED(Preferences::UnregisterCallback(
                                   WorkerPrefChanged,
@@ -2421,16 +2492,37 @@ RuntimeService::NoteIdleThread(WorkerThr
 
 void
 RuntimeService::UpdateAllWorkerRuntimeOptions()
 {
   BROADCAST_ALL_WORKERS(UpdateRuntimeOptions, sDefaultJSSettings.runtimeOptions);
 }
 
 void
+RuntimeService::UpdateAppNameOverridePreference(const nsAString& aValue)
+{
+  AssertIsOnMainThread();
+  mNavigatorProperties.mAppNameOverridden = aValue;
+}
+
+void
+RuntimeService::UpdateAppVersionOverridePreference(const nsAString& aValue)
+{
+  AssertIsOnMainThread();
+  mNavigatorProperties.mAppVersionOverridden = aValue;
+}
+
+void
+RuntimeService::UpdatePlatformOverridePreference(const nsAString& aValue)
+{
+  AssertIsOnMainThread();
+  mNavigatorProperties.mPlatformOverridden = aValue;
+}
+
+void
 RuntimeService::UpdateAllWorkerPreference(WorkerPreference aPref, bool aValue)
 {
   BROADCAST_ALL_WORKERS(UpdatePreference, aPref, aValue);
 }
 
 void
 RuntimeService::UpdateAllWorkerLanguages(const nsTArray<nsString>& aLanguages)
 {
--- a/dom/workers/RuntimeService.h
+++ b/dom/workers/RuntimeService.h
@@ -100,18 +100,21 @@ private:
 
   static JSSettings sDefaultJSSettings;
   static bool sDefaultPreferences[WORKERPREF_COUNT];
 
 public:
   struct NavigatorProperties
   {
     nsString mAppName;
+    nsString mAppNameOverridden;
     nsString mAppVersion;
+    nsString mAppVersionOverridden;
     nsString mPlatform;
+    nsString mPlatformOverridden;
     nsString mUserAgent;
     nsTArray<nsString> mLanguages;
   };
 
 private:
   NavigatorProperties mNavigatorProperties;
 
   // True when the observer service holds a reference to this object.
@@ -196,16 +199,25 @@ public:
   static void
   SetDefaultRuntimeOptions(const JS::RuntimeOptions& aRuntimeOptions)
   {
     AssertIsOnMainThread();
     sDefaultJSSettings.runtimeOptions = aRuntimeOptions;
   }
 
   void
+  UpdateAppNameOverridePreference(const nsAString& aValue);
+
+  void
+  UpdateAppVersionOverridePreference(const nsAString& aValue);
+
+  void
+  UpdatePlatformOverridePreference(const nsAString& aValue);
+
+  void
   UpdateAllWorkerRuntimeOptions();
 
   void
   UpdateAllWorkerLanguages(const nsTArray<nsString>& aLanguages);
 
   void
   UpdateAllWorkerPreference(WorkerPreference aPref, bool aValue);
 
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/bug1062920_worker.js
@@ -0,0 +1,6 @@
+postMessage({ appCodeName: navigator.appCodeName,
+              appName: navigator.appName,
+              appVersion: navigator.appVersion,
+              platform: navigator.platform,
+              userAgent: navigator.userAgent,
+              product: navigator.product });
--- a/dom/workers/test/chrome.ini
+++ b/dom/workers/test/chrome.ini
@@ -13,16 +13,17 @@ support-files =
   fileReaderSyncErrors_worker.js
   fileReaderSync_worker.js
   fileSlice_worker.js
   fileSubWorker_worker.js
   file_worker.js
   jsm_url_worker.js
   workersDisabled_worker.js
   file_url.jsm
+  bug1062920_worker.js
 
 [test_bug883784.jsm]
 [test_bug883784.xul]
 [test_chromeWorker.xul]
 [test_chromeWorkerJSM.xul]
 [test_extension.xul]
 [test_extensionBootstrap.xul]
 [test_file.xul]
@@ -31,8 +32,9 @@ support-files =
 [test_filePosting.xul]
 [test_fileReadSlice.xul]
 [test_fileReaderSync.xul]
 [test_fileReaderSyncErrors.xul]
 [test_fileSlice.xul]
 [test_fileSubWorker.xul]
 [test_workersDisabled.xul]
 [test_url.xul]
+[test_bug1062920.xul]
--- a/dom/workers/test/mochitest.ini
+++ b/dom/workers/test/mochitest.ini
@@ -79,16 +79,17 @@ support-files =
   subdir/relativeLoad_sub_worker.js
   subdir/relativeLoad_sub_worker2.js
   subdir/relativeLoad_sub_import.js
   test_worker_interfaces.js
   test_worker_performance_now.js
   worker_driver.js
   worker_wrapper.js
   bug1060621_worker.js
+  bug1062920_worker.js
 
 [test_404.html]
 [test_atob.html]
 [test_blobConstructor.html]
 [test_blobWorkers.html]
 [test_bug1002702.html]
 [test_bug949946.html]
 [test_bug1010784.html]
@@ -169,8 +170,9 @@ skip-if = buildapp == 'b2g' || e10s
 [test_xhr_system.html]
 skip-if = buildapp == 'b2g' || e10s
 [test_xhr_system.js]
 [test_xhr_timeout.html]
 skip-if = (os == "win") || (os == "mac") || toolkit == 'android' || e10s #bug 798220
 [test_url_exceptions.html]
 [test_urlSearchParams.html]
 [test_bug1060621.html]
+[test_bug1062920.html]
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/test_bug1062920.html
@@ -0,0 +1,61 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for navigator property override</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+<script class="testbody" type="text/javascript">
+
+  function checkValues() {
+    var worker = new Worker("bug1062920_worker.js");
+
+    worker.onmessage = function(event) {
+      is(event.data.appCodeName, navigator.appCodeName, "appCodeName should match");
+      is(event.data.appName, navigator.appName, "appName should match");
+      is(event.data.appVersion, navigator.appVersion, "appVersion should match");
+      is(event.data.platform, navigator.platform, "platform should match");
+      is(event.data.userAgent, navigator.userAgent, "userAgent should match");
+      is(event.data.product, navigator.product, "product should match");
+      runTests();
+    };
+  }
+
+  function replaceAndCheckValues() {
+    SpecialPowers.pushPrefEnv({"set": [
+      ["general.appname.override", "appName overridden"],
+      ["general.appversion.override", "appVersion overridden"],
+      ["general.platform.override", "platform overridden"]
+    ]}, checkValues);
+  }
+
+  var tests = [
+    checkValues,
+    replaceAndCheckValues
+  ];
+
+  function runTests() {
+    if (tests.length == 0) {
+      SimpleTest.finish();
+      return;
+    }
+
+    var test = tests.shift();
+    test();
+  }
+
+  SimpleTest.waitForExplicitFinish();
+  runTests();
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/test_bug1062920.xul
@@ -0,0 +1,68 @@
+<?xml version="1.0"?>
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<window title="DOM Worker Threads Test"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+  <script type="application/javascript" src="dom_worker_helper.js"/>
+
+  <script type="application/javascript">
+
+  function checkValues() {
+    var worker = new Worker("bug1062920_worker.js");
+
+    worker.onmessage = function(event) {
+      is(event.data.appCodeName, navigator.appCodeName, "appCodeName should match");
+      is(event.data.appName, navigator.appName, "appName should match");
+      isnot(event.data.appName, "appName overridden", "appName is not overridden");
+      is(event.data.appVersion, navigator.appVersion, "appVersion should match");
+      isnot(event.data.appVersion, "appVersion overridden", "appVersion is not overridden");
+      is(event.data.platform, navigator.platform, "platform should match");
+      isnot(event.data.platform, "platform overridden", "platform is not overridden");
+      is(event.data.userAgent, navigator.userAgent, "userAgent should match");
+      is(event.data.product, navigator.product, "product should match");
+      runTests();
+    };
+  }
+
+  function replaceAndCheckValues() {
+    SpecialPowers.pushPrefEnv({"set": [
+      ["general.appname.override", "appName overridden"],
+      ["general.appversion.override", "appVersion overridden"],
+      ["general.platform.override", "platform overridden"]
+    ]}, checkValues);
+  }
+
+  var tests = [
+    checkValues,
+    replaceAndCheckValues
+  ];
+
+  function runTests() {
+    if (tests.length == 0) {
+      SimpleTest.finish();
+      return;
+    }
+
+    var test = tests.shift();
+    test();
+  }
+
+  SimpleTest.waitForExplicitFinish();
+  runTests();
+
+  </script>
+
+  <body xmlns="http://www.w3.org/1999/xhtml">
+    <p id="display"></p>
+    <div id="content" style="display:none;"></div>
+    <pre id="test"></pre>
+  </body>
+  <label id="test-result"/>
+</window>