summaryrefslogtreecommitdiffstats
path: root/toolkit/components/httpsonlyerror/tests/browser/browser_exception.js
blob: 2e441fa9eed8c9e4073678df9f12bf8a4ebc2f94 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

const ROOT_PATH = getRootDirectory(gTestPath);
const EXPIRED_ROOT_PATH = ROOT_PATH.replace(
  "chrome://mochitests/content",
  "http://supports-insecure.expired.example.com"
);
const SECURE_ROOT_PATH = ROOT_PATH.replace(
  "chrome://mochitests/content",
  "http://example.com"
);
const INSECURE_ROOT_PATH = ROOT_PATH.replace(
  "chrome://mochitests/content",
  "http://example.com"
);

// This is how this test works:
//
// +----[REQUEST]  https://file_upgrade_insecure_server.sjs?queryresult
// |
// |  +-[REQUEST]  http://file_upgrade_insecure_server.sjs?content
// |  |            -> Internal HTTPS redirect
// |  |
// |  +>[RESPONSE] Expired Certificate Response
// |               -> HTTPS-Only Mode Error Page shows up
// |               -> Click exception button
// |
// |  +-[REQUEST]  http://file_upgrade_insecure_server.sjs?content
// |  |
// |  +>[RESPONSE] Webpage with a bunch of sub-resources
// |               -> http://file_upgrade_insecure_ser^er.sjs?img
// |               -> http://file_upgrade_insecure_server.sjs?xhr
// |               -> http://file_upgrade_insecure_server.sjs?iframe
// |               -> etc.
// |
// +--->[RESPONSE] List of all recorded requests and whether they were loaded
//                 with HTTP or not (eg.: img-ok, xhr-ok, iframe-error, ...)

add_task(async function () {
  const testCases = ["default", "private", "firstpartyisolation"];
  for (let i = 0; i < testCases.length; i++) {
    // Call sjs-file with setup query-string and store promise
    let expectedQueries = new Set([
      "content",
      "img",
      "iframe",
      "xhr",
      "nestedimg",
    ]);

    const filesLoaded = setupFileServer();
    // Since we don't know when the server has saved all it's variables,
    // let's wait a bit before reloading the page.
    await new Promise(resolve => executeSoon(resolve));

    // Create a new private window but reuse the normal one.
    let privateWindow = false;
    if (testCases[i] === "private") {
      privateWindow = await BrowserTestUtils.openNewBrowserWindow({
        private: true,
      });
    } else if (testCases[i] === "firstpartyisolation") {
      await SpecialPowers.pushPrefEnv({
        set: [["privacy.firstparty.isolate", true]],
      });
    }

    // Create new tab with sjs-file requesting content.
    // "supports-insecure.expired.example.com" responds to http and https but
    // with an expired certificate
    let tab = await openErrorPage(
      `${EXPIRED_ROOT_PATH}file_upgrade_insecure_server.sjs?content`,
      false,
      privateWindow
    );
    let browser = tab.linkedBrowser;

    let pageShownPromise = BrowserTestUtils.waitForContentEvent(
      browser,
      "pageshow",
      true
    );

    // click on exception-button and wait for page to load
    await SpecialPowers.spawn(browser, [], async function () {
      let openInsecureButton = content.document.getElementById("openInsecure");
      ok(openInsecureButton != null, "openInsecureButton should exist.");
      openInsecureButton.click();
    });

    await pageShownPromise;

    // Check if the original page got loaded with http this time
    await SpecialPowers.spawn(browser, [], async function () {
      let doc = content.document;
      ok(
        !doc.documentURI.startsWith("http://expired.example.com"),
        "Page should load normally after exception button was clicked."
      );
    });

    // Wait for initial sjs request to resolve
    let results = await filesLoaded;

    for (let resultIndex in results) {
      const response = results[resultIndex];
      // A response looks either like this "iframe-ok" or "[key]-[result]"
      const [key, result] = response.split("-", 2);
      // try to find the expected result within the results array
      if (expectedQueries.has(key)) {
        expectedQueries.delete(key);
        is(result, "ok", `Request '${key}' should be loaded with HTTP.'`);
      } else {
        ok(false, `Unexpected response from server (${response})`);
      }
    }

    // Clean up permissions, tab and potentially preferences
    Services.perms.removeAll();

    if (testCases[i] === "firstpartyisolation") {
      await SpecialPowers.popPrefEnv();
    }

    if (privateWindow) {
      await BrowserTestUtils.closeWindow(privateWindow);
    } else {
      gBrowser.removeCurrentTab();
    }
  }
});

function setupFileServer() {
  // We initialize the upgrade-server with the queryresult query-string.
  // We'll get a response once all files have been requested and then
  // can see if they have been requested with http.
  return new Promise((resolve, reject) => {
    var xhrRequest = new XMLHttpRequest();
    xhrRequest.open(
      "GET",
      `${SECURE_ROOT_PATH}file_upgrade_insecure_server.sjs?queryresult=${INSECURE_ROOT_PATH}`
    );
    xhrRequest.onload = function (e) {
      var results = xhrRequest.responseText.split(",");
      resolve(results);
    };
    xhrRequest.onerror = e => {
      ok(false, "Could not query results from server (" + e.message + ")");
      reject();
    };
    xhrRequest.send();
  });
}