gecko-dev/dom/tests/mochitest/whatwg/test_postMessage_special.xhtml

398 lines
11 KiB
HTML
Raw Normal View History

<!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="/MochiKit/packed.js"></script>
<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;
var aboutBlankResponseReceived = false;
var aboutBlank2ResponseReceived = false;
var dataResponseReceived = false;
var finished = false;
/** 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.uri, "http://localhost:8888/tests/dom/tests/mochitest/whatwg/test_postMessage_special.xhtml",
"wrong uri for event from about:blank");
ok(evt.domain === "localhost",
"wrong domain for event from about:blank; " +
"got " + sourceify(evt.domain) + ", " +
"expected 'localhost'");
is(evt.source, aboutBlankWindow, "wrong source");
aboutBlankResponseReceived = true;
}
else if (evt.data === "about:blank2-response")
{
is(evt.uri, "http://localhost:8888/tests/dom/tests/mochitest/whatwg/test_postMessage_special.xhtml",
"wrong uri for event from about:blank #2");
ok(evt.domain === "localhost",
"wrong domain for event from about:blank; " +
"got " + sourceify(evt.domain) + ", expected 'localhost'");
is(evt.source, aboutBlank2Window, "wrong source");
aboutBlank2ResponseReceived = true;
}
else if (evt.data === "data-response")
{
// Again, HTML5 hasn't yet defined this, but we're going to do the same
// thing as with about:blank -- for a data: URL opened from page A, the
// uri and domain properties correspond to those of page A. This happens
// to fall out naturally from using the window's security principal to
// determine these two properties.
//
// Mozilla currently gives data: URLs the principal of the opener/parent
// window, and at least for now we'll test for that behavior. If we ever
// change how data: URLs are given principals, we can update this test
// then.
if (isMozilla)
{
is(evt.uri, "http://localhost:8888/tests/dom/tests/mochitest/whatwg/test_postMessage_special.xhtml",
"wrong uri for event from data URL (but note that this URI is " +
"the result of Mozilla's current policy that data: URLs inherit " +
"the principal of their opener/parent, a policy not currently " +
"specified by any standards)");
ok(evt.domain === "localhost",
"wrong domain for event from data URL; " +
"got " + sourceify(evt.domain) + ", expected ''");
}
is(evt.source, dataWindow, "wrong source");
dataResponseReceived = true;
}
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.uri !== 'http://localhost:8888/tests/dom/tests/mochitest/whatwg/test_postMessage_special.xhtml')\n" +
" response += ' wrong-uri(' + evt.uri + ')';\n" +
" if (evt.domain !== 'localhost')\n" +
" response += ' wrong-domain(' + evt.domain + ')';\n" +
" if (evt.data !== 'from-opener')\n" +
" response += ' wrong-data(' + evt.data + ')';\n" +
"\n" +
" window.parent.postMessage(response);\n" +
"}\n" +
"\n" +
"function ready()\n" +
"{\n" +
" window.parent.postMessage('next-test');\n" +
"}\n" +
"\n" +
"window.addEventListener('load', ready, false);\n" +
"document.addEventListener('message', receive, false);\n" +
" </script>\n" +
"</head>\n" +
"<body><p>" + description + "</p></body>\n" +
"</html>";
return contents;
}
var xhtmlns = "http://www.w3.org/1999/xhtml";
function insert(el)
{
var content = $("content");
content.parentNode.insertBefore(el, content);
}
var LOAD_TIMEOUT = 5000;
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. :-\
// Catch recalcitrant browsers that fail inside the iframe document code.
setTimeout(blankFailed, LOAD_TIMEOUT);
}
function blankFailed()
{
if (!aboutBlankResponseReceived && !finished)
{
ok(false,
"test timed out (postMessage not accessible on window.parent in " +
"the first about:blank iframe?)");
finished = true;
SimpleTest.finish();
}
}
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...
// Catch recalcitrant browsers that fail inside the iframe document code.
setTimeout(dataFailed, LOAD_TIMEOUT);
}
function dataFailed()
{
if (!dataResponseReceived && !finished)
{
ok(false,
"test timed out (postMessage not accessible on window.parent in " +
"the data: iframe?)");
finished = true;
SimpleTest.finish();
}
}
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()
{
try
{
aboutBlankWindow.postMessage("from-opener");
}
catch (e)
{
ok(false, "exception thrown trying to post message #1 to about:blank");
}
ok(aboutBlankResponseReceived, "about:blank never got a response!");
setTimeout(setupBlank2, 0);
}
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');";
doc.body.appendChild(script);
// Note that this script gets run synchronously, so we're done with the
// test here.
ok(aboutBlank2ResponseReceived, "postMessage from about:blank #2 failed");
setTimeout(setupData, 0);
}
function testData()
{
try
{
dataWindow.postMessage("from-opener");
}
catch (e)
{
ok(false, "exception thrown trying to post message to data: URL window");
}
ok(dataResponseReceived, "we never got a response!");
// Don't re-report -- we must have already failed, and this can
// screw up the displayed results.
if (finished)
return;
finished = true;
SimpleTest.finish();
}
document.addEventListener("message", messageReceiver, false);
addLoadEvent(setupBlank);
]]></script>
</pre>
</body>
</html>