summaryrefslogtreecommitdiffstats
path: root/dom/security/test/https-only/browser_hsts_host.js
blob: 7adb365b94c3615ab01530ec923bab82ca3daafb (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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
// Bug 1722489 - HTTPS-Only Mode - Tests evaluation order
// https://bugzilla.mozilla.org/show_bug.cgi?id=1722489
// This test ensures that an http request to an hsts host
// gets upgraded by hsts and not by https-only.
"use strict";

// Set bools to track that tests ended.
let readMessage = false;
let testFinished = false;
// Visit a secure site that sends an HSTS header to set up the rest of the
// test.
add_task(async function see_hsts_header() {
  let setHstsUrl =
    getRootDirectory(gTestPath).replace(
      "chrome://mochitests/content",
      "https://example.com"
    ) + "hsts_headers.sjs";
  Services.obs.addObserver(observer, "http-on-examine-response");
  await BrowserTestUtils.loadURIString(gBrowser.selectedBrowser, setHstsUrl);

  await BrowserTestUtils.waitForCondition(() => readMessage);
  // Clean up
  Services.obs.removeObserver(observer, "http-on-examine-response");
});

// Test that HTTPS_Only is not performed if HSTS host is visited.
add_task(async function () {
  // A longer timeout is necessary for this test than the plain mochitests
  // due to opening a new tab with the web console.
  requestLongerTimeout(4);

  // Enable HTTPS-Only Mode and register console-listener
  await SpecialPowers.pushPrefEnv({
    set: [["dom.security.https_only_mode", true]],
  });

  Services.console.registerListener(onNewMessage);
  const RESOURCE_LINK =
    getRootDirectory(gTestPath).replace(
      "chrome://mochitests/content",
      "http://example.com"
    ) + "hsts_headers.sjs";

  // 1. Upgrade page to https://
  await BrowserTestUtils.loadURIString(gBrowser.selectedBrowser, RESOURCE_LINK);

  await BrowserTestUtils.waitForCondition(() => testFinished);

  // Clean up
  Services.console.unregisterListener(onNewMessage);

  await SpecialPowers.popPrefEnv();
});

// Test that when clicking on #fragment with a different scheme (http vs https)
// DOES cause an actual navigation with HSTS, even though https-only mode is
// enabled.
add_task(async function () {
  await SpecialPowers.pushPrefEnv({
    set: [
      ["dom.security.https_only_mode", true],
      [
        "dom.security.https_only_mode_break_upgrade_downgrade_endless_loop",
        false,
      ],
    ],
  });

  const TEST_PAGE =
    "http://example.com/browser/dom/security/test/https-only/file_fragment_noscript.html";

  await BrowserTestUtils.withNewTab(
    {
      gBrowser,
      url: TEST_PAGE,
      waitForLoad: true,
    },
    async function (browser) {
      const UPGRADED_URL = TEST_PAGE.replace("http:", "https:");

      await SpecialPowers.spawn(browser, [UPGRADED_URL], async function (url) {
        is(content.window.location.href, url);

        content.window.addEventListener("scroll", () => {
          ok(false, "scroll event should not trigger");
        });

        let beforeUnload = new Promise(resolve => {
          content.window.addEventListener("beforeunload", resolve, {
            once: true,
          });
        });

        content.window.document.querySelector("#clickMeButton").click();

        // Wait for unload event.
        await beforeUnload;
      });

      await BrowserTestUtils.browserLoaded(browser);

      await SpecialPowers.spawn(browser, [UPGRADED_URL], async function (url) {
        is(content.window.location.href, url + "#foo");
      });
    }
  );

  await SpecialPowers.popPrefEnv();
});

add_task(async function () {
  // Reset HSTS header
  readMessage = false;
  let clearHstsUrl =
    getRootDirectory(gTestPath).replace(
      "chrome://mochitests/content",
      "https://example.com"
    ) + "hsts_headers.sjs?reset";

  Services.obs.addObserver(observer, "http-on-examine-response");
  // reset hsts header
  await BrowserTestUtils.loadURIString(gBrowser.selectedBrowser, clearHstsUrl);
  await BrowserTestUtils.waitForCondition(() => readMessage);
  // Clean up
  Services.obs.removeObserver(observer, "http-on-examine-response");
});

function observer(subject, topic, state) {
  info("observer called with " + topic);
  if (topic == "http-on-examine-response") {
    onExamineResponse(subject);
  }
}

function onExamineResponse(subject) {
  let channel = subject.QueryInterface(Ci.nsIHttpChannel);
  // If message was already read or is not related to "example.com",
  // don't examine it.
  if (!channel.URI.spec.includes("example.com") || readMessage) {
    return;
  }
  info("onExamineResponse with " + channel.URI.spec);
  if (channel.URI.spec.includes("reset")) {
    try {
      let hsts = channel.getResponseHeader("Strict-Transport-Security");
      is(hsts, "max-age=0", "HSTS header is not set");
    } catch (e) {
      ok(false, "HSTS header still set");
    }
    readMessage = true;
    return;
  }
  try {
    let hsts = channel.getResponseHeader("Strict-Transport-Security");
    let csp = channel.getResponseHeader("Content-Security-Policy");
    // Check that HSTS and CSP upgrade headers are set
    is(hsts, "max-age=60", "HSTS header is set");
    is(csp, "upgrade-insecure-requests", "CSP header is set");
  } catch (e) {
    ok(false, "No header set");
  }
  readMessage = true;
}

function onNewMessage(msgObj) {
  const message = msgObj.message;
  // ensure that request is not upgraded HTTPS-Only.
  if (message.includes("Upgrading insecure request")) {
    ok(false, "Top-Level upgrade shouldn't get logged");
    testFinished = true;
  } else if (
    message.includes("Upgrading insecure speculative TCP connection")
  ) {
    // TODO: Check assertion
    // https://bugzilla.mozilla.org/show_bug.cgi?id=1735683
    ok(true, "Top-Level upgrade shouldn't get logged");
    testFinished = true;
  } else if (gBrowser.selectedBrowser.currentURI.scheme === "https") {
    ok(true, "Top-Level upgrade shouldn't get logged");
    testFinished = true;
  }
}