Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 <html> | 1 <html> |
| 2 <!-- This page can create whatever iframe structure you want, across whatever | 2 <!-- This page can create whatever iframe structure you want, across whatever |
| 3 sites you want. This is useful for testing site isolation. | 3 sites you want. This is useful for testing site isolation. |
| 4 | 4 |
| 5 Example usage in a browsertest, explained: | 5 Example usage in a browsertest, explained: |
| 6 | 6 |
| 7 GURL url = embedded_test_server()-> | 7 GURL url = embedded_test_server()-> |
| 8 GetURL("a.com", "/cross_site_iframe_factory.html?a(b(c,d))"); | 8 GetURL("a.com", "/cross_site_iframe_factory.html?a(b(c,d))"); |
| 9 | 9 |
| 10 When you navigate to the above URL, the outer document (on a.com) will create a | 10 When you navigate to the above URL, the outer document (on a.com) will create a |
| 11 single iframe: | 11 single iframe: |
| 12 | 12 |
| 13 <iframe src="http://b.com:1234/cross_site_iframe_factory.html?b(c(),d())"> | 13 <iframe src="http://b.com:1234/cross_site_iframe_factory.html?b(c(),d())"> |
| 14 | 14 |
| 15 Inside of which, then, are created the two leaf iframes: | 15 Inside of which, then, are created the two leaf iframes: |
| 16 | 16 |
| 17 <iframe src="http://c.com:1234/cross_site_iframe_factory.html?c()"> | 17 <iframe src="http://c.com:1234/cross_site_iframe_factory.html?c()"> |
| 18 <iframe src="http://d.com:1234/cross_site_iframe_factory.html?d()"> | 18 <iframe src="http://d.com:1234/cross_site_iframe_factory.html?d()"> |
| 19 | 19 |
| 20 Add iframe options by enclosing them in '{' and '}' characters after the | |
| 21 hostname (multiple options can be separated with ';' characters): | |
| 22 | |
| 23 cross_site_iframe_factory.html?a(b{allowfullscreen}(),c{sandbox-allow-scripts} (d)) | |
|
alexmos
2017/05/04 21:47:00
Awesome, this can also simplify some of our other
ncarter (slow)
2017/05/04 22:06:56
I'm okay with either of these options.
iclelland
2017/05/05 14:54:27
Right, we would still need to write it as {sandbox
| |
| 24 | |
| 25 Will create two iframes: | |
| 26 | |
| 27 <iframe src="http://a.com:1234/cross_site_iframe_factory.html?b()" allowfullsc reen> | |
| 28 <iframe src="http://c.com:1234/cross_site_iframe_factory.html?c{sandbox-allow- scripts}(d())" sandbox="allow-scripts"> | |
| 29 | |
| 30 These options are supported: | |
| 31 | |
| 32 allowfullscreen | |
| 33 allowpaymentrequest | |
| 34 allow-{featurename} - Adds {featurename} to the "allow" attribute | |
| 35 sandbox-{flagname} - Adds {flagname} to the "sandbox" attribute | |
| 36 | |
| 20 To make this page work, your browsertest needs a MockHostResolver, like: | 37 To make this page work, your browsertest needs a MockHostResolver, like: |
| 21 | 38 |
| 22 void SetUpOnMainThread() override { | 39 void SetUpOnMainThread() override { |
| 23 host_resolver()->AddRule("*", "127.0.0.1"); | 40 host_resolver()->AddRule("*", "127.0.0.1"); |
| 24 ASSERT_TRUE(embedded_test_server()->Start()); | 41 ASSERT_TRUE(embedded_test_server()->Start()); |
| 25 } | 42 } |
| 26 | 43 |
| 27 You can play around with the arguments by loading this page via file://, but | 44 You can play around with the arguments by loading this page via file://, but |
| 28 you probably won't get the same process behavior as if you loaded via http. --> | 45 you probably won't get the same process behavior as if you loaded via http. --> |
| 29 <head> | 46 <head> |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 74 // Light pastel. | 91 // Light pastel. |
| 75 return pastelColorForFirstCharacter(site, .75); | 92 return pastelColorForFirstCharacter(site, .75); |
| 76 } | 93 } |
| 77 | 94 |
| 78 function borderColorForSite(site) { | 95 function borderColorForSite(site) { |
| 79 // Darker color in the same hue has the background. | 96 // Darker color in the same hue has the background. |
| 80 return pastelColorForFirstCharacter(site, .32); | 97 return pastelColorForFirstCharacter(site, .32); |
| 81 } | 98 } |
| 82 | 99 |
| 83 /** | 100 /** |
| 101 * Splits a hostname string with optional arguments, like "a" or | |
| 102 * "a.com{allowfullscreen}", into a hostname and an argument list, and returns | |
| 103 * both as a 2-element array. | |
| 104 */ | |
| 105 function splitSiteAndArgs(siteAndArgsString) { | |
|
ncarter (slow)
2017/05/04 22:06:56
Would it make more sense to do the parsing of the
iclelland
2017/05/05 14:54:27
Maybe -- I wasn't sure how generic TreeParserUtil
| |
| 106 var startOfArgs = siteAndArgsString.indexOf('{'); | |
| 107 if (startOfArgs > -1 && siteAndArgsString.endsWith('}')) { | |
| 108 site = siteAndArgsString.slice(0, startOfArgs); | |
| 109 argsString = siteAndArgsString.slice(startOfArgs+1,-1); | |
| 110 args = argsString.split(';'); | |
| 111 } | |
| 112 else { | |
| 113 site = siteAndArgsString; | |
| 114 args = []; | |
| 115 } | |
| 116 return [site, args]; | |
| 117 } | |
| 118 | |
| 119 /** | |
| 84 * Adds ".com" to an argument if it doesn't already have a top level domain. | 120 * Adds ".com" to an argument if it doesn't already have a top level domain. |
| 85 * This cuts down on noise in the query string, letting you use single-letter | 121 * This cuts down on noise in the query string, letting you use single-letter |
| 86 * names. | 122 * names. |
| 87 */ | 123 */ |
| 88 function canonicalizeSite(siteString) { | 124 function canonicalizeSite(siteString) { |
| 89 if (siteString.indexOf('.') == -1) | 125 if (siteString.indexOf('.') == -1) |
| 90 return siteString + '.com'; | 126 return siteString + '.com'; |
| 91 return siteString; | 127 return siteString; |
| 92 } | 128 } |
| 93 | 129 |
| 94 /** | 130 /** |
| 131 * Parses the list of iframe options and applies them to the provided element. | |
| 132 */ | |
| 133 function applyIFrameOptions(element, options) { | |
| 134 var sandboxArguments = []; | |
| 135 var allowFeatures = []; | |
| 136 for (var option of options) { | |
| 137 if (option == "allowfullscreen") { | |
| 138 element.allowFullscreen = true; | |
| 139 } | |
| 140 if (option == "allowpaymentrequest") { | |
| 141 element.allowPaymentRequest = true; | |
| 142 } | |
| 143 if (option.startsWith("sandbox-")) { | |
|
ncarter (slow)
2017/05/04 22:06:56
I think this means that a(b{sandbox-}) will work l
iclelland
2017/05/05 14:54:28
It should work like that -- It's a good hack :) I
ncarter (slow)
2017/05/05 22:37:03
I think in practice folks are likely going to want
| |
| 144 sandboxArguments.push(option.slice(8)); | |
| 145 } | |
| 146 if (option.startsWith("allow-")) { | |
| 147 allowFeatures.push(option.slice(6)) | |
| 148 } | |
| 149 | |
|
alexmos
2017/05/04 21:46:59
nit: no blank line, or move it one line down?
| |
| 150 } | |
| 151 if (sandboxArguments.length) { | |
| 152 element.sandbox = sandboxArguments.join(" "); | |
| 153 } | |
| 154 if (allowFeatures.length) { | |
| 155 element.allow = allowFeatures.join(" "); | |
| 156 } | |
| 157 } | |
| 158 | |
| 159 /** | |
| 95 * Simple recursive layout heuristic, since frames can't size themselves. | 160 * Simple recursive layout heuristic, since frames can't size themselves. |
| 96 * This scribbles .layoutX and .layoutY properties into |tree|. | 161 * This scribbles .layoutX and .layoutY properties into |tree|. |
| 97 */ | 162 */ |
| 98 function layout(tree) { | 163 function layout(tree) { |
| 99 // Step 1: layout children. | 164 // Step 1: layout children. |
| 100 var numFrames = tree.children.length; | 165 var numFrames = tree.children.length; |
| 101 for (var i = 0; i < numFrames; i++) { | 166 for (var i = 0; i < numFrames; i++) { |
| 102 layout(tree.children[i]); | 167 layout(tree.children[i]); |
| 103 } | 168 } |
| 104 | 169 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 125 var gridSizeX = Math.ceil(Math.sqrt(numFrames)); | 190 var gridSizeX = Math.ceil(Math.sqrt(numFrames)); |
| 126 var gridSizeY = Math.round(Math.sqrt(numFrames)); | 191 var gridSizeY = Math.round(Math.sqrt(numFrames)); |
| 127 tree.layoutX = Math.max(gridSizeX * largestChildX + extraXPerLevel, minX); | 192 tree.layoutX = Math.max(gridSizeX * largestChildX + extraXPerLevel, minX); |
| 128 tree.layoutY = Math.max(gridSizeY * largestChildY + extraYPerLevel, minY); | 193 tree.layoutY = Math.max(gridSizeY * largestChildY + extraYPerLevel, minY); |
| 129 } | 194 } |
| 130 | 195 |
| 131 function main() { | 196 function main() { |
| 132 var goCrossSite = !window.location.protocol.startsWith('file'); | 197 var goCrossSite = !window.location.protocol.startsWith('file'); |
| 133 var queryString = decodeURIComponent(window.location.search.substring(1)); | 198 var queryString = decodeURIComponent(window.location.search.substring(1)); |
| 134 var frameTree = TreeParserUtil.parse(queryString); | 199 var frameTree = TreeParserUtil.parse(queryString); |
| 135 var currentSite = canonicalizeSite(frameTree.value); | 200 var currentSite = canonicalizeSite(splitSiteAndArgs(frameTree.value)[0]); |
| 136 | 201 |
| 137 // Apply style to the current document. | 202 // Apply style to the current document. |
| 138 document.getElementById('siteNameHeading').appendChild( | 203 document.getElementById('siteNameHeading').appendChild( |
| 139 document.createTextNode(currentSite)); | 204 document.createTextNode(currentSite)); |
| 140 document.body.style.backgroundColor = backgroundColorForSite(currentSite); | 205 document.body.style.backgroundColor = backgroundColorForSite(currentSite); |
| 141 | 206 |
| 142 // Determine how big the children should be (using a very rough heuristic). | 207 // Determine how big the children should be (using a very rough heuristic). |
| 143 layout(frameTree); | 208 layout(frameTree); |
| 144 | 209 |
| 145 for (var i = 0; i < frameTree.children.length; i++) { | 210 for (var i = 0; i < frameTree.children.length; i++) { |
| 146 // Compute the URL for this iframe . | 211 // Compute the URL for this iframe. |
| 147 var site = canonicalizeSite(frameTree.children[i].value); | 212 var siteAndArgs = splitSiteAndArgs(frameTree.children[i].value); |
| 213 var site = canonicalizeSite(siteAndArgs[0]); | |
| 214 var args = siteAndArgs[1]; | |
| 148 var subtreeString = TreeParserUtil.flatten(frameTree.children[i]); | 215 var subtreeString = TreeParserUtil.flatten(frameTree.children[i]); |
| 149 var url = ''; | 216 var url = ''; |
| 150 url += window.location.protocol + '//'; // scheme (preserved) | 217 url += window.location.protocol + '//'; // scheme (preserved) |
| 151 url += goCrossSite ? site : window.location.host; // host | 218 url += goCrossSite ? site : window.location.host; // host |
| 152 if (window.location.port) | 219 if (window.location.port) |
| 153 url += ':' + window.location.port; // port (preserved) | 220 url += ':' + window.location.port; // port (preserved) |
| 154 url += window.location.pathname; // path (preserved) | 221 url += window.location.pathname; // path (preserved) |
| 155 url += '?' + encodeURIComponent(subtreeString); // query | 222 url += '?' + encodeURIComponent(subtreeString); // query |
| 156 | 223 |
| 157 // Add the iframe to the document. | 224 // Construct the iframe. |
| 158 var iframe = document.createElement('iframe'); | 225 var iframe = document.createElement('iframe'); |
| 159 iframe.src = url; | 226 iframe.src = url; |
| 160 iframe.id = "child-" + i; | 227 iframe.id = "child-" + i; |
| 161 iframe.style.borderColor = borderColorForSite(site); | 228 iframe.style.borderColor = borderColorForSite(site); |
| 162 iframe.width = frameTree.children[i].layoutX; | 229 iframe.width = frameTree.children[i].layoutX; |
| 163 iframe.height = frameTree.children[i].layoutY; | 230 iframe.height = frameTree.children[i].layoutY; |
| 231 // Apply any additional attributes. | |
| 232 applyIFrameOptions(iframe, args); | |
| 233 | |
| 234 // Add the iframe to the document. | |
| 164 document.body.appendChild(iframe); | 235 document.body.appendChild(iframe); |
| 165 } | 236 } |
| 166 } | 237 } |
| 167 | 238 |
| 168 main(); | 239 main(); |
| 169 </script> | 240 </script> |
| 170 </body></html> | 241 </body></html> |
| OLD | NEW |