browser_https_telemetry.js (15773B)
1 /* Any copyright is dedicated to the Public Domain. 2 * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 // We explicitly need HTTP URLs in this test 7 /* eslint-disable @microsoft/sdl/no-insecure-url */ 8 9 requestLongerTimeout(3); 10 11 ChromeUtils.defineLazyGetter(this, "UrlbarTestUtils", () => { 12 const { UrlbarTestUtils: module } = ChromeUtils.importESModule( 13 "resource://testing-common/UrlbarTestUtils.sys.mjs" 14 ); 15 module.init(this); 16 return module; 17 }); 18 19 const TEST_PATH_HTTP = getRootDirectory(gTestPath).replace( 20 "chrome://mochitests/content", 21 "http://example.com" 22 ); 23 const TEST_PATH_HTTPS = getRootDirectory(gTestPath).replace( 24 "chrome://mochitests/content", 25 "https://example.com" 26 ); 27 const TEST_PATH_SCHEMELESS = getRootDirectory(gTestPath).replace( 28 "chrome://mochitests/content", 29 "example.com" 30 ); 31 32 const HSTS_SITE = TEST_PATH_HTTPS + "file_https_telemetry_hsts.sjs"; 33 34 const NO_HTTPS_SUPPORT_SITE = TEST_PATH_HTTP + "file_no_https_support.sjs"; 35 const NO_HTTPS_SUPPORT_SITE_SCHEMELESS = 36 TEST_PATH_SCHEMELESS + "file_no_https_support.sjs"; 37 38 async function setPrefsAndResetFog( 39 aHTTPSOnlyPref, 40 aHTTPSFirstPref, 41 aSchemeLessPref 42 ) { 43 Services.fog.testResetFOG(); 44 45 await SpecialPowers.pushPrefEnv({ 46 set: [ 47 ["dom.security.https_only_mode", aHTTPSOnlyPref], 48 ["dom.security.https_first", aHTTPSFirstPref], 49 ["dom.security.https_first_schemeless", aSchemeLessPref], 50 ], 51 }); 52 } 53 54 function verifyGleanValues(aDescription, aExpected) { 55 info(aDescription); 56 57 let notInitialized = aExpected.notInitialized || null; 58 let noUpgrade = aExpected.noUpgrade || null; 59 let alreadyHTTPS = aExpected.alreadyHTTPS || null; 60 let hsts = aExpected.hsts || null; 61 let httpsOnlyUpgrade = aExpected.httpsOnlyUpgrade || null; 62 let httpsOnlyUpgradeDowngrade = aExpected.httpsOnlyUpgradeDowngrade || null; 63 let httpsFirstUpgrade = aExpected.httpsFirstUpgrade || null; 64 let httpsFirstUpgradeDowngrade = aExpected.httpsFirstUpgradeDowngrade || null; 65 let httpsFirstSchemelessUpgrade = 66 aExpected.httpsFirstSchemelessUpgrade || null; 67 let httpsFirstSchemelessUpgradeDowngrade = 68 aExpected.httpsFirstSchemelessUpgradeDowngrade || null; 69 let cspUpgradeInsecureRequests = aExpected.cspUpgradeInsecureRequests || null; 70 let httpsRR = aExpected.httpsRR || null; 71 let webExtensionUpgrade = aExpected.webExtensionUpgrade || null; 72 let upgradeException = aExpected.upgradeException || null; 73 74 let glean = Glean.networking.httpToHttpsUpgradeReason; 75 is( 76 glean.not_initialized.testGetValue(), 77 notInitialized, 78 "verify not_initialized" 79 ); 80 is(glean.no_upgrade.testGetValue(), noUpgrade, "verify no_upgrade"); 81 is(glean.already_https.testGetValue(), alreadyHTTPS, "verify already_https"); 82 is(glean.hsts.testGetValue(), hsts, "verify hsts"); 83 is( 84 glean.https_only_upgrade.testGetValue(), 85 httpsOnlyUpgrade, 86 "verify https_only_upgrade" 87 ); 88 is( 89 glean.https_only_upgrade_downgrade.testGetValue(), 90 httpsOnlyUpgradeDowngrade, 91 "verify https_only_upgrade_downgrade" 92 ); 93 is( 94 glean.https_first_upgrade.testGetValue(), 95 httpsFirstUpgrade, 96 "verify https_first_upgrade" 97 ); 98 is( 99 glean.https_first_upgrade_downgrade.testGetValue(), 100 httpsFirstUpgradeDowngrade, 101 "verify https_first_upgrade_downgrade" 102 ); 103 is( 104 glean.https_first_schemeless_upgrade.testGetValue(), 105 httpsFirstSchemelessUpgrade, 106 "verify https_first_schemeless_upgrade" 107 ); 108 is( 109 glean.https_first_schemeless_upgrade_downgrade.testGetValue(), 110 httpsFirstSchemelessUpgradeDowngrade, 111 "verify https_first_schemeless_upgrade_downgrade" 112 ); 113 is( 114 glean.csp_uir.testGetValue(), 115 cspUpgradeInsecureRequests, 116 "verify csp_uir" 117 ); 118 is(glean.https_rr.testGetValue(), httpsRR, "verify https_rr"); 119 is( 120 glean.web_extension_upgrade.testGetValue(), 121 webExtensionUpgrade, 122 "verify web_extension_upgrade" 123 ); 124 is( 125 glean.upgrade_exception.testGetValue(), 126 upgradeException, 127 "verify upgrade_exception" 128 ); 129 } 130 131 async function runUpgradeTest(aURI, aDesc, aAssertURLStartsWith) { 132 await BrowserTestUtils.withNewTab("about:blank", async function (browser) { 133 const loaded = BrowserTestUtils.browserLoaded(browser, false, null, true); 134 BrowserTestUtils.startLoadingURIString(browser, aURI); 135 await loaded; 136 137 await SpecialPowers.spawn( 138 browser, 139 [aDesc, aAssertURLStartsWith], 140 async function (aDesc, aAssertURLStartsWith) { 141 ok( 142 content.document.location.href.startsWith(aAssertURLStartsWith), 143 aDesc 144 ); 145 } 146 ); 147 await SpecialPowers.removePermission("https-only-load-insecure", aURI); 148 }); 149 } 150 151 async function runSchemelessTest(aURI, aDesc, aAssertURLStartsWith) { 152 await BrowserTestUtils.withNewTab("about:blank", async function (browser) { 153 const loaded = BrowserTestUtils.browserLoaded(browser, false, null, true); 154 await UrlbarTestUtils.promiseAutocompleteResultPopup({ 155 window, 156 value: aURI, 157 }); 158 EventUtils.synthesizeKey("KEY_Enter", { ctrlKey: true }); 159 await loaded; 160 await SpecialPowers.spawn( 161 browser, 162 [aDesc, aAssertURLStartsWith], 163 async function (aDesc, aAssertURLStartsWith) { 164 ok( 165 content.document.location.href.startsWith(aAssertURLStartsWith), 166 aDesc 167 ); 168 } 169 ); 170 // we can't pass a schemeless uri to removePermission 171 let uri = "https://" + aURI; 172 await SpecialPowers.removePermission("https-only-load-insecure", uri); 173 }); 174 } 175 176 add_task(async function () { 177 info("(0) exempt loopback addresses"); 178 179 await setPrefsAndResetFog( 180 false /* aHTTPSOnlyPref */, 181 false /* aHTTPSFirstPref */, 182 false /* aSchemeLessPref */ 183 ); 184 185 // the request to localhost will actually fail in our test infra, 186 // though the telemetry would be recorded. 187 await runUpgradeTest( 188 "https://localhost", 189 "(0) exempt loopback addresses", 190 "https://" 191 ); 192 verifyGleanValues("(0) exempt loopback addresses", {}); 193 }); 194 195 add_task(async function () { 196 info("(1) no upgrade test"); 197 198 await setPrefsAndResetFog( 199 false /* aHTTPSOnlyPref */, 200 false /* aHTTPSFirstPref */, 201 false /* aSchemeLessPref */ 202 ); 203 204 await runUpgradeTest( 205 "http://example.com?test1", 206 "(1) no upgrade test", 207 "http://" 208 ); 209 verifyGleanValues("(1) no upgrade test", { noUpgrade: 1 }); 210 }); 211 212 add_task(async function () { 213 info("(2) already https test"); 214 215 await setPrefsAndResetFog( 216 false /* aHTTPSOnlyPref */, 217 false /* aHTTPSFirstPref */, 218 false /* aSchemeLessPref */ 219 ); 220 221 await runUpgradeTest( 222 "https://example.com?test2", 223 "(2) already https test", 224 "https://" 225 ); 226 227 verifyGleanValues("(2) already https test", { alreadyHTTPS: 1 }); 228 }); 229 230 add_task(async function () { 231 info("(2b) already https test all prefs true"); 232 233 await setPrefsAndResetFog( 234 true /* aHTTPSOnlyPref */, 235 true /* aHTTPSFirstPref */, 236 true /* aSchemeLessPref */ 237 ); 238 239 await runUpgradeTest( 240 "https://example.com?test2b", 241 "(2b) already https test all prefs true", 242 "https://" 243 ); 244 245 verifyGleanValues("(2b) already https test all prefs true", { 246 alreadyHTTPS: 1, 247 }); 248 }); 249 250 add_task(async function () { 251 info("(3) hsts"); 252 253 await setPrefsAndResetFog( 254 false /* aHTTPSOnlyPref */, 255 false /* aHTTPSFirstPref */, 256 false /* aSchemeLessPref */ 257 ); 258 259 // we need to setup hsts first 260 await BrowserTestUtils.withNewTab("about:blank", async function (browser) { 261 const loaded = BrowserTestUtils.browserLoaded(browser, false, null, true); 262 BrowserTestUtils.startLoadingURIString(browser, HSTS_SITE); 263 await loaded; 264 }); 265 266 // now we reset glean again 267 Services.fog.testResetFOG(); 268 269 await runUpgradeTest("http://example.com?test3", "(3) hsts", "https://"); 270 271 verifyGleanValues("(3) hsts", { hsts: 1 }); 272 273 // finally we need to reset hsts 274 await BrowserTestUtils.withNewTab("about:blank", async function (browser) { 275 const loaded = BrowserTestUtils.browserLoaded(browser, false, null, true); 276 BrowserTestUtils.startLoadingURIString(browser, HSTS_SITE + "?reset"); 277 await loaded; 278 }); 279 280 info("(3b) hsts with all prefs true"); 281 282 await setPrefsAndResetFog( 283 true /* aHTTPSOnlyPref */, 284 true /* aHTTPSFirstPref */, 285 true /* aSchemeLessPref */ 286 ); 287 288 // we need to setup hsts first 289 await BrowserTestUtils.withNewTab("about:blank", async function (browser) { 290 const loaded = BrowserTestUtils.browserLoaded(browser, false, null, true); 291 BrowserTestUtils.startLoadingURIString(browser, HSTS_SITE); 292 await loaded; 293 }); 294 295 // now we reset glean again 296 Services.fog.testResetFOG(); 297 298 await runUpgradeTest( 299 "http://example.com?test3b", 300 "(3b) hsts with all prefs true", 301 "https://" 302 ); 303 304 verifyGleanValues("(3b) hsts with all prefs true", { hsts: 1 }); 305 306 // finally we need to reset the hsts host 307 await BrowserTestUtils.withNewTab("about:blank", async function (browser) { 308 const loaded = BrowserTestUtils.browserLoaded(browser, false, null, true); 309 BrowserTestUtils.startLoadingURIString(browser, HSTS_SITE + "?reset"); 310 await loaded; 311 }); 312 }); 313 314 add_task(async function () { 315 info("(4) https-only upgrade"); 316 317 await setPrefsAndResetFog( 318 true /* aHTTPSOnlyPref */, 319 false /* aHTTPSFirstPref */, 320 false /* aSchemeLessPref */ 321 ); 322 323 await runUpgradeTest( 324 "http://example.com?test4", 325 "(4) https-only upgrade", 326 "https://" 327 ); 328 329 verifyGleanValues("(4) https-only upgrade", { httpsOnlyUpgrade: 1 }); 330 331 info("(4b) https-only upgrade downgrade"); 332 333 await setPrefsAndResetFog( 334 true /* aHTTPSOnlyPref */, 335 false /* aHTTPSFirstPref */, 336 false /* aSchemeLessPref */ 337 ); 338 339 // We specifically want a insecure url here that will fail to upgrade 340 let uri = "http://untrusted.example.com:80"; 341 let desc = "(4b) https-only upgrade downgrade"; 342 let assertErrorPageStartsWith = "https://"; 343 let assertDowngradedURLStartsWith = "http://"; 344 345 await BrowserTestUtils.withNewTab("about:blank", async function (browser) { 346 const loaded = BrowserTestUtils.waitForErrorPage(browser); 347 BrowserTestUtils.startLoadingURIString(browser, uri); 348 await loaded; 349 350 await SpecialPowers.spawn( 351 browser, 352 [desc, assertErrorPageStartsWith], 353 async function (desc, assertErrorPageStartsWith) { 354 ok( 355 content.document.location.href.startsWith(assertErrorPageStartsWith), 356 desc 357 ); 358 } 359 ); 360 361 const downGradeLoaded = BrowserTestUtils.browserLoaded( 362 browser, 363 false, 364 null, 365 true 366 ); 367 368 // click the 'continue to insecure page' button 369 await SpecialPowers.spawn(browser, [], async function () { 370 let openInsecureButton = content.document.getElementById("openInsecure"); 371 Assert.notEqual( 372 openInsecureButton, 373 null, 374 "openInsecureButton should exist." 375 ); 376 info("Waiting for openInsecureButton to be enabled."); 377 function callback() { 378 if (!openInsecureButton.classList.contains("disabled")) { 379 observer.disconnect(); 380 content.requestAnimationFrame(() => { 381 content.requestAnimationFrame(() => { 382 openInsecureButton.click(); 383 }); 384 }); 385 } 386 } 387 const observer = new content.MutationObserver(callback); 388 observer.observe(openInsecureButton, { attributeFilter: ["class"] }); 389 callback(); 390 }); 391 392 await downGradeLoaded; 393 394 await SpecialPowers.spawn( 395 browser, 396 [desc, assertDowngradedURLStartsWith], 397 async function (desc, assertDowngradedURLStartsWith) { 398 ok( 399 content.document.location.href.startsWith( 400 assertDowngradedURLStartsWith 401 ), 402 desc 403 ); 404 } 405 ); 406 await SpecialPowers.removePermission("https-only-load-insecure", uri); 407 }); 408 409 verifyGleanValues("(4b) https-only upgrade downgrade", { 410 httpsOnlyUpgrade: 1, 411 httpsOnlyUpgradeDowngrade: 1, 412 }); 413 }); 414 415 add_task(async function () { 416 info("(5) https-first upgrade"); 417 418 await setPrefsAndResetFog( 419 false /* aHTTPSOnlyPref */, 420 true /* aHTTPSFirstPref */, 421 false /* aSchemeLessPref */ 422 ); 423 424 await runUpgradeTest( 425 "http://example.com?test5", 426 "(5) https-first upgrade", 427 "https://" 428 ); 429 430 verifyGleanValues("(5) https-first upgrade", { httpsFirstUpgrade: 1 }); 431 432 info("(5b) https-first upgrade downgrade"); 433 434 await setPrefsAndResetFog( 435 false /* aHTTPSOnlyPref */, 436 true /* aHTTPSFirstPref */, 437 false /* aSchemeLessPref */ 438 ); 439 440 await runUpgradeTest( 441 NO_HTTPS_SUPPORT_SITE + "?test5b", 442 "(5b) https-first upgrade downgrade", 443 "http://" 444 ); 445 446 verifyGleanValues("(5) https-first upgrade", { 447 httpsFirstUpgrade: 1, 448 httpsFirstUpgradeDowngrade: 1, 449 }); 450 }); 451 452 add_task(async function () { 453 info("(6) schemeless https-first upgrade"); 454 455 await setPrefsAndResetFog( 456 false /* aHTTPSOnlyPref */, 457 false /* aHTTPSFirstPref */, 458 true /* aSchemeLessPref */ 459 ); 460 461 await runSchemelessTest( 462 "example.com?test6", 463 "(6) schemeless https-first upgrade", 464 "https://" 465 ); 466 467 verifyGleanValues("(6) schemeless https-first upgrade", { 468 httpsFirstSchemelessUpgrade: 1, 469 }); 470 471 info("(6b) schemeless https-first upgrade downgrade"); 472 473 await setPrefsAndResetFog( 474 false /* aHTTPSOnlyPref */, 475 false /* aHTTPSFirstPref */, 476 true /* aSchemeLessPref */ 477 ); 478 479 await runSchemelessTest( 480 NO_HTTPS_SUPPORT_SITE_SCHEMELESS + "?test6b", 481 "(6) schemeless https-first upgrade downgrade", 482 "http://" 483 ); 484 485 verifyGleanValues("(6b) schemeless https-first upgrade downgrade", { 486 httpsFirstSchemelessUpgrade: 1, 487 httpsFirstSchemelessUpgradeDowngrade: 1, 488 }); 489 }); 490 491 add_task(async function () { 492 info("(7) https-rr upgrade"); 493 494 Services.fog.testResetFOG(); 495 496 await SpecialPowers.pushPrefEnv({ 497 set: [ 498 ["dom.security.https_only_mode", false], 499 ["dom.security.https_first", false], 500 ["dom.security.https_first_schemeless", false], 501 ["network.dns.force_use_https_rr", true], 502 ["network.dns.mock_HTTPS_RR_domain", "example.org"], 503 ], 504 }); 505 506 await runUpgradeTest( 507 "http://example.org", 508 "(7) https-rr upgrade", 509 "https://" 510 ); 511 512 verifyGleanValues("(7) https-rr upgrade", { httpsRR: 1 }); 513 }); 514 515 add_task(async function () { 516 info("(8) upgrade/downgrade/reload"); 517 // This test performs an upgrade-downgrade and then reloads 518 // the document which then triggers an upgrade_exception. 519 520 await setPrefsAndResetFog( 521 false /* aHTTPSOnlyPref */, 522 true /* aHTTPSFirstPref */, 523 false /* aSchemeLessPref */ 524 ); 525 526 await BrowserTestUtils.withNewTab("about:blank", async function (browser) { 527 // First, perform the upgrade/downgrade 528 const upgradeDowngradeLoaded = BrowserTestUtils.browserLoaded( 529 browser, 530 false, 531 null, 532 true 533 ); 534 BrowserTestUtils.startLoadingURIString( 535 browser, 536 NO_HTTPS_SUPPORT_SITE + "?test8" 537 ); 538 await upgradeDowngradeLoaded; 539 540 await SpecialPowers.spawn(browser, [], async function () { 541 ok( 542 content.document.location.href.startsWith("http://"), 543 "(8) upgrade/downgrade/reload" 544 ); 545 }); 546 547 // Before reloading the doc we have to reset the fog 548 Services.fog.testResetFOG(); 549 550 const reloadLoaded = BrowserTestUtils.browserLoaded( 551 browser, 552 false, 553 null, 554 true 555 ); 556 557 await SpecialPowers.spawn(browser, [], async function () { 558 content.location.reload(); 559 }); 560 561 await reloadLoaded; 562 563 await SpecialPowers.spawn(browser, [], async function () { 564 ok( 565 content.document.location.href.startsWith("http://"), 566 "(8) upgrade/downgrade/reload" 567 ); 568 }); 569 }); 570 571 verifyGleanValues("(8) upgrade/downgrade/reload", { upgradeException: 1 }); 572 });