Chromium Code Reviews| 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..ec947c8cf7118ae38ff060db634ab96d96cc27de |
| --- /dev/null |
| +++ b/content/test/data/cross_site_iframe_factory.html |
| @@ -0,0 +1,171 @@ |
| +<html><!-- |
|
dcheng
2015/07/30 23:35:04
Super minor nit: I feel like placing the <!-- migh
ncarter (slow)
2015/08/04 23:51:21
Done -- though check my work, since I wasn't 100%
|
| +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; |
|
dcheng
2015/07/30 23:35:04
Fancy!
ncarter (slow)
2015/08/04 23:51:21
Acknowledged.
|
| + 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; // Needs to be tall enough for |
|
dcheng
2015/08/04 00:14:41
for what? =)
ncarter (slow)
2015/08/04 23:51:21
Done.
|
| + var minY = 110; // Could be less, but squares look nice. |
| + var extraXPerLevel = 50; // Could be less, but squares look nice. |
| + var extraYPerLevel = 50; // Needs to be tall enough for our value. |
| + |
| + // 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 = unescape(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 += '?' + escape(subtreeString); // query |
|
dcheng
2015/08/04 00:14:41
escape => encodeURIComponent
ncarter (slow)
2015/08/04 23:51:21
Done.
|
| + |
| + // Add the iframe to the document. |
| + var iframe = document.createElement('iframe'); |
| + iframe.src = url; |
| + iframe.style.borderColor = borderColorForSite(site); |
| + iframe.scrolling = 'no'; |
|
dcheng
2015/08/04 00:14:41
Is this necessary given the layout() call? It migh
ncarter (slow)
2015/08/04 23:51:21
Good call. I added this early on, before the layou
|
| + iframe.width = frameTree.children[i].layoutX; |
| + iframe.height = frameTree.children[i].layoutY; |
| + document.body.appendChild(iframe); |
| + } |
| +} |
| + |
| +main(); |
| +</script> |
| +</body></html> |