Backed out 4 changesets (bug 1342178) for frequent test_network_security.html failures a=backout
authorWes Kocher <wkocher@mozilla.com>
Mon, 10 Apr 2017 12:34:10 -0700
changeset 560233 167230c49025646595e659ae92eb13ae442dcb71
parent 560232 4feb5533f54ac748cd335d2bdcad01811b95c6cf
child 560234 a21a26ea6947fe80775fda3a671381ae13342001
push id53365
push userjichen@mozilla.com
push dateTue, 11 Apr 2017 08:35:12 +0000
reviewersbackout
bugs1342178
milestone55.0a1
backs out7f9114ffbcae47f2870f542d62bb95dd6a0166aa
f19289f0cfefc116efeb99cf02164c41238d2353
4afce44bc2b9f0793d81e868dafc73ffd0ddd3be
db9b64a440120c4e259397b203cf11f82c6f1859
Backed out 4 changesets (bug 1342178) for frequent test_network_security.html failures a=backout Backed out changeset 7f9114ffbcae (bug 1342178) Backed out changeset f19289f0cfef (bug 1342178) Backed out changeset 4afce44bc2b9 (bug 1342178) Backed out changeset db9b64a44012 (bug 1342178)
browser/base/content/browser.js
browser/base/content/content.js
browser/base/content/test/general/browser_aboutCertError.js
devtools/client/debugger/new/debugger.js
devtools/shared/webconsole/network-helper.js
devtools/shared/webconsole/test/chrome.ini
devtools/shared/webconsole/test/test_network_security-hpkp.html
devtools/shared/webconsole/test/test_network_security-hsts.html
devtools/shared/webconsole/test/test_network_security.html
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -3019,18 +3019,17 @@ var BrowserOnClick = {
     }
   },
 
   receiveMessage(msg) {
     switch (msg.name) {
       case "Browser:CertExceptionError":
         this.onCertError(msg.target, msg.data.elementId,
                          msg.data.isTopFrame, msg.data.location,
-                         msg.data.securityInfoAsString,
-                         msg.data.originAttributesAsString);
+                         msg.data.securityInfoAsString);
       break;
       case "Browser:OpenCaptivePortalPage":
         CaptivePortalWatcher.ensureCaptivePortalTab();
       break;
       case "Browser:SiteBlockedError":
         this.onAboutBlocked(msg.data.elementId, msg.data.reason,
                             msg.data.isTopFrame, msg.data.location,
                             msg.data.blockedInfo);
@@ -3084,18 +3083,17 @@ var BrowserOnClick = {
     transportSecurityInfo.QueryInterface(Ci.nsITransportSecurityInfo)
 
     let errorReporter = Cc["@mozilla.org/securityreporter;1"]
                           .getService(Ci.nsISecurityReporter);
     errorReporter.reportTLSError(transportSecurityInfo,
                                  uri.host, uri.port);
   },
 
-  onCertError(browser, elementId, isTopFrame, location, securityInfoAsString,
-              originAttributesAsString) {
+  onCertError(browser, elementId, isTopFrame, location, securityInfoAsString) {
     let secHistogram = Services.telemetry.getHistogramById("SECURITY_UI");
     let securityInfo;
 
     switch (elementId) {
       case "exceptionDialogButton":
         if (isTopFrame) {
           secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_CLICK_ADD_EXCEPTION);
         }
@@ -3135,31 +3133,29 @@ var BrowserOnClick = {
 
       case "advancedButton":
         if (isTopFrame) {
           secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_UNDERSTAND_RISKS);
         }
 
         securityInfo = getSecurityInfo(securityInfoAsString);
         let errorInfo = getDetailedCertErrorInfo(location,
-                                                 securityInfo,
-                                                 JSON.parse(originAttributesAsString));
+                                                 securityInfo);
         browser.messageManager.sendAsyncMessage( "CertErrorDetails", {
             code: securityInfo.errorCode,
             info: errorInfo
         });
         break;
 
       case "copyToClipboard":
         const gClipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"]
                                     .getService(Ci.nsIClipboardHelper);
         securityInfo = getSecurityInfo(securityInfoAsString);
         let detailedInfo = getDetailedCertErrorInfo(location,
-                                                    securityInfo,
-                                                    JSON.parse(originAttributesAsString));
+                                                    securityInfo);
         gClipboardHelper.copyString(detailedInfo);
         break;
 
     }
   },
 
   onAboutBlocked(elementId, reason, isTopFrame, location, blockedInfo) {
     // Depending on what page we are displaying here (malware/phishing/unwanted)
@@ -3414,17 +3410,17 @@ function getSecurityInfo(securityInfoAsS
 
   return securityInfo;
 }
 
 /**
  * Returns a string with detailed information about the certificate validation
  * failure from the specified URI that can be used to send a report.
  */
-function getDetailedCertErrorInfo(location, securityInfo, originAttributes) {
+function getDetailedCertErrorInfo(location, securityInfo) {
   if (!securityInfo)
     return "";
 
   let certErrorDetails = location;
   let code = securityInfo.errorCode;
   let errors = Cc["@mozilla.org/nss_errors_service;1"]
                   .getService(Ci.nsINSSErrorsService);
 
@@ -3435,18 +3431,18 @@ function getDetailedCertErrorInfo(locati
   // SiteSecurityService uses different storage if the channel is
   // private. Thus we must give isSecureURI correct flags or we
   // might get incorrect results.
   let flags = PrivateBrowsingUtils.isWindowPrivate(window) ?
               Ci.nsISocketProvider.NO_PERMANENT_STORAGE : 0;
 
   let uri = Services.io.newURI(location);
 
-  let hasHSTS = sss.isSecureURI(sss.HEADER_HSTS, uri, flags, originAttributes);
-  let hasHPKP = sss.isSecureURI(sss.HEADER_HPKP, uri, flags, originAttributes);
+  let hasHSTS = sss.isSecureURI(sss.HEADER_HSTS, uri, flags);
+  let hasHPKP = sss.isSecureURI(sss.HEADER_HPKP, uri, flags);
   certErrorDetails += "\r\n\r\n" +
                       gNavigatorBundle.getFormattedString("certErrorDetailsHSTS.label",
                                                           [hasHSTS]);
   certErrorDetails += "\r\n" +
                       gNavigatorBundle.getFormattedString("certErrorDetailsKeyPinning.label",
                                                           [hasHPKP]);
 
   let certChain = "";
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -288,24 +288,16 @@ function getSiteBlockedErrorDetails(docS
 }
 
 addMessageListener("DeceptiveBlockedDetails", (message) => {
   sendAsyncMessage("DeceptiveBlockedDetails:Result", {
     blockedInfo: getSiteBlockedErrorDetails(docShell),
   });
 });
 
-function getSerializedOriginAttributes(docShell) {
-  let originAttributes = {};
-  if (docShell.failedChannel) {
-    originAttributes = docShell.failedChannel.loadInfo.originAttributes;
-  }
-  return JSON.stringify(originAttributes);
-}
-
 var AboutNetAndCertErrorListener = {
   init(chromeGlobal) {
     addMessageListener("CertErrorDetails", this);
     addMessageListener("Browser:CaptivePortalFreed", this);
     chromeGlobal.addEventListener("AboutNetErrorLoad", this, false, true);
     chromeGlobal.addEventListener("AboutNetErrorOpenCaptivePortal", this, false, true);
     chromeGlobal.addEventListener("AboutNetErrorSetAutomatic", this, false, true);
     chromeGlobal.addEventListener("AboutNetErrorResetPreferences", this, false, true);
@@ -604,17 +596,16 @@ var ClickEventHandler = {
     let docShell = ownerDoc.defaultView.QueryInterface(Ci.nsIInterfaceRequestor)
                                        .getInterface(Ci.nsIWebNavigation)
                                        .QueryInterface(Ci.nsIDocShell);
     sendAsyncMessage("Browser:CertExceptionError", {
       location: ownerDoc.location.href,
       elementId: targetElement.getAttribute("id"),
       isTopFrame: (ownerDoc.defaultView.parent === ownerDoc.defaultView),
       securityInfoAsString: getSerializedSecurityInfo(docShell),
-      originAttributesAsString: getSerializedOriginAttributes(docShell),
     });
   },
 
   onAboutBlocked(targetElement, ownerDoc) {
     var reason = "phishing";
     if (/e=malwareBlocked/.test(ownerDoc.documentURI)) {
       reason = "malware";
     } else if (/e=unwantedBlocked/.test(ownerDoc.documentURI)) {
--- a/browser/base/content/test/general/browser_aboutCertError.js
+++ b/browser/base/content/test/general/browser_aboutCertError.js
@@ -254,23 +254,20 @@ add_task(function* checkAdvancedDetails(
     let text = doc.getElementById("certificateErrorText");
 
     let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
                      .getService(Ci.nsISerializationHelper);
     let serializable =  docShell.failedChannel.securityInfo
                                 .QueryInterface(Ci.nsITransportSecurityInfo)
                                 .QueryInterface(Ci.nsISerializable);
     let serializedSecurityInfo = serhelper.serializeToString(serializable);
-    let originAttributes = docShell.failedChannel.loadInfo.originAttributes;
-    let serializedOriginAttributes = JSON.stringify(originAttributes);
     return {
       divDisplay: content.getComputedStyle(div).display,
       text: text.textContent,
-      securityInfoAsString: serializedSecurityInfo,
-      originAttributesAsString: serializedOriginAttributes,
+      securityInfoAsString: serializedSecurityInfo
     };
   });
   isnot(message.divDisplay, "none", "Debug information is visible");
   ok(message.text.includes(BAD_CERT), "Correct URL found");
   ok(message.text.includes("Certificate has expired"),
      "Correct error message found");
   ok(message.text.includes("HTTP Strict Transport Security: false"),
      "Correct HSTS value found");
@@ -326,23 +323,20 @@ add_task(function* checkAdvancedDetailsF
     let text = doc.getElementById("certificateErrorText");
 
     let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
                      .getService(Ci.nsISerializationHelper);
     let serializable =  docShell.failedChannel.securityInfo
                                 .QueryInterface(Ci.nsITransportSecurityInfo)
                                 .QueryInterface(Ci.nsISerializable);
     let serializedSecurityInfo = serhelper.serializeToString(serializable);
-    let originAttributes = docShell.failedChannel.loadInfo.originAttributes;
-    let serializedOriginAttributes = JSON.stringify(originAttributes);
     return {
       divDisplay: content.getComputedStyle(div).display,
       text: text.textContent,
-      securityInfoAsString: serializedSecurityInfo,
-      originAttributesAsString: serializedOriginAttributes,
+      securityInfoAsString: serializedSecurityInfo
     };
   });
   isnot(message.divDisplay, "none", "Debug information is visible");
   ok(message.text.includes(badStsUri.spec), "Correct URL found");
   ok(message.text.includes("requested domain name does not match the server\u2019s certificate"),
      "Correct error message found");
   ok(message.text.includes("HTTP Strict Transport Security: false"),
      "Correct HSTS value found");
--- a/devtools/client/debugger/new/debugger.js
+++ b/devtools/client/debugger/new/debugger.js
@@ -8935,30 +8935,20 @@ return /******/ (function(modules) { // 
 
 
 	        // SiteSecurityService uses different storage if the channel is
 	        // private. Thus we must give isSecureHost correct flags or we
 	        // might get incorrect results.
 	        let flags = (httpActivity.private) ?
 	                      Ci.nsISocketProvider.NO_PERMANENT_STORAGE : 0;
 
-	        if (!uri) {
-	          // isSecureURI only cares about the host, not the scheme.
-	          let host = httpActivity.hostname;
-	          uri = Services.io.newURI("https://" + host);
-	        }
-
-	        let originAttributes = {};
-	        if (httpActivity.channel) {
-	          originAttributes = httpActivity.channel.loadInfo.originAttributes;
-	        }
-	        info.hsts = sss.isSecureURI(sss.HEADER_HSTS, uri, flags,
-	                                    originAttributes);
-	        info.hpkp = sss.isSecureURI(sss.HEADER_HPKP, uri, flags,
-	                                    originAttributes);
+	        let host = httpActivity.hostname;
+
+	        info.hsts = sss.isSecureHost(sss.HEADER_HSTS, host, flags);
+	        info.hpkp = sss.isSecureHost(sss.HEADER_HPKP, host, flags);
 	      } else {
 	        DevToolsUtils.reportException("NetworkHelper.parseSecurityInfo",
 	          "Could not get HSTS/HPKP status as hostname is not available.");
 	        info.hsts = false;
 	        info.hpkp = false;
 	      }
 
 	    } else {
--- a/devtools/shared/webconsole/network-helper.js
+++ b/devtools/shared/webconsole/network-helper.js
@@ -639,24 +639,18 @@ var NetworkHelper = {
                       Ci.nsISocketProvider.NO_PERMANENT_STORAGE : 0;
 
         if (!uri) {
           // isSecureURI only cares about the host, not the scheme.
           let host = httpActivity.hostname;
           uri = Services.io.newURI("https://" + host);
         }
 
-        let originAttributes = {};
-        if (httpActivity.channel) {
-          originAttributes = httpActivity.channel.loadInfo.originAttributes;
-        }
-        info.hsts = sss.isSecureURI(sss.HEADER_HSTS, uri, flags,
-                                    originAttributes);
-        info.hpkp = sss.isSecureURI(sss.HEADER_HPKP, uri, flags,
-                                    originAttributes);
+        info.hsts = sss.isSecureURI(sss.HEADER_HSTS, uri, flags);
+        info.hpkp = sss.isSecureURI(sss.HEADER_HPKP, uri, flags);
       } else {
         DevToolsUtils.reportException("NetworkHelper.parseSecurityInfo",
           "Could not get HSTS/HPKP status as hostname is not available.");
         info.hsts = false;
         info.hpkp = false;
       }
     } else {
       // The connection failed.
--- a/devtools/shared/webconsole/test/chrome.ini
+++ b/devtools/shared/webconsole/test/chrome.ini
@@ -27,15 +27,16 @@ support-files =
 [test_jsterm.html]
 [test_jsterm_autocomplete.html]
 [test_jsterm_cd_iframe.html]
 [test_jsterm_last_result.html]
 [test_jsterm_queryselector.html]
 [test_network_get.html]
 [test_network_longstring.html]
 [test_network_post.html]
-[test_network_security.html]
+[test_network_security-hpkp.html]
+[test_network_security-hsts.html]
 [test_nsiconsolemessage.html]
 [test_object_actor.html]
 [test_object_actor_native_getters.html]
 [test_object_actor_native_getters_lenient_this.html]
 [test_page_errors.html]
 [test_throw.html]
rename from devtools/shared/webconsole/test/test_network_security.html
rename to devtools/shared/webconsole/test/test_network_security-hpkp.html
--- a/devtools/shared/webconsole/test/test_network_security.html
+++ b/devtools/shared/webconsole/test/test_network_security-hpkp.html
@@ -9,187 +9,97 @@
      - http://creativecommons.org/publicdomain/zero/1.0/ -->
 </head>
 <body>
 <p>Test for the network actor (HPKP detection)</p>
 
 <iframe src="https://example.com/chrome/devtools/shared/webconsole/test/network_requests_iframe.html"></iframe>
 
 <script class="testbody" type="text/javascript">
-Cu.import("resource://testing-common/BrowserTestUtils.jsm");
-Cu.import("resource://gre/modules/Task.jsm");
-
 SimpleTest.waitForExplicitFinish();
 
 let gCurrentTestCase = -1;
 const HPKP_PREF = "security.cert_pinning.process_headers_from_non_builtin_roots";
 
 // Static pins tested by unit/test_security-info-static-hpkp.js.
 const TEST_CASES = [
   {
-    desc: "no HSTS or HPKP",
+    desc: "no Public Key Pinning",
     url: "https://example.com",
-    usesHSTS: false,
-    usesPinning: false,
-  },
-  {
-    desc: "HSTS from this response, no Public Key Pinning",
-    url: "https://example.com/" +
-         "browser/browser/base/content/test/general/browser_star_hsts.sjs",
-    usesHSTS: true,
-    usesPinning: false,
-  },
-  {
-    desc: "stored HSTS from previous response, no Public Key Pinning",
-    url: "https://example.com/",
-    usesHSTS: true,
     usesPinning: false,
   },
   {
-    desc: "no Public Key Pinning or HSTS",
-    url: "https://include-subdomains.pinning-dynamic.example.com/",
-    usesHSTS: false,
-    usesPinning: false,
-  },
-  {
-    desc: "dynamic Public Key Pinning with this request, no HSTS",
+    desc: "dynamic Public Key Pinning with this request",
     url: "https://include-subdomains.pinning-dynamic.example.com/" +
          "browser/browser/base/content/test/general/pinning_headers.sjs",
-    usesHSTS: false,
     usesPinning: true,
   },
   {
-    desc: "dynamic Public Key Pinning with previous request, no HSTS",
+    desc: "dynamic Public Key Pinning with previous request",
     url: "https://include-subdomains.pinning-dynamic.example.com/",
-    usesHSTS: false,
     usesPinning: true,
   }
 ];
 
-const TEST_MODES = [ "public", "private" ];
-let ALL_TESTS = [];
-
 function startTest() {
   // Need to enable this pref or pinning headers are rejected due test
   // certificate.
   Services.prefs.setBoolPref(HPKP_PREF, true);
   SimpleTest.registerCleanupFunction(() => {
     Services.prefs.setBoolPref(HPKP_PREF, false);
 
     // Reset pinning state.
     let gSSService = Cc["@mozilla.org/ssservice;1"]
                        .getService(Ci.nsISiteSecurityService);
 
     let gIOService = Cc["@mozilla.org/network/io-service;1"]
                        .getService(Ci.nsIIOService);
     for (let {url} of TEST_CASES) {
       let uri = gIOService.newURI(url);
-      gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0);
-      gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
-                             Ci.nsISocketProvider.NO_PERMANENT_STORAGE,
-                             { privateBrowsingId: 1 });
       gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0);
-      gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HPKP, uri,
-                             Ci.nsISocketProvider.NO_PERMANENT_STORAGE,
-                             { privateBrowsingId: 1 });
     }
   });
 
-  info("Test detection of HTTP Strict Transport Security" +
-       " and Public Key Pinning.");
-  for (let mode of TEST_MODES) {
-    for (let testCase of TEST_CASES) {
-      let test = { mode };
-      for (let attr in testCase) {
-        test[attr] = testCase[attr];
-      }
-      ALL_TESTS.push(test);
-    }
-  }
-
+  info("Test detection of Public Key Pinning.");
   removeEventListener("load", startTest);
   attachConsoleToTab(["NetworkActivity"], onAttach);
 }
 
 function onAttach(state, response) {
-  let callback = onNetworkEventUpdate.bind(null, state);
-  state.dbgClient.addListener("networkEventUpdate", callback);
+  onNetworkEventUpdate = onNetworkEventUpdate.bind(null, state);
+  state.dbgClient.addListener("networkEventUpdate", onNetworkEventUpdate);
 
   runNextCase(state);
 }
 
 function runNextCase(state) {
   gCurrentTestCase++;
-  if (gCurrentTestCase === ALL_TESTS.length) {
+  if (gCurrentTestCase === TEST_CASES.length) {
     info("Tests ran. Cleaning up.");
     closeDebugger(state, SimpleTest.finish);
     return;
   }
 
-  let { desc, url, mode } = ALL_TESTS[gCurrentTestCase];
+  let { desc, url } = TEST_CASES[gCurrentTestCase];
   info("Testing site with " + desc);
 
-  if (mode == "private") {
-    info("Cleaning up the previous window.");
-    closeDebugger(state, runInPrivateWindow);
-  } else {
-    let iframe = document.querySelector("iframe").contentWindow;
-    iframe.wrappedJSObject.makeXhrCallback("GET", url);
-  }
+  let iframe = document.querySelector("iframe").contentWindow;
+  iframe.wrappedJSObject.makeXhrCallback("GET", url);
 }
 
 function onNetworkEventUpdate(state, type, packet) {
   function onSecurityInfo(received) {
-    let data = ALL_TESTS[gCurrentTestCase];
-    is(received.securityInfo.hsts, data.usesHSTS,
-      "Strict Transport Security detected correctly.");
+    let data = TEST_CASES[gCurrentTestCase];
     is(received.securityInfo.hpkp, data.usesPinning,
       "Public Key Pinning detected correctly.");
 
     runNextCase(state);
   }
 
   if (packet.updateType === "securityInfo") {
     state.client.getSecurityInfo(packet.from, onSecurityInfo);
   }
 }
 
-function whenDelayedStartupFinished(aWindow, aCallback) {
-  SpecialPowers.Services.obs.addObserver(function observer(aSubject, aTopic) {
-    if (aWindow == aSubject) {
-      SpecialPowers.Services.obs.removeObserver(observer, aTopic);
-      SimpleTest.executeSoon(aCallback);
-    }
-  }, "browser-delayed-startup-finished", false);
-}
-
-let mainWindow =
-  window.QueryInterface(Ci.nsIInterfaceRequestor).
-  getInterface(Ci.nsIWebNavigation).QueryInterface(Ci.nsIDocShellTreeItem).
-  rootTreeItem.QueryInterface(Ci.nsIInterfaceRequestor).
-  getInterface(Ci.nsIDOMWindow);
-
-function runInPrivateWindow() {
-  let win = mainWindow.OpenBrowserWindow({private: true});
-
-  Task.spawn(function* () {
-    yield new Promise(resolve => whenDelayedStartupFinished(win, resolve));
-    let browser = win.gBrowser.selectedBrowser;
-    let url = ALL_TESTS[gCurrentTestCase].url;
-    win.gBrowser.selectedTab = win.gBrowser.getTabForBrowser(browser);
-
-    yield new Promise(function(resolve) {
-      attachConsoleToTab(["NetworkActivity"], function(state) {
-        let callback = onNetworkEventUpdate.bind(null, state);
-        state.dbgClient.addListener("networkEventUpdate", callback);
-
-        resolve();
-      });
-    });
-
-    yield BrowserTestUtils.loadURI(browser, url);
-  });
-}
-
 addEventListener("load", startTest);
 </script>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/devtools/shared/webconsole/test/test_network_security-hsts.html
@@ -0,0 +1,100 @@
+<!DOCTYPE HTML>
+<html lang="en">
+<head>
+  <meta charset="utf8">
+  <title>Test for the network actor (HSTS detection)</title>
+  <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="common.js"></script>
+  <!-- Any copyright is dedicated to the Public Domain.
+     - http://creativecommons.org/publicdomain/zero/1.0/ -->
+</head>
+<body>
+<p>Test for the network actor (HSTS detection)</p>
+
+<iframe src="https://example.com/chrome/devtools/shared/webconsole/test/network_requests_iframe.html"></iframe>
+
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+let gCurrentTestCase = -1;
+const TEST_CASES = [
+  {
+    desc: "no HSTS",
+    url: "https://example.com",
+    usesHSTS: false,
+  },
+  {
+    desc: "HSTS from this response",
+    url: "https://example.com/"+
+         "browser/browser/base/content/test/general/browser_star_hsts.sjs",
+    usesHSTS: true,
+  },
+  {
+    desc: "stored HSTS from previous response",
+    url: "https://example.com/",
+    usesHSTS: true,
+  }
+];
+
+function startTest()
+{
+
+  SimpleTest.registerCleanupFunction(() => {
+    // Reset HSTS state.
+    let gSSService = Cc["@mozilla.org/ssservice;1"]
+                       .getService(Ci.nsISiteSecurityService);
+
+    let gIOService = Cc["@mozilla.org/network/io-service;1"]
+                       .getService(Ci.nsIIOService);
+
+    let uri = gIOService.newURI(TEST_CASES[0].url);
+    gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0);
+  });
+
+  info("Test detection of HTTP Strict Transport Security.");
+  removeEventListener("load", startTest);
+  attachConsoleToTab(["NetworkActivity"], onAttach);
+}
+
+function onAttach(aState, aResponse)
+{
+  onNetworkEventUpdate = onNetworkEventUpdate.bind(null, aState);
+  aState.dbgClient.addListener("networkEventUpdate", onNetworkEventUpdate);
+
+  runNextCase(aState);
+}
+
+function runNextCase(aState) {
+  gCurrentTestCase++;
+  if (gCurrentTestCase === TEST_CASES.length) {
+    info("Tests ran. Cleaning up.");
+    closeDebugger(aState, SimpleTest.finish);
+    return;
+  }
+
+  let { desc, url } = TEST_CASES[gCurrentTestCase];
+  info("Testing site with " + desc);
+
+  let iframe = document.querySelector("iframe").contentWindow;
+  iframe.wrappedJSObject.makeXhrCallback("GET", url);
+}
+
+function onNetworkEventUpdate(aState, aType, aPacket)
+{
+  function onSecurityInfo(packet) {
+    let data = TEST_CASES[gCurrentTestCase];
+    is(packet.securityInfo.hsts, data.usesHSTS,
+      "Strict Transport Security detected correctly.");
+
+    runNextCase(aState);
+  }
+
+  if (aPacket.updateType === "securityInfo") {
+    aState.client.getSecurityInfo(aPacket.from, onSecurityInfo);
+  }
+}
+
+addEventListener("load", startTest);
+</script>
+</body>
+</html>