| Index: content/test/data/cross_site_iframe_factory.html
|
| diff --git a/content/test/data/cross_site_iframe_factory.html b/content/test/data/cross_site_iframe_factory.html
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..2a01c409e26d9da551480e70272a4addd5731a53
|
| --- /dev/null
|
| +++ b/content/test/data/cross_site_iframe_factory.html
|
| @@ -0,0 +1,169 @@
|
| +<html>
|
| +<!-- This page can create whatever iframe structure you want, across whatever
|
| +sites you want. This is useful for testing site isolation.
|
| +
|
| +Example usage in a browsertest, explained:
|
| +
|
| + GURL url =
|
| + test_server()->GetURL("a.com", "/cross_site_iframe_factory.html?a(b(c,d))");
|
| +
|
| +When you navigate to the above URL, the outer document (on a.com) will create a
|
| +single iframe:
|
| +
|
| + <iframe src="http://b.com:1234/cross_site_iframe_factory.html?b(c(),d())">
|
| +
|
| +Inside of which, then, are created the two leaf iframes:
|
| +
|
| + <iframe src="http://c.com:1234/cross_site_iframe_factory.html?c()">
|
| + <iframe src="http://d.com:1234/cross_site_iframe_factory.html?d()">
|
| +
|
| +To make this page work, your browsertest needs a MockHostResolver, like:
|
| +
|
| + void SetUpOnMainThread() override {
|
| + host_resolver()->AddRule("*", "127.0.0.1");
|
| + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
|
| + }
|
| +
|
| +You can play around with the arguments by loading this page via file://, but
|
| +you probably won't get the same process behavior as if you loaded via http. -->
|
| +<head>
|
| +<title>Cross-site iframe factory</title>
|
| +<style>
|
| +body {
|
| + font-family: Sans-Serif;
|
| + text-align: center;
|
| +}
|
| +iframe {
|
| + border-radius: 7px;
|
| + border-style: solid;
|
| + vertical-align: top;
|
| + margin: 2px;
|
| + box-shadow: 2px 2px 2px #888888;
|
| +}
|
| +</style>
|
| +</head>
|
| +<body>
|
| +<h2 id='siteNameHeading'></h2>
|
| +
|
| +
|
| +<script src='tree_parser_util.js'></script>
|
| +<script type='text/javascript'>
|
| +
|
| +/**
|
| + * Determines a random pastel-ish color from the first character of a string.
|
| + */
|
| +function pastelColorForFirstCharacter(seedString, lightness) {
|
| + // Map the first character to an index. This could be negative, we don't
|
| + // really care.
|
| + var index = seedString.charCodeAt(0) - 'a'.charCodeAt(0);
|
| +
|
| + // If the first character is 'a', this will the the starting color.
|
| + var hueOfA = 200; // Spoiler alert: it's blue.
|
| +
|
| + // Color palette generation articles suggest that spinning the hue wheel by
|
| + // the golden ratio yields a magically nice color distribution. Something
|
| + // about sunflower seeds. I am skeptical of the rigor of that claim (probably
|
| + // any irrational number at a slight offset from 2/3 would do) but it does
|
| + // look pretty.
|
| + var phi = 2 / (1 + Math.pow(5, .5));
|
| + var hue = Math.round((360 * index * phi + hueOfA) % 360);
|
| + return 'hsl(' + hue + ', 60%, ' + Math.round(100 * lightness) + '%)';
|
| +}
|
| +
|
| +function backgroundColorForSite(site) {
|
| + // Light pastel.
|
| + return pastelColorForFirstCharacter(site, .75);
|
| +}
|
| +
|
| +function borderColorForSite(site) {
|
| + // Darker color in the same hue has the background.
|
| + return pastelColorForFirstCharacter(site, .32);
|
| +}
|
| +
|
| +/**
|
| + * Adds ".com" to an argument if it doesn't already have a top level domain.
|
| + * This cuts down on noise in the query string, letting you use single-letter
|
| + * names.
|
| + */
|
| +function canonicalizeSite(siteString) {
|
| + if (siteString.indexOf('.') == -1)
|
| + return siteString + '.com';
|
| + return siteString;
|
| +}
|
| +
|
| +/**
|
| + * Simple recursive layout heuristic, since frames can't size themselves.
|
| + * This scribbles .layoutX and .layoutY properties into |tree|.
|
| + */
|
| +function layout(tree) {
|
| + // Step 1: layout children.
|
| + var numFrames = tree.children.length;
|
| + for (var i = 0; i < numFrames; i++) {
|
| + layout(tree.children[i]);
|
| + }
|
| +
|
| + // Step 2: find largest child.
|
| + var largestChildX = 0;
|
| + var largestChildY = 0;
|
| + for (var i = 0; i < numFrames; i++) {
|
| + largestChildX = Math.max(largestChildX, tree.children[i].layoutX);
|
| + largestChildY = Math.max(largestChildY, tree.children[i].layoutY);
|
| + }
|
| +
|
| + // Step 3: Tweakable control parameters.
|
| + var minX = 110; // Should be wide enough to fit a decent sized domain.
|
| + var minY = 110; // Could be less, but squares look nice.
|
| + var extraYPerLevel = 50; // Needs to be tall enough to fit a line of text.
|
| + var extraXPerLevel = 50; // Could be less, but squares look nice.
|
| +
|
| + // Account for padding around each <iframe>.
|
| + largestChildX += 30;
|
| + largestChildY += 30;
|
| +
|
| + // Step 4: Assume a gridSizeX-by-gridSizeY layout that's big enough to fit if
|
| + // all children were the size of the largest one.
|
| + var gridSizeX = Math.ceil(Math.sqrt(numFrames));
|
| + var gridSizeY = Math.round(Math.sqrt(numFrames));
|
| + tree.layoutX = Math.max(gridSizeX * largestChildX + extraXPerLevel, minX);
|
| + tree.layoutY = Math.max(gridSizeY * largestChildY + extraYPerLevel, minY);
|
| +}
|
| +
|
| +function main() {
|
| + var goCrossSite = !window.location.protocol.startsWith('file');
|
| + var queryString = decodeURIComponent(window.location.search.substring(1));
|
| + var frameTree = TreeParserUtil.parse(queryString);
|
| + var currentSite = canonicalizeSite(frameTree.value);
|
| +
|
| + // Apply style to the current document.
|
| + document.getElementById('siteNameHeading').appendChild(
|
| + document.createTextNode(currentSite));
|
| + document.body.style.backgroundColor = backgroundColorForSite(currentSite);
|
| +
|
| + // Determine how big the children should be (using a very rough heuristic).
|
| + layout(frameTree);
|
| +
|
| + for (var i = 0; i < frameTree.children.length; i++) {
|
| + // Compute the URL for this iframe .
|
| + var site = canonicalizeSite(frameTree.children[i].value);
|
| + var subtreeString = TreeParserUtil.flatten(frameTree.children[i]);
|
| + var url = '';
|
| + url += window.location.protocol + '//'; // scheme (preserved)
|
| + url += goCrossSite ? site : window.location.host; // host
|
| + if (window.location.port)
|
| + url += ':' + window.location.port; // port (preserved)
|
| + url += window.location.pathname; // path (preserved)
|
| + url += '?' + encodeURIComponent(subtreeString); // query
|
| +
|
| + // Add the iframe to the document.
|
| + var iframe = document.createElement('iframe');
|
| + iframe.src = url;
|
| + iframe.style.borderColor = borderColorForSite(site);
|
| + iframe.width = frameTree.children[i].layoutX;
|
| + iframe.height = frameTree.children[i].layoutY;
|
| + document.body.appendChild(iframe);
|
| + }
|
| +}
|
| +
|
| +main();
|
| +</script>
|
| +</body></html>
|
|
|