Bug 1062920 - WorkerNavigator strings should honor general.*.override prefs. r=khuey, a=sledru
authorAndrea Marchesini <amarchesini@mozilla.com>
Tue, 23 Sep 2014 20:11:18 +0100
changeset 216850 6d53cfba12f0
parent 216849 32d5ee00c3ab
child 216851 e178848e43d1
push id3941
push userryanvm@gmail.com
push date2014-09-25 21:01 +0000
treeherdermozilla-beta@e178848e43d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey, sledru
bugs1062920
milestone33.0
Bug 1062920 - WorkerNavigator strings should honor general.*.override prefs. r=khuey, a=sledru
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").
  *
@@ -450,17 +450,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");
@@ -2377,39 +2377,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;
     }
   }
@@ -2438,20 +2421,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;
     }
   }
@@ -2473,23 +2457,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
@@ -42,18 +42,16 @@ struct MobileIdOptions;
 #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
@@ -158,16 +156,24 @@ public:
   // The XPCOM GetDoNotTrack is ok
   Geolocation* GetGeolocation(ErrorResult& aRv);
   battery::BatteryManager* GetBattery(ErrorResult& aRv);
 
   static already_AddRefed<Promise> GetDataStores(nsPIDOMWindow* aWindow,
                                                  const nsAString& aName,
                                                  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,
                                           ErrorResult& aRv);
 
   // Feature Detection API
   already_AddRefed<Promise> GetFeature(const nsAString &aName,
                                        ErrorResult& aRv);
 
   bool Vibrate(uint32_t aDuration);
@@ -345,12 +351,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,
-                        aOnLine);
+    new WorkerNavigator(properties, aOnLine);
 
   return navigator.forget();
 }
 
 JSObject*
 WorkerNavigator::WrapObject(JSContext* aCx)
 {
   return WorkerNavigatorBinding_workers::Wrap(aCx, this);
@@ -268,9 +266,51 @@ WorkerNavigator::GetDataStores(JSContext
 
   nsRefPtr<NavigatorGetDataStoresRunnable> runnable =
     new NavigatorGetDataStoresRunnable(workerPrivate, promise, aName, aRv);
   runnable->Dispatch(aCx);
 
   return promise.forget();
 }
 
+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,31 +20,24 @@ namespace dom {
 class Promise;
 }
 }
 
 BEGIN_WORKERS_NAMESPACE
 
 class WorkerNavigator MOZ_FINAL : public nsWrapperCache
 {
-  nsString mAppName;
-  nsString mAppVersion;
-  nsString mPlatform;
-  nsString mUserAgent;
+  typedef struct RuntimeService::NavigatorProperties NavigatorProperties;
+
+  NavigatorProperties mProperties;
   bool mOnline;
 
-  WorkerNavigator(const nsAString& aAppName,
-                  const nsAString& aAppVersion,
-                  const nsAString& aPlatform,
-                  const nsAString& aUserAgent,
+  WorkerNavigator(const NavigatorProperties& aProperties,
                   bool aOnline)
-    : mAppName(aAppName)
-    , mAppVersion(aAppVersion)
-    , mPlatform(aPlatform)
-    , mUserAgent(aUserAgent)
+    : mProperties(aProperties)
     , mOnline(aOnline)
   {
     MOZ_COUNT_CTOR(WorkerNavigator);
     SetIsDOMBinding();
   }
 
   ~WorkerNavigator()
   {
@@ -64,42 +58,35 @@ 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 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
@@ -118,16 +118,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 @@ private:
 
   virtual bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
   {
     return mTask->RunTask(aCx);
   }
 };
 
+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;
 
@@ -1432,25 +1478,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.
+
       mNavigatorPropertiesLoaded = true;
     }
 
     nsPIDOMWindow* window = aWorkerPrivate->GetWindow();
 
     nsTArray<WorkerPrivate*>* windowArray;
     if (!mWindowMap.Get(window, &windowArray)) {
       windowArray = new nsTArray<WorkerPrivate*>(1);
@@ -1779,16 +1830,28 @@ RuntimeService::Init()
       NS_FAILED(Preferences::RegisterCallback(LoadRuntimeAndContextOptions,
                                               PREF_JS_OPTIONS_PREFIX,
                                               nullptr)) ||
       NS_FAILED(Preferences::RegisterCallbackAndCall(
                                                    LoadRuntimeAndContextOptions,
                                                    PREF_WORKERS_OPTIONS_PREFIX,
                                                    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;
@@ -1924,16 +1987,25 @@ 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(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(LoadRuntimeAndContextOptions,
                                                   PREF_JS_OPTIONS_PREFIX,
                                                   nullptr)) ||
         NS_FAILED(Preferences::UnregisterCallback(LoadRuntimeAndContextOptions,
                                                   PREF_WORKERS_OPTIONS_PREFIX,
                                                   nullptr)) ||
 #if DUMP_CONTROLLED_BY_PREF
         NS_FAILED(Preferences::UnregisterCallback(
@@ -2384,16 +2456,37 @@ RuntimeService::UpdateAllWorkerRuntimeAn
 {
   BROADCAST_ALL_WORKERS(UpdateRuntimeAndContextOptions,
                         sDefaultJSSettings.runtimeOptions,
                         sDefaultJSSettings.content.contextOptions,
                         sDefaultJSSettings.chrome.contextOptions);
 }
 
 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::UpdateAllWorkerMemoryParameter(JSGCParamKey aKey,
                                                uint32_t aValue)
--- 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;
   };
 
 private:
   NavigatorProperties mNavigatorProperties;
 
   // True when the observer service holds a reference to this object.
   bool mObserved;
@@ -200,16 +203,25 @@ public:
   {
     AssertIsOnMainThread();
     sDefaultJSSettings.runtimeOptions = aRuntimeOptions;
     sDefaultJSSettings.content.contextOptions = aContentCxOptions;
     sDefaultJSSettings.chrome.contextOptions = aChromeCxOptions;
   }
 
   void
+  UpdateAppNameOverridePreference(const nsAString& aValue);
+
+  void
+  UpdateAppVersionOverridePreference(const nsAString& aValue);
+
+  void
+  UpdatePlatformOverridePreference(const nsAString& aValue);
+
+  void
   UpdateAllWorkerRuntimeAndContextOptions();
 
   void
   UpdateAllWorkerPreference(WorkerPreference aPref, bool aValue);
 
   static void
   SetDefaultJSGCSettings(JSGCParamKey aKey, uint32_t 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
@@ -73,16 +73,17 @@ support-files =
   xhr_headers_worker.js
   xhr_headers_server.sjs
   url_exceptions_worker.js
   urlSearchParams_worker.js
   subdir/relativeLoad_sub_worker.js
   subdir/relativeLoad_sub_worker2.js
   subdir/relativeLoad_sub_import.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]
@@ -158,8 +159,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>