diff options
Diffstat (limited to '')
-rw-r--r-- | browser/components/extensions/test/xpcshell/test_ext_settings_overrides_search.js | 597 |
1 files changed, 597 insertions, 0 deletions
diff --git a/browser/components/extensions/test/xpcshell/test_ext_settings_overrides_search.js b/browser/components/extensions/test/xpcshell/test_ext_settings_overrides_search.js new file mode 100644 index 0000000000..10fed4d36b --- /dev/null +++ b/browser/components/extensions/test/xpcshell/test_ext_settings_overrides_search.js @@ -0,0 +1,597 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ + +"use strict"; + +const { AddonTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/AddonTestUtils.sys.mjs" +); +const { setTimeout } = ChromeUtils.importESModule( + "resource://gre/modules/Timer.sys.mjs" +); + +let delay = () => new Promise(resolve => setTimeout(resolve, 0)); + +const kSearchFormURL = "https://example.com/searchform"; +const kSearchEngineURL = "https://example.com/?search={searchTerms}"; +const kSearchSuggestURL = "https://example.com/?suggest={searchTerms}"; +const kSearchTerm = "foo"; +const kSearchTermIntl = "日"; +const URLTYPE_SUGGEST_JSON = "application/x-suggestions+json"; + +AddonTestUtils.init(this); +AddonTestUtils.createAppInfo( + "xpcshell@tests.mozilla.org", + "XPCShell", + "42", + "42" +); + +add_task(async function setup() { + await AddonTestUtils.promiseStartupManager(); + await Services.search.init(); +}); + +add_task(async function test_extension_adding_engine() { + let ext1 = ExtensionTestUtils.loadExtension({ + manifest: { + icons: { + 16: "foo.ico", + 32: "foo32.ico", + }, + chrome_settings_overrides: { + search_provider: { + name: "MozSearch", + keyword: "MozSearch", + search_form: kSearchFormURL, + search_url: kSearchEngineURL, + suggest_url: kSearchSuggestURL, + }, + }, + }, + useAddonManager: "temporary", + }); + + await ext1.startup(); + await AddonTestUtils.waitForSearchProviderStartup(ext1); + + let engine = Services.search.getEngineByName("MozSearch"); + ok(engine, "Engine should exist."); + + let { baseURI } = ext1.extension; + equal( + engine.getIconURL(), + baseURI.resolve("foo.ico"), + "16x16 icon path matches" + ); + equal( + engine.getIconURL(16), + baseURI.resolve("foo.ico"), + "16x16 icon path matches" + ); + // TODO: Bug 1871036 - Differently sized icons are currently incorrectly + // handled for add-ons. + // equal( + // engine.getIconURL(32), + // baseURI.resolve("foo32.ico"), + // "32x32 icon path matches" + // ); + + let expectedSuggestURL = kSearchSuggestURL.replace( + "{searchTerms}", + kSearchTerm + ); + let submissionSuggest = engine.getSubmission( + kSearchTerm, + URLTYPE_SUGGEST_JSON + ); + let encodedSubmissionURL = engine.getSubmission(kSearchTermIntl).uri.spec; + let testSubmissionURL = kSearchEngineURL.replace( + "{searchTerms}", + encodeURIComponent(kSearchTermIntl) + ); + equal( + encodedSubmissionURL, + testSubmissionURL, + "Encoded UTF-8 URLs should match" + ); + + equal( + submissionSuggest.uri.spec, + expectedSuggestURL, + "Suggest URLs should match" + ); + + equal(engine.searchForm, kSearchFormURL, "Search form URLs should match"); + await ext1.unload(); + await delay(); + + engine = Services.search.getEngineByName("MozSearch"); + ok(!engine, "Engine should not exist"); +}); + +add_task(async function test_extension_adding_engine_with_spaces() { + let ext1 = ExtensionTestUtils.loadExtension({ + manifest: { + chrome_settings_overrides: { + search_provider: { + name: "MozSearch ", + keyword: "MozSearch", + search_url: "https://example.com/?q={searchTerms}", + }, + }, + }, + useAddonManager: "temporary", + }); + + await ext1.startup(); + await AddonTestUtils.waitForSearchProviderStartup(ext1); + + let engine = Services.search.getEngineByName("MozSearch"); + ok(engine, "Engine should exist."); + + await ext1.unload(); + await delay(); + + engine = Services.search.getEngineByName("MozSearch"); + ok(!engine, "Engine should not exist"); +}); + +add_task(async function test_upgrade_default_position_engine() { + let ext1 = ExtensionTestUtils.loadExtension({ + manifest: { + chrome_settings_overrides: { + search_provider: { + name: "MozSearch", + keyword: "MozSearch", + search_url: "https://example.com/?q={searchTerms}", + }, + }, + browser_specific_settings: { + gecko: { + id: "testengine@mozilla.com", + }, + }, + version: "0.1", + }, + useAddonManager: "temporary", + }); + + await ext1.startup(); + await AddonTestUtils.waitForSearchProviderStartup(ext1); + + let engine = Services.search.getEngineByName("MozSearch"); + await Services.search.setDefault( + engine, + Ci.nsISearchService.CHANGE_REASON_UNKNOWN + ); + await Services.search.moveEngine(engine, 1); + + await ext1.upgrade({ + manifest: { + chrome_settings_overrides: { + search_provider: { + name: "MozSearch", + keyword: "MozSearch", + search_url: "https://example.com/?q={searchTerms}", + }, + }, + browser_specific_settings: { + gecko: { + id: "testengine@mozilla.com", + }, + }, + version: "0.2", + }, + useAddonManager: "temporary", + }); + await AddonTestUtils.waitForSearchProviderStartup(ext1); + + engine = Services.search.getEngineByName("MozSearch"); + equal( + Services.search.defaultEngine, + engine, + "Default engine should still be MozSearch" + ); + equal( + (await Services.search.getEngines()).map(e => e.name).indexOf(engine.name), + 1, + "Engine is in position 1" + ); + + await ext1.unload(); + await delay(); + + engine = Services.search.getEngineByName("MozSearch"); + ok(!engine, "Engine should not exist"); +}); + +add_task(async function test_extension_get_params() { + let ext1 = ExtensionTestUtils.loadExtension({ + manifest: { + chrome_settings_overrides: { + search_provider: { + name: "MozSearch", + keyword: "MozSearch", + search_url: kSearchEngineURL, + search_url_get_params: "foo=bar&bar=foo", + suggest_url: kSearchSuggestURL, + suggest_url_get_params: "foo=bar&bar=foo", + }, + }, + }, + useAddonManager: "temporary", + }); + + await ext1.startup(); + await AddonTestUtils.waitForSearchProviderStartup(ext1); + + let engine = Services.search.getEngineByName("MozSearch"); + ok(engine, "Engine should exist."); + + let url = engine.wrappedJSObject._getURLOfType("text/html"); + equal(url.method, "GET", "Search URLs method is GET"); + + let expectedURL = kSearchEngineURL.replace("{searchTerms}", kSearchTerm); + let submission = engine.getSubmission(kSearchTerm); + equal( + submission.uri.spec, + `${expectedURL}&foo=bar&bar=foo`, + "Search URLs should match" + ); + + let expectedSuggestURL = kSearchSuggestURL.replace( + "{searchTerms}", + kSearchTerm + ); + let submissionSuggest = engine.getSubmission( + kSearchTerm, + URLTYPE_SUGGEST_JSON + ); + equal( + submissionSuggest.uri.spec, + `${expectedSuggestURL}&foo=bar&bar=foo`, + "Suggest URLs should match" + ); + + await ext1.unload(); +}); + +add_task(async function test_extension_post_params() { + let ext1 = ExtensionTestUtils.loadExtension({ + manifest: { + chrome_settings_overrides: { + search_provider: { + name: "MozSearch", + keyword: "MozSearch", + search_url: kSearchEngineURL, + search_url_post_params: "foo=bar&bar=foo", + suggest_url: kSearchSuggestURL, + suggest_url_post_params: "foo=bar&bar=foo", + }, + }, + }, + useAddonManager: "temporary", + }); + + await ext1.startup(); + await AddonTestUtils.waitForSearchProviderStartup(ext1); + + let engine = Services.search.getEngineByName("MozSearch"); + ok(engine, "Engine should exist."); + + let url = engine.wrappedJSObject._getURLOfType("text/html"); + equal(url.method, "POST", "Search URLs method is POST"); + + let expectedURL = kSearchEngineURL.replace("{searchTerms}", kSearchTerm); + let submission = engine.getSubmission(kSearchTerm); + equal(submission.uri.spec, expectedURL, "Search URLs should match"); + // postData is a nsIMIMEInputStream which contains a nsIStringInputStream. + equal( + submission.postData.data.data, + "foo=bar&bar=foo", + "Search postData should match" + ); + + let expectedSuggestURL = kSearchSuggestURL.replace( + "{searchTerms}", + kSearchTerm + ); + let submissionSuggest = engine.getSubmission( + kSearchTerm, + URLTYPE_SUGGEST_JSON + ); + equal( + submissionSuggest.uri.spec, + expectedSuggestURL, + "Suggest URLs should match" + ); + equal( + submissionSuggest.postData.data.data, + "foo=bar&bar=foo", + "Suggest postData should match" + ); + + await ext1.unload(); +}); + +add_task(async function test_extension_no_query_params() { + const ext1 = ExtensionTestUtils.loadExtension({ + manifest: { + chrome_settings_overrides: { + search_provider: { + name: "MozSearch", + keyword: "MozSearch", + search_url: "https://example.com/{searchTerms}", + suggest_url: "https://example.com/suggest/{searchTerms}", + }, + }, + }, + useAddonManager: "temporary", + }); + + await ext1.startup(); + await AddonTestUtils.waitForSearchProviderStartup(ext1); + + let engine = Services.search.getEngineByName("MozSearch"); + ok(engine, "Engine should exist."); + + const encodedSubmissionURL = engine.getSubmission(kSearchTermIntl).uri.spec; + const testSubmissionURL = + "https://example.com/" + encodeURIComponent(kSearchTermIntl); + equal( + encodedSubmissionURL, + testSubmissionURL, + "Encoded UTF-8 URLs should match" + ); + + const expectedSuggestURL = "https://example.com/suggest/" + kSearchTerm; + let submissionSuggest = engine.getSubmission( + kSearchTerm, + URLTYPE_SUGGEST_JSON + ); + equal( + submissionSuggest.uri.spec, + expectedSuggestURL, + "Suggest URLs should match" + ); + + await ext1.unload(); + await delay(); + + engine = Services.search.getEngineByName("MozSearch"); + ok(!engine, "Engine should not exist"); +}); + +add_task(async function test_extension_empty_suggestUrl() { + let ext1 = ExtensionTestUtils.loadExtension({ + manifest: { + default_locale: "en", + chrome_settings_overrides: { + search_provider: { + name: "MozSearch", + keyword: "MozSearch", + search_url: kSearchEngineURL, + search_url_post_params: "foo=bar&bar=foo", + suggest_url: "__MSG_suggestUrl__", + suggest_url_get_params: "__MSG_suggestUrlGetParams__", + }, + }, + }, + useAddonManager: "temporary", + files: { + "_locales/en/messages.json": { + suggestUrl: { + message: "", + }, + suggestUrlGetParams: { + message: "", + }, + }, + }, + }); + + await ext1.startup(); + await AddonTestUtils.waitForSearchProviderStartup(ext1); + + let engine = Services.search.getEngineByName("MozSearch"); + ok(engine, "Engine should exist."); + + let url = engine.wrappedJSObject._getURLOfType("text/html"); + equal(url.method, "POST", "Search URLs method is POST"); + + let expectedURL = kSearchEngineURL.replace("{searchTerms}", kSearchTerm); + let submission = engine.getSubmission(kSearchTerm); + equal(submission.uri.spec, expectedURL, "Search URLs should match"); + // postData is a nsIMIMEInputStream which contains a nsIStringInputStream. + equal( + submission.postData.data.data, + "foo=bar&bar=foo", + "Search postData should match" + ); + + let submissionSuggest = engine.getSubmission( + kSearchTerm, + URLTYPE_SUGGEST_JSON + ); + ok(!submissionSuggest, "There should be no suggest URL."); + + await ext1.unload(); +}); + +add_task(async function test_extension_empty_suggestUrl_with_params() { + let ext1 = ExtensionTestUtils.loadExtension({ + manifest: { + default_locale: "en", + chrome_settings_overrides: { + search_provider: { + name: "MozSearch", + keyword: "MozSearch", + search_url: kSearchEngineURL, + search_url_post_params: "foo=bar&bar=foo", + suggest_url: "__MSG_suggestUrl__", + suggest_url_get_params: "__MSG_suggestUrlGetParams__", + }, + }, + }, + useAddonManager: "temporary", + files: { + "_locales/en/messages.json": { + suggestUrl: { + message: "", + }, + suggestUrlGetParams: { + message: "abc", + }, + }, + }, + }); + + await ext1.startup(); + await AddonTestUtils.waitForSearchProviderStartup(ext1); + + let engine = Services.search.getEngineByName("MozSearch"); + ok(engine, "Engine should exist."); + + let url = engine.wrappedJSObject._getURLOfType("text/html"); + equal(url.method, "POST", "Search URLs method is POST"); + + let expectedURL = kSearchEngineURL.replace("{searchTerms}", kSearchTerm); + let submission = engine.getSubmission(kSearchTerm); + equal(submission.uri.spec, expectedURL, "Search URLs should match"); + // postData is a nsIMIMEInputStream which contains a nsIStringInputStream. + equal( + submission.postData.data.data, + "foo=bar&bar=foo", + "Search postData should match" + ); + + let submissionSuggest = engine.getSubmission( + kSearchTerm, + URLTYPE_SUGGEST_JSON + ); + ok(!submissionSuggest, "There should be no suggest URL."); + + await ext1.unload(); +}); + +async function checkBadUrl(searchProviderKey, urlValue) { + let normalized = await ExtensionTestUtils.normalizeManifest({ + chrome_settings_overrides: { + search_provider: { + name: "MozSearch", + keyword: "MozSearch", + search_url: "https://example.com/", + [searchProviderKey]: urlValue, + }, + }, + }); + + ok( + /Error processing chrome_settings_overrides\.search_provider[^:]*: .* must match/.test( + normalized.error + ), + `Expected error for ${searchProviderKey}:${urlValue} "${normalized.error}"` + ); +} + +async function checkValidUrl(urlValue) { + let normalized = await ExtensionTestUtils.normalizeManifest({ + chrome_settings_overrides: { + search_provider: { + name: "MozSearch", + keyword: "MozSearch", + search_form: urlValue, + search_url: urlValue, + suggest_url: urlValue, + }, + }, + }); + equal(normalized.error, undefined, `Valid search_provider url: ${urlValue}`); +} + +add_task(async function test_extension_not_allow_http() { + await checkBadUrl("search_form", "http://example.com/{searchTerms}"); + await checkBadUrl("search_url", "http://example.com/{searchTerms}"); + await checkBadUrl("suggest_url", "http://example.com/{searchTerms}"); +}); + +add_task(async function test_manifest_disallows_http_localhost_prefix() { + await checkBadUrl("search_url", "http://localhost.example.com"); + await checkBadUrl("search_url", "http://localhost.example.com/"); + await checkBadUrl("search_url", "http://127.0.0.1.example.com/"); + await checkBadUrl("search_url", "http://localhost:1234@example.com/"); +}); + +add_task(async function test_manifest_allow_http_for_localhost() { + await checkValidUrl("http://localhost"); + await checkValidUrl("http://localhost/"); + await checkValidUrl("http://localhost:/"); + await checkValidUrl("http://localhost:1/"); + await checkValidUrl("http://localhost:65535/"); + + await checkValidUrl("http://127.0.0.1"); + await checkValidUrl("http://127.0.0.1:"); + await checkValidUrl("http://127.0.0.1:/"); + await checkValidUrl("http://127.0.0.1/"); + await checkValidUrl("http://127.0.0.1:80/"); + + await checkValidUrl("http://[::1]"); + await checkValidUrl("http://[::1]:"); + await checkValidUrl("http://[::1]:/"); + await checkValidUrl("http://[::1]/"); + await checkValidUrl("http://[::1]:80/"); +}); + +add_task(async function test_extension_allow_http_for_localhost() { + let ext1 = ExtensionTestUtils.loadExtension({ + manifest: { + chrome_settings_overrides: { + search_provider: { + name: "MozSearch", + keyword: "MozSearch", + search_url: "http://localhost/{searchTerms}", + suggest_url: "http://localhost/suggest/{searchTerms}", + }, + }, + }, + useAddonManager: "temporary", + }); + + await ext1.startup(); + await AddonTestUtils.waitForSearchProviderStartup(ext1); + + let engine = Services.search.getEngineByName("MozSearch"); + ok(engine, "Engine should exist."); + + await ext1.unload(); +}); + +add_task(async function test_search_favicon_mv3() { + Services.prefs.setBoolPref("extensions.manifestV3.enabled", true); + let normalized = await ExtensionTestUtils.normalizeManifest({ + manifest_version: 3, + chrome_settings_overrides: { + search_provider: { + name: "HTTP Icon in MV3", + search_url: "https://example.org/", + favicon_url: "https://example.org/icon.png", + }, + }, + }); + Assert.ok( + normalized.error.endsWith("must be a relative URL"), + "Should have an error" + ); + normalized = await ExtensionTestUtils.normalizeManifest({ + manifest_version: 3, + chrome_settings_overrides: { + search_provider: { + name: "HTTP Icon in MV3", + search_url: "https://example.org/", + favicon_url: "/icon.png", + }, + }, + }); + Assert.ok(!normalized.error, "Should not have an error"); +}); |