test_ext_settings_overrides_search.js (16349B)
1 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ 2 /* vim: set sts=2 sw=2 et tw=80: */ 3 4 "use strict"; 5 6 const { AddonTestUtils } = ChromeUtils.importESModule( 7 "resource://testing-common/AddonTestUtils.sys.mjs" 8 ); 9 const { setTimeout } = ChromeUtils.importESModule( 10 "resource://gre/modules/Timer.sys.mjs" 11 ); 12 13 let delay = () => new Promise(resolve => setTimeout(resolve, 0)); 14 15 const kSearchEngineURL = "https://example.com/?search={searchTerms}"; 16 const kSearchSuggestURL = "https://example.com/?suggest={searchTerms}"; 17 const kSearchTerm = "foo"; 18 const kSearchTermIntl = "日"; 19 const URLTYPE_SUGGEST_JSON = "application/x-suggestions+json"; 20 21 AddonTestUtils.init(this); 22 AddonTestUtils.createAppInfo( 23 "xpcshell@tests.mozilla.org", 24 "XPCShell", 25 "42", 26 "42" 27 ); 28 29 add_task(async function setup() { 30 await AddonTestUtils.promiseStartupManager(); 31 await Services.search.init(); 32 }); 33 34 add_task(async function test_extension_adding_engine() { 35 let ext1 = ExtensionTestUtils.loadExtension({ 36 manifest: { 37 icons: { 38 16: "foo.ico", 39 32: "foo32.ico", 40 }, 41 chrome_settings_overrides: { 42 search_provider: { 43 name: "MozSearch", 44 keyword: "MozSearch", 45 search_url: kSearchEngineURL, 46 suggest_url: kSearchSuggestURL, 47 }, 48 }, 49 }, 50 useAddonManager: "temporary", 51 }); 52 53 await ext1.startup(); 54 await AddonTestUtils.waitForSearchProviderStartup(ext1); 55 56 let engine = Services.search.getEngineByName("MozSearch"); 57 ok(engine, "Engine should exist."); 58 59 let { baseURI } = ext1.extension; 60 equal( 61 await engine.getIconURL(), 62 baseURI.resolve("foo.ico"), 63 "16x16 icon path matches" 64 ); 65 equal( 66 await engine.getIconURL(16), 67 baseURI.resolve("foo.ico"), 68 "16x16 icon path matches" 69 ); 70 71 equal( 72 await engine.getIconURL(32), 73 baseURI.resolve("foo32.ico"), 74 "32x32 icon path matches" 75 ); 76 77 let expectedSuggestURL = kSearchSuggestURL.replace( 78 "{searchTerms}", 79 kSearchTerm 80 ); 81 let submissionSuggest = engine.getSubmission( 82 kSearchTerm, 83 URLTYPE_SUGGEST_JSON 84 ); 85 let encodedSubmissionURL = engine.getSubmission(kSearchTermIntl).uri.spec; 86 let testSubmissionURL = kSearchEngineURL.replace( 87 "{searchTerms}", 88 encodeURIComponent(kSearchTermIntl) 89 ); 90 equal( 91 encodedSubmissionURL, 92 testSubmissionURL, 93 "Encoded UTF-8 URLs should match" 94 ); 95 96 equal( 97 submissionSuggest.uri.spec, 98 expectedSuggestURL, 99 "Suggest URLs should match" 100 ); 101 102 await ext1.unload(); 103 await delay(); 104 105 engine = Services.search.getEngineByName("MozSearch"); 106 ok(!engine, "Engine should not exist"); 107 }); 108 109 add_task(async function test_extension_adding_engine_with_spaces() { 110 let ext1 = ExtensionTestUtils.loadExtension({ 111 manifest: { 112 chrome_settings_overrides: { 113 search_provider: { 114 name: "MozSearch ", 115 keyword: "MozSearch", 116 search_url: "https://example.com/?q={searchTerms}", 117 }, 118 }, 119 }, 120 useAddonManager: "temporary", 121 }); 122 123 await ext1.startup(); 124 await AddonTestUtils.waitForSearchProviderStartup(ext1); 125 126 let engine = Services.search.getEngineByName("MozSearch"); 127 ok(engine, "Engine should exist."); 128 129 await ext1.unload(); 130 await delay(); 131 132 engine = Services.search.getEngineByName("MozSearch"); 133 ok(!engine, "Engine should not exist"); 134 }); 135 136 add_task(async function test_upgrade_default_position_engine() { 137 let ext1 = ExtensionTestUtils.loadExtension({ 138 manifest: { 139 chrome_settings_overrides: { 140 search_provider: { 141 name: "MozSearch", 142 keyword: "MozSearch", 143 search_url: "https://example.com/?q={searchTerms}", 144 }, 145 }, 146 browser_specific_settings: { 147 gecko: { 148 id: "testengine@mozilla.com", 149 }, 150 }, 151 version: "0.1", 152 }, 153 useAddonManager: "temporary", 154 }); 155 156 await ext1.startup(); 157 await AddonTestUtils.waitForSearchProviderStartup(ext1); 158 159 let engine = Services.search.getEngineByName("MozSearch"); 160 await Services.search.setDefault( 161 engine, 162 Ci.nsISearchService.CHANGE_REASON_UNKNOWN 163 ); 164 await Services.search.moveEngine(engine, 1); 165 166 await ext1.upgrade({ 167 manifest: { 168 chrome_settings_overrides: { 169 search_provider: { 170 name: "MozSearch", 171 keyword: "MozSearch", 172 search_url: "https://example.com/?q={searchTerms}", 173 }, 174 }, 175 browser_specific_settings: { 176 gecko: { 177 id: "testengine@mozilla.com", 178 }, 179 }, 180 version: "0.2", 181 }, 182 useAddonManager: "temporary", 183 }); 184 await AddonTestUtils.waitForSearchProviderStartup(ext1); 185 186 engine = Services.search.getEngineByName("MozSearch"); 187 equal( 188 Services.search.defaultEngine, 189 engine, 190 "Default engine should still be MozSearch" 191 ); 192 equal( 193 (await Services.search.getEngines()).map(e => e.name).indexOf(engine.name), 194 1, 195 "Engine is in position 1" 196 ); 197 198 await ext1.unload(); 199 await delay(); 200 201 engine = Services.search.getEngineByName("MozSearch"); 202 ok(!engine, "Engine should not exist"); 203 }); 204 205 add_task(async function test_extension_get_params() { 206 let ext1 = ExtensionTestUtils.loadExtension({ 207 manifest: { 208 chrome_settings_overrides: { 209 search_provider: { 210 name: "MozSearch", 211 keyword: "MozSearch", 212 search_url: kSearchEngineURL, 213 search_url_get_params: "foo=bar&bar=foo", 214 suggest_url: kSearchSuggestURL, 215 suggest_url_get_params: "foo=bar&bar=foo", 216 }, 217 }, 218 }, 219 useAddonManager: "temporary", 220 }); 221 222 await ext1.startup(); 223 await AddonTestUtils.waitForSearchProviderStartup(ext1); 224 225 let engine = Services.search.getEngineByName("MozSearch"); 226 ok(engine, "Engine should exist."); 227 228 let url = engine.wrappedJSObject.getURLOfType("text/html"); 229 equal(url.method, "GET", "Search URLs method is GET"); 230 231 let expectedURL = kSearchEngineURL.replace("{searchTerms}", kSearchTerm); 232 let submission = engine.getSubmission(kSearchTerm); 233 equal( 234 submission.uri.spec, 235 `${expectedURL}&foo=bar&bar=foo`, 236 "Search URLs should match" 237 ); 238 239 let expectedSuggestURL = kSearchSuggestURL.replace( 240 "{searchTerms}", 241 kSearchTerm 242 ); 243 let submissionSuggest = engine.getSubmission( 244 kSearchTerm, 245 URLTYPE_SUGGEST_JSON 246 ); 247 equal( 248 submissionSuggest.uri.spec, 249 `${expectedSuggestURL}&foo=bar&bar=foo`, 250 "Suggest URLs should match" 251 ); 252 253 await ext1.unload(); 254 }); 255 256 add_task(async function test_extension_post_params() { 257 let ext1 = ExtensionTestUtils.loadExtension({ 258 manifest: { 259 chrome_settings_overrides: { 260 search_provider: { 261 name: "MozSearch", 262 keyword: "MozSearch", 263 search_url: kSearchEngineURL, 264 search_url_post_params: "foo=bar&bar=foo", 265 suggest_url: kSearchSuggestURL, 266 suggest_url_post_params: "foo=bar&bar=foo", 267 }, 268 }, 269 }, 270 useAddonManager: "temporary", 271 }); 272 273 await ext1.startup(); 274 await AddonTestUtils.waitForSearchProviderStartup(ext1); 275 276 let engine = Services.search.getEngineByName("MozSearch"); 277 ok(engine, "Engine should exist."); 278 279 let url = engine.wrappedJSObject.getURLOfType("text/html"); 280 equal(url.method, "POST", "Search URLs method is POST"); 281 282 let expectedURL = kSearchEngineURL.replace("{searchTerms}", kSearchTerm); 283 let submission = engine.getSubmission(kSearchTerm); 284 equal(submission.uri.spec, expectedURL, "Search URLs should match"); 285 // postData is a nsIMIMEInputStream which contains a nsIStringInputStream. 286 equal( 287 submission.postData.data.data, 288 "foo=bar&bar=foo", 289 "Search postData should match" 290 ); 291 292 let expectedSuggestURL = kSearchSuggestURL.replace( 293 "{searchTerms}", 294 kSearchTerm 295 ); 296 let submissionSuggest = engine.getSubmission( 297 kSearchTerm, 298 URLTYPE_SUGGEST_JSON 299 ); 300 equal( 301 submissionSuggest.uri.spec, 302 expectedSuggestURL, 303 "Suggest URLs should match" 304 ); 305 equal( 306 submissionSuggest.postData.data.data, 307 "foo=bar&bar=foo", 308 "Suggest postData should match" 309 ); 310 311 await ext1.unload(); 312 }); 313 314 add_task(async function test_extension_no_query_params() { 315 const ext1 = ExtensionTestUtils.loadExtension({ 316 manifest: { 317 chrome_settings_overrides: { 318 search_provider: { 319 name: "MozSearch", 320 keyword: "MozSearch", 321 search_url: "https://example.com/{searchTerms}", 322 suggest_url: "https://example.com/suggest/{searchTerms}", 323 }, 324 }, 325 }, 326 useAddonManager: "temporary", 327 }); 328 329 await ext1.startup(); 330 await AddonTestUtils.waitForSearchProviderStartup(ext1); 331 332 let engine = Services.search.getEngineByName("MozSearch"); 333 ok(engine, "Engine should exist."); 334 335 const encodedSubmissionURL = engine.getSubmission(kSearchTermIntl).uri.spec; 336 const testSubmissionURL = 337 "https://example.com/" + encodeURIComponent(kSearchTermIntl); 338 equal( 339 encodedSubmissionURL, 340 testSubmissionURL, 341 "Encoded UTF-8 URLs should match" 342 ); 343 344 const expectedSuggestURL = "https://example.com/suggest/" + kSearchTerm; 345 let submissionSuggest = engine.getSubmission( 346 kSearchTerm, 347 URLTYPE_SUGGEST_JSON 348 ); 349 equal( 350 submissionSuggest.uri.spec, 351 expectedSuggestURL, 352 "Suggest URLs should match" 353 ); 354 355 await ext1.unload(); 356 await delay(); 357 358 engine = Services.search.getEngineByName("MozSearch"); 359 ok(!engine, "Engine should not exist"); 360 }); 361 362 add_task(async function test_extension_empty_suggestUrl() { 363 let ext1 = ExtensionTestUtils.loadExtension({ 364 manifest: { 365 default_locale: "en", 366 chrome_settings_overrides: { 367 search_provider: { 368 name: "MozSearch", 369 keyword: "MozSearch", 370 search_url: kSearchEngineURL, 371 search_url_post_params: "foo=bar&bar=foo", 372 suggest_url: "__MSG_suggestUrl__", 373 suggest_url_get_params: "__MSG_suggestUrlGetParams__", 374 }, 375 }, 376 }, 377 useAddonManager: "temporary", 378 files: { 379 "_locales/en/messages.json": { 380 suggestUrl: { 381 message: "", 382 }, 383 suggestUrlGetParams: { 384 message: "", 385 }, 386 }, 387 }, 388 }); 389 390 await ext1.startup(); 391 await AddonTestUtils.waitForSearchProviderStartup(ext1); 392 393 let engine = Services.search.getEngineByName("MozSearch"); 394 ok(engine, "Engine should exist."); 395 396 let url = engine.wrappedJSObject.getURLOfType("text/html"); 397 equal(url.method, "POST", "Search URLs method is POST"); 398 399 let expectedURL = kSearchEngineURL.replace("{searchTerms}", kSearchTerm); 400 let submission = engine.getSubmission(kSearchTerm); 401 equal(submission.uri.spec, expectedURL, "Search URLs should match"); 402 // postData is a nsIMIMEInputStream which contains a nsIStringInputStream. 403 equal( 404 submission.postData.data.data, 405 "foo=bar&bar=foo", 406 "Search postData should match" 407 ); 408 409 let submissionSuggest = engine.getSubmission( 410 kSearchTerm, 411 URLTYPE_SUGGEST_JSON 412 ); 413 ok(!submissionSuggest, "There should be no suggest URL."); 414 415 await ext1.unload(); 416 }); 417 418 add_task(async function test_extension_empty_suggestUrl_with_params() { 419 let ext1 = ExtensionTestUtils.loadExtension({ 420 manifest: { 421 default_locale: "en", 422 chrome_settings_overrides: { 423 search_provider: { 424 name: "MozSearch", 425 keyword: "MozSearch", 426 search_url: kSearchEngineURL, 427 search_url_post_params: "foo=bar&bar=foo", 428 suggest_url: "__MSG_suggestUrl__", 429 suggest_url_get_params: "__MSG_suggestUrlGetParams__", 430 }, 431 }, 432 }, 433 useAddonManager: "temporary", 434 files: { 435 "_locales/en/messages.json": { 436 suggestUrl: { 437 message: "", 438 }, 439 suggestUrlGetParams: { 440 message: "abc", 441 }, 442 }, 443 }, 444 }); 445 446 await ext1.startup(); 447 await AddonTestUtils.waitForSearchProviderStartup(ext1); 448 449 let engine = Services.search.getEngineByName("MozSearch"); 450 ok(engine, "Engine should exist."); 451 452 let url = engine.wrappedJSObject.getURLOfType("text/html"); 453 equal(url.method, "POST", "Search URLs method is POST"); 454 455 let expectedURL = kSearchEngineURL.replace("{searchTerms}", kSearchTerm); 456 let submission = engine.getSubmission(kSearchTerm); 457 equal(submission.uri.spec, expectedURL, "Search URLs should match"); 458 // postData is a nsIMIMEInputStream which contains a nsIStringInputStream. 459 equal( 460 submission.postData.data.data, 461 "foo=bar&bar=foo", 462 "Search postData should match" 463 ); 464 465 let submissionSuggest = engine.getSubmission( 466 kSearchTerm, 467 URLTYPE_SUGGEST_JSON 468 ); 469 ok(!submissionSuggest, "There should be no suggest URL."); 470 471 await ext1.unload(); 472 }); 473 474 async function checkBadUrl(searchProviderKey, urlValue) { 475 let normalized = await ExtensionTestUtils.normalizeManifest({ 476 chrome_settings_overrides: { 477 search_provider: { 478 name: "MozSearch", 479 keyword: "MozSearch", 480 search_url: "https://example.com/", 481 [searchProviderKey]: urlValue, 482 }, 483 }, 484 }); 485 486 ok( 487 /Error processing chrome_settings_overrides\.search_provider[^:]*: .* must match/.test( 488 normalized.error 489 ), 490 `Expected error for ${searchProviderKey}:${urlValue} "${normalized.error}"` 491 ); 492 } 493 494 async function checkValidUrl(urlValue) { 495 let normalized = await ExtensionTestUtils.normalizeManifest({ 496 chrome_settings_overrides: { 497 search_provider: { 498 name: "MozSearch", 499 keyword: "MozSearch", 500 search_url: urlValue, 501 suggest_url: urlValue, 502 }, 503 }, 504 }); 505 equal(normalized.error, undefined, `Valid search_provider url: ${urlValue}`); 506 } 507 508 add_task(async function test_extension_not_allow_http() { 509 await checkBadUrl("search_url", "http://example.com/{searchTerms}"); 510 await checkBadUrl("suggest_url", "http://example.com/{searchTerms}"); 511 }); 512 513 add_task(async function test_manifest_disallows_http_localhost_prefix() { 514 await checkBadUrl("search_url", "http://localhost.example.com"); 515 await checkBadUrl("search_url", "http://localhost.example.com/"); 516 await checkBadUrl("search_url", "http://127.0.0.1.example.com/"); 517 await checkBadUrl("search_url", "http://localhost:1234@example.com/"); 518 }); 519 520 add_task(async function test_manifest_allow_http_for_localhost() { 521 await checkValidUrl("http://localhost"); 522 await checkValidUrl("http://localhost/"); 523 await checkValidUrl("http://localhost:/"); 524 await checkValidUrl("http://localhost:1/"); 525 await checkValidUrl("http://localhost:65535/"); 526 527 await checkValidUrl("http://127.0.0.1"); 528 await checkValidUrl("http://127.0.0.1:"); 529 await checkValidUrl("http://127.0.0.1:/"); 530 await checkValidUrl("http://127.0.0.1/"); 531 await checkValidUrl("http://127.0.0.1:80/"); 532 533 await checkValidUrl("http://[::1]"); 534 await checkValidUrl("http://[::1]:"); 535 await checkValidUrl("http://[::1]:/"); 536 await checkValidUrl("http://[::1]/"); 537 await checkValidUrl("http://[::1]:80/"); 538 }); 539 540 add_task(async function test_extension_allow_http_for_localhost() { 541 let ext1 = ExtensionTestUtils.loadExtension({ 542 manifest: { 543 chrome_settings_overrides: { 544 search_provider: { 545 name: "MozSearch", 546 keyword: "MozSearch", 547 search_url: "http://localhost/{searchTerms}", 548 suggest_url: "http://localhost/suggest/{searchTerms}", 549 }, 550 }, 551 }, 552 useAddonManager: "temporary", 553 }); 554 555 await ext1.startup(); 556 await AddonTestUtils.waitForSearchProviderStartup(ext1); 557 558 let engine = Services.search.getEngineByName("MozSearch"); 559 ok(engine, "Engine should exist."); 560 561 await ext1.unload(); 562 }); 563 564 add_task(async function test_search_favicon_mv3() { 565 let normalized = await ExtensionTestUtils.normalizeManifest({ 566 manifest_version: 3, 567 chrome_settings_overrides: { 568 search_provider: { 569 name: "HTTP Icon in MV3", 570 search_url: "https://example.org/", 571 favicon_url: "https://example.org/icon.png", 572 }, 573 }, 574 }); 575 Assert.ok( 576 normalized.error.endsWith("must be a relative URL"), 577 "Should have an error" 578 ); 579 normalized = await ExtensionTestUtils.normalizeManifest({ 580 manifest_version: 3, 581 chrome_settings_overrides: { 582 search_provider: { 583 name: "HTTP Icon in MV3", 584 search_url: "https://example.org/", 585 favicon_url: "/icon.png", 586 }, 587 }, 588 }); 589 Assert.ok(!normalized.error, "Should not have an error"); 590 });