<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <!-- https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage --> <head> <title>postMessage from about:blank, data URLs</title> <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <script type="text/javascript" src="browserFu.js"></script> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> </head> <body> <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage">Mozilla Bug 387706</a> <p id="display"></p> <div id="content" style="display: none"></div> <pre id="test"> <script class="testbody" type="application/javascript"><![CDATA[ /** Test for Bug 387706 **/ SimpleTest.waitForExplicitFinish(); var B64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /** * Encodes an array of bytes into a string using the base 64 encoding scheme. * * @param bytes * An array of bytes to encode. */ function b64(str) { var byteArray = new Array(str.length); for (var i = 0, sz = str.length; i < sz; i++) byteArray[i] = str.charCodeAt(i); var index = 0; function get3Bytes() { if (byteArray.length - index < 3) return null; // Less than three bytes remaining // Return the next three bytes in the array, and increment index for our // next invocation return byteArray.slice(index, index += 3); } var out = ""; var bytes = null; while ((bytes = get3Bytes())) { var bits = 0; for (var i = 0; i < 3; i++) bits = (bits << 8) | bytes[i]; for (var j = 18; j >= 0; j -= 6) out += B64_CHARS[(bits>>j) & 0x3F]; } // Get the remaining bytes bytes = byteArray.slice(index); switch (bytes.length) { case 2: out += B64_CHARS[(bytes[0]>>2) & 0x3F] + B64_CHARS[((bytes[0] & 0x03) << 4) | ((bytes[1] >> 4) & 0x0F)] + B64_CHARS[((bytes[1] & 0x0F) << 2)] + "="; break; case 1: out += B64_CHARS[(bytes[0]>>2) & 0x3F] + B64_CHARS[(bytes[0] & 0x03) << 4] + "=="; break; } return out; } var aboutBlankWindow = null; var aboutBlank2Window = null; var dataWindow = null; /** Convert a nullable string to a pretty representation */ function sourceify(v) { if (typeof v == "string") return "'" + v + "'"; return String(v); } /** Receives MessageEvents to this window. */ function messageReceiver(evt) { // It's not clear what the security model is for data: URLs and whether they // can access their parents; WebKit denies access, while Gecko currently // allows it. We work around this problem by using postMessage (surprise!) // to start the round of tests when each iframe loads. if (evt.data === "next-test") { setTimeout(nextTest, 0); return; } try { ok(evt instanceof MessageEvent, "umm, how did we get this?"); is(evt.type, "message", "expected events of type 'message'"); if (isMozilla) { ok(evt.isTrusted === false, "shouldn't have been a trusted event"); } if (evt.data === "about:blank-response") { // This isn't clarified in HTML5 yet, but the origin for a document which // has been open()ed is the origin of the calling code, somewhat loosely // speaking. For the specific case of about:blank it's also possible // that the origin is determined by the code that opens the window. It's // not codified yet which of these two causes the identifier tokens on // the event generated by the new window to be those of this window, but // in either case this is what they should be. is(evt.origin, "http://mochi.test:8888", "wrong origin for event from about:blank"); is(evt.source, aboutBlankWindow, "wrong source"); // ...and onto the next test setupBlank2(); } else if (evt.data === "about:blank2-response") { is(evt.origin, "http://mochi.test:8888", "wrong origin for event from about:blank #2"); is(evt.source, aboutBlank2Window, "wrong source"); setupData(); } else if (evt.data === "data-response") { // HTML5 defines the origin of a data: URI as the origin of the window or // script that opened the data: URI. is(evt.origin, "http://mochi.test:8888", "wrong origin for event from data URL (should be the origin of the " + "window/script that opened the URL, in this case the origin of this " + "file)"); is(evt.source, dataWindow, "wrong source"); finish(); } else { ok(false, "unexpected message: " + evt.data); } } catch (e) { ok(false, "error processing event with data '" + evt.data + "': " + e); } } function getContents(description, responseText) { var contents = "<!DOCTYPE html>\n" + "<html>\n" + "<head>\n" + " <title>about:blank</title>\n" + " <script type='application/javascript'>\n" + "function receive(evt)\n" + "{\n" + " var response = '" + responseText + "';\n" + "\n" + " if (evt.source !== window.parent)\n" + " response += ' wrong-source';\n" + " if (evt.origin !== 'http://mochi.test:8888')\n" + " response += ' wrong-origin(' + evt.origin + ')';\n" + " if (evt.data !== 'from-opener')\n" + " response += ' wrong-data(' + evt.data + ')';\n" + "\n" + " window.parent.postMessage(response, 'http://mochi.test:8888');\n" + "}\n" + "\n" + "function ready()\n" + "{\n" + " window.parent.postMessage('next-test', 'http://mochi.test:8888');\n" + "}\n" + "\n" + "window.addEventListener('load', ready, false);\n" + "window.addEventListener('message', receive, false);\n" + " </script>\n" + "</head>\n" + "<body><p>" + description + "</p></body>\n" + "</html>"; return contents; } function finish() { SimpleTest.finish(); } var xhtmlns = "http://www.w3.org/1999/xhtml"; function insert(el) { var content = $("content"); content.parentNode.insertBefore(el, content); } function setupBlank() { var aboutBlankFrame = document.createElementNS(xhtmlns, "iframe"); aboutBlankFrame.setAttribute("src", "about:blank"); insert(aboutBlankFrame); aboutBlankWindow = aboutBlankFrame.contentWindow; var doc = aboutBlankWindow.document; doc.open(); doc.write(getContents("This was about:blank #1", "about:blank-response")); doc.close(); // I don't believe anything guarantees sync parsing, so we have to wait for // the new window to poke us to actually do the test. :-\ } function setupBlank2() { var aboutBlank2Frame = document.createElementNS(xhtmlns, "iframe"); aboutBlank2Frame.addEventListener("load", nextTest, false); aboutBlank2Frame.setAttribute("src", "about:blank"); insert(aboutBlank2Frame); } // Could use window.btoa here, but that's not standardized, and we want to be // able to run these tests against browsers that don't support it. var dataURI = "data:text/html;base64," + b64(getContents("A data: URL", "data-response")); function setupData() { var dataFrame = document.createElementNS(xhtmlns, "iframe"); dataFrame.setAttribute("src", dataURI); insert(dataFrame); dataWindow = dataFrame.contentWindow; // ...and wait again for the window to load... } var count = 0; function nextTest() { switch (count++) { case 0: testBlank(); break; case 1: testBlank2(); break; case 2: testData(); break; default: ok(false, "unreached"); break; } } function testBlank() { aboutBlankWindow.postMessage("from-opener", "http://mochi.test:8888"); } function testBlank2() { // For some reason we can't access this across browsers prior to the iframe // loading, so set its value here. aboutBlank2Window = window.frames[1]; var doc = aboutBlank2Window.document; doc.body.textContent = "This was about:blank #2"; var script = doc.createElement("script"); script.textContent = "window.parent.postMessage('about:blank2-response', " + " 'http://mochi.test:8888');"; doc.body.appendChild(script); } function testData() { dataWindow.postMessage("from-opener", "http://mochi.test:8888"); } window.addEventListener("message", messageReceiver, false); addLoadEvent(setupBlank); ]]></script> </pre> </body> </html>