Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
michael@0 | 1 | <!DOCTYPE html> |
michael@0 | 2 | <html xmlns="http://www.w3.org/1999/xhtml"> |
michael@0 | 3 | <!-- |
michael@0 | 4 | https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage |
michael@0 | 5 | --> |
michael@0 | 6 | <head> |
michael@0 | 7 | <title>postMessage from about:blank, data URLs</title> |
michael@0 | 8 | <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> |
michael@0 | 9 | <script type="text/javascript" src="browserFu.js"></script> |
michael@0 | 10 | <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> |
michael@0 | 11 | </head> |
michael@0 | 12 | <body> |
michael@0 | 13 | <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage">Mozilla Bug 387706</a> |
michael@0 | 14 | <p id="display"></p> |
michael@0 | 15 | <div id="content" style="display: none"></div> |
michael@0 | 16 | |
michael@0 | 17 | <pre id="test"> |
michael@0 | 18 | <script class="testbody" type="application/javascript"><![CDATA[ |
michael@0 | 19 | /** Test for Bug 387706 **/ |
michael@0 | 20 | |
michael@0 | 21 | SimpleTest.waitForExplicitFinish(); |
michael@0 | 22 | |
michael@0 | 23 | var B64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
michael@0 | 24 | |
michael@0 | 25 | /** |
michael@0 | 26 | * Encodes an array of bytes into a string using the base 64 encoding scheme. |
michael@0 | 27 | * |
michael@0 | 28 | * @param bytes |
michael@0 | 29 | * An array of bytes to encode. |
michael@0 | 30 | */ |
michael@0 | 31 | function b64(str) |
michael@0 | 32 | { |
michael@0 | 33 | var byteArray = new Array(str.length); |
michael@0 | 34 | for (var i = 0, sz = str.length; i < sz; i++) |
michael@0 | 35 | byteArray[i] = str.charCodeAt(i); |
michael@0 | 36 | |
michael@0 | 37 | var index = 0; |
michael@0 | 38 | function get3Bytes() |
michael@0 | 39 | { |
michael@0 | 40 | if (byteArray.length - index < 3) |
michael@0 | 41 | return null; // Less than three bytes remaining |
michael@0 | 42 | |
michael@0 | 43 | // Return the next three bytes in the array, and increment index for our |
michael@0 | 44 | // next invocation |
michael@0 | 45 | return byteArray.slice(index, index += 3); |
michael@0 | 46 | } |
michael@0 | 47 | |
michael@0 | 48 | var out = ""; |
michael@0 | 49 | var bytes = null; |
michael@0 | 50 | while ((bytes = get3Bytes())) |
michael@0 | 51 | { |
michael@0 | 52 | var bits = 0; |
michael@0 | 53 | for (var i = 0; i < 3; i++) |
michael@0 | 54 | bits = (bits << 8) | bytes[i]; |
michael@0 | 55 | for (var j = 18; j >= 0; j -= 6) |
michael@0 | 56 | out += B64_CHARS[(bits>>j) & 0x3F]; |
michael@0 | 57 | } |
michael@0 | 58 | |
michael@0 | 59 | // Get the remaining bytes |
michael@0 | 60 | bytes = byteArray.slice(index); |
michael@0 | 61 | |
michael@0 | 62 | switch (bytes.length) |
michael@0 | 63 | { |
michael@0 | 64 | case 2: |
michael@0 | 65 | out += B64_CHARS[(bytes[0]>>2) & 0x3F] + |
michael@0 | 66 | B64_CHARS[((bytes[0] & 0x03) << 4) | ((bytes[1] >> 4) & 0x0F)] + |
michael@0 | 67 | B64_CHARS[((bytes[1] & 0x0F) << 2)] + |
michael@0 | 68 | "="; |
michael@0 | 69 | break; |
michael@0 | 70 | case 1: |
michael@0 | 71 | out += B64_CHARS[(bytes[0]>>2) & 0x3F] + |
michael@0 | 72 | B64_CHARS[(bytes[0] & 0x03) << 4] + |
michael@0 | 73 | "=="; |
michael@0 | 74 | break; |
michael@0 | 75 | } |
michael@0 | 76 | |
michael@0 | 77 | return out; |
michael@0 | 78 | } |
michael@0 | 79 | |
michael@0 | 80 | |
michael@0 | 81 | var aboutBlankWindow = null; |
michael@0 | 82 | var aboutBlank2Window = null; |
michael@0 | 83 | var dataWindow = null; |
michael@0 | 84 | |
michael@0 | 85 | /** Convert a nullable string to a pretty representation */ |
michael@0 | 86 | function sourceify(v) |
michael@0 | 87 | { |
michael@0 | 88 | if (typeof v == "string") |
michael@0 | 89 | return "'" + v + "'"; |
michael@0 | 90 | return String(v); |
michael@0 | 91 | } |
michael@0 | 92 | |
michael@0 | 93 | /** Receives MessageEvents to this window. */ |
michael@0 | 94 | function messageReceiver(evt) |
michael@0 | 95 | { |
michael@0 | 96 | // It's not clear what the security model is for data: URLs and whether they |
michael@0 | 97 | // can access their parents; WebKit denies access, while Gecko currently |
michael@0 | 98 | // allows it. We work around this problem by using postMessage (surprise!) |
michael@0 | 99 | // to start the round of tests when each iframe loads. |
michael@0 | 100 | if (evt.data === "next-test") |
michael@0 | 101 | { |
michael@0 | 102 | setTimeout(nextTest, 0); |
michael@0 | 103 | return; |
michael@0 | 104 | } |
michael@0 | 105 | |
michael@0 | 106 | |
michael@0 | 107 | try |
michael@0 | 108 | { |
michael@0 | 109 | ok(evt instanceof MessageEvent, "umm, how did we get this?"); |
michael@0 | 110 | is(evt.type, "message", "expected events of type 'message'"); |
michael@0 | 111 | |
michael@0 | 112 | if (isMozilla) |
michael@0 | 113 | { |
michael@0 | 114 | ok(evt.isTrusted === false, "shouldn't have been a trusted event"); |
michael@0 | 115 | } |
michael@0 | 116 | |
michael@0 | 117 | if (evt.data === "about:blank-response") |
michael@0 | 118 | { |
michael@0 | 119 | // This isn't clarified in HTML5 yet, but the origin for a document which |
michael@0 | 120 | // has been open()ed is the origin of the calling code, somewhat loosely |
michael@0 | 121 | // speaking. For the specific case of about:blank it's also possible |
michael@0 | 122 | // that the origin is determined by the code that opens the window. It's |
michael@0 | 123 | // not codified yet which of these two causes the identifier tokens on |
michael@0 | 124 | // the event generated by the new window to be those of this window, but |
michael@0 | 125 | // in either case this is what they should be. |
michael@0 | 126 | is(evt.origin, "http://mochi.test:8888", |
michael@0 | 127 | "wrong origin for event from about:blank"); |
michael@0 | 128 | is(evt.source, aboutBlankWindow, "wrong source"); |
michael@0 | 129 | |
michael@0 | 130 | // ...and onto the next test |
michael@0 | 131 | setupBlank2(); |
michael@0 | 132 | } |
michael@0 | 133 | else if (evt.data === "about:blank2-response") |
michael@0 | 134 | { |
michael@0 | 135 | is(evt.origin, "http://mochi.test:8888", |
michael@0 | 136 | "wrong origin for event from about:blank #2"); |
michael@0 | 137 | is(evt.source, aboutBlank2Window, "wrong source"); |
michael@0 | 138 | |
michael@0 | 139 | setupData(); |
michael@0 | 140 | } |
michael@0 | 141 | else if (evt.data === "data-response") |
michael@0 | 142 | { |
michael@0 | 143 | // HTML5 defines the origin of a data: URI as the origin of the window or |
michael@0 | 144 | // script that opened the data: URI. |
michael@0 | 145 | is(evt.origin, "http://mochi.test:8888", |
michael@0 | 146 | "wrong origin for event from data URL (should be the origin of the " + |
michael@0 | 147 | "window/script that opened the URL, in this case the origin of this " + |
michael@0 | 148 | "file)"); |
michael@0 | 149 | is(evt.source, dataWindow, "wrong source"); |
michael@0 | 150 | |
michael@0 | 151 | finish(); |
michael@0 | 152 | } |
michael@0 | 153 | else |
michael@0 | 154 | { |
michael@0 | 155 | ok(false, "unexpected message: " + evt.data); |
michael@0 | 156 | } |
michael@0 | 157 | } |
michael@0 | 158 | catch (e) |
michael@0 | 159 | { |
michael@0 | 160 | ok(false, "error processing event with data '" + evt.data + "': " + e); |
michael@0 | 161 | } |
michael@0 | 162 | } |
michael@0 | 163 | |
michael@0 | 164 | function getContents(description, responseText) |
michael@0 | 165 | { |
michael@0 | 166 | var contents = |
michael@0 | 167 | "<!DOCTYPE html>\n" + |
michael@0 | 168 | "<html>\n" + |
michael@0 | 169 | "<head>\n" + |
michael@0 | 170 | " <title>about:blank</title>\n" + |
michael@0 | 171 | " <script type='application/javascript'>\n" + |
michael@0 | 172 | "function receive(evt)\n" + |
michael@0 | 173 | "{\n" + |
michael@0 | 174 | " var response = '" + responseText + "';\n" + |
michael@0 | 175 | "\n" + |
michael@0 | 176 | " if (evt.source !== window.parent)\n" + |
michael@0 | 177 | " response += ' wrong-source';\n" + |
michael@0 | 178 | " if (evt.origin !== 'http://mochi.test:8888')\n" + |
michael@0 | 179 | " response += ' wrong-origin(' + evt.origin + ')';\n" + |
michael@0 | 180 | " if (evt.data !== 'from-opener')\n" + |
michael@0 | 181 | " response += ' wrong-data(' + evt.data + ')';\n" + |
michael@0 | 182 | "\n" + |
michael@0 | 183 | " window.parent.postMessage(response, 'http://mochi.test:8888');\n" + |
michael@0 | 184 | "}\n" + |
michael@0 | 185 | "\n" + |
michael@0 | 186 | "function ready()\n" + |
michael@0 | 187 | "{\n" + |
michael@0 | 188 | " window.parent.postMessage('next-test', 'http://mochi.test:8888');\n" + |
michael@0 | 189 | "}\n" + |
michael@0 | 190 | "\n" + |
michael@0 | 191 | "window.addEventListener('load', ready, false);\n" + |
michael@0 | 192 | "window.addEventListener('message', receive, false);\n" + |
michael@0 | 193 | " </script>\n" + |
michael@0 | 194 | "</head>\n" + |
michael@0 | 195 | "<body><p>" + description + "</p></body>\n" + |
michael@0 | 196 | "</html>"; |
michael@0 | 197 | |
michael@0 | 198 | return contents; |
michael@0 | 199 | } |
michael@0 | 200 | |
michael@0 | 201 | function finish() |
michael@0 | 202 | { |
michael@0 | 203 | SimpleTest.finish(); |
michael@0 | 204 | } |
michael@0 | 205 | |
michael@0 | 206 | var xhtmlns = "http://www.w3.org/1999/xhtml"; |
michael@0 | 207 | |
michael@0 | 208 | function insert(el) |
michael@0 | 209 | { |
michael@0 | 210 | var content = $("content"); |
michael@0 | 211 | content.parentNode.insertBefore(el, content); |
michael@0 | 212 | } |
michael@0 | 213 | |
michael@0 | 214 | function setupBlank() |
michael@0 | 215 | { |
michael@0 | 216 | var aboutBlankFrame = document.createElementNS(xhtmlns, "iframe"); |
michael@0 | 217 | aboutBlankFrame.setAttribute("src", "about:blank"); |
michael@0 | 218 | insert(aboutBlankFrame); |
michael@0 | 219 | |
michael@0 | 220 | aboutBlankWindow = aboutBlankFrame.contentWindow; |
michael@0 | 221 | var doc = aboutBlankWindow.document; |
michael@0 | 222 | doc.open(); |
michael@0 | 223 | doc.write(getContents("This was about:blank #1", "about:blank-response")); |
michael@0 | 224 | doc.close(); |
michael@0 | 225 | |
michael@0 | 226 | // I don't believe anything guarantees sync parsing, so we have to wait for |
michael@0 | 227 | // the new window to poke us to actually do the test. :-\ |
michael@0 | 228 | } |
michael@0 | 229 | |
michael@0 | 230 | function setupBlank2() |
michael@0 | 231 | { |
michael@0 | 232 | var aboutBlank2Frame = document.createElementNS(xhtmlns, "iframe"); |
michael@0 | 233 | aboutBlank2Frame.addEventListener("load", nextTest, false); |
michael@0 | 234 | aboutBlank2Frame.setAttribute("src", "about:blank"); |
michael@0 | 235 | |
michael@0 | 236 | insert(aboutBlank2Frame); |
michael@0 | 237 | } |
michael@0 | 238 | |
michael@0 | 239 | // Could use window.btoa here, but that's not standardized, and we want to be |
michael@0 | 240 | // able to run these tests against browsers that don't support it. |
michael@0 | 241 | var dataURI = "data:text/html;base64," + |
michael@0 | 242 | b64(getContents("A data: URL", "data-response")); |
michael@0 | 243 | |
michael@0 | 244 | function setupData() |
michael@0 | 245 | { |
michael@0 | 246 | var dataFrame = document.createElementNS(xhtmlns, "iframe"); |
michael@0 | 247 | dataFrame.setAttribute("src", dataURI); |
michael@0 | 248 | insert(dataFrame); |
michael@0 | 249 | |
michael@0 | 250 | dataWindow = dataFrame.contentWindow; |
michael@0 | 251 | |
michael@0 | 252 | // ...and wait again for the window to load... |
michael@0 | 253 | } |
michael@0 | 254 | |
michael@0 | 255 | var count = 0; |
michael@0 | 256 | function nextTest() |
michael@0 | 257 | { |
michael@0 | 258 | switch (count++) |
michael@0 | 259 | { |
michael@0 | 260 | case 0: |
michael@0 | 261 | testBlank(); |
michael@0 | 262 | break; |
michael@0 | 263 | |
michael@0 | 264 | case 1: |
michael@0 | 265 | testBlank2(); |
michael@0 | 266 | break; |
michael@0 | 267 | |
michael@0 | 268 | case 2: |
michael@0 | 269 | testData(); |
michael@0 | 270 | break; |
michael@0 | 271 | |
michael@0 | 272 | default: |
michael@0 | 273 | ok(false, "unreached"); |
michael@0 | 274 | break; |
michael@0 | 275 | } |
michael@0 | 276 | } |
michael@0 | 277 | |
michael@0 | 278 | function testBlank() |
michael@0 | 279 | { |
michael@0 | 280 | aboutBlankWindow.postMessage("from-opener", "http://mochi.test:8888"); |
michael@0 | 281 | } |
michael@0 | 282 | |
michael@0 | 283 | function testBlank2() |
michael@0 | 284 | { |
michael@0 | 285 | // For some reason we can't access this across browsers prior to the iframe |
michael@0 | 286 | // loading, so set its value here. |
michael@0 | 287 | aboutBlank2Window = window.frames[1]; |
michael@0 | 288 | |
michael@0 | 289 | var doc = aboutBlank2Window.document; |
michael@0 | 290 | |
michael@0 | 291 | doc.body.textContent = "This was about:blank #2"; |
michael@0 | 292 | |
michael@0 | 293 | var script = doc.createElement("script"); |
michael@0 | 294 | script.textContent = |
michael@0 | 295 | "window.parent.postMessage('about:blank2-response', " + |
michael@0 | 296 | " 'http://mochi.test:8888');"; |
michael@0 | 297 | doc.body.appendChild(script); |
michael@0 | 298 | } |
michael@0 | 299 | |
michael@0 | 300 | function testData() |
michael@0 | 301 | { |
michael@0 | 302 | dataWindow.postMessage("from-opener", "http://mochi.test:8888"); |
michael@0 | 303 | } |
michael@0 | 304 | |
michael@0 | 305 | window.addEventListener("message", messageReceiver, false); |
michael@0 | 306 | |
michael@0 | 307 | addLoadEvent(setupBlank); |
michael@0 | 308 | ]]></script> |
michael@0 | 309 | </pre> |
michael@0 | 310 | </body> |
michael@0 | 311 | </html> |