Bug 1469889 - Allow blacklisting search engines based on URL. r?florian
MozReview-Commit-ID: IGL6JJGcyXa
--- a/toolkit/components/search/nsSearchService.js
+++ b/toolkit/components/search/nsSearchService.js
@@ -2867,34 +2867,38 @@ SearchService.prototype = {
let buildID = Services.appinfo.platformBuildID;
let rebuildCache = !cache.engines ||
cache.version != CACHE_VERSION ||
cache.locale != getLocale() ||
cache.buildID != buildID ||
cache.visibleDefaultEngines.length != this._visibleDefaultEngines.length ||
this._visibleDefaultEngines.some(notInCacheVisibleEngines);
- if (rebuildCache) {
- LOG("_loadEngines: Absent or outdated cache. Loading engines from disk.");
- distDirs.forEach(this._loadEnginesFromDir, this);
-
- this._loadFromChromeURLs(chromeURIs);
-
- LOG("_loadEngines: load user-installed engines from the obsolete cache");
- this._loadEnginesFromCache(cache, true);
-
- this._loadEnginesMetadataFromCache(cache);
- this._buildCache();
- return;
+ if (!rebuildCache) {
+ LOG("_loadEngines: loading from cache directories");
+ this._loadEnginesFromCache(cache);
+ if (Object.keys(this._engines).length) {
+ LOG("_loadEngines: done using existing cache");
+ return;
+ }
+ LOG("_loadEngines: No valid engines found in cache. Loading engines from disk.");
}
- LOG("_loadEngines: loading from cache directories");
- this._loadEnginesFromCache(cache);
-
- LOG("_loadEngines: done");
+ LOG("_loadEngines: Absent or outdated cache. Loading engines from disk.");
+ distDirs.forEach(this._loadEnginesFromDir, this);
+
+ this._loadFromChromeURLs(chromeURIs);
+
+ LOG("_loadEngines: load user-installed engines from the obsolete cache");
+ this._loadEnginesFromCache(cache, true);
+
+ this._loadEnginesMetadataFromCache(cache);
+ this._buildCache();
+
+ LOG("_loadEngines: done using rebuilt cache");
},
/**
* Loads engines asynchronously.
*
* @returns {Promise} A promise, resolved successfully if loading data
* succeeds.
*/
@@ -2937,39 +2941,43 @@ SearchService.prototype = {
let buildID = Services.appinfo.platformBuildID;
let rebuildCache = !cache.engines ||
cache.version != CACHE_VERSION ||
cache.locale != getLocale() ||
cache.buildID != buildID ||
cache.visibleDefaultEngines.length != this._visibleDefaultEngines.length ||
this._visibleDefaultEngines.some(notInCacheVisibleEngines);
- if (rebuildCache) {
- LOG("_asyncLoadEngines: Absent or outdated cache. Loading engines from disk.");
- for (let loadDir of distDirs) {
- let enginesFromDir =
- await checkForSyncCompletion(this._asyncLoadEnginesFromDir(loadDir));
- enginesFromDir.forEach(this._addEngineToStore, this);
+ if (!rebuildCache) {
+ LOG("_asyncLoadEngines: loading from cache directories");
+ this._loadEnginesFromCache(cache);
+ if (Object.keys(this._engines).length) {
+ LOG("_asyncLoadEngines: done using existing cache");
+ return;
}
- let enginesFromURLs =
- await checkForSyncCompletion(this._asyncLoadFromChromeURLs(chromeURIs));
- enginesFromURLs.forEach(this._addEngineToStore, this);
-
- LOG("_asyncLoadEngines: loading user-installed engines from the obsolete cache");
- this._loadEnginesFromCache(cache, true);
-
- this._loadEnginesMetadataFromCache(cache);
- this._buildCache();
- return;
+ LOG("_asyncLoadEngines: No valid engines found in cache. Loading engines from disk.");
+ }
+
+ LOG("_asyncLoadEngines: Absent or outdated cache. Loading engines from disk.");
+ for (let loadDir of distDirs) {
+ let enginesFromDir =
+ await checkForSyncCompletion(this._asyncLoadEnginesFromDir(loadDir));
+ enginesFromDir.forEach(this._addEngineToStore, this);
}
-
- LOG("_asyncLoadEngines: loading from cache directories");
- this._loadEnginesFromCache(cache);
-
- LOG("_asyncLoadEngines: done");
+ let enginesFromURLs =
+ await checkForSyncCompletion(this._asyncLoadFromChromeURLs(chromeURIs));
+ enginesFromURLs.forEach(this._addEngineToStore, this);
+
+ LOG("_asyncLoadEngines: loading user-installed engines from the obsolete cache");
+ this._loadEnginesFromCache(cache, true);
+
+ this._loadEnginesMetadataFromCache(cache);
+ this._buildCache();
+
+ LOG("_asyncLoadEngines: done using rebuilt cache");
},
_asyncReInit() {
LOG("_asyncReInit");
// Start by clearing the initialized state, so we don't abort early.
gInitialized = false;
(async () => {
@@ -3102,17 +3110,27 @@ SearchService.prototype = {
LOG("batchTask: Invalidating engine cache");
this._buildCache();
};
this._batchTask = new DeferredTask(task, CACHE_INVALIDATION_DELAY);
}
return this._batchTask;
},
+ _blackList: [
+ "blacklist=true",
+ ],
+
_addEngineToStore: function SRCH_SVC_addEngineToStore(aEngine) {
+ let url = aEngine._getURLOfType("text/html").getSubmission("dummy", aEngine).uri.spec;
+ if (this._blackList.some(code => url.includes(code))) {
+ LOG("_addEngineToStore: Ignoring blacklisted engine");
+ return;
+ }
+
LOG("_addEngineToStore: Adding engine: \"" + aEngine.name + "\"");
// See if there is an existing engine with the same name. However, if this
// engine is updating another engine, it's allowed to have the same name.
var hasSameNameAsUpdate = (aEngine._engineToUpdate &&
aEngine.name == aEngine._engineToUpdate.name);
if (aEngine.name in this._engines && !hasSameNameAsUpdate) {
LOG("_addEngineToStore: Duplicate engine found, aborting!");
new file mode 100644
--- /dev/null
+++ b/toolkit/components/search/tests/xpcshell/data/search_blacklist.json
@@ -0,0 +1,90 @@
+{
+ "version": 1,
+ "buildID": "20121106",
+ "locale": "en-US",
+ "metaData": {},
+ "engines": [
+ {
+ "_name": "Test search engine",
+ "_shortName": "test-search-engine",
+ "description": "A test search engine (based on Google search)",
+ "extensionID": "test-addon-id@mozilla.org",
+ "__searchForm": "http://www.google.com/",
+ "_iconURL": "data:image/png;base64,AAABAAEAEBAAAAEAGABoAwAAFgAAACgAAAAQAAAAIAAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADs9Pt8xetPtu9FsfFNtu%2BTzvb2%2B%2Fne4dFJeBw0egA%2FfAJAfAA8ewBBegAAAAD%2B%2FPtft98Mp%2BwWsfAVsvEbs%2FQeqvF8xO7%2F%2F%2F63yqkxdgM7gwE%2FggM%2BfQA%2BegBDeQDe7PIbotgQufcMufEPtfIPsvAbs%2FQvq%2Bfz%2Bf%2F%2B%2B%2FZKhR05hgBBhQI8hgBAgAI9ewD0%2B%2Fg3pswAtO8Cxf4Kw%2FsJvvYAqupKsNv%2B%2Fv7%2F%2FP5VkSU0iQA7jQA9hgBDgQU%2BfQH%2F%2Ff%2FQ6fM4sM4KsN8AteMCruIqqdbZ7PH8%2Fv%2Fg6Nc%2Fhg05kAA8jAM9iQI%2BhQA%2BgQDQu6b97uv%2F%2F%2F7V8Pqw3eiWz97q8%2Ff%2F%2F%2F%2F7%2FPptpkkqjQE4kwA7kAA5iwI8iAA8hQCOSSKdXjiyflbAkG7u2s%2F%2B%2F%2F39%2F%2F7r8utrqEYtjQE8lgA7kwA7kwA9jwA9igA9hACiWSekVRyeSgiYSBHx6N%2F%2B%2Fv7k7OFRmiYtlAA5lwI7lwI4lAA7kgI9jwE9iwI4iQCoVhWcTxCmb0K%2BooT8%2Fv%2F7%2F%2F%2FJ2r8fdwI1mwA3mQA3mgA8lAE8lAE4jwA9iwE%2BhwGfXifWvqz%2B%2Ff%2F58u%2Fev6Dt4tr%2B%2F%2F2ZuIUsggA7mgM6mAM3lgA5lgA6kQE%2FkwBChwHt4dv%2F%2F%2F728ei1bCi7VAC5XQ7kz7n%2F%2F%2F6bsZkgcB03lQA9lgM7kwA2iQktZToPK4r9%2F%2F%2F9%2F%2F%2FSqYK5UwDKZAS9WALIkFn%2B%2F%2F3%2F%2BP8oKccGGcIRJrERILYFEMwAAuEAAdX%2F%2Ff7%2F%2FP%2B%2BfDvGXQLIZgLEWgLOjlf7%2F%2F%2F%2F%2F%2F9QU90EAPQAAf8DAP0AAfMAAOUDAtr%2F%2F%2F%2F7%2B%2Fu2bCTIYwDPZgDBWQDSr4P%2F%2Fv%2F%2F%2FP5GRuABAPkAA%2FwBAfkDAPAAAesAAN%2F%2F%2B%2Fz%2F%2F%2F64g1C5VwDMYwK8Yg7y5tz8%2Fv%2FV1PYKDOcAAP0DAf4AAf0AAfYEAOwAAuAAAAD%2F%2FPvi28ymXyChTATRrIb8%2F%2F3v8fk6P8MAAdUCAvoAAP0CAP0AAfYAAO4AAACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAA",
+ "_metaData": {},
+ "_urls": [
+ {
+ "template": "http://suggestqueries.google.com/complete/search?output=firefox&client=firefox&hl={moz:locale}&q={searchTerms}",
+ "rels": [
+ ],
+ "type": "application/x-suggestions+json",
+ "params": [
+ ]
+ },
+ {
+ "template": "http://www.google.com/search",
+ "resultDomain": "google.com",
+ "rels": [
+ ],
+ "params": [
+ {
+ "name": "q",
+ "value": "{searchTerms}"
+ },
+ {
+ "name": "ie",
+ "value": "utf-8"
+ },
+ {
+ "name": "oe",
+ "value": "utf-8"
+ },
+ {
+ "name": "aq",
+ "value": "t"
+ },
+ {
+ "name": "blacklist",
+ "value": "true"
+ },
+ {
+ "name": "channel",
+ "value": "fflb",
+ "purpose": "keyword"
+ },
+ {
+ "name": "channel",
+ "value": "rcs",
+ "purpose": "contextmenu"
+ }
+ ]
+ },
+ {
+ "template": "http://www.google.com/search",
+ "resultDomain": "purpose.google.com",
+ "rels": [
+ ],
+ "type": "application/x-moz-default-purpose",
+ "params": [
+ {
+ "name": "q",
+ "value": "{searchTerms}"
+ },
+ {
+ "name": "channel",
+ "value": "fflb",
+ "purpose": "keyword"
+ },
+ {
+ "name": "channel",
+ "value": "rcs",
+ "purpose": "contextmenu"
+ }
+ ]
+ }
+ ],
+ "queryCharset": "UTF-8",
+ "_readOnly": false
+ }
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/components/search/tests/xpcshell/test_blacklist.js
@@ -0,0 +1,20 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const kSearchEngineID = "blacklist_test_engine";
+const kSearchEngineURL = "http://example.com/?search={searchTerms}&blacklist=true";
+
+add_task(async function test_blacklistEngine() {
+ Assert.ok(!Services.search.isInitialized);
+
+ await asyncInit();
+
+ Services.search.addEngineWithDetails(kSearchEngineID, "", "", "", "get",
+ kSearchEngineURL);
+
+ // A blacklisted engine shouldn't be available at all
+ let engine = Services.search.getEngineByName(kSearchEngineID);
+ Assert.equal(engine, null, "Engine should not exist");
+});
new file mode 100644
--- /dev/null
+++ b/toolkit/components/search/tests/xpcshell/test_json_cache_blacklist.js
@@ -0,0 +1,59 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/*
+ * Test initializing from the search cache.
+ */
+
+"use strict";
+
+var cacheTemplate, appPluginsPath, profPlugins;
+
+/**
+ * Test reading from search.json.mozlz4
+ */
+function run_test() {
+ let cacheTemplateFile = do_get_file("data/search_blacklist.json");
+ cacheTemplate = readJSONFile(cacheTemplateFile);
+ cacheTemplate.buildID = getAppInfo().platformBuildID;
+
+ let engineFile = gProfD.clone();
+ engineFile.append("searchplugins");
+ engineFile.append("test-search-engine.xml");
+ engineFile.parent.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
+
+ // Copy the test engine to the test profile.
+ let engineTemplateFile = do_get_file("data/engine.xml");
+ engineTemplateFile.copyTo(engineFile.parent, "test-search-engine.xml");
+
+ // The list of visibleDefaultEngines needs to match or the cache will be ignored.
+ cacheTemplate.visibleDefaultEngines = getDefaultEngineList(false);
+
+ run_next_test();
+}
+
+add_test(function prepare_test_data() {
+ promiseSaveCacheData(cacheTemplate).then(run_next_test);
+});
+
+/**
+ * Start the search service and confirm the cache was reset
+ */
+add_test(function test_cache_rest() {
+ info("init search service");
+
+ Services.search.init(function initComplete(aResult) {
+ info("init'd search service");
+ Assert.ok(Components.isSuccessCode(aResult));
+
+ let engines = Services.search.getEngines({});
+
+ // Engine list will have been reset to the default,
+ // Not the one engine in the cache.
+ // It should have more than one engine.
+ Assert.ok(engines.length > 1);
+
+ removeCacheFile();
+ run_next_test();
+ });
+});
--- a/toolkit/components/search/tests/xpcshell/xpcshell.ini
+++ b/toolkit/components/search/tests/xpcshell/xpcshell.ini
@@ -26,25 +26,28 @@ support-files =
data/list.json
data/search.json
data/searchSuggestions.sjs
data/searchTest.jar
[test_nocache.js]
[test_645970.js]
[test_big_icon.js]
+[test_blacklist.js]
[test_bug930456.js]
[test_bug930456_child.js]
[test_engine_set_alias.js]
[test_hasEngineWithURL.js]
[test_identifiers.js]
[test_invalid_engine_from_dir.js]
[test_init_async_multiple.js]
[test_init_async_multiple_then_sync.js]
[test_json_cache.js]
+[test_json_cache_blacklist.js]
+support-files = data/search_blacklist.json
[test_list_json_locale.js]
[test_list_json_searchdefault.js]
[test_list_json_searchdefault_distro.js]
[test_list_json_searchorder.js]
[test_location.js]
[test_location_error.js]
[test_location_malformed_json.js]
[test_location_partner.js]