summaryrefslogtreecommitdiffstats
path: root/dom/security/test/general/test_block_toplevel_data_navigation.html
blob: bbadacb21820cc1c43521dc7e6deb2f2829b343b (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
<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <title>Bug 1331351 - Block top level window data: URI navigations</title>
  <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
  <script src="/tests/SimpleTest/SimpleTest.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<script class="testbody" type="text/javascript">

async function expectBlockedToplevelData() {
  await SpecialPowers.spawnChrome([], async () => {
    let progressListener;
    let bid = await new Promise(resolve => {
      let bcs = [];
      progressListener = {
        QueryInterface: ChromeUtils.generateQI(["nsIWebProgressListener", "nsISupportsWeakReference"]),
        onStateChange(webProgress, request, stateFlags, status) {
          if (!(request instanceof Ci.nsIChannel) || !webProgress.isTopLevel ||
              !(stateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW) ||
              !(stateFlags & Ci.nsIWebProgressListener.STATE_STOP)) {
            return;
          }

          if (!["NS_ERROR_DOM_BAD_URI", "NS_ERROR_CORRUPTED_CONTENT"].includes(ChromeUtils.getXPCOMErrorName(status))) {
            info(ChromeUtils.getXPCOMErrorName(status));
            isnot(request.URI.scheme, "data");
            return;
          }

          // We can't check for the scheme to be "data" because in the case of a
          // redirected load, we'll get a `NS_ERROR_DOM_BAD_URI` load error
          // before observing the redirect, cancelling the load. Instead we just
          // wait for any load to error with `NS_ERROR_DOM_BAD_URI`.
          for (let bc of bcs) {
            try {
              bc.webProgress.removeProgressListener(progressListener);
            } catch(e) { }
          }
          bcs = [];
          Services.obs.removeObserver(observer, "browsing-context-attached");
          resolve(webProgress.browsingContext.browserId);
        }
      };

      function observer(subject, topic) {
        if (!bcs.includes(subject.webProgress)) {
          bcs.push(subject.webProgress);
          subject.webProgress.addProgressListener(progressListener, Ci.nsIWebProgress.NOTIFY_ALL);
        }
      }
      Services.obs.addObserver(observer, "browsing-context-attached");
    });
    return bid;
  });
}

async function expectBlockedURIWarning() {
  await SpecialPowers.spawnChrome([], async () => {
    return new Promise(resolve => {
      Services.console.registerListener(function onConsoleMessage(msg) {
        info("Seeing console message: " + msg.message);
        if (!(msg instanceof Ci.nsIScriptError)) {
          return;
        }
        if (msg.category != "DATA_URI_BLOCKED") {
          return;
        }

        Services.console.unregisterListener(onConsoleMessage);
        resolve();
      });
    });
  });
}

async function expectBrowserDiscarded(browserId) {
  await SpecialPowers.spawnChrome([browserId], async (browserId) => {
    return new Promise(resolve => {
      function check() {
        if (!BrowsingContext.getCurrentTopByBrowserId(browserId)) {
          ok(true, `BrowserID ${browserId} discarded`);
          resolve();
          Services.obs.removeObserver(check, "browsing-context-discarded");
        }
      }
      Services.obs.addObserver(check, "browsing-context-discarded");
      check();
    });
  });
}

async function popupTest(uri, expectClose) {
  info(`Running expect blocked test for ${uri}`);
  let reqBlockedPromise = expectBlockedToplevelData();
  let warningPromise = expectBlockedURIWarning();
  let win = window.open(uri);
  let browserId = await reqBlockedPromise;
  await warningPromise;
  if (expectClose) {
    await expectBrowserDiscarded(browserId);
  }
  win.close();
}

add_task(async function() {
  await SpecialPowers.pushPrefEnv({
    set: [["security.data_uri.block_toplevel_data_uri_navigations", true]],
  });

  // simple data: URI click navigation should be prevented
  await popupTest("file_block_toplevel_data_navigation.html", false);

  // data: URI in iframe which opens data: URI in _blank should be blocked
  await popupTest("file_block_toplevel_data_navigation2.html", false);

  // navigating to a data: URI using window.location.href should be blocked
  await popupTest("file_block_toplevel_data_navigation3.html", false);

  // navigating to a data: URI using window.open() should be blocked
  await popupTest("data:text/html,<body>toplevel data: URI navigations should be blocked</body>", false);

  // navigating to a URI which redirects to a data: URI using window.open() should be blocked
  await popupTest("file_block_toplevel_data_redirect.sjs", false);

  // navigating to a data: URI without a Content Type should be blocked
  await popupTest("data:,DataURIsWithNoContentTypeShouldBeBlocked", false);
});

</script>
</body>
</html>