From a5268caf0ac3add1c1581bd72ad9053528607926 Mon Sep 17 00:00:00 2001 From: Fernando Jimenez Date: Tue, 21 Jul 2015 21:34:37 +0200 Subject: [PATCH 01/96] Bug 1182071 - Allow System app to fetch Sync keys. r=spenrose --- b2g/components/FxAccountsMgmtService.jsm | 17 ++-- services/fxaccounts/FxAccountsCommon.js | 1 + services/fxaccounts/FxAccountsManager.jsm | 41 +++++++++- .../fxaccounts/tests/xpcshell/test_manager.js | 78 +++++++++++++++++++ 4 files changed, 130 insertions(+), 7 deletions(-) diff --git a/b2g/components/FxAccountsMgmtService.jsm b/b2g/components/FxAccountsMgmtService.jsm index ee11c53894f0..427dbcdf09b3 100644 --- a/b2g/components/FxAccountsMgmtService.jsm +++ b/b2g/components/FxAccountsMgmtService.jsm @@ -93,12 +93,19 @@ this.FxAccountsMgmtService = { delete data.accountId; } + // XXX dirty hack because Gaia is sending getAccounts. + if (data.method == "getAccounts") { + data.method = "getAccount"; + } + switch(data.method) { - case "getAccounts": - FxAccountsManager.getAccount().then( - account => { - // We only expose the email and verification status so far. - self._onFulfill(msg.id, account); + case "getAccount": + case "getKeys": + FxAccountsManager[data.method]().then( + result => { + // For the getAccounts case, we only expose the email and + // verification status so far. + self._onFulfill(msg.id, result); }, reason => { self._onReject(msg.id, reason); diff --git a/services/fxaccounts/FxAccountsCommon.js b/services/fxaccounts/FxAccountsCommon.js index 9d90ad380626..065403fb9ebd 100644 --- a/services/fxaccounts/FxAccountsCommon.js +++ b/services/fxaccounts/FxAccountsCommon.js @@ -176,6 +176,7 @@ exports.ERROR_OFFLINE = "OFFLINE"; exports.ERROR_PERMISSION_DENIED = "PERMISSION_DENIED"; exports.ERROR_REQUEST_BODY_TOO_LARGE = "REQUEST_BODY_TOO_LARGE"; exports.ERROR_SERVER_ERROR = "SERVER_ERROR"; +exports.ERROR_SYNC_DISABLED = "SYNC_DISABLED"; exports.ERROR_TOO_MANY_CLIENT_REQUESTS = "TOO_MANY_CLIENT_REQUESTS"; exports.ERROR_SERVICE_TEMP_UNAVAILABLE = "SERVICE_TEMPORARY_UNAVAILABLE"; exports.ERROR_UI_ERROR = "UI_ERROR"; diff --git a/services/fxaccounts/FxAccountsManager.jsm b/services/fxaccounts/FxAccountsManager.jsm index 3531a7bd0edf..02d33b806cf9 100644 --- a/services/fxaccounts/FxAccountsManager.jsm +++ b/services/fxaccounts/FxAccountsManager.jsm @@ -127,7 +127,15 @@ this.FxAccountsManager = { user: this._user }); } - return client[aMethod](aEmail, aPassword); + let syncEnabled = false; + try { + syncEnabled = Services.prefs.getBoolPref("services.sync.enabled"); + } catch(e) { + dump(e + "\n"); + } + // XXX Refetch FxA credentials if services.sync.enabled preference + // changes. Bug 1183103 + return client[aMethod](aEmail, aPassword, syncEnabled); } ).then( user => { @@ -577,8 +585,37 @@ this.FxAccountsManager = { return this._uiRequest(UI_REQUEST_SIGN_IN_FLOW, aAudience, principal); } ); - } + }, + getKeys: function() { + let syncEnabled = false; + try { + syncEnabled = Services.prefs.getBoolPref("services.sync.enabled"); + } catch(e) { + dump("Sync is disabled, so you won't get the keys. " + e + "\n"); + } + + if (!syncEnabled) { + return Promise.reject(ERROR_SYNC_DISABLED); + } + + return this.getAccount().then( + user => { + if (!user) { + log.debug("No signed in user"); + return Promise.resolve(null); + } + + if (!user.verified) { + return this._error(ERROR_UNVERIFIED_ACCOUNT, { + user: user + }); + } + + return this._fxAccounts.getKeys(); + } + ); + } }; FxAccountsManager.init(); diff --git a/services/fxaccounts/tests/xpcshell/test_manager.js b/services/fxaccounts/tests/xpcshell/test_manager.js index 36e2d0a98506..37774bd6fcc8 100644 --- a/services/fxaccounts/tests/xpcshell/test_manager.js +++ b/services/fxaccounts/tests/xpcshell/test_manager.js @@ -101,6 +101,7 @@ FxAccountsManager._fxAccounts = { _error: 'error', _assertion: 'assertion', + _keys: 'keys', _signedInUser: null, _reset: function() { @@ -139,6 +140,13 @@ FxAccountsManager._fxAccounts = { return deferred.promise; }, + getKeys: function() { + let deferred = Promise.defer(); + this._reject ? deferred.reject(this._error) + : deferred.resolve(this._keys); + return deferred.promise; + }, + resendVerificationEmail: function() { return this.getSignedInUser().then(data => { if (data) { @@ -899,3 +907,73 @@ add_test(function() { run_next_test(); }); }); + +add_test(function(test_getKeys_sync_disabled) { + do_print("= getKeys sync disabled ="); + Services.prefs.setBoolPref("services.sync.enabled", false); + FxAccountsManager.getKeys().then( + result => { + do_throw("Unexpected success"); + }, + error => { + do_check_eq(error, ERROR_SYNC_DISABLED); + Services.prefs.clearUserPref("services.sync.enabled"); + run_next_test(); + } + ); +}); + +add_test(function(test_getKeys_no_session) { + do_print("= getKeys no session ="); + Services.prefs.setBoolPref("services.sync.enabled", true); + FxAccountsManager._fxAccounts._signedInUser = null; + FxAccountsManager._activeSession = null; + FxAccountsManager.getKeys().then( + result => { + do_check_null(result); + FxAccountsManager._fxAccounts._reset(); + Services.prefs.clearUserPref("services.sync.enabled"); + run_next_test(); + }, + error => { + do_throw("Unexpected error: " + error); + } + ); +}); + +add_test(function(test_getKeys_unverified_account) { + do_print("= getKeys unverified ="); + Services.prefs.setBoolPref("services.sync.enabled", true); + FakeFxAccountsClient._verified = false; + FxAccountsManager.signIn("user@domain.org", "password").then(result => { + do_check_false(result.verified); + return FxAccountsManager.getKeys(); + }).then(result => { + do_throw("Unexpected success"); + }, + error => { + do_check_eq(error.error, ERROR_UNVERIFIED_ACCOUNT); + FxAccountsManager._fxAccounts._reset(); + Services.prefs.clearUserPref("services.sync.enabled"); + FxAccountsManager.signOut().then(run_next_test) + } + ); +}); + +add_test(function(test_getKeys_success) { + do_print("= getKeys success ="); + Services.prefs.setBoolPref("services.sync.enabled", true); + FakeFxAccountsClient._verified = true; + FxAccountsManager.signIn("user@domain.org", "password").then(result => { + return FxAccountsManager.getKeys(); + }).then(result => { + do_check_eq(result, FxAccountsManager._fxAccounts._keys); + FxAccountsManager._fxAccounts._reset(); + Services.prefs.clearUserPref("services.sync.enabled"); + run_next_test(); + }, + error => { + do_throw("Unexpected error " + error); + } + ); +}); From d36ea2dd7714aa9618703acd3e52eff9cad8b0c0 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Tue, 21 Jul 2015 12:35:58 -0700 Subject: [PATCH 02/96] Bug 1167292 - Part 1: Add a telemetry probe to time how long it takes to save a heap snapshot; r=ejpbruel --- toolkit/components/telemetry/Histograms.json | 7 +++++++ toolkit/devtools/server/HeapSnapshot.cpp | 19 +++++++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index c17594ba9493..7ad3c2a44d6c 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -7078,6 +7078,13 @@ "n_buckets": "100", "description": "The mean number of pinned tabs (app tabs) in all windows for a session for devtools users." }, + "DEVTOOLS_SAVE_HEAP_SNAPSHOT_MS": { + "expires_in_version": "never", + "kind": "exponential", + "high": "100000", + "n_buckets": "1000", + "description": "The time (in milliseconds) that it took to save a heap snapshot in mozilla::devtools::ChromeUtils::SaveHeapSnapshot." + }, "BROWSER_IS_USER_DEFAULT": { "expires_in_version": "never", "kind": "boolean", diff --git a/toolkit/devtools/server/HeapSnapshot.cpp b/toolkit/devtools/server/HeapSnapshot.cpp index 499879158093..2482a577a9a9 100644 --- a/toolkit/devtools/server/HeapSnapshot.cpp +++ b/toolkit/devtools/server/HeapSnapshot.cpp @@ -19,6 +19,8 @@ #include "mozilla/devtools/ZeroCopyNSIOutputStream.h" #include "mozilla/dom/ChromeUtils.h" #include "mozilla/dom/HeapSnapshotBinding.h" +#include "mozilla/Telemetry.h" +#include "mozilla/TimeStamp.h" #include "mozilla/UniquePtr.h" #include "jsapi.h" @@ -550,6 +552,8 @@ ThreadSafeChromeUtils::SaveHeapSnapshot(GlobalObject& global, const HeapSnapshotBoundaries& boundaries, ErrorResult& rv) { + auto start = TimeStamp::Now(); + bool wantNames = true; ZoneSet zones; Maybe maybeNoGC; @@ -587,12 +591,15 @@ ThreadSafeChromeUtils::SaveHeapSnapshot(GlobalObject& global, wantNames, zones.initialized() ? &zones : nullptr, maybeNoGC.ref())) - { - rv.Throw(zeroCopyStream.failed() - ? zeroCopyStream.result() - : NS_ERROR_UNEXPECTED); - return; - } + { + rv.Throw(zeroCopyStream.failed() + ? zeroCopyStream.result() + : NS_ERROR_UNEXPECTED); + return; + } + + Telemetry::AccumulateTimeDelta(Telemetry::DEVTOOLS_SAVE_HEAP_SNAPSHOT_MS, + start); } /* static */ already_AddRefed From 7f059162e351541eafea12c028e5fd4934b515c7 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Tue, 21 Jul 2015 12:35:58 -0700 Subject: [PATCH 03/96] Bug 1167292 - Part 2: Add a telemetry probe to time how long it takes to read a heap snapshot; r=ejpbruel --- toolkit/components/telemetry/Histograms.json | 7 +++++++ toolkit/devtools/server/HeapSnapshot.cpp | 14 +++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 7ad3c2a44d6c..9ec42e569dad 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -7085,6 +7085,13 @@ "n_buckets": "1000", "description": "The time (in milliseconds) that it took to save a heap snapshot in mozilla::devtools::ChromeUtils::SaveHeapSnapshot." }, + "DEVTOOLS_READ_HEAP_SNAPSHOT_MS": { + "expires_in_version": "never", + "kind": "exponential", + "high": "100000", + "n_buckets": "1000", + "description": "The time (in milliseconds) that it took to read a heap snapshot in mozilla::devtools::ChromeUtils::ReadHeapSnapshot." + }, "BROWSER_IS_USER_DEFAULT": { "expires_in_version": "never", "kind": "boolean", diff --git a/toolkit/devtools/server/HeapSnapshot.cpp b/toolkit/devtools/server/HeapSnapshot.cpp index 2482a577a9a9..9c47fd473532 100644 --- a/toolkit/devtools/server/HeapSnapshot.cpp +++ b/toolkit/devtools/server/HeapSnapshot.cpp @@ -608,6 +608,8 @@ ThreadSafeChromeUtils::ReadHeapSnapshot(GlobalObject& global, const nsAString& filePath, ErrorResult& rv) { + auto start = TimeStamp::Now(); + UniquePtr path(ToNewCString(filePath)); if (!path) { rv.Throw(NS_ERROR_OUT_OF_MEMORY); @@ -619,9 +621,15 @@ ThreadSafeChromeUtils::ReadHeapSnapshot(GlobalObject& global, if (rv.Failed()) return nullptr; - return HeapSnapshot::Create(cx, global, - reinterpret_cast(mm.address()), - mm.size(), rv); + auto snapshot = HeapSnapshot::Create(cx, global, + reinterpret_cast(mm.address()), + mm.size(), rv); + + if (!rv.Failed()) + Telemetry::AccumulateTimeDelta(Telemetry::DEVTOOLS_READ_HEAP_SNAPSHOT_MS, + start); + + return snapshot; } } // namespace dom From d285eb00b3c4c494e92bb672f8f0afd82710e64f Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Tue, 21 Jul 2015 12:35:58 -0700 Subject: [PATCH 04/96] Bug 1167292 - Part 3: Add telemetry probes for node and edge counts when saving heap snapshots; r=ejpbruel --- toolkit/components/telemetry/Histograms.json | 14 ++++ toolkit/devtools/server/HeapSnapshot.cpp | 76 +++++++++++++------- toolkit/devtools/server/HeapSnapshot.h | 17 ++++- 3 files changed, 82 insertions(+), 25 deletions(-) diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 9ec42e569dad..02460c9dbfc0 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -7092,6 +7092,20 @@ "n_buckets": "1000", "description": "The time (in milliseconds) that it took to read a heap snapshot in mozilla::devtools::ChromeUtils::ReadHeapSnapshot." }, + "DEVTOOLS_HEAP_SNAPSHOT_NODE_COUNT": { + "expires_in_version": "never", + "kind": "linear", + "high": "10000000", + "n_buckets": "10000", + "description": "The number of nodes serialized into a heap snapshot." + }, + "DEVTOOLS_HEAP_SNAPSHOT_EDGE_COUNT": { + "expires_in_version": "never", + "kind": "linear", + "high": "10000000", + "n_buckets": "10000", + "description": "The number of edges serialized into a heap snapshot." + }, "BROWSER_IS_USER_DEFAULT": { "expires_in_version": "never", "kind": "boolean", diff --git a/toolkit/devtools/server/HeapSnapshot.cpp b/toolkit/devtools/server/HeapSnapshot.cpp index 9c47fd473532..0f4343e4ee87 100644 --- a/toolkit/devtools/server/HeapSnapshot.cpp +++ b/toolkit/devtools/server/HeapSnapshot.cpp @@ -461,6 +461,10 @@ class MOZ_STACK_CLASS HeapSnapshotHandler JS::ZoneSet* zones; public: + // For telemetry. + uint32_t nodeCount; + uint32_t edgeCount; + HeapSnapshotHandler(CoreDumpWriter& writer, JS::ZoneSet* zones) : writer(writer), @@ -477,6 +481,8 @@ public: NodeData*, bool first) { + edgeCount++; + // We're only interested in the first time we reach edge.referent, not in // every edge arriving at that node. "But, don't we want to serialize every // edge in the heap graph?" you ask. Don't worry! This edge is still @@ -486,6 +492,8 @@ public: if (!first) return true; + nodeCount++; + const JS::ubi::Node& referent = edge.referent; if (!zones) @@ -517,7 +525,9 @@ WriteHeapGraph(JSContext* cx, CoreDumpWriter& writer, bool wantNames, JS::ZoneSet* zones, - JS::AutoCheckCannotGC& noGC) + JS::AutoCheckCannotGC& noGC, + uint32_t& outNodeCount, + uint32_t& outEdgeCount) { // Serialize the starting node to the core dump. @@ -534,8 +544,15 @@ WriteHeapGraph(JSContext* cx, return false; traversal.wantNames = wantNames; - return traversal.addStartVisited(node) && - traversal.traverse(); + bool ok = traversal.addStartVisited(node) && + traversal.traverse(); + + if (ok) { + outNodeCount = handler.nodeCount; + outEdgeCount = handler.edgeCount; + } + + return ok; } } // namespace devtools @@ -556,13 +573,8 @@ ThreadSafeChromeUtils::SaveHeapSnapshot(GlobalObject& global, bool wantNames = true; ZoneSet zones; - Maybe maybeNoGC; - ubi::RootList rootList(cx, maybeNoGC, wantNames); - if (!EstablishBoundaries(cx, rv, boundaries, rootList, zones)) - return; - - MOZ_ASSERT(maybeNoGC.isSome()); - ubi::Node roots(&rootList); + uint32_t nodeCount = 0; + uint32_t edgeCount = 0; nsCOMPtr file; rv = NS_NewLocalFile(filePath, false, getter_AddRefs(file)); @@ -581,25 +593,41 @@ ThreadSafeChromeUtils::SaveHeapSnapshot(GlobalObject& global, StreamWriter writer(cx, gzipStream, wantNames); - // Serialize the initial heap snapshot metadata to the core dump. - if (!writer.writeMetadata(PR_Now()) || - // Serialize the heap graph to the core dump, starting from our list of - // roots. - !WriteHeapGraph(cx, - roots, - writer, - wantNames, - zones.initialized() ? &zones : nullptr, - maybeNoGC.ref())) { - rv.Throw(zeroCopyStream.failed() - ? zeroCopyStream.result() - : NS_ERROR_UNEXPECTED); - return; + Maybe maybeNoGC; + ubi::RootList rootList(cx, maybeNoGC, wantNames); + if (!EstablishBoundaries(cx, rv, boundaries, rootList, zones)) + return; + + MOZ_ASSERT(maybeNoGC.isSome()); + ubi::Node roots(&rootList); + + // Serialize the initial heap snapshot metadata to the core dump. + if (!writer.writeMetadata(PR_Now()) || + // Serialize the heap graph to the core dump, starting from our list of + // roots. + !WriteHeapGraph(cx, + roots, + writer, + wantNames, + zones.initialized() ? &zones : nullptr, + maybeNoGC.ref(), + nodeCount, + edgeCount)) + { + rv.Throw(zeroCopyStream.failed() + ? zeroCopyStream.result() + : NS_ERROR_UNEXPECTED); + return; + } } Telemetry::AccumulateTimeDelta(Telemetry::DEVTOOLS_SAVE_HEAP_SNAPSHOT_MS, start); + Telemetry::Accumulate(Telemetry::DEVTOOLS_HEAP_SNAPSHOT_NODE_COUNT, + nodeCount); + Telemetry::Accumulate(Telemetry::DEVTOOLS_HEAP_SNAPSHOT_EDGE_COUNT, + edgeCount); } /* static */ already_AddRefed diff --git a/toolkit/devtools/server/HeapSnapshot.h b/toolkit/devtools/server/HeapSnapshot.h index ff1d3462407b..a690c7fdaa2f 100644 --- a/toolkit/devtools/server/HeapSnapshot.h +++ b/toolkit/devtools/server/HeapSnapshot.h @@ -162,7 +162,22 @@ WriteHeapGraph(JSContext* cx, CoreDumpWriter& writer, bool wantNames, JS::ZoneSet* zones, - JS::AutoCheckCannotGC& noGC); + JS::AutoCheckCannotGC& noGC, + uint32_t& outNodeCount, + uint32_t& outEdgeCount); +inline bool +WriteHeapGraph(JSContext* cx, + const JS::ubi::Node& node, + CoreDumpWriter& writer, + bool wantNames, + JS::ZoneSet* zones, + JS::AutoCheckCannotGC& noGC) +{ + uint32_t ignoreNodeCount; + uint32_t ignoreEdgeCount; + return WriteHeapGraph(cx, node, writer, wantNames, zones, noGC, + ignoreNodeCount, ignoreEdgeCount); +} } // namespace devtools } // namespace mozilla From 8cb39f819f00ce2f1f26d84b393fbbb4b079d418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Pag=C3=A8s?= Date: Mon, 20 Jul 2015 17:32:41 +0200 Subject: [PATCH 05/96] Bug 1172918 - Clean up talos options that are not used (removing from mozharness). r=jmaher --HG-- extra : rebase_source : 62cd572974cf92b4c56eba4f4433e0761d5f4dcb --- .../configs/android/android_panda_talos_releng.py | 2 -- testing/mozharness/configs/talos/linux_config.py | 2 -- testing/mozharness/configs/talos/mac_config.py | 2 -- testing/mozharness/configs/talos/windows_config.py | 2 -- testing/mozharness/mozharness/mozilla/testing/talos.py | 7 ------- testing/mozharness/scripts/android_panda_talos.py | 6 ------ 6 files changed, 21 deletions(-) diff --git a/testing/mozharness/configs/android/android_panda_talos_releng.py b/testing/mozharness/configs/android/android_panda_talos_releng.py index 15972953b2c0..89c8b0d4c4cb 100644 --- a/testing/mozharness/configs/android/android_panda_talos_releng.py +++ b/testing/mozharness/configs/android/android_panda_talos_releng.py @@ -17,8 +17,6 @@ config = { "install_app_path": "/builds/sut_tools/installApp.py", "talos_from_code_url": "https://hg.mozilla.org/%s/raw-file/%s/testing/talos/talos_from_code.py", "talos_json_url": "https://hg.mozilla.org/%s/raw-file/%s/testing/talos/talos.json", - "datazilla_urls": ["https://datazilla.mozilla.org/talos"], - "datazilla_authfile": os.path.join(os.getcwd(), "oauth.txt"), #remotePerfConfigurator.py options "preflight_talos_options": [ "-v", "-e", "%(app_name)s", diff --git a/testing/mozharness/configs/talos/linux_config.py b/testing/mozharness/configs/talos/linux_config.py index 9d80ceb4c6e1..3225306eb41d 100644 --- a/testing/mozharness/configs/talos/linux_config.py +++ b/testing/mozharness/configs/talos/linux_config.py @@ -20,8 +20,6 @@ config = { }, "title": os.uname()[1].lower().split('.')[0], "results_url": "http://graphs.mozilla.org/server/collect.cgi", - "datazilla_urls": ["https://datazilla.mozilla.org/talos"], - "datazilla_authfile": os.path.join(os.getcwd(), "oauth.txt"), "default_actions": [ "clobber", "read-buildbot-config", diff --git a/testing/mozharness/configs/talos/mac_config.py b/testing/mozharness/configs/talos/mac_config.py index 82c457949326..2e1bce874738 100644 --- a/testing/mozharness/configs/talos/mac_config.py +++ b/testing/mozharness/configs/talos/mac_config.py @@ -30,8 +30,6 @@ config = { }, "title": os.uname()[1].lower().split('.')[0], "results_url": "http://graphs.mozilla.org/server/collect.cgi", - "datazilla_urls": ["https://datazilla.mozilla.org/talos"], - "datazilla_authfile": os.path.join(os.getcwd(), "oauth.txt"), "default_actions": [ "clobber", "read-buildbot-config", diff --git a/testing/mozharness/configs/talos/windows_config.py b/testing/mozharness/configs/talos/windows_config.py index 978add3992ec..d3f3d4b750af 100644 --- a/testing/mozharness/configs/talos/windows_config.py +++ b/testing/mozharness/configs/talos/windows_config.py @@ -29,8 +29,6 @@ config = { }, "title": socket.gethostname().split('.')[0], "results_url": "http://graphs.mozilla.org/server/collect.cgi", - "datazilla_urls": ["https://datazilla.mozilla.org/talos"], - "datazilla_authfile": os.path.join(os.getcwd(), "oauth.txt"), "default_actions": [ "clobber", "read-buildbot-config", diff --git a/testing/mozharness/mozharness/mozilla/testing/talos.py b/testing/mozharness/mozharness/mozilla/testing/talos.py index 977d3e95a16a..e0f7fa980d93 100755 --- a/testing/mozharness/mozharness/mozilla/testing/talos.py +++ b/testing/mozharness/mozharness/mozilla/testing/talos.py @@ -444,13 +444,6 @@ class Talos(TestingMixin, MercurialScript, BlobUploadMixin): kw_options['activeTests'] = tests for key, value in kw_options.items(): options.extend(['--%s' % key, value]) - # add datazilla results urls - for url in self.config.get('datazilla_urls', []): - options.extend(['--datazilla-url', url]) - # add datazilla authfile - authfile = self.config.get('datazilla_authfile') - if authfile: - options.extend(['--authfile', authfile]) # configure profiling options options.extend(self.query_sps_profile_options()) # extra arguments diff --git a/testing/mozharness/scripts/android_panda_talos.py b/testing/mozharness/scripts/android_panda_talos.py index 4fddc4f64bac..557e70d24427 100644 --- a/testing/mozharness/scripts/android_panda_talos.py +++ b/testing/mozharness/scripts/android_panda_talos.py @@ -383,12 +383,6 @@ class PandaTalosTest(TestingMixin, MercurialScript, BlobUploadMixin, MozpoolMixi if self.config['%s_options' % suite_category]: for option in self.config['%s_options' % suite_category]: options.append(option % str_format_values) - for url in self.config.get('datazilla_urls', []): - options.extend(['--datazilla-url', url]) - # add datazilla authfile - authfile = self.config.get('datazilla_authfile') - if authfile: - options.extend(['--authfile', authfile]) abs_base_cmd = base_cmd + options return abs_base_cmd else: From 9a2da7a4da9726eb2e36746cae48de7dc95b60e3 Mon Sep 17 00:00:00 2001 From: Milan Sreckovic Date: Tue, 21 Jul 2015 11:42:25 -0400 Subject: [PATCH 06/96] Bug 1163038 - More tests to pass by running instead of catching an exception. r=kats --HG-- extra : rebase_source : 2c561c39037c4ba75b6931ba14553d2f5ebb537a --- .../test/xpcshell/test_gfxBlacklist_Device.js | 18 +++++++-------- .../xpcshell/test_gfxBlacklist_DriverNew.js | 16 ++++++-------- .../test_gfxBlacklist_Equal_DriverNew.js | 16 ++++++-------- .../test_gfxBlacklist_Equal_DriverOld.js | 16 ++++++-------- .../xpcshell/test_gfxBlacklist_Equal_OK.js | 16 ++++++-------- .../test_gfxBlacklist_GTE_DriverOld.js | 16 ++++++-------- .../test/xpcshell/test_gfxBlacklist_GTE_OK.js | 16 ++++++-------- .../test_gfxBlacklist_No_Comparison.js | 18 +++++++-------- .../test/xpcshell/test_gfxBlacklist_OS.js | 19 +++++++--------- .../test_gfxBlacklist_OSVersion_match.js | 19 ++++++++-------- ...cklist_OSVersion_mismatch_DriverVersion.js | 22 +++++++++---------- ...xBlacklist_OSVersion_mismatch_OSVersion.js | 19 ++++++++-------- .../test/xpcshell/test_gfxBlacklist_Vendor.js | 18 +++++++-------- 13 files changed, 102 insertions(+), 127 deletions(-) diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Device.js b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Device.js index 5f781edf466a..adff22123d10 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Device.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Device.js @@ -2,11 +2,14 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ +// This should eventually be moved to head_addons.js +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; + // Test whether a machine which differs only on device ID, but otherwise // exactly matches the blacklist entry, is not blocked. // Uses test_gfxBlacklist.xml -Components.utils.import("resource://testing-common/httpd.js"); +Cu.import("resource://testing-common/httpd.js"); var gTestserver = new HttpServer(); gTestserver.start(-1); @@ -14,8 +17,8 @@ gPort = gTestserver.identity.primaryPort; mapFile("/data/test_gfxBlacklist.xml", gTestserver); function get_platform() { - var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"] - .getService(Components.interfaces.nsIXULRuntime); + var xulRuntime = Cc["@mozilla.org/xre/app-info;1"] + .getService(Ci.nsIXULRuntime); return xulRuntime.OS; } @@ -29,12 +32,7 @@ function load_blocklist(file) { // Performs the initial setup function run_test() { - try { - var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); - } catch (e) { - do_test_finished(); - return; - } + var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); // We can't do anything if we can't spoof the stuff we need. if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) { @@ -60,7 +58,7 @@ function run_test() { case "Darwin": gfxInfo.spoofVendorID("0xabcd"); gfxInfo.spoofDeviceID("0x9876"); - gfxInfo.spoofOSVersion(0x1050); + gfxInfo.spoofOSVersion(0x1060); break; case "Android": gfxInfo.spoofVendorID("abcd"); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_DriverNew.js b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_DriverNew.js index 802fe11e2ee2..7122030ec23d 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_DriverNew.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_DriverNew.js @@ -2,11 +2,14 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ +// This should eventually be moved to head_addons.js +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; + // Test whether a new-enough driver bypasses the blacklist, even if the rest of // the attributes match the blacklist entry. // Uses test_gfxBlacklist.xml -Components.utils.import("resource://testing-common/httpd.js"); +Cu.import("resource://testing-common/httpd.js"); var gTestserver = new HttpServer(); gTestserver.start(-1); @@ -14,8 +17,8 @@ gPort = gTestserver.identity.primaryPort; mapFile("/data/test_gfxBlacklist.xml", gTestserver); function get_platform() { - var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"] - .getService(Components.interfaces.nsIXULRuntime); + var xulRuntime = Cc["@mozilla.org/xre/app-info;1"] + .getService(Ci.nsIXULRuntime); return xulRuntime.OS; } @@ -29,12 +32,7 @@ function load_blocklist(file) { // Performs the initial setup function run_test() { - try { - var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); - } catch (e) { - do_test_finished(); - return; - } + var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); // We can't do anything if we can't spoof the stuff we need. if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) { diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverNew.js b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverNew.js index 08e87c38cee3..6d4dc3c09716 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverNew.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverNew.js @@ -2,11 +2,14 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ +// This should eventually be moved to head_addons.js +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; + // Test whether a machine which is newer than the equal // blacklist entry is allowed. // Uses test_gfxBlacklist.xml -Components.utils.import("resource://testing-common/httpd.js"); +Cu.import("resource://testing-common/httpd.js"); var gTestserver = new HttpServer(); gTestserver.start(-1); @@ -14,8 +17,8 @@ gPort = gTestserver.identity.primaryPort; mapFile("/data/test_gfxBlacklist.xml", gTestserver); function get_platform() { - var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"] - .getService(Components.interfaces.nsIXULRuntime); + var xulRuntime = Cc["@mozilla.org/xre/app-info;1"] + .getService(Ci.nsIXULRuntime); return xulRuntime.OS; } @@ -29,12 +32,7 @@ function load_blocklist(file) { // Performs the initial setup function run_test() { - try { - var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); - } catch (e) { - do_test_finished(); - return; - } + var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); // We can't do anything if we can't spoof the stuff we need. if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) { diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverOld.js b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverOld.js index 73253c89bd2f..1052e3774916 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverOld.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverOld.js @@ -2,11 +2,14 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ +// This should eventually be moved to head_addons.js +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; + // Test whether a machine which is older than the equal // blacklist entry is correctly allowed. // Uses test_gfxBlacklist.xml -Components.utils.import("resource://testing-common/httpd.js"); +Cu.import("resource://testing-common/httpd.js"); var gTestserver = new HttpServer(); gTestserver.start(-1); @@ -14,8 +17,8 @@ gPort = gTestserver.identity.primaryPort; mapFile("/data/test_gfxBlacklist.xml", gTestserver); function get_platform() { - var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"] - .getService(Components.interfaces.nsIXULRuntime); + var xulRuntime = Cc["@mozilla.org/xre/app-info;1"] + .getService(Ci.nsIXULRuntime); return xulRuntime.OS; } @@ -29,12 +32,7 @@ function load_blocklist(file) { // Performs the initial setup function run_test() { - try { - var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); - } catch (e) { - do_test_finished(); - return; - } + var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); // We can't do anything if we can't spoof the stuff we need. if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) { diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_OK.js b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_OK.js index 2dde268a3499..b9051324bd78 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_OK.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_OK.js @@ -2,11 +2,14 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ +// This should eventually be moved to head_addons.js +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; + // Test whether a machine which exactly matches the equal // blacklist entry is successfully blocked. // Uses test_gfxBlacklist.xml -Components.utils.import("resource://testing-common/httpd.js"); +Cu.import("resource://testing-common/httpd.js"); var gTestserver = new HttpServer(); gTestserver.start(-1); @@ -14,8 +17,8 @@ gPort = gTestserver.identity.primaryPort; mapFile("/data/test_gfxBlacklist.xml", gTestserver); function get_platform() { - var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"] - .getService(Components.interfaces.nsIXULRuntime); + var xulRuntime = Cc["@mozilla.org/xre/app-info;1"] + .getService(Ci.nsIXULRuntime); return xulRuntime.OS; } @@ -29,12 +32,7 @@ function load_blocklist(file) { // Performs the initial setup function run_test() { - try { - var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); - } catch (e) { - do_test_finished(); - return; - } + var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); // We can't do anything if we can't spoof the stuff we need. if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) { diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_DriverOld.js b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_DriverOld.js index fd3145f5a90d..91965d91ede5 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_DriverOld.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_DriverOld.js @@ -2,11 +2,14 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ +// This should eventually be moved to head_addons.js +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; + // Test whether a machine which is lower than the greater-than-or-equal // blacklist entry is allowed. // Uses test_gfxBlacklist.xml -Components.utils.import("resource://testing-common/httpd.js"); +Cu.import("resource://testing-common/httpd.js"); var gTestserver = new HttpServer(); gTestserver.start(-1); @@ -14,8 +17,8 @@ gPort = gTestserver.identity.primaryPort; mapFile("/data/test_gfxBlacklist.xml", gTestserver); function get_platform() { - var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"] - .getService(Components.interfaces.nsIXULRuntime); + var xulRuntime = Cc["@mozilla.org/xre/app-info;1"] + .getService(Ci.nsIXULRuntime); return xulRuntime.OS; } @@ -29,12 +32,7 @@ function load_blocklist(file) { // Performs the initial setup function run_test() { - try { - var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); - } catch (e) { - do_test_finished(); - return; - } + var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); // We can't do anything if we can't spoof the stuff we need. if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) { diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_OK.js b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_OK.js index 0c2c65572fda..86bdcfa4bfdd 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_OK.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_OK.js @@ -2,11 +2,14 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ +// This should eventually be moved to head_addons.js +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; + // Test whether a machine which exactly matches the greater-than-or-equal // blacklist entry is successfully blocked. // Uses test_gfxBlacklist.xml -Components.utils.import("resource://testing-common/httpd.js"); +Cu.import("resource://testing-common/httpd.js"); var gTestserver = new HttpServer(); gTestserver.start(-1); @@ -14,8 +17,8 @@ gPort = gTestserver.identity.primaryPort; mapFile("/data/test_gfxBlacklist.xml", gTestserver); function get_platform() { - var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"] - .getService(Components.interfaces.nsIXULRuntime); + var xulRuntime = Cc["@mozilla.org/xre/app-info;1"] + .getService(Ci.nsIXULRuntime); return xulRuntime.OS; } @@ -29,12 +32,7 @@ function load_blocklist(file) { // Performs the initial setup function run_test() { - try { - var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); - } catch (e) { - do_test_finished(); - return; - } + var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); // We can't do anything if we can't spoof the stuff we need. if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) { diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_No_Comparison.js b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_No_Comparison.js index 61372cff86ff..2e13b34b623a 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_No_Comparison.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_No_Comparison.js @@ -2,11 +2,14 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ +// This should eventually be moved to head_addons.js +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; + // Test whether a machine which exactly matches the blacklist entry is // successfully blocked. // Uses test_gfxBlacklist.xml -Components.utils.import("resource://testing-common/httpd.js"); +Cu.import("resource://testing-common/httpd.js"); var gTestserver = new HttpServer(); gTestserver.start(-1); @@ -14,8 +17,8 @@ gPort = gTestserver.identity.primaryPort; mapFile("/data/test_gfxBlacklist.xml", gTestserver); function get_platform() { - var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"] - .getService(Components.interfaces.nsIXULRuntime); + var xulRuntime = Cc["@mozilla.org/xre/app-info;1"] + .getService(Ci.nsIXULRuntime); return xulRuntime.OS; } @@ -29,12 +32,7 @@ function load_blocklist(file) { // Performs the initial setup function run_test() { - try { - var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); - } catch (e) { - do_test_finished(); - return; - } + var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); // We can't do anything if we can't spoof the stuff we need. if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) { @@ -56,7 +54,7 @@ function run_test() { case "Linux": break; case "Darwin": - gfxInfo.spoofOSVersion(0x1050); + gfxInfo.spoofOSVersion(0x1060); break; case "Android": break; diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OS.js b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OS.js index 81edc9cd11d8..6edd196840ea 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OS.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OS.js @@ -2,11 +2,14 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ +// This should eventually be moved to head_addons.js +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; + // Test whether a machine which differs only on OS version, but otherwise // exactly matches the blacklist entry, is not blocked. // Uses test_gfxBlacklist.xml -Components.utils.import("resource://testing-common/httpd.js"); +Cu.import("resource://testing-common/httpd.js"); var gTestserver = new HttpServer(); gTestserver.start(-1); @@ -14,8 +17,8 @@ gPort = gTestserver.identity.primaryPort; mapFile("/data/test_gfxBlacklist.xml", gTestserver); function get_platform() { - var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"] - .getService(Components.interfaces.nsIXULRuntime); + var xulRuntime = Cc["@mozilla.org/xre/app-info;1"] + .getService(Ci.nsIXULRuntime); return xulRuntime.OS; } @@ -29,12 +32,7 @@ function load_blocklist(file) { // Performs the initial setup function run_test() { - try { - var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); - } catch (e) { - do_test_finished(); - return; - } + var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); // We can't do anything if we can't spoof the stuff we need. if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) { @@ -60,8 +58,7 @@ function run_test() { case "Darwin": gfxInfo.spoofVendorID("0xabcd"); gfxInfo.spoofDeviceID("0x1234"); - // Snow Leopard - gfxInfo.spoofOSVersion(0x1060); + gfxInfo.spoofOSVersion(0x1070); break; case "Android": // On Android, the driver version is used as the OS version (because diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_match.js b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_match.js index 3472c6d7e57a..b8b320d65ca6 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_match.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_match.js @@ -2,18 +2,22 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ +// This should eventually be moved to head_addons.js +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; + // Test whether new OS versions are matched properly. // Uses test_gfxBlacklist_OS.xml -Components.utils.import("resource://testing-common/httpd.js"); +Cu.import("resource://testing-common/httpd.js"); var gTestserver = new HttpServer(); gTestserver.start(-1); gPort = gTestserver.identity.primaryPort; +mapFile("/data/test_gfxBlacklist_OSVersion.xml", gTestserver); function get_platform() { - var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"] - .getService(Components.interfaces.nsIXULRuntime); + var xulRuntime = Cc["@mozilla.org/xre/app-info;1"] + .getService(Ci.nsIXULRuntime); return xulRuntime.OS; } @@ -27,12 +31,7 @@ function load_blocklist(file) { // Performs the initial setup function run_test() { - try { - var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); - } catch (e) { - do_test_finished(); - return; - } + var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); // We can't do anything if we can't spoof the stuff we need. if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) { @@ -92,5 +91,5 @@ function run_test() { do_execute_soon(checkBlacklist); }, "blocklist-data-gfxItems", false); - load_blocklist("test_gfxBlacklist_OS.xml"); + load_blocklist("test_gfxBlacklist_OSVersion.xml"); } diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_DriverVersion.js b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_DriverVersion.js index fb25b9509b26..5a4f8502a4ef 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_DriverVersion.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_DriverVersion.js @@ -2,19 +2,23 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ +// This should eventually be moved to head_addons.js +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; + // Test whether blocklists specifying new OSeswcorrectly don't block if driver // versions are appropriately up-to-date. // Uses test_gfxBlacklist_OS.xml -Components.utils.import("resource://testing-common/httpd.js"); +Cu.import("resource://testing-common/httpd.js"); var gTestserver = new HttpServer(); gTestserver.start(-1); gPort = gTestserver.identity.primaryPort; +mapFile("/data/test_gfxBlacklist_OSVersion.xml", gTestserver); function get_platform() { - var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"] - .getService(Components.interfaces.nsIXULRuntime); + var xulRuntime = Cc["@mozilla.org/xre/app-info;1"] + .getService(Ci.nsIXULRuntime); return xulRuntime.OS; } @@ -28,12 +32,7 @@ function load_blocklist(file) { // Performs the initial setup function run_test() { - try { - var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); - } catch (e) { - do_test_finished(); - return; - } + var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); // We can't do anything if we can't spoof the stuff we need. if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) { @@ -59,8 +58,7 @@ function run_test() { do_test_finished(); return; case "Darwin": - // Mountain Lion - gfxInfo.spoofOSVersion(0x1080); + gfxInfo.spoofOSVersion(0x1090); break; case "Android": // On Android, the driver version is used as the OS version (because @@ -93,5 +91,5 @@ function run_test() { do_execute_soon(checkBlacklist); }, "blocklist-data-gfxItems", false); - load_blocklist("test_gfxBlacklist_OS.xml"); + load_blocklist("test_gfxBlacklist_OSVersion.xml"); } diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_OSVersion.js b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_OSVersion.js index 4fb162262184..c7a1a915ad34 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_OSVersion.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_OSVersion.js @@ -2,19 +2,23 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ +// This should eventually be moved to head_addons.js +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; + // Test whether old OS versions are not matched when the blacklist contains // only new OS versions. // Uses test_gfxBlacklist_OS.xml -Components.utils.import("resource://testing-common/httpd.js"); +Cu.import("resource://testing-common/httpd.js"); var gTestserver = new HttpServer(); gTestserver.start(-1); gPort = gTestserver.identity.primaryPort; +mapFile("/data/test_gfxBlacklist_OSVersion.xml", gTestserver); function get_platform() { - var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"] - .getService(Components.interfaces.nsIXULRuntime); + var xulRuntime = Cc["@mozilla.org/xre/app-info;1"] + .getService(Ci.nsIXULRuntime); return xulRuntime.OS; } @@ -28,12 +32,7 @@ function load_blocklist(file) { // Performs the initial setup function run_test() { - try { - var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); - } catch (e) { - do_test_finished(); - return; - } + var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); // We can't do anything if we can't spoof the stuff we need. if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) { @@ -93,5 +92,5 @@ function run_test() { do_execute_soon(checkBlacklist); }, "blocklist-data-gfxItems", false); - load_blocklist("test_gfxBlacklist_OS.xml"); + load_blocklist("test_gfxBlacklist_OSVersion.xml"); } diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Vendor.js b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Vendor.js index a5d1c71cff7e..bb09ac9461ea 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Vendor.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Vendor.js @@ -2,11 +2,14 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ +// This should eventually be moved to head_addons.js +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; + // Test whether a machine which differs only on vendor, but otherwise // exactly matches the blacklist entry, is not blocked. // Uses test_gfxBlacklist.xml -Components.utils.import("resource://testing-common/httpd.js"); +Cu.import("resource://testing-common/httpd.js"); var gTestserver = new HttpServer(); gTestserver.start(-1); @@ -14,8 +17,8 @@ gPort = gTestserver.identity.primaryPort; mapFile("/data/test_gfxBlacklist.xml", gTestserver); function get_platform() { - var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"] - .getService(Components.interfaces.nsIXULRuntime); + var xulRuntime = Cc["@mozilla.org/xre/app-info;1"] + .getService(Ci.nsIXULRuntime); return xulRuntime.OS; } @@ -29,12 +32,7 @@ function load_blocklist(file) { // Performs the initial setup function run_test() { - try { - var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); - } catch (e) { - do_test_finished(); - return; - } + var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); // We can't do anything if we can't spoof the stuff we need. if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) { @@ -60,7 +58,7 @@ function run_test() { case "Darwin": gfxInfo.spoofVendorID("0xdcba"); gfxInfo.spoofDeviceID("0x1234"); - gfxInfo.spoofOSVersion(0x1050); + gfxInfo.spoofOSVersion(0x1060); break; case "Android": gfxInfo.spoofVendorID("dcba"); From c5dbe5ac939d96b0db5a4ef1781126c2a7338486 Mon Sep 17 00:00:00 2001 From: Dragana Damjanovic Date: Tue, 21 Jul 2015 09:23:00 -0400 Subject: [PATCH 07/96] Bug 1182066 - Enforce defaultLoadFlags for all requests. r=mayhemer --HG-- extra : rebase_source : f2239d857000f4dab462fa043a18600919151816 --- .../test/browser_net_copy_as_curl.js | 8 +++- netwerk/base/nsLoadGroup.cpp | 44 +++++++++++++++---- netwerk/base/nsLoadGroup.h | 1 + 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/browser/devtools/netmonitor/test/browser_net_copy_as_curl.js b/browser/devtools/netmonitor/test/browser_net_copy_as_curl.js index a5b1adb8e3c3..540781bca861 100644 --- a/browser/devtools/netmonitor/test/browser_net_copy_as_curl.js +++ b/browser/devtools/netmonitor/test/browser_net_copy_as_curl.js @@ -21,7 +21,9 @@ function test() { "-H 'X-Custom-Header-2: 8.8.8.8'", "-H 'X-Custom-Header-3: Mon, 3 Mar 2014 11:11:11 GMT'", "-H 'Referer: " + CURL_URL + "'", - "-H 'Connection: keep-alive'" + "-H 'Connection: keep-alive'", + "-H 'Pragma: no-cache'", + "-H 'Cache-Control: no-cache'" ].join(" "); const EXPECTED_WIN_RESULT = [ @@ -36,7 +38,9 @@ function test() { '-H "X-Custom-Header-2: 8.8.8.8"', '-H "X-Custom-Header-3: Mon, 3 Mar 2014 11:11:11 GMT"', '-H "Referer: ' + CURL_URL + '"', - '-H "Connection: keep-alive"' + '-H "Connection: keep-alive"', + '-H "Pragma: no-cache"', + '-H "Cache-Control: no-cache"' ].join(" "); const EXPECTED_RESULT = Services.appinfo.OS == "WINNT" diff --git a/netwerk/base/nsLoadGroup.cpp b/netwerk/base/nsLoadGroup.cpp index 7c6e747a7514..a8b00daf3180 100644 --- a/netwerk/base/nsLoadGroup.cpp +++ b/netwerk/base/nsLoadGroup.cpp @@ -524,13 +524,14 @@ nsLoadGroup::AddRequest(nsIRequest *request, nsISupports* ctxt) } nsLoadFlags flags; - // if the request is the default load request or if the default - // load request is null, then the load group should inherit its - // load flags from the request. - if (mDefaultLoadRequest == request || !mDefaultLoadRequest) - rv = request->GetLoadFlags(&flags); - else + // if the request is the default load request or if the default load + // request is null, then the load group should inherit its load flags from + // the request, but also we need to enforce defaultLoadFlags. + if (mDefaultLoadRequest == request || !mDefaultLoadRequest) { + rv = MergeDefaultLoadFlags(request, flags); + } else { rv = MergeLoadFlags(request, flags); + } if (NS_FAILED(rv)) return rv; // @@ -1058,14 +1059,16 @@ nsLoadGroup::TelemetryReportChannel(nsITimedChannel *aTimedChannel, #undef HTTP_REQUEST_HISTOGRAMS } -nsresult nsLoadGroup::MergeLoadFlags(nsIRequest *aRequest, nsLoadFlags& outFlags) +nsresult nsLoadGroup::MergeLoadFlags(nsIRequest *aRequest, + nsLoadFlags& outFlags) { nsresult rv; nsLoadFlags flags, oldFlags; rv = aRequest->GetLoadFlags(&flags); - if (NS_FAILED(rv)) + if (NS_FAILED(rv)) { return rv; + } oldFlags = flags; @@ -1080,11 +1083,34 @@ nsresult nsLoadGroup::MergeLoadFlags(nsIRequest *aRequest, nsLoadFlags& outFlags // ... and force the default flags. flags |= mDefaultLoadFlags; - if (flags != oldFlags) + if (flags != oldFlags) { rv = aRequest->SetLoadFlags(flags); + } outFlags = flags; return rv; } +nsresult nsLoadGroup::MergeDefaultLoadFlags(nsIRequest *aRequest, + nsLoadFlags& outFlags) +{ + nsresult rv; + nsLoadFlags flags, oldFlags; + + rv = aRequest->GetLoadFlags(&flags); + if (NS_FAILED(rv)) { + return rv; + } + + oldFlags = flags; + // ... and force the default flags. + flags |= mDefaultLoadFlags; + + if (flags != oldFlags) { + rv = aRequest->SetLoadFlags(flags); + } + outFlags = flags; + return rv; +} + #undef LOG diff --git a/netwerk/base/nsLoadGroup.h b/netwerk/base/nsLoadGroup.h index ae152b59b1dc..a1235be5307b 100644 --- a/netwerk/base/nsLoadGroup.h +++ b/netwerk/base/nsLoadGroup.h @@ -54,6 +54,7 @@ public: protected: nsresult MergeLoadFlags(nsIRequest *aRequest, nsLoadFlags& flags); + nsresult MergeDefaultLoadFlags(nsIRequest *aRequest, nsLoadFlags& flags); private: void TelemetryReport(); From f93c97ac468ef94c8a906cf4f5616788973d4d2b Mon Sep 17 00:00:00 2001 From: Jim Mathies Date: Mon, 20 Jul 2015 10:20:15 -0500 Subject: [PATCH 08/96] Bug 1128454 - When plugin bridging fails, propagate the error back to the content process without aborting tabs. r=billm --HG-- extra : rebase_source : dbe95e294a973f52b3015f1b1f7c0cd229a745c2 --- dom/plugins/ipc/PluginModuleParent.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/dom/plugins/ipc/PluginModuleParent.cpp b/dom/plugins/ipc/PluginModuleParent.cpp index 00b945788cc9..fde3ce2ee7dd 100755 --- a/dom/plugins/ipc/PluginModuleParent.cpp +++ b/dom/plugins/ipc/PluginModuleParent.cpp @@ -130,16 +130,6 @@ mozilla::plugins::SetupBridge(uint32_t aPluginId, return true; } *rv = PPluginModule::Bridge(aContentParent, chromeParent); - if (NS_FAILED(*rv)) { -#if defined(MOZ_CRASHREPORTER) - // We are going to abort due to the failure, lets note the cause - // in the report for diagnosing. - nsAutoCString error; - error.AppendPrintf("%X %d", *rv, chromeParent->GetIPCChannel()->GetChannelState__TotallyRacy()); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("BridgePluginError"), error); -#endif - return false; - } return true; } From 4f18eeb505e41afcea572b05f0f2735dcf453fd6 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Fri, 17 Jul 2015 14:22:58 -0700 Subject: [PATCH 09/96] Bug 1161831 - Generate an extra macro to declare a non-virtual variant of an interface. r=billm This allows us to have a shared superclass that implements the guts of a shared superinterface, without having the superclass actually inherit the superinterface (which leads to annoying and unnecessary diamond-inheritance). --- xpcom/idl-parser/xpidl/header.py | 45 ++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/xpcom/idl-parser/xpidl/header.py b/xpcom/idl-parser/xpidl/header.py index 4ed76a17f26c..15eba9dd7efe 100644 --- a/xpcom/idl-parser/xpidl/header.py +++ b/xpcom/idl-parser/xpidl/header.py @@ -62,10 +62,10 @@ def attributeParamlist(a, getter): return ", ".join(l) -def attributeAsNative(a, getter): +def attributeAsNative(a, getter, declType = 'NS_IMETHOD'): deprecated = a.deprecated and "NS_DEPRECATED " or "" params = {'deprecated': deprecated, - 'returntype': attributeReturnType(a, 'NS_IMETHOD'), + 'returntype': attributeReturnType(a, declType), 'binaryname': attributeNativeName(a, getter), 'paramlist': attributeParamlist(a, getter)} return "%(deprecated)s%(returntype)s %(binaryname)s(%(paramlist)s)" % params @@ -88,8 +88,8 @@ def methodReturnType(m, macro): return macro -def methodAsNative(m): - return "%s %s(%s)" % (methodReturnType(m, 'NS_IMETHOD'), +def methodAsNative(m, declType = 'NS_IMETHOD'): + return "%s %s(%s)" % (methodReturnType(m, declType), methodNativeName(m), paramlistAsNative(m)) @@ -255,6 +255,11 @@ iface_epilog = """}; /* Use this macro when declaring classes that implement this interface. */ #define NS_DECL_%(macroname)s """ +iface_nonvirtual = """ + +/* Use this macro when declaring the members of this interface when the + class doesn't implement the interface. This is useful for forwarding. */ +#define NS_DECL_NON_VIRTUAL_%(macroname)s """ iface_forward = """ @@ -420,20 +425,26 @@ def write_interface(iface, fd): fd.write(iface_epilog % names) - for member in iface.members: - if isinstance(member, xpidl.Attribute): - if member.infallible: - fd.write("\\\n using %s::%s; " % (iface.name, attributeNativeName(member, True))) - fd.write("\\\n %s override; " % attributeAsNative(member, True)) - if not member.readonly: - fd.write("\\\n %s override; " % attributeAsNative(member, False)) - elif isinstance(member, xpidl.Method): - fd.write("\\\n %s override; " % methodAsNative(member)) - if len(iface.members) == 0: - fd.write('\\\n /* no methods! */') - elif not member.kind in ('attribute', 'method'): - fd.write('\\') + def writeDeclaration(fd, iface, virtual): + declType = "NS_IMETHOD" if virtual else "NS_METHOD" + suffix = " override" if virtual else "" + for member in iface.members: + if isinstance(member, xpidl.Attribute): + if member.infallible: + fd.write("\\\n using %s::%s; " % (iface.name, attributeNativeName(member, True))) + fd.write("\\\n %s%s; " % (attributeAsNative(member, True, declType), suffix)) + if not member.readonly: + fd.write("\\\n %s%s; " % (attributeAsNative(member, False, declType), suffix)) + elif isinstance(member, xpidl.Method): + fd.write("\\\n %s%s; " % (methodAsNative(member, declType), suffix)) + if len(iface.members) == 0: + fd.write('\\\n /* no methods! */') + elif not member.kind in ('attribute', 'method'): + fd.write('\\') + writeDeclaration(fd, iface, True); + fd.write(iface_nonvirtual % names) + writeDeclaration(fd, iface, False); fd.write(iface_forward % names) def emitTemplate(forward_infallible, tmpl, tmpl_notxpcom=None): From b089aa16764a5c5e2e584ae72d1d6171f8981e39 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Fri, 17 Jul 2015 14:40:21 -0700 Subject: [PATCH 10/96] Bug 1161831 - Stop using threaddsafe ISupports for nsResProtocolHandler. r=billm As far as I can tell, this thing isn't threadsafe at all. --- netwerk/protocol/res/nsResProtocolHandler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netwerk/protocol/res/nsResProtocolHandler.h b/netwerk/protocol/res/nsResProtocolHandler.h index 7670a7caa4a4..36cd2243dda9 100644 --- a/netwerk/protocol/res/nsResProtocolHandler.h +++ b/netwerk/protocol/res/nsResProtocolHandler.h @@ -27,7 +27,7 @@ public: class nsResProtocolHandler final : public nsIResProtocolHandler, public nsSupportsWeakReference { public: - NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_ISUPPORTS NS_DECL_NSIPROTOCOLHANDLER NS_DECL_NSIRESPROTOCOLHANDLER From 12ea1bf6fe5d44b0e9b570dde86c2e6fe642566f Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Thu, 16 Jul 2015 15:50:07 -0700 Subject: [PATCH 11/96] Bug 1161831 - Factor the sharable bits out of nsIResProtocolHandler. r=billm --- chrome/RegistryMessageUtils.h | 29 +- chrome/nsChromeRegistryChrome.cpp | 2 +- chrome/nsChromeRegistryContent.cpp | 22 +- chrome/nsChromeRegistryContent.h | 6 +- dom/ipc/ContentChild.cpp | 6 +- dom/ipc/ContentChild.h | 4 +- dom/ipc/PContent.ipdl | 6 +- netwerk/build/nsNetCID.h | 12 +- netwerk/build/nsNetModule.cpp | 10 +- .../res/SubstitutingProtocolHandler.cpp | 374 ++++++++++++++++++ .../res/SubstitutingProtocolHandler.h | 71 ++++ netwerk/protocol/res/moz.build | 2 + .../protocol/res/nsIResProtocolHandler.idl | 37 +- .../res/nsISubstitutingProtocolHandler.idl | 46 +++ netwerk/protocol/res/nsResProtocolHandler.cpp | 373 +---------------- netwerk/protocol/res/nsResProtocolHandler.h | 44 +-- 16 files changed, 573 insertions(+), 471 deletions(-) create mode 100644 netwerk/protocol/res/SubstitutingProtocolHandler.cpp create mode 100644 netwerk/protocol/res/SubstitutingProtocolHandler.h create mode 100644 netwerk/protocol/res/nsISubstitutingProtocolHandler.idl diff --git a/chrome/RegistryMessageUtils.h b/chrome/RegistryMessageUtils.h index 1f8879cdbf7c..2d2e7d276b5a 100644 --- a/chrome/RegistryMessageUtils.h +++ b/chrome/RegistryMessageUtils.h @@ -39,14 +39,16 @@ struct ChromePackage } }; -struct ResourceMapping +struct SubstitutionMapping { - nsCString resource; + nsCString scheme; + nsCString path; SerializedURI resolvedURI; - bool operator ==(const ResourceMapping& rhs) const + bool operator ==(const SubstitutionMapping& rhs) const { - return resource.Equals(rhs.resource) && + return scheme.Equals(rhs.scheme) && + path.Equals(rhs.path) && resolvedURI == rhs.resolvedURI; } }; @@ -134,24 +136,27 @@ struct ParamTraits }; template <> -struct ParamTraits +struct ParamTraits { - typedef ResourceMapping paramType; + typedef SubstitutionMapping paramType; static void Write(Message* aMsg, const paramType& aParam) { - WriteParam(aMsg, aParam.resource); + WriteParam(aMsg, aParam.scheme); + WriteParam(aMsg, aParam.path); WriteParam(aMsg, aParam.resolvedURI); } static bool Read(const Message* aMsg, void** aIter, paramType* aResult) { - nsCString resource; + nsCString scheme, path; SerializedURI resolvedURI; - if (ReadParam(aMsg, aIter, &resource) && + if (ReadParam(aMsg, aIter, &scheme) && + ReadParam(aMsg, aIter, &path) && ReadParam(aMsg, aIter, &resolvedURI)) { - aResult->resource = resource; + aResult->scheme = scheme; + aResult->path = path; aResult->resolvedURI = resolvedURI; return true; } @@ -160,7 +165,9 @@ struct ParamTraits static void Log(const paramType& aParam, std::wstring* aLog) { - aLog->append(StringPrintf(L"[%s, %s, %u]", aParam.resource.get(), + aLog->append(StringPrintf(L"[%s://%s, %s, %u]", + aParam.scheme.get(), + aParam.path.get(), aParam.resolvedURI.spec.get())); } }; diff --git a/chrome/nsChromeRegistryChrome.cpp b/chrome/nsChromeRegistryChrome.cpp index 9d83da94b77b..3cd145385270 100644 --- a/chrome/nsChromeRegistryChrome.cpp +++ b/chrome/nsChromeRegistryChrome.cpp @@ -445,7 +445,7 @@ nsChromeRegistryChrome::SendRegisteredChrome( mozilla::dom::PContentParent* aParent) { InfallibleTArray packages; - InfallibleTArray resources; + InfallibleTArray resources; InfallibleTArray overrides; EnumerationArgs args = { diff --git a/chrome/nsChromeRegistryContent.cpp b/chrome/nsChromeRegistryContent.cpp index eec49b22373d..3714d3e439ef 100644 --- a/chrome/nsChromeRegistryContent.cpp +++ b/chrome/nsChromeRegistryContent.cpp @@ -17,7 +17,7 @@ nsChromeRegistryContent::nsChromeRegistryContent() void nsChromeRegistryContent::RegisterRemoteChrome( const InfallibleTArray& aPackages, - const InfallibleTArray& aResources, + const InfallibleTArray& aSubstitutions, const InfallibleTArray& aOverrides, const nsACString& aLocale, bool aReset) @@ -36,9 +36,9 @@ nsChromeRegistryContent::RegisterRemoteChrome( RegisterPackage(aPackages[i]); } - for (uint32_t i = aResources.Length(); i > 0; ) { + for (uint32_t i = aSubstitutions.Length(); i > 0; ) { --i; - RegisterResource(aResources[i]); + RegisterSubstitution(aSubstitutions[i]); } for (uint32_t i = aOverrides.Length(); i > 0; ) { @@ -94,32 +94,32 @@ nsChromeRegistryContent::RegisterPackage(const ChromePackage& aPackage) } void -nsChromeRegistryContent::RegisterResource(const ResourceMapping& aResource) +nsChromeRegistryContent::RegisterSubstitution(const SubstitutionMapping& aSubstitution) { nsCOMPtr io (do_GetIOService()); if (!io) return; nsCOMPtr ph; - nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph)); + nsresult rv = io->GetProtocolHandler(aSubstitution.scheme.get(), getter_AddRefs(ph)); if (NS_FAILED(rv)) return; - nsCOMPtr rph (do_QueryInterface(ph)); - if (!rph) + nsCOMPtr sph (do_QueryInterface(ph)); + if (!sph) return; nsCOMPtr resolvedURI; - if (aResource.resolvedURI.spec.Length()) { + if (aSubstitution.resolvedURI.spec.Length()) { nsresult rv = NS_NewURI(getter_AddRefs(resolvedURI), - aResource.resolvedURI.spec, - aResource.resolvedURI.charset.get(), + aSubstitution.resolvedURI.spec, + aSubstitution.resolvedURI.charset.get(), nullptr, io); if (NS_FAILED(rv)) return; } - rv = rph->SetSubstitution(aResource.resource, resolvedURI); + rv = sph->SetSubstitution(aSubstitution.path, resolvedURI); if (NS_FAILED(rv)) return; } diff --git a/chrome/nsChromeRegistryContent.h b/chrome/nsChromeRegistryContent.h index e7dc8848a487..fc164f664382 100644 --- a/chrome/nsChromeRegistryContent.h +++ b/chrome/nsChromeRegistryContent.h @@ -10,7 +10,7 @@ #include "nsClassHashtable.h" struct ChromePackage; -struct ResourceMapping; +struct SubstitutionMapping; struct OverrideMapping; class nsChromeRegistryContent : public nsChromeRegistry @@ -19,7 +19,7 @@ class nsChromeRegistryContent : public nsChromeRegistry nsChromeRegistryContent(); void RegisterRemoteChrome(const InfallibleTArray& aPackages, - const InfallibleTArray& aResources, + const InfallibleTArray& aResources, const InfallibleTArray& aOverrides, const nsACString& aLocale, bool aReset); @@ -41,7 +41,7 @@ class nsChromeRegistryContent : public nsChromeRegistry void RegisterPackage(const ChromePackage& aPackage); void RegisterOverride(const OverrideMapping& aOverride); - void RegisterResource(const ResourceMapping& aResource); + void RegisterSubstitution(const SubstitutionMapping& aResource); private: struct PackageEntry diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 97bea84d103e..9667202fa404 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -1838,7 +1838,7 @@ ContentChild::DeallocPWebrtcGlobalChild(PWebrtcGlobalChild *aActor) bool ContentChild::RecvRegisterChrome(InfallibleTArray&& packages, - InfallibleTArray&& resources, + InfallibleTArray&& resources, InfallibleTArray&& overrides, const nsCString& locale, const bool& reset) @@ -1866,8 +1866,8 @@ ContentChild::RecvRegisterChromeItem(const ChromeRegistryItem& item) chromeRegistry->RegisterOverride(item.get_OverrideMapping()); break; - case ChromeRegistryItem::TResourceMapping: - chromeRegistry->RegisterResource(item.get_ResourceMapping()); + case ChromeRegistryItem::TSubstitutionMapping: + chromeRegistry->RegisterSubstitution(item.get_SubstitutionMapping()); break; default: diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h index 20293839fb9e..806d12fb694b 100644 --- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -21,7 +21,7 @@ struct ChromePackage; class nsIObserver; -struct ResourceMapping; +struct SubstitutionMapping; struct OverrideMapping; class nsIDomainPolicy; @@ -282,7 +282,7 @@ public: virtual bool DeallocPSpeechSynthesisChild(PSpeechSynthesisChild* aActor) override; virtual bool RecvRegisterChrome(InfallibleTArray&& packages, - InfallibleTArray&& resources, + InfallibleTArray&& resources, InfallibleTArray&& overrides, const nsCString& locale, const bool& reset) override; diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index 335fc31e4a9b..d7b596b72258 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -71,7 +71,7 @@ include "mozilla/dom/indexedDB/SerializationHelpers.h"; using GeoPosition from "nsGeoPositionIPCSerialiser.h"; using struct ChromePackage from "mozilla/chrome/RegistryMessageUtils.h"; -using struct ResourceMapping from "mozilla/chrome/RegistryMessageUtils.h"; +using struct SubstitutionMapping from "mozilla/chrome/RegistryMessageUtils.h"; using struct OverrideMapping from "mozilla/chrome/RegistryMessageUtils.h"; using base::ChildPrivileges from "base/process_util.h"; using base::ProcessId from "base/process.h"; @@ -94,7 +94,7 @@ union ChromeRegistryItem { ChromePackage; OverrideMapping; - ResourceMapping; + SubstitutionMapping; }; namespace mozilla { @@ -521,7 +521,7 @@ child: PTestShell(); - RegisterChrome(ChromePackage[] packages, ResourceMapping[] resources, + RegisterChrome(ChromePackage[] packages, SubstitutionMapping[] substitutions, OverrideMapping[] overrides, nsCString locale, bool reset); RegisterChromeItem(ChromeRegistryItem item); diff --git a/netwerk/build/nsNetCID.h b/netwerk/build/nsNetCID.h index e816906ab685..dc70366744a9 100644 --- a/netwerk/build/nsNetCID.h +++ b/netwerk/build/nsNetCID.h @@ -637,15 +637,13 @@ {0x8c, 0xda, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3} \ } -#define NS_RESURL_CID \ -{ /* ff8fe7ec-2f74-4408-b742-6b7a546029a8 */ \ - 0xff8fe7ec, \ - 0x2f74, \ - 0x4408, \ - {0xb7, 0x42, 0x6b, 0x7a, 0x54, 0x60, 0x29, 0xa8} \ +#define NS_SUBSTITUTINGURL_CID \ +{ 0xdea9657c, \ + 0x18cf, \ + 0x4984, \ + { 0xbd, 0xe9, 0xcc, 0xef, 0x5d, 0x8a, 0xb4, 0x73 } \ } - /****************************************************************************** * netwerk/protocol/file/ classes */ diff --git a/netwerk/build/nsNetModule.cpp b/netwerk/build/nsNetModule.cpp index 875b899d3763..933c8d27c412 100644 --- a/netwerk/build/nsNetModule.cpp +++ b/netwerk/build/nsNetModule.cpp @@ -272,8 +272,12 @@ namespace net { #ifdef NECKO_PROTOCOL_res // resource #include "nsResProtocolHandler.h" +#include "SubstitutingProtocolHandler.h" NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsResProtocolHandler, Init) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsResURL) + +namespace mozilla { +NS_GENERIC_FACTORY_CONSTRUCTOR(SubstitutingURL) +} // namespace mozilla #endif #ifdef NECKO_PROTOCOL_device @@ -756,7 +760,7 @@ NS_DEFINE_NAMED_CID(NS_FTPPROTOCOLHANDLER_CID); #endif #ifdef NECKO_PROTOCOL_res NS_DEFINE_NAMED_CID(NS_RESPROTOCOLHANDLER_CID); -NS_DEFINE_NAMED_CID(NS_RESURL_CID); +NS_DEFINE_NAMED_CID(NS_SUBSTITUTINGURL_CID); #endif NS_DEFINE_NAMED_CID(NS_ABOUTPROTOCOLHANDLER_CID); NS_DEFINE_NAMED_CID(NS_SAFEABOUTPROTOCOLHANDLER_CID); @@ -902,7 +906,7 @@ static const mozilla::Module::CIDEntry kNeckoCIDs[] = { #endif #ifdef NECKO_PROTOCOL_res { &kNS_RESPROTOCOLHANDLER_CID, false, nullptr, nsResProtocolHandlerConstructor }, - { &kNS_RESURL_CID, false, nullptr, nsResURLConstructor }, + { &kNS_SUBSTITUTINGURL_CID, false, nullptr, mozilla::SubstitutingURLConstructor }, #endif { &kNS_ABOUTPROTOCOLHANDLER_CID, false, nullptr, nsAboutProtocolHandlerConstructor }, { &kNS_SAFEABOUTPROTOCOLHANDLER_CID, false, nullptr, nsSafeAboutProtocolHandlerConstructor }, diff --git a/netwerk/protocol/res/SubstitutingProtocolHandler.cpp b/netwerk/protocol/res/SubstitutingProtocolHandler.cpp new file mode 100644 index 000000000000..751e1721dcc6 --- /dev/null +++ b/netwerk/protocol/res/SubstitutingProtocolHandler.cpp @@ -0,0 +1,374 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#include "mozilla/chrome/RegistryMessageUtils.h" +#include "mozilla/dom/ContentParent.h" +#include "mozilla/unused.h" + +#include "SubstitutingProtocolHandler.h" +#include "nsIIOService.h" +#include "nsIFile.h" +#include "nsNetCID.h" +#include "nsNetUtil.h" +#include "nsURLHelper.h" +#include "nsEscape.h" + +using mozilla::dom::ContentParent; + +namespace mozilla { + +// Log module for Substituting Protocol logging. We keep the pre-existing module +// name of "nsResProtocol" to avoid disruption. +static PRLogModuleInfo *gResLog; + +static NS_DEFINE_CID(kSubstitutingURLCID, NS_SUBSTITUTINGURL_CID); + +//--------------------------------------------------------------------------------- +// SubstitutingURL : overrides nsStandardURL::GetFile to provide nsIFile resolution +//--------------------------------------------------------------------------------- + +nsresult +SubstitutingURL::EnsureFile() +{ + nsAutoCString ourScheme; + nsresult rv = GetScheme(ourScheme); + NS_ENSURE_SUCCESS(rv, rv); + + // Get the handler associated with this scheme. It would be nice to just + // pass this in when constructing SubstitutingURLs, but we need a generic + // factory constructor. + nsCOMPtr io = do_GetIOService(&rv); + nsCOMPtr handler; + rv = io->GetProtocolHandler(ourScheme.get(), getter_AddRefs(handler)); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr substHandler = do_QueryInterface(handler); + MOZ_ASSERT(substHandler); + + nsAutoCString spec; + rv = substHandler->ResolveURI(this, spec); + if (NS_FAILED(rv)) + return rv; + + nsAutoCString scheme; + rv = net_ExtractURLScheme(spec, nullptr, nullptr, &scheme); + if (NS_FAILED(rv)) + return rv; + + // Bug 585869: + // In most cases, the scheme is jar if it's not file. + // Regardless, net_GetFileFromURLSpec should be avoided + // when the scheme isn't file. + if (!scheme.EqualsLiteral("file")) + return NS_ERROR_NO_INTERFACE; + + return net_GetFileFromURLSpec(spec, getter_AddRefs(mFile)); +} + +/* virtual */ nsStandardURL* +SubstitutingURL::StartClone() +{ + SubstitutingURL *clone = new SubstitutingURL(); + return clone; +} + +NS_IMETHODIMP +SubstitutingURL::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc) +{ + *aClassIDNoAlloc = kSubstitutingURLCID; + return NS_OK; +} + +SubstitutingProtocolHandler::SubstitutingProtocolHandler(const char* aScheme, uint32_t aFlags) + : mScheme(aScheme) + , mFlags(aFlags) + , mSubstitutions(16) +{ + nsresult rv; + mIOService = do_GetIOService(&rv); + MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv) && mIOService); + + if (!gResLog) { + gResLog = PR_NewLogModule("nsResProtocol"); + } +} + +// +// IPC marshalling. +// + +struct EnumerateSubstitutionArg +{ + EnumerateSubstitutionArg(nsCString& aScheme, nsTArray& aMappings) + : mScheme(aScheme), mMappings(aMappings) {} + nsCString& mScheme; + nsTArray& mMappings; +}; + +static PLDHashOperator +EnumerateSubstitution(const nsACString& aKey, + nsIURI* aURI, + void* aArg) +{ + auto arg = static_cast(aArg); + SerializedURI uri; + if (aURI) { + aURI->GetSpec(uri.spec); + aURI->GetOriginCharset(uri.charset); + } + + SubstitutionMapping substitution = { arg->mScheme, nsCString(aKey), uri }; + arg->mMappings.AppendElement(substitution); + return (PLDHashOperator)PL_DHASH_NEXT; +} + +void +SubstitutingProtocolHandler::CollectSubstitutions(InfallibleTArray& aMappings) +{ + EnumerateSubstitutionArg arg(mScheme, aMappings); + mSubstitutions.EnumerateRead(&EnumerateSubstitution, &arg); +} + +void +SubstitutingProtocolHandler::SendSubstitution(const nsACString& aRoot, nsIURI* aBaseURI) +{ + if (GeckoProcessType_Content == XRE_GetProcessType()) { + return; + } + + nsTArray parents; + ContentParent::GetAll(parents); + if (!parents.Length()) { + return; + } + + SubstitutionMapping mapping; + mapping.scheme = mScheme; + mapping.path = aRoot; + if (aBaseURI) { + aBaseURI->GetSpec(mapping.resolvedURI.spec); + aBaseURI->GetOriginCharset(mapping.resolvedURI.charset); + } + + for (uint32_t i = 0; i < parents.Length(); i++) { + unused << parents[i]->SendRegisterChromeItem(mapping); + } +} + +//---------------------------------------------------------------------------- +// nsIProtocolHandler +//---------------------------------------------------------------------------- + +nsresult +SubstitutingProtocolHandler::GetScheme(nsACString &result) +{ + result = mScheme; + return NS_OK; +} + +nsresult +SubstitutingProtocolHandler::GetDefaultPort(int32_t *result) +{ + *result = -1; + return NS_OK; +} + +nsresult +SubstitutingProtocolHandler::GetProtocolFlags(uint32_t *result) +{ + *result = mFlags; + return NS_OK; +} + +nsresult +SubstitutingProtocolHandler::NewURI(const nsACString &aSpec, + const char *aCharset, + nsIURI *aBaseURI, + nsIURI **result) +{ + nsresult rv; + + nsRefPtr url = new SubstitutingURL(); + if (!url) + return NS_ERROR_OUT_OF_MEMORY; + + // unescape any %2f and %2e to make sure nsStandardURL coalesces them. + // Later net_GetFileFromURLSpec() will do a full unescape and we want to + // treat them the same way the file system will. (bugs 380994, 394075) + nsAutoCString spec; + const char *src = aSpec.BeginReading(); + const char *end = aSpec.EndReading(); + const char *last = src; + + spec.SetCapacity(aSpec.Length()+1); + for ( ; src < end; ++src) { + if (*src == '%' && (src < end-2) && *(src+1) == '2') { + char ch = '\0'; + if (*(src+2) == 'f' || *(src+2) == 'F') { + ch = '/'; + } else if (*(src+2) == 'e' || *(src+2) == 'E') { + ch = '.'; + } + + if (ch) { + if (last < src) { + spec.Append(last, src-last); + } + spec.Append(ch); + src += 2; + last = src+1; // src will be incremented by the loop + } + } + } + if (last < src) + spec.Append(last, src-last); + + rv = url->Init(nsIStandardURL::URLTYPE_STANDARD, -1, spec, aCharset, aBaseURI); + if (NS_SUCCEEDED(rv)) { + url.forget(result); + } + return rv; +} + +nsresult +SubstitutingProtocolHandler::NewChannel2(nsIURI* uri, + nsILoadInfo* aLoadInfo, + nsIChannel** result) +{ + NS_ENSURE_ARG_POINTER(uri); + nsAutoCString spec; + nsresult rv = ResolveURI(uri, spec); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr newURI; + rv = NS_NewURI(getter_AddRefs(newURI), spec); + NS_ENSURE_SUCCESS(rv, rv); + + rv = NS_NewChannelInternal(result, newURI, aLoadInfo); + NS_ENSURE_SUCCESS(rv, rv); + + nsLoadFlags loadFlags = 0; + (*result)->GetLoadFlags(&loadFlags); + (*result)->SetLoadFlags(loadFlags & ~nsIChannel::LOAD_REPLACE); + return (*result)->SetOriginalURI(uri); +} + +nsresult +SubstitutingProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result) +{ + return NewChannel2(uri, nullptr, result); +} + +nsresult +SubstitutingProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval) +{ + // don't override anything. + *_retval = false; + return NS_OK; +} + +//---------------------------------------------------------------------------- +// nsISubstitutingProtocolHandler +//---------------------------------------------------------------------------- + +nsresult +SubstitutingProtocolHandler::SetSubstitution(const nsACString& root, nsIURI *baseURI) +{ + if (!baseURI) { + mSubstitutions.Remove(root); + SendSubstitution(root, baseURI); + return NS_OK; + } + + // If baseURI isn't a same-scheme URI, we can set the substitution immediately. + nsAutoCString scheme; + nsresult rv = baseURI->GetScheme(scheme); + NS_ENSURE_SUCCESS(rv, rv); + if (!scheme.Equals(mScheme)) { + mSubstitutions.Put(root, baseURI); + SendSubstitution(root, baseURI); + return NS_OK; + } + + // baseURI is a same-type substituting URI, let's resolve it first. + nsAutoCString newBase; + rv = ResolveURI(baseURI, newBase); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr newBaseURI; + rv = mIOService->NewURI(newBase, nullptr, nullptr, getter_AddRefs(newBaseURI)); + NS_ENSURE_SUCCESS(rv, rv); + + mSubstitutions.Put(root, newBaseURI); + SendSubstitution(root, newBaseURI); + return NS_OK; +} + +nsresult +SubstitutingProtocolHandler::GetSubstitution(const nsACString& root, nsIURI **result) +{ + NS_ENSURE_ARG_POINTER(result); + + if (mSubstitutions.Get(root, result)) + return NS_OK; + + return GetSubstitutionInternal(root, result); +} + +nsresult +SubstitutingProtocolHandler::HasSubstitution(const nsACString& root, bool *result) +{ + NS_ENSURE_ARG_POINTER(result); + + *result = mSubstitutions.Get(root, nullptr); + return NS_OK; +} + +nsresult +SubstitutingProtocolHandler::ResolveURI(nsIURI *uri, nsACString &result) +{ + nsresult rv; + + nsAutoCString host; + nsAutoCString path; + + rv = uri->GetAsciiHost(host); + if (NS_FAILED(rv)) return rv; + + rv = uri->GetPath(path); + if (NS_FAILED(rv)) return rv; + + // Unescape the path so we can perform some checks on it. + nsAutoCString unescapedPath(path); + NS_UnescapeURL(unescapedPath); + + // Don't misinterpret the filepath as an absolute URI. + if (unescapedPath.FindChar(':') != -1) + return NS_ERROR_MALFORMED_URI; + + if (unescapedPath.FindChar('\\') != -1) + return NS_ERROR_MALFORMED_URI; + + const char *p = path.get() + 1; // path always starts with a slash + NS_ASSERTION(*(p-1) == '/', "Path did not begin with a slash!"); + + if (*p == '/') + return NS_ERROR_MALFORMED_URI; + + nsCOMPtr baseURI; + rv = GetSubstitution(host, getter_AddRefs(baseURI)); + if (NS_FAILED(rv)) return rv; + + rv = baseURI->Resolve(nsDependentCString(p, path.Length()-1), result); + + if (MOZ_LOG_TEST(gResLog, LogLevel::Debug)) { + nsAutoCString spec; + uri->GetAsciiSpec(spec); + MOZ_LOG(gResLog, LogLevel::Debug, ("%s\n -> %s\n", spec.get(), PromiseFlatCString(result).get())); + } + return rv; +} + +} // namespace mozilla diff --git a/netwerk/protocol/res/SubstitutingProtocolHandler.h b/netwerk/protocol/res/SubstitutingProtocolHandler.h new file mode 100644 index 000000000000..c75436c009f1 --- /dev/null +++ b/netwerk/protocol/res/SubstitutingProtocolHandler.h @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 SubstitutingProtocolHandler_h___ +#define SubstitutingProtocolHandler_h___ + +#include "nsISubstitutingProtocolHandler.h" + +#include "nsInterfaceHashtable.h" +#include "nsIOService.h" +#include "nsStandardURL.h" +#include "mozilla/chrome/RegistryMessageUtils.h" + +class nsIIOService; + +namespace mozilla { + +// +// Base class for resource://-like substitution protocols. +// +// If you add a new protocol, make sure to change nsChromeRegistryChrome +// to properly invoke CollectSubstitutions at the right time. +class SubstitutingProtocolHandler +{ +public: + SubstitutingProtocolHandler(const char* aScheme, uint32_t aFlags); + + NS_INLINE_DECL_REFCOUNTING(SubstitutingProtocolHandler); + NS_DECL_NON_VIRTUAL_NSIPROTOCOLHANDLER; + NS_DECL_NON_VIRTUAL_NSISUBSTITUTINGPROTOCOLHANDLER; + + void CollectSubstitutions(InfallibleTArray& aResources); + +protected: + virtual ~SubstitutingProtocolHandler() {} + + void SendSubstitution(const nsACString& aRoot, nsIURI* aBaseURI); + + // Override this in the subclass to try additional lookups after checking + // mSubstitutions. + virtual nsresult GetSubstitutionInternal(const nsACString& aRoot, nsIURI** aResult) + { + *aResult = nullptr; + return NS_ERROR_NOT_AVAILABLE; + } + + nsIIOService* IOService() { return mIOService; } + +private: + nsCString mScheme; + uint32_t mFlags; + nsInterfaceHashtable mSubstitutions; + nsCOMPtr mIOService; +}; + +// SubstitutingURL : overrides nsStandardURL::GetFile to provide nsIFile resolution +class SubstitutingURL : public nsStandardURL +{ +public: + SubstitutingURL() : nsStandardURL(true) {} + virtual nsStandardURL* StartClone(); + virtual nsresult EnsureFile(); + NS_IMETHOD GetClassIDNoAlloc(nsCID *aCID); +}; + +} // namespace mozilla + +#endif /* SubstitutingProtocolHandler_h___ */ diff --git a/netwerk/protocol/res/moz.build b/netwerk/protocol/res/moz.build index 3875aedf9c49..61771b38e008 100644 --- a/netwerk/protocol/res/moz.build +++ b/netwerk/protocol/res/moz.build @@ -6,12 +6,14 @@ XPIDL_SOURCES += [ 'nsIResProtocolHandler.idl', + 'nsISubstitutingProtocolHandler.idl', ] XPIDL_MODULE = 'necko_res' SOURCES += [ 'nsResProtocolHandler.cpp', + 'SubstitutingProtocolHandler.cpp', ] FAIL_ON_WARNINGS = True diff --git a/netwerk/protocol/res/nsIResProtocolHandler.idl b/netwerk/protocol/res/nsIResProtocolHandler.idl index 0548d3c49928..56c597f4c73f 100644 --- a/netwerk/protocol/res/nsIResProtocolHandler.idl +++ b/netwerk/protocol/res/nsIResProtocolHandler.idl @@ -3,43 +3,12 @@ * 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/. */ -#include "nsIProtocolHandler.idl" +#include "nsISubstitutingProtocolHandler.idl" /** * Protocol handler interface for the resource:// protocol */ -[scriptable, uuid(067ca872-e947-4bd6-8946-a479cb6ba5dd)] -interface nsIResProtocolHandler : nsIProtocolHandler +[scriptable, uuid(241d34ac-9ed5-46d7-910c-7a9d914aa0c5)] +interface nsIResProtocolHandler : nsISubstitutingProtocolHandler { - /** - * Sets the substitution for the root key: - * resource://root/path ==> baseURI.resolve(path) - * - * A null baseURI removes the specified substitution. - * - * A root key should always be lowercase; however, this may not be - * enforced. - */ - void setSubstitution(in ACString root, in nsIURI baseURI); - - /** - * Gets the substitution for the root key. - * - * @throws NS_ERROR_NOT_AVAILABLE if none exists. - */ - nsIURI getSubstitution(in ACString root); - - /** - * Returns TRUE if the substitution exists and FALSE otherwise. - */ - boolean hasSubstitution(in ACString root); - - /** - * Utility function to resolve a resource URI. A resolved URI is not - * guaranteed to reference a resource that exists (ie. opening a channel to - * the resolved URI may fail). - * - * @throws NS_ERROR_NOT_AVAILABLE if resURI.host() is an unknown root key. - */ - AUTF8String resolveURI(in nsIURI resURI); }; diff --git a/netwerk/protocol/res/nsISubstitutingProtocolHandler.idl b/netwerk/protocol/res/nsISubstitutingProtocolHandler.idl new file mode 100644 index 000000000000..e2c816a85577 --- /dev/null +++ b/netwerk/protocol/res/nsISubstitutingProtocolHandler.idl @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +#include "nsIProtocolHandler.idl" + +/** + * Protocol handler superinterface for a protocol which performs substitutions + * from URIs of its scheme to URIs of another scheme. + */ +[scriptable, uuid(154c64fd-a69e-4105-89f8-bd7dfe621372)] +interface nsISubstitutingProtocolHandler : nsIProtocolHandler +{ + /** + * Sets the substitution for the root key: + * resource://root/path ==> baseURI.resolve(path) + * + * A null baseURI removes the specified substitution. + * + * A root key should always be lowercase; however, this may not be + * enforced. + */ + void setSubstitution(in ACString root, in nsIURI baseURI); + + /** + * Gets the substitution for the root key. + * + * @throws NS_ERROR_NOT_AVAILABLE if none exists. + */ + nsIURI getSubstitution(in ACString root); + + /** + * Returns TRUE if the substitution exists and FALSE otherwise. + */ + boolean hasSubstitution(in ACString root); + + /** + * Utility function to resolve a substituted URI. A resolved URI is not + * guaranteed to reference a resource that exists (ie. opening a channel to + * the resolved URI may fail). + * + * @throws NS_ERROR_NOT_AVAILABLE if resURI.host() is an unknown root key. + */ + AUTF8String resolveURI(in nsIURI resURI); +}; diff --git a/netwerk/protocol/res/nsResProtocolHandler.cpp b/netwerk/protocol/res/nsResProtocolHandler.cpp index f13cedb4d3be..9dbef19b47c2 100644 --- a/netwerk/protocol/res/nsResProtocolHandler.cpp +++ b/netwerk/protocol/res/nsResProtocolHandler.cpp @@ -21,108 +21,13 @@ using mozilla::dom::ContentParent; using mozilla::LogLevel; using mozilla::unused; -static NS_DEFINE_CID(kResURLCID, NS_RESURL_CID); - -static nsResProtocolHandler *gResHandler = nullptr; - -// -// Log module for Resource Protocol logging... -// -// To enable logging (see prlog.h for full details): -// -// set NSPR_LOG_MODULES=nsResProtocol:5 -// set NSPR_LOG_FILE=log.txt -// -// this enables LogLevel::Debug level information and places all output in -// the file log.txt -// -static PRLogModuleInfo *gResLog; - #define kAPP NS_LITERAL_CSTRING("app") #define kGRE NS_LITERAL_CSTRING("gre") -//---------------------------------------------------------------------------- -// nsResURL : overrides nsStandardURL::GetFile to provide nsIFile resolution -//---------------------------------------------------------------------------- - -nsresult -nsResURL::EnsureFile() -{ - nsresult rv; - - NS_ENSURE_TRUE(gResHandler, NS_ERROR_NOT_AVAILABLE); - - nsAutoCString spec; - rv = gResHandler->ResolveURI(this, spec); - if (NS_FAILED(rv)) - return rv; - - nsAutoCString scheme; - rv = net_ExtractURLScheme(spec, nullptr, nullptr, &scheme); - if (NS_FAILED(rv)) - return rv; - - // Bug 585869: - // In most cases, the scheme is jar if it's not file. - // Regardless, net_GetFileFromURLSpec should be avoided - // when the scheme isn't file. - if (!scheme.EqualsLiteral("file")) - return NS_ERROR_NO_INTERFACE; - - rv = net_GetFileFromURLSpec(spec, getter_AddRefs(mFile)); -#ifdef DEBUG_bsmedberg - if (NS_SUCCEEDED(rv)) { - bool exists = true; - mFile->Exists(&exists); - if (!exists) { - printf("resource %s doesn't exist!\n", spec.get()); - } - } -#endif - - return rv; -} - -/* virtual */ nsStandardURL* -nsResURL::StartClone() -{ - nsResURL *clone = new nsResURL(); - return clone; -} - -NS_IMETHODIMP -nsResURL::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc) -{ - *aClassIDNoAlloc = kResURLCID; - return NS_OK; -} - -//---------------------------------------------------------------------------- -// nsResProtocolHandler -//---------------------------------------------------------------------------- - -nsResProtocolHandler::nsResProtocolHandler() - : mSubstitutions(16) -{ - gResLog = PR_NewLogModule("nsResProtocol"); - - NS_ASSERTION(!gResHandler, "res handler already created!"); - gResHandler = this; -} - -nsResProtocolHandler::~nsResProtocolHandler() -{ - gResHandler = nullptr; -} - nsresult nsResProtocolHandler::Init() { nsresult rv; - - mIOService = do_GetIOService(&rv); - NS_ENSURE_SUCCESS(rv, rv); - nsAutoCString appURI, greURI; rv = mozilla::Omnijar::GetURIString(mozilla::Omnijar::APP, appURI); NS_ENSURE_SUCCESS(rv, rv); @@ -165,226 +70,19 @@ nsResProtocolHandler::Init() return rv; } -static PLDHashOperator -EnumerateSubstitution(const nsACString& aKey, - nsIURI* aURI, - void* aArg) -{ - nsTArray* resources = - static_cast*>(aArg); - SerializedURI uri; - if (aURI) { - aURI->GetSpec(uri.spec); - aURI->GetOriginCharset(uri.charset); - } - - ResourceMapping resource = { - nsCString(aKey), uri - }; - resources->AppendElement(resource); - return (PLDHashOperator)PL_DHASH_NEXT; -} - -void -nsResProtocolHandler::CollectSubstitutions(InfallibleTArray& aResources) -{ - mSubstitutions.EnumerateRead(&EnumerateSubstitution, &aResources); -} - //---------------------------------------------------------------------------- // nsResProtocolHandler::nsISupports //---------------------------------------------------------------------------- -NS_IMPL_ISUPPORTS(nsResProtocolHandler, - nsIResProtocolHandler, - nsIProtocolHandler, - nsISupportsWeakReference) +NS_IMPL_QUERY_INTERFACE(nsResProtocolHandler, nsIResProtocolHandler, + nsISubstitutingProtocolHandler, nsIProtocolHandler, + nsISupportsWeakReference) +NS_IMPL_ADDREF_INHERITED(nsResProtocolHandler, SubstitutingProtocolHandler) +NS_IMPL_RELEASE_INHERITED(nsResProtocolHandler, SubstitutingProtocolHandler) -//---------------------------------------------------------------------------- -// nsResProtocolHandler::nsIProtocolHandler -//---------------------------------------------------------------------------- - -NS_IMETHODIMP -nsResProtocolHandler::GetScheme(nsACString &result) +nsresult +nsResProtocolHandler::GetSubstitutionInternal(const nsACString& root, nsIURI **result) { - result.AssignLiteral("resource"); - return NS_OK; -} - -NS_IMETHODIMP -nsResProtocolHandler::GetDefaultPort(int32_t *result) -{ - *result = -1; // no port for res: URLs - return NS_OK; -} - -NS_IMETHODIMP -nsResProtocolHandler::GetProtocolFlags(uint32_t *result) -{ - // XXXbz Is this really true for all resource: URIs? Could we - // somehow give different flags to some of them? - *result = URI_STD | URI_IS_UI_RESOURCE | URI_IS_LOCAL_RESOURCE; - return NS_OK; -} - -NS_IMETHODIMP -nsResProtocolHandler::NewURI(const nsACString &aSpec, - const char *aCharset, - nsIURI *aBaseURI, - nsIURI **result) -{ - nsresult rv; - - nsRefPtr resURL = new nsResURL(); - if (!resURL) - return NS_ERROR_OUT_OF_MEMORY; - - // unescape any %2f and %2e to make sure nsStandardURL coalesces them. - // Later net_GetFileFromURLSpec() will do a full unescape and we want to - // treat them the same way the file system will. (bugs 380994, 394075) - nsAutoCString spec; - const char *src = aSpec.BeginReading(); - const char *end = aSpec.EndReading(); - const char *last = src; - - spec.SetCapacity(aSpec.Length()+1); - for ( ; src < end; ++src) { - if (*src == '%' && (src < end-2) && *(src+1) == '2') { - char ch = '\0'; - if (*(src+2) == 'f' || *(src+2) == 'F') - ch = '/'; - else if (*(src+2) == 'e' || *(src+2) == 'E') - ch = '.'; - - if (ch) { - if (last < src) - spec.Append(last, src-last); - spec.Append(ch); - src += 2; - last = src+1; // src will be incremented by the loop - } - } - } - if (last < src) - spec.Append(last, src-last); - - rv = resURL->Init(nsIStandardURL::URLTYPE_STANDARD, -1, spec, aCharset, aBaseURI); - if (NS_SUCCEEDED(rv)) { - resURL.forget(result); - } - return rv; -} - -NS_IMETHODIMP -nsResProtocolHandler::NewChannel2(nsIURI* uri, - nsILoadInfo* aLoadInfo, - nsIChannel** result) -{ - NS_ENSURE_ARG_POINTER(uri); - nsAutoCString spec; - nsresult rv = ResolveURI(uri, spec); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr newURI; - rv = NS_NewURI(getter_AddRefs(newURI), spec); - NS_ENSURE_SUCCESS(rv, rv); - - rv = NS_NewChannelInternal(result, - newURI, - aLoadInfo); - NS_ENSURE_SUCCESS(rv, rv); - - nsLoadFlags loadFlags = 0; - (*result)->GetLoadFlags(&loadFlags); - (*result)->SetLoadFlags(loadFlags & ~nsIChannel::LOAD_REPLACE); - return (*result)->SetOriginalURI(uri); -} - -NS_IMETHODIMP -nsResProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result) -{ - return NewChannel2(uri, nullptr, result); -} - -NS_IMETHODIMP -nsResProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval) -{ - // don't override anything. - *_retval = false; - return NS_OK; -} - -//---------------------------------------------------------------------------- -// nsResProtocolHandler::nsIResProtocolHandler -//---------------------------------------------------------------------------- - -static void -SendResourceSubstitution(const nsACString& root, nsIURI* baseURI) -{ - if (GeckoProcessType_Content == XRE_GetProcessType()) { - return; - } - - ResourceMapping resourceMapping; - resourceMapping.resource = root; - if (baseURI) { - baseURI->GetSpec(resourceMapping.resolvedURI.spec); - baseURI->GetOriginCharset(resourceMapping.resolvedURI.charset); - } - - nsTArray parents; - ContentParent::GetAll(parents); - if (!parents.Length()) { - return; - } - - for (uint32_t i = 0; i < parents.Length(); i++) { - unused << parents[i]->SendRegisterChromeItem(resourceMapping); - } -} - -NS_IMETHODIMP -nsResProtocolHandler::SetSubstitution(const nsACString& root, nsIURI *baseURI) -{ - if (!baseURI) { - mSubstitutions.Remove(root); - SendResourceSubstitution(root, baseURI); - return NS_OK; - } - - // If baseURI isn't a resource URI, we can set the substitution immediately. - nsAutoCString scheme; - nsresult rv = baseURI->GetScheme(scheme); - NS_ENSURE_SUCCESS(rv, rv); - if (!scheme.EqualsLiteral("resource")) { - mSubstitutions.Put(root, baseURI); - SendResourceSubstitution(root, baseURI); - return NS_OK; - } - - // baseURI is a resource URI, let's resolve it first. - nsAutoCString newBase; - rv = ResolveURI(baseURI, newBase); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr newBaseURI; - rv = mIOService->NewURI(newBase, nullptr, nullptr, - getter_AddRefs(newBaseURI)); - NS_ENSURE_SUCCESS(rv, rv); - - mSubstitutions.Put(root, newBaseURI); - SendResourceSubstitution(root, newBaseURI); - return NS_OK; -} - -NS_IMETHODIMP -nsResProtocolHandler::GetSubstitution(const nsACString& root, nsIURI **result) -{ - NS_ENSURE_ARG_POINTER(result); - - if (mSubstitutions.Get(root, result)) - return NS_OK; - // try invoking the directory service for "resource:root" nsAutoCString key; @@ -396,64 +94,9 @@ nsResProtocolHandler::GetSubstitution(const nsACString& root, nsIURI **result) if (NS_FAILED(rv)) return NS_ERROR_NOT_AVAILABLE; - rv = mIOService->NewFileURI(file, result); + rv = IOService()->NewFileURI(file, result); if (NS_FAILED(rv)) return NS_ERROR_NOT_AVAILABLE; return NS_OK; } - -NS_IMETHODIMP -nsResProtocolHandler::HasSubstitution(const nsACString& root, bool *result) -{ - NS_ENSURE_ARG_POINTER(result); - - *result = mSubstitutions.Get(root, nullptr); - return NS_OK; -} - -NS_IMETHODIMP -nsResProtocolHandler::ResolveURI(nsIURI *uri, nsACString &result) -{ - nsresult rv; - - nsAutoCString host; - nsAutoCString path; - - rv = uri->GetAsciiHost(host); - if (NS_FAILED(rv)) return rv; - - rv = uri->GetPath(path); - if (NS_FAILED(rv)) return rv; - - // Unescape the path so we can perform some checks on it. - nsAutoCString unescapedPath(path); - NS_UnescapeURL(unescapedPath); - - // Don't misinterpret the filepath as an absolute URI. - if (unescapedPath.FindChar(':') != -1) - return NS_ERROR_MALFORMED_URI; - - if (unescapedPath.FindChar('\\') != -1) - return NS_ERROR_MALFORMED_URI; - - const char *p = path.get() + 1; // path always starts with a slash - NS_ASSERTION(*(p-1) == '/', "Path did not begin with a slash!"); - - if (*p == '/') - return NS_ERROR_MALFORMED_URI; - - nsCOMPtr baseURI; - rv = GetSubstitution(host, getter_AddRefs(baseURI)); - if (NS_FAILED(rv)) return rv; - - rv = baseURI->Resolve(nsDependentCString(p, path.Length()-1), result); - - if (MOZ_LOG_TEST(gResLog, LogLevel::Debug)) { - nsAutoCString spec; - uri->GetAsciiSpec(spec); - MOZ_LOG(gResLog, LogLevel::Debug, - ("%s\n -> %s\n", spec.get(), PromiseFlatCString(result).get())); - } - return rv; -} diff --git a/netwerk/protocol/res/nsResProtocolHandler.h b/netwerk/protocol/res/nsResProtocolHandler.h index 36cd2243dda9..f125b51068df 100644 --- a/netwerk/protocol/res/nsResProtocolHandler.h +++ b/netwerk/protocol/res/nsResProtocolHandler.h @@ -6,46 +6,34 @@ #ifndef nsResProtocolHandler_h___ #define nsResProtocolHandler_h___ +#include "SubstitutingProtocolHandler.h" + #include "nsIResProtocolHandler.h" #include "nsInterfaceHashtable.h" #include "nsWeakReference.h" #include "nsStandardURL.h" -class nsIIOService; -struct ResourceMapping; - -// nsResURL : overrides nsStandardURL::GetFile to provide nsIFile resolution -class nsResURL : public nsStandardURL +struct SubstitutionMapping; +class nsResProtocolHandler final : public nsIResProtocolHandler, + public mozilla::SubstitutingProtocolHandler, + public nsSupportsWeakReference { public: - nsResURL() : nsStandardURL(true) {} - virtual nsStandardURL* StartClone(); - virtual nsresult EnsureFile(); - NS_IMETHOD GetClassIDNoAlloc(nsCID *aCID); -}; - -class nsResProtocolHandler final : public nsIResProtocolHandler, public nsSupportsWeakReference -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIPROTOCOLHANDLER + NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIRESPROTOCOLHANDLER - nsResProtocolHandler(); + NS_FORWARD_NSIPROTOCOLHANDLER(mozilla::SubstitutingProtocolHandler::) + NS_FORWARD_NSISUBSTITUTINGPROTOCOLHANDLER(mozilla::SubstitutingProtocolHandler::) + + nsResProtocolHandler() + : SubstitutingProtocolHandler("resource", URI_STD | URI_IS_UI_RESOURCE | URI_IS_LOCAL_RESOURCE) + {} nsresult Init(); - void CollectSubstitutions(InfallibleTArray& aResources); - -private: - virtual ~nsResProtocolHandler(); - - nsresult Init(nsIFile *aOmniJar); - nsresult AddSpecialDir(const char* aSpecialDir, const nsACString& aSubstitution); - nsInterfaceHashtable mSubstitutions; - nsCOMPtr mIOService; - - friend class nsResURL; +protected: + nsresult GetSubstitutionInternal(const nsACString& aRoot, nsIURI** aResult) override; + virtual ~nsResProtocolHandler() {} }; #endif /* nsResProtocolHandler_h___ */ From f925835ed952ae269c219f5e8a54d266a619ba4f Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Sun, 19 Jul 2015 18:42:16 -0700 Subject: [PATCH 12/96] Bug 1161831 - Implement moz-extension protocol. r=bz,r=billm,sr=mcmanus The heavy lifting all happened in the previous patch, so this is easy now. --- caps/nsIAddonPolicyService.idl | 7 +++- caps/nsScriptSecurityManager.cpp | 10 ++++++ caps/nsScriptSecurityManager.h | 16 +++++++++ netwerk/build/nsNetCID.h | 8 +++++ netwerk/build/nsNetModule.cpp | 5 +++ .../protocol/res/ExtensionProtocolHandler.cpp | 16 +++++++++ .../protocol/res/ExtensionProtocolHandler.h | 35 +++++++++++++++++++ netwerk/protocol/res/moz.build | 1 + toolkit/components/utils/simpleServices.js | 26 ++++++++++++++ 9 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 netwerk/protocol/res/ExtensionProtocolHandler.cpp create mode 100644 netwerk/protocol/res/ExtensionProtocolHandler.h diff --git a/caps/nsIAddonPolicyService.idl b/caps/nsIAddonPolicyService.idl index f858b1484f7c..caad17cb32ce 100644 --- a/caps/nsIAddonPolicyService.idl +++ b/caps/nsIAddonPolicyService.idl @@ -11,7 +11,7 @@ * This interface allows the security manager to query custom per-addon security * policy. */ -[scriptable,uuid(fedf126c-988e-42df-82c9-f2ac99cd65f3)] +[scriptable,uuid(3ec203f8-2bd0-4f4c-8f99-f9f056221231)] interface nsIAddonPolicyService : nsISupports { /** @@ -19,4 +19,9 @@ interface nsIAddonPolicyService : nsISupports * data from |aURI|. */ boolean addonMayLoadURI(in AString aAddonId, in nsIURI aURI); + + /** + * Returns true if a given extension:// URI is web-accessible. + */ + boolean extensionURILoadableByAnyone(in nsIURI aURI); }; diff --git a/caps/nsScriptSecurityManager.cpp b/caps/nsScriptSecurityManager.cpp index 55d555bbb575..7ab202c36aa0 100644 --- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -745,6 +745,16 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal, // the methods that work on chains of nested URIs and they will only look // at the flags for our one URI. + // Special case: moz-extension has a whitelist of URIs that are loadable by + // anyone. + if (targetScheme.EqualsLiteral("moz-extension") && GetAddonPolicyService()) { + bool loadable = false; + rv = GetAddonPolicyService()->ExtensionURILoadableByAnyone(targetBaseURI, &loadable); + if (NS_SUCCEEDED(rv) && loadable) { + return NS_OK; + } + } + // Check for system target URI rv = DenyAccessIfURIHasFlags(targetBaseURI, nsIProtocolHandler::URI_DANGEROUS_TO_LOAD); diff --git a/caps/nsScriptSecurityManager.h b/caps/nsScriptSecurityManager.h index e141b6089a7b..50b9a8a410b2 100644 --- a/caps/nsScriptSecurityManager.h +++ b/caps/nsScriptSecurityManager.h @@ -8,10 +8,15 @@ #define nsScriptSecurityManager_h__ #include "nsIScriptSecurityManager.h" + +#include "nsIAddonPolicyService.h" +#include "mozilla/Maybe.h" +#include "nsIAddonPolicyService.h" #include "nsIPrincipal.h" #include "nsCOMPtr.h" #include "nsIChannelEventSink.h" #include "nsIObserver.h" +#include "nsServiceManagerUtils.h" #include "plstr.h" #include "js/TypeDecls.h" @@ -124,6 +129,17 @@ private: // policy machinery will be removed soon. nsCOMPtr mDomainPolicy; + // Cached addon policy service. We can't generate this in Init() because + // that's too early to get a service. + mozilla::Maybe> mAddonPolicyService; + nsIAddonPolicyService* GetAddonPolicyService() + { + if (mAddonPolicyService.isNothing()) { + mAddonPolicyService.emplace(do_GetService("@mozilla.org/addons/policy-service;1")); + } + return mAddonPolicyService.ref(); + } + static bool sStrictFileOriginPolicy; static nsIIOService *sIOService; diff --git a/netwerk/build/nsNetCID.h b/netwerk/build/nsNetCID.h index dc70366744a9..804ad825e22e 100644 --- a/netwerk/build/nsNetCID.h +++ b/netwerk/build/nsNetCID.h @@ -637,6 +637,14 @@ {0x8c, 0xda, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3} \ } +#define NS_EXTENSIONPROTOCOLHANDLER_CID \ +{ /* aea16cd0-f020-4138-b068-0716c4a15b5a */ \ + 0xaea16cd0, \ + 0xf020, \ + 0x4138, \ + {0xb0, 0x68, 0x07, 0x16, 0xc4, 0xa1, 0x5b, 0x5a} \ +} + #define NS_SUBSTITUTINGURL_CID \ { 0xdea9657c, \ 0x18cf, \ diff --git a/netwerk/build/nsNetModule.cpp b/netwerk/build/nsNetModule.cpp index 933c8d27c412..3a5881f7c005 100644 --- a/netwerk/build/nsNetModule.cpp +++ b/netwerk/build/nsNetModule.cpp @@ -272,10 +272,12 @@ namespace net { #ifdef NECKO_PROTOCOL_res // resource #include "nsResProtocolHandler.h" +#include "ExtensionProtocolHandler.h" #include "SubstitutingProtocolHandler.h" NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsResProtocolHandler, Init) namespace mozilla { +NS_GENERIC_FACTORY_CONSTRUCTOR(ExtensionProtocolHandler) NS_GENERIC_FACTORY_CONSTRUCTOR(SubstitutingURL) } // namespace mozilla #endif @@ -760,6 +762,7 @@ NS_DEFINE_NAMED_CID(NS_FTPPROTOCOLHANDLER_CID); #endif #ifdef NECKO_PROTOCOL_res NS_DEFINE_NAMED_CID(NS_RESPROTOCOLHANDLER_CID); +NS_DEFINE_NAMED_CID(NS_EXTENSIONPROTOCOLHANDLER_CID); NS_DEFINE_NAMED_CID(NS_SUBSTITUTINGURL_CID); #endif NS_DEFINE_NAMED_CID(NS_ABOUTPROTOCOLHANDLER_CID); @@ -906,6 +909,7 @@ static const mozilla::Module::CIDEntry kNeckoCIDs[] = { #endif #ifdef NECKO_PROTOCOL_res { &kNS_RESPROTOCOLHANDLER_CID, false, nullptr, nsResProtocolHandlerConstructor }, + { &kNS_EXTENSIONPROTOCOLHANDLER_CID, false, nullptr, mozilla::ExtensionProtocolHandlerConstructor }, { &kNS_SUBSTITUTINGURL_CID, false, nullptr, mozilla::SubstitutingURLConstructor }, #endif { &kNS_ABOUTPROTOCOLHANDLER_CID, false, nullptr, nsAboutProtocolHandlerConstructor }, @@ -1061,6 +1065,7 @@ static const mozilla::Module::ContractIDEntry kNeckoContracts[] = { #endif #ifdef NECKO_PROTOCOL_res { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "resource", &kNS_RESPROTOCOLHANDLER_CID }, + { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "moz-extension", &kNS_EXTENSIONPROTOCOLHANDLER_CID }, #endif { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "about", &kNS_ABOUTPROTOCOLHANDLER_CID }, { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "moz-safe-about", &kNS_SAFEABOUTPROTOCOLHANDLER_CID }, diff --git a/netwerk/protocol/res/ExtensionProtocolHandler.cpp b/netwerk/protocol/res/ExtensionProtocolHandler.cpp new file mode 100644 index 000000000000..2d6032b98401 --- /dev/null +++ b/netwerk/protocol/res/ExtensionProtocolHandler.cpp @@ -0,0 +1,16 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#include "ExtensionProtocolHandler.h" + +namespace mozilla { + +NS_IMPL_QUERY_INTERFACE(ExtensionProtocolHandler, nsISubstitutingProtocolHandler, + nsIProtocolHandler, nsISupportsWeakReference) +NS_IMPL_ADDREF_INHERITED(ExtensionProtocolHandler, SubstitutingProtocolHandler) +NS_IMPL_RELEASE_INHERITED(ExtensionProtocolHandler, SubstitutingProtocolHandler) + +} // namespace mozilla diff --git a/netwerk/protocol/res/ExtensionProtocolHandler.h b/netwerk/protocol/res/ExtensionProtocolHandler.h new file mode 100644 index 000000000000..7b022b9c7401 --- /dev/null +++ b/netwerk/protocol/res/ExtensionProtocolHandler.h @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 ExtensionProtocolHandler_h___ +#define ExtensionProtocolHandler_h___ + +#include "SubstitutingProtocolHandler.h" +#include "nsWeakReference.h" + +namespace mozilla { + +class ExtensionProtocolHandler final : public nsISubstitutingProtocolHandler, + public mozilla::SubstitutingProtocolHandler, + public nsSupportsWeakReference +{ +public: + NS_DECL_ISUPPORTS_INHERITED + NS_FORWARD_NSIPROTOCOLHANDLER(mozilla::SubstitutingProtocolHandler::) + NS_FORWARD_NSISUBSTITUTINGPROTOCOLHANDLER(mozilla::SubstitutingProtocolHandler::) + + // In general a moz-extension URI is only loadable by chrome, but a whitelisted + // subset are web-accessible (see nsIAddonPolicyService). + ExtensionProtocolHandler() + : SubstitutingProtocolHandler("moz-extension", URI_STD | URI_DANGEROUS_TO_LOAD | URI_IS_LOCAL_RESOURCE) + {} + +protected: + ~ExtensionProtocolHandler() {} +}; + +} // namespace mozilla + +#endif /* ExtensionProtocolHandler_h___ */ diff --git a/netwerk/protocol/res/moz.build b/netwerk/protocol/res/moz.build index 61771b38e008..665807f4a690 100644 --- a/netwerk/protocol/res/moz.build +++ b/netwerk/protocol/res/moz.build @@ -12,6 +12,7 @@ XPIDL_SOURCES += [ XPIDL_MODULE = 'necko_res' SOURCES += [ + 'ExtensionProtocolHandler.cpp', 'nsResProtocolHandler.cpp', 'SubstitutingProtocolHandler.cpp', ] diff --git a/toolkit/components/utils/simpleServices.js b/toolkit/components/utils/simpleServices.js index c9c3b62df495..8777da4b7f58 100644 --- a/toolkit/components/utils/simpleServices.js +++ b/toolkit/components/utils/simpleServices.js @@ -66,6 +66,21 @@ AddonPolicyService.prototype = { return cb ? cb(aURI) : false; }, + /* + * Invokes a callback (if any) to determine if an extension URI should be + * web-accessible. + * + * @see nsIAddonPolicyService.extensionURILoadableByAnyone + */ + extensionURILoadableByAnyone(aURI) { + if (aURI.scheme != "moz-extension") { + throw new TypeError("non-extension URI passed"); + } + + let cb = this.extensionURILoadCallback; + return cb ? cb(aURI) : false; + }, + /* * Sets the callbacks used in addonMayLoadURI above. Not accessible over * XPCOM - callers should use .wrappedJSObject on the service to call it @@ -74,6 +89,17 @@ AddonPolicyService.prototype = { setAddonLoadURICallback(aAddonId, aCallback) { this.mayLoadURICallbacks[aAddonId] = aCallback; }, + + /* + * Sets the callback used in extensionURILoadableByAnyone above. Not + * accessible over XPCOM - callers should use .wrappedJSObject on the + * service to call it directly. + */ + setExtensionURILoadCallback(aCallback) { + var old = this.extensionURILoadCallback; + this.extensionURILoadCallback = aCallback; + return old; + } }; this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RemoteTagServiceService, AddonPolicyService]); From 8bba083e85b6140ad6d4c490238ea4f4a0cd1e08 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Sun, 19 Jul 2015 23:06:52 -0700 Subject: [PATCH 13/96] Bug 1161831 - Forbid mapping to anything but file:// and jar:// URIs. r=billm,sr=bz --- .../protocol/res/SubstitutingProtocolHandler.cpp | 9 ++++++++- netwerk/protocol/res/SubstitutingProtocolHandler.h | 14 +++++++++++++- netwerk/protocol/res/nsResProtocolHandler.h | 3 ++- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/netwerk/protocol/res/SubstitutingProtocolHandler.cpp b/netwerk/protocol/res/SubstitutingProtocolHandler.cpp index 751e1721dcc6..9bfa1f34424e 100644 --- a/netwerk/protocol/res/SubstitutingProtocolHandler.cpp +++ b/netwerk/protocol/res/SubstitutingProtocolHandler.cpp @@ -81,10 +81,12 @@ SubstitutingURL::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc) return NS_OK; } -SubstitutingProtocolHandler::SubstitutingProtocolHandler(const char* aScheme, uint32_t aFlags) +SubstitutingProtocolHandler::SubstitutingProtocolHandler(const char* aScheme, uint32_t aFlags, + bool aEnforceFileOrJar) : mScheme(aScheme) , mFlags(aFlags) , mSubstitutions(16) + , mEnforceFileOrJar(aEnforceFileOrJar) { nsresult rv; mIOService = do_GetIOService(&rv); @@ -287,6 +289,11 @@ SubstitutingProtocolHandler::SetSubstitution(const nsACString& root, nsIURI *bas nsresult rv = baseURI->GetScheme(scheme); NS_ENSURE_SUCCESS(rv, rv); if (!scheme.Equals(mScheme)) { + if (mEnforceFileOrJar && !scheme.EqualsLiteral("file") && !scheme.EqualsLiteral("jar")) { + NS_WARNING("Refusing to create substituting URI to non-file:// target"); + return NS_ERROR_INVALID_ARG; + } + mSubstitutions.Put(root, baseURI); SendSubstitution(root, baseURI); return NS_OK; diff --git a/netwerk/protocol/res/SubstitutingProtocolHandler.h b/netwerk/protocol/res/SubstitutingProtocolHandler.h index c75436c009f1..d3180aadb3c5 100644 --- a/netwerk/protocol/res/SubstitutingProtocolHandler.h +++ b/netwerk/protocol/res/SubstitutingProtocolHandler.h @@ -26,7 +26,7 @@ namespace mozilla { class SubstitutingProtocolHandler { public: - SubstitutingProtocolHandler(const char* aScheme, uint32_t aFlags); + SubstitutingProtocolHandler(const char* aScheme, uint32_t aFlags, bool aEnforceFileOrJar = true); NS_INLINE_DECL_REFCOUNTING(SubstitutingProtocolHandler); NS_DECL_NON_VIRTUAL_NSIPROTOCOLHANDLER; @@ -54,6 +54,18 @@ private: uint32_t mFlags; nsInterfaceHashtable mSubstitutions; nsCOMPtr mIOService; + + // In general, we expect the principal of a document loaded from a + // substituting URI to be a codebase principal for that URI (rather than + // a principal for whatever is underneath). However, this only works if + // the protocol handler for the underlying URI doesn't set an explicit + // owner (which chrome:// does, for example). So we want to require that + // substituting URIs only map to other URIs of the same type, or to + // file:// and jar:// URIs. + // + // Enforcing this for ye olde resource:// URIs could carry compat risks, so + // we just try to enforce it on new protocols going forward. + bool mEnforceFileOrJar; }; // SubstitutingURL : overrides nsStandardURL::GetFile to provide nsIFile resolution diff --git a/netwerk/protocol/res/nsResProtocolHandler.h b/netwerk/protocol/res/nsResProtocolHandler.h index f125b51068df..d3e1d0d303f9 100644 --- a/netwerk/protocol/res/nsResProtocolHandler.h +++ b/netwerk/protocol/res/nsResProtocolHandler.h @@ -26,7 +26,8 @@ public: NS_FORWARD_NSISUBSTITUTINGPROTOCOLHANDLER(mozilla::SubstitutingProtocolHandler::) nsResProtocolHandler() - : SubstitutingProtocolHandler("resource", URI_STD | URI_IS_UI_RESOURCE | URI_IS_LOCAL_RESOURCE) + : SubstitutingProtocolHandler("resource", URI_STD | URI_IS_UI_RESOURCE | URI_IS_LOCAL_RESOURCE, + /* aEnforceFileOrJar = */ false) {} nsresult Init(); From 0ead8c2e5e8ec66559f8ad9752370c793b2471e7 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 20 Jul 2015 14:46:58 -0700 Subject: [PATCH 14/96] Bug 1161831 - Associate extension URIs with the appropriate addon ID. r=billm,sr=bz --- caps/nsIAddonPolicyService.idl | 7 +++++- caps/nsScriptSecurityManager.cpp | 20 ++++++++++++++++ caps/nsScriptSecurityManager.h | 3 +++ toolkit/components/utils/simpleServices.js | 28 ++++++++++++++++++++++ 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/caps/nsIAddonPolicyService.idl b/caps/nsIAddonPolicyService.idl index caad17cb32ce..7a9c1f66215e 100644 --- a/caps/nsIAddonPolicyService.idl +++ b/caps/nsIAddonPolicyService.idl @@ -11,7 +11,7 @@ * This interface allows the security manager to query custom per-addon security * policy. */ -[scriptable,uuid(3ec203f8-2bd0-4f4c-8f99-f9f056221231)] +[scriptable,uuid(8a034ef9-9d14-4c5d-8319-06c1ab574baa)] interface nsIAddonPolicyService : nsISupports { /** @@ -24,4 +24,9 @@ interface nsIAddonPolicyService : nsISupports * Returns true if a given extension:// URI is web-accessible. */ boolean extensionURILoadableByAnyone(in nsIURI aURI); + + /** + * Maps an extension URI to the ID of the addon it belongs to. + */ + AString extensionURIToAddonId(in nsIURI aURI); }; diff --git a/caps/nsScriptSecurityManager.cpp b/caps/nsScriptSecurityManager.cpp index 7ab202c36aa0..407f2c864ca6 100644 --- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -360,6 +360,20 @@ nsScriptSecurityManager::GetChannelResultPrincipal(nsIChannel* aChannel, return GetChannelURIPrincipal(aChannel, aPrincipal); } +nsresult +nsScriptSecurityManager::MaybeSetAddonIdFromURI(OriginAttributes& aAttrs, nsIURI* aURI) +{ + nsAutoCString scheme; + nsresult rv = aURI->GetScheme(scheme); + NS_ENSURE_SUCCESS(rv, rv); + if (scheme.EqualsLiteral("moz-extension") && GetAddonPolicyService()) { + rv = GetAddonPolicyService()->ExtensionURIToAddonId(aURI, aAttrs.mAddonId); + NS_ENSURE_SUCCESS(rv, rv); + } + + return NS_OK; +} + /* The principal of the URI that this channel is loading. This is never * affected by things like sandboxed loads, or loads where we forcefully * inherit the principal. Think of this as the principal of the server @@ -391,6 +405,8 @@ nsScriptSecurityManager::GetChannelURIPrincipal(nsIChannel* aChannel, } OriginAttributes attrs(UNKNOWN_APP_ID, false); + rv = MaybeSetAddonIdFromURI(attrs, uri); + NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr prin = BasePrincipal::CreateCodebasePrincipal(uri, attrs); prin.forget(aPrincipal); return *aPrincipal ? NS_OK : NS_ERROR_FAILURE; @@ -1097,6 +1113,8 @@ nsScriptSecurityManager:: OriginAttributes attrs; aLoadContext->GetAppId(&attrs.mAppId); aLoadContext->GetIsInBrowserElement(&attrs.mInBrowser); + nsresult rv = MaybeSetAddonIdFromURI(attrs, aURI); + NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr prin = BasePrincipal::CreateCodebasePrincipal(aURI, attrs); prin.forget(aPrincipal); return *aPrincipal ? NS_OK : NS_ERROR_FAILURE; @@ -1109,6 +1127,8 @@ nsScriptSecurityManager::GetDocShellCodebasePrincipal(nsIURI* aURI, { // XXXbholley - Make this more general in bug 1165466. OriginAttributes attrs(aDocShell->GetAppId(), aDocShell->GetIsInBrowserElement()); + nsresult rv = MaybeSetAddonIdFromURI(attrs, aURI); + NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr prin = BasePrincipal::CreateCodebasePrincipal(aURI, attrs); prin.forget(aPrincipal); return *aPrincipal ? NS_OK : NS_ERROR_FAILURE; diff --git a/caps/nsScriptSecurityManager.h b/caps/nsScriptSecurityManager.h index 50b9a8a410b2..15bf69f5694c 100644 --- a/caps/nsScriptSecurityManager.h +++ b/caps/nsScriptSecurityManager.h @@ -120,6 +120,9 @@ private: inline void AddSitesToFileURIWhitelist(const nsCString& aSiteList); + // If aURI is a moz-extension:// URI, set mAddonId to the associated addon. + nsresult MaybeSetAddonIdFromURI(mozilla::OriginAttributes& aAttrs, nsIURI* aURI); + nsCOMPtr mSystemPrincipal; bool mPrefInitialized; bool mIsJavaScriptEnabled; diff --git a/toolkit/components/utils/simpleServices.js b/toolkit/components/utils/simpleServices.js index 8777da4b7f58..69b727d9eced 100644 --- a/toolkit/components/utils/simpleServices.js +++ b/toolkit/components/utils/simpleServices.js @@ -81,6 +81,23 @@ AddonPolicyService.prototype = { return cb ? cb(aURI) : false; }, + /* + * Maps an extension URI to an addon ID. + * + * @see nsIAddonPolicyService.extensionURIToAddonId + */ + extensionURIToAddonId(aURI) { + if (aURI.scheme != "moz-extension") { + throw new TypeError("non-extension URI passed"); + } + + let cb = this.extensionURIToAddonIdCallback; + if (!cb) { + throw new Error("no callback set to map extension URIs to addon Ids"); + } + return cb(aURI); + }, + /* * Sets the callbacks used in addonMayLoadURI above. Not accessible over * XPCOM - callers should use .wrappedJSObject on the service to call it @@ -99,6 +116,17 @@ AddonPolicyService.prototype = { var old = this.extensionURILoadCallback; this.extensionURILoadCallback = aCallback; return old; + }, + + /* + * Sets the callback used in extensionURIToAddonId above. Not accessible over + * XPCOM - callers should use .wrappedJSObject on the service to call it + * directly. + */ + setExtensionURIToAddonIdCallback(aCallback) { + var old = this.extensionURIToAddonIdCallback; + this.extensionURIToAddonIdCallback = aCallback; + return old; } }; From 5689b3b6a62e46dc4fee4d8fc0bc62e44f8eae59 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Sun, 19 Jul 2015 19:23:55 -0700 Subject: [PATCH 15/96] Bug 1161831 - Tests. r=billm --- caps/moz.build | 5 + caps/tests/mochitest/mochitest.ini | 2 + caps/tests/mochitest/resource_test_file.html | 2 + caps/tests/mochitest/test_extensionURL.html | 144 +++++++++++++++++++ 4 files changed, 153 insertions(+) create mode 100644 caps/tests/mochitest/resource_test_file.html create mode 100644 caps/tests/mochitest/test_extensionURL.html diff --git a/caps/moz.build b/caps/moz.build index b2e4f1be80a3..7eec7036525e 100644 --- a/caps/moz.build +++ b/caps/moz.build @@ -8,6 +8,11 @@ MOCHITEST_MANIFESTS += ['tests/mochitest/mochitest.ini'] MOCHITEST_CHROME_MANIFESTS += ['tests/mochitest/chrome.ini'] XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini'] +# Hack to make this file available as a resource:// URI. +TESTING_JS_MODULES += [ + 'tests/mochitest/resource_test_file.html', +] + XPIDL_SOURCES += [ 'nsIAddonPolicyService.idl', 'nsIDomainPolicy.idl', diff --git a/caps/tests/mochitest/mochitest.ini b/caps/tests/mochitest/mochitest.ini index b6529ef5e8c7..e005135f9a5c 100644 --- a/caps/tests/mochitest/mochitest.ini +++ b/caps/tests/mochitest/mochitest.ini @@ -11,3 +11,5 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop spec [test_bug423375.html] [test_bug470804.html] [test_disallowInheritPrincipal.html] +[test_extensionURL.html] +skip-if = (os == 'android' || buildapp == 'b2g') # Bug 1185773 for android, nonsensical on b2g diff --git a/caps/tests/mochitest/resource_test_file.html b/caps/tests/mochitest/resource_test_file.html new file mode 100644 index 000000000000..8201bd70e00a --- /dev/null +++ b/caps/tests/mochitest/resource_test_file.html @@ -0,0 +1,2 @@ + +resource test file diff --git a/caps/tests/mochitest/test_extensionURL.html b/caps/tests/mochitest/test_extensionURL.html new file mode 100644 index 000000000000..6c1d7e09a0f0 --- /dev/null +++ b/caps/tests/mochitest/test_extensionURL.html @@ -0,0 +1,144 @@ + + + + + + Test for Bug 1161831 + + + + + +Mozilla Bug 1161831 +

+ +
+
+ + From 4819fcdd0fd1ac7fa3d7659f8df984a59d49aed9 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Mon, 20 Jul 2015 08:20:35 -0700 Subject: [PATCH 16/96] Bug 1185749 - Implement a DynamicTraceable HashMap subclass that can be used with Rooted; r=jonco --HG-- extra : rebase_source : ec7e634e3cc4f6a60bddc613cda346ec9d347d89 --- js/public/RootingAPI.h | 39 +++-- js/public/TraceableHashTable.h | 186 ++++++++++++++++++++++ js/src/gc/Tracer.h | 17 ++ js/src/jsapi-tests/testGCExactRooting.cpp | 78 +++++++++ js/src/moz.build | 1 + 5 files changed, 304 insertions(+), 17 deletions(-) create mode 100644 js/public/TraceableHashTable.h diff --git a/js/public/RootingAPI.h b/js/public/RootingAPI.h index 79f6c751cdc6..5cd88257d5f6 100644 --- a/js/public/RootingAPI.h +++ b/js/public/RootingAPI.h @@ -11,6 +11,7 @@ #include "mozilla/DebugOnly.h" #include "mozilla/GuardObjects.h" #include "mozilla/LinkedList.h" +#include "mozilla/Move.h" #include "mozilla/TypeTraits.h" #include "jspubtd.h" @@ -643,7 +644,7 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase /* Note: CX is a subclass of either ContextFriendFields or PerThreadDataFriendFields. */ template - void init(CX* cx) { + void registerWithRootLists(CX* cx) { js::ThingRootKind kind = js::RootKind::rootKind(); this->stack = &cx->roots.stackRoots_[kind]; this->prev = *stack; @@ -656,15 +657,16 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase : ptr(js::GCMethods::initial()) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; - init(js::ContextFriendFields::get(cx)); + registerWithRootLists(js::ContextFriendFields::get(cx)); } - Rooted(JSContext* cx, const T& initial + template + Rooted(JSContext* cx, S&& initial MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : ptr(initial) + : ptr(mozilla::Forward(initial)) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; - init(js::ContextFriendFields::get(cx)); + registerWithRootLists(js::ContextFriendFields::get(cx)); } explicit Rooted(js::ContextFriendFields* cx @@ -672,15 +674,16 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase : ptr(js::GCMethods::initial()) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; - init(cx); + registerWithRootLists(cx); } - Rooted(js::ContextFriendFields* cx, const T& initial + template + Rooted(js::ContextFriendFields* cx, S&& initial MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : ptr(initial) + : ptr(mozilla::Forward(initial)) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; - init(cx); + registerWithRootLists(cx); } explicit Rooted(js::PerThreadDataFriendFields* pt @@ -688,15 +691,16 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase : ptr(js::GCMethods::initial()) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; - init(pt); + registerWithRootLists(pt); } - Rooted(js::PerThreadDataFriendFields* pt, const T& initial + template + Rooted(js::PerThreadDataFriendFields* pt, S&& initial MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : ptr(initial) + : ptr(mozilla::Forward(initial)) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; - init(pt); + registerWithRootLists(pt); } explicit Rooted(JSRuntime* rt @@ -704,15 +708,16 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase : ptr(js::GCMethods::initial()) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; - init(js::PerThreadDataFriendFields::getMainThread(rt)); + registerWithRootLists(js::PerThreadDataFriendFields::getMainThread(rt)); } - Rooted(JSRuntime* rt, const T& initial + template + Rooted(JSRuntime* rt, S&& initial MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : ptr(initial) + : ptr(mozilla::Forward(initial)) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; - init(js::PerThreadDataFriendFields::getMainThread(rt)); + registerWithRootLists(js::PerThreadDataFriendFields::getMainThread(rt)); } ~Rooted() { diff --git a/js/public/TraceableHashTable.h b/js/public/TraceableHashTable.h new file mode 100644 index 000000000000..3d1f679cdb51 --- /dev/null +++ b/js/public/TraceableHashTable.h @@ -0,0 +1,186 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * 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 gc_HashTable_h +#define gc_HashTable_h + +#include "js/HashTable.h" +#include "js/RootingAPI.h" + +namespace js { + +template struct DefaultTracer; + +// A TraceableHashMap is a HashMap with an additional trace method that knows +// how to visit all keys and values in the table. HashMaps that contain GC +// pointers that must be traced to be kept alive will generally want to use +// this TraceableHashMap specializeation in lieu of HashMap. +// +// Most types of GC pointers as keys and values can be traced with no extra +// infrastructure. For structs and non-gc-pointer members, ensure that there +// is a specialization of DefaultTracer with an appropriate trace method +// available to handle the custom type. +// +// Note that although this HashMap's trace will deal correctly with moved keys, +// it does not itself know when to barrier or trace keys. To function properly +// it must either be used with Rooted, or barriered and traced manually. +template , + typename AllocPolicy = TempAllocPolicy, + typename KeyTraceFunc = DefaultTracer, + typename ValueTraceFunc = DefaultTracer> +class TraceableHashMap : public HashMap, + public JS::DynamicTraceable +{ + using Base = HashMap; + + public: + explicit TraceableHashMap(AllocPolicy a = AllocPolicy()) : Base(a) {} + + void trace(JSTracer* trc) override { + if (!this->initialized()) + return; + for (typename Base::Enum e(*this); !e.empty(); e.popFront()) { + ValueTraceFunc::trace(trc, &e.front().value(), "hashmap value"); + Key key = e.front().key(); + KeyTraceFunc::trace(trc, &key, "hashmap key"); + if (key != e.front().key()) + e.rekeyFront(key); + } + } + + // TraceableHashMap is movable + TraceableHashMap(TraceableHashMap&& rhs) : Base(mozilla::Forward(rhs)) {} + void operator=(TraceableHashMap&& rhs) { + MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); + Base::operator=(mozilla::Forward(rhs)); + } + + private: + // TraceableHashMap is not copyable or assignable + TraceableHashMap(const TraceableHashMap& hm) = delete; + TraceableHashMap& operator=(const TraceableHashMap& hm) = delete; +}; + +template +class TraceableHashMapOperations +{ + using Map = TraceableHashMap; + using Lookup = typename Map::Lookup; + using Ptr = typename Map::Ptr; + using AddPtr = typename Map::AddPtr; + using Range = typename Map::Range; + using Enum = typename Map::Enum; + + const Map& map() const { return static_cast(this)->extract(); } + + public: + bool initialized() const { return map().initialized(); } + Ptr lookup(const Lookup& l) const { return map().lookup(l); } + AddPtr lookupForAdd(const Lookup& l) const { return map().lookupForAdd(l); } + Range all() const { return map().all(); } + bool empty() const { return map().empty(); } + uint32_t count() const { return map().count(); } + size_t capacity() const { return map().capacity(); } + uint32_t generation() const { return map().generation(); } + bool has(const Lookup& l) const { return map().lookup(l).found(); } +}; + +template +class MutableTraceableHashMapOperations + : public TraceableHashMapOperations +{ + using Map = TraceableHashMap; + using Lookup = typename Map::Lookup; + using Ptr = typename Map::Ptr; + using AddPtr = typename Map::AddPtr; + using Range = typename Map::Range; + using Enum = typename Map::Enum; + + Map& map() { return static_cast(this)->extract(); } + + public: + bool init(uint32_t len = 16) { return map().init(len); } + void clear() { map().clear(); } + void finish() { map().finish(); } + void remove(Ptr p) { map().remove(p); } + + template + bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) { + return map().add(p, mozilla::Forward(k), mozilla::Forward(v)); + } + + template + bool add(AddPtr& p, KeyInput&& k) { + return map().add(p, mozilla::Forward(k), Map::Value()); + } + + template + bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) { + return map().relookupOrAdd(p, k, + mozilla::Forward(k), + mozilla::Forward(v)); + } + + template + bool put(KeyInput&& k, ValueInput&& v) { + return map().put(mozilla::Forward(k), mozilla::Forward(v)); + } + + template + bool putNew(KeyInput&& k, ValueInput&& v) { + return map().putNew(mozilla::Forward(k), mozilla::Forward(v)); + } +}; + +template